Example #1
0
 async def remind(
         self, ctx, execute_at: interpret_str_as_datetime, *,
         content: commands.clean_content(fix_channel_mentions=True)
 ):
     if len(content) > Reminder.MAX_CONTENT_LENGTH:
         raise commands.BadArgument
     description = (
         f'**Przypomnę ci tutaj "{content}" {human_datetime(execute_at)}.**\n*Przypomnienie zostanie anulowane '
         'jeśli usuniesz tę wiadomość. Możesz to zrobić przy użyciu komendy `nie`.*'
     )
     embed = self.bot.generate_embed('🍅', 'Ustawiono przypomnienie', description)
     confirmation_message = await self.bot.send(ctx, embed=embed)
     if confirmation_message is None:
         return
     try:
         details = {
             'confirmation_message_id': confirmation_message.id, 'channel_id': ctx.channel.id, 'content': content,
             'user_id': ctx.author.id, 'requested_at': utc_to_naive_local(ctx.message.created_at),
             'execute_at': execute_at
         }
         with data.session(commit=True) as session:
             reminder = Reminder(**details)
             session.add(reminder)
             self.bot.loop.create_task(self.set_off_reminder(**details))
     except:
         await confirmation_message.delete()
         raise
Example #2
0
 async def on_ready(self):
     psutil.cpu_percent()
     localize()
     self.ready_datetime = dt.datetime.now()
     self.session = aiohttp.ClientSession(loop=self.loop, headers=self.HEADERS)
     self.ch_client = ChClient(
         self.session,
         url=configuration["clickhouse_url"],
         user=configuration["clickhouse_user"],
         password=configuration["clickhouse_password"],
         database="somsiad",
     )
     assert await self.ch_client.is_alive()
     print('Przygotowywanie danych serwerów...')
     data.Server.register_all(self.guilds)
     with data.session(commit=True) as session:
         for server in session.query(data.Server):
             self.prefixes[server.id] = tuple(server.command_prefix.split('|')) if server.command_prefix else ()
             if server.joined_at is None:
                 discord_server = self.get_guild(server.id)
                 if discord_server is not None and discord_server.me is not None:
                     server.joined_at = utc_to_naive_local(discord_server.me.joined_at)
     self.system_channel = cast(Optional[discord.TextChannel], await self.fetch_channel(517422572615499777))  # magic
     self.public_channel = cast(Optional[discord.TextChannel], await self.fetch_channel(479458695126974466))  # magic
     self.loop.create_task(self.cycle_presence())
     await self.system_notify('✅', 'Włączyłem się')
     self.print_info()
Example #3
0
 async def burn(self, ctx, execute_at: interpret_str_as_datetime):
     """Removes the message after a specified mount time."""
     confirmation_description = (
         md_link(f'**Zostanie ona usunięta {human_datetime(execute_at)}.**',
                 ctx.message.jump_url) +
         '\n*Spalenie zostanie anulowane jeśli usuniesz tę wiadomość. Możesz to zrobić przy użyciu komendy `nie`.*'
     )
     confirmation_embed = self.bot.generate_embed('🔥',
                                                  f'Spalę twoją wiadomość',
                                                  confirmation_description)
     confirmation_message = await self.bot.send(ctx,
                                                embed=confirmation_embed)
     if confirmation_message is None:
         return
     try:
         details = {
             'confirmation_message_id': confirmation_message.id,
             'target_message_id': ctx.message.id,
             'channel_id': ctx.channel.id,
             'user_id': ctx.author.id,
             'requested_at': utc_to_naive_local(ctx.message.created_at),
             'execute_at': execute_at,
         }
         with data.session(commit=True) as session:
             reminder = Burning(**details)
             session.add(reminder)
             self.bot.loop.create_task(self.set_off_burning(**details))
     except:
         await confirmation_message.delete()
         raise
Example #4
0
 async def on_message(self, message: discord.Message):
     if not message.attachments or message.guild is None:
         return
     images9000 = []
     for attachment in message.attachments:
         if attachment.height and attachment.width:
             image_bytes = io.BytesIO()
             try:
                 await attachment.save(image_bytes)
             except (discord.HTTPException, discord.NotFound):
                 continue
             else:
                 try:
                     hash_string = self._hash(image_bytes)
                 except:
                     continue
                 images9000.append(
                     Image9000(
                         attachment_id=attachment.id,
                         message_id=message.id,
                         user_id=message.author.id,
                         channel_id=message.channel.id,
                         server_id=message.guild.id,
                         hash=hash_string,
                         sent_at=utc_to_naive_local(message.created_at),
                     ))
     try:
         with data.session(commit=True) as session:
             session.bulk_save_objects(images9000)
     except (psycopg2.errors.ForeignKeyViolation,
             psycopg2.errors.UniqueViolation):
         pass
Example #5
0
 async def on_command(self, ctx: commands.Context):
     with data.session(commit=True) as session:
         invocation = Invocation(
             message_id=ctx.message.id,
             server_id=ctx.guild.id if ctx.guild is not None else None,
             channel_id=ctx.channel.id,
             user_id=ctx.author.id,
             prefix=ctx.prefix,
             full_command=ctx.command.qualified_name,
             root_command=str(ctx.command.root_parent
                              or ctx.command.qualified_name),
             created_at=utc_to_naive_local(ctx.message.created_at))
         session.add(invocation)
Example #6
0
 async def vote(
         self,
         ctx,
         conclude_at: Optional[interpret_str_as_datetime] = None,
         *,
         matter: commands.clean_content(fix_channel_mentions=True),
 ):
     if len(matter) > Ballot.MAX_MATTER_LENGTH:
         raise commands.BadArgument
     letters = ''.join(
         {match[0]: None
          for match in self.LETTER_REGEX.findall(matter)})
     if len(letters) < 2:
         letters = None
     description = 'Zagłosuj w tej sprawie przy użyciu reakcji.'
     if conclude_at is not None:
         description += (
             f'\n**Wyniki zostaną ogłoszone {human_datetime(conclude_at)}.**\n*Ogłoszenie wyników zostanie '
             'anulowane jeśli usuniesz tę wiadomość. Możesz to zrobić przy użyciu komendy `nie`.*'
         )
     embed = self.bot.generate_embed('🗳', matter, description)
     urn_message = await self.bot.send(ctx, embed=embed)
     if urn_message is None:
         return
     options = ('👍', '👎') if letters is None else tuple(
         map(self.LETTER_EMOJIS.get, letters))
     try:
         for option in options:
             await urn_message.add_reaction(option)
         details = {
             'urn_message_id': urn_message.id,
             'channel_id': ctx.channel.id,
             'matter': matter,
             'letters': letters,
             'user_id': ctx.author.id,
             'commenced_at': utc_to_naive_local(ctx.message.created_at),
             'conclude_at': conclude_at,
         }
         if conclude_at is not None:
             with data.session(commit=True) as session:
                 reminder = Ballot(**details)
                 session.add(reminder)
                 self.bot.loop.create_task(self.set_off_ballot(**details))
     except discord.Forbidden:
         await urn_message.delete()
         embed = self.bot.generate_embed(
             '⚠️', 'Bot nie ma uprawnień do dodawania reakcji')
     except:
         await urn_message.delete()
         raise
Example #7
0
 async def _update_metadata_cache(self, channel: discord.TextChannel, session: data.RawSession):
     try:
         self.relevant_channel_stats[channel.id] = self.relevant_channel_stats.default_factory()
         relevant_message_metadata = session.query(MessageMetadata).filter(
             MessageMetadata.channel_id == channel.id
         ).order_by(MessageMetadata.id.desc())
         last_cached_message_metadata = relevant_message_metadata.first()
         if last_cached_message_metadata is not None:
             after = discord.utils.snowflake_time(last_cached_message_metadata.id)
         else:
             after = None
         metadata_cache_update = []
         async for message in channel.history(limit=None, after=after):
             if message.type == discord.MessageType.default:
                 message_datetime = utc_to_naive_local(message.created_at)
                 content_parts = [message.clean_content]
                 for embed in message.embeds:
                     content_parts.append(embed.title)
                     content_parts.append(embed.description)
                     for field in embed.fields:
                         content_parts.append(field.name)
                         content_parts.append(field.value)
                     if embed.footer:
                         content_parts.append(embed.footer.text)
                     if embed.author:
                         content_parts.append(embed.author.text)
                 content = ' '.join(filter(None, content_parts))
                 message_metadata = MessageMetadata(
                     id=message.id, server_id=message.guild.id, channel_id=channel.id, user_id=message.author.id,
                     word_count=len(content.split()), character_count=len(content),
                     hour=message_datetime.hour, weekday=message_datetime.weekday(),
                     datetime=message_datetime
                 )
                 metadata_cache_update.append(message_metadata)
                 self.messages_cached += 1
                 if self.messages_cached % 10_000 == 0:
                     await self._send_or_update_progress()
                 if len(metadata_cache_update) % self.STEP == 0:
                     metadata_cache_update.reverse()
                     session.bulk_save_objects(metadata_cache_update)
                     session.commit()
                     metadata_cache_update = []
         metadata_cache_update.reverse()
         session.bulk_save_objects(metadata_cache_update)
         session.commit()
Example #8
0
 async def on_ready(self):
     psutil.cpu_percent()
     localize()
     self.run_datetime = dt.datetime.now()
     self.session = aiohttp.ClientSession(loop=self.loop,
                                          headers=self.HEADERS)
     print('Przygotowywanie danych serwerów...')
     data.Server.register_all(self.guilds)
     with data.session(commit=True) as session:
         for server in session.query(data.Server):
             self.prefixes[server.id] = tuple(
                 server.command_prefix.split(
                     '|')) if server.command_prefix else ()
             if server.joined_at is None:
                 discord_server = self.get_guild(server.id)
                 if discord_server is not None and discord_server.me is not None:
                     server.joined_at = utc_to_naive_local(
                         discord_server.me.joined_at)
     self.loop.create_task(self.cycle_presence())
     self.print_info()
Example #9
0
    def _plot_activity_by_channel(self, ax):
        # plot the chart
        channels = [self.ctx.bot.get_channel(channel) for channel in self.relevant_channel_stats]
        channel_names = [f'#{channel}' for channel in channels]
        channel_existence_lengths = (
            (self.timeframe_end_date - utc_to_naive_local(channel.created_at).date()).days + 1 for channel in channels
        )
        if self.last_days:
            channel_existence_lengths = (
                min(self.last_days, channel_existence_length) for channel_existence_length in channel_existence_lengths
            )
        average_daily_message_counts = [
            channel_stats['message_count'] / channel_existence_length for channel_stats, channel_existence_length
            in zip(self.relevant_channel_stats.values(), channel_existence_lengths)
        ]
        ax.bar(
            channel_names,
            average_daily_message_counts,
            color=self.BACKGROUND_COLOR,
            facecolor=self.FOREGROUND_COLOR,
            width=1
        )

        # set proper X axis formatting
        ax.set_xlim(-0.5, len(channel_names)-0.5)
        ax.set_xticklabels(channel_names, rotation=30, ha='right')

        # set proper ticker intervals on the Y axis accounting for the maximum number of messages
        ax.yaxis.set_major_locator(ticker.MaxNLocator(nbins='auto', steps=[10], integer=True))
        if max(average_daily_message_counts) >= 10:
            ax.yaxis.set_minor_locator(ticker.AutoMinorLocator(n=10))

        # make it look nice
        ax.set_facecolor(self.BACKGROUND_COLOR)
        ax.set_xlabel('Kanał', color=self.FOREGROUND_COLOR, fontsize=11, fontweight='bold')
        ax.set_ylabel(
            'Średnio wysłanych\nwiadomości dziennie', color=self.FOREGROUND_COLOR, fontsize=11, fontweight='bold'
        )

        return ax
Example #10
0
 async def _fill_in_details(self):
     timeframe_start_date_utc = None
     if self.user_by_id:
         try:
             self.subject = await self.ctx.bot.fetch_user(self.subject_id)
         except discord.NotFound:
             self.type = self.Type.DELETED_USER
             self._generate_relevant_embed = self._generate_deleted_user_embed
         else:
             self.type = self.Type.USER
             self._generate_relevant_embed = self._generate_user_embed
     elif isinstance(self.subject, discord.Guild):
         self.type = self.Type.SERVER
         self._generate_relevant_embed = self._generate_server_embed
         timeframe_start_date_utc = self.subject.created_at
     elif isinstance(self.subject, discord.TextChannel):
         self.type = self.Type.CHANNEL
         # raise an exception if the requesting user doesn't have access to the channel
         if not self.subject.permissions_for(self.ctx.author).read_messages:
             raise commands.BadArgument
         self._generate_relevant_embed = self._generate_channel_embed
         timeframe_start_date_utc = self.subject.created_at
     elif isinstance(self.subject, discord.CategoryChannel):
         self.type = self.Type.CATEGORY
         # raise an exception if the requesting user doesn't have access to the channel
         if not self.subject.permissions_for(self.ctx.author).read_messages:
             raise commands.BadArgument
         self._generate_relevant_embed = self._generate_category_embed
         timeframe_start_date_utc = self.subject.created_at
     elif isinstance(self.subject, discord.Member):
         self.type = self.Type.MEMBER
         self._generate_relevant_embed = self._generate_member_embed
         timeframe_start_date_utc = self.subject.joined_at
     elif isinstance(self.subject, discord.User):
         self.type = self.Type.USER
         self._generate_relevant_embed = self._generate_user_embed
     if timeframe_start_date_utc is not None:
         self.timeframe_start_date = utc_to_naive_local(timeframe_start_date_utc).date()