Passed
Push — master ( 269135...eec213 )
by
unknown
01:33
created

schools.SchoolCog.admin_add_school()   B

Complexity

Conditions 5

Size

Total Lines 63
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

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