Passed
Push — master ( 95e0ba...ca4927 )
by Cyb3r
01:11
created

schools.SchoolCog.add_school()   C

Complexity

Conditions 9

Size

Total Lines 93
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 57
nop 4
dl 0
loc 93
rs 6.0739
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(
129
        name="add-school",
130
        help="Adds a new school and makes a role for it.\n"
131
        "Only schools on the list are allowed to join.\n"
132
        "List: https://github.com/Competitive-Cyber-Clubs/School-List/blob/master/school_list.csv",
133
        description="Creates a new school",
134
    )
135
    @commands.has_role("new")
136
    async def add_school(
137
        self, ctx: commands.Context, *, school_name: str
138
    ) -> None:  # pylint: disable=too-many-branches
139
        """
140
        Add school
141
142
        Enables users to create a school role. They are required to have the role "new". Schools
143
        will automatically be assigned a region based on the school_list.csv in utils.
144
145
        **Raises:**
146
147
            utils.FailedReactionCheck: Exception is raised if the reaction check does not validate.
148
149
        :param ctx: Command Context
150
        :type ctx: discord.ext.commands.Context
151
        :param school_name: Name of school to join
152
        :type school_name: str
153
        :return: None
154
        """
155
        if not await utils.school_check(self.bot.school_list, school_name):
156
            return await utils.error_message(ctx, message="School name not valid.")
157
158
        if await utils.select("schools", "school", "school", school_name):
159
            self.bot.log.info(
160
                f"{ctx.author.name} attempted to create a duplicate role for {school_name}"
161
            )
162
            return await utils.error_message(
163
                ctx,
164
                f"School role for {school_name} already exists.\n"
165
                f"Use `?join-school {school_name}` to join it",
166
            )
167
168
        regions = await utils.fetch("regions", "name")
169
        region = await utils.region_select(self.bot.school_list, school_name)
170
        if region not in regions:
171
            # No region map error
172
            self.bot.log.error(
173
                f"There is no region map for {school_name}, region: {region}, regions{regions}"
174
            )
175
            return await utils.error_message(ctx, f"No region defined for {school_name}")
176
177
        await utils.make_embed(
178
            ctx,
179
            title=f"You are about to create a new school: {school_name}.",
180
            description="React 👍 to this message in 60 seconds to confirm.",
181
        )
182
        # Gives the member 60 seconds to add the reaction '👍' to the message.
183
        try:
184
            reactions, user = await self.bot.wait_for("reaction_add", timeout=60)
185
            if not await utils.check_react(ctx, user, reactions, "👍"):
186
                raise utils.FailedReactionCheck
187
        except asyncio.TimeoutError:
188
            await utils.error_message(
189
                ctx, "Timed out waiting for a reaction. Please reach to the message in 30 seconds"
190
            )
191
        except utils.FailedReactionCheck:
192
            await utils.error_message(ctx, "Wrong reaction added or added by the wrong member")
193
        else:
194
            color = int(f"0x{random.randint(0, 0xFFFFFF)}", 16)  # nosec
195
            added_school = await ctx.guild.create_role(
196
                name=school_name,
197
                color=discord.Color(color),
198
                mentionable=True,
199
                hoist=False,
200
                reason=f"Added by {ctx.author.name}",
201
            )
202
            data = [
203
                school_name,
204
                region,
205
                color,
206
                added_school.id,
207
                (ctx.author.name + ctx.author.discriminator),
208
                ctx.author.id,
209
            ]
210
            status = await utils.insert("schools", data)
211
            if status == "error":
212
                await utils.error_message(ctx, "There was an error with creating the role.")
213
                await added_school.delete(reason="Error in creation")
214
                self.bot.log.warning("Error with School Role creation.")
215
            else:
216
                success_msg = (
217
                    f'School "{school_name}" has been created in {region} with color of 0x{color}'
218
                )
219
                await utils.make_embed(ctx, color=color, title="Success", description=success_msg)
220
                await self.join_school(ctx=ctx, school_name=school_name)
221
222
223
def setup(bot):
224
    """Needed for extension loading"""
225
    bot.add_cog(SchoolCog(bot))
226