|
1 | 1 | """Contains cog classes for SU platform access cookie authorisation check interactions.""" |
2 | 2 |
|
3 | 3 | import logging |
4 | | -from enum import Enum |
5 | 4 | from typing import TYPE_CHECKING, override |
6 | 5 |
|
7 | | -import bs4 |
8 | 6 | import discord |
9 | 7 | from discord.ext import tasks |
10 | 8 |
|
|
13 | 11 | from utils.error_capture_decorators import ( |
14 | 12 | capture_guild_does_not_exist_error, |
15 | 13 | ) |
16 | | -from utils.msl import fetch_url_content_with_session |
| 14 | +from utils.msl import ( |
| 15 | + get_su_platform_access_cookie_status, |
| 16 | + get_su_platform_organisations, |
| 17 | +) |
17 | 18 |
|
18 | 19 | if TYPE_CHECKING: |
19 | | - from collections.abc import Iterable, Sequence |
| 20 | + from collections.abc import Sequence |
20 | 21 | from collections.abc import Set as AbstractSet |
21 | 22 | from logging import Logger |
22 | 23 | from typing import Final |
|
38 | 39 | ) |
39 | 40 |
|
40 | 41 |
|
41 | | -class SUPlatformAccessCookieStatus(Enum): |
42 | | - """Enum class defining the status of the SU Platform Access Cookie.""" |
43 | | - |
44 | | - INVALID = ( |
45 | | - logging.WARNING, |
46 | | - ( |
47 | | - "The SU platform access cookie is not associated with any MSL user, " |
48 | | - "meaning it is invalid or expired." |
49 | | - ), |
50 | | - ) |
51 | | - VALID = ( |
52 | | - logging.WARNING, |
53 | | - ( |
54 | | - "The SU platform access cookie is associated with a valid MSL user, " |
55 | | - "but is not an admin to any MSL organisations." |
56 | | - ), |
57 | | - ) |
58 | | - AUTHORISED = ( |
59 | | - logging.INFO, |
60 | | - ( |
61 | | - "The SU platform access cookie is associated with a valid MSL user and " |
62 | | - "has access to at least one MSL organisation." |
63 | | - ), |
64 | | - ) |
65 | | - |
66 | | - |
67 | | -class CheckSUPlatformAuthorisationBaseCog(TeXBotBaseCog): |
68 | | - """Cog class that defines the base functionality for cookie authorisation checks.""" |
69 | | - |
70 | | - async def get_su_platform_access_cookie_status(self) -> SUPlatformAccessCookieStatus: |
71 | | - """Retrieve the current validity status of the SU platform access cookie.""" |
72 | | - response_object: bs4.BeautifulSoup = bs4.BeautifulSoup( |
73 | | - await fetch_url_content_with_session(SU_PLATFORM_PROFILE_URL), "html.parser" |
74 | | - ) |
75 | | - page_title: bs4.Tag | bs4.NavigableString | None = response_object.find("title") |
76 | | - if not page_title or "Login" in str(page_title): |
77 | | - logger.warning("Token is invalid or expired.") |
78 | | - return SUPlatformAccessCookieStatus.INVALID |
79 | | - |
80 | | - organisation_admin_url: str = ( |
81 | | - f"{SU_PLATFORM_ORGANISATION_URL}/{settings['ORGANISATION_ID']}" |
82 | | - ) |
83 | | - response_html: str = await fetch_url_content_with_session(organisation_admin_url) |
84 | | - |
85 | | - if "admin tools" in response_html.lower(): |
86 | | - return SUPlatformAccessCookieStatus.AUTHORISED |
87 | | - |
88 | | - if "You do not have any permissions for this organisation" in response_html.lower(): |
89 | | - return SUPlatformAccessCookieStatus.VALID |
90 | | - |
91 | | - logger.warning( |
92 | | - "Unexpected response when checking SU platform access cookie authorisation." |
93 | | - ) |
94 | | - return SUPlatformAccessCookieStatus.INVALID |
95 | | - |
96 | | - async def get_su_platform_organisations(self) -> "Iterable[str]": |
97 | | - """Retrieve the MSL organisations the current SU platform cookie has access to.""" |
98 | | - response_object: bs4.BeautifulSoup = bs4.BeautifulSoup( |
99 | | - await fetch_url_content_with_session(SU_PLATFORM_PROFILE_URL), "html.parser" |
100 | | - ) |
101 | | - |
102 | | - page_title: bs4.Tag | bs4.NavigableString | None = response_object.find("title") |
103 | | - |
104 | | - if not page_title: |
105 | | - logger.warning( |
106 | | - "Profile page returned no content when checking " |
107 | | - "SU platform access cookie's authorisation." |
108 | | - ) |
109 | | - return () |
110 | | - |
111 | | - if "Login" in str(page_title): |
112 | | - logger.warning( |
113 | | - "Authentication redirected to login page. " |
114 | | - "SU platform access cookie is invalid or expired." |
115 | | - ) |
116 | | - return () |
117 | | - |
118 | | - profile_section_html: bs4.Tag | bs4.NavigableString | None = response_object.find( |
119 | | - "div", {"id": "profile_main"} |
120 | | - ) |
121 | | - |
122 | | - if profile_section_html is None: |
123 | | - logger.warning( |
124 | | - "Couldn't find the profile section of the user " |
125 | | - "when scraping the SU platform's website HTML." |
126 | | - ) |
127 | | - logger.debug("Retrieved HTML: %s", response_object.text) |
128 | | - return () |
129 | | - |
130 | | - user_name: bs4.Tag | bs4.NavigableString | int | None = profile_section_html.find("h1") |
131 | | - |
132 | | - if not isinstance(user_name, bs4.Tag): |
133 | | - logger.warning( |
134 | | - "Found user profile on the SU platform but couldn't find their name." |
135 | | - ) |
136 | | - logger.debug("Retrieved HTML: %s", response_object.text) |
137 | | - return () |
138 | | - |
139 | | - parsed_html: bs4.Tag | bs4.NavigableString | None = response_object.find( |
140 | | - "ul", {"id": "ulOrgs"} |
141 | | - ) |
142 | | - |
143 | | - if parsed_html is None or isinstance(parsed_html, bs4.NavigableString): |
144 | | - NO_ADMIN_TABLE_MESSAGE: Final[str] = ( |
145 | | - f"Failed to retrieve the admin table for user: {user_name.string}. " |
146 | | - "Please check you have used the correct SU platform access token!" |
147 | | - ) |
148 | | - logger.warning(NO_ADMIN_TABLE_MESSAGE) |
149 | | - return () |
150 | | - |
151 | | - organisations: Iterable[str] = [ |
152 | | - list_item.get_text(strip=True) for list_item in parsed_html.find_all("li") |
153 | | - ] |
154 | | - |
155 | | - logger.debug( |
156 | | - "SU platform access cookie has admin authorisation to: %s as user %s", |
157 | | - organisations, |
158 | | - user_name.text, |
159 | | - ) |
160 | | - |
161 | | - return organisations |
162 | | - |
163 | | - |
164 | | -class CheckSUPlatformAuthorisationCommandCog(CheckSUPlatformAuthorisationBaseCog): |
| 42 | +class CheckSUPlatformAuthorisationCommandCog(TeXBotBaseCog): |
165 | 43 | """Cog class that defines the "/check-su-platform-authorisation" command.""" |
166 | 44 |
|
167 | 45 | @discord.slash_command( |
|
0 commit comments