def test_amulets():
  reset.reset(True)
  db.signup(1,'Alice',':hugging:')
  db.signup(2,'Bob',':smirk:')
  db.signup(3,'Charlie',':orange_book:')

  db.add_category(100,True)
  db.add_channel(10,1,True)
  db.add_channel(11,2,True)
  db.add_channel(12,1,True)

  db.add_secret_channel(10,'Amulet_Holder')
  db.add_secret_channel(11,'Amulet_Holder')

  db.set_user_in_channel(10,1,1)
  db.set_user_in_channel(10,2,3)
  db.set_user_in_channel(11,2,1)
  db.set_user_in_channel(12,1,1)
  db.set_user_in_channel(12,3,1)

  assert db.get_secret_channels('Amulet_Holder') == [10,11]

  assert db.amulets(1) == [10]
  assert db.amulets(2) == [10,11]
  assert db.amulets(3) == []
  assert db.has_amulet(1) == True
  assert db.has_amulet(3) == False
  reset.reset(True)
def test_secrets():
  reset.reset(True)
  assert db.get_secret_channels('Assassin') == []
  db.add_secret_channel(1,'Assassin')
  db.add_secret_channel(2,'Assassin')
  assert db.get_secret_channels('Assassin') == [1,2]
  db.add_secret_channel(3,'Werewolf')
  assert db.get_secret_channels('Assassin') == [1,2]
  db.add_secret_channel(4,'Assassin')
  assert db.get_secret_channels('Assassin') == [1,2,4]
  reset.reset(True)
Beispiel #3
0
async def process_message(message,result):
    #if "<@&{}>".format(config.game_master) in message.content:
        #stats.increment_stat("game_master_pings", 1)
        #stats.increment_user_stat(message.author.id, "game_master_pings", 1)

    if db.isParticipant(message.author.id,True,True,True):
        db_set(message.author.id,'activity',0)

    gamelog_channel = client.get_channel(int(config.game_log))
    botspam_channel = client.get_channel(int(config.bot_spam))
    storytime_channel = client.get_channel(int(config.story_time))

    # The temp_msg list is for keeping track of temporary messages for deletion.
    temp_msg = []

    for mailbox in result:

        # If a Mailbox says so, all existing polls will be evaluated.
        if mailbox.evaluate_polls == True:
            for poll in db.get_all_polls():
                # poll.msg_table -> list of message ids
                # poll.blamed -> name of killer
                # poll.purpose -> the reason of the kill

                poll_channel = client.get_channel(int(poll.channel))
                if poll_channel == None:
                    await botspam_channel.send("We got a problem! Could you send these results to the appropriate channel, please?")
                    poll_channel = botspam_channel

                user_table = []
                for msg in poll.msg_table:
                    poll_msg = await poll_channel.get_message(msg)
                    for emoji in poll_msg.reactions:
                        users = await emoji.users().flatten()

                        for person in users:
                            if db.isParticipant(person.id):
                                user_table.append([person.id,emoji.emoji])

                log, result, chosen_emoji = count_votes(user_table,poll.purpose,dy.get_mayor())

                await botspam_channel.send(log)
                await poll_channel.send(result)
                for graveyard in db.get_secret_channels("Graveyard"):
                    await client.get_channel(graveyard).send(result)

                chosen_one = db.emoji_to_player(chosen_emoji)

                if chosen_emoji != '' and chosen_one != None:
                    chosen_one = int(chosen_one)
                    if poll.purpose == 'lynch':
                        db.add_kill(chosen_one,'Innocent')
                    elif poll.purpose == 'Mayor':
                        dy.set_mayor(chosen_one)
                        member = gamelog_channel.guild.get_member(int(chosen_one))
                        if member != None:
                            await member.add_roles(get_role(gamelog_channel.guild.roles, config.mayor), reason="Promoting {} to Mayor".format(member.display_name))
                    elif poll.purpose == 'Reporter':
                        dy.set_reporter(chosen_one)
                        for channel_id in db.get_secret_channels("Reporter"):
                            mailbox.edit_cc(channel_id,chosen_one,1)
                        member = gamelog_channel.guild.get_member(int(chosen_one))
                        if member != None:
                            await member.add_roles(get_role(gamelog_channel.guild.roles, config.reporter), reason="Promoting {} to Reporter".format(member.display_name))
                    elif poll.purpose == 'wolf':
                        db.add_kill(chosen_one,'Werewolf',db.random_wolf())
                    elif poll.purpose == 'cult':
                        db.add_kill(chosen_one,'Cult Leader',db.random_cult())
                    elif poll.purpose == 'thing':
                        db.add_kill(chosen_one,'The Thing','')

        for user_id in mailbox.demotions:
            if user_id == message.author.id and message.guild == gamelog_channel.guild:
                member = message.author
            else:
                member = gamelog_channel.guild.get_member(int(user_id))

            if member != None:
                for role in member.roles:
                    if role.id == config.mayor:
                        await member.remove_roles(role, reason="Demoting the Mayor")
                    if role.id == config.reporter:
                        await member.remove_roles(role, reason="Demoting the Reporter")

        # Create a new shop instance
        for element in mailbox.shops:
            shop_data = db_shop.get_shop_config(element.shop_config)
            i = 1
            j = 0
            emoji_table = []
            page_amount = int(len(shop_data["items"])-1/20)+1


            for item in shop_data["items"]:
                if j % 20 == 0:
                    embed = discord.Embed(title="Shop (Page {}/{})".format(i,page_amount), description=shop_data["shop_description"], color=0x00ff00)

                embed.add_field(name="[{}] {}".format(item["emoji"], item["name"]), value="{} {}\n*{}*\n".format(item["price"], shop_data["currency"], item["description"]), inline=False) # Add item to shop
                emoji_table.append(emojize(item["emoji"]))
                j += 1

                if j % 20 == 0:
                    i += 1
                    response = await client.get_channel(int(element.destination)).send(embed=embed)
                    db_shop.add_shop(response.id)

                    for item in emoji_table:
                        await response.add_reaction(item)
                    emoji_table = []

            if j % 20 != 0:
                response = await client.get_channel(int(element.destination)).send(embed=embed)
                db_shop.add_shop(response.id)

                for item in emoji_table:
                    await response.add_reaction(item)

        # If the Mailbox has a message for the gamelog, this is where it's sent.
        for element in mailbox.gamelog:
            msg = await gamelog_channel.send(element.content)
            for emoji in element.reactions:
                await msg.add_reaction(emoji)
            if element.temporary == True:
                temp_msg.append(msg)

        # If the Mailbox has a message for the botspam, this is where it's sent.
        for element in mailbox.botspam:
            msg = await botspam_channel.send(element.content)
            for emoji in element.reactions:
                await msg.add_reaction(emoji)
            if element.temporary == True:
                temp_msg.append(msg)

        # If the Mailbox has a message for the storytime (in-game announcements) channel, this is where it's sent.
        for element in mailbox.storytime:
            msg = await storytime_channel.send(element.content)
            for emoji in element.reactions:
                await msg.add_reaction(emoji)
            if element.temporary == True:
                temp_msg.append(msg)

        # The messages are sent here if they are a direct message to the one sending a command.
        for element in mailbox.answer:
            msg = await message.channel.send(element.content)
            for emoji in element.reactions:
                await msg.add_reaction(emoji)
            if element.temporary == True:
                temp_msg.append(msg)

        # The messages that are destined for a specific channel, are sent here.
        for element in mailbox.channel:

            # The following code is sent if the message is an embed.
            if element.embed:
                if element.destination == "spam":
                    msg = await botspam_channel.send(embed=element.content)
                    for emoji in element.reactions:
                        await msg.add_reaction(emoji)
                    if element.temporary == True:
                        temp_msg.append(msg)
                else:
                    msg = await client.get_channel(int(element.destination)).send(embed=element.content)
                    for emoji in element.reactions:
                        await msg.add_reaction(emoji)
                    if element.temporary == True:
                        temp_msg.append(msg)
            # The following code is sent if the message is a regular message.
            else:
                msg = await client.get_channel(int(element.destination)).send(element.content)
                for emoji in element.reactions:
                    await msg.add_reaction(emoji)
                if element.temporary == True:
                    temp_msg.append(msg)

        # DMs are sent here.
        for element in mailbox.player:
            member = client.get_user(int(element.destination))
            main_guild = botspam_channel.guild
            if member == None:
                member = main_guild.get_member(int(element.destination))
            if member == None:
                await message.channel.send("Couldn't send a DM to <@{}>!".format(element.destination))
                await botspam_channel.send(
                    "<@{}> has attempted to send a DM to <@{}>, but failed, because we couldn't find the specified user via `client.get_user`.".format(
                        message.author.id, element.destination))
            else:
                try:
                    msg = await member.send(element.content)
                    for emoji in element.reactions:
                        await msg.add_reaction(emoji)
                    if element.temporary == True:
                        temp_msg.append(msg)
                except discord.errors.Forbidden:
                    botspam_channel.send('I wasn\'t allowed to send a DM to <@{}>! Here\'s the content:'.format(member.id))
                    botspam_channel.send(element.content)
                except Exception:
                    botspam_channel.send('I failed to send a DM to <@{}>! Could somebody send this, please?'.format(member.id))
                    botspam_channel.send(element.content)

        # Settings of existing channels are altered here.
        for element in mailbox.oldchannels:
            # element.channel - channel to be edited;
            # element.victim - person's permission to be changed;
            # element.number - type of setting to set to: see issue #83 for more info.

            print('Editing permissions of {} for channel {}...'.format(element.victim,element.channel))
            channel = client.get_channel(element.channel)
            user = client.get_user(int(element.victim))
            main_guild = botspam_channel.guild
            member = main_guild.get_member(int(element.victim))
            if member == None:
                if user == None:
                    await botspam_channel.send("That\'s problematic! I couldn\'t edit the cc info of <@{0}> *(<#{0}> <@&{0}> ?)*".format(element.victim))
                    print('Unable to locate member {}.'.format(element.victim))
                member = user
            if channel == None:
                await botspam_channel.send('Unable to edit channel <#{0}> *(<@{0}> <@&{0}> ?)*'.format(int(element.victim)))
            elif member != None:
                await remove_all_game_roles(member)
                if element.number == 0:
                    await channel.set_permissions(user, read_messages=False, send_messages=False)
                    try:
                        if int(db_get(member.id,'frozen')) == 0:
                            raise NotImplementedError("This is a purposeful error raise!")
                    except Exception:
                        if db.isParticipant(member.id):
                            await member.add_roles(get_role(main_guild.roles, config.participant), reason="Updating CC Permissions")
                        elif db.isParticipant(member.id,True,True):
                            await member.add_roles(get_role(main_guild.roles, config.dead_participant), reason="Updating CC Permissions")
                        elif db.isParticipant(member.id,True,True,True):
                            await member.add_roles(get_role(main_guild.roles, config.suspended), reason="Updating CC Permissions")
                    else:
                        await member.add_roles(get_role(main_guild.roles, config.frozen_participant), reason="Updating CC Permissions")
                elif element.number == 1:
                    await channel.set_permissions(user, read_messages=True, send_messages=True)
                    await member.add_roles(get_role(main_guild.roles, config.participant), reason="Updating CC Permissions")
                elif element.number == 2:
                    await channel.set_permissions(user, read_messages=True, send_messages=False)
                    await member.add_roles(get_role(main_guild.roles, config.frozen_participant), reason="Updating CC Permissions")
                elif element.number == 3:
                    await channel.set_permissions(user, read_messages=False, send_messages=False)
                    await member.add_roles(get_role(main_guild.roles, config.participant), reason="Updating CC Permissions")
                elif element.number == 4:
                    await channel.set_permissions(user, read_messages=True, send_messages=False)
                    if db.isParticipant(member.id,False,True):
                        await member.add_roles(get_role(main_guild.roles, config.dead_participant), reason="Updating CC Permissions")
                elif element.number == 5:
                    await channel.set_permissions(user, read_messages=True, send_messages=False)
                    await member.add_roles(get_role(main_guild.roles, config.participant), reason="Updating CC Permissions")
                elif element.number == 6:
                    await channel.set_permissions(user, read_messages=False, send_messages=False)
                    await member.add_roles(get_role(main_guild.roles, config.participant), reason="Updating CC Permissions")
                elif element.number == 7:
                    await channel.set_permissions(user, read_messages=False, send_messages=False)
                    await member.add_roles(get_role(main_guild.roles, config.participant), reason="Updating CC Permissions")
                elif element.number == 8:
                    await channel.set_permissions(user, read_messages=False, send_messages=False)
                    await member.add_roles(get_role(main_guild.roles, config.suspended), reason="Updating CC Permissions")
                else:
                    await msg.channel.send('Something went wrong! Please contact a Game Master.')
                    return
                if db.isParticipant(element.victim,True,True):
                    db.set_user_in_channel(element.channel,element.victim,element.number)


        # New channels are created here.
        for element in mailbox.newchannels:
            # element.name - name of the channel;
            # element.owner - owner of the channel;
            # element.members - members of the channel
            # element.settlers - members for whom this shall become their home channel
            # element.secret - boolean if the channel is a secret channel

            if element.secret:
                element.owner = client.user.id

            if ' ' not in element.name:

                main_guild = botspam_channel.guild # Find the guild we're in

                if element.owner not in element.members:
                    element.members.append(element.owner)
                for buddy in element.settlers:
                    if buddy not in element.members:
                        msg = """**Warning:** I'm adding settlers to a channel!\nThis is should not be a problem, \
                        but it does at least indicate a flaw in the bot's code. Please, report this to the Game Masters!"""
                        await client.get_channel(message.channel).send(msg)
                        element.members.append(buddy)

                viewers = []
                frozones = []
                abductees = []
                deadies = []

                # Add dead people & spectators to cc
                if not element.secret:
                    for user in [dead_buddy for dead_buddy in db.player_list() if dead_buddy not in db.player_list(True)]:
                        element.members.append(user)

                # Categorize all players
                for user in element.members:
                    member = main_guild.get_member(user)

                    if member == None:
                        await botspam_channel.send("That\'s problematic! I couldn\'t add <@{0}> to a cc. *(<#{0}> <@&{0}> ?)*".format(element.victim))
                        await message.author.send("It doesn't seem like <@{}> is part of the server! I am sorry, I can't add them to your **conspiracy channel**.".format(user))
                    elif db.isParticipant(user,False,True) == True:
                        if int(db_get(user,'abducted')) == 1:
                            abductees.append(member)
                        elif int(db_get(user,'frozen')) == 1:
                            frozones.append(member)
                        elif db.isParticipant(user,False,False) == False:
                            deadies.append(member)
                        else:
                            viewers.append(member)
                    elif db_get(user,'role') == 'Suspended':
                        pass
                    else:
                        deadies.append(member)

                # Delete any potential duplicates
                viewers = list(set(viewers))
                frozones = list(set(frozones))
                abductees = list(set(abductees))
                deadies = list(set(deadies))

                # Role objects (based on ID)
                roles = main_guild.roles # Roles from the guild
                game_master_role = discord.utils.find(lambda r: r.id == game_master, roles)
                # TODO: Add read permissions for spectators if element.secret == False
                default_permissions = {
                    main_guild.default_role: discord.PermissionOverwrite(read_messages=False,send_messages=False),
                    game_master_role: discord.PermissionOverwrite(read_messages=True,send_messages=True),
                    client.user: discord.PermissionOverwrite(read_messages=True,send_messages=True),
                    **{
                        member: discord.PermissionOverwrite(read_messages=True,send_messages=True) for member in viewers
                    },
                    **{
                        member: discord.PermissionOverwrite(read_messages=True,send_messages=False) for member in frozones
                    },
                    **{
                        member: discord.PermissionOverwrite(read_messages=True,send_messages=False) for member in deadies
                    }
                }

                if not element.secret:
                    intro_msg = creation_messages.cc_intro([v.id for v in viewers])
                    reason_msg = 'CC requested by ' + message.author.name
                    title = "s{}_cc_{}".format(config.season,element.name)
                    category_name = 'S{} CCs PART {}'.format(config.season,db.count_categories(element.secret) + 1)
                else:
                    intro_msg = secret_messages.creation(element.name,[v.id for v in viewers])
                    reason_msg = 'Secret {} channel created.'.format(element.name)
                    title = "s{}_{}".format(config.season,element.name)
                    category_name = 'S{} Secret Channels Part {}'.format(config.season,db.count_categories(element.secret) + 1)

                # Create a new category if needed
                if db.get_category(element.secret) == None:
                    category = await main_guild.create_category(category_name, reason='It seems like we couldn\'t use our previous category! Don\'t worry, I just created a new one.')
                    db.add_category(category.id,element.secret)
                else:
                    category = main_guild.get_channel(db.get_category(element.secret))

                try:
                    # Create the text channel
                    channel = await main_guild.create_text_channel(
                        name=title,
                        category=category,
                        overwrites=default_permissions,
                        reason=reason_msg)
                    db.add_channel(channel.id,element.owner,element.secret)
                    if element.secret:
                        db.add_secret_channel(channel.id,element.name)

                        # If the channel is meant for an amulet holder, assign the amulet holder.
                        if element.name == 'Amulet_Holder':
                            for member in viewers:
                                if db_get(member.id,'role') == 'Amulet Holder':
                                    db_set(member.id,'amulet',channel.id)
                    if element.trashy:
                        db.add_trash_channel(channel.id)

                    await channel.send(intro_msg)

                    # Set all access rules in the database
                    for member in viewers:
                        db.set_user_in_channel(channel.id,member.id,1)
                    for member in frozones:
                        db.set_user_in_channel(channel.id,member.id,2)
                    for member in abductees:
                        db.set_user_in_channel(channel.id,member.id,3)
                    for member in deadies:
                        if db.isParticipant(member.id,True,True) == True:
                            db.set_user_in_channel(channel.id,member.id,4)


                except Exception as e: # Catch any thrown exceptions and send an error to the user.
                    await message.channel.send('It seems like I\'ve encountered an error! Please let the Game Masters know about this!')
                    await botspam_channel.send("Oi, Game Masters! I got a problem concerning channel creation for ya to fix.")
                    await botspam_channel.send(e)
                    raise e # Send the full log to Buddy1913 and his sketchy VM.

                # Give the settlers their own happy little residence
                for buddy in element.settlers:
                    db_set(buddy,"channel",channel.id)

            else:
                """This should not happen, but we'll use it, to prevent the bot from purposely causing an error
                everytime someone attempts to create a channel that contains spaces. 'cause believe me,
                that happens ALL the time."""
                msg = await message.channel.send("I\'m terribly sorry, but you can\'t use spaces in your channel name. Try again!")
                temp_msg.append(msg)


        # Polls are created here.
        for element in mailbox.polls:
            # element.channel
            # element.purpose
            # element.user_id
            # element.description

            msg = element.description + '\n'
            emoji_table = []
            msg_table = []
            i = 0

            for user in db.poll_list():
                if db.isParticipant(int(user[0])):
                    i += 1
                    msg += user[1] + " - <@" + str(user[0]) + "> "

                    if int(user[2]) + int(user[3]) > 0:
                        if int(user[2]) == 1:
                            msg += "**[FROZEN]** "
                        if int(user[3]) == 1:
                            msg += "**[ABDUCTED] **"
                    else:
                        emoji_table.append(user[1])

                    if i % 20 == 19:
                        if client.get_channel(int(element.channel)) == None:
                            await botspam_channel.send("Failed to send message in correct channel. ({})".format(element.channel))
                            msg = await botspam_channel.send(element.content)
                        else:
                            msg = await client.get_channel(int(element.channel)).send(msg)
                        for emoji in emoji_table:
                            await msg.add_reaction(emoji)
                        msg_table.append(msg)
                        emoji_table = []
                        msg = ''
                    else:
                        msg += '\n'

            if msg != '':
                msg = await client.get_channel(element.channel).send(msg)
                for emoji in emoji_table:
                    await msg.add_reaction(emoji)
                msg_table.append(msg)
            db.add_poll(msg_table,element.purpose,element.channel,element.user_id)
            await botspam_channel.send("A poll has been created in <#{}>!".format(element.channel))


        # Categories are deleted here.
        for element in mailbox.deletecategories:
            id = element.channel
            category = client.get_channel(id)
            if category != None:
                bot_message = await message.channel.send('Please react with 👍 to confirm deletion of category `' + category.name + '`.\n\nNote: This action will irreversibly delete all channels contained within the specified category. Please use with discretion.')
                await bot_message.add_reaction('👍')
                def check(reaction, user):
                    return user == message.author and str(reaction.emoji) == '👍'
                try:
                    reaction, user = await client.wait_for('reaction_add', timeout=30.0, check=check)
                except asyncio.TimeoutError:
                    await message.channel.send('Confirmation timed out.')
                    try:
                        await bot_message.delete()
                    except Exception:
                        pass
                else:
                    await message.channel.send('Ok, I\'ll get right on that.\n\n*This might take some time.*')
                    for channel in category.channels:
                        await channel.delete()
                    await category.delete()
                    await message.channel.send('\n:thumbsup: Channels and category deleted')
            else:
                await message.channel.send('Sorry, I couldn\'t find that category.')

        clean_time = len(mailbox.cleaners)
        if clean_time > 0:
            await botspam_channel.send("Cleaning up {} channels! This may take some time.".format(clean_time))

        for channel in mailbox.cleaners:

            trash_channel = client.get_channel(int(channel))

            if trash_channel != None:
                for message_id in db.empty_trash_channel(channel):
                    message = await trash_channel.get_message(int(message_id))
                    if message != None:
                        await message.delete()

    # Delete all temporary messages after about two minutes.
    await asyncio.sleep(120)
    for msg in temp_msg:
        try:
            await msg.delete()
        except Exception:
            # Unable to delete the message.
            # It was probaly already deleted or something.
            pass