예제 #1
0
async def sticker_top(
    raw_sticker: ('str', 'Pick an sticker', 'sticker'),
    months: (range(1, 13), 'The months to get') = 1,
):
    """List the users using the given sticker the most."""
    sticker = GUILD__NEKO_DUNGEON.get_sticker_like(raw_sticker)
    if sticker is None:
        abort(f'There is not sticker with name `{raw_sticker}` in the guild.')

    async with DB_ENGINE.connect() as connector:
        response = await connector.execute(
            select([
            sticker_counter_model.user_id,
            alchemy_function.count(sticker_counter_model.user_id).label('total'),
            ]). \
            where(and_(
                sticker_counter_model.sticker_id == sticker.id,
                sticker_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months,
            )). \
            limit(30). \
            group_by(sticker_counter_model.user_id). \
            order_by(desc('total'))
        )

        results = await response.fetchall()

    if results:
        index = 0
        limit = len(results)
        description_parts = []

        while True:
            user_id, count = results[index]

            index += 1

            try:
                user = USERS[user_id]
            except KeyError:
                continue

            try:
                guild_profile = user.guild_profiles[GUILD__NEKO_DUNGEON]
            except KeyError:
                nick = None
            else:
                nick = guild_profile.nick

            description_parts.append(str(index))
            description_parts.append('.: **')
            description_parts.append(str(count))
            description_parts.append('** x ')
            description_parts.append(user.full_name)
            if (nick is not None):
                description_parts.append(' *[')
                description_parts.append(nick)
                description_parts.append(']*')

            if index == limit:
                break

            description_parts.append('\n')
            continue

        description = ''.join(description_parts)
    else:
        description = '*No usages recorded*'

    return Embed(
        f'Top sticker users of {sticker.name}',
        description,
    ).add_thumbnail(sticker.url)
예제 #2
0
async def most_used(
    months: (range(1, 13), 'The months to get') = 1,
    page: ('int', 'Select a page') = 1,
    order: (ORDERS, 'Ordering?') = ORDER_DECREASING,
):
    """Shows the most used stickers."""
    if page < 1:
        abort('Page value can be only positive')

    low_date_limit = datetime.utcnow() - RELATIVE_MONTH * months
    is_new_limit = datetime.utcnow() - MONTH

    async with DB_ENGINE.connect() as connector:

        response = await connector.execute(
            select([
                sticker_counter_model.sticker_id,
                alchemy_function.count(sticker_counter_model.user_id).label('total'),
            ]). \
            where(and_(
                sticker_counter_model.timestamp > low_date_limit,
            )). \
            group_by(sticker_counter_model.sticker_id)
        )

        results = await response.fetchall()

    items = []

    guild_stickers = set(GUILD__NEKO_DUNGEON.stickers.values())

    for sticker_id, count in results:
        try:
            sticker = STICKERS[sticker_id]
        except KeyError:
            continue

        guild_stickers.discard(sticker)

        is_new = (sticker.created_at >= is_new_limit)
        items.append((sticker, count, is_new))

    for sticker in guild_stickers:
        is_new = (sticker.created_at >= is_new_limit)
        items.append((sticker, 0, is_new))

    items.sort(key=item_sort_key, reverse=order)

    page_shift = (page - 1) * MOST_USED_PER_PAGE

    index = page_shift
    limit = min(len(items), index + MOST_USED_PER_PAGE)

    description_parts = []

    if index < limit:
        while True:
            sticker, count, is_new = items[index]
            index += 1

            description_parts.append(str(index))
            description_parts.append('.: **')
            description_parts.append(str(count))
            description_parts.append('** x ')
            description_parts.append(sticker.name)

            if is_new:
                description_parts.append(' *[New!]*')

            if index == limit:
                break

            description_parts.append('\n')
            continue

        description = ''.join(description_parts)
    else:
        description = '*No recorded data*'

    return Embed('Most used stickers:', description). \
        add_footer(f'Page {page} / {(len(items)//MOST_USED_PER_PAGE)+1}')
예제 #3
0
    async def __new__(cls, client, message, guild, changes):
        unused_emojis = set(message.reactions.keys())
        used_emojis = {item[0] for item in changes.added}
        unused_emojis -= used_emojis

        for emoji in unused_emojis:
            try:
                await client.reaction_delete_emoji(message, emoji)
            except BaseException as err:
                if isinstance(err, ConnectionError):
                    return

                if isinstance(err, DiscordException):
                    if err.code in (
                            ERROR_CODES.unknown_message,  # message deleted
                            ERROR_CODES.unknown_channel,  # channel deleted
                            ERROR_CODES.invalid_access,  # client removed
                            ERROR_CODES.
                            invalid_permissions,  # permissions changed meanwhile
                    ):
                        return

                await client.events.error(client, f'{cls.__name__}.__new__',
                                          err)
                return

        for emoji in used_emojis:
            try:
                await client.reaction_add(message, emoji)
            except BaseException as err:
                if isinstance(err, ConnectionError):
                    return

                if isinstance(err, DiscordException):
                    if err.code in (
                            ERROR_CODES.unknown_emoji,  # emoji deleted
                            ERROR_CODES.
                            max_reactions,  # reached reaction 20, some1 is trolling us.
                            ERROR_CODES.unknown_message,  # message deleted
                            ERROR_CODES.unknown_channel,  # channel deleted
                            ERROR_CODES.invalid_access,  # client removed
                            ERROR_CODES.
                            invalid_permissions,  # permissions changed meanwhile
                    ):
                        return

                await client.events.error(client, f'{cls.__name__}.__new__',
                                          err)
                return

        data = bytearray(320)
        position = 0

        relations = {}

        for emoji, role in changes.added:
            data[position:position + 8] = emoji.id.to_bytes(8, byteorder='big')
            position += 8
            data[position:position + 8] = role.id.to_bytes(8, byteorder='big')
            position += 8

            relations[emoji] = role
            relations[role] = emoji

        async with DB_ENGINE.connect() as connector:
            await connector.execute(AUTO_REACT_ROLE_TABLE.insert().values(
                message_id=message.id,
                channel_id=message.channel.id,
                data=data,
                behaviour=changes.new_behaviour,
                client_id=client.id))

        self = object.__new__(cls)
        self.message = message
        self.relations = relations
        self.behaviour = changes.new_behaviour
        self.guild = guild
        self.client = client
        self.destroy_called = False
        self.add_events()
        return self
예제 #4
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)
예제 #5
0
async def most_used(
        months: (range(1, 13), 'The months to get') = 1,
        page: ('int', 'Select a page') = 1,
        type_: (EMOJI_MOST_USED_TYPES, 'Choose emoji type to filter on') = EMOJI_MOST_USED_TYPE_ALL,
        action_type: (EMOJI_COMMAND_ACTION_TYPES, ('Choose emoji action type')) = EMOJI_COMMAND_ACTION_TYPE_ALL,
        order: (ORDERS, 'Ordering?') = ORDER_DECREASING,
            ):
    """Shows the most used emojis."""
    
    if page < 1:
        abort('Page value can be only positive')
    
    low_date_limit = datetime.utcnow()-RELATIVE_MONTH*months
    is_new_limit = datetime.utcnow()-MONTH
    
    async with DB_ENGINE.connect() as connector:
        
        statement = (
            select([
                emoji_counter_model.emoji_id,
                alchemy_function.count(emoji_counter_model.user_id).label('total'),
            ]). \
            where(and_(
                emoji_counter_model.timestamp > low_date_limit,
            )). \
            group_by(emoji_counter_model.emoji_id)
        )
        
        if (action_type != EMOJI_COMMAND_ACTION_TYPE_ALL):
            statement = statement.where(emoji_counter_model.action_type==action_type)
        
        response = await connector.execute(statement)
        results = await response.fetchall()
    
    items = []
    
    emoji_filter = EMOJI_MOST_USED_FILTERS[type_]
    
    guild_emojis = set(emoji for emoji in GUILD__NEKO_DUNGEON.emojis.values() if emoji_filter(emoji))
    
    for emoji_id, count in results:
        try:
            emoji = EMOJIS[emoji_id]
        except KeyError:
            continue
        
        if not emoji_filter(emoji):
            continue
        
        guild_emojis.discard(emoji)
        
        is_new = (emoji.created_at >= is_new_limit)
        items.append((emoji, count, is_new))
    
    for emoji in guild_emojis:
        is_new = (emoji.created_at >= is_new_limit)
        items.append((emoji, 0, is_new))
    
    items.sort(key=item_sort_key, reverse=order)
    
    page_shift = (page-1)*MOST_USED_PER_PAGE
    
    index = page_shift
    limit = min(len(items), index+MOST_USED_PER_PAGE)
    
    description_parts = []
    
    if index < limit:
        while True:
            emoji, count, is_new = items[index]
            index += 1
            
            description_parts.append(str(index))
            description_parts.append('.: **')
            description_parts.append(str(count))
            description_parts.append('** x ')
            description_parts.append(emoji.as_emoji)
            
            if is_new:
                description_parts.append(' *[New!]*')
            
            if index == limit:
                break
            
            description_parts.append('\n')
            continue
        
        description = ''.join(description_parts)
    else:
        description = '*No recorded data*'
    
    return Embed('Most used emojis:', description). \
        add_footer(f'Page {page} / {(len(items)//MOST_USED_PER_PAGE)+1}')
예제 #6
0
async def emoji_top(
        raw_emoji: ('str', 'Pick an emoji', 'emoji'),
        months: (range(1, 13), 'The months to get') = 1,
        action_type: (EMOJI_COMMAND_ACTION_TYPES, ('Choose emoji action type')) = EMOJI_COMMAND_ACTION_TYPE_ALL,
            ):
    """List the users using the given emoji the most."""
    emoji = parse_emoji(raw_emoji)
    if emoji is None:
        emoji = GUILD__NEKO_DUNGEON.get_emoji_like(raw_emoji)
        if emoji is None:
            abort(f'`{raw_emoji}` is not an emoji.')
    else:
        if emoji.is_unicode_emoji():
            abort(f'{emoji:e} is an unicode emoji. Please give custom.')
        
        if emoji.guild is not GUILD__NEKO_DUNGEON:
            abort(f'{emoji:e} is bound to an other guild.')
    
    async with DB_ENGINE.connect() as connector:
        statement = (
            select([
            emoji_counter_model.user_id,
            alchemy_function.count(emoji_counter_model.user_id).label('total'),
            ]). \
            where(and_(
                emoji_counter_model.emoji_id == emoji.id,
                emoji_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months,
            )). \
            limit(30). \
            group_by(emoji_counter_model.user_id). \
            order_by(desc('total'))
        )
        
        if (action_type != EMOJI_COMMAND_ACTION_TYPE_ALL):
            statement = statement.where(emoji_counter_model.action_type==action_type)
        
        response = await connector.execute(statement)
        results = await response.fetchall()
    
    
    if results:
        index = 0
        limit = len(results)
        description_parts = []
        
        while True:
            user_id, count = results[index]
            
            index += 1
            
            try:
                user = USERS[user_id]
            except KeyError:
                continue
            
            try:
                guild_profile = user.guild_profiles[GUILD__NEKO_DUNGEON]
            except KeyError:
                nick = None
            else:
                nick = guild_profile.nick
            
            description_parts.append(str(index))
            description_parts.append('.: **')
            description_parts.append(str(count))
            description_parts.append('** x ')
            description_parts.append(user.full_name)
            if (nick is not None):
                description_parts.append(' *[')
                description_parts.append(nick)
                description_parts.append(']*')
            
            if index == limit:
                break
            
            description_parts.append('\n')
            continue
        
        description = ''.join(description_parts)
    else:
        description = '*No usages recorded*'
    
    
    return Embed(
        f'Top emoji users of {emoji.name}',
        description,
    ).add_thumbnail(emoji.url)
예제 #7
0
async def user_top(event,
        user: ('user', 'By who?') = None,
        count: (range(10, 91, 10), 'The maximal amount of emojis to show') = 30,
        months: (range(1, 13), 'The months to get') = 1,
        action_type: (EMOJI_COMMAND_ACTION_TYPES, ('Choose emoji action type')) = EMOJI_COMMAND_ACTION_TYPE_ALL,
            ):
    """List the most used emojis at ND by you or by the selected user."""
    if user is None:
        user = event.user
    
    async with DB_ENGINE.connect() as connector:
        statement = (
            select([
                emoji_counter_model.emoji_id,
                alchemy_function.count(emoji_counter_model.emoji_id).label('total'),
            ]). \
            where(and_(
                emoji_counter_model.user_id == user.id,
                emoji_counter_model.timestamp > datetime.utcnow()-RELATIVE_MONTH*months,
            )). \
            limit(count). \
            group_by(emoji_counter_model.emoji_id). \
            order_by(desc('total'))
        )
        
        if (action_type != EMOJI_COMMAND_ACTION_TYPE_ALL):
            statement = statement.where(emoji_counter_model.action_type==action_type)
        
        response = await connector.execute(statement)
        results = await response.fetchall()
    
    embed = Embed(
        f'Most used emojis by {user.full_name}',
        color = user.color_at(GUILD__NEKO_DUNGEON),
    ).add_thumbnail(user.avatar_url)
    
    if results:
        description_parts = []
        start = 1
        limit = len(results)
        index = 0
        
        while True:
            emoji_id, count = results[index]
            
            index += 1
            
            try:
                emoji = EMOJIS[emoji_id]
            except KeyError:
                continue
            
            description_parts.append(str(index))
            description_parts.append('.: **')
            description_parts.append(str(count))
            description_parts.append('** x ')
            description_parts.append(emoji.as_emoji)
            if (not index%10) or (index == limit):
                description = ''.join(description_parts)
                description_parts.clear()
                embed.add_field(f'{start} - {index}', description, inline=True)
                
                if (index == limit):
                    break
                
                start = index+1
                continue
            
            description_parts.append('\n')
            continue
    
    else:
        embed.description = '*No recorded data.*'
    
    return embed