-
Notifications
You must be signed in to change notification settings - Fork 2
/
roles.py
103 lines (84 loc) · 3.9 KB
/
roles.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import bisect
import requests
import config, crypto, db
import logging
async def refresh_top_roles(guild):
collected = []
i = 1
while len(collected) < max(config.levels.ranks):
collected += crypto.fetch_scoreboard(i)
i += 1
usermapping = {e["username"]: e["rank"] for e in collected}
for limit, role_name in zip(config.levels.ranks, config.levels.rank_names):
role = [r for r in guild.roles if r.name == role_name][0]
for m in role.members:
# Remove all old role members that no longer belong
m_username = db.lookup_by_discord_id(m.id)
if m_username is None: continue
m_username = m_username.cryptohack_name
if m_username in usermapping and usermapping[m_username] <= limit:
del usermapping[m_username]
else:
await m.remove_roles(role)
for user in [u for u, v in usermapping.items() if v <= limit]:
# Add this role to all who deserve it
del usermapping[user]
if (m_id := db.lookup_by_cryptohack_username(user)) is not None:
try:
member = await guild.fetch_member(m_id.discord_id)
except:
logging.info(f"Member not found for {user}")
continue
await member.add_roles(role)
async def clear_roles(bot, user_id):
"""Returns the top x role name that was removed, if any"""
guild = bot.get_guild(config.levels.guild_id)
member = await guild.fetch_member(user_id)
member_roles = [r.name for r in member.roles]
top_role = None
# Clean roles:
for role in guild.roles:
if role.name in config.levels.names + config.levels.rank_names + config.levels.special_roles and role.name in member_roles:
await member.remove_roles(role)
if role.name in config.levels.rank_names:
top_role = role.name
return top_role
async def update_roles(bot, user_id, score):
async def add_role_by_name(name):
logging.info(f"add role by name: {name}")
await member.add_roles([r for r in guild.roles if r.name == name][0])
guild = bot.get_guild(config.levels.guild_id)
member = await guild.fetch_member(user_id)
logging.info(f"update roles for member {member.name}")
old_top_role = await clear_roles(bot, user_id)
logging.info(f"Old_top_role: {old_top_role}")
# Find the correct level role
ptidx = max(0, bisect.bisect_right(config.levels.points, score.points) - 1)
if 0 <= ptidx < len(config.levels.names):
await add_role_by_name(config.levels.names[ptidx])
# Find potentially a rank role
for rank, name in zip(config.levels.ranks, config.levels.rank_names):
if score.global_rank <= rank:
logging.info(f"Found a rank role: {name}")
if name != old_top_role:
logging.info(f"It's different, updating everything")
await refresh_top_roles(guild)
else:
logging.info(f"It's the old one, just add it back")
await add_role_by_name(old_top_role)
break
else:
logging.info(f"No rank role found")
# User has solved all challenges
if score.points == score.total_points:
logging.info(f"User has solved all challenges, giving 100% Cleared role")
await add_role_by_name("100% Cleared")
async def process_reaction(callback, message_id, guild, emoji):
if (actions := config.role_reactions.get(str(message_id))) is not None:
for act in actions:
if act.emoji == emoji:
await callback([r for r in guild.roles if r.name == act.role][0])
async def add_verified_role(bot, user_id):
guild = bot.get_guild(config.user_verification.guild_id)
member = await(guild.fetch_member(user_id))
await member.add_roles([r for r in guild.roles if r.name == config.user_verification.role][0])