Exemplo n.º 1
0
    async def takedown(self, context, student_id: int, *post):
        post = ' '.join(post)
        if not post:
            await context.send(
                'You must supply the user to stand down and the post you are standing them down from, '
                f'usage: `{helpers.PREFIX}takedown <STUDENT NUMBER> <POST>`')
            return
        matching_posts = helpers.match_post(post)
        if not matching_posts:
            await context.send(
                'Looks like that post isn\'t available for this election, '
                f'use `{helpers.PREFIX}posts` to see the posts up for election`'
            )
            return
        post = matching_posts[0]

        if student_id not in helpers.standing[post]:
            await context.send(
                'Looks like this user isn\'t standing for this post')
            return

        helpers.email_secretary(str(helpers.standing[post][student_id][0]),
                                post,
                                stood_down=True)
        del helpers.standing[post][student_id]

        helpers.save_standing()

        helpers.log(
            f'{student_id} has been stood down from standing for {post}')
        await context.send(
            f'{student_id} has been stood down from running for {post}')
Exemplo n.º 2
0
    async def resetname(self, context, student_id: int):
        if student_id not in helpers.preferred_names:
            await context.send(
                'The supplied student ID has not updated their name')
            return

        async with helpers.current_live_post_lock.reader_lock:
            if helpers.current_live_post:
                await context.send(
                    'I\'m afraid you can\'t reset a name whilst a vote is ongoing, '
                    f'please wait until the vote has finished, or end it early using `{helpers.PREFIX}end`'
                )
                return

            del helpers.preferred_names[student_id]

            union_name = helpers.get_members()[student_id]

            for post in helpers.standing:
                if student_id in helpers.standing[post]:
                    helpers.standing[post][student_id] = (
                        Candidate(union_name),
                        helpers.standing[post][student_id][1],
                        context.author.id)
        helpers.save_names()
        helpers.save_standing()

        helpers.log(f'The name used for {student_id} has been reset')
        await context.send(f'The name used for {student_id} has been reset')
Exemplo n.º 3
0
    async def standdown(self, context, *post):
        post = ' '.join(post)
        if not post:
            await context.send(
                f'Must supply the post you are standing down from, usage: `{helpers.PREFIX}standdown <POST>`'
            )
            return
        matching_posts = helpers.match_post(post)
        if not matching_posts:
            await context.send(
                'Looks like that post isn\'t available for this election, '
                f'use `{helpers.PREFIX}posts` to see the posts up for election`'
            )
            return
        post = matching_posts[0]

        author = context.author.id

        if helpers.registered_members[author] not in helpers.standing[post]:
            await context.send('Looks like you weren\'t standing for this post'
                               )
            return

        helpers.email_secretary(str(
            helpers.standing[post][helpers.registered_members[author]][0]),
                                post,
                                stood_down=True)
        del helpers.standing[post][helpers.registered_members[author]]

        helpers.save_standing()

        helpers.log(
            f'{helpers.registered_members[author]} has stood down from standing for {post}'
        )
        await context.send(f'You have stood down from running for {post}')
Exemplo n.º 4
0
    async def rename(self, context, old_post, new_post):
        matching_posts = helpers.match_post(old_post)
        if not matching_posts:
            await context.send(f'{old_post} doesn\'t exist')
            return

        helpers.standing[new_post] = helpers.standing.pop(matching_posts[0])

        helpers.save_standing()

        helpers.log(
            f'The post of {matching_posts[0]} has been renamed to {new_post}')
        await context.send(
            f'The post of {matching_posts[0]} has been renamed to {new_post}')
Exemplo n.º 5
0
    async def setup(self, context, *post):
        post = ' '.join(post)
        matching_posts = helpers.match_post(post)
        if matching_posts:
            await context.send(f'{post} already exists')
            return

        helpers.standing[post] = {
            0: (Candidate('RON (Re-Open Nominations)'), '*****@*****.**', 42)
        }

        helpers.save_standing()

        helpers.log(f'The post of {post} has been created')
        await context.send(f'The post of {post} has been created')
Exemplo n.º 6
0
    async def begin(self, context, *post):
        post = ' '.join(post)
        if not post:
            await context.send(
                'Must supply the post/referendum title you are starting the vote for, usage:'
                f'`{helpers.PREFIX}begin <POST/TITLE>`')
            return
        matching_posts = helpers.match_post(post)
        type = 'POST'
        if not matching_posts:
            matching_posts = helpers.match_referendum(post)
            type = 'REFERENDUM'
            if not matching_posts:
                await context.send(
                    'Looks like that post/referendum isn\'t available for this election, '
                    f'use `{helpers.PREFIX}posts` to see the posts up for election or '
                    f'or use `{helpers.PREFIX}referenda` to see the referenda that will be voted upon'
                )
                return

        async with helpers.current_live_post_lock.writer_lock:
            if helpers.current_live_post:
                await context.send(
                    'You can\'t start a new vote until the last one has finished'
                )
                return
            post = matching_posts[0]

            helpers.current_live_post = (type, post)
        helpers.log(f'Voting has now begun for: {post}')

        if type == 'POST':
            await self.distribute_all_post_ballots(post)

            await context.send(
                f'Voting has now begun for: {post}\n'
                'All registered voters will have just received a message from me. '
                'Please vote by reacting to the candidates listed in your DMs where '
                ':one: is your top candidate, :two: is your second top candidate, etc. '
                'You do not need to put a ranking in for every candidate')
        else:
            await self.distribute_all_referenda_ballots(post)

            await context.send(
                f'Voting has now begun for: {post}\n'
                'All registered voters will have just received a message from me. Please vote by '
                'reacting :ballot_box_with_check: to either the \'For\' or \'Against\' message '
                'in your DMs')
Exemplo n.º 7
0
    async def referendum(self, context, title, *description):
        description = ' '.join(description)
        if description.startswith('\''):
            description = description.strip('\'')

        matching_referenda = helpers.match_referendum(title)
        if matching_referenda:
            await context.send(f'{title} already exists')
            return

        helpers.referenda[title] = description

        helpers.save_referenda()

        helpers.log(f'The referendum for \"{title}\" has been created')
        await context.send(f'The referendum for \"{title}\" has been created')
Exemplo n.º 8
0
    async def changename(self, context, *name):

        name = ' '.join(name)
        if not name:
            await context.send(
                f'Must supply the name you are wanting to change to, usage: `{helpers.PREFIX}changename <NAME>`'
            )
            return
        if name.startswith('\''):
            name = name.strip('\'')

        author = context.author.id
        if author not in helpers.registered_members:
            await context.send(
                'It looks like you\'re not registered yet, you must first register using '
                f'`{helpers.PREFIX}register <STUDENT NUMBER>` before you can update your name'
            )
            return

        async with helpers.current_live_post_lock.reader_lock:
            if helpers.current_live_post:
                await context.send(
                    'I\'m afraid you can\'t change your name whilst a vote is ongoing, '
                    'please wait until the vote has finished')
                return

            author_id = helpers.registered_members[author]
            helpers.preferred_names[author_id] = name

            for post in helpers.standing:
                if author_id in helpers.standing[post]:
                    helpers.standing[post][author_id] = (
                        Candidate(name), helpers.standing[post][author_id][1],
                        author)
        helpers.save_names()
        helpers.save_standing()

        await context.send(f'The bot now recognises your name to be {name}')
        helpers.log(
            f'{context.author.name}({author_id}) has changed their name to {name}'
        )
Exemplo n.º 9
0
    async def end(self, context):
        voting_channel = await self.bot.fetch_channel(helpers.VOTING_CHANNEL_ID
                                                      )
        committee_channel = await self.bot.fetch_channel(
            helpers.COMMITTEE_CHANNEL_ID)

        last_live_post = helpers.current_live_post
        async with helpers.current_live_post_lock.writer_lock:
            helpers.current_live_post = None
        helpers.voting_messages.clear()
        async with helpers.voted_lock:
            helpers.voted.clear()

        await voting_channel.send(
            f'Voting has now ended for: {last_live_post[1]}')

        async with helpers.votes_lock.writer_lock:
            if last_live_post[0] == 'POST':
                results = pyrankvote.instant_runoff_voting([
                    i for i, _, _ in helpers.standing[
                        last_live_post[1]].values()
                ], helpers.votes)
            else:
                results = pyrankvote.instant_runoff_voting(
                    helpers.referendum_options, helpers.votes)

            helpers.votes.clear()

        # Announce the scores and the winner to the committee
        winner = results.get_winners()[0]

        helpers.log(f'Result: {results}')
        helpers.log(f'Winner: {winner}')

        if last_live_post[0] == 'POST':
            await committee_channel.send(
                'The votes were tallied as follows:\n'
                f'```{results}```\n'
                f'The winning candidate for the post of {last_live_post[1]} is: {winner}'
            )
        else:
            await committee_channel.send(
                'The votes were tallied as follows:\n'
                f'```{results}```\n'
                f'The result for the referendum on {last_live_post[1]} is: {winner}'
            )

        helpers.log(f'Voting has now ended for: {last_live_post[1]}')
        for voter in helpers.registered_members:
            user = await self.bot.fetch_user(voter)
            await user.send(f'Voting has now ended for: {last_live_post[1]}')
Exemplo n.º 10
0
    async def register(self, context, student_number: int):

        author = context.author.id
        members = helpers.get_members()

        output_str = 'Error'
        if student_number in members:
            if author in helpers.registered_members:
                output_str = f'Looks like your Discord username is already registered to {helpers.registered_members[author]}'
            elif student_number in helpers.registered_members.values():
                output_str = (
                    'Looks like your student ID is already registered to someone else, '
                    'please contact a committee member')
                other_user_id = [
                    key for key, value in helpers.registered_members.items()
                    if value == student_number
                ][0]
                other_user = await self.bot.fetch_user(other_user_id).name
                helpers.log(
                    f'{context.author} tried to register student ID {student_number}, '
                    f'but it\'s already registered to {other_user}')
            else:
                helpers.registered_members[author] = student_number
                output_str = (
                    f'Thank you {members[helpers.registered_members[author]]}, you are now registered. '
                    'If you\'d like to change the name used by the bot, use '
                    f'`{helpers.PREFIX}changename <NAME>`\n\n{helpers.RULES_STRING}'
                )
                helpers.log(
                    f'{helpers.registered_members[author]} is now registered ({len(helpers.registered_members)} total)'
                )
        else:
            output_str = f'Looks like you\'re not a member yet, please become a member here: {helpers.JOIN_LINK}'
            helpers.log(
                f'{context.author.name} has failed to register because they are not a member'
            )

        helpers.save_voters()
        await context.send(output_str)
Exemplo n.º 11
0
async def on_command_error(context, error):
    if isinstance(error, commands.errors.CommandNotFound):
        helpers.log(error)
        await context.channel.send(
            f'I couldn\'t find that command, please use {PREFIX}help for a list of commands.'
        )
Exemplo n.º 12
0
    async def submit(self, context, code):
        # Only work for users who got sent messages
        author = context.author.id
        if author not in helpers.voting_messages:
            return

        if code.upper() != helpers.VOTING_CODE:
            await context.send(
                'The code you have supplied is incorrect, '
                'you must use the one given out in the election call, your vote was not cast'
            )
            return

        valid = await self.validate(context)
        if not valid:
            await context.send(
                'Your vote was not cast, please correct your ballot and resubmit'
            )
            return

        async with helpers.voted_lock:
            if author in helpers.voted:
                await context.send(
                    'You have already cast your vote and it cannot be changed')
                return

            async with helpers.votes_lock.reader_lock:
                async with helpers.current_live_post_lock.reader_lock:
                    if helpers.current_live_post[0] == 'POST':
                        ballot_list = [''] * len(
                            helpers.standing[helpers.current_live_post[1]])

                        # Create ballot
                        for candidate, message_id in helpers.voting_messages[
                                author]:
                            message = await context.author.fetch_message(
                                message_id)
                            if message.reactions:
                                reaction = message.reactions[0].emoji
                                ballot_list[helpers.EMOJI_LOOKUP[
                                    reaction]] = helpers.standing[
                                        helpers.
                                        current_live_post[1]][candidate][0]

                        helpers.votes.append(
                            Ballot(ranked_candidates=[
                                ballot for ballot in ballot_list
                                if str(ballot) != ''
                            ]))
                    else:
                        # Create ballot
                        for option, message_id in helpers.voting_messages[
                                author]:
                            message = await context.author.fetch_message(
                                message_id)
                            if message.reactions:
                                helpers.votes.append(
                                    Ballot(ranked_candidates=[option]))
                                break
                        else:
                            helpers.votes.append(Ballot(ranked_candidates=[]))

                    helpers.voted.append(author)
                await context.send('Your vote was successfully cast')
                helpers.log(
                    f'Votes cast: {len(helpers.votes)} - Votes not yet cast: {len(helpers.registered_members)-len(helpers.votes)}'
                )
Exemplo n.º 13
0
    async def stand(self, context, *input):
        if not input:
            await context.send(
                'Must supply the post you are running for and a valid email address, '
                f'usage:`{helpers.PREFIX}stand <POST> <EMAIL>`')
            return
        email = input[-1]
        post = ' '.join(input[:-1])
        if not post:
            await context.send(
                'Must supply the post you are running for and a valid email address, '
                f'usage:`{helpers.PREFIX}stand <POST> <EMAIL>`')
            return
        if '@' not in email:
            await context.send(
                'Must supply the post you are running for and a valid email address, '
                f'usage:`{helpers.PREFIX}stand <POST> <EMAIL>`')
            return

        matching_posts = helpers.match_post(post)
        if not matching_posts:
            await context.send(
                'Looks like that post isn\'t available for this election, '
                f'use `{helpers.PREFIX}posts` to see the posts up for election'
            )
            return
        post = matching_posts[0]
        async with helpers.current_live_post_lock.reader_lock:
            if helpers.current_live_post:
                if post == helpers.current_live_post[1]:
                    await context.send(
                        f'I\'m afraid voting for {post} has already begun, you cannot stand for this post'
                    )
                    return

            author = context.author.id
            members = helpers.get_members()

            output_str = 'Error'
            if author in helpers.registered_members:
                if [
                        i for i in helpers.standing[post]
                        if i == helpers.registered_members[author]
                ]:
                    output_str = (
                        f'It looks like you, {members[helpers.registered_members[author]]} are already '
                        f'standing for the position of: {post}')
                else:
                    helpers.standing[post][
                        helpers.registered_members[author]] = (Candidate(
                            members[helpers.registered_members[author]]),
                                                               email, author)
                    output_str = (
                        f'Congratulations {members[helpers.registered_members[author]]}, '
                        f'you are now standing for the position of {post}. If you no longer wish to stand, you '
                        f'can send `{helpers.PREFIX}standdown {post}`\n\n'
                        'Now you\'ll need to prepare a 2 minute speech to be given in the election call.\n'
                        f'If you have any questions please contact the secretary {helpers.SECRETARY_NAME}'
                        f'({helpers.SECRETARY_EMAIL}), or someone else on the committee.\n'
                        'If you can\'t make it to the actual election call, you must get in touch with the '
                        'secretary ASAP to sort out alternative arrangements.')
                    helpers.log(
                        f'{context.author.name}({helpers.registered_members[author]}) is now standing for {post}'
                    )
                    helpers.email_secretary(
                        members[helpers.registered_members[author]], post)
            else:
                output_str = (
                    'Looks like you\'re not registered yet, '
                    f'please register using `{helpers.PREFIX}register <STUDENT NUMBER>`'
                )
                helpers.log(
                    f'{context.author.name} has failed to stand for {post} because they are not registered'
                )

        helpers.save_standing()
        await context.send(output_str)