示例#1
0
    async def projects(self, ctx, *, project_name: str = None):
        user_lookup = utils.UserLookup(ctx.bot)

        if not project_name:
            session = database.new_session()
            projects = sorted(session.query(database.Project).all(),
                              key=lambda proj: proj.name)
            users = session.query(database.User).all()

            lookup = {}
            for user in users:
                for p in user.projects:
                    if p.id not in lookup:
                        lookup[p.id] = []
                    if user.mal_name:
                        lookup[p.id].append(
                            user_lookup.display_name_from_mal(user.mal_name))

            message = '\n'.join(
                map(lambda x: self.project_string(x, lookup), projects))
            await utils.safe_say(
                ctx,
                f'Use `!project [project_name]` to get details about a project.\n\n{message}'
            )
        else:
            project_name = project_name.strip()
            session = database.new_session()
            await ctx.bot.say(
                self.project_build_message(ctx, session, user_lookup,
                                           project_name))
示例#2
0
    async def preload_all(self):
        print('Preloading lists...')
        session = database.new_session()
        users = session.query(database.User).filter(
            database.User.mal_name.isnot(None)).all()

        for entity in ['anime', 'manga']:
            print(f'Downloading {entity} lists...')
            downloaded = self.animelists if entity == 'anime' else self.mangalists
            dl_stats = self.anime_stats if entity == 'anime' else self.manga_stats
            async with aiohttp.ClientSession() as session:
                for user in users:
                    try:
                        list = await self.load_entity_list(user.mal_name,
                                                           session,
                                                           entity=entity)
                        downloaded[user.mal_name] = list[entity]
                        dl_stats[user.mal_name] = list['statistics']
                    except:
                        pass

            if downloaded:
                print('Download complete')
                if entity == 'anime':
                    self.animelists = downloaded
                    self.anime_stats = dl_stats
                elif entity == 'manga':
                    self.mangalists = downloaded
                    self.manga_stats = dl_stats

        print('Preloading airing...')
        await self.require_airing()
        print('Done.')

        self.last_update = datetime.datetime.now()
示例#3
0
    async def db_update(self, ctx):
        await shared.state.lock_user(ctx, '!user update')

        try:
            user_id = ctx.message.author.id

            session = database.new_session()
            user = session.query(database.User).filter(
                database.User.discord_id == user_id).first()
            if user is None:
                await ctx.bot.whisper(
                    f'Hello {ctx.message.author.name}, your profile doesn\'t exist yet. Please run `!user setup` to get started!'
                )
                return

            fields = ', '.join(map(lambda x: f'`{x}`', self.questions.keys()))
            fields += 'and `projects`'
            dm = await ctx.bot.whisper(
                f'Hello {ctx.message.author.name}, You can edit any of the following fields (just type its name, or `done` to stop updating your profile):\n{fields}'
            )
            data = {
                'ctx': ctx,
                'user': ctx.message.author,
                'channel': dm.channel,
            }

            while True:
                response = await self.db_wait_message(data)
                response = response.lower()

                if response == 'done':
                    break

                elif response in ['mal_name', 'gender', 'bio']:
                    setattr(user, response, await self.db_ask(data, response))
                    session.commit()
                elif response in ['birthdate']:
                    setattr(user, response, await
                            self.db_ask_date(data, response))
                    session.commit()
                elif response == 'country':
                    await self.db_fill_country(ctx, data, session, user)
                elif response == 'timezone':
                    await self.db_fill_tz(ctx, data, session, user)
                elif response == 'languages':
                    await self.db_fill_languages(ctx, data, session, user)
                elif response == 'prog_languages':
                    await self.db_fill_prog_languages(ctx, data, session, user)
                elif response == 'projects':
                    await self.update_projects(ctx, data, session, user)

                await ctx.bot.whisper(
                    f'You can edit any of the following fields (just type its name, or `done` to stop updating your profile):\n{fields}'
                )

            await ctx.bot.whisper(f'Thank you!')
        finally:
            shared.state.unlock(ctx)
示例#4
0
    async def list(self, ctx):
        session = database.new_session()
        extras = session.query(database.Extras).all()

        message = ''
        for extra in extras:
            options = f' => {extra.options}' if extra.options else ''
            message += f'**{extra.id}** - {extra.question}{options}\n'

        await utils.safe_say(ctx, message)
示例#5
0
async def require_mal_username(ctx, member):
    if member is None:
        member = ctx.message.author

    session = database.new_session()
    user = session.query(
        database.User).filter(database.User.discord_id == member.id).first()

    if user is None or user.mal_name is None:
        await ctx.bot.say(f'{member.name} has not set their MAL username!')
        return None
    return user.mal_name
示例#6
0
    def __init__(self, bot):
        self.bot = bot

        session = database.new_session()
        users = session.query(database.User).all()
        table = {}
        for user in users:
            if user.mal_name:
                table[user.mal_name] = user.discord_id

        self.mal_table = table
        self.user_id_cache = {}
示例#7
0
async def check_birthdays(bot):
    print(f'checking birthdays {datetime.datetime.utcnow()}')
    utils.write_property('last_birthday_check', datetime.datetime.utcnow().strftime('%Y-%m-%d'))

    session = database.new_session()
    users = session.query(database.User).filter(database.User.birthdate.isnot(None)).all()

    today = datetime.datetime.utcnow().strftime('%Y-%m-%d')
    for user in users:
        if user.birthdate[4:] == today[4:]:
            if user.discord_id not in shared.birthday_blacklist:
                if utils.is_birthdate_valid(user.birthdate):
                    await wish_birthday(bot, user)
示例#8
0
    async def db_update(self, ctx):
        await shared.state.lock_user(ctx, '!user extras update')

        try:
            session = database.new_session()
            user = await self.get_user(ctx, session, ctx.message.author.id)

            extras = session.query(database.Extras).all()
            user_extras = session.query(database.UserExtras).filter(
                database.UserExtras.user_id == user.id).all()

            if len(extras) == 0:
                await ctx.bot.whisper('No extras available')
                return

            done_extras, new_extras = self.sort_extras(extras, user_extras)

            done_extras_display = '\n'.join(
                map(lambda x: f'**{x["extra"].id}** - {x["extra"].question}',
                    done_extras))
            new_extras_display = '\n'.join(
                map(lambda x: f'**{x.id}** - {x.question}', new_extras))

            if not done_extras_display:
                done_extras_display = 'None'
            if not new_extras_display:
                new_extras_display = 'None'

            message = f"""To answer a question, simply type its identifier.
If you do not want to answer a question, simply type `-` and I will skip it (and remove your previous answer if any).
If at any point you want to stop editing questions, type `!quit` (or `done` when selecting questions).
Questions you've already answered:
{done_extras_display}

New questions:
{new_extras_display}"""

            dm = await utils.force_say(message, ctx.bot.whisper)

            data = {
                'ctx': ctx,
                'user': ctx.message.author,
                'channel': dm.channel,
            }

            while True:
                done_extras, new_extras = await self.db_update_loop(
                    ctx, data, session, user, done_extras, new_extras)
        finally:
            shared.state.unlock(ctx)
示例#9
0
    async def rm(self, ctx, id):
        session = database.new_session()
        extra = session.query(database.Extras).filter(database.Extras.id == id).first()

        if extra:
            user_extras = session.query(database.UserExtras).filter(database.UserExtras.extras_id == extra.id).all()
            for item in user_extras:
                session.delete(item)

            session.delete(extra)
            session.commit()
            await ctx.bot.add_reaction(ctx.message, shared.reaction_ok)
        else:
            await ctx.bot.add_reaction(ctx.message, shared.reaction_ko)
示例#10
0
    async def add(self, ctx, *, raw):
        parts = raw.split('=>')

        question = parts[0].strip()
        session = database.new_session()
        new_extra = database.Extras(question=question)

        if len(parts) > 1:
            options = parts[1].strip()
            new_extra.options = options

        session.add(new_extra)
        session.commit()

        await ctx.bot.add_reaction(ctx.message, shared.reaction_ok)
示例#11
0
    async def require_entity_lists(self, ctx, entity):
        session = database.new_session()
        users = session.query(database.User).filter(
            database.User.mal_name.isnot(None)).all()

        self.cleanup_cache(users)
        self.check_cache_expiry()
        if len(self.entitylists(entity)) >= len(users):
            return self.entitylists(entity)
        else:
            errors = []
            loaded = 0
            loading_message = await ctx.bot.say(
                f'Refreshing cached {entity}lists...')
            async with aiohttp.ClientSession() as session:
                for user in users:
                    if user.mal_name not in self.entitylists(entity):
                        try:
                            if user.mal_name:
                                list = await self.load_entity_list(
                                    user.mal_name, session, entity=entity)
                                self.set_entitylists(entity, user.mal_name,
                                                     list[entity])
                                self.set_stats(entity, user.mal_name,
                                               list['statistics'])

                            loaded += 1
                            if user.mal_name:
                                await ctx.bot.edit_message(
                                    loading_message,
                                    f'Refreshing cached {entity}lists... ({loaded}/{len(users)})'
                                )
                        except Exception as e:
                            errors.append(
                                f'Error getting {user.mal_name}\'s {entity}list: {e}'
                            )

            await ctx.bot.delete_message(loading_message)
            #if errors:
            #    await ctx.bot.edit_message(loading_message, f'Finished loading with {len(errors)} errors.\n')
            #else:
            #    await ctx.bot.edit_message(loading_message, f'Loaded {len(self.entitylists(entity))} lists.')

        self.last_update = datetime.datetime.now()
        return self.entitylists(entity)
示例#12
0
    async def db_setup(self, ctx):
        await shared.state.lock_user(ctx, '!user extras setup')

        try:
            session = database.new_session()
            user = await self.get_user(ctx, session, ctx.message.author.id)

            extras = session.query(database.Extras).all()
            user_extras = session.query(database.UserExtras).filter(
                database.UserExtras.user_id == user.id).all()

            if len(extras) == 0:
                await ctx.bot.whisper('No extras available')
                return

            done_extras, new_extras = self.sort_extras(extras, user_extras)

            if len(new_extras) == 0:
                await ctx.bot.whisper(
                    'You\'ve already answered all extra questions. To edit them, use `!extras update`.'
                )
                return

            dm = await ctx.bot.whisper(
                """I will now ask you some random questions.
If you do not want to answer a question, simply type `-` and I will skip it.
If possible answers are specified, you can only use one of them. Otherwise, you're free to write what you want.
If at any point you want to stop answering these questions, type `!quit`.
""")

            data = {
                'ctx': ctx,
                'user': ctx.message.author,
                'channel': dm.channel,
            }

            for item in new_extras:
                await self.ask_extra(data, session, user, item)

            await ctx.bot.whisper(
                'Annnnnnd done! Thank you! You can use `!profile extras [user]` to view other people\'s answers.'
            )
        finally:
            shared.state.unlock(ctx)
示例#13
0
    def util_list_all(self, wants_stat_grouping, wants_grouping_detail,
                      valid_user_check, get_grouping_properties,
                      get_display_string, sorting, formatted_group_name):
        session = database.new_session()
        users = session.query(database.User).all()

        items_lookup = {}
        for user in users:
            if valid_user_check(user) and user.mal_name:
                properties = get_grouping_properties(user)
                for meta, property in properties:
                    if property in items_lookup:
                        items_lookup[property].append((user, meta))
                    else:
                        items_lookup[property] = [(user, meta)]

        sorted_items = sorting(items_lookup) if sorting else sorted(
            items_lookup.keys())
        message = ''
        for item in sorted_items:
            if wants_grouping_detail:
                message += f'`{formatted_group_name(item, items_lookup[item])}: `'
            else:
                message += f'**{formatted_group_name(item, items_lookup[item])}**: '
            n = len(items_lookup[item])
            if wants_stat_grouping:
                if wants_grouping_detail:
                    message += f' **{n}**'
                else:
                    message += f' {n}'

            names = ', '.join(
                map(lambda x: get_display_string(x[0], x[1]),
                    items_lookup[item]))
            if wants_stat_grouping:
                if wants_grouping_detail:
                    message += f' *({names})*'
            else:
                message += f'{names}'

            message += '\n'

        return message
示例#14
0
    def convert(self):
        message = self.ctx.message
        bot = self.ctx.bot
        match = self._get_id_match() or re.match(r'<@!?([0-9]+)>$',
                                                 self.argument)
        server = message.server
        result = None

        # Exact discord match or ID
        if match is None:
            result = self.convert_get_from_member(server, bot,
                                                  'get_member_named')
        else:
            user_id = match.group(1)
            if server:
                result = server.get_member(user_id)
            else:
                result = converter._get_from_servers(bot, 'get_member',
                                                     user_id)

        # Exact MAL match
        session = database.new_session()
        if result is None:
            result = self.convert_get_from_mal(session, server, bot,
                                               self.argument)

        # Fuzzy discord match
        if result is None:
            result = self.convert_get_from_member(server, bot,
                                                  'get_member_named_fuzzy')

        # Fuzzy MAL match
        if result is None:
            result = self.convert_get_from_mal(session, server, bot,
                                               f'%{self.argument}%')

        if result is None:
            raise errors.BadArgument('Member "{}" not found'.format(
                self.argument))

        return result
示例#15
0
    async def edit(self, ctx, id, *, raw):
        session = database.new_session()
        extra = session.query(database.Extras).filter(database.Extras.id == id).first()

        if extra:
            parts = raw.split('=>')

            question = parts[0].strip()
            extra.question = question

            if len(parts) > 1:
                options = parts[1].strip()
                extra.options = options
            else:
                extra.options = None

            session.commit()

            await ctx.bot.add_reaction(ctx.message, shared.reaction_ok)
        else:
            await ctx.bot.add_reaction(ctx.message, shared.reaction_ko)
示例#16
0
    async def profile(self,
                      ctx,
                      first_param: str = None,
                      second_param: str = None):

        show_extra = None
        if first_param and (first_param
                            in ['extra', 'extras', '+extra', '+extras']):
            member_raw = second_param
            show_extra = first_param
        elif second_param and (second_param
                               in ['extra', 'extras', '+extra', '+extras']):
            member_raw = first_param
            show_extra = second_param
        else:
            member_raw = first_param

        member = await utils.convert_member(ctx, member_raw, optional=True)
        if member is None:
            member = ctx.message.author

        session = database.new_session()
        user = session.query(database.User).filter(
            database.User.discord_id == member.id).first()

        if user is None:
            await ctx.bot.say(f'No data recorded for {member.name}')
            return

        if not show_extra or show_extra.startswith('+'):
            await ctx.bot.say(embed=self.profile_main_message(
                ctx, user, member, session, show_extra))
        if show_extra:
            message = self.profile_extra_message(ctx, session, user, member)
            if message:
                await utils.force_say(message, ctx.bot.say)
示例#17
0
    async def users(self, ctx, extras: str = None):
        session = database.new_session()
        users = session.query(database.User).all()

        lookup = {}
        for user in users:
            lookup[user.discord_id] = user

        registered_users_raw = []
        registered_users = []
        new_users = []
        mal_users = lookup

        server_id = ctx.message.server.id if ctx.message.server and ctx.message.server.id else shared.main_server_id
        server = ctx.bot.get_server(server_id)
        for member in server.members:
            if not member.bot:
                true_name = utils.UserLookup.display_name_from_user(member)
                if member.id in lookup:
                    if true_name == lookup[member.id].mal_name:
                        registered_users.append(true_name)
                    else:
                        registered_users.append(
                            f'{true_name} *({lookup[member.id].mal_name})*')
                    registered_users_raw.append(member)
                    mal_users.pop(member.id)
                else:
                    new_users.append(true_name)

        message = ''
        if registered_users:
            message += '**Registered users**:\n'
            message += ', '.join(registered_users)
            message += '\n\n'
        if new_users:
            message += '**Users who have not filled their profile yet** (type `!user setup`):\n'
            message += ', '.join(new_users)
            message += '\n\n'
        if mal_users:
            message += '**Registered users who are not in this server**:\n'
            message += ', '.join(map(lambda x: x.mal_name, mal_users.values()))
            message += '\n\n'

        if extras and extras in ['extra', 'extras']:
            message += 'Registered users with an extras profile:\n'

            user_extras = session.query(database.UserExtras).all()
            extras_lookup = {}
            for item in user_extras:
                extras_lookup[item.user_id] = item

            user_extra_profile = []
            for user in registered_users_raw:
                if lookup[user.id].id in extras_lookup:
                    user_extra_profile.append(
                        utils.UserLookup.display_name_from_user(user))

            message += ', '.join(user_extra_profile)
            message += '\n\n'

        await utils.safe_say(ctx, message)
示例#18
0
    async def tz(self, ctx, member_raw: str = None):
        member = await utils.convert_member(ctx, member_raw, optional=True)
        if member is None:
            user_lookup = utils.UserLookup(ctx.bot)
            session = database.new_session()
            users = session.query(database.User).filter(
                database.User.timezone.isnot(None)).all()

            timezones = {}
            now = datetime.datetime.utcnow()
            for user in users:
                local_time = pytz.utc.localize(now, is_dst=None).astimezone(
                    pytz.timezone(user.timezone))
                key = local_time.strftime('%Y%m%d %H:%M:%S')
                if key in timezones:
                    timezones[key]['data'].append(user)
                else:
                    timezones[key] = {'tz': local_time, 'data': [user]}

            days_tz = {}
            for key in timezones.keys():
                day_string = key.split(' ')[0]
                if day_string not in days_tz:
                    days_tz[day_string] = []
                days_tz[day_string].append({
                    'sorting': key,
                    'time': timezones[key]['tz'],
                    'users': timezones[key]['data']
                })

            sorted_tz = {
                k: sorted(v, key=lambda x: x['sorting'])
                for k, v in days_tz.items()
            }

            flat_tz = []
            for item in sorted_tz.keys():
                flat_tz.append({'day': item, 'data': sorted_tz[item]})

            final_tz = sorted(flat_tz, key=lambda x: x['day'])

            message = ''
            for day in final_tz:
                day_string = day['data'][0]['time'].strftime('%A')
                message += f'**{day_string}:**\n\n'
                for item in day['data']:
                    display_time = item['time'].strftime('%H:%M:%S')
                    tz_users = ', '.join(
                        map(
                            lambda x:
                            f'{user_lookup.display_name_from_mal(x.mal_name)} *({x.timezone})*',
                            item['users']))
                    message += f'{display_time}:\n{tz_users}\n\n'
            await utils.safe_say(ctx, message)

        else:
            session = database.new_session()
            user = session.query(database.User).filter(
                database.User.discord_id == member.id).first()

            if user is None or user.timezone is None:
                await ctx.bot.say(
                    f'{utils.UserLookup.display_name_from_user(member)} has not set their timezone!'
                )
                return

            tz = pytz.timezone(user.timezone)
            time = pytz.utc.localize(datetime.datetime.utcnow(),
                                     is_dst=None).astimezone(tz)
            timezone_string = time.strftime('%A %H:%M:%S')
            await ctx.bot.say(f'{timezone_string} ({user.timezone})\n')
示例#19
0
    async def db_setup(self, ctx, arg=None):

        session = database.new_session()
        user_id = ctx.message.author.id
        user = session.query(
            database.User).filter(database.User.discord_id == user_id).first()

        if user is not None and arg != 'force':
            await ctx.bot.whisper(
                f"""You already have a profile, did you mean to edit it using `!user update`?
If you want to go through the setup again, use `!user setup force`""")
            return

        await shared.state.lock_user(ctx, '!user setup')
        try:
            dm = await ctx.bot.whisper(
                f"""Hello {ctx.message.author.name}, let's get started!
I'm going to ask a few questions so we can get to know you. This is just to get a general idea of who you are, it's not for the NSA, I swear.
If you don't want to answer one of these question, just type `-` and I'll ignore it or put some default value if needed.
You can edit this later using `!user update`.""")

            data = {
                'ctx': ctx,
                'user': ctx.message.author,
                'channel': dm.channel,
            }

            if user is None:
                user = database.User(discord_id=user_id)
                session.add(user)

            user.mal_name = await self.db_ask(data, 'mal_name')
            session.commit()
            user.birthdate = await self.db_ask_date(data, 'birthdate')
            session.commit()
            user.gender = await self.db_ask(data, 'gender')
            session.commit()

            await self.db_fill_country(ctx, data, session, user)
            await self.db_fill_tz(ctx, data, session, user)
            await self.db_fill_languages(ctx, data, session, user)
            await self.db_fill_prog_languages(ctx, data, session, user)
            user.bio = await self.db_ask(data, 'bio')
            session.commit()
            await self.update_projects(ctx, data, session, user)

            session.commit()
            await ctx.bot.whisper(f"""That's all for now, thank you!
You can see your profile or other people's profile by using `!profile [user]`

If you still want to tell us about you, here are some additional commands you can run:
`!user extras setup`: Lets you answer some additional random questions
`b/waifuset`: A command by BobDono to let you set your waifu

You can also run `!bots` for more info about bots, don't hesitate to play with us.
Lastly, keep an eye on the channels under ELECTIONS, we run very important waifu wars in them. Yes, this server is for Intellectuals™.

Also, please avoid using `@everyone` or `@here` unless it's a real emergency.
Instead, you should use `@AMA` if you have a question or need some help.""")

        finally:
            shared.state.unlock(ctx)