schools.SchoolCog.import_school()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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