Exemple #1
0
    async def news_auth_add(self, ctx: Context, user: Member,
                            channel: TextChannel,
                            notification_role: Optional[Role]):
        """
        authorize a new user to send news to a specific channel
        """

        if await db.exists(
                select(NewsAuthorization).filter_by(user_id=user.id,
                                                    channel_id=channel.id)):
            raise CommandError(t.news_already_authorized)
        if not channel.permissions_for(channel.guild.me).send_messages:
            raise CommandError(t.news_not_added_no_permissions)

        role_id = notification_role.id if notification_role is not None else None

        await NewsAuthorization.create(user.id, channel.id, role_id)
        embed = Embed(title=t.news,
                      colour=Colors.News,
                      description=t.news_authorized)
        await reply(ctx, embed=embed)
        await send_to_changelog(
            ctx.guild, t.log_news_authorized(user.mention, channel.mention))
Exemple #2
0
 async def disallow(self, ctx, role: DiscordRole):
     session = Session()
     obj = to_sql(session, role, Role)
     data = self.get_data(obj, DEFAULT_ROLE_DATA)
     if data:
         self.set_data(session, obj, False)
         session.close()
         embed = generate_embed_template(ctx,
                                         'Role Disallowed Successfully')
         embed.description = str(role)
         await ctx.send(embed=embed)
         return
     session.close()
     raise CommandError('Role `{}` is already disallowed'.format(str(role)))
Exemple #3
0
    async def reactionpin_add(self, ctx: Context, channel: TextChannel):
        """
        add channel to whitelist
        """

        if await db_thread(db.get, ReactionPinChannel, channel.id) is not None:
            raise CommandError(translations.channel_already_whitelisted)

        await db_thread(ReactionPinChannel.create, channel.id)
        embed = Embed(
            title=translations.reactionpin, colour=Colours.ReactionPin, description=translations.channel_whitelisted
        )
        await ctx.send(embed=embed)
        await send_to_changelog(ctx.guild, translations.f_log_channel_whitelisted_rp(channel.mention))
Exemple #4
0
    async def logging_maxage(self, ctx: Context, days: int):
        if days != -1 and not 0 < days < (1 << 31):
            raise CommandError(tg.invalid_duration)

        await LoggingSettings.maxage.set(days)
        embed = Embed(title=t.logging, color=Colors.Logging)
        if days == -1:
            embed.description = t.maxage_set_disabled
            await send_to_changelog(ctx.guild, t.maxage_set_disabled)
        else:
            embed.description = t.maxage_set(cnt=days)
            await send_to_changelog(ctx.guild, t.maxage_set(cnt=days))

        await reply(ctx, embed=embed)
    async def add_channel(self, ctx: Context, channel: TextChannel):
        """
        add channel to whitelist
        """

        if await run_in_thread(db.get, ReactionPinChannel,
                               channel.id) is not None:
            raise CommandError(translations.channel_already_whitelisted)

        await run_in_thread(ReactionPinChannel.create, channel.id)
        await ctx.send(translations.channel_whitelisted)
        await send_to_changelog(
            ctx.guild,
            translations.f_log_channel_whitelisted_rp(channel.mention))
Exemple #6
0
    async def permissions_set(self, ctx: Context, permission_name: str,
                              level: PermissionLevelConverter):
        level: BasePermissionLevel
        for permission in get_permissions():
            if permission.fullname.lower() == permission_name.lower():
                break
        else:
            raise CommandError(t.invalid_permission)

        max_level: BasePermissionLevel = await Config.PERMISSION_LEVELS.get_permission_level(
            ctx.author)
        if max(level.level,
               (await permission.resolve()).level) > max_level.level:
            raise CommandError(t.cannot_manage_permission_level)

        await permission.set(level)

        description = permission.fullname, level.description
        embed = Embed(title=t.permissions_title,
                      colour=Colors.Permissions,
                      description=t.permission_set(*description))
        await reply(ctx, embed=embed)
        await send_to_changelog(ctx.guild, t.log_permission_set(*description))
Exemple #7
0
    async def aoc_role_rank(self, ctx: Context, rank: int):
        """
        set the minimum rank users need to get the role
        """

        if not 1 <= rank <= 200:
            raise CommandError(t.invalid_rank)

        await AdventOfCodeSettings.rank.set(rank)
        await self.update_roles(await
                                AOCConfig.get_leaderboard(disable_hook=True))

        await reply(ctx, t.rank_set)
        await send_to_changelog(ctx.guild, t.log_rank_set(rank))
Exemple #8
0
    async def send_discohook(self, ctx: Context, channel: TextChannel, *, discohook_url: str):
        try:
            messages: list[MessageContent] = [
                msg for msg in await load_discohook_link(discohook_url) if not msg.is_empty
            ]
        except DiscoHookError:
            raise CommandError(t.discohook_invalid)

        if not messages:
            raise CommandError(t.discohook_empty)

        check_message_send_permissions(channel, check_embed=any(m.embeds for m in messages))

        try:
            for message in messages:
                content: str | None = message.content
                for embed in message.embeds or [None]:
                    await channel.send(content=content, embed=embed)
                    content = None
        except (HTTPException, Forbidden):
            raise CommandError(t.msg_could_not_be_sent)

        await add_reactions(ctx.message, "white_check_mark")
async def auth_add(ctx: Context, *, role: Role):
    """
    authorize role to control this bot
    """

    authorization: Optional[AuthorizedRole] = await run_in_thread(
        db.get, AuthorizedRole, role.id)
    if authorization is not None:
        raise CommandError(translations.f_already_authorized(role))

    await run_in_thread(AuthorizedRole.create, role.id)
    await ctx.send(translations.f_role_authorized(role))
    await send_to_changelog(ctx.guild,
                            translations.f_log_role_authorized(role))
Exemple #10
0
 async def prepare_player(self, ctx: Context) -> Any:
     """Ensure that the user can run these commands."""
     if ctx.voice_client is None:
         if ctx.author.voice:
             await ctx.author.voice.channel.connect()
         else:
             return await ctx.send("You are not connected to a voice channel!")
             raise CommandError("User is not connected to a voice channel.")
     elif ctx.author.voice and ctx.author.voice.channel != ctx.voice_client.channel:
         await self.save_quit_player(ctx.voice_client, ctx.guild.id)
         await self.join_continue_player(ctx.author.voice.channel)
     elif ctx.voice_client.is_playing():
         self.players[ctx.guild.id].seconds = time() - ctx.voice_client.started
         ctx.voice_client.stop()
Exemple #11
0
    async def invites_add(self, ctx: Context, invite: Invite,
                          applicant: Member):
        """
        allow a new discord server
        """

        if invite.guild is None:
            raise CommandError(translations.invalid_invite)

        guild: Guild = invite.guild
        if await db_thread(db.get, AllowedInvite, guild.id) is not None:
            raise CommandError(translations.server_already_whitelisted)

        await db_thread(AllowedInvite.create, guild.id, invite.code,
                        guild.name, applicant.id, ctx.author.id)
        await db_thread(InviteLog.create, guild.id, guild.name, applicant.id,
                        ctx.author.id, True)
        embed = Embed(title=translations.invites,
                      description=translations.server_whitelisted,
                      color=Colours.AllowedInvites)
        await ctx.send(embed=embed)
        await send_to_changelog(
            ctx.guild, translations.f_log_server_whitelisted(guild.name))
    async def verification_password(self, ctx: Context, *, password: str):
        """
        configure verification password
        """

        if len(password) > 256:
            raise CommandError(translations.password_too_long)

        await run_in_thread(Settings.set, str, "verification_password",
                            password)
        await ctx.send(translations.verification_password_configured)
        await send_to_changelog(
            ctx.guild,
            translations.f_log_verification_password_configured(password))
Exemple #13
0
 async def walk(self, data, curr, path: typing.List[str], ctx: Context):
     if len(path) == 0:
         return curr
     if curr == 'Boolean' or curr == 'String':
         await self.bot.add_reaction(ctx.message, u'❌')
         return None
     if 'Compound' in curr:
         cpd = data['compound_arena'][curr['Compound']]
         if path[0] in cpd['fields']:
             return await self.walk(data, cpd['fields'][path[0]]['nbttype'],
                                    path[1:], ctx)
         else:
             if 'supers' in cpd:
                 if cpd['supers'] == None:
                     return None
                 if 'Compound' in cpd['supers']:
                     return await self.walk(
                         data, {'Compound': cpd['supers']['Compound']},
                         path, ctx)
                 elif 'Registry' in cpd['supers']:
                     return await self.walk(
                         data, {
                             'Compound':
                             data.registries[cpd['supers']['Registry']
                                             ['target']][1]
                         }, path, ctx)
                 else:
                     # This shouldn't happen
                     raise CommandError('Unknown key in {}'.format(
                         cpd.supers))
             else:
                 await self.bot.add_reaction(ctx.message, u'🤷')
                 return None
     elif 'List' in curr:
         return await self.walk(data, curr['List']['value_type'], path, ctx)
     elif 'Index' in curr:
         return await self.walk(
             data, data['compound_arena'][data['registries'][
                 cpd['supers']['Registry']['target']][1]], path, ctx)
     elif 'Or' in curr:
         for v in curr['Or']:
             val = await self.walk(data, v, path, ctx)
             if val:
                 return val
         await self.bot.add_reaction(ctx.message, u'❌')
         return None
     else:
         await self.bot.add_reaction(ctx.message, u'❌')
         return None
Exemple #14
0
    async def unregister_role(self, ctx: Context, *, topics: str):
        """
        delete one or more topics
        """

        guild: Guild = ctx.guild
        roles: List[Role] = []
        btp_roles: List[BTPRole] = []
        names = split_topics(topics)
        if not names:
            await ctx.send_help(self.register_role)
            return
        for topic in names:
            for role in guild.roles:
                if role.name.lower() == topic.lower():
                    break
            else:
                raise CommandError(translations.f_topic_not_registered(topic))
            if (btp_role := await run_in_thread(db.get, BTPRole,
                                                role.id)) is None:
                raise CommandError(translations.f_topic_not_registered(topic))

            roles.append(role)
            btp_roles.append(btp_role)
Exemple #15
0
    async def autokick_delay(self, ctx: Context, seconds: int):
        """
        configure autokick delay (in seconds)
        """

        if not 0 < seconds < 300:
            raise CommandError(translations.invalid_duration)

        await Settings.set(int, "autokick_delay", seconds)
        embed = Embed(title=translations.autokick,
                      description=translations.autokick_delay_configured,
                      colour=Colours.AutoMod)
        await ctx.send(embed=embed)
        await send_to_changelog(
            ctx.guild, translations.f_log_autokick_delay_configured(seconds))
Exemple #16
0
    async def clear(self, ctx: Context, count: int):
        channel: TextChannel = ctx.channel

        if count not in range(1, 101):
            raise CommandError(t.count_between)

        if not await Confirmation().run(ctx, t.confirm(channel.mention, cnt=count)):
            return

        messages = (await channel.history(limit=count + 2).flatten())[2:]
        try:
            await channel.delete_messages(messages)
        except (Forbidden, NotFound, HTTPException):
            raise CommandError(t.msg_not_deleted)

        await reply(
            ctx,
            embed=Embed(
                title=t.clear_channel,
                description=t.deleted_messages(channel.mention, cnt=count),
                color=Colors.MessageCommands,
            ),
        )
        await send_alert(ctx.guild, t.log_cleared(ctx.author.mention, channel.mention, cnt=count))
Exemple #17
0
async def parse_topics(guild: Guild, topics: str,
                       author: Member) -> List[Role]:
    roles: List[Role] = []
    all_topics: List[Role] = await list_topics(guild)
    for topic in split_topics(topics):
        for role in guild.roles:
            if role.name.lower() == topic.lower():
                if role in all_topics:
                    break
                if not role.managed and role > guild.me.top_role:
                    raise CommandError(
                        translations.f_youre_not_the_first_one(
                            topic, author.mention))
        else:
            if all_topics:
                best_match = min((r.name for r in all_topics),
                                 key=lambda a: calculate_edit_distance(
                                     a.lower(), topic.lower()))
                raise CommandError(
                    translations.f_topic_not_found_did_you_mean(
                        topic, best_match))
            raise CommandError(translations.f_topic_not_found(topic))
        roles.append(role)
    return roles
Exemple #18
0
    async def remove(self, ctx: Context, member: Member):
        """
        remove a member from a private voice channel
        """

        _, _, voice_channel, text_channel = await self.get_dynamic_voice_channel(
            ctx.author, True)
        if member in (ctx.author, self.bot.user):
            raise CommandError(translations.cannot_remove_member)

        await voice_channel.set_permissions(member, overwrite=None)
        team_role = await run_in_thread(Settings.get, int, "team_role")
        if member.guild_permissions.administrator or any(
                role.id == team_role for role in member.roles):
            raise CommandError(translations.member_could_not_be_kicked)

        if member.voice is not None and member.voice.channel == voice_channel:
            await member.move_to(None)
        if text_channel is not None:
            await text_channel.send(
                translations.f_user_removed_from_private_voice(member.mention))
        if text_channel != ctx.channel:
            await ctx.send(
                translations.user_removed_from_private_voice_response)
Exemple #19
0
    async def logging_exclude_add(self, ctx: Context, channel: TextChannel):
        """
        exclude a channel from logging
        """

        if await db_thread(LogExclude.exists, channel.id):
            raise CommandError(translations.already_excluded)

        await db_thread(LogExclude.add, channel.id)
        embed = Embed(title=translations.excluded_channels,
                      description=translations.excluded,
                      colour=Colours.Logging)
        await ctx.send(embed=embed)
        await send_to_changelog(ctx.guild,
                                translations.f_log_excluded(channel.mention))
Exemple #20
0
    async def logging_edit_mindist(self, ctx: Context, mindist: int):
        """
        change the minimum edit distance between the old and new content of the message to be logged
        """

        if mindist <= 0:
            raise CommandError(translations.min_diff_gt_zero)

        await Settings.set(int, "logging_edit_mindiff", mindist)
        embed = Embed(title=translations.logging,
                      description=translations.f_edit_mindiff_updated(mindist),
                      color=Colours.Logging)
        await ctx.send(embed=embed)
        await send_to_changelog(ctx.guild,
                                translations.f_log_mindiff_updated(mindist))
Exemple #21
0
    async def user_notes_remove(self, ctx: Context, note_id: int):
        user_note: Optional[UserNote] = await db.get(UserNote, id=note_id)
        if not user_note:
            raise CommandError(t.note_not_found)

        if not await Confirmation().run(
                ctx, t.confirm(f"<@{user_note.member_id}>",
                               user_note.content)):
            return

        await db.delete(user_note)
        await send_to_changelog(
            ctx.guild,
            t.removed_note(ctx.author.mention, f"<@{user_note.member_id}>",
                           user_note.content))
Exemple #22
0
    async def regex(self, ctx: Context, pattern: ContentFilterConverter, *,
                    new_regex: RegexConverter):
        pattern: BadWord
        new_regex: str

        if await db.exists(filter_by(BadWord, regex=new_regex)):
            raise CommandError(t.already_blacklisted)

        old = pattern.regex
        pattern.regex = new_regex
        await sync_redis()

        await add_reactions(ctx.message, "white_check_mark")
        await send_to_changelog(ctx.guild,
                                t.log_regex_updated(old, pattern.regex))
 async def convert(self, ctx, argument):
     parser_settings = {
         "RETURN_AS_TIMEZONE_AWARE": True,
         "PREFER_DATES_FROM": "future",
         "TIMEZONE": "CET"
     }
     argument = argument.replace('for', 'in')
     argument = argument.replace('voor', 'over')
     argument = argument.replace('tot', 'om')
     try:
         date = parse(argument,
                      languages=['en', 'nl'],
                      settings=parser_settings)
     except Exception as e:
         raise CommandError(e)
     tz = timezone('Europe/Amsterdam')
     if date <= datetime.now(tz=tz):
         if ':' in argument:
             date = date + timedelta(days=1)
         else:
             date = datetime.now(tz=tz) + (datetime.now(tz=tz) - date)
     if not date:
         raise CommandError("Invalid Date")
     return date
Exemple #24
0
    async def verification_password(self, ctx: Context, *, password: str):
        """
        configure verification password
        """

        if len(password) > 256:
            raise CommandError(t.password_too_long)

        await VerificationSettings.password.set(password)
        embed = Embed(title=t.verification,
                      description=t.verification_password_configured,
                      colour=Colors.Verification)
        await reply(ctx, embed=embed)
        await send_to_changelog(
            ctx.guild, t.log_verification_password_configured(password))
Exemple #25
0
    async def logging_exclude_remove(self, ctx: Context, channel: TextChannel):
        """
        remove a channel from exclude list
        """

        if not await db_thread(LogExclude.exists, channel.id):
            raise CommandError(translations.not_excluded)

        await db_thread(LogExclude.remove, channel.id)
        embed = Embed(title=translations.excluded_channels,
                      description=translations.unexcluded,
                      colour=Colours.Logging)
        await ctx.send(embed=embed)
        await send_to_changelog(ctx.guild,
                                translations.f_log_unexcluded(channel.mention))
Exemple #26
0
    async def cleverbot_add(self, ctx: Context, channel: TextChannel):
        """
        add channel to whitelist
        """

        if await db.get(CleverBotChannel, channel=channel.id) is not None:
            raise CommandError(t.channel_already_whitelisted)

        await CleverBotChannel.create(channel.id)
        embed = Embed(title=t.cleverbot,
                      description=t.channel_whitelisted,
                      colour=Colors.CleverBot)
        await reply(ctx, embed=embed)
        await send_to_changelog(ctx.guild,
                                t.log_channel_whitelisted(channel.mention))
Exemple #27
0
    async def report(self, ctx: Context, member: Member, *, reason: str):
        """
        report a member
        """

        if len(reason) > 900:
            raise CommandError(translations.reason_too_long)

        await run_in_thread(Report.create, member.id, str(member),
                            ctx.author.id, reason)
        await ctx.send(translations.reported_response)
        await send_to_changelog(
            ctx.guild,
            translations.f_log_reported(ctx.author.mention, member.mention,
                                        member, reason))
Exemple #28
0
def query_mc_server(*, server_ip: str, port: int = 25565) -> dict:
    """Gets information from a minecraft server

	Keyword Arguments
	----------
	ip = ip: str
		The IP of the server to query

	port = 25565 : int, optional
		The port of the server to query, by default 25565

	Returns
	-------
	serverinfo : dict
		Structured below:

		{
		  "MaxPlayers": int,
		  "MOTD": str,
		  "Playerlist": list,
		  "Players": int,
		  "Plugins": list,
		  "Software": str,
		  "Version": str,
		  "Status": str
		}

	Raises
	------
	InvalidMcServer
			This is raised if the server ip or port is invalid

	TimeoutError
		This is raised if the query took too long

	CommandError
		This is raised as a generic error response
	"""
    res = requests.get(f"https://api.minetools.eu/query/{server_ip}/{port}")
    res = json.loads(res.text)
    if res["status"] == "ERR":
        if res["error"] == "[Errno -2] Name or service not known":
            raise InvalidMcServer
        elif res["error"] == "timed out":
            raise TimeoutError
        else:
            raise CommandError(res["error"])
    return res
Exemple #29
0
    async def aoc_link_remove(self, ctx: Context, *, member: Union[Member, str]):
        """
        remove a link
        """

        if isinstance(member, Member):
            link = await db_thread(db.get, AOCLink, member.id)
        else:
            aoc_member = await AOCConfig.get_member(member)
            link = aoc_member and await db_thread(db.first, AOCLink, aoc_id=aoc_member["id"])

        if not link:
            raise CommandError(translations.aoc_link_not_found)

        await db_thread(db.delete, link)
        await ctx.send(translations.aoc_link_removed)
Exemple #30
0
    async def reddit_interval(self, ctx: Context, hours: int):
        """
        change lookup interval (in hours)
        """

        if not 0 < hours < (1 << 31):
            raise CommandError(t.invalid_interval)

        await RedditSettings.interval.set(hours)
        await self.start_loop(hours)
        embed = Embed(title=t.reddit,
                      colour=Colors.Reddit,
                      description=t.reddit_interval_set)
        await reply(ctx, embed=embed)
        await send_to_changelog(ctx.guild,
                                t.log_reddit_interval_set(cnt=hours))