Esempio n. 1
0
    async def cancel(self, ctx, req_id=None):
        '''Cancel an application.'''
        # Check if the requester matches, or a staff can cancel.
        data_dict = utils.open_requestlog()

        # Setup a Flow controller.
        flow = request.Flow(self.bot, ctx)
        found = False
        found_data = dict()
        # Since we only allow 1 application per user per time, do a quick search if
        # req_id = none and there is an open application of this user.
        if not req_id:
            req_id = self.auto_find(data_dict, ctx.message.author.name)
        for request_id, details in list(data_dict.items()):
            if str(request_id) == str(req_id):
                # user can only cancel their own request.
                for k, v in list(details.items()):
                    if k == u'name' and ctx.message.author.name in v:
                        message = 'You are about to cancel an application **%s**' % req_id
                        em = utils.get_embed('red',
                                             message,
                                             title='Cancel An Application')
                        await ctx.channel.send(embed=em)
                        found = True
                        details['status'] = utils.Status.CANCEL.name
                        # mark a last_modified timestring
                        tm = time.localtime(time.time())
                        timestring = time.strftime(TIME_FORMAT, tm)
                        details['last_modified'] = timestring
                        found_data[request_id] = details
                        break
        if not found:
            message = 'Your application %s was not found.' % req_id
            em = utils.get_embed('red', message, title='Application Not Found')
            await ctx.channel.send(embed=em)
            return

        are_you_sure = await ctx.send(
            f":information_source: Please confirm YES/NO to cancel"
            f" this application **%s**" % request_id)

        reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200)
        if reaction is None:
            return
        if not reaction:
            em = utils.get_embed('red', 'Aborted.')
            return await ctx.channel.send(embed=em)
        elif reaction:
            utils.flush_requestlog(data_dict)
            await ctx.send(f"You\'ve cancelled this application.")
            await self.send_logs_user('Cancelled application %s by %s' %
                                      (req_id, ctx.message.author.name))
            await sheet.update_data(found_data)
            # Then hide the close row.
            await sheet.archive_column(req_id)
Esempio n. 2
0
async def on_command_error(ctx, error):
    if isinstance(error, commands.DisabledCommand):
        em = utils.get_embed('red',
                             f'_{ctx.command}_ command has been disabled.')
        await ctx.send(embed=em)
    elif isinstance(error, commands.MissingRequiredArgument):
        em = utils.get_embed(
            'red', f'_{ctx.command}_ command missed a required argument.\n'
            'Please use *~help <command>* to see what is missing.')
        await ctx.send(embed=em)

    elif isinstance(error, commands.BadArgument):
        em = utils.get_embed(
            'red', f'_{ctx.command}_ command called a bad argument.\n'
            'Please use *~help <command>* to see what is missing.')
        await ctx.send(embed=em)
    else:
        await ctx.send(error)
Esempio n. 3
0
async def shutdown(ctx):
    '''Shut down the bot'''
    async def close():
        await bot.session.close()
        return await bot.logout()

    logger.info('Disconnected from Discord. Shutting down the bot.')
    em = utils.get_embed('red', 'Shutting down....', title='Offline!')
    await ctx.send(embed=em)
    # Release logger resource.
    for h in logger.handlers:
        h.close()
        logger.removeHandler(h)
    return await close()
Esempio n. 4
0
 async def status(self, ctx):
     '''Check the status of a user's application.'''
     # Retrieve data_dict from the request log file.
     data_dict = utils.open_requestlog()
     found = ""
     for request_id, details in list(data_dict.items()):
         for k, v in list(details.items()):
             if k == u'name' and ctx.message.author.name in v:
                 # also hide closed requests with status == 'cancel',
                 # 'rejected' or 'closed'
                 if details['status'] not in (utils.Status.CLOSED.name,
                                              utils.Status.CANCEL.name,
                                              utils.Status.REJECTED.name):
                     found += 'application_id: **%s**\n' % request_id
                     found += utils.printadict(details, hide_self=True)
                     found += '\n'
     if found:
         await ctx.send("Found your application:")
         color = utils.status_color(details)
         em = utils.get_embed(color, found)
         await ctx.channel.send(embed=em)
     else:
         em = utils.get_embed('red', "You don\'t have any application.")
         await ctx.channel.send(embed=em)
Esempio n. 5
0
async def invite(ctx):
    '''Invite the bot to your server'''
    em = utils.get_embed('gray',
                         f'Invite me to your server: {INVITE_URL}',
                         title='Invite me!')
    await ctx.send(embed=em)
Esempio n. 6
0
async def ping(ctx):
    '''Pong! Get the bot's response time'''
    em = utils.get_embed('green', f'{bot.latency * 1000} ms', title='Pong!')
    await ctx.send(embed=em)
    for guild in bot.guilds:
        print('Joined this guild: %s(%d)' % (guild.name, guild.id))
Esempio n. 7
0
    async def apply(self, ctx, villager=None):
        '''Apply to request a villager and get an <application ID> in return.'''

        # Setup a Flow controller.
        flow = request.Flow(self.bot, ctx)
        # Find is_bot_locked from Staff cog.
        staff_cog = self.bot.get_cog('Staff')
        if staff_cog.is_bot_locked:
            text = 'I am sorry but the application queue is now locked and '
            text += 'cannot accept any application.\nPlease stay tuned in the '
            text += '#villager-adoption-program channel for future updates.'
            em = utils.get_embed('gold', text)
            return await ctx.channel.send(embed=em)
        if not villager:
            text = 'Greetings! Which villager would you like to request?\n'
            text += 'Use `~apply <villager>` command to create an application.'
            em = utils.get_embed('gray', text)
            return await ctx.channel.send(embed=em)
        # Before starting anything, check if this applicant was rejected in
        # the last two weeks.
        data_dict = utils.open_requestlog()
        rejected = []
        for request_id, details in list(data_dict.items()):
            for k, v in list(details.items()):
                if k == u'name' and ctx.message.author.name in v:
                    # also hide requests with status == 'cancel' or 'closed'
                    if details['status'] in (utils.Status.REJECTED.name):
                        rejected.append(details)
        current = datetime.datetime.utcnow()
        for detail in rejected:
            # Fixed the period to 2 weeks.
            then_ts = time.strptime(detail['last_modified'], TIME_FORMAT)
            then_dt = datetime.datetime.fromtimestamp(time.mktime(then_ts))
            period = datetime.timedelta(days=14)
            if (current - then_dt) < period:
                rejected_msg = (
                    'Sorry, your previous application was closed at '
                    '%s within a two weeks cooldown.\nPlease come back'
                    ' and reapply later.' % detail['last_modified'])
                em = utils.get_embed('red',
                                     rejected_msg,
                                     title='Still In Cooldown')
                await self.send_logs_user('%s attempted to re-apply a dreamie '
                                          'while in a 2 weeks cooldown.' %
                                          detail['name'])
                return await ctx.channel.send(embed=em)
        # Viallger name differeniation: some villagers have a space char
        # between its names:
        v = villager.lower()
        if v is not 'kidd' and v in ('kid', 'agent', 'big', 'wart'):
            if v == 'kid':
                villager = 'Kid Cat'
                villager_link = 'https://villagerdb.com/villager/kid-cat'
            if v == 'agent':
                villager = 'Agent S'
                villager_link = 'https://villagerdb.com/villager/agent-s'
            if v == 'big':
                villager = 'Big Top'
                villager_link = 'https://villagerdb.com/villager/big-top'
            if v == 'wart':
                villager = 'Wart Jr.'
                villager_link = 'https://villagerdb.com/villager/wart-jr'
        else:
            # Form a villager link
            villager_link = 'https://villagerdb.com/villager/{}'.format(
                villager.lower())
            villager = villager.capitalize()
        # Validate the villager's name before everything.
        result = checks.validate_name(villager)
        if result:
            return await ctx.send(result)
        villager_data = "{}, {}".format(villager, villager_link)

        request_id = utils.generate_id(data_dict)  # ctx.message.id
        name = ctx.message.author.name
        name += '#' + ctx.message.author.discriminator
        message = checks.precheck(name, villager)
        if message:
            em = utils.get_embed('red', message, title='Precheck Failed')
            return await ctx.channel.send(embed=em)

        tm = time.localtime(time.time())
        timestring = time.strftime(TIME_FORMAT, tm)
        # init data and data_dict
        # data might be redundant because I use data_dict mostly.
        data = ""
        data_dict = dict()
        data = u"Request_Id: **{}**\n".format(request_id)
        details = dict()
        data += u"Name: {}\n".format(name)
        details['name'] = name
        details['user_id'] = ctx.message.author.id
        data += 'Villager: {}\n'.format(villager_data)
        details['villager'] = villager_data
        data += u"CreatedTime: {}\n".format(timestring)
        details['created_time'] = timestring

        em = utils.get_embed('gray', 'Your Application Details:')
        await ctx.channel.send(embed=em)
        await ctx.channel.send(utils.printadict(details, hide_self=True))
        time.sleep(1)
        # default null for these two. Added after showing details to users,
        # so they won't know.
        details['last_modified'] = ''
        details['staff'] = ''
        # Flow control.
        tt_or_not = await ctx.send(
            f":information_source: Are you willing to do Time Travel in order to "
            f"make the process quicker?")
        tt_reaction = await flow.get_yes_no_reaction_confirm(tt_or_not, 200)
        if tt_reaction is None:
            return ctx.send(
                "Application cancelled. You may apply again at any time.")
        if not tt_reaction:
            details['can_time_travel'] = False
            # Only accept non-tter with an open plot in 72 hours to apply.
            within_72_hr = await ctx.send(
                f":question: Will you have an open plot with 72 hours? ")
            reaction = await flow.get_yes_no_reaction_confirm(
                within_72_hr, 200)
            if reaction is None:
                return ctx.send(
                    "Application cancelled. You may apply again when an open plot is ready."
                )
            if not reaction:
                rejected_text = (
                    "We’re sorry, your application cannot be accepted at this time.\n"
                    "Please apply again when you are within a 72 hour window "
                    "of an open plot.")
                em = utils.get_embed('red',
                                     rejected_text,
                                     title="Application Denied")
                return await ctx.channel.send(embed=em)
        else:
            details['can_time_travel'] = True

        # Available timeslot selection
        timeslot = await ctx.send(
            f":information_source: Which time slot is the best choice to contact you"
            " if we have to? \n"
            "NOTE: Please refer to https://www.thetimezoneconverter.com/ or https://time.is/UTC\n"
            " and select your most available timeslot in **UTC**.\n"
            ":sparkles: Slot 1: 00:00 - 03:59 UTC.\n:eight_spoked_asterisk: "
            "Slot 2: 04:00 - 07:59 UTC.\n"
            ":heart: Slot 3: 08:00 - 11:59 UTC.\n:rocket: Slot 4: 12:00 - 15:59 UTC.\n"
            ":crescent_moon: Slot 5: 16:00 - 19:59 UTC.\n:full_moon: Slot 6: "
            "20:00 - 23:59 UTC.\n")
        time.sleep(1)
        slot_reaction = await flow.get_timeslot_reaction_confirm(timeslot, 600)
        if slot_reaction is None:
            return ctx.send(
                "Application cancelled. You may apply again at any time.")
        if slot_reaction == 1:
            details['avail_time'] = '00:00-03:59 UTC'
        if slot_reaction == 2:
            details['avail_time'] = '04:00-07:59 UTC'
        if slot_reaction == 3:
            details['avail_time'] = '08:00-11:59 UTC'
        if slot_reaction == 4:
            details['avail_time'] = '12:00-15:59 UTC'
        if slot_reaction == 5:
            details['avail_time'] = '16:00-19:59 UTC'
        if slot_reaction == 6:
            details['avail_time'] = '20:00-23:59 UTC'

        # Final confirmation
        are_you_sure = await ctx.send(
            f":question: Please confirm YES/NO to create a new "
            f"application of finding **%s**." % villager)

        reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200)
        if reaction is None:
            return ctx.send(
                "Application cancelled. You may apply again at any time.")
        if not reaction:
            return await ctx.send("Aborted your application.")
        elif reaction:
            user_obj = self.bot.get_user(ctx.message.author.id)
            await ctx.send("This application has been logged for review.")
            await ctx.send(
                "%s Please take a note of your application ID:\n**%s**" %
                (user_obj.mention, request_id))
            time.sleep(1)
            # Add a default status.
            data += u"Status: {}".format(utils.Status.PENDING.name)
            details['status'] = utils.Status.PENDING.name

            # data_dict is keyed by request_id, and its value contains the rest details as a dictionary.
            data_dict[request_id] = details
            # Open request log file and append to the end.
            with open(RECORD_FILE, mode="a") as f:
                json.dump(data_dict, f, indent=None)
                f.write('\n')
            await sheet.update_data(data_dict)
            await self.send_logs_user('%s requested a dreamie (%s) at %s' %
                                      (name, villager.capitalize(), timestring)
                                      )
Esempio n. 8
0
    async def ready(self, ctx, req_id=None):
        '''Send a note to the staff team when you are ready to accept a new villager.'''
        # Check if the requester matches.
        data_dict = utils.open_requestlog()
        dreamie = None
        found = None
        found_data = dict()

        # Setup a Flow controller.
        flow = request.Flow(self.bot, ctx)
        # Since we only allow 1 application per user per time, do a quick search if
        # req_id = none and there is an open application of this user.
        if not req_id:
            req_id = self.auto_find(data_dict, ctx.message.author.name)
        for request_id, details in list(data_dict.items()):
            if str(request_id) == str(req_id):
                # user can only mark their own request.
                for k, v in list(details.items()):
                    if k == u'name' and ctx.message.author.name in v:
                        found = (
                            '%s has marked the application **%s** as ready to '
                            'accept the dreamie!' %
                            (ctx.message.author.name, req_id))
                        details['status'] = utils.Status.READY.name
                        dreamie = details['villager']
                        dreamie = dreamie.split(',')[0]
                        # mark a last_modified timestring
                        tm = time.localtime(time.time())
                        timestring = time.strftime(TIME_FORMAT, tm)
                        details['last_modified'] = timestring
                        found_data[request_id] = details
                        break

        if not found:
            em = utils.get_embed('red',
                                 'Cannot found your application %s.' % req_id)
            return await ctx.channel.send(embed=em)

        are_you_sure = await ctx.send(
            f":information_source: Please confirm YES/NO to indicate"
            f" that you have an open plot ready to receive your dreamie.\n"
            f"Application ID:**%s**" % req_id)
        reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200)

        if reaction is None:
            return
        if not reaction:
            em = utils.get_embed('red', 'Aborted.')
            return await ctx.channel.send(embed=em)
        elif reaction:
            color = utils.status_color(details)
            em = utils.get_embed(color, found)
            await ctx.channel.send(embed=em)
            utils.flush_requestlog(data_dict)
            user_obj = self.bot.get_user(found_data[req_id]['user_id'])
            await self.send_logs_user('%s is ready to accept a dreamie (%s).' %
                                      (found_data[req_id]['name'], dreamie))
            await sheet.update_data(found_data)
            staff_lst = found_data[req_id]['staff'].split('#')
            staff_id = discord.utils.get(self.bot.get_all_members(),
                                         name=staff_lst[0],
                                         discriminator=staff_lst[1]).id
            staff_obj = self.bot.get_user(staff_id)
            staff_dm = staff_obj.dm_channel or await staff_obj.create_dm()
            staff_msg = '%s: %s is ready to accept a dreamie (%s).' % (
                staff_obj.mention, user_obj.mention, dreamie)
            await staff_dm.send(staff_msg)
            """