Passed
Push — master ( dcd1eb...4f7f97 )
by Cyb3r
02:51 queued 01:44
created

bot.cogs.schools.SchoolCog.add_school()   C

Complexity

Conditions 9

Size

Total Lines 91
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 56
nop 4
dl 0
loc 91
rs 6.1066
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""Schools commands for bot"""
2
import asyncio
3
import random
4
import logging
5
import discord
6
from discord.ext import commands
7
from bot import utils
8
9
log = logging.getLogger("bot")
10
11
12
class SchoolCog(commands.Cog, name="Schools"):
13
    """
14
    School Cog
15
16
    **Commands:**
17
18
        - `list-schools`: List all the available school roles that are joinable.
19
20
        - `import-school`: Allows admin to import current roles into schools.
21
22
        - `join-school`: Allows users to join any available school role.
23
24
        - `add-school`: Command that allows users to create their own school.
25
26
    """
27
28
    def __init__(self, bot):
29
        self.bot = bot
30
31
    @commands.command(name="list-schools", help="Gets list of current schools")
32
    async def list_schools(self, ctx) -> None:
33
        """
34
        List schools
35
36
        Lists current schools in the database. Message is a embed that has a random color with the
37
        list of all schools.
38
39
        :param ctx: Command context
40
        :type ctx: discord.ext.commands.Context
41
        :return: None
42
        """
43
        fetched = sorted(await utils.fetch("schools", "school"), key=str.lower)
44
        if len(fetched) == 0:
45
            return await utils.error_message(ctx, "No schools to join")
46
        await utils.list_message(
47
            ctx,
48
            fetched,
49
            title="Available schools to join:",
50
            footer="If your school is not in the list, use `$help add-school`",
51
        )
52
53
    @commands.command(name="import-school", help="Admin Only Feature")
54
    @commands.check(utils.check_admin)
55
    async def import_school(self, ctx, school_name: str, region: str) -> None:
56
        """
57
        Import school
58
59
        Allows admins to import existing roles as schools.
60
61
        :param ctx: Command context
62
        :param school_name: Name of school role
63
        :type school_name: str
64
        :param region: Region of the school
65
        :type region: str
66
        :return: None
67
        """
68
        school_role = discord.utils.get(ctx.guild.roles, name=school_name)
69
        if school_role.name in await utils.fetch("schools", "school"):
70
            await utils.error_message(ctx, "School role already exists")
71
        else:
72
            new_school = [
73
                school_name,
74
                region,
75
                school_role.color.value,
76
                school_role.id,  # noqa: E501 pylint: disable=no-member
77
                "Imported",
78
                self.bot.owner_id,
79
            ]
80
            status = await utils.insert("schools", new_school)
81
            if status == "error":
82
                await utils.error_message(ctx, "Error importing school")
83
            else:
84
                await utils.make_embed(ctx, color="28b463", title="School has been imported")
85
86
    @commands.command(name="join-school", help="Joins a schools.")
87
    @commands.has_role("new")
88
    async def join_school(self, ctx, *, school_name: str) -> None:
89
        """Join School
90
91
        Enables users to join a school role. school_name arguments is not to be quote separated.
92
        Users are required to have the role "new". Users will be assigned the school role, region
93
        role and "verified" role. They will lose their "new" role.
94
95
        :param ctx: Command context
96
        :type ctx: discord.ext.commands.Context
97
        :param school_name: Name of the school role
98
        :type school_name: str
99
        :return: None
100
        """
101
        user = ctx.message.author
102
        db_entry = await utils.select("schools", "school, region", "school", school_name)
103
        if len(db_entry) == 0:
104
            return await utils.error_message(
105
                ctx, "School could not be found.", title="Missing School:"
106
            )
107
108
        to_add = [discord.utils.get(ctx.guild.roles, name=x) for x in (school_name, "verified")]
109
        if None in to_add:
110
            await utils.error_message(ctx, "The school you select does not have valid role.")
111
            log.warning(
112
                "{} tried to join {}. Only roles found: {}".format(
113
                    ctx.author.name, school_name, to_add
114
                )
115
            )
116
        else:
117
            log.debug("Adding roles: {} to {}".format(to_add, user))
118
            await user.add_roles(*to_add, reason=f"{user.name} joined {school_name}")
119
            await user.remove_roles(
120
                discord.utils.get(ctx.guild.roles, name="new"),
121
                reason=f"{user.name} joined {school_name}",
122
            )
123
            await ctx.author.send(
124
                embed=await utils.make_embed(
125
                    ctx,
126
                    "28b463",
127
                    send=False,
128
                    title=f"School assigned: {school_name}",
129
                )
130
            )
131
132
    @commands.command(
133
        name="add-school",
134
        help="Adds a new school and makes a role for it.\n"
135
        "Only schools on the list are allowed to join.\n"
136
        "List: https://github.com/Competitive-Cyber-Clubs/School-List/blob/master/school_list.csv",
137
        description="Creates a new school",
138
    )
139
    @commands.has_role("new")
140
    async def add_school(
141
        self, ctx: commands.Context, *, school_name: str
142
    ) -> None:  # pylint: disable=too-many-branches
143
        """
144
        Add school
145
146
        Enables users to create a school role. They are required to have the role "new". Schools
147
        will automatically be assigned a region based on the school_list.csv in utils.
148
149
        **Raises:**
150
151
            utils.FailedReactionCheck: Exception is raised if the reaction check does not validate.
152
153
        :param ctx: Command Context
154
        :type ctx: discord.ext.commands.Context
155
        :param school_name: Name of school to join
156
        :type school_name: str
157
        :return: None
158
        """
159
        if not await utils.school_check(self.bot.school_list, school_name):
160
            return await utils.error_message(ctx, message="School name not valid.")
161
162
        if await utils.select("schools", "school", "school", school_name):
163
            log.info(
164
                "{} attempted to create a duplicate role for {}".format(
165
                    ctx.author.name, school_name
166
                )
167
            )
168
            return await utils.error_message(ctx, f"School role for {school_name} already exists.")
169
170
        regions = await utils.fetch("regions", "name")
171
        region = await utils.region_select(self.bot.school_list, school_name)
172
        if region not in regions:
173
            # No region map error
174
            log.error(
175
                "There is no region map for {}, region: {}, {}".format(school_name, region, regions)
176
            )
177
            return await utils.error_message(ctx, f"No region defined for {school_name}")
178
179
        await utils.make_embed(
180
            ctx,
181
            title=f"You are about to create a new school: {school_name}.",
182
            description="React 👍 to this message in 60 seconds to confirm.",
183
        )
184
        # Gives the member 60 seconds to add the reaction '👍' to the message.
185
        try:
186
            reactions, user = await self.bot.wait_for("reaction_add", timeout=60)
187
            if not await utils.check_react(ctx, user, reactions, "👍"):
188
                raise utils.FailedReactionCheck
189
        except asyncio.TimeoutError:
190
            await utils.error_message(
191
                ctx, "Timed out waiting for a reaction. Please reach to the message in 30 seconds"
192
            )
193
        except utils.FailedReactionCheck:
194
            await utils.error_message(ctx, "Wrong reaction added or added by the wrong member")
195
        else:
196
            color = int("0x%06x" % random.randint(0, 0xFFFFFF), 16)  # nosec
197
            added_school = await ctx.guild.create_role(
198
                name=school_name,
199
                color=discord.Color(color),
200
                mentionable=True,
201
                hoist=False,
202
                reason="Added by {}".format(ctx.author.name),
203
            )
204
            data = [
205
                school_name,
206
                region,
207
                color,
208
                added_school.id,
209
                (ctx.author.name + ctx.author.discriminator),
210
                ctx.author.id,
211
            ]
212
            status = await utils.insert("schools", data)
213
            if status == "error":
214
                await utils.error_message(ctx, "There was an error with creating the role.")
215
                await added_school.delete(reason="Error in creation")
216
                log.warning("Error with School Role creation.")
217
            else:
218
                success_msg = 'School "{}" has been created in {} with color of 0x{}'.format(
219
                    school_name, region, color
220
                )
221
                await utils.make_embed(ctx, color=color, title="Success", description=success_msg)
222
                await self.join_school(ctx=ctx, school_name=school_name)
223
224
225
def setup(bot):
226
    """Needed for extension loading"""
227
    bot.add_cog(SchoolCog(bot))
228