async def aux_invite_member(ctx, host_member: discord.Member, invited_member: discord.Member): guild = ctx.guild existing_lab_group = hpf.existing_member_lab_group(host_member) if not existing_lab_group: await ctx.send(btm.error_not_in_group_for_invite(host_member)) elif hpf.member_in_teaching_team(invited_member, guild): await ctx.send(btm.error_can_not_invite_teaching_team()) else: async with invites_lock: group_num = hpf.get_lab_group_number(existing_lab_group.name) invite_list = GUILD_CONFIG.group_invites(guild) if hpf.existing_member_lab_group(invited_member): await ctx.send( btm.error_member_already_in_group(invited_member.name, existing_lab_group.name)) elif invite_list.has_invite(invited_member.id, group_num): await ctx.send(btm.error_invite_already_sent(invited_member)) else: # Add invitation invite_list.add_invite(invited_member.id, group_num) general_text_channel = hpf.get_general_text_channel(guild) if general_text_channel: await general_text_channel.send( btm.success_invite_sent_to_group( invited_member, existing_lab_group, group_num)) group_channel = hpf.get_lab_text_channel(guild, group_num) if group_channel: await group_channel.send( btm.success_invite_sent(invited_member))
async def clean_all_command(ctx, *args): async with ctx.channel.typing(): excluded_groups = hpf.get_excluded_groups(*args) groups_to_be_cleaned = [group for group in hpf.all_existing_lab_groups(ctx.guild) if hpf.get_lab_group_number(group.name) not in excluded_groups and is_open_group(ctx.guild, group)] for group in sorted(groups_to_be_cleaned, key=lambda c: c.name, reverse=False): await aux_clean_group(ctx, group.name)
async def random_assignment( ctx, member: discord.Member, available_existing_groups: List[discord.CategoryChannel]): if not member.nick: await ctx.send(btm.message_member_need_name_error(member)) return available_existing_groups max_group_size = GUILD_CONFIG.max_students_per_group(ctx.guild) while len(available_existing_groups) > 0: random_lab_group = random.choice(available_existing_groups) random_group = hpf.get_lab_group_number(random_lab_group.name) if random_group and len( hpf.all_students_in_group(ctx.guild, random_group)) < max_group_size: success = await aux_join_group(ctx, member, random_group) if success: return available_existing_groups available_existing_groups.remove(random_lab_group) new_group = await aux_create_group(ctx) new_group_number = hpf.get_lab_group_number(new_group.name) if await aux_join_group(ctx, member, new_group_number): ctx.send(btm.message_default_error()) available_existing_groups.append(new_group) return available_existing_groups
def aux_group_details(ctx, group: discord.CategoryChannel, details: bool = False, none_if_empty: bool = False) -> Optional[str]: guild = ctx.guild members = hpf.all_students_in_group(guild, group.name) if not members and none_if_empty: return None if details: return btm.info_group_details(members, group, is_open=is_open_group(guild, group)) else: return btm.message_list_group_members( hpf.get_lab_group_number(group.name), members)
async def aux_random_join(ctx, member_mention: discord.Member, *args): member = discord.utils.get(ctx.message.mentions, name=member_mention.name) excluded_groups = hpf.get_excluded_groups(*args) if not member: await ctx.send(btm.message_member_not_exists(member_mention.nick)) elif not excluded_groups: await ctx.send("All extra arguments should be integers!") else: available_lab_groups = [] for group in hpf.all_existing_lab_groups(ctx.guild): group_number = hpf.get_lab_group_number(group.name) if group_number and group not in excluded_groups and is_open_group( ctx.guild, group): available_lab_groups.append(group) await random_assignment(ctx, member, available_lab_groups)
async def aux_raise_hand(ctx): member = ctx.author existing_lab_group = hpf.existing_member_lab_group(member) general_text_channel = hpf.get_general_text_channel(ctx.guild) if not existing_lab_group: await ctx.channel.send(btm.message_member_not_in_group_for_help()) elif ctx.channel != hpf.existing_member_lab_text_channel(member): await ctx.channel.send( btm.error_stay_in_your_seat(ctx.author, existing_lab_group)) elif general_text_channel: group_num = hpf.get_lab_group_number(existing_lab_group.name) # Check if group already asked for help async with help_queue_lock: help_queue = GUILD_CONFIG.help_queue(ctx.guild) queue_size = help_queue.size() if group_num in help_queue: await ctx.channel.send( btm.info_help_queue_size(queue_size - 1) if queue_size > 1 else ":eyes:" ) return # Get help online_team = hpf.all_teaching_team_members(ctx.author.guild) available_team = [ member for member in online_team if not hpf.existing_member_lab_group(member) ] help_message = None if available_team: await ctx.channel.send(btm.message_asking_for_help()) help_message = await general_text_channel.send( btm.message_call_for_help(existing_lab_group.name, available_team)) elif online_team: await ctx.channel.send(btm.message_no_one_available_error()) help_message = await general_text_channel.send( btm.message_call_for_help(existing_lab_group.name, online_team)) else: await ctx.channel.send(btm.message_no_one_online_error()) if help_message: async with help_queue_lock: if queue_size > 0: await ctx.channel.send(btm.info_help_queue_size(queue_size) ) help_queue.add(group=group_num, message_id=help_message.id) else: await ctx.channel.send(btm.message_can_not_get_help_error())
async def map_size_of_members_to_group( guild: discord.Guild) -> Dict[int, List[discord.CategoryChannel]]: print('Getting num of members per group') size_to_group = {} print('Created dictionary') for group in hpf.all_existing_lab_groups(guild): print('Processing group ' + group.name) group_num = hpf.get_lab_group_number(group.name) if is_open_group(guild, group): size = len(hpf.all_students_in_group(guild, group_num)) print('The group is open and it has ' + str(size) + " members") groups = size_to_group.get(size) if groups is None: groups = [] size_to_group[size] = groups groups.append(group) print('Done. The dictionary: ' + str(size_to_group)) return size_to_group
async def aux_random_join_all(ctx, *args): # Get excluded groups excluded_groups = hpf.get_excluded_groups(*args) #if not excluded_groups: # await ctx.send("All extra arguments should be integers for excluded groups.") # return # Get available groups available_lab_groups = [] for group in hpf.all_existing_lab_groups(ctx.guild): group_number = hpf.get_lab_group_number(group.name) if group_number and group not in excluded_groups and is_open_group( ctx.guild, group): available_lab_groups.append(group) no_group_members = hpf.all_students_with_no_group(ctx.guild) # Assign groups for member in no_group_members: # if member.status == discord.Status.online: available_lab_groups = await random_assignment(ctx, member, available_lab_groups)
async def on_reaction_add(reaction: discord.Reaction, user: Union[discord.Member, discord.User]): message = reaction.message emoji = reaction.emoji guild = message.guild # bot reacted for marking the message as attended if bot.user == user: return elif message.author == bot.user and re.search(r"calling for help", message.content): success = False if len(message.reactions) <= 1 and hpf.member_in_teaching_team(user, guild): success = await rhh.go_for_help_from_message(user, message, group=hpf.get_lab_group_number(message.content)) if not success: await message.remove_reaction(reaction, user) elif message.author == bot.user and len(message.reactions) <= 1: if same_emoji(emoji, 'slight_smile'): await message.add_reaction(get_unicode_emoji_from_alias('thumbsup')) await message.channel.send(emoji) else: print(emoji, get_unicode_from_emoji(emoji))
async def aux_assign_all(ctx): print('Assigning students to open groups automatically') # Get number of members per group size_to_group = await map_size_of_members_to_group(ctx.guild) largest_size = max(size_to_group) max_group_size = GUILD_CONFIG.max_students_per_group(ctx.guild) no_group_students = hpf.all_students_with_no_group(ctx.guild) print(str(len(no_group_students)) + ' students are without a group') online_no_group_students = hpf.select_online_members( ctx.guild, no_group_students) # online_no_group_students = no_group_students # ... for debugging late at night print( str(len(online_no_group_students)) + ' students are online without a group') online_no_group_students_with_nick = [] for student in online_no_group_students: if not student.nick: await ctx.send(btm.message_member_need_name_error(student)) else: online_no_group_students_with_nick.append(student) print( str(len(online_no_group_students_with_nick)) + ' students are online without a group but have a nick') if not online_no_group_students_with_nick: await ctx.send( "There are no online students with a nickname and without a group to assign." ) return await ctx.send('Assigning ' + str(len(online_no_group_students_with_nick)) + ' online students with a nickname and without a group.') print('Shuffling students') random.shuffle(online_no_group_students_with_nick) for i in range(1, max_group_size): added_member = [] groups = size_to_group.get(i) print('Processing existing groups of size ' + str(i)) if not groups is None: for group in groups: group_num = hpf.get_lab_group_number(group.name) print('Processing group ' + group.name + ' num ' + str(group_num)) if online_no_group_students_with_nick: member = online_no_group_students_with_nick.pop(0) print('Assigning student ' + member.nick) success = await aux_join_group(ctx, member, group_num) if success: added_member.append(group) else: ctx.send('Unknown error adding ' + member.nick) else: return # else skip member for now print('Updating group sizes') next_group = size_to_group.get(i + 1) if next_group is None: next_group = [] size_to_group[i + 1] = next_group for group in added_member: groups.remove(group) if i < max_group_size: next_group.append(group) print('Processing empty groups') empty_groups = size_to_group.get(0) print(str(len(empty_groups)) + ' empty groups exist') while online_no_group_students_with_nick: print('Moving to next empty group') if empty_groups is None or not empty_groups: empty_group = await aux_create_group(ctx) print('Created new empty group') else: empty_group = empty_groups.pop(0) print('Reusing existing empty group') empty_group_num = hpf.get_lab_group_number(empty_group.name) print('Empty group number is ' + str(empty_group_num)) for i in range(max_group_size): if not online_no_group_students_with_nick: break print('Adding member ' + str(i + 1) + ' to group ' + str(empty_group_num)) member = online_no_group_students_with_nick.pop(0) print('Left to assign ' + str(len(online_no_group_students_with_nick))) await aux_join_group(ctx, member, empty_group_num) # avoid having a group with 1 if possible if (len(online_no_group_students_with_nick) == 2 and max_group_size - (i + 1) < 2): print('Skipping to ensure at least 2 members in each group') break print('Finished assignment')
async def aux_join_group(ctx, member: discord.Member, group: Union[int, str], group_message: bool = True, general_message: bool = True) -> bool: guild = ctx.guild new_role = hpf.get_lab_role(guild, group) new_lab_group = hpf.get_lab_group(guild, group) existing_lab_group = hpf.existing_member_lab_group(member) max_group_size = GUILD_CONFIG.max_students_per_group(guild) if GUILD_CONFIG.require_nickname(guild) and not member.nick: await ctx.send(btm.message_member_need_name_error(member)) elif existing_lab_group: await ctx.send( btm.error_member_already_in_group(hpf.get_nick(member), existing_lab_group.name)) elif not new_role: await ctx.send(btm.message_lab_group_not_exists(new_lab_group.name)) elif not hpf.member_in_teaching_team(member, guild) and len( hpf.all_students_in_group(guild, group)) >= max_group_size: await ctx.send( btm.message_max_members_in_group_error(new_lab_group.name, max_group_size)) else: if not hpf.member_in_teaching_team(member, guild): group_num = hpf.get_lab_group_number(new_lab_group.name) async with invites_lock: invite_list = GUILD_CONFIG.group_invites(guild) invited = invite_list.has_invite(member.id, group_num) if is_closed_group(guild, new_lab_group) and not invited: text_channel = hpf.get_lab_text_channel(guild, group) if text_channel: await text_channel.send( btm.error_someone_try_to_enter(member)) await ctx.send(btm.error_lab_group_is_closed(new_lab_group) ) return False if invited: invite_list.remove_invite(member.id, group_num) await join_group(guild, member, new_role, new_lab_group, group_message=group_message, general_message=general_message) else: await join_group(guild, member, new_role, new_lab_group, group_message=group_message, general_message=general_message) # Remove other invitations async with invites_lock: invite_list = GUILD_CONFIG.group_invites(guild) old_invites = invite_list.retrieve_invites(member.id) for group_invite in old_invites: text_channel = hpf.get_lab_text_channel(guild, group_invite) await text_channel.send( btm.info_member_accepted_another_invite(member)) return True return False