Ejemplo n.º 1
0
async def test_explicit_initial_runs_tomorrow_multi():
    now = utils.utcnow()

    if not ((0, 4) < (now.hour, now.minute) < (23, 59)):
        await asyncio.sleep(5 * 60)  # sleep for 5 minutes

    now = utils.utcnow()

    # multiple times that are in the past for today
    times = []
    for _ in range(3):
        now -= datetime.timedelta(minutes=1)
        times.append(datetime.time(hour=now.hour, minute=now.minute))

    has_run = False

    async def inner():
        nonlocal has_run
        has_run = True

    # a loop that should have an initial run tomorrow
    loop = tasks.loop(time=times)(inner)

    loop.start()
    await asyncio.sleep(1)

    try:
        assert not has_run
    finally:
        loop.cancel()
Ejemplo n.º 2
0
async def test_explicit_initial_runs_tomorrow_single():
    now = utils.utcnow()

    if not ((0, 4) < (now.hour, now.minute) < (23, 59)):
        await asyncio.sleep(5 * 60)  # sleep for 5 minutes

    now = utils.utcnow()

    has_run = False

    async def inner():
        nonlocal has_run
        has_run = True

    time = utils.utcnow() - datetime.timedelta(minutes=1)

    # a loop that should have an initial run tomorrow
    loop = tasks.loop(time=datetime.time(hour=time.hour, minute=time.minute))(inner)

    loop.start()
    await asyncio.sleep(1)

    try:
        assert not has_run
    finally:
        loop.cancel()
Ejemplo n.º 3
0
    async def mod_loop(self):
        guild: Guild = self.bot.guilds[0]

        async for ban in await db.stream(filter_by(Ban, active=True)):
            if ban.days != -1 and utcnow() >= ban.timestamp + timedelta(
                    days=ban.days):
                await Ban.deactivate(ban.id)

                try:
                    user = await self.bot.fetch_user(ban.member)
                except NotFound:
                    user = ban.member, ban.member_name

                if isinstance(user, User):
                    try:
                        await guild.unban(user)
                    except Forbidden:
                        await send_alert(
                            guild,
                            t.cannot_unban_user_permissions(
                                user.mention, user.id))

                await send_to_changelog_mod(guild, None, Colors.unban,
                                            t.log_unbanned, user,
                                            t.log_unbanned_expired)

        mute_role: Optional[Role] = guild.get_role(await
                                                   RoleSettings.get("mute"))
        if mute_role is None:
            return

        try:
            check_role_assignable(mute_role)
        except CommandError:
            await send_alert(
                guild, t.cannot_assign_mute_role(mute_role, mute_role.id))
            return

        async for mute in await db.stream(filter_by(Mute, active=True)):
            if mute.days != -1 and utcnow() >= mute.timestamp + timedelta(
                    days=mute.days):
                if member := guild.get_member(mute.member):
                    await member.remove_roles(mute_role)
                else:
                    member = mute.member, mute.member_name

                await send_to_changelog_mod(guild, None, Colors.unmute,
                                            t.log_unmuted, member,
                                            t.log_unmuted_expired)
                await Mute.deactivate(mute.id)
Ejemplo n.º 4
0
async def create_and_start_event(bot: Bot):
    event_name = Plugin.get_cvar("qlx_discord_ext_event_name")
    for scheduled_event in bot.guilds[0].scheduled_events:
        if event_name in scheduled_event.name and scheduled_event.status == EventStatus.active:
            return

    event_location = Plugin.get_cvar("qlx_discord_ext_event_location")
    start_date = utcnow() + timedelta(seconds=1)
    end_date = utcnow() + timedelta(hours=8)
    await bot.guilds[0].create_scheduled_event(
        name=event_name,
        privacy_level=PrivacyLevel.guild_only,
        start_time=start_date,
        end_time=end_date,
        entity_type=EntityType.external,
        location=event_location)
Ejemplo n.º 5
0
 async def create(member_id: int, author_id: int, content: str) -> UserNote:
     row = UserNote(member_id=member_id,
                    author_id=author_id,
                    content=content,
                    timestamp=utcnow())
     await db.add(row)
     return row
Ejemplo n.º 6
0
    async def create_boss_embed(self, bangs=0, boss_message=None):
        boss_life = self.config()['required_bangs']

        new_embed = discord.Embed(
            title=random.choice([
                "A duck boss is here...", "A wild boss has appeared...",
                "A boss has spawned...", "KILL THE BOSS !",
                "Who wants some foie gras ?", "There is a Duck Boss nearby...",
                "You cannot sleep when enemies are nearby."
            ]),
            color=discord.Color.green(),
            description="React with 🔫 to kill it.",
        )

        new_embed.set_image(
            url=
            "https://media.discordapp.net/attachments/795225915248214036/795404123443953705/boss_Calgeka.png"
        )
        new_embed.add_field(name="Health",
                            value=f"{boss_life - bangs}/{boss_life}")
        if boss_message:
            time_delta = utcnow() - boss_message.created_at
            new_embed.set_footer(
                text=
                f"The boss spawned {format_timedelta(time_delta, locale='en_US')} ago"
            )
        else:
            new_embed.set_footer(text=f"The boss just spawned")

        return new_embed
Ejemplo n.º 7
0
 async def create(member_id: int, channel_id: int) -> DynChannelMember:
     member = DynChannelMember(id=str(uuid4()),
                               member_id=member_id,
                               channel_id=channel_id,
                               timestamp=utcnow())
     await db.add(member)
     return member
Ejemplo n.º 8
0
class HeartbeatCog(Cog, name="Heartbeat"):
    CONTRIBUTORS = [Contributor.Defelo, Contributor.wolflu]

    def __init__(self):
        super().__init__()

        self.initialized = False

    def get_owner(self) -> Optional[User]:
        return self.bot.get_user(OWNER_ID)

    @tasks.loop(seconds=20)
    async def status_loop(self):
        if (owner := self.get_owner()) is None:
            return
        try:
            await send_editable_log(
                owner,
                t.online_status,
                t.status_description(Config.NAME, Config.VERSION),
                t.heartbeat,
                format_dt(now := utcnow(), style="D") + " " +
                format_dt(now, style="T"),
            )
            Path("health").write_text(str(int(datetime.now().timestamp())))
        except Forbidden:
            pass
Ejemplo n.º 9
0
 async def create(member: int, member_name: str,
                  channel: int) -> MediaOnlyDeletion:
     row = MediaOnlyDeletion(member=member,
                             member_name=member_name,
                             timestamp=utcnow(),
                             channel=channel)
     await db.add(row)
     return row
Ejemplo n.º 10
0
 async def create(regex: str, description: str, delete: bool) -> BadWord:
     row = BadWord(regex=regex,
                   description=description,
                   delete=delete,
                   timestamp=utcnow())
     await db.add(row)
     await sync_redis()
     return row
Ejemplo n.º 11
0
 async def deactivate(mute_id: int,
                      unmute_mod: int = None,
                      reason: str = None) -> "Mute":
     row: Mute = await db.get(Mute, id=mute_id)
     row.active = False
     row.deactivation_timestamp = utcnow()
     row.unmute_mod = unmute_mod
     row.unmute_reason = reason
     return row
Ejemplo n.º 12
0
 async def create(member: int, member_name: str, mod: int,
                  reason: str) -> Warn:
     row = Warn(member=member,
                member_name=member_name,
                mod=mod,
                timestamp=utcnow(),
                reason=reason)
     await db.add(row)
     return row
Ejemplo n.º 13
0
 async def create(member: int, member_name: str, reporter: int,
                  reason: str) -> Report:
     row = Report(member=member,
                  member_name=member_name,
                  reporter=reporter,
                  timestamp=utcnow(),
                  reason=reason)
     await db.add(row)
     return row
Ejemplo n.º 14
0
 async def deactivate(ban_id: int,
                      unban_mod: int = None,
                      unban_reason: str = None) -> Ban:
     row: Ban = await db.get(Ban, id=ban_id)
     row.active = False
     row.deactivation_timestamp = utcnow()
     row.unban_mod = unban_mod
     row.unban_reason = unban_reason
     return row
Ejemplo n.º 15
0
 async def create(member: int, member_name: str, mod: Optional[int],
                  reason: Optional[str]) -> Kick:
     row = Kick(member=member,
                member_name=member_name,
                mod=mod,
                timestamp=utcnow(),
                reason=reason)
     await db.add(row)
     return row
Ejemplo n.º 16
0
 async def update_msg(m: Message, content):
     embed.description = content
     embed.timestamp = utcnow()
     await ignore_message_edit(m)
     try:
         await m.edit(embed=embed)
     except NotFound:
         return await reply(ctx, embed=embed)
     return m
Ejemplo n.º 17
0
 async def create(member: int, member_name: str, channel: int,
                  name: str) -> IllegalInvitePost:
     row = IllegalInvitePost(member=member,
                             member_name=member_name,
                             timestamp=utcnow(),
                             channel=channel,
                             name=name)
     await db.add(row)
     return row
Ejemplo n.º 18
0
 async def update_progress_message():
     while len(completed) < len(channels):
         content = t.scanning_channel(len(completed),
                                      len(channels),
                                      cnt=len(active))
         for a, d in active.items():
             channel_age = (utcnow() - a.created_at).days
             content += f"\n:small_orange_diamond: {a.mention} ({d} / {min(channel_age, days)})"
         message[0] = await update_msg(message[0], content)
         await asyncio.sleep(2)
Ejemplo n.º 19
0
 async def handle_get_user_status_entries(
         self, user_id: int) -> list[tuple[str, str]]:
     status = t.none
     if (ban := await db.get(Ban, member=user_id, active=True)) is not None:
         if ban.days != -1:
             expiry_date: datetime = ban.timestamp + timedelta(
                 days=ban.days)
             days_left = (expiry_date - utcnow()).days + 1
             status = t.status_banned_days(cnt=ban.days, left=days_left)
         else:
             status = t.status_banned
Ejemplo n.º 20
0
 async def create(guild_id: int, guild_name: str, applicant: int, mod: int,
                  approved: bool) -> InviteLog:
     row = InviteLog(
         guild_id=guild_id,
         guild_name=guild_name,
         applicant=applicant,
         mod=mod,
         timestamp=utcnow(),
         approved=approved,
     )
     await db.add(row)
     return row
Ejemplo n.º 21
0
 async def create(member: int, member_name: str, channel: int, content: str,
                  deleted: bool) -> BadWordPost:
     row = BadWordPost(
         member=member,
         member_name=member_name,
         channel=channel,
         content=content,
         deleted_message=deleted,
         timestamp=utcnow(),
     )
     await db.add(row)
     return row
Ejemplo n.º 22
0
def test_task_is_imaginary():
    import zoneinfo

    tz = zoneinfo.ZoneInfo('America/New_York')

    # 2:30 AM was skipped
    dt = datetime.datetime(2022, 3, 13, 2, 30, tzinfo=tz)
    assert tasks.is_imaginary(dt)

    now = utils.utcnow()
    # UTC time is never imaginary or ambiguous
    assert not tasks.is_imaginary(now)
Ejemplo n.º 23
0
def test_task_is_ambiguous():
    import zoneinfo

    tz = zoneinfo.ZoneInfo('America/New_York')

    # 1:30 AM happened twice
    dt = datetime.datetime(2022, 11, 6, 1, 30, tzinfo=tz)
    assert tasks.is_ambiguous(dt)

    now = utils.utcnow()
    # UTC time is never imaginary or ambiguous
    assert not tasks.is_imaginary(now)
Ejemplo n.º 24
0
 async def create(guild_id: int, code: str, guild_name: str, applicant: int,
                  approver: int) -> AllowedInvite:
     row = AllowedInvite(
         guild_id=guild_id,
         code=code,
         guild_name=guild_name,
         applicant=applicant,
         approver=approver,
         description=None,
         created_at=utcnow(),
     )
     await db.add(row)
     return row
Ejemplo n.º 25
0
    async def update_members(c: TextChannel):
        active[c] = 0

        async for msg in c.history(limit=None, oldest_first=False):
            s = (utcnow() - msg.created_at).total_seconds()
            if s > days * 24 * 60 * 60:
                break
            members[msg.author] = max(members.get(msg.author, msg.created_at),
                                      msg.created_at)
            active[c] = int(s / (24 * 60 * 60))

        del active[c]
        completed.append(c)
Ejemplo n.º 26
0
 async def on_ready(self):
     if (owner := self.get_owner()) is not None:
         try:
             await send_editable_log(
                 owner,
                 t.online_status,
                 t.status_description(Config.NAME, Config.VERSION),
                 t.logged_in,
                 format_dt(now := utcnow(), style="D") + " " +
                 format_dt(now, style="T"),
                 force_resend=True,
                 force_new_embed=not self.initialized,
             )
         except Forbidden:
             pass
Ejemplo n.º 27
0
    async def handle_get_user_status_entries(self,
                                             user_id) -> list[tuple[str, str]]:
        inactive_days = await InactivitySettings.inactive_days.get()

        activity: Optional[Activity] = await db.get(Activity, id=user_id)

        if activity is None:
            status = t.status.inactive
        elif (utcnow() - activity.timestamp).days >= inactive_days:
            status = t.status.inactive_since(
                format_dt(activity.timestamp, style="R"))
        else:
            status = t.status.active(format_dt(activity.timestamp, style="R"))

        return [(t.activity, status)]
Ejemplo n.º 28
0
async def send_poll(ctx: Context,
                    title: str,
                    args: str,
                    field: Optional[Tuple[str, str]] = None,
                    allow_delete: bool = True):
    question, *options = [
        line.replace("\x00", "\n")
        for line in args.replace("\\\n", "\x00").split("\n") if line
    ]

    if not options:
        raise CommandError(t.missing_options)
    if len(options) > MAX_OPTIONS - allow_delete:
        raise CommandError(t.too_many_options(MAX_OPTIONS - allow_delete))

    options = [PollOption(ctx, line, i) for i, line in enumerate(options)]

    if any(len(str(option)) > EmbedLimits.FIELD_VALUE for option in options):
        raise CommandError(t.option_too_long(EmbedLimits.FIELD_VALUE))

    embed = Embed(title=title,
                  description=question,
                  color=Colors.Polls,
                  timestamp=utcnow())
    embed.set_author(name=str(ctx.author),
                     icon_url=ctx.author.display_avatar.url)
    if allow_delete:
        embed.set_footer(text=t.created_by(ctx.author, ctx.author.id),
                         icon_url=ctx.author.display_avatar.url)

    if len(set(map(lambda x: x.emoji, options))) < len(options):
        raise CommandError(t.option_duplicated)

    for option in options:
        embed.add_field(name="** **", value=str(option), inline=False)

    if field:
        embed.add_field(name=field[0], value=field[1], inline=False)

    poll: Message = await ctx.send(embed=embed)

    try:
        for option in options:
            await poll.add_reaction(option.emoji)
        if allow_delete:
            await poll.add_reaction(name_to_emoji["wastebasket"])
    except Forbidden:
        raise CommandError(t.could_not_add_reactions(ctx.channel.mention))
Ejemplo n.º 29
0
    async def cleanup_loop(self):
        days: int = await LoggingSettings.maxage.get()
        if days == -1:
            return

        timestamp = utcnow() - timedelta(days=days)
        for setting in [
                LoggingSettings.edit_channel, LoggingSettings.delete_channel
        ]:
            channel: Optional[TextChannel] = await self.get_logging_channel(
                setting)
            if channel is None:
                continue

            async for message in channel.history(
                    limit=None, oldest_first=True):  # type: Message
                if message.created_at > timestamp:
                    break

                await message.delete()
Ejemplo n.º 30
0
async def send_to_changelog_mod(
    guild: Guild,
    message: Optional[Message],
    colour: int,
    title: str,
    member: Union[Member, User, Tuple[int, str]],
    reason: str,
    *,
    duration: Optional[str] = None,
):
    embed = Embed(title=title, colour=colour, timestamp=utcnow())

    if isinstance(member, tuple):
        member_id, member_name = member
        embed.set_author(name=member_name)
    else:
        member_id: int = member.id
        member_name: str = str(member)
        embed.set_author(name=member_name, icon_url=member.display_avatar.url)

    embed.add_field(name=t.log_field.member,
                    value=f"<@{member_id}>",
                    inline=True)
    embed.add_field(name=t.log_field.member_id,
                    value=str(member_id),
                    inline=True)

    if message:
        embed.set_footer(text=str(message.author),
                         icon_url=message.author.display_avatar.url)
        embed.add_field(name=t.log_field.channel,
                        value=t.jump_url(message.channel.mention,
                                         message.jump_url),
                        inline=True)

    if duration:
        embed.add_field(name=t.log_field.duration, value=duration, inline=True)

    embed.add_field(name=t.log_field.reason, value=reason, inline=False)

    await send_to_changelog(guild, embed)