Beispiel #1
0
    async def on_message_edit(self, before, message):
        # Adds the edited message to the table
        if message.guild is None:
            return

        # gets the char difference between the two messages
        b_cont = before.content
        a_cont = message.content
        before_char_count = len(b_cont)
        before_word_count = len(b_cont.split(" "))
        before_emoji_count = b_cont.count(":") // 2
        before_spoiler_count = b_cont.count("||") // 2
        after_char_count = len(a_cont)
        after_word_count = len(a_cont.split(" "))
        after_emoji_count = a_cont.count(":") // 2
        after_spoiler_count = a_cont.count("||") // 2

        SUBJECT_ID = self.get_current_subject()
        SQLFunctions.update_statistics(
            message.author,
            SUBJECT_ID,
            messages_edited=1,
            characters_sent=after_char_count - before_char_count,
            words_sent=after_word_count - before_word_count,
            emojis_sent=after_emoji_count - before_emoji_count,
            spoilers_sent=after_spoiler_count - before_spoiler_count)
Beispiel #2
0
 def __init__(self, bot):
     self.bot = bot
     self.send_message_to_finn = False
     self.lecture_updater_version = "v1.0"
     self.db_path = "./data/discord.db"
     self.conn = SQLFunctions.connect()
     self.channel_to_post = SQLFunctions.get_config(
         "channel_to_post_updates", self.conn)
     self.background_loop.start()
     self.current_activity = ""
     self.sent_updates = {
         1: False,
         2: False,
         3: False,
         4: False,
         5: False,
         6: False
     }
     self.lecture_updates_role_ids = {
         "first": 885810281358446623,
         "second": 885810349121622056,
         "third": 885810401969831978
     }
     self.sent_advent = False
     self.sent_website_updates = False
Beispiel #3
0
    async def on_message(self, message):
        # fights against people trying to ruin my images hehe ;)
        if message.content.startswith(".place setpixel ") and self.image is not None:
            cont = message.content.split(" ")
            try:
                x = int(cont[2])
                y = int(cont[3])
            except ValueError:
                return
            r, g, b, a = self.image.getpixel((x, y))
            if a != 0:
                color = rgb2hex(r, g, b)
                if color != cont[4].lower():
                    channel = self.bot.get_channel(819966095070330950)
                    if channel is None:
                        channel = self.bot.get_channel(402563165247766528)
                    await channel.send(f".place setpixel {x} {y} {color} | COUNTERING {message.author.name}")

        if message.author.id == self.userToCopyTextFrom and message.channel.id != 813430350965375046 and is_valid_msg(message.content):
            if len(self.queue) > 50:
                return
            pil_img, self.last_line, self.last_char = self.draw_text(message.content, self.last_line, self.last_char)
            SQLFunctions.insert_or_update_config("Draw_Last_Line", self.last_line, self.conn)
            SQLFunctions.insert_or_update_config("Draw_Last_Char", self.last_char, self.conn)
            # id to stop specific draw
            ID = str(random.randint(1000, 10000))
            img = im2q.PixPlace(ID, ID, False, pil_img=pil_img)
            img.left_to_right()
            self.handle_image(img, 0, ID)
Beispiel #4
0
 async def on_message_delete(self, message):
     if message.guild is None:
         return
     SUBJECT_ID = self.get_current_subject()
     SQLFunctions.update_statistics(message.author,
                                    SUBJECT_ID,
                                    messages_deleted=1)
Beispiel #5
0
    async def add_rep(self, message, member, author):
        """
        Adds the reputation to the file
        """
        # Can the user rep yet?
        author_member = SQLFunctions.get_or_create_discord_member(
            author, conn=self.conn)
        if not self.check_valid_time(author_member):
            return False

        receiver_member = SQLFunctions.get_or_create_discord_member(
            member, conn=self.conn)

        # Format the reputation message
        msg_list = message.content.split(" ")
        if len(msg_list) > 2:
            msg = " ".join(msg_list[2:])
        else:
            return False

        # Check if the rep is positive
        if msg.startswith("-"):
            isPositive = False
            msg = msg[1:].strip()
        else:
            isPositive = True

        # Add to DB
        SQLFunctions.add_reputation(author_member, receiver_member, msg,
                                    isPositive, self.conn)
        return True
Beispiel #6
0
    def __init__(self, bot):
        self.bot = bot
        self.cancel_all = False
        self.cancel_draws = []
        self.pause_draws = False
        self.progress = {}
        self.image = None
        self.queue = []
        self.background_draw.start()
        self.db_path = "./data/discord.db"
        self.place_path = "./place/"
        self.conn = SQLFunctions.connect()

        self.LINE_HEIGHT = 62  # amount of lines which fit on the place canvas
        self.CHAR_WIDTH = 166  # amount of chars which fit in a line on the place canvas
        self.font = ImageFont.truetype("./data/nk57-monospace-cd-rg.ttf", 12)
        self.userToCopyTextFrom = -1
        self.last_line = SQLFunctions.get_config("Draw_Last_Line", self.conn)
        if len(self.last_line) == 0:
            self.last_line = 0
        else:
            self.last_line = self.last_line[0]
        self.last_char = SQLFunctions.get_config("Draw_Last_Char", self.conn)
        if len(self.last_char) == 0:
            self.last_char = 0
        else:
            self.last_char = self.last_char[0]
Beispiel #7
0
 async def on_reaction_remove(self, reaction, member):
     if reaction.message.guild is None or member.bot:
         return
     if member.id == reaction.message.author.id:
         return
     SUBJECT_ID = self.get_current_subject()
     SQLFunctions.update_statistics(member, SUBJECT_ID, reactions_removed=1)
     SQLFunctions.update_statistics(reaction.message.author,
                                    SUBJECT_ID,
                                    reactions_taken_away=1)
Beispiel #8
0
 def remove_drawing(self, ID):
     # removes the drawing from the sql table
     SQLFunctions.delete_config(f"%{ID}", self.conn)
     # removes it from the queue and progress bar
     if ID in self.progress:
         self.progress.pop(ID)
         self.queue.pop(0)
     while ID in self.cancel_draws:
         self.cancel_draws.remove(ID)
     os.remove(f"{self.place_path}{ID}.npy")
Beispiel #9
0
    async def add_xp(self, member: discord.Member, amount_min, amount_max):
        """
        Adds xp to a specific user in that guild
        :param member:
        :param amount_min:
        :param amount_max:
        :return:
        """
        rand_amount = random.randrange(amount_min, amount_max)

        SQLFunctions.insert_or_update_voice_level(member, rand_amount,
                                                  self.conn)
Beispiel #10
0
 async def on_reaction_add(self, reaction, member):
     if reaction.message.guild is None or member.bot:
         return
     if member.id == reaction.message.author.id:
         return
     SUBJECT_ID = self.get_current_subject()
     SQLFunctions.update_statistics(
         member, SUBJECT_ID,
         reactions_added=1)  # reactions added by the user
     SQLFunctions.update_statistics(
         reaction.message.author, SUBJECT_ID,
         reactions_received=1)  # reactions received by the user
Beispiel #11
0
    async def on_member_join(self, member):
        # adds the user to the db
        try:
            SQLFunctions.get_or_create_discord_member(member, conn=self.conn)
        except Exception as e:
            print(e)

        if member.bot:
            return
        # if the server is the main server
        if member.guild.id == 747752542741725244:
            channel = self.bot.get_channel(815936830779555841)
            await self.send_welcome_message(channel, member, member.guild)
Beispiel #12
0
    def __init__(self, bot):
        self.bot = bot
        self.db_path = "./data/discord.db"
        self.conn = SQLFunctions.connect()

        # gets the button value to watch
        self.watch_button_value = SQLFunctions.get_config("ButtonValue", self.conn)
        if len(self.watch_button_value) == 0:
            self.watch_button_value = 1e6
        else:
            self.watch_button_value = self.watch_button_value[0]
        self.sent_message = False
        self.old_value = 1e6  # to ignore fake buttons we store the last value
Beispiel #13
0
 def __init__(self, bot):
     self.bot = bot
     self.newcomers = {}
     self.ta_request = {}
     self.bot_prefix_path = "./data/bot_prefix.json"
     with open(self.bot_prefix_path, "r") as f:
         self.all_prefix = json.load(f)
     self.db_path = "./data/discord.db"
     self.conn = SQLFunctions.connect()
     self.welcome_message_id = SQLFunctions.get_config(
         "WelcomeMessage", self.conn)
     self.requested_help = [
     ]  # list of DiscordUserIDs of who requested help
     self.requested_ta = [
     ]  # list of DiscordUserIDs which requested TA role to avoid spam
Beispiel #14
0
    async def on_message(self, message):
        # only count stats in servers
        if message.guild is None:
            return
        # deletes the message if its in #newcomers
        if message.channel.id == 815881148307210260 and not message.author.bot:
            try:
                await message.delete()
                deleted_messages = SQLFunctions.get_config(
                    "deleted_messages", self.conn)
                if len(deleted_messages) == 0:
                    deleted_messages = 0
                else:
                    deleted_messages = deleted_messages[0]
                SQLFunctions.insert_or_update_config("deleted_messages",
                                                     deleted_messages + 1,
                                                     self.conn)
            except discord.NotFound:  # message was already deleted
                pass
        SUBJECT_ID = self.get_current_subject()
        # Makes it better to work with the message
        msg = demojize(message.content)

        char_count = len(msg)
        word_count = len(msg.split(" "))
        emoji_count = msg.count(":") // 2
        spoiler_count = msg.count("||") // 2

        # File Statistics
        files_amount = len(message.attachments)
        file_sizes = 0
        images_amt = 0
        for f in message.attachments:
            file_sizes += f.size
            if f.height is not None and f.height > 0:
                images_amt += 1

        SQLFunctions.update_statistics(message.author,
                                       SUBJECT_ID,
                                       conn=self.conn,
                                       messages_sent=1,
                                       characters_sent=char_count,
                                       words_sent=word_count,
                                       spoilers_sent=spoiler_count,
                                       emojis_sent=emoji_count,
                                       files_sent=files_amount,
                                       file_size_sent=file_sizes,
                                       images_sent=images_amt)
Beispiel #15
0
    async def background_draw(self):
        await self.bot.wait_until_ready()
        # opens and readies all the files
        imgs = self.get_all_queues(self.place_path)
        for im in imgs:
            if im.fp not in self.progress:
                start = SQLFunctions.get_config(f"Start_{im.fp}", self.conn)
                if len(start) == 0:
                    start = 0
                else:
                    start = start[0]
                self.progress[im.fp] = {
                    "count": start,
                    "img": im,
                    "queue": im.get_queue()
                }
                self.queue.append({
                    "ID": im.fp,
                    "size": im.size,
                    "img": im,
                    "queue": im.get_queue()
                })

        channelID = SQLFunctions.get_config("PlaceChannel", self.conn)
        if len(channelID) == 0:
            channelID = 819966095070330950
        else:
            channelID = channelID[0]
        channel = self.bot.get_channel(channelID)
        if channel is None:
            channel = self.bot.get_channel(402551175272202252)  # fallback test channel

        # keeps going through all lists
        while len(self.queue) > 0 and not self.pause_draws:
            drawing = self.queue[0]
            start = SQLFunctions.get_config(f"Start_{drawing['ID']}", self.conn)
            end = SQLFunctions.get_config(f"End_{drawing['ID']}", self.conn)
            if len(start) == 0:
                start = 0
            else:
                start = start[0]
            if len(end) == 0:
                end = drawing["img"].size
            else:
                end = end[0]
            done = await self.draw_pixels(drawing["ID"], channel, start, end)
            if done:
                self.remove_drawing(drawing["ID"])
Beispiel #16
0
 async def perm(self, ctx, command=None):
     """
     Can be used to edit or view permissions for a command.
     For more information view the `add` subcommand.
     Permissions: Owner
     """
     if ctx.invoked_subcommand is None:
         if command is None:
             await ctx.reply("ERROR! No command to view given.")
             raise discord.ext.commands.BadArgument
         if command.lower() not in [com.name.lower() for com in self.bot.commands]:
             await ctx.reply("ERROR! Command not found. Did you maybe mistype a subcommand?")
             raise discord.ext.commands.BadArgument
         command_level = SQLFunctions.get_all_command_levels(command.lower(), self.conn)
         embed = discord.Embed(
             description=f"Dynamic permissions for `{command.lower()}`:",
             color=discord.Color.blue()
         )
         user_msg = "\n".join(f"* {k}: {v}" for k, v in command_level.user_levels.items())
         role_msg = "\n".join(f"* {k}: {v}" for k, v in command_level.role_levels.items())
         channel_msg = "\n".join(f"* {k}: {v}" for k, v in command_level.channel_levels.items())
         guild_msg = "\n".join(f"* {k}: {v}" for k, v in command_level.guild_levels.items())
         embed.add_field(name="User", value=f"```md\n{user_msg} ```")
         embed.add_field(name="Role", value=f"```md\n{role_msg} ```")
         embed.add_field(name="\u200b", value="\u200b", inline=False)
         embed.add_field(name="Channel", value=f"```md\n{channel_msg} ```")
         embed.add_field(name="Guild", value=f"```md\n{guild_msg} ```")
         await ctx.reply(embed=embed)
Beispiel #17
0
 def __init__(self, bot):
     self.bot = bot
     with open("./data/ignored_users.json") as f:
         self.ignored_users = json.load(f)
     self.db_path = "./data/discord.db"
     self.conn = SQLFunctions.connect()
     self.time_to_wait = 20 * 3600  # Wait 20 hours before repping again
Beispiel #18
0
    async def rank(self, ctx, user=None):
        """
        This command sends the users voice XP rank. If no user is defined, the command user's rank is sent.
        """
        if user is None:
            member = ctx.message.author
        else:
            user_id = user.replace("<@", "").replace(">", "").replace("!", "")
            member = None
            if user_id.isnumeric():
                member = ctx.message.guild.get_member(int(user_id))

        if member is None:
            await ctx.send(
                f"{ctx.message.author.mention}, invalid mention or user ID. Can't display rank for that user."
            )
            raise ValueError

        # Query User experience
        voice_level = SQLFunctions.get_voice_level(member, self.conn)

        level = levefier(voice_level.experience)
        pre_level = round(voice_level.experience - xpfier(level))
        aft_level = round(xpfier(level + 1) - xpfier(level))
        embed = discord.Embed(
            title="Voice Level",
            description=f"User: <@!{voice_level.member.DiscordUserID}>\n"
            f"Current Level: `{level}`\n"
            f"Level XP: `{pre_level}` / `{aft_level}`\n"
            f"Total XP: `{number_split(voice_level.experience)}`\n"
            f"Estimated Hours: `{round(voice_level.experience / 3600, 1)}`",
            color=0x00FF00)
        await ctx.send(embed=embed)
Beispiel #19
0
 def check_valid_time(self, member: SQLFunctions.DiscordMember):
     result = SQLFunctions.get_most_recent_time(member, self.conn)
     if result is None:
         return True
     time_sent = datetime.datetime.fromisoformat(result)
     if time.time() - time_sent.timestamp() > self.time_to_wait:
         return True
     return False
Beispiel #20
0
    async def point_distribute(self, confirmed_cases):
        log(f"Starting COVID points distribution", "COVID")
        lb_messages = []
        rank = 1
        guessers = SQLFunctions.get_covid_guessers(self.conn, guessed=True)
        for g in guessers:
            g.TempPoints = int(calculate_points(confirmed_cases, g.NextGuess))
        # Sort the guessers by their gotten points
        guessers.sort(key=lambda x: x.TempPoints, reverse=True)
        for g in guessers:
            msg = f"**{rank}:** <@{g.member.DiscordUserID}> got {g.TempPoints} points *(guess: {g.NextGuess})*"
            rank += 1
            lb_messages.append(msg)
        SQLFunctions.clear_covid_guesses(users=guessers,
                                         increment=True,
                                         conn=self.conn)

        return lb_messages
Beispiel #21
0
    def handle_image(self, img: im2q, drawn: int, ID: str):
        self.progress[ID] = {
            "count": drawn,
            "img": img,
            "queue": img.get_queue()
        }
        self.queue.append({
            "ID": ID,
            "size": img.size,
            "img": img,
            "queue": img.get_queue()
        })

        SQLFunctions.insert_or_update_config(f"Start_{ID}", 0, self.conn)
        SQLFunctions.insert_or_update_config(f"End_{ID}", img.size, self.conn)

        # saves the img as a numpy file so it can easily be reload when the bot restarts
        img.save_array(f"{self.place_path}{ID}")
Beispiel #22
0
 async def watch(self, ctx, val=None):
     await ctx.message.delete()
     if val is None:
         # yes if we're tracking, no if we're at default value
         if self.watch_button_value < 1e6:
             await ctx.send(f"{self.watch_button_value} | {self.sent_message}", delete_after=5)
         else:
             await ctx.send("no", delete_after=5)
     else:
         if not val.isnumeric():
             await ctx.send("not int", delete_after=5)
             raise discord.ext.commands.errors.BadArgument
         # saves the value to watch into config
         SQLFunctions.insert_or_update_config("ButtonValue", int(val), self.conn)
         self.watch_button_value = int(val)
         self.old_value = 1e6
         self.sent_message = False
         await ctx.send("ok", delete_after=5)
Beispiel #23
0
 def __init__(self, bot):
     self.bot = bot
     self.script_start = 0
     self.waiting = False
     self.time_counter = 0  # So statistics dont get saved every few seconds, and instead only every 2 mins
     self.bot_changed_to_yesterday = {}
     self.background_git_backup.start()
     self.sent_file = False
     self.current_subject = [-1, 0]
     self.conn = SQLFunctions.connect()
Beispiel #24
0
 def __init__(self, bot):
     self.bot = bot
     self.clap_counter = 0
     self.time = 0
     self.confirmed_cases = 0
     self.confirm_msg = None  # Confirmed message
     self.conn = SQLFunctions.connect()
     self.time_since_task_start = time.time()
     self.background_check_cases.start()
     self.sent_covid = False
     recent_covid_cases = SQLFunctions.get_config("COVID_Cases", self.conn)
     recent_covid_day = SQLFunctions.get_config("COVID_Day", self.conn)
     if len(recent_covid_cases) > 0:
         self.cases_today = recent_covid_cases[0]
     else:
         self.cases_today = 0
     if len(recent_covid_day) > 0:
         self.last_cases_day = recent_covid_day[0]
     else:
         self.last_cases_day = 0
Beispiel #25
0
 def get_current_subject(self, semester=2) -> int:
     """
     Minor cache system to only make a subject query if it's a new minute
     Returns the current subject ID
     """
     minute = datetime.now().minute
     if self.current_subject[0] != minute:
         subject_id = SQLFunctions.get_current_subject_id(semester,
                                                          conn=self.conn)
         self.current_subject = [minute, subject_id]
     return self.current_subject[1]
Beispiel #26
0
 async def ImagesSent(self, ctx, mx=10):
     """
     See ImagesSent Stats. `amount shown` is the amount of users that \
     should be displayed in the leaderboard. Min: 1, Max: 20.
     """
     if mx < 0:
         mx = 1
     elif mx > 20:
         mx = 20
     column = SQLFunctions.get_statistic_rows("ImagesSent", mx, self.conn)
     embed = await self.get_top_users(single_statistic=column,
                                      single_statistic_name="Images Sent")
     await ctx.send(embed=embed)
Beispiel #27
0
 async def draw_pixels(self, ID, channel, start, end) -> bool:
     pixels_queue = self.progress[ID]["queue"][start:end]
     # draws the pixels
     while len(pixels_queue) > 0:
         if self.cancel_all or str(ID) in self.cancel_draws:
             await channel.send(f"Canceled Project {ID}.")
             return True
         if self.pause_draws:
             return False
         pix = pixels_queue[0]
         pX = pix[0]
         pY = pix[1]
         pHex = rgb2hex(pix[2], pix[3], pix[4])
         try:
             await channel.send(f".place setpixel {pX} {pY} {pHex} | PROJECT {ID}")
             self.progress[ID]["count"] += 1
             pixels_queue.pop(0)
             if self.progress[ID]["count"] % 10 == 0:
                 SQLFunctions.insert_or_update_config(f"Start_{ID}", self.progress[ID]["count"], self.conn)
         except Exception:
             await asyncio.sleep(5)
     return True
Beispiel #28
0
 async def VoteCount(self, ctx, mx=10):
     """
     See only ReactionsTakenAway Stats. `amount shown` is the amount of users that \
     should be displayed in the leaderboard. Min: 1, Max: 20.
     """
     if mx < 0:
         mx = 1
     elif mx > 20:
         mx = 20
     column = SQLFunctions.get_statistic_rows("VoteCount", mx, self.conn)
     embed = await self.get_top_users(
         single_statistic=column,
         single_statistic_name="Quote Battles voted on")
     await ctx.send(embed=embed)
Beispiel #29
0
async def globally_handle_permissions(ctx):
    """
    Checks if the command can be used in the channel. It's a blacklist system, so by default all commands
    can be used. Hierarchy is USER > ROLE > CHANNEL > GUILD.
    0 is the default value
    1 is allowed
    -1 is not allowed
    """
    guild_id = 0
    role_ids = []
    if ctx.message.guild is not None:
        guild_id = ctx.message.guild.id
        role_ids = [role.id for role in ctx.message.author.roles]
    command_name = ctx.command.name
    if ctx.command.root_parent is not None:
        command_name = ctx.command.root_parent.name
    permission_level = SQLFunctions.get_command_level(command_name, ctx.message.author.id, role_ids, ctx.message.channel.id, guild_id, conn)
    return permission_level != -1
Beispiel #30
0
    async def statistics(self, ctx, user=None):
        """
        Used to call the statistics page of a user or of the server.
        The user parameter can be another user or "top" to get the top three users \
        of each category.
        """
        if ctx.invoked_subcommand is None:
            statistic_columns = {
                "MessagesSent": [],
                "MessagesDeleted": [],
                "MessagesEdited": [],
                "CharactersSent": [],
                "WordsSent": [],
                "SpoilersSent": [],
                "EmojisSent": [],
                "FilesSent": [],
                "FileSizeSent": [],
                "ImagesSent": [],
                "ReactionsAdded": [],
                "ReactionsRemoved": [],
                "ReactionsReceived": [],
                "ReactionsTakenAway": [],
                "VoteCount": []
            }

            for key in statistic_columns.keys():
                statistic_columns[key] = SQLFunctions.get_statistic_rows(
                    key, 5000, self.conn)
            if user is None:
                embed = await self.create_embed(ctx.message.author,
                                                statistic_columns)
                await ctx.send(embed=embed)
            else:
                try:
                    memberconverter = discord.ext.commands.MemberConverter()
                    member = await memberconverter.convert(ctx, user)
                except discord.ext.commands.errors.BadArgument:
                    await ctx.send(
                        "Invalid user. Mention the user for this to work.")
                    raise discord.ext.commands.errors.BadArgument
                embed = await self.create_embed(member, statistic_columns)
                await ctx.send(embed=embed)