예제 #1
0
 async def on_command_error(ctx: Context, error: Exception):
     log.debug('Event "on_command_error" registered')
     if isinstance(error, CommandNotFound):
         if in_production():
             await ctx.send(embed=ErrorEmbed(
                 author=ctx.author,
                 title=':x: Command not found',
                 description=f'There is no command named `{ctx.message.content[1:].split(" ")[0]}`.'
                             f' Check available commands with `>help`.'
             ))
         else:
             log.info(f'Undefined action "{ctx.message.content}"')
     elif isinstance(error, MissingPermissions):
         await ctx.send(embed=ErrorEmbed(
             author=ctx.author,
             title=':x: Missing permissions',
             description=f'You do not have those permissions:```\n{", ".join(error.missing_perms).upper()}\n```'
         ))
     elif isinstance(error, BotMissingPermissions):
         await ctx.send(embed=ErrorEmbed(
             author=ctx.author,
             title=':x: Missing permissions',
             description=f'Bot does not have those permissions:```\n{", ".join(error.missing_perms).upper()}\n```'
         ))
     elif isinstance(error, UserNotFound):
         await ctx.send(embed=ErrorEmbed(
             author=ctx.author,
             title=':x: User not found',
             description='Please make sure that you have passed right name or ID.\n'
                         'If you are looking for a server member,  it is better to use @mention.'
         ))
     elif isinstance(error, CommandOnCooldown):
         await ctx.send(embed=ErrorEmbed(
             author=ctx.author,
             title=':x: Command is on cooldown',
             description='Please try again in a minute.'
         ))
     elif isinstance(error, DisabledCommand):
         if in_production():
             await ctx.send(embed=ErrorEmbed(
                 author=ctx.author,
                 title=':x: Command is disabled'
             ))
     else:
         await debug_log(ctx=ctx, e=error, member=ctx.author)
         raise error
예제 #2
0
class GameSeeker(Cog):
    def __init__(self, bot):
        self.bot = bot

    @command(
        name='host',
        brief='Hosts game',
        description='Creates your\'s event in provided game.',
        help=
        'Bot sends info to all guilds with set game hosting, allowing other people too get in touch with you and'
        ' other gamers.',
        usage='<game name> [additional info]',
        enabled=not in_production())
    async def host(self,
                   ctx: Context,
                   game: str = None,
                   description: str = None):
        await ctx.send(embed=DevelopmentEmbed(
            author=ctx.author).add_field(name='GAME', value=game).add_field(
                name='DESCRIPTION', value=str(description)))
예제 #3
0
class Utilities(Cog):
    def __init__(self, bot):
        self.bot = bot

    # noinspection SpellCheckingInspection
    @cooldown(3, 60, BucketType.user)
    @command(
        name='spotify',
        brief='Spotify lurker',
        description='Searching Spotify for a specified object and sends YouTube version (single track only).',
        help='Available Spotify types:\n'
             '\u2003- `track`,\n'
             '\u2003- `album`,\n'
             '\u2003- `artist`,\n'
             '\u2003- `playlist`.\n'
             'For example:```\n>spotify 3cfOd4CMv2snFaKAnMdnvK track\n```\n'
             'If you pass a valid link, bot is able to recognize type. Like:```\n'
             '>spotify https://open.spotify.com/track/4uLU6hMCjMI75M1A2tKUQC\n```',
        usage='<Spotify link|ID> [type]',
        enabled=in_production()
    )
    async def spotify(self, ctx: Context, url: str = None, type_: str = None):
        if not url:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Missing Spotify link or ID'
            ))
        elif not type_:
            try:
                type_ = url.split('&')[0].split('?')[0].split('/')[3]
            except IndexError:
                pass

        if type_ == 'user':
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: User profiles are not supported',
                description='...yet?'
            ))
        elif type_ not in ['track', 'album', 'artist', 'playlist']:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: What is this?',
                description='Is it `track`, `album`, `artist` or `playlist`?'
            ))

        if url.startswith(('http://open.spotify.com', 'https://open.spotify.com')):
            url = url.split('?')[0].split('/')[-1]

        type_ = type_.lower()

        try:
            sp = Spotify(auth_manager=SpotifyClientCredentials(
                client_id=spotify_client_id(),
                client_secret=spotify_client_secret()
            ))
        except SpotifyOauthError:
            sp = None

        if not sp:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Unable to connect to Spotify!'
            ))

        result = error_code = None
        em = SuccessEmbed(
            author=ctx.author
        ).set_author(
            name=f'{ctx.author.display_name} shared a{"n" if type_[0] == "a" else ""} {type_}:',
            icon_url=ctx.author.avatar_url
        )

        if type_ == 'track':
            try:
                result = sp.track(url)
            except SpotifyException as e:
                error_code = int(e.http_status)
        elif type_ == 'album':
            try:
                result = sp.album(url)
            except SpotifyException as e:
                error_code = int(e.http_status)
        elif type_ == 'playlist':
            try:
                result = sp.playlist(url)
            except SpotifyException as e:
                error_code = int(e.http_status)
        elif type_ == 'artist':
            try:
                result = sp.artist(url)
            except SpotifyException as e:
                error_code = int(e.http_status)
        else:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Unknown object type',
                description='Check `>help` for valid object types.'
            ))

        if error_code:
            if error_code == 400:
                d = 'Invalid ID or URL.'
            elif error_code == 429:
                d = 'Unable to do that now, please try again in 5 minutes.'
            elif str(error_code).startswith('5'):
                d = 'Spotify is not responding.'
            else:
                d = 'Unknown error. Please try again in a few minutes and please make sure URL or ID is valid.'
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: An error occurred!',
                description=d
            ))
        elif not result:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Unable to find anything on Spotify',
                description='Probably URL/ID is wrong.'
            ))

        title = result['name']

        # Artists
        if type_ not in ['artist', 'playlist']:
            artists = list(map(lambda x: [x['name'], x['external_urls']['spotify']], result['artists']))
        elif type_ in ['playlist']:
            artists = [[result['owner']['display_name'], result['owner']['external_urls']['spotify']]]
        else:
            artists = None

        # Released
        if type_ == 'track':
            released = result['album']['release_date']
        elif type_ == 'album':
            released = result['release_date']
        else:
            released = None

        # Genres
        if type_ in ['artist', 'album']:
            genres = ', '.join(result['genres']) or 'Not specified'
        else:
            genres = None

        ex_url = result['external_urls']['spotify']
        thumbnail = result['album']['images'][0]['url'] if type_ == 'track' else result['images'][0]['url']

        # Title
        if title:
            em.add_field(
                name='Name' if type_ in ['artist'] else 'Title',
                value=title
            )

        # Author / Artist(s)
        if artists:
            em.add_field(
                name='Author' if type_ == 'playlist' else 'Artist' if len(artists) == 1 else 'Artists',
                value=', '.join(map(lambda x: f'[{x[0]}]({x[1]} "Check it on Spotify")', artists))
            )

        # Followers
        if type_ in ['artist', 'playlist']:
            em.add_field(
                name='Followers',
                value=result['followers']['total']
            )

        # Album
        if type_ == 'track':
            em.add_field(
                name='Album',
                value=f'[{result["name"]}]({result["album"]["external_urls"]["spotify"]} "Check it on Spotify")'
            )

        # Released
        if released:
            em.add_field(
                name='Released',
                value=released
            )

        # Tracks
        if type_ in ['playlist', 'album']:
            em.add_field(
                name='Tracks',
                value=str(result['tracks']['total'])
            )

        # Genres
        if genres:
            em.add_field(
                name='Genres',
                value=genres
            )

        # Popularity
        if type_ in ['track', 'artist', 'album']:
            em.add_field(
                name='Popularity',
                value=str(result['popularity'])
            )

        # Label
        elif type_ == 'album':
            em.add_field(
                name='Label',
                value=result['label']
            )

        # Spotify link
        if ex_url:
            em.add_field(
                name='Spotify',
                value=ex_url,
                inline=False
            )

        # YouTube link
        if type_ == 'track':
            # Lookup YouTube
            query = '{} {}'.format(result['name'], ' '.join(map(lambda x: x['name'], result['artists'])))
            yt = SearchVideos(
                query,
                mode='dict',
                max_results=1
            ).result()
            # noinspection PyTypeChecker
            yt = yt['search_result'][0]['link'] if yt else None
            em.add_field(
                name='YouTube',
                value=yt,
                inline=False
            )

        # Thumbnail
        if thumbnail:
            em.set_thumbnail(
                url=thumbnail
            )

        await ctx.send(embed=em)

        try:
            await ctx.message.delete()
        except Forbidden or NotFound or HTTPException:
            pass
예제 #4
0
class Profiles(Cog):
    def __init__(self, bot):
        self.bot = bot

    @command(
        name='profile',
        brief='Shows user\'s profile',
        description='Show user\'s profile from database (XP, cash, etc.)',
        usage='[user]',
        aliases=['prof'],
        enabled=in_production()
    )
    async def profile(self, ctx: Context, user: User = None):
        if not user:
            user = ctx.author
        if user.bot is True:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Bots do not have profiles'
            ))
        else:
            msg = await ctx.send(embed=PleaseWaitEmbed(author=ctx.author))
            result_user = get_single_user(user.id if user else ctx.author.id)
            await msg.edit(embed=SuccessEmbed(
                author=ctx.author,
                title=':card_box: User\'s data',
                description='```py\n'
                            '{0.display_name}#{0.discriminator}\n'
                            '```'.format(ctx.guild.get_member(result_user.user_id))
            ).add_field(
                name='XP',
                value=str(result_user.user_xp)
            ).add_field(
                name='Cash',
                value=f_btc(result_user.user_cash)
            ))

    @command(
        name='daily',
        brief='Collect daily cash bonus',
        help='Cooldown resets on 00:00.',
        enabled=in_production()
    )
    async def daily(self, ctx: Context):
        base_cash = 200
        user = get_single_user(ctx.author.id)
        now = d.now()
        able = False
        time_travel = False
        if user.last_daily.year == now.year:
            if user.last_daily.month == now.month:
                if user.last_daily.day == now.day:
                    pass
                elif user.last_daily.day < now.day:
                    able = True
                else:
                    time_travel = True
            elif user.last_daily.month < now.month:
                able = True
            else:
                time_travel = True
        elif user.last_daily.year < now.year:
            able = True
        else:
            time_travel = True
        if time_travel:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Hello time traveler',
                description='Anyway, there\'s no cash for you.'
            ))
        elif able:
            new_user = user_get_cash(ctx.author.id, base_cash)
            await ctx.send(embed=SuccessEmbed(
                author=ctx.author,
                title=':moneybag: Daily bonus gained!',
                description=f'You\'ve earned **{f_btc(base_cash)}**,'
                            f' so now you have **{f_btc(new_user.user_cash)}**.'
            ))
        else:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: You\'ve already collected your daily cash',
                description='Please come back tomorrow.'
            ))

    @command(
        name='reputation',
        brief='[ WIP ] Gives someone reputation',
        help='Available once a day, resets on 00:00.',
        usage='<user>',
        aliases=['rep'],
        enabled=not in_production()
    )
    async def reputation(self, ctx: Context, user: User):
        # TODO - Reputation
        await ctx.send(embed=DevelopmentEmbed(
            author=ctx.author
        ).add_field(
            name='USER',
            value=str(user)
        ))

    @command(
        name='manage',
        brief='Manages users\' data',
        description='Only true Anonymous can use this command',
        help='Available options:\n'
             '- xp\n'
             '- cash',
        usage='<user> <option> <value>',
        enabled=in_production(),
        hidden=True
    )
    async def manage(self, ctx: Context, user: User = None, option: str = None, value: int = None):
        if ctx.author.id != self.bot.owner_id:
            st = ':x: You\'re not authorized'
        elif not user:
            st = ':x: No user provided'
        elif user.bot is True:
            st = ':x: Bots do not have profiles'
        elif not option:
            st = ':x: No option specified'
        elif option not in ['xp', 'cash']:
            st = ':x: Invalid option'
        elif value is None:
            st = ':x: No amount provided'
        else:
            st = None
            msg = await ctx.send(embed=PleaseWaitEmbed(author=ctx.author))
            managed_user = get_single_user(user.id)
            if not managed_user:
                await msg.edit(embed=ErrorEmbed(
                    author=ctx.author,
                    title=':x: User do not exists in database'
                ))
            else:
                if option == 'xp':
                    updated_user = update_profile(user.id, xp=value)
                elif option == 'cash':
                    updated_user = update_profile(user.id, cash=value)
                else:
                    raise
                text = '```py\n{0.display_name}#{0.discriminator}\n'.format(ctx.guild.get_member(updated_user.user_id))
                if option == 'xp':
                    text += f'XP:         {value}\n'
                elif option == 'cash':
                    text += f'Cash:       {f_btc(value)}\n'
                text += '```'
                await msg.edit(embed=SuccessEmbed(
                    author=ctx.author,
                    title=':incoming_envelope: Profile has been updated',
                    description=text
                ))
        if st:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=st
            ))

    @command(
        name='avatar',
        brief='Shows user\'s avatar',
        description='No arg will return your\'s avatar and adding user ID or mention will show other user\'s avatar',
        usage='[user]',
        aliases=['avk'],
        enabled=in_production()
    )
    async def avatar(self, ctx: Context, user: User = None):
        if not user:
            user = ctx.author
        await ctx.send(embed=SuccessEmbed(
            author=ctx.author,
            title=f':bust_in_silhouette: {user} avatar',
            description=f'As you wish, {ctx.author.mention}.'
        ).set_image(
            url=user.avatar_url
        ))

    @command(
        name='whois',
        brief='Short info about user',
        usage='<user>',
        enabled=in_production()
    )
    async def whois(self, ctx: Context, user: User = None):
        if not user:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: No user specified'
            ))
        else:
            await ctx.send(embed=InfoEmbed(
                author=ctx.author,
                title=f':face_with_monocle: Who is {user.display_name}'
            ).add_field(
                name='Original name',
                value='{0.name}#{0.discriminator}'.format(user),
                inline=False
            ).add_field(
                name='User ID',
                value=str(user.id),
                inline=False
            ).add_field(
                name='Joined Discord at',
                value=str(user.created_at)[:19],
                inline=False
            ).add_field(
                name='Bot account',
                value=str(user.bot),
                inline=False
            ).add_field(
                name='Public flags',
                value=', '.join(map(lambda z: f'`{z.upper()}`' if z else None, list(filter(
                    lambda y: y is not None, map(lambda x: x[0] if x[1] else None, user.public_flags)
                )))) or 'None'
            ).set_thumbnail(
                url=user.avatar_url
            ))

    @command(
        name='notes',
        brief='Manages your notes',
        description='Every user can save upto 3 notes.',
        help='Available options:'
             '- create <note content>'
             '- delete <note UID>'
             '- edit <note UID>',
        usage='<option [...]>',
        enabled=not in_production()
    )
    async def notes(self, ctx: Context, option: str = None, arg: Union[int, str] = None):
        # TODO - Notes
        await ctx.send(embed=DevelopmentEmbed(
            author=ctx.author
        ).add_field(
            name='OPTION',
            value=option
        ).add_field(
            name='ARG',
            value=f'{str(arg)} ({type(arg).__class__.__name__})'
        ))
예제 #5
0
class Basics(Cog):
    def __init__(self, bot):
        self.bot = bot

    @command(name='help',
             brief='Shows this message',
             usage='[category|command]',
             enabled=in_production())
    async def help(self, ctx: Context, arg: str = None):
        help_em = InfoEmbed(author=ctx.author, title=':grey_question: Help')
        help_category = 'You can also type `>help <category>` for more info on a category.'
        help_command = 'Type `>help <command>` for more info on a command.'
        if arg is None:
            help_em.description = f'{help_category}\n{help_command}'
            for cog in self.bot.cogs:
                help_em.add_field(name=str(cog),
                                  value=', '.join(
                                      map(lambda x: f'`{x.name}`',
                                          self.bot.cogs[cog].get_commands())),
                                  inline=False)
        else:
            cmd: Command = self.bot.get_command(arg)
            if not cmd:
                cog: Cog = self.bot.get_cog(arg.capitalize())
                if not cog:
                    help_em.description = f'No command or category called `{arg}` found.'
                # Cog found
                else:
                    help_em.description = help_command
                    help_em.add_field(name='Category',
                                      value=f'```\n{cog.qualified_name}\n```',
                                      inline=False)
                    for cmd in cog.get_commands():
                        try:
                            if await cmd.can_run(ctx):
                                help_em.add_field(name=f'`{cmd}`',
                                                  value=cmd.brief or '\u200b')
                        except CommandError:
                            pass
            # Command found
            else:
                help_em.description = help_category
                help_em.add_field(name='Command',
                                  value=f'```\n{cmd.name}\n```',
                                  inline=False)
                if cmd.description:
                    help_em.add_field(name='Description',
                                      value=cmd.description,
                                      inline=False)
                if cmd.aliases:
                    help_em.add_field(name='Aliases',
                                      value=', '.join(
                                          map(lambda x: f'`{x}`',
                                              cmd.aliases)),
                                      inline=False)
                if cmd.usage:
                    help_em.add_field(
                        name='Usage',
                        value=f'```\n>{cmd.name} {cmd.usage}\n```',
                        inline=False)
                if cmd.help:
                    help_em.add_field(name='Additional help',
                                      value=cmd.help,
                                      inline=False)
                if cmd.aliases or cmd.usage:
                    base = cmd.name if not cmd.aliases else f'[{"|".join([cmd.name, *cmd.aliases])}]'
                    tail = cmd.usage or ''
                    if f'{cmd.name} {cmd.usage}' != f'{base} {tail}':
                        help_em.add_field(name='Classic representation',
                                          value=f'```\n>{base} {tail}\n```')

        await ctx.send(embed=help_em)

    @command(
        name='ping',
        brief='Checks bot latency',
        description=
        'Counts time difference between command execution time and bot\'s response',
        enabled=in_production())
    async def ping(self, ctx: Context):
        elapsed_time: timedelta = datetime.utcnow() - ctx.message.created_at
        m, s = divmod(elapsed_time.total_seconds(), 60)
        ping = int(round((m * 60 + s) * 1000))
        await ctx.send(embed=SuccessEmbed(
            author=ctx.author, title=':ping_pong: Pong!').add_field(
                name='Latency', value=f'{round(self.bot.latency * 1000)}ms').
                       add_field(name='Ping', value=f'{ping}ms'))

    @command(name='invite',
             brief='Sends bot\'s invite link',
             enabled=in_production())
    async def invite(self, ctx: Context):
        await ctx.send(embed=InfoEmbed(
            author=ctx.author,
            title=':mailbox_with_mail: Check at top.gg',
            description=
            '**\u00bb [Click me!](https://top.gg/bot/678357487560425555) \u00ab**'
        ).add_field(
            name='Important info',
            value=
            'Remember, that you need **manage users** permission to add me to the server.'
        ))

    @command(
        name='info',
        brief='Sends short bot\'s info',
        description=
        'Sends info about bot itself and its author. This is NOT help command.',
        aliases=['about', 'github', 'code'],
        enabled=in_production())
    async def info(self, ctx: Context):
        await ctx.send(embed=InfoEmbed(
            author=ctx.author,
            title=':desktop: Source code',
            description='This bot is made on open source, GNU GPL v3.0 license.'
        ).add_field(
            name='Links',
            value=
            '\u00b7 [GitHub homepage](https://github.com/AnonymousX86/Enigma-Bot)\n'
            '\u00b7 [Changelog](https://github.com/AnonymousX86/Enigma-Bot/'
            'blob/master/docs/CHANGELOG.md#enigma-bot-changelog)\n',
            inline=False
        ).add_field(
            name='Support',
            value=
            'If you\'d like to help to develop this bot please check GitHub. (Link above)\n'
            'And if **you** need support please check'
            ' [official support server](https://discord.gg/SRdmrPpf2z "3N1GMA Support Server").',
            inline=False).add_field(
                name='More about bot',
                value=f'Version: `{self.bot.version}`.\n'
                f'Author: `{str(self.bot.get_user(self.bot.owner_id))}`.',
                inline=False))

    @cooldown(1, 120, BucketType.user)
    @command(name='suggest',
             brief='Suggest a change',
             description='Ask dev(s) for a functionality or give a feedback.',
             help='Keep your message between 25 and 120 characters.',
             usage='<message>',
             aliases=['change', 'feedback'],
             enabled=in_production())
    async def change(self, ctx: Context, *, message: str = None):
        if not message:
            await ctx.send(
                embed=ErrorEmbed(author=ctx.author,
                                 title=':x: Whoops!',
                                 description='You forget to add a message.'))
        elif len(message) < 25:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Whoops!',
                description='Suggestion is too short. Write more, please.'))
        elif len(message) > 120:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Whoops!',
                description='Suggestion is too long. Write less, please.'))
        else:
            channel: TextChannel = self.bot.get_channel(
                suggestions_channel_id())
            msg = await channel.send(
                embed=SuggestionEmbed(author=ctx.author, message=message))
            await ctx.send(embed=SuccessEmbed(
                author=ctx.author,
                title=':thumbsup: Thanks for suggestion!',
                description=
                f'Check your suggestion here: {channel.mention} or click'
                f' [here]({msg.jump_url} "Direct message link").'))
            await msg.add_reaction(emoji='👍')
            await msg.add_reaction(emoji='👎')

    @cooldown(1, 60, BucketType.guild)
    @command(name='servers',
             brief='List of guilds bot is in',
             aliases=['guilds', 'serverlist', 'guildlist', 'slist'],
             enabled=not in_production(),
             hidden=True)
    async def servers(self, ctx: Context):
        if ctx.author.id != self.bot.owner_id:
            raise MissingPermissions(missing_perms=['bot_owner'])
        em = InfoEmbed(author=ctx.author,
                       title=':passport_control: Bot\'s servers list',
                       description='Last 10 (or less) servers')
        for g, num in zip(
                self.bot.guilds[:10],
                'one,two,three,four,five,six,seven,eight,nine,one::zero'.split(
                    ',')):
            em.add_field(name=f':{num}:  -  {g.name}',
                         value=f'```py\n'
                         f'Created at:    {str(g.created_at)[:10]}\n'
                         f'Joined at:     {str(g.me.joined_at)[:10]}\n'
                         f'Member count:  {g.member_count}\n'
                         f'Owner:         {str(g.owner)}\n'
                         f'Premium tier:  {g.premium_tier}\n'
                         f'Features:      {", ".join(g.features) or "-"}\n'
                         f'```',
                         inline=False)
        await ctx.send(embed=em)
예제 #6
0
class Fun(Cog):
    def __init__(self, bot):
        self.bot = bot

    # How to send images from imigur
    # https://stackoverflow.com/questions/57043797/discord-py-getting-random-imgur-images

    @has_permissions(manage_guild=True)
    @cooldown(1, 30, BucketType.guild)
    @command(
        name='giveaway',
        brief='Initiates a giveaway',
        help='Available options:\n'
             '- create, start, new;'
             ' with argument <channel>\n'
             '- delete, stop, end;'
             ' with argument <message ID>\n'
             '  Message ID could be found under the giveaway message.\n'
             'Maximum item\'s length is 30 characters and maximum amount is 25.',
        usage='<option> <additional argument> [group result by]',
        aliases=['ga'],
        enabled=in_production()
    )
    async def giveaway(self, ctx: Context, option: str = '', arg1: Union[TextChannel, int] = None):
        if not option:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Please specify an option'
            ))
        else:
            def check(m):
                return m.channel == ctx.channel and m.author == ctx.author

            if option in ['create', 'start', 'new']:
                if not arg1:
                    await ctx.send(embed=ErrorEmbed(
                        author=ctx.author,
                        title=':x: Missing channel'
                    ))
                elif type(arg1) is not TextChannel:
                    await ctx.send(embed=ErrorEmbed(
                        author=ctx.author,
                        title=':x: Bad channel format'
                    ))
                else:
                    perms = arg1.permissions_for(ctx.guild.get_member(self.bot.user.id))
                    if not perms.read_messages:
                        await ctx.send(embed=ErrorEmbed(
                            author=ctx.author,
                            title=':x: I can\'s see that channel'
                        ))
                    elif not perms.send_messages:
                        await ctx.send(embed=ErrorEmbed(
                            author=ctx.author,
                            title=':x: I can\'s send messages to that channel'
                        ))
                    else:
                        msg = await ctx.send(embed=InfoEmbed(
                            author=ctx.author,
                            title=':shopping_bags: Create giveaway',
                            description=f'Final message will be sent to {arg1.mention}.'
                        ))

                        things: List[List[str, str]] = []
                        index = 0

                        info = await ctx.send(embed=InfoEmbed(
                            author=ctx.author,
                            title='Preparing...'
                        ))

                        # Getting items for giveaway
                        while True:
                            index += 1
                            await info.edit(embed=InfoEmbed(
                                author=ctx.author,
                                title=f':name_badge: {index}{number_suffix(index)} item name...',
                            ))
                            try:
                                # Get item's name
                                response_1 = await self.bot.wait_for('message', check=check, timeout=30)
                            except WaitTimeout:
                                return await info.edit(embed=TimeoutEmbed(author=ctx.author))
                            else:
                                # Ended before adding at least one item
                                if response_1.content.lower() in ['stop', 'end', 'x']:
                                    try:
                                        await response_1.delete()
                                    except Forbidden:
                                        pass
                                    if len(things) == 0:
                                        return await info.edit(embed=ErrorEmbed(
                                            author=ctx.author,
                                            title=':x: Too few things'
                                        ))
                                    break
                                elif len(response_1.content) > 30:
                                    try:
                                        await response_1.delete()
                                    except Forbidden:
                                        pass
                                    await info.edit(embed=ErrorEmbed(
                                        author=ctx.author,
                                        title=':x: Name\'s too long',
                                        description='Keep it under 30 characters.'
                                    ))
                                    return
                                await info.edit(embed=InfoEmbed(
                                    author=ctx.author,
                                    title=f':1234: {index}{number_suffix(index)} item quantity...'
                                ))
                                try:
                                    # Get item's quantity
                                    response_2 = await self.bot.wait_for('message', check=check, timeout=10)
                                except WaitTimeout:
                                    await info.edit(embed=TimeoutEmbed(author=ctx.author))
                                    try:
                                        await response_1.delete()
                                    except Forbidden:
                                        pass
                                    return
                                else:
                                    # Checking if quantity is a number
                                    try:
                                        q = int(response_2.content)
                                        if q < 1:
                                            raise ValueError
                                    except ValueError:
                                        await info.edit(embed=ErrorEmbed(
                                            author=ctx.author,
                                            title=':x: Bad format, quantity must be a number and higher than 0'
                                        ))
                                        try:
                                            await response_1.delete()
                                            await response_2.delete()
                                        except Forbidden:
                                            pass
                                        return
                                    if int(response_2.content) > 25:
                                        try:
                                            await response_1.delete()
                                        except Forbidden:
                                            pass
                                        await info.edit(embed=ErrorEmbed(
                                            author=ctx.author,
                                            title=':x: Too much',
                                            description='Keep quantity under 25.'
                                        ))
                                        return

                                    await info.edit(embed=PleaseWaitEmbed(author=ctx.author))
                                    things.append([response_1.content, response_2.content])
                                    await msg.edit(embed=msg.embeds[0].add_field(
                                        name=things[-1][1],
                                        value=things[-1][0]
                                    ))
                                    try:
                                        await response_1.delete()
                                        await response_2.delete()
                                    except Forbidden:
                                        pass

                        await info.delete()
                        final_em = SuccessEmbed(
                            author=ctx.author,
                            title=':white_check_mark: Done!'
                        ).set_footer(
                            text=f'Created by {ctx.author.display_name}'
                        )
                        for thing in things:
                            final_em.add_field(
                                name=f'x{thing[1]}',
                                value=thing[0]
                            )
                        await msg.edit(embed=final_em)

                        # Preparing final giveaway message
                        final_em.title = ':gift: Giveaway!'
                        final_em.add_field(
                            name='\u200b',
                            value='React with `📝` to participate!',
                            inline=False
                        )
                        # Sending final giveaway message
                        try:
                            new_g = await arg1.send(embed=final_em)
                        except Forbidden:
                            await ctx.send(embed=ErrorEmbed(
                                author=ctx.author,
                                title=f':x: I have no permissions to send message in {arg1.mention}'
                            ))
                        else:
                            # Adding message ID to footer
                            await new_g.edit(embed=new_g.embeds[0].add_field(name='\u200b', value=f'{new_g.id}'))
                            try:
                                await new_g.add_reaction(emoji='📝')
                            except Forbidden:
                                await ctx.send(embed=ErrorEmbed(
                                    author=ctx.author,
                                    title=f':x: I can\'t add emoji to the message in {arg1.mention}'
                                ))
                            else:
                                create_giveaway(new_g.id, ctx.guild.id, data=str(things))
            elif option in ['delete', 'stop', 'end']:
                # Discord ID has 18 digits
                if len(str(arg1)) != 18:
                    await ctx.send(embed=ErrorEmbed(
                        author=ctx.author,
                        title=':x: Bad ID format'
                    ))
                else:
                    giveaway = get_giveaway_from_message(arg1)

                    # Giveaway message ID do not exists in database
                    if giveaway is None:
                        await ctx.send(embed=ErrorEmbed(
                            author=ctx.author,
                            title=':x: Giveaway do not exists'
                        ))

                    # Users shouldn't end giveaway from another guild
                    elif giveaway.guild_id != ctx.guild.id:
                        await ctx.send(embed=ErrorEmbed(
                            author=ctx.author,
                            title=':x: This giveaway do not belongs to this guild'
                        ))

                    else:
                        info = await ctx.send(embed=PleaseWaitEmbed(author=ctx.author))

                        # Finding giveaway's message
                        giveaway_message: Optional[Message] = None
                        for channel in ctx.guild.text_channels:
                            try:
                                giveaway_message = await channel.fetch_message(arg1)
                            except NotFound:
                                pass
                            else:
                                break

                        # Message do not exists but giveaway do
                        if giveaway_message is None:
                            await info.edit(embed=ErrorEmbed(
                                author=ctx.author,
                                title=':x: Message not found',
                                description='Giveaway exists but its message was probably removed,'
                                            ' so I\'m removing the giveaway.'
                            ))
                            if not delete_giveaway(message_id=arg1):
                                await self.bot.debug_log(
                                    ctx=ctx, e=DatabaseError(f'Unable to delete giveaway with message ID {arg1}')
                                )
                        else:
                            # Claiming giveaway's reactions
                            participants = []
                            for reaction in giveaway_message.reactions:
                                if reaction.emoji == '📝':
                                    async for user in reaction.users():
                                        if not user.bot:
                                            participants.append(user)
                                    break
                                await ctx.send(embed=ErrorEmbed(
                                    author=ctx.author,
                                    title=':x: Giveaway reaction not found',
                                    description='Deleting giveaway without winners.'
                                ))
                                await giveaway_message.edit(
                                    embed=giveaway_message.embeds[0].add_field(
                                        name='\u200b',
                                        value=f'Ended on {d.now()[:16]}'
                                    )
                                )
                                if not delete_giveaway(message_id=arg1):
                                    await self.bot.debug_log(
                                        ctx=ctx, e=DatabaseError(f'Unable to delete giveaway with message ID {arg1}')
                                    )

                            # No one added reaction to giveaway
                            if not participants:
                                await ctx.send(embed=ErrorEmbed(
                                    author=ctx.author,
                                    title=':x: No participants found',
                                    description='Deleting giveaway without winners.'
                                ))
                                if not delete_giveaway(message_id=arg1):
                                    await self.bot.debug_log(
                                        ctx=ctx, e=DatabaseError(f'Unable to delete giveaway with message ID {arg1}')
                                    )

                            else:
                                # Prepare giveaway's data
                                giveaway_data: List[List[str, str]] = literal_eval(giveaway.data)
                                winners = {}
                                for item in giveaway_data:
                                    possibles = participants.copy()
                                    item_winners = []
                                    for quantity in range(int(item[1])):
                                        if len(possibles) == 0:
                                            possibles = participants.copy()
                                        random_winner = choice(possibles)
                                        item_winners.append(random_winner)
                                        possibles.remove(random_winner)
                                    winners[item[0]] = item_winners
                                # noinspection SpellCheckingInspection
                                win_em = SuccessEmbed(
                                    author=ctx.author,
                                    title=':tada: Winners'
                                )

                                await info.edit(embed=InfoEmbed(
                                    author=ctx.author,
                                    title='How you\'d like to group result?',
                                    description='Please type `item` or `user`.'
                                ))
                                try:
                                    response: Message = await self.bot.wait_for('message', check=check, timeout=10)
                                except WaitTimeout:
                                    await info.edit(embed=TimeoutEmbed(author=ctx.author))
                                    return

                                r = response.content.lower()
                                u = ['u', 'user', 'users']
                                i = ['i', 'item', 'items']

                                if r in [*u, *i]:
                                    try:
                                        await response.delete()
                                    except Forbidden:
                                        pass

                                # Group by users
                                if r in u:
                                    all_users = set()
                                    for item in winners:
                                        for users in winners[item]:
                                            all_users.add(users)
                                    user_items = {}
                                    for user in all_users:
                                        prizes = []
                                        checked = []
                                        for prize in winners:
                                            for winner_user in winners[prize]:
                                                if winner_user.id == user.id:
                                                    prizes.append(prize)
                                        n_prizes = []
                                        for prize in prizes:
                                            if prize not in checked:
                                                n_prizes.append(f'{prize} x{prizes.count(prize)}')
                                                checked.append(prize)
                                        user_items[user] = n_prizes
                                    for user in user_items:
                                        win_em.add_field(
                                            name=user.display_name,
                                            value='- ' + '\n- '.join(user_items[user])
                                        )

                                # Group by items
                                elif r in i:
                                    for item in winners:
                                        winners_f = {}
                                        for w in [el for i, el in enumerate(winners[item], 1) if
                                                  el not in winners[item][i:]]:
                                            winners_f[w] = winners[item].count(w)
                                        win_em.add_field(
                                            name=item,
                                            value='- ' + '\n- '.join(map(
                                                lambda x: x.mention + str(
                                                    ((" *x" + str(winners_f[x])) + "*") if winners_f[x] > 1 else ""
                                                ),
                                                set(sorted(winners[item], key=lambda x: x.display_name))
                                            ))
                                        )

                                else:
                                    await info.edit(embed=ErrorEmbed(
                                        author=ctx.author,
                                        title=f':x: Unknown option `{r}`'
                                    ))
                                    return

                                await ctx.send(embed=win_em)
                                try:
                                    await ctx.message.delete()
                                except Forbidden:
                                    pass
                                await giveaway_message.edit(
                                    embed=giveaway_message.embeds[0].set_footer(text=f'Ended on {str(d.now())[:16]}')
                                )
                                if not delete_giveaway(message_id=arg1):
                                    await self.bot.debug_log(
                                        ctx=ctx, e=DatabaseError(f'Unable to delete giveaway with message ID {arg1}')
                                    )
                                await info.delete()
            else:
                await ctx.send(embed=ErrorEmbed(
                    author=ctx.author,
                    title=':x: Invalid option'
                ))

    @giveaway.error
    async def giveaway_error(self, ctx: Context, error: Exception):
        if isinstance(error, CommandInvokeError):
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: There was a problem with the giveaway',
                description='Probably, there are too many items in the giveaway.'
            ))
        else:
            raise CommandError(error)

    @cooldown(2, 5, BucketType.guild)
    @command(
        name='iq',
        brief='Check your IQ',
        usage='[user]',
        enabled=in_production()
    )
    async def iq(self, ctx: Context, user: User = None):
        if not user:
            user = ctx.author
        if user.id == self.bot.user.id:
            iq = 200
        elif user.bot is True:
            iq = 0
        else:
            iq = int(user.id) % int(user.discriminator) % 115 + 5
        description = ''
        if iq == 0:
            # noinspection SpellCheckingInspection
            description = 'Bots are stuuupiiid.'
        elif iq < 10:
            description = 'Oh my... I didn\'t think it\'s possible to be that stupid.' \
                          ' *(You\'d be great friends with Paimon)*'
        elif iq < 25:
            description = 'It\'s sickness, you know?'
        elif iq < 40:
            description = 'Some potatoes are smarter than you.'
        elif iq < 60:
            description = 'Roomba is smarter than you LMFAO.'
        elif iq == 69:
            description = 'Nice.'
        elif iq < 70:
            description = 'In terms of law - you\'re retarded.\n' \
                          '> Intellectual disability (ID), also known as general learning disability and mental' \
                          ' retardation (MR), is a generalized neurodevelopmental disorder characterized by' \
                          ' significantly impaired intellectual and adaptive functioning. It is defined by an IQ' \
                          ' under 70, in addition to deficits in two or more adaptive behaviors that affect everyday,' \
                          ' general living.'
        elif iq < 90:
            description = 'It\'s okay, but still not so smart.'
        elif iq < 110:
            description = 'You\'re normal, ***b o r i n g***.'
        elif iq <= 120:
            description = 'Okay, your\'e smart and it\'s maximum value. Cheater...'
        elif iq == 200:
            description = 'Oh my... It\'s super duper smart!!1!'
        safe_name = str(user.display_name). \
            replace('*', '\\*'). \
            replace('_', '\\_'). \
            replace('~', '\\~'). \
            replace('>', '\\>')
        await ctx.send(embed=SuccessEmbed(
            author=ctx.author,
            title=f':abacus: {safe_name}\'s IQ is {iq}',
            description=description
        ))

    @cooldown(1, 6, BucketType.guild)
    @command(
        name='meme',
        brief='Send a meme',
        description='Sends meme from r/dankmemes.',
        enabled=in_production()
    )
    async def meme(self, ctx: Context):
        reddit = Reddit(
            client_id=reddit_client_id(),
            client_secret=reddit_client_secret(),
            user_agent=reddit_user_agent()
        )
        posts = []
        # noinspection SpellCheckingInspection
        for submission in reddit.subreddit('dankmemes').hot(limit=20):
            if not submission.archived:
                if submission.score > 50:
                    if not submission.is_self:
                        if not submission.over_18:
                            posts.append(submission)
        if posts:
            await ctx.send(embed=SuccessEmbed(
                author=ctx.author,
                title=':black_joker: Meme found'
            ).set_image(
                url=choice(posts).url
            ))
        else:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Meme not found',
                description='Just try again'
            ))

    # noinspection SpellCheckingInspection
    @command(
        name='randomnumber',
        brief='Sends random number',
        description='You can provide maximun and minimum number to choose.',
        usage='[max] [min]',
        aliases=['randomnum', 'randnumber', 'randnum'],
        enabled=in_production()
    )
    async def randomnumber(self, ctx: Context, max_: int = 10, min_: int = 1):
        nums = list(range(min_, max_ + 1))
        if len(nums) == 0:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Invalid argument(s)',
                description='Please remember, that first argument is `max` and the second is `min`.'
            ))
        else:
            num = choice(nums)
            url = f'https://numbersapi.p.rapidapi.com/{num}/math'
            headers = {
                'x-rapidapi-host': 'numbersapi.p.rapidapi.com',
                'x-rapidapi-key': rapid_api_key()
            }
            querystring = {"fragment": "false", "json": "false"}
            response = request("GET", url, headers=headers, params=querystring)
            result: Optional[dict] = json_loads(response.text) if response.status_code == 200 else None
            em = SuccessEmbed(
                author=ctx.author,
                title=f':1234: I\'ve chosen {num}'
            )
            if result and result['found']:
                em.add_field(
                    name='Funfact',
                    value=f'{result["text"].capitalize()}.'
                )
            await ctx.send(embed=em)

    @command(
        name='choice',
        brief='Helps with choosing',
        usage='<thing1> <thing2> [thingN]',
        enabled=in_production()
    )
    async def choice(self, ctx: Context, *, things: str):
        breakpoint()
        em = ErrorEmbed
        if not things:
            title = ':x: No items specified'
        elif len(things) < 2:
            title = ':x: Too few thing specified'
        else:
            title = f':abcd: I\'ve chosen {choice(things)}'
            em = SuccessEmbed
        await ctx.send(embed=em(
            author=ctx.author,
            title=title
        ))

    @command(
        name='coin',
        brief='Tosses a coin',
        descriptiom='O Valley of Plenty...',
        aliases=['toss'],
        enabled=in_production()
    )
    async def coin(self, ctx: Context):
        await ctx.send(embed=SuccessEmbed(
            author=ctx.author,
            title=':small_red_triangle_down: Tails' if randint(1, 2) == 1 else ':small_red_triangle: Heads'
        ))
예제 #7
0
class Admin(Cog):
    def __init__(self, bot):
        self.bot = bot

    @command(name='ban',
             brief='Bans user',
             usage='<user> [reason]',
             enabled=in_production())
    @has_permissions(ban_members=True)
    @bot_has_permissions(ban_members=True)
    async def ban(self,
                  ctx: Context,
                  member: Member = None,
                  *,
                  reason: str = None):
        # No user provided
        if not member:
            await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':face_with_raised_eyebrow: Who do I need to ban?',
                description='You\'ve not provided a victim',
            ))
        else:
            # User is trying to ban yourself
            if member.id == ctx.message.author.id:
                await ctx.send(embed=ErrorEmbed(
                    author=ctx.author,
                    title=':clown: You can\'t ban yourself',
                    description=
                    'Ask someone to help you commit sepuku or something...',
                ))
            # User is trying to ban guild owner
            elif member.id == ctx.guild.owner.id:
                await ctx.send(embed=ErrorEmbed(
                    author=ctx.author,
                    title=':crown: You can\'t ban guild owner',
                    description='He\'s the almighty one, sorry'))
            # User is trying to ban the bot
            elif member.id == self.bot.user.id:
                await ctx.send(embed=ErrorEmbed(
                    author=ctx.author,
                    title=':zany_face: I can\'t ban myself',
                    description='Even if I would I can\'t, sorry'))
            # No errors
            else:
                await ctx.send(embed=SuccessEmbed(
                    author=ctx.author,
                    title=
                    f':hammer: Banning {get(ctx.guild.members, id=member.id)}'
                ).add_field(name='REASON', value=str(reason)))
                await member.ban(reason=reason)

    @has_permissions(ban_members=True)
    @bot_has_permissions(ban_members=True)
    @command(
        name='unban',
        brief='Unbans user',
        help=
        'Because user of course isn\'t in server, provide user\'s name or ID.',
        uasge='<user> [reason]',
        enabled=not in_production())
    async def unban(self,
                    ctx: Context,
                    user: User = None,
                    *,
                    reason: str = None):
        if not user:
            await ctx.send(
                embed=ErrorEmbed(author=ctx.author, title=':x: User not found')
            )
        else:
            try:
                await ctx.guild.unban(user, reason=reason)
            except HTTPException as e:
                await ctx.send(embed=ErrorEmbed(author=ctx.author,
                                                title=':x: Can\'t unban user'))
                await self.bot.debug_log(ctx=ctx, e=e, user=user)
            else:
                await ctx.send(embed=SuccessEmbed(
                    author=ctx.author,
                    title=':white_check_mark: User unbanned',
                    description=
                    f'**{user.display_name}** now can join back to **{ctx.guild.name}**.'
                ).add_field(name='REASON', value=str(reason)))

    @command(name='kick',
             brief='Kicks user',
             description='You can provide user ID or mention someone',
             usage='<user> [reason]',
             enabled=in_production())
    @has_permissions(kick_members=True)
    @bot_has_permissions(kick_members=True)
    async def kick(self,
                   ctx: Context,
                   member: Member = None,
                   *,
                   reason: str = None):
        # No user provided
        if not member:
            st = (':cowboy: Who do I need to kick round the clock?',
                  'You\'ve not provided a victim')
        # User is trying to ban yourself
        elif member.id == ctx.author.id:
            st = (
                ':man_facepalming: No... That\'s not how mafia works',
                'If you want to leave, do this, but don\'t try to kick yourself, that\'s stupid'
            )
        # User is trying to ban guild owner
        elif member.id == ctx.guild.owner.id:
            st = (':oncoming_police_car: Wait, that\'s illegal',
                  'You can\'t kick the police officer')
        # User is trying to ban the bot
        elif member.id == self.bot.user.id:
            st = (':face_with_symbols_over_mouth: NO',
                  'I won\'t leave this guild even if you want to')
        # No errors
        else:
            await ctx.send(embed=SuccessEmbed(
                author=ctx.author,
                title=
                f':boot: I\'m kicking {get(ctx.guild.members, id=member.id)} out'
            ).add_field(name='REASON', value=str(reason)))
            await member.kick(reason=reason)
            return
        await ctx.send(
            embed=ErrorEmbed(author=ctx.author, title=st[0], description=st[1])
        )

    @has_permissions(manage_messages=True)
    @bot_has_permissions(manage_messages=True, read_message_history=True)
    @cooldown(1, 30, BucketType.guild)
    @command(name='prune',
             biref='Clears messages',
             descriptions='Clears last X messages in current channel',
             help='You can delete 20 messages at once.',
             usage='[amount]',
             enabled=in_production())
    async def prune(self, ctx: Context, amount: int = 0):
        if amount < 1:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Argument error',
                description='Please provide proper amount of messages to prune.'
            ))
        elif amount > 20:
            return await ctx.send(embed=ErrorEmbed(
                author=ctx.author,
                title=':x: Too many messages',
                description='Please provide amount less than 20.'))
        deleted = 0
        msg = await ctx.send(embed=PleaseWaitEmbed(author=ctx.author))
        await ctx.message.delete()
        async for m in ctx.channel.history(limit=amount + 1):
            if m.id == msg.id:
                continue
            try:
                await m.delete()
            except NotFound or HTTPException:
                pass
            else:
                deleted += 1
        if deleted < 1:
            await msg.edit(embed=ErrorEmbed(author=ctx.author,
                                            title=':x: Deleting failed'))
        await msg.edit(embed=SuccessEmbed(
            author=ctx.author,
            title=
            f':wastebasket: Successfully deleted {deleted} message{"s" if deleted > 1 else ""}.'
        ))
        await msg.delete(delay=3.0)
예제 #8
0
 def __init__(self, author: User, **kwargs):
     super().__init__(**kwargs)
     self.timestamp = datetime.utcnow()
     self.set_footer(text=str(author) +
                     (' \u2615' if not in_production() else ''),
                     icon_url=author.avatar_url)