Example #1
0
 async def reload_(self, ctx, *extensions):
     if "*" in extensions:
         title = "Reloading all extensions"
     elif len(extensions) > 1:
         title = "Reloading extensions"
     else:
         title = f"Reloading `{extensions[0]}`"
     embed = make_embed(color=colors.EMBED_INFO, title=title)
     m = await ctx.send(embed=embed)
     color = colors.EMBED_SUCCESS
     description = ""
     if "*" in extensions:
         extensions = get_extensions()
     for extension in extensions:
         try:
             self.bot.unload_extension("cogs." + extension)
         except commands.ExtensionNotLoaded:
             pass
         try:
             self.bot.load_extension("cogs." + extension)
             description += f"Successfully loaded `{extension}`.\n"
         except:
             color = colors.EMBED_ERROR
             description += f"Failed to load `{extension}`.\n"
             _, exc, _ = sys.exc_info()
             if not isinstance(exc, ImportError):
                 await report_error(ctx, exc, *extensions)
     description += "Done."
     await m.edit(embed=make_embed(color=color,
                                   title=title.replace("ing", "ed"),
                                   description=description))
Example #2
0
async def designate_channel(ctx,
                            channel_name,
                            current_channel,
                            *,
                            new_channel,
                            setter,
                            change_warning=''):
    if current_channel and new_channel.id == current_channel.id:
        await ctx.send(embed=make_embed(
            color=colors.EMBED_INFO,
            title=channel_name.capitalize(),
            description=
            f"{current_channel.mention} is already the {channel_name}."))
    else:
        if current_channel is None:
            description = f"Set {new_channel.mention} as the {channel_name}?"
        else:
            description = f"Change the {channel_name} from {current_channel.mention} to {new_channel.mention}? {change_warning}"
        m = await ctx.send(embed=make_embed(color=colors.EMBED_INFO,
                                            title=f"Set {channel_name}?",
                                            description=description))
        response = await react_yes_no(ctx, m)
        if response == 'y':
            setter(new_channel)
            description = f"The {channel_name} is now {new_channel.mention}."
        else:
            description = None
        title = f"{channel_name.capitalize()} change {YES_NO_HUMAN_RESULT[response]}"
        await m.edit(embed=make_embed(color=YES_NO_EMBED_COLORS[response],
                                      title=title,
                                      description=description))
Example #3
0
 async def add_currency(self, ctx, currency_name: str, color: discord.Color,
                        *aliases: str):
     """Create a new currency."""
     game = get_game(ctx)
     currency_name = currency_name.lower()
     aliases = list(map(str.lower, aliases))
     for s in [currency_name] + aliases:
         if game.get_currency(s):
             raise commands.UserInputError(
                 f"Currency name '{s}' is already used.")
     description = f"Color: {format_discord_color(color)}"
     description += "\nAliases: " + (", ".join(f"`{a}`" for a in aliases)
                                     or "(none)")
     m = await ctx.send(
         embed=make_embed(color=colors.EMBED_ASK,
                          title=f"Create currency '{currency_name}'?",
                          description=description))
     response = await react_yes_no(ctx, m)
     await m.edit(
         embed=make_embed(color=YES_NO_EMBED_COLORS[response],
                          title=f"Currency '{currency_name}' established"
                          if response else "Currency creation " +
                          YES_NO_HUMAN_RESULT[response],
                          description=description))
     if response != 'y':
         return
     game.add_currency(currency_name, color=color, aliases=aliases)
Example #4
0
 async def shutdown_(self, ctx, noconfirm=False):
     if noconfirm:
         result = "y"
     else:
         m = await ctx.send(embed=make_embed(
             color=colors.EMBED_ASK,
             title="Shutdown?",
             description=
             "This action may be difficult to undo without phsyical or remote access to the host machine. Are you sure?",
         ))
         result = await react_yes_no(ctx, m)
     await (ctx.send if noconfirm else m.edit)(embed=make_embed(
         color={
             "y": colors.EMBED_INFO if noconfirm else colors.EMBED_CONFIRM,
             "n": colors.EMBED_CANCEL,
             "t": colors.EMBED_TIMEOUT,
         }[result],
         title={
             "y": "Shutting down...",
             "n": "Shutdown cancelled.",
             "t": "Shutdown timed out.",
         }[result],
     ))
     if result is "y":
         l.info(
             f"Shutting down at the command of {ctx.message.author.display_name}..."
         )
         await self.bot.logout()
Example #5
0
    async def active_cutoff(self, ctx, new_cutoff: int = None):
        """Set or view the the active user cutoff time period.

        `new_cutoff` must be specified as an integer number of hours.
        """
        game = get_game(ctx)
        description = f"The current active user cutoff is **{format_hour_interval(game.active_cutoff)}**."
        if new_cutoff is None:
            await ctx.send(embed=make_embed(color=colors.EMBED_INFO,
                                            title="Active user cutoff time",
                                            description=description))
            return
        description += f" Change it to **{format_hour_interval(new_cutoff)}**?"
        m = await ctx.send(
            embed=make_embed(color=colors.EMBED_ASK,
                             title="Change active user cutoff time?",
                             description=description))
        response = await react_yes_no(ctx, m)
        if response == 'y':
            game.active_cutoff = new_cutoff
            game.save()
        await m.edit(embed=make_embed(
            color=YES_NO_EMBED_COLORS[response],
            title=
            f"Active user cutoff time change {YES_NO_HUMAN_RESULT[response]}"))
Example #6
0
    async def reload_(self, ctx, *extensions):
        if (utils.check_perms(ctx.author.id)):
            if "*" in extensions:
                title = "Reloading all extensions"
            elif len(extensions) > 1:
                title = "Reloading extensions"
            else:
                title = f"Reloading {extensions[0]}"

            embed = make_embed(author_url=[title, "", config.THUMBNAIL],
                               color=config.EMBED_INFO)  #, title=title
            m = await ctx.send(embed=embed)
            color = config.EMBED_SUCCESS
            fields = [[f"", '\u200b']]
            if "*" in extensions:
                extensions = list(self.bot.extensions.keys())
            for extension in extensions:
                self.bot.unload_extension(extension)
                try:
                    self.bot.load_extension(extension)
                    #fields.append([f"+ {extension}", '\u200b'])
                    fields[0][0] += f"+ {extension}\n"
                except:
                    color = config.EMBED_ERROR
                    #fields.append([f"- {extension}", '\u200b'])
                    fields[0][0] += f"- {extension}\n"
            #description += "Done."
            await m.edit(embed=make_embed(
                author_url=[title.replace("ing", "ed"), "", config.THUMBNAIL],
                fields=fields,
                color=color))  #title=title.replace("ing", "ed")
Example #7
0
    async def edit_channel(self, ctx, value: str):
        settings = {'yes': 1, 'no': 0}

        value_num = settings.get(value.lower())
        if value_num != None:
            db = sqltils.DbConn(db_file, ctx.guild.id, "setting")

            # if setting is already there old value needs to be deleted
            if len(db.search_table(value="edit_channel", column="setting")
                   ) == 1:  # there can only be one archive and log
                db.remove_line('"edit_channel"', column="setting")

            entry = ("edit_channel", "value_name", value_num,
                     time.strftime("%Y-%m-%d %H:%M:%S"), config.VERSION_SQL)
            db.write_server_table(entry)

            emby = utils.make_embed(
                color=discord.Color.green(),
                name="Success",
                value=f"Channel Creator can edit channel-name: {value}")
            await ctx.send(embed=emby)

        else:
            emby = utils.make_embed(
                color=discord.Color.orange(),
                name="Missing argument",
                value=f"Please enter `yes` or `no` as argument.")
            await ctx.send(embed=emby)
Example #8
0
async def undesignate_channel(ctx,
                              channel_name,
                              current_channel,
                              *,
                              deleter,
                              remove_warning=''):
    if current_channel is None:
        await ctx.send(embed=make_embed(
            color=colors.EMBED_INFO,
            title=channel_name.capitalize(),
            description=f"There already is no {channel_name}."))
    else:
        m = await ctx.send(embed=make_embed(
            color=colors.EMBED_ASK,
            title=f"Reset {channel_name}?",
            description=
            f"Are you sure you want to reset the {channel_name}? {remove_warning}"
        ))
        response = await react_yes_no(ctx, m)
        if response == 'y':
            deleter()
        await m.edit(embed=make_embed(
            color=YES_NO_EMBED_COLORS[response],
            title=
            f"{channel_name.capitalize()} reset {YES_NO_HUMAN_RESULT[response]}",
            description=f"There is now no {channel_name}" if response ==
            'y' else None))
Example #9
0
 async def remove_proposal(self, user, *proposal_nums, reason='', m=None):
     if m:
         human_proposals = f"{len(proposal_nums)} proposal{'s' * (len(proposal_nums) != 1)}"
         title = f"Removing {human_proposals}\N{HORIZONTAL ELLIPSIS}"
         await m.edit(embed=make_embed(
             color=colors.EMBED_INFO,
             title=title,
             description="Removing proposals\N{HORIZONTAL ELLIPSIS}"
         ))
     number_sequence = list(range(1, self.proposal_count + 1))
     for proposal_num in proposal_nums:
         proposal = self.get_proposal(proposal_num)
         del self.proposals[str(proposal_num)]
         number_sequence.remove(proposal_num)
         nomic.logging.add_to_proposal_log(self.guild,
             event_name='remove_proposal',
             user_id=user.id,
             proposal_number=proposal_num,
             reason=reason,
         )
         try:
             message = await self.proposal_channel.get_message(proposal.get('message'))
             await message.delete()
         except:
             pass
     self.proposal_count = len(number_sequence)
     if number_sequence:
         if m:
             await m.edit(embed=make_embed(
                 color=colors.EMBED_INFO,
                 title=title,
                 description="Renumbering remaining proposals\N{HORIZONTAL ELLIPSIS}"
             ))
         moved_proposals = []
         for i in range(len(number_sequence)):
             old_num = str(number_sequence[i])
             new_num = str(i + 1)
             if old_num != new_num:
                 self.proposals[new_num] = self.proposals[old_num]
                 del self.proposals[old_num]
                 self.proposals[new_num]['n'] = new_num
                 moved_proposals.append(new_num)
                 nomic.logging.add_to_proposal_log(self.guild,
                     event_name='renumber',
                     user_id=user.id,
                     proposal_number=old_num,
                     new_number=new_num,
                 )
         self.save()
         await self.refresh_proposal(*moved_proposals)
     else:
         self.save()
     if m:
         await m.edit(embed=make_embed(
             color=colors.EMBED_SUCCESS,
             title=f"Removed {human_proposals}"
         ))
Example #10
0
    async def channel_from_input(
            ctx, channel_type: str,
            channel_id: str) -> Union[Tuple[str, str], Tuple[None, None]]:
        """
        Get the channel for a given channel id, send error message if no channel was found\n
        - checks if channel exists\n
        - checks if type matches the given setting\n
        
        :param ctx: discord.Context to send possible help message and to extract guild id
        :param channel_type: channel type searched, like log_channel. Matched with names from settings dict
        :param channel_id: channel id that was given

        :returns: (channel id as string, best way to mention / name channel) if found, else (None, None)
        """
        set_channel = await Settings.validate_channel(ctx, channel_id)

        if set_channel is None:
            return None, None

        # check if channel type and wanted setting match
        if type(set_channel
                ) == discord.TextChannel and channel_type == "log_channel":
            return str(set_channel.id), set_channel.mention

        elif type(
                set_channel
        ) == discord.CategoryChannel and channel_type == "archive_category":
            return str(set_channel.id), set_channel.name

        elif type(set_channel) == discord.VoiceChannel and channel_type in [
                'public_channel', 'private_channel', 'static_channel'
        ]:

            # check if max for tracked channels is reached
            if not settings_db.is_track_limit_reached(ctx.guild.id,
                                                      channel_type):
                return str(set_channel.id), set_channel.name

            await ctx.send(embed=utils.make_embed(
                color=utils.orange,
                name="Too many entries",
                value=
                f"Hey, you can't make me watch more than {CHANNEL_TRACK_LIMIT} channels for this setting\n"
                f"If you wanna change the channels I watch use `{PREFIX}ds [channel-id]` "
                f"to remove a channel from your settings"))
            return None, None

        else:
            # gained channel and required type didn't match
            await ctx.send(embed=utils.make_embed(
                name='Not a voice channel',
                value=
                f"The channel {set_channel.name} is no {channel_type.replace('_', ' ')}, "
                f"please enter a valid channel-id",
                color=utils.yellow))

        return None, None
Example #11
0
    async def delete_settings(self, ctx: commands.Context, value: str):
        """
        remove tracked channel from database

        :param ctx: command context
        :param value: id of the channel to be deleted
        """
        if not value:
            emby = utils.make_embed(
                color=utils.orange,
                name="No input",
                value=f"This function requires exactly one input:\n"
                "`channel-id` please give a valid channel ID as argument to remove that channel from"
                "the list of watched channels.\n"
                f"You can get a list of all watched channels with `{PREFIX}gs`"
            )

            await ctx.send(embed=emby)
            return

        # get channel setting or setting string
        setting_setting = settings.get(value, None)  # name of setting
        value_setting = utils.extract_id_from_message(
            value)  # id / value of setting

        if not (setting_setting or value_setting):
            emby = utils.make_embed(
                color=utils.orange,
                name="No valid setting",
                value="It seems like you didn't give me a valid channel ID or "
                "setting name to work with")
            await ctx.send(embed=emby)
            return

        # all checks passed - removing that entry
        if setting_setting:
            settings_db.del_setting_by_setting(ctx.guild.id, setting_setting)

        elif value_setting:
            # We don't know if the setting we aim for is located in channels-db (like static channel)
            # or in settings db like everything else, but that's okay, we just delete the setting in bot DBs
            channels_db.del_channel(
                value_setting)  # here if it's a static channel
            settings_db.del_setting_by_value(
                ctx.guild.id,
                str(value_setting))  # here if it's something else
            # TODO: If a static channel is in use when deleted from db the text-channel will stay, how to fix this?

        # channel only applied to setting by value
        channel = ctx.guild.get_channel(value_setting)
        await ctx.send(embed=utils.make_embed(
            color=utils.green,
            name="Deleted",
            value=f"Removed "
            f"`{channel.name if channel else setting_setting}` from settings"))
Example #12
0
    async def set_archive(self, ctx, setting: str, value: str):
        # possible settings switch -returns same value but nothing if key isn't valid
        settings = {
            "archive": utils.get_chan(ctx.guild, value),
            "log": utils.get_chan(ctx.guild, value)
        }
        # trying to get a corresponding channel / id
        value = settings.get(setting)
        # if value is "None" this means that there is no such setting or no such value for it
        # checking if keyword matches the entered channel type
        # -> ensures that the process of getting a correct setting has worked

        # set channels
        if value is not None and value.type == discord.ChannelType.text and setting == "log" \
                or value.type == discord.ChannelType.category and setting == "archive":

            # connecting to db - creating a new one if there is none yet
            db = sqltils.DbConn(db_file, ctx.guild.id, "setting")

            # Settings won't be stored if max watched channels are reached
            # -> searching for amount of matching entries
            if len(db.search_table(value=setting, column="setting")
                   ) >= 1:  # there can only be one archive and log

                text = f"Hey, you can only have one archive and log at once\n \
                        If you wanna change those settings use `{config.PREFIX}ds [channel-id]` to remove a channel from your settings"

                emby = utils.make_embed(color=discord.Color.orange(),
                                        name="Too many entries",
                                        value=text)
                await ctx.send(embed=emby)

            # writing entry to db - the way things should go
            else:
                entry = (setting, "value_name", value.id,
                         time.strftime("%Y-%m-%d %H:%M:%S"),
                         config.VERSION_SQL)
                db.write_server_table(entry)

                emby = utils.make_embed(color=discord.Color.green(),
                                        name="Success",
                                        value="Setting saved")
                await ctx.send(embed=emby)

        # when false inputs were given
        else:
            value = ("Please ensure that you've entered a valid setting \
                    and channel-id or role-id for that setting.")
            emby = utils.make_embed(color=discord.Color.orange(),
                                    name="Can't get setting",
                                    value=value)
            await ctx.send(embed=emby)
    async def break_out_rooms(self, ctx: discord.ext.commands.Context, *split: str):

        # check if invoker is in a channel
        if not ctx.author.voice:
            await hp.send_embed(ctx, embed=utils.make_embed("You're not in a VoiceChannel", discord.Color.orange(),
                                                            value="Please enter a Voice Channel and try again"))
            return

        # ensuring members var is given and is int
        try:
            # check can fail when typecast fails or number too small
            if int(split[0]) > 0:
                split = int(split[0])  # saving integer in variable

            # number too small
            else:
                await hp.send_embed(ctx, embed=utils.make_embed("Number must be greater than 0", discord.Color.orange(),
                                                                value=f"Try again :wink:\nExample: `{config.PREFIX}opro 4`"))
                return

        # type conversion failed
        except (IndexError, ValueError):
            await hp.send_embed(ctx, embed=utils.make_embed("Wrong argument", discord.Color.orange(),
                                                            value=f"Please enter the amount of members per channel\n"
                                                                  f"Example: `{config.PREFIX}opro 4`"))
            return

        # channel invoker is based in
        base_vc: discord.VoiceChannel = ctx.author.voice.channel

        # making a copy of members in channel - used to move members
        members: List[discord.Member] = base_vc.members.copy()
        members.remove(ctx.author)  # invoker should not be moved to break-out-room
        random.shuffle(members)  # shuffling list

        overwrites = base_vc.category.overwrites  # settings for new channels
        mv_channel = None  # temp var for holding current created channel
        for i in range(len(members)):
            """
            Iterating trough members of VC
            Creating new channel when last one filled
            Moving members
            """
            if i % split == 0:
                mv_channel, _ = await make_channel(ctx.author.voice, members[i], overwrites,
                                                   vc_name=f"Breakout Room {i // split + 1}",
                                                   tc_name=f"Breakout Room {i // split + 1}",
                                                   channel_type="brout")
            if members[i].voice is None:
                continue
            await members[i].move_to(mv_channel, reason="Moved to breakout room")
Example #14
0
 async def _submit_proposal(self, ctx, content):
     game = get_game(ctx)
     m = await ctx.send(embed=make_embed(color=colors.EMBED_ASK,
                                         title="Submit new proposal?",
                                         description=content))
     response = await react_yes_no(ctx, m)
     if ctx.channel.id == game.proposal_channel.id:
         await m.delete()
     else:
         await m.edit(embed=make_embed(
             color=YES_NO_EMBED_COLORS[response],
             title=f"Proposal submission {YES_NO_HUMAN_RESULT[response]}"))
     if response != 'y':
         return
     await game.submit_proposal(ctx, content.strip())
Example #15
0
    async def create(self, ctx, name, *, times=""):
        """Create an event.
        If no times are given, the event will only be able to be triggered manually.
        Otherwise, you can schedule triggers, like `3 hours later` or `12:30PM`, seperated by commas.
        If you have a time added with the `time` command, your timezone will be assumed. Otherwise, UTC will be used unless you specify a timezone like `at 12:30PM EST`.
        Example usage: `event create game in two minutes, 6PM`
        """
        if name.lower() in event_config:
            await show_error(ctx, "That event already exists.")

        event = Event(name, [], [], ctx.author.id, [])
        await self.parse_times(ctx, event, times)

        event_config[name.lower()] = event
        saving = {}
        for event in event_config:
            saving[event] = list(event_config[event])
        save_json(paths.EVENT_SAVES, saving)

        await ctx.send(
            embed=make_embed(
                title="Added event",
                description="Your event was created successfully.",
                color=colors.EMBED_SUCCESS,
            )
        )
Example #16
0
 async def update(self, ctx):
     """Runs `git pull` to update the bot."""
     subproc = await asyncio.create_subprocess_exec('git', 'pull', stdout=PIPE)
     embed = make_embed(
         color=colors.EMBED_INFO,
         title="Running `git pull`"
     )
     m = await ctx.send(embed=embed)
     returncode = await subproc.wait()
     embed.color = colors.EMBED_ERROR if returncode else colors.EMBED_SUCCESS
     stdout, stderr = await subproc.communicate()
     fields = []
     if stdout:
         embed.add_field(
             name="Stdout",
             value=f"```\n{stdout.decode('utf-8')}\n```",
             inline=False
         )
     if stderr:
         embed.add_field(
             name="Stderr",
             value=f"```\n{stderr.decode('utf-8')}\n```",
             inline=False
         )
     if not (stdout or stderr):
         embed.description = "`git pull` completed."
     await m.edit(embed=embed)
     await self.reload_(ctx, '*')
Example #17
0
    async def get_settings(self, ctx):
        """
		prints set channels
		"""
        db = sqltils.DbConn(db_file, ctx.guild.id, "setting")
        results = db.read_server_table()  #gets a list ob entry objects

        pub = "__Public Channels:__\n"
        priv = "__Private Channels:___\n"
        log = "__Log Channel__\n"
        archive = "__Archive Category__\n"
        for i in range(len(results)):  #building strings
            if results[i].setting == "pub-channel":
                pub += f"`{ctx.guild.get_channel(results[i].value_id)}` with ID `{results[i].value_id}`\n"

            elif results[i].setting == "priv-channel":
                priv += f"`{ctx.guild.get_channel(results[i].value_id)}` with ID `{results[i].value_id}`\n"

            elif results[i].setting == "log":
                log += f"`{ctx.guild.get_channel(results[i].value_id)}` with ID `{results[i].value_id}`\n"

            elif results[i].setting == "archive":
                archive += f"`{ctx.guild.get_channel(results[i].value_id)}` with ID `{results[i].value_id}`\n"

        emby = utils.make_embed(color=discord.Color.green(),
                                name="Server Settings",
                                value=f"‌\n{pub}\n {priv}\n{archive}\n{log}")
        await ctx.send(embed=emby)
Example #18
0
async def on_error(function, *args, **kwargs):
    """
    Overwriting error handler from discord.py
    """
    # exception type
    exception = sys.exc_info()[1]
    # traceback text
    tb_text = f'Error in: {function}\n{exception}\nTraceback (most recent call last):\n' \
              + "".join(traceback.format_tb(sys.exc_info()[2])) + f"{exception}"

    print("----------\n")
    print(tb_text)
    logging.error(tb_text)

    # sending message to member when channel creation process fails
    if function == "on_voice_state_update" and isinstance(
            exception, discord.errors.Forbidden):
        member = args[0]  # member is first arg that is passed in
        # check if it's the error we expect
        if tb_text.find("create_voice_channel") != -1:
            await member.send(embed=utils.make_embed(
                name=f"Something's wrong with my permissions",
                value="I can't prepare (create & edit) a channel for you "
                "or I can't move you.\n"
                "Please check whether a channel was created and inform the server team "
                "about that problem.\n I'm sorry! :confused:",
                color=discord.Color.red()))
Example #19
0
 async def do_it(include_url):
     description = '\n'.join(
         map(lambda m: self.get_proposal_message(ctx, m, include_url),
             proposal_nums))
     await ctx.send(embed=make_embed(color=colors.EMBED_INFO,
                                     title="Proposal information",
                                     description=description))
Example #20
0
 async def list(self, ctx, event: Event):
     await ctx.send(embed=make_embed(
         title="Managers",
         description="\n".join(
             [self.bot.get_user(x).mention for x in event.managers]),
         color=colors.EMBED_SUCCESS,
     ))
Example #21
0
 async def about(self, ctx):
     await ctx.send(embed=make_embed(
         title=f"About {info.NAME}",
         description=info.ABOUT_TEXT,
         fields=[("Author", f"[{info.AUTHOR}]({info.AUTHOR_LINK})",
                  True), ("GitHub Repository", info.GITHUB_LINK, True)],
         footer_text=f"{info.NAME} v{info.VERSION}"))
Example #22
0
    async def validate_toggle(
            ctx: commands.Context,
            decision: str) -> Union[Tuple[str, str], Tuple[None, None]]:
        """
        Check if value matches yes_or_no toggle dict\n
        Send error if mapping doesn't work


        :param ctx: context of the command, used to send a possible message
        :param decision: 'boolean' input of the user to map to True or False

        :returns: ('1' or '0', descriptive string if user can or can't edit) if its valid, else (None, None)
        """
        yes_or_no = yes_no_dict.get(decision, None)
        if yes_or_no is not None:
            return str(
                yes_or_no
            ), "creator can edit" if yes_or_no else " creator can _not_ edit"

        await ctx.send(embed=utils.make_embed(
            name="Can't extract your decision",
            value="You needed to either enter `yes` or `no` as valid state.\n"
            "I can' figure out whether you want to allow or disable "
            "that the channel creator can edit the created channel.\n"
            "Use `yes` to allow it or `no` to prohibit.",
            color=utils.yellow,
            footer=
            "It's only recommend to enable that feature if you trust your members "
            "and / or have an active moderation team!"))

        return None, None
Example #23
0
    async def refresh_proposal(self, ctx, *proposal_nums: int):
        """Refresh one or more proposal messages.

        This is mostly useful for fixing minor glitches, or if voting rules have
        changed.
        """
        if not proposal_nums:
            await invoke_command_help(ctx)
            return
        game = get_game(ctx)
        proposal_nums = dedupe(proposal_nums)
        succeeded, failed = await game.refresh_proposal(*proposal_nums)
        description = ''
        if succeeded:
            if len(succeeded) == 1:
                description += f"Proposal {succeeded[0]} succeessfully refreshed.\n"
            else:
                description += f"{len(succeeded)}/{len(proposal_nums)} proposal messages succeessfully refreshed.\n"
        if failed:
            description += f"Proposal{'' if len(failed) == 1 else 's'} {human_list(map(str, failed))} could not be refreshed.\n"
        m = await ctx.send(embed=make_embed(
            color=colors.EMBED_ERROR if failed else colors.EMBED_SUCCESS,
            title="Refreshed proposal messages",
            description=description))
        await game.wait_delete_if_illegal(ctx.message, m)
Example #24
0
    async def restart_bot(self, ctx):
        if (utils.check_perms(ctx.author.id)):
            m = await ctx.send(
                embed=make_embed(title="Restarting...", color=0xff00ff))

            msg_id = m.id
            msg_channel_id = m.channel.id
            msg_guild_id = m.guild.id
            print(m)
            print(m.id)
            print(m.channel.id)
            print(m.guild.id)
            #print(await self.bot.get_guild(msg_guild_id).get_channel(msg_channel_id).fetch_message(msg_id).edit("this"))
            #		channel = self.bot.get_guild(msg_guild_id).get_channel(msg_channel_id)
            #channel = guild.get_channel(msg_channel_id)
            #		msg = await channel.fetch_message(msg_id)
            #		await msg.edit(embed=make_embed(title="Restarted.", color=0xff00ff))
            with open('restart.dat', 'w+') as f:
                f.write(f"True\n{m.guild.id}\n{m.channel.id}\n{m.id}")
                #f.write('\n')
                #f.write(str(m))
                #pickle.dump(m, f, -1)
            #await ctx.send("Hi!")
            await self.bot.logout()
            await self.bot.close()
Example #25
0
    async def prefix_validation(
            ctx: commands.Context,
            new_prefix: str) -> Union[Tuple[str, str], Tuple[None, None]]:
        """
        Validate that a prefix fit the set criteria, send error message if it does not match\n
        Criteria:\n
        - shorter or equal to env variable MAX_PREFIX_LENGTH\n
        - ends on a non-word character like '!'
        
        :param ctx: context of the command, used to send a possible message
        :param new_prefix: string to validate
        
        :returns: (prefix, prefix) if its valid, else (None, None)
        """
        example_prefix = f"A valid prefix would be `{'f' * (MAX_PREFIX_LENGTH - 1)}!` or just `?`"

        # validate length and scheme
        # example: r"^\w{0,3}\W$" (the upper limit can be changed dynamically)
        pattern = re.compile(r"^\w{0," + str(MAX_PREFIX_LENGTH - 1) + r"}\W$")
        if re.search(pattern, new_prefix) is not None:
            return new_prefix, new_prefix  # prefix shall be entered to db and be sent in message

        await ctx.send(embed=utils.make_embed(
            name="Prefix should be short and easy to remember",
            value=
            f"The length limit for this bot is {MAX_PREFIX_LENGTH - 1} letters or digits, "
            f"followed by one 'non-word' character like !, ?, ~\n"
            f"{example_prefix}",
            color=utils.yellow))
        return None, None
Example #26
0
 async def list_active_users(self, ctx, *users: discord.Member):
     """List only users that are active (or those specified)."""
     game = get_game(ctx)
     description = ''
     users = list(users)
     if not users:
         for user_id in game.player_last_seen:
             try:
                 user = ctx.guild.get_member(int(user_id))
                 if self.is_active(ctx, user):
                     users.append(user)
             except:
                 pass
     users = sorted(
         sorted(users, key=member_sort_key(ctx)),
         key=lambda member: self.last_seen_diff(ctx, member) or 1e9)
     for user in users:
         last_seen = self.last_seen_diff(ctx, user)
         if last_seen is None:
             last_seen_text = "never"
         elif last_seen < 2:
             last_seen_text = "very recently"
         else:
             last_seen_text = f"about {format_hour_interval(self.last_seen_diff(ctx, user))} ago"
         description += f"{user.mention} was last seen **{last_seen_text}**"
         if self.is_active(ctx, user):
             description += " _(active)_"
         else:
             description += " _(inactive)_"
         description += "\n"
     await ctx.send(embed=make_embed(color=colors.EMBED_INFO,
                                     title=f"Active users ({len(users)})",
                                     description=description))
Example #27
0
 async def submit_proposal(self, ctx, content):
     self.proposal_count += 1
     m = await self.proposal_channel.send(embed=make_embed(
         color=colors.EMBED_INFO,
         title=f"Preparing proposal #{self.proposal_count}\N{HORIZONTAL ELLIPSIS}"
     ))
     timestamp = datetime.utcnow()
     mutset(self.guild_data, ['proposals', str(self.proposal_count)], {
         'n': self.proposal_count,
         'author': ctx.author.id,
         'content': content,
         'message': m.id,
         # 'status' can be 'voting', 'passed', or 'failed'
         'status': 'voting',
         'votes': {
             'for': {},
             'against': {},
             'abstain': {},
         },
         'timestamp': timestamp.timestamp(),
     })
     self.save()
     nomic.logging.add_to_proposal_log(self.guild,
         timestamp=timestamp,
         event_name='submit',
         user_id=ctx.author.id,
         proposal_number=self.proposal_count
     )
     await self.refresh_proposal(self.proposal_count)
Example #28
0
 async def transact(self, transaction, reason=''):
     amount        = transaction['amount']
     currency_name = transaction['currency_name']
     user_id       = transaction['user_id']
     user_agent_id = transaction['user_agent_id']
     timestamp     = datetime.utcnow()
     currency = self.get_currency(currency_name)
     user_agent = self.guild.get_member(user_agent_id)
     mutget(currency, ['players', str(user_id)], 0)
     currency['players'][str(user_id)] += amount
     m = await self.transaction_channel.send(embed=make_embed(
         color=int(currency.get('color')[1:], 16) or colors.EMBED_INFO,
         description=self.format_transaction(transaction, include_total=True),
         footer_text=f"Authorized at {timestamp.strftime(TIME_FORMAT)} by {user_agent.name}#{user_agent.discriminator}"
     ))
     self.transaction_messages.append(m.id)
     self.save()
     nomic.logging.add_to_transaction_log(self.guild,
         timestamp=timestamp,
         currency=currency_name,
         agent_id=user_agent_id,
         recipient_id=user_id,
         amt=amount,
         reason=reason,
     )
Example #29
0
 async def edit(self, ctx, id: int, *, new_blurb):
     try:
         entry = self.hub_entries[str(id)]
     except KeyError:
         return await show_error(ctx, "That ID isn't a hub entry.")
     await self.bot.http.edit_message(channels.HUB_CHANNEL,
                                      id,
                                      embed=make_embed(
                                          title=entry["name"],
                                          url=entry["url"],
                                          description=new_blurb).to_dict())
     entry["blurb"] = new_blurb
     await ctx.send(embed=make_embed(title="Success",
                                     description="Edited hub entry.",
                                     color=colors.EMBED_SUCCESS))
     self.save()
Example #30
0
    async def quote(self, ctx, message_id: int = None):
        """Quote a previous message."""
        if not message_id:
            quote_message = await ctx.send(embed=make_embed(
                title="No message",
                description=f"React to a message with {emoji.QUOTE}.",
            ))

            try:
                payload = await self.bot.wait_for(
                    "raw_reaction_add",
                    check=lambda m: m.guild_id == ctx.guild.id and m.emoji ==
                    emoji.QUOTE,
                    timeout=60,
                )
            except asyncio.TimeoutError:
                await quote_message.edit(embed=make_embed(
                    title="No message", description=f"No reaction given."))
                return

            channel = ctx.guild.get_channel(payload.channel_id)
            message = await channel.fetch_message(payload.message_id)
        else:
            message = await get_message_guild(ctx.guild, message_id,
                                              ctx.channel)
            if not message:
                await ctx.send(embed=make_embed(
                    title="No message", description="Bad message ID given."))
            quote_message = ctx.channel
        embed = make_embed(
            description=message.content,
            timestamp=message.edited_at or message.created_at,
            footer_text="#" + message.channel.name,
        )
        embed.set_author(name=message.author.name,
                         icon_url=message.author.avatar_url)
        if message.attachments:
            filename = message.attachments[0].filename
            if (filename.endswith(".png") or filename.endswith(".jpg")
                    or filename.endswith(".jpeg")):
                embed.set_image(url=message.attachments[0].url)

        if hasattr(quote_message, "send"):
            await quote_message.send(embed=embed)
        else:
            await quote_message.edit(embed=embed)