async def delete_module(self, message, token):

        if has_admin_rights(message.author):
            resultset = session.query(EventMessage).filter_by(token=token)

            if resultset.count() > 0:
                row = resultset.first()

                # Save the old position and delete the record
                old_position = row.position
                session.delete(row)
                session.commit()

                # Iterate over higher positions and lower by one, then store back
                resultset = session.query(EventMessage).filter(
                    EventMessage.position > old_position)
                for row in resultset:
                    row.position -= 1
                    session.add(row)
                    session.commit()

                response = "RE-MOVED TEXT FOR DES-IG-NA-TED TO-KEN."

            else:
                response = "COULD NOT FIND TEXT FOR DES-IG-NA-TED TO-KEN."

            await reply_to_command(self.client, message, response)

        return
Example #2
0
 async def reset_giveaway_entries(self, message):
     if has_admin_rights(message.author):
         session.query(Entry).delete()
         session.commit()
         # Send reply to channel the message was from
         request, response = message, "{}: COM-MEN-DA-TIONS FROM THE PRE-VI-OUS MONTH HAVE BEEN PURGED SUC-CESS-FULLY.".format(
             message.author.mention)
         await reply_to_command(self.client, request, response)
     return
Example #3
0
    async def draw_winner(self, message, intermediary=False):
        if has_admin_rights(message.author):

            server = next(iter(self.client.servers))

            # Grab all the entries
            entries = self.get_entries_as_list()

            if len(entries) == 0:
                return

            # Calculate the sum for all the tickets
            ticket_sum = sum([x[1] for x in entries])
            prize_sender = server.get_member(settings.PRIZE_HANDOUT_NOTIFY)

            # Determine win ranges and win chance
            win_ranges = [
            ]  # Will contain a list [Member, min winning value, max winning value, winchance]
            cur_range = 0
            for entry in entries:
                min_range = cur_range
                max_range = cur_range + entry[1] - 1
                cur_range += entry[1]
                win_chance = entry[1] / ticket_sum * 100
                win_ranges.append([entry[0], min_range, max_range, win_chance])

            # Draw the winning number (inclusive start, exclusive end, step)
            lucky_number = random.randrange(0, ticket_sum + 1, 1)

            # Check to see who won! So exciting
            for entry in win_ranges:
                if entry[1] <= lucky_number <= entry[2]:
                    msg = "CON-GRA-TU-LATIONS {}, YOU ARE A WIN-NER. (WIN-CHANCE: {:.2f}%)".format(
                        entry[0].mention, entry[3])
                    await self.client.send_message(message.channel, msg)

                    date_str = time.strftime("%d/%m/%Y %H:%M")
                    dm = "{} Won a gem giveaway ({:.2f}% chance) on {}\n".format(
                        entry[0].name, entry[3], date_str)
                    dm += "Their winning range was [{}-{}] (inclusive) and I drew {}\n".format(
                        entry[1], entry[2], lucky_number)
                    dm += "If you feel this drawing is incorrect based on the info above, please contact Anve or Twyki."
                    await self.client.send_message(prize_sender, dm)

                    # Remove the winner from the entries table (assuming 1 drawing/month as default)
                    if not intermediary:
                        self.remove_entry(entry[0].id)

                    return
            return

        return
Example #4
0
    async def print_entries(self, message):
        if has_admin_rights(message.author):
            entries = self.get_entries_as_list()
            msg = "**THE FOL-LO-WING CI-TI-ZENS ARE EN-DORSED BY M.O.X.: **\n"  # The text to be sent back
            for entry in entries:
                # Constrain the text size since discord has a character limit of 2000
                if len(msg) > 1500:
                    # If the message exceeds 1500 characters, send it prematurely and wipe the text for continuation
                    await self.client.send_message(message.channel, msg)
                    msg = ""
                msg += "{}: {} COM-MEN-DA-TIONS\n".format(
                    entry[0].name, entry[1])

            await self.client.send_message(message.channel, msg)

        return
Example #5
0
    async def add_abuser(self, message, abuser_mention):
        if has_admin_rights(message.author) or message.author.id in dev_list:
            server = next(iter(self.client.servers))
            abuser_id = abuser_mention[2:-1]
            resultset = session.query(Abuser).filter_by(discord_id=abuser_id)
            count = resultset.count()
            if count == 0:
                # User wasn't in the abuse list yet, so let's add him
                abuser = Abuser(discord_id=abuser_id)
                session.add(abuser)
                session.commit()

            reply = "I THINK THERE-FORE I AT-TACK! {} HAD THEIR PRI-VI-LEGE PURGED.".format(
                abuser_mention)
            await reply_to_command(self.client, message, reply)
        return
    async def dm_modules(self, message):

        if has_admin_rights(message.author):
            resultset = session.query(EventMessage).order_by(
                EventMessage.position)

            if resultset.count() > 0:
                dm = "**Here are all the tokens and positions:** \n"

                for row in resultset:
                    dm += "Position {}: {}\n".format(row.position, row.token)

            else:
                dm = "**No tokens found**"

            await self.client.send_message(message.author, dm)
            await self.client.delete_message(message)

        return
Example #7
0
    async def remove_abuser(self, message, abuser_mention):
        if has_admin_rights(message.author) or message.author.id in dev_list:
            server = next(iter(self.client.servers))
            abuser_id = abuser_mention[2:-1]
            resultset = session.query(Abuser).filter_by(discord_id=abuser_id)
            count = resultset.count()
            if count == 1:
                # User was in the list, so let's remove him
                session.query(Abuser).filter_by(discord_id=abuser_id).delete()
                session.commit()
            else:
                reply = "{}: TAR-GET COULD NOT GET AC-QUIRED. ALL OP-ER-ATIONS WITH-IN NOR-MAL PA-RA-MA-TERS.".format(
                    message.author.mention)
                await reply_to_command(self.client, message, reply)
                return

            reply = "THE ONLY WIN-NING MOVE IS NOT TO PLAY. FUNC-TIO-NA-LI-TIES RE-STORED FOR {}".format(
                abuser_mention)
            await reply_to_command(self.client, message, reply)

        return
Example #8
0
async def on_message(message):

    global giveaway_is_running

    # we do not want the bot to reply to itself
    if message.author == client.user:
        return

    # Log all recieved commands, even if it came from DM
    if message.content.startswith('.'):
        # Don't log if second character is ., _ or " "
        char_2 = message.content[1]
        if  char_2 not in [" ", "_", ".", "-"]:
            delta = datetime.now()
            username = message.author.name
            channel = message.channel.name
            msg = message.content

            log_message = "{} - {}@{}: {}".format(delta, username, channel, message.content) + "\n"

            with open("command_log", "a") as log_file:
                log_file.write(log_message)

    # Check if the message was recieved over DM
    if message.channel.type == discord.ChannelType.private:
        return

    # Check for the next (expected) patch date for GW2
    if message.content.startswith('.patch'):
        link = 'https://www.thatshaman.com/tools/countdown/'
        json_link = link + '?format=json'
        with urllib.request.urlopen(json_link) as url:
            s = url.read()
            response = s.decode('utf-8')

        json_obj = json.loads(response)

        date = json_obj['date'].split("T")[0]

        if json_obj['confirmed']:
            status = "Confirmed"
        else:
            status = "Expected"

        output = "Here's what I could find...\n"
        output += "**Status**: {}\n".format(status)
        output += "**Date**: {}\n".format(date)
        output += "Based on info from that_shaman: <{}>".format(link)

        await client.send_message(message.channel, output)
        return

    # Test for voice access
    if message.content.startswith('.listchannelacces'):
        if message.author.id in devs:
            server = next(iter(client.servers))
            channels = []
            for channel in server.channels:
                if not channel.is_private:
                    if channel.type == discord.ChannelType.text:
                        typename = "text"
                    elif channel.type == discord.ChannelType.voice:
                        typename = "voice"
                    else:
                        typename = "unknown"
                    channels.append("{} ({}),".format(channel.name, typename))
            msg = ""
            for c in channels:
                msg += c
            await client.send_message(message.channel, msg)

    # Show given permissions


    # COMMUNITY GIVEAWAYS!
    if message.content.startswith('.giveaway --check-rank'):
        if not giveaway_is_running:
            if has_admin_rights(message.author) or message.author.id in devs:
                # Set config rank restriction to True
                config = SafeConfigParser()
                config.read('config.ini')
                config.set('giveaway', 'rank_restriction', 'True')
                with open('config.ini', 'w') as f:
                    config.write(f)

                giveaway_is_running = True
                await client.send_message(message.channel, "{} has started a giveaway! This giveaway is restricted to Little Sprouts and higher (lvl 2+)! Type .enter to enter the giveaway!".format(message.author.mention))


        return

    if message.content.startswith('.giveaway'):
        if not giveaway_is_running:
            if has_admin_rights(message.author) or message.author.id in devs:
                # Set the rank restriction in config to false
                config = SafeConfigParser()
                config.read('config.ini')
                config.set('giveaway', 'rank_restriction', 'False')
                with open('config.ini', 'w') as f:
                    config.write(f)
                
                giveaway_is_running = True
                await client.send_message(message.channel, "{} has started a giveaway! This giveaway is open to all! Type .enter to enter the giveaway!".format(message.author.mention))
                return

    if message.content.startswith('.enter'):
        if giveaway_is_running:
            discord_id = message.author.id

            # Check if user is entered, either manually by admin or by the user himself
            resultset = session.query(Giveaway).filter_by(discord_id = discord_id)
            if resultset.count() > 0:
                sent_msg = await client.send_message(message.channel, "{}, you are already entered in the giveaway!".format(message.author.mention))
                await asyncio.sleep(5)
                await client.delete_message(sent_msg)
                await client.delete_message(message)
                return

            # Check if the giveaway is rank restricted
            config = SafeConfigParser()
            config.read('config.ini')

            rank_restricted = config.getboolean('giveaway', 'rank_restriction')
            # If the rank is restricted, and the user doesn't match the rank
            # They get a DM and the function is exited because it doesn't need to check the rest
            if rank_restricted:
                # Check if the user has the required rank
                member = message.author
                has_rank = False
                for role in member.roles:
                    if role.name == "Little Sprout":
                        has_rank = True

                if not has_rank:
                    explain = ""
                    explain += "The giveaway you tried to enter has a rank restriction.\n\n"
                    explain += "**Why is there a rank restriction?**\n"
                    explain += "We have two types of giveaways. There's global giveaways set up by the GM's and WP, and "
                    explain += "there are giveaways set up by individual members. Global giveaways are open to all. However, when an "
                    explain += "individual member gives away something, they can choose to put this rank restriction in place. Usually this is "
                    explain += "to prevent people generally not really engaging with the community snatching away keys from more active members. "
                    explain += "You should see this type of giveaway as a giveaway where a community member gives away something personal to another (active) community member.\n\n"
                    explain += "**So how do these ranks work?**\n"
                    explain += "The ranks are tied in to the Mee6 leveling system. When you post a message on the discord server, Mee6 gives you XP. "
                    explain += "When you've accumulated enough XP, Mee6 will give you a new level, and at certain levels also a new rank. You need to be "
                    explain += "at least level 2 (which is the Little Sprout rank on discord) to enter this giveaway.\n\n"
                    explain += "**Can I still enter the giveaway if I manage to get the required rank before the giveaway ends?**\n"
                    explain += "Absolutely! Just be aware that it might take several minutes for Mee6 to give you the rank once you hit level 2.\n\n"
                    explain += "**So I should just spam all day to get my rank up huh?**\n"
                    explain += "Mee6 only gives you XP once every minute. Spamming will not help to get your rank any faster.\n\n"
                    explain += "**I still engage with the community through other means. Shouldn't I still be allowed to enter?**\n"
                    explain += "It depends. If you are not active through chat but active through other means, send a message to the member facilitating "
                    explain += "this giveaway. Ultimately, since they are giving away the goods, it's their decision. If they agree with you, you can be "
                    explain += "entered in the giveaway manually!"

                    await client.send_message(member, explain)
                    await client.delete_message(message)

                    return
                
            new_record = Giveaway(discord_id = discord_id)
            session.add(new_record)
            session.commit()
            sent_msg = await client.send_message(message.channel, "{}, you have succesfully entered the giveaway!".format(message.author.mention))
            await asyncio.sleep(5)
            await client.delete_message(sent_msg)
            await client.delete_message(message)

            return
        else:
            await client.send_message(message.author, "You attempted to enter a giveaway, but there isn't one running. If you believe this is in error, please ask in chat or contact the bot owner or a server admin.")
            await client.delete_message(message)
            return

    if message.content.startswith('.roll'):
        if has_admin_rights(message.author) or message.author.id in devs:
            giveaway_is_running = False
            # Check if there are any entries
            resultset = session.query(Giveaway)
            if resultset.count() <= 0:
                await client.send_message(message.channel, "There were no entries (left) so no winner was drawn.")
                return

            # Fetch all entries as a list
            entries = []
            server = next(iter(client.servers))
            # First, get all the entries from the db
            for instance in session.query(Giveaway):
                # Lookup the discord member object from the user_id
                member = server.get_member(instance.discord_id)
                # If the member has left the server, they can no longer be found during lookup and will result in a NoneType
                if member is not None:
                    entries.append(member)

            win_chance = 1 / len(entries) * 100
            winner = random.choice(entries)

            msg = "Congratulations {}! You won the giveaway (win chance {:.2f}%).".format(winner.mention, win_chance)

            # Remove the winner from the giveaway table
            session.query(Giveaway).filter_by(discord_id = winner.id).delete()
            session.commit()

            await client.send_message(message.channel, msg)
            return

    if message.content.startswith('.end'):
        if has_admin_rights(message.author) or message.author.id in devs:
            session.query(Giveaway).delete()
            session.commit()
            giveaway_is_running = False
            await client.send_message(message.channel, "The current giveaway has ended!")
        return

    if message.content.startswith('.approve'):
        if has_admin_rights(message.author) or message.author.id in devs:
            if giveaway_is_running:
                member = message.mentions[0]
                resultset = session.query(Giveaway).filter_by(discord_id = member.id)
                # Don't save a new record if the person already entered
                if resultset.count() > 0:
                    sent_msg = await client.send_message(message.channel, "This user has already entered the giveaway!")
                    await asyncio.sleep(5)
                    await client.delete_message(sent_msg)
                    await client.delete_message(message)
                else:
                    new_record = Giveaway(discord_id = member.id)
                    session.add(new_record)
                    session.commit()
                    sent_msg = await client.send_message(message.channel, "{} has approved {} for the giveaway manually!".format(message.author.mention, member.mention))
                    await asyncio.sleep(5)
                    await client.delete_message(message)
                return
            else:
                await client.send_message(message.author, "You attempted to manually approve someone for the giveaway, but I couldn't find a giveaway running at this time.")

            return

    # POLLS!
    if message.content.startswith('.poll'):
        if has_admin_rights(message.author) or message.author.id in devs:
            split_message = message.content.split()
            poll_body = "**POLL TIME BA-BY!** \n"
            poll_body += " ".join(split_message[1:])
            poll = await client.send_message(message.channel, poll_body)
            await client.add_reaction(poll, '\U0001F44D')
            await client.add_reaction(poll, '\U0001F44E')
        else:
            return

    # Remove self-assignable role
    if message.content.startswith('.iamn'):
        author = message.author
        split_message = message.content.split()
        try:
            role_cmd = split_message[1].lower()
            if role_cmd in self_roles:
                role_to_set = self_roles[role_cmd]
                rm = RoleManager(client, message)
                role = rm.fetch_role_by_name(role_to_set)
                await rm.take_role(role, author)
                return
            else:
                return
        except:
            return

    # Add self-assignable role
    if message.content.startswith('.iam'):
        author = message.author
        split_message = message.content.split()
        try:
            role_cmd = split_message[1].lower()
            if role_cmd in self_roles:
                role_to_set = self_roles[role_cmd]
                rm = RoleManager(client, message)
                role = rm.fetch_role_by_name(role_to_set)
                await rm.give_role(role, author)
                return
            else:
                raise
                return
        except:
            return

    # Add moderator assignable roles
    # i.e. .giverole Role MemberMention MemberMention (as *args)
    if message.content.startswith('.giverole'):
        author = message.author
        rm = RoleManager(client, message)
        # Check if message author has access to command
        if has_admin_rights(author) or message.author.id in devs:
            # Parse the given command arguments.
            try:
                arguments = message.content.split()
                role_txt = arguments[1].lower()
                # Find the role, see if it is a mass-assignable role and fetch the role object
                if role_txt in mod_roles:
                    role_name = mod_roles[role_txt]
                    role = rm.fetch_role_by_name(role_name)
                else:
                    return

                # Parse all the members given to the command
                member_mentions = arguments[2:]
                members = [] # Keep track of the fetched member objects
                for mention in member_mentions:
                    if '!' in mention:
                        member_id = mention[3:-1]
                    else:
                        member_id = mention[2:-1]
                    member = message.server.get_member(member_id)
                    members.append(member)
                    

                # Hand over all parsed data to the RoleManager
                await rm.mass_give_role(role, members)
                return

            except:
                raise
                return
        else:
            return

    # Remove moderator assignable role
    if message.content.startswith('.takerole'):
        author = message.author
        rm = RoleManager(client, message)
        # Check if message author has access to command
        if has_admin_rights(author) or message.author.id in devs:
            # Parse the given command arguments.
            try:
                arguments = message.content.split()
                role_txt = arguments[1].lower()
                # Find the role, see if it is a mass-assignable role and fetch the role object
                if role_txt in mod_roles:
                    role_name = mod_roles[role_txt]
                    role = rm.fetch_role_by_name(role_name)
                else:
                    return

                # Parse all the members given to the command
                member_mentions = arguments[2:]
                members = [] # Keep track of the fetched member objects
                for mention in member_mentions:
                    if '!' in mention:
                        member_id = mention[3:-1]
                    else:
                        member_id = mention[2:-1]
                    member = message.server.get_member(member_id)
                    members.append(member)
                    

                # Hand over all parsed data to the RoleManager
                await rm.mass_take_role(role, members)
                return

            except:
                raise
                return
        else:
            return

    # Reset the giveaway entries table
    if message.content.startswith('.reset'):
        pm = PrizeManager(client)
        await pm.reset_giveaway_entries(message)
        return

    # List the entries for the giveaway
    if message.content.startswith('.entries'):
        pm = PrizeManager(client)
        await pm.print_entries(message)
        return

    # DM the list of giveaway entries
    if message.content.startswith('.dmentries'):
        pm = PrizeManager(client)
        await pm.dm_entries(message)
        return

    # MAKE SURE THIS STAYS ABOVE .DRAW OR IT WILL NOT FIRE
    if message.content.startswith('.draw --preserve'):
        pm = PrizeManager(client)
        await pm.draw_winner(message, intermediary=True)
        return

    if message.content.startswith('.draw'):
        pm = PrizeManager(client)
        await pm.draw_winner(message)
        return

    if message.content.startswith('.bug'):
        report = " ".join(message.content.split()[1:])
        br = BugReporter(client)
        await br.report_bug(message, report)
        return

    if message.content.startswith('.denyreporting'):
        br = BugReporter(client)
        await br.add_abuser(message, abuser_mention=message.content.split()[1])
        return

    if message.content.startswith('.allowreporting'):
        br = BugReporter(client)
        await br.remove_abuser(message, abuser_mention=message.content.split()[1])
        return

    if message.content.startswith('.issue'):
        command = message.content[6:]
        try:
            title, body = command.split("|")
            br = BugReporter(client)
            await br.create_issue(message, title, body)
        except:
            return
        return

    # Send copyright notice
    if message.content.startswith('.copyright'):
        msg = "All Guildwars-related texts, names and images are © 2015 ArenaNet, "
        msg += "LLC. All rights reserved. NCSOFT, the interlocking NC logo, ArenaNet, Guild Wars, "
        msg += "Guild Wars Factions, Guild Wars Nightfall, Guild Wars: Eye of the North, Guild Wars 2, "
        msg += "Heart of Thorns, and all associated logos and designs are trademarks or registered "
        msg += "trademarks of NCSOFT Corporation. All other trademarks are the property of their "
        msg += "respective owners."

        await client.send_message(message.author, msg)
        await client.delete_message(message)
        return

    if message.content.startswith('.build'):
        if has_admin_rights(message.author) or has_build_rights(message.author):
            mb = MessageBuilder(client)
            await mb.print_stuff_happening()

        await client.delete_message(message)
        return

    # Dm the evoker a list of all token positions in the event modules
    if message.content.startswith('.modules'):
        mb = MessageBuilder(client)
        await mb.dm_modules(message)
        return

    if message.content.startswith('.delmodule'):
        try:
            token = message.content.split(" ")[1]
            mb = MessageBuilder(client)
            await mb.delete_module(message, token)
        except:
            raise
        return

    if message.content.startswith('.addmodule'):
        if has_admin_rights(message.author):
            try:
                mb = MessageBuilder(client)
                contents = message.content[11:]
                commands = contents.split("|")
                token = commands[0].strip() # Strip leading and trailing spaces
                if not mb.token_in_use(token):
                    position = commands[1].strip()
                    image_link = commands[2].strip()
                    contents = commands[3].strip()

                    await mb.add_module(message, token, position, image_link, contents)
                else:
                    resp = "Sorry, the token you have given me already exists. "
                    resp += "Please find your original message below:\n{}".format(message.content)
                    await client.send_message(message.author, resp)

            except:
                resp = "I'm sorry, but I could not understand you command. Contact the hoster of this bot if you have any questions. "
                resp += "Original message: \n{}".format(message.content)
                await client.send_message(message.author, resp)
                raise

        await client.delete_message(message)

        
        return

    if message.content.startswith('.commands'):
        file = open("commands.md", "r")
        msg = ""
        for line in file:
            msg += line
        await client.send_message(message.author, msg)
        await client.delete_message(message)
        return

    # Sends some bot stats over DM
    if message.content.startswith('.stats'):
        if message.author.id in settings.REPORT_TO_DEVS or has_admin_rights(message.author):
            server = next(iter(client.servers))

            msg = "**Bot Version**\n"
            msg += "Bot version: {}\n".format(settings.BOT_VERSION)
            msg += "Lib version: {}\n\n".format(discord.__version__)

            cnt_eu = 0
            cnt_na = 0
            cnt_no_role = 0
            cnt_any = 0
            for member in server.members:
                valid_roles = 0
                for role in member.roles:
                    if role.name == 'NA':
                        cnt_na += 1
                        valid_roles += 1
                    elif role.name == "EU":
                        cnt_eu += 1
                        valid_roles += 1

                if valid_roles == 0:
                    cnt_no_role += 1
                else:
                    cnt_any += valid_roles

            total_found = len(server.members)
            percent_eu = cnt_eu / total_found * 100 if cnt_eu > 0 else 0
            percent_na = cnt_na / total_found * 100 if cnt_na > 0 else 0
            percent_none = cnt_no_role / total_found * 100 if cnt_no_role > 0 else 0
            msg += "**Region role distribution** (of entire population) \n"
            msg += "Total discord members: {}\n".format(total_found)
            msg += "EU role percentage: {:.2f}%  \n".format(percent_eu)
            msg += "NA role percentage: {:.2f}% \n".format(percent_na)
            msg += "No role percentage: {:.2f}% \n".format(percent_none)
            msg += "\n"

            percent_eu = cnt_eu / cnt_any * 100 if cnt_eu > 0 else 0
            percent_na = cnt_na / cnt_any * 100 if cnt_na > 0 else 0
            msg += "**Region role distribution amongst distributed roles**\n"
            msg += "EU role percentage: {:.2f}% ({} members)\n".format(percent_eu, cnt_eu)
            msg += "NA role percentage: {:.2f}% ({} members)\n\n".format(percent_na, cnt_na)

            msg += "**Assignable roles allowed** \n"
            msg += "Self-assignable roles list: \n"
            for key in self_roles:
                msg += "\t{} => {} \n".format(key, self_roles[key])
        
            msg += "\nGM-assignable roles list:  \n"
            for key in mod_roles:
                msg += "\t{} => {} \n".format(key, mod_roles[key])

            msg += "\n"
            pm = PrizeManager(client)
            sum_tickets = pm.sum_entries()
            avg_tickets = pm.avg_entries()
            participants = len(pm.get_entries_as_list())
            msg += "**Giveaway Stats**\n"
            msg += "Giveaway entries distributed this month: {}\n".format(sum_tickets)
            msg += "Average giveaway entries/entered member: {:.2f}\n".format(avg_tickets)
            msg += "Total giveaway participants: {}\n".format(participants)
            await client.send_message(message.author, msg)
            await client.delete_message(message)
        return