示例#1
0
async def add_emoji(client,
                    event,
                    emoji: ('str', 'The emoji to add.'),
                    name: ('str',
                           'Custom name to add the emoji with.') = None):
    """Adds an emoji to the guild."""
    if not client.is_owner(event.user):
        abort('Owner only!')

    emoji = parse_emoji(emoji)
    if emoji is None:
        abort('That\'s not an emoji.')

    if emoji.is_unicode_emoji():
        abort('Cannot add unicode emojis')

    if name is None:
        name = emoji.name
    else:
        if len(name) > 32:
            abort('Name length can be max 32.')

    embed = Embed('Are you sure to add this emoji?').add_field(
        'Name:', name).add_image(emoji.url)

    message = yield InteractionResponse(embed=embed,
                                        components=ADD_EMOJI_COMPONENTS)

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=functools.partial(check_is_user_same, event.user))

    except TimeoutError:
        component_interaction = None
        cancelled = True
    else:
        if component_interaction.interaction == ADD_EMOJI_BUTTON_CANCEL:
            cancelled = True
        else:
            cancelled = False

    if cancelled:
        embed.title = 'Adding emoji has been cancelled.'
    else:
        embed.title = 'Emoji has been added!'

        async with client.http.get(emoji.url) as response:
            emoji_data = await response.read()

        await client.emoji_create(event.guild, name, emoji_data)

    yield InteractionResponse(embed=embed,
                              components=None,
                              message=message,
                              event=component_interaction)
示例#2
0
async def edit_(
    client,
    event,
    sticker_name: ('str', 'The sticker\'s name to delete', 'sticker'),
    new_name: (
        'str',
        'New name for the sticker',
    ) = None,
    new_emoji_value: (str, 'Emoji representation of the sticker.',
                      'new_emoji') = None,
    new_description: (str, 'Description for the sticker.') = None,
):
    """Edits the given sticker. (You must have emoji-council role)"""
    if not event.user.has_role(ROLE__NEKO_DUNGEON__EMOJI_MANAGER):
        abort(
            f'You must have {ROLE__NEKO_DUNGEON__EMOJI_MANAGER:m} role to invoke this command.'
        )

    sticker = event.guild.get_sticker_like(sticker_name)
    if (sticker is None):
        abort(f'No sticker matched the given name: {sticker_name!r}.')

    anything_to_edit = False

    if (new_name is not None):
        if (sticker.name != new_name):
            name_length = len(new_name)
            if (name_length < 2) or (name_length > 32):
                abort(
                    f'Sticker name\'s length can be in range [2:32], got {name_length!r}, {new_name!r}.'
                )

            anything_to_edit = True
        else:
            new_name = None

    if (new_emoji_value is not None):
        new_emoji = parse_emoji(new_emoji_value)

        if new_emoji is None:
            abort(f'{new_emoji_value} cannot be interpreted as an emoji.')

        if new_emoji.is_custom_emoji():
            abort(f'Only unicode can be used, got {new_emoji:e}')

        tags = sticker.tags
        if (tags is None) or (len(tags) != 1) or (next(iter(tags)) !=
                                                  new_emoji.name):
            anything_to_edit = True
        else:
            new_emoji = None
    else:
        new_emoji = None

    if (new_description is not None):
        description_length = len(new_description)
        if (description_length > 100):
            abort(
                f'Sticker description\'s length can be in range [0:100], got {description_length!r}, '
                f'{new_description!r}.')

        if (sticker.description != new_description):
            anything_to_edit = True
        else:
            new_description = None

    if not anything_to_edit:
        abort('No differences were provided.')

    embed = Embed('Confirmation',
                  f'Are you sure to edit {sticker.name!r} sticker?')

    if (new_name is not None):
        embed.add_field('Name', f'{sticker.name} -> {new_name}')

    if (new_emoji is not None):
        embed.add_field('Tags',
                        f'{", ".join(sticker.tags)} -> {new_emoji.name}')

    if (new_description is not None):
        embed.add_field('Description',
                        f'{sticker.description} -> {new_description}')

    message = yield InteractionResponse(embed=embed,
                                        components=STICKER_EDIT_COMPONENTS,
                                        allowed_mentions=None)

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=partial_func(check_sticker_editor, event.user))

    except TimeoutError:
        embed.title = 'Timeout'
        embed.description = f'Sticker {sticker.name!r} was not edited.'

        # Edit the source message with the source interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  message=message)
        return

    if component_interaction.interaction == STICKER_EDIT_BUTTON_CANCEL:
        embed.title = 'Cancelled'
        embed.description = f'Sticker {sticker.name!r} was not edited.'

        # Edit the source message with the component interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  event=component_interaction)
        return

    # Acknowledge the event
    await client.interaction_component_acknowledge(component_interaction)

    kwargs = {}

    if (new_name is not None):
        kwargs['name'] = new_name

    if (new_emoji is not None):
        kwargs['emoji_representation'] = new_emoji

    if (new_description is not None):
        kwargs['description'] = new_description

    try:
        await client.sticker_guild_edit(sticker, **kwargs)
    except ConnectionError:
        # No internet, let it be
        return

    except DiscordException as err:
        if err.code == ERROR_CODES.unknown_sticker:
            failure = False
        else:
            failure = True
            embed.title = 'Failure'
            embed.description = repr(err)
    else:
        failure = False

    if not failure:
        embed.title = 'Success'
        embed.description = f'Sticker {sticker.name!r} has been successfully edited.'

    # Edit the source message
    yield InteractionResponse(embed=embed, message=message, components=None)
示例#3
0
async def delete_(
        client,
        event,
        sticker_name: ('str', 'The sticker\'s name to delete', 'sticker'),
):
    """Deletes the given sticker. (You must have emoji-council role)"""
    if not event.user.has_role(ROLE__NEKO_DUNGEON__EMOJI_MANAGER):
        abort(
            f'You must have {ROLE__NEKO_DUNGEON__EMOJI_MANAGER:m} role to invoke this command.'
        )

    sticker = event.guild.get_sticker_like(sticker_name)
    if (sticker is None):
        abort(f'No sticker matched the given name: {sticker_name!r}.')

    embed = Embed(
        'Confirmation',
        f'Are you sure to delete {sticker.name!r} ({sticker.id}) sticker forever?'
    )

    message = yield InteractionResponse(embed=embed,
                                        components=STICKER_DELETE_COMPONENTS,
                                        allowed_mentions=None)

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=partial_func(check_sticker_deleter, event.user))

    except TimeoutError:
        embed.title = 'Timeout'
        embed.description = f'Sticker {sticker.name!r} was not deleted.'

        # Edit the source message with the source interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  message=message)
        return

    if component_interaction.interaction == STICKER_DELETE_BUTTON_CANCEL:
        embed.title = 'Cancelled'
        embed.description = f'Sticker {sticker.name!r} was not deleted.'

        # Edit the source message with the component interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  event=component_interaction)
        return

    # Acknowledge the event
    await client.interaction_component_acknowledge(component_interaction)

    try:
        await client.sticker_guild_delete(sticker)
    except ConnectionError:
        # No internet, let it be
        return

    except DiscordException as err:
        if err.code == ERROR_CODES.unknown_sticker:
            failure = False
        else:
            failure = True
            embed.title = 'Failure'
            embed.description = repr(err)
    else:
        failure = False

    if not failure:
        embed.title = 'Success'
        embed.description = f'Sticker {sticker.name!r} has been deleted successfully.'

    # Edit the source message
    yield InteractionResponse(embed=embed, message=message, components=None)
示例#4
0
async def yeet(
    client,
    event,
    user: ('user', 'Select the user to yeet!'),
    reason: ('str', 'Any reason why you would want to yeet?') = None,
    delete_message_days: (range(8), 'Delete previous messages?') = 0,
    notify_user: ('bool',
                  'Whether the user should get DM about the ban.') = True,
):
    """Yeets someone out of the guild. You must have ban users permission."""
    # Check permissions
    guild = event.guild
    if guild is None:
        abort('Guild only command.')

    if guild not in client.guild_profiles:
        abort('I must be in the guild to do this.')

    if not event.user_permissions.can_ban_users:
        abort('You must have yeet users permission to use this command.')

    if not guild.cached_permissions_for(client).can_ban_users:
        abort(f'{client.name_at(guild)} cannot yeet in the guild.')

    if not event.user.has_higher_role_than_at(user, guild):
        abort('You must have higher role than the person to be yeeted.')

    if not client.has_higher_role_than_at(user, guild):
        abort('I must have higher role than the person to yeeted.')

    # Ask, whether the user should be banned.
    if (reason is not None) and (not reason):
        reason = None

    embed = Embed('Confirmation', f'Are you sure to yeet {user.mention} from {guild.name}?'). \
        add_field('Delete message day', str(delete_message_days), inline=True). \
        add_field('Notify user', 'true' if notify_user else 'false', inline=True). \
        add_field('Reason', '*No reason provided.*' if reason is None else reason)

    message = yield InteractionResponse(embed=embed,
                                        components=BAN_COMPONENTS,
                                        allowed_mentions=None)

    # Wait for user input

    try:
        component_interaction = await wait_for_component_interaction(
            message,
            timeout=300.0,
            check=partial_func(check_banner, event.user))

    except TimeoutError:
        embed.title = 'Timeout'
        embed.description = f'{user.mention} was not yeeted from {guild.name}.'

        # Edit the source message with the source interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  message=message)
        return

    if component_interaction.interaction == BAN_BUTTON_CANCEL:
        embed.title = 'Cancelled'
        embed.description = f'{user.mention} was not yeeted from {guild.name}.'

        # Edit the source message with the component interaction
        yield InteractionResponse(embed=embed,
                                  components=None,
                                  allowed_mentions=None,
                                  event=component_interaction)
        return

    # Acknowledge the event
    await client.interaction_component_acknowledge(component_interaction)

    # Try to notify the user. Ignore bot notifications.
    if notify_user:
        if user.is_bot:
            notify_note = None
        else:

            try:
                channel = await client.channel_private_create(user)
            except BaseException as err:
                if isinstance(err, ConnectionError):
                    return  # We cannot help no internet

                raise

            embed = Embed('Yeeted', f'You were yeeted from {guild.name}.'). \
                add_field('Reason', '*No reason provided.*' if reason is None else reason)

            try:
                await client.message_create(channel, embed=embed)
            except BaseException as err:
                if isinstance(err, ConnectionError):
                    return  # We cannot help no internet

                elif isinstance(err, DiscordException) and (
                        err.code == ERROR_CODES.cannot_message_user):
                    notify_note = 'Notification cannot be delivered: user has DM disabled.'
                else:
                    raise
            else:
                notify_note = None
    else:
        notify_note = None

    if reason is None:
        caller = event.user
        reason = f'Requested by: {caller.full_name} [{caller.id}]'

    await client.guild_ban_add(guild,
                               user,
                               delete_message_days=delete_message_days,
                               reason=reason)

    embed = Embed('Hecatia yeah!', f'{user.full_name} has been yeeted.')
    if (notify_note is not None):
        embed.add_footer(notify_note)

    # Edit the source message
    yield InteractionResponse(embed=embed, message=message, components=None)
示例#5
0
    async def runner(self):
        client = self.client
        channel = self.channel
        answers = self.answers
        buffer = ReuBytesIO()
        embed = Embed(color=KANAKO_COLOR).add_image(
            'attachment://guess_me.png').add_footer('')

        time_till_notify = CIRCLE_TIME - 10

        for index, (question, answer) in enumerate(self.map, 1):
            embed.footer.text = f'{index} / {len(self.map)}'
            if self.possibilities:
                self.options = self.generate_options(answer)
                embed.description = '\n'.join([
                    f'**{index}.: {value}**'
                    for index, value in enumerate(self.options, 1)
                ])

            try:
                await client.message_create(channel,
                                            embed=embed,
                                            file=('guess_me.png',
                                                  draw(buffer, question)))
            except BaseException as err:
                self.cancel()
                if isinstance(err, ConnectionError):
                    return

                if isinstance(err, DiscordException):
                    if err.code in (
                            ERROR_CODES.unknown_channel,  # channel deleted
                            ERROR_CODES.missing_access,  # client removed
                            ERROR_CODES.
                            missing_permissions,  # permissions changed meanwhile
                    ):
                        return

                await client.events.error(client,
                                          f'{self.__class__.__name__}.runner',
                                          err)
                return

            circle_start = LOOP_TIME()
            self.waiter = waiter = Future(KOKORO)
            future_or_timeout(waiter, time_till_notify)

            try:
                await waiter
            except TimeoutError:
                Task(self.notify_late_users(), KOKORO)

                self.waiter = waiter = Future(KOKORO)
                future_or_timeout(waiter, 10)

                try:
                    await waiter
                except TimeoutError:
                    leavers = []

                    users = self.users

                    for index in reversed(range(len(users))):
                        user = users[index]
                        if user in answers:
                            continue

                        leavers.append(user)
                        del users[index]

                        for element in self.history:
                            del element.answers[index]

                    if len(self.users) == 0:
                        self.cancel()
                        embed = Embed(
                            None,
                            'No-one gave answer in time, cancelling the game.',
                            color=KANAKO_COLOR)
                    else:
                        embed = Embed(None,
                                      '\n'.join([
                                          'Users timed out:',
                                          *(user.full_name for user in leavers)
                                      ]),
                                      color=KANAKO_COLOR)

                    try:
                        await client.message_create(channel, embed=embed)
                    except BaseException as err:
                        self.cancel()
                        if isinstance(err, ConnectionError):
                            return

                        if isinstance(err, DiscordException):
                            if err.code in (
                                    ERROR_CODES.
                                    unknown_channel,  # channel deleted
                                    ERROR_CODES.
                                    missing_access,  # client removed
                                    ERROR_CODES.
                                    missing_permissions,  # permissions changed meanwhile
                            ):
                                return

                        await client.events.error(
                            client, f'{self.__class__.__name__}.runner', err)
                        return

            if self.cancelled:
                return

            self.waiter = None

            element = HistoryElement()
            element.question = question
            element.answer = answer
            element.options = self.options
            element.answers = [(value[0], value[1] - circle_start)
                               for value in (answers[user.id]
                                             for user in self.users)]
            self.history.append(element)

            answers.clear()

            embed.title = f'Last answer: {answer}'

        self.cancel()

        embed = Embed(embed.title, color=KANAKO_COLOR)
        try:
            await client.message_create(channel, embed=embed)
        except BaseException as err:
            self.cancel()
            if isinstance(err, ConnectionError):
                return

            if isinstance(err, DiscordException):
                if err.code in (
                        ERROR_CODES.unknown_channel,  # channel deleted
                        ERROR_CODES.missing_access,  # client removed
                        ERROR_CODES.
                        missing_permissions,  # permissions changed meanwhile
                ):
                    return

            await client.events.error(client,
                                      f'{self.__class__.__name__}.runner', err)
            return

        await GameStatistics(self)
示例#6
0
async def buy(client, event,
        item : ([(item.name, item.id) for item in BUYABLE], 'Select the item to buy nya!'),
        amount : (int, 'How much items would you want to buy?'),
            ):
    """Buy?"""
    try:
        item = ITEMS[item]
    except KeyError:
        abort('Item not available.')
    
    permissions = event.channel.cached_permissions_for(client)
    if (not permissions.can_send_messages) or (not permissions.can_add_reactions):
        abort('I need `send messages` and `add reactions` permissions to execute the command.')
    
    yield
    
    user = event.user
    async with DB_ENGINE.connect() as connector:
        response = await connector.execute(
            select([currency_model.total_love]). \
                where(currency_model.user_id==user.id))
        
        results = await response.fetchall()
        if results:
            total_love = results[0]
        else:
            total_love = 0
    
    embed = Embed('Confirm buying',
        f'Selected item: {item.emoji:e} **{item.name}**\n'
        f'Amount: **{amount}**\n'
        f'\n'
        f'Price: {calculate_buy_cost(item.market_cost, amount)} {EMOJI__HEART_CURRENCY:e}\n'
        f'Budget: {total_love} {EMOJI__HEART_CURRENCY:e}'
    )
    
    embed.add_author(user.avaar_url, user.full_name)
    embed.add_footer('The prices of context of demand and supply.')
    
    message = await client.message_create(event.channel, embed=embed)
    await client.reaction_add(message, item.emoji)
    await client.reaction_add(message, CONFIRM_NAH)
    
    try:
        event = await wait_for_reaction(client, message, partial_func(check_confirm_emoji, item.emoji), 300.0)
    except TimeoutError:
        return
    
    if event.emoji is CONFIRM_NAH:
        embed.title = 'Buying cancelled'
    else:
        user = event.user
        async with DB_ENGINE.connect() as connector:
            response = await connector.execute(
                select([currency_model.total_love, currency_model.total_allocated]). \
                    where(currency_model.user_id==user.id))
            
            results = await response.fetchall()
            if results:
                total_love, total_allocated = results[0]
            else:
                total_love = total_allocated = 0
            
            if total_love == 0:
                amount = cost = 0
            else:
                amount, cost = calculate_buyable_and_cost(item.market_cost, amount, total_love-total_allocated)
                
                item.market_cost += amount
            
            if cost == 0:
                new_love = total_love
            else:
                new_love = total_love-cost
                await connector.execute(update(currency_model.user_id==user.id). \
                    values(total_love = new_love))
                
                response = await connector.execute(select([item_model.id, item_model.amount]). \
                    where(item_model.user_id==user.id).where(item_model.type==item.id))
                
                results = await response.fetchall()
                if results:
                    row_id, actual_amount = results[0]
                    new_amount = actual_amount+amount
                    to_execute = ITEM_TABLE.update().values(
                        amount=new_amount
                            ).where(item_model.id==row_id)
                else:
                    to_execute = ITEM_TABLE.insert().values(
                        user_id = user.id,
                        amount  = amount,
                        type    = item.id
                    )
                
                await connector.execute(to_execute)
        
        embed.title = 'Buying confirmed'
        embed.description = (
            f'Selected item: {item.emoji:e} **{item.name}**\n'
            f'Bought mount: **{amount}**\n'
            f'\n'
            f'Hearts: {total_love} {EMOJI__HEART_CURRENCY:e} -> {new_love} {EMOJI__HEART_CURRENCY:e}'
        )
    
    await client.message_edit(message, embed=embed)
示例#7
0
    async def run(self):
        client = self.client
        channel = self.channel
        answers = self.answers
        buffer = ReuBytesIO()
        embed = Embed(color=KANAKO_COLOR)
        embed.add_image('attachment://guessme.png')
        embed.add_footer('')
        time_till_notify = CIRCLE_TIME - 10

        for index, (question, answer) in enumerate(self.map, 1):
            embed.footer.text = f'{index} / {len(self.map)}'
            if self.possibilities:
                self.options = self.generate_options(answer)
                embed.description = '\n'.join([
                    f'**{index}.: {value}**'
                    for index, value in enumerate(self.options, 1)
                ])

            try:
                await client.message_create(channel,
                                            embed=embed,
                                            file=('guessme.png',
                                                  draw(buffer, question)))
            except DiscordException:
                return self.cancel()

            circle_start = LOOP_TIME()
            waiter = sleep(time_till_notify, client.loop)
            self.waiter = waiter
            try:
                await waiter
                Task(
                    self.send_or_except(
                        Embed(
                            'Hurry! Only 10 seconds left!', '\n'.join([
                                user.full_name for user in self.users
                                if user.id not in answers
                            ]), KANAKO_COLOR)), client.loop)
                waiter = sleep(time_till_notify, client.loop)
                self.waiter = waiter
                await waiter
                self.calculate_leavers()
            except CancelledError:
                pass
            except InterruptedError as err:
                return self.cancel()

            element = history_element()
            element.question = question
            element.answer = answer
            element.options = self.options
            element.answers = [(value[0], value[1] - circle_start)
                               for value in (answers[user.id]
                                             for user in self.users)]
            self.history.append(element)

            answers.clear()

            embed.title = f'Last answer: {answer}'

        await self.send_or_except(Embed(embed.title, '', KANAKO_COLOR))

        del ACTIVE_GAMES[channel.id]
        client.events.message_create.remove(self.channel, self)
        self.running = False

        await game_statistics(self)