Skip to content

Commit e9d2dcd

Browse files
authored
Add backend support for the Admin dashboard (#66)
* rename files, start writing add new exec endpoint * rename auth models.py to table.py * complete crud functions for officer info & officer term * add endpoints for creating & updating executive info * fix bugs with officer info/term create/update * fix ruff issue * fix bugs with all endpoints & login test * remove dead code * remove debug print statement * remove accidental inclusions
1 parent 480c971 commit e9d2dcd

File tree

19 files changed

+770
-383
lines changed

19 files changed

+770
-383
lines changed

.github/workflows/ruff.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ jobs:
66
steps:
77
- uses: actions/checkout@v4
88
- uses: chartboost/ruff-action@v1
9+
with:
10+
version: 0.4.4

src/alembic/env.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import asyncio
22
from logging.config import fileConfig
33

4-
import auth.models
4+
import auth.tables
55
import database
6-
import officers.models
6+
import officers.tables
77
from alembic import context
88
from sqlalchemy import pool
99
from sqlalchemy.engine import Connection

src/auth/crud.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import Optional
44

55
import sqlalchemy
6-
from auth.models import SiteUser, UserSession
6+
from auth.tables import SiteUser, UserSession
77
from sqlalchemy.ext.asyncio import AsyncSession
88

99

File renamed without changes.

src/auth/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ async def login_user(
4545
# verify the ticket is valid
4646
url = (
4747
f"https://cas.sfu.ca/cas/serviceValidate?service={urllib.parse.quote(root_ip_address)}"
48-
f"/auth/login%3Fnext_url%3D{urllib.parse.quote(next_url)}&ticket={ticket}"
48+
f"/api/auth/login%3Fnext_url%3D{urllib.parse.quote(next_url)}&ticket={ticket}"
4949
)
5050
cas_response = xmltodict.parse(requests.get(url).text)
5151

src/constants.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import os
22

3-
root_ip_address = "http://localhost:8000" if os.environ.get("LOCAL") == "true" else "https://api.sfucsss.org"
3+
root_ip_address = "http://localhost:8080" if os.environ.get("LOCAL") == "true" else "https://api.sfucsss.org"
44
guild_id = "1260652618875797504" if os.environ.get("LOCAL") == "true" else "228761314644852736"
55
github_org_name = "CSSS-Test-Organization" if os.environ.get("LOCAL") == "true" else "CSSS"
66

77
SESSION_ID_LEN = 512
88
# technically a max of 8 digits https://www.sfu.ca/computing/about/support/tips/sfu-userid.html
99
COMPUTING_ID_LEN = 32
10+
COMPUTING_ID_MAX = 8
1011

1112
# see https://support.discord.com/hc/en-us/articles/4407571667351-How-to-Find-User-IDs-for-Law-Enforcement#:~:text=Each%20Discord%20user%20is%20assigned,user%20and%20cannot%20be%20changed.
1213
DISCORD_ID_LEN = 18

src/load_test_db.py

Lines changed: 99 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
# python load_test_db.py
44

55
import asyncio
6-
from datetime import datetime, timedelta
6+
from datetime import date, datetime, timedelta
77

88
import sqlalchemy
99
from auth.crud import create_user_session
1010
from database import SQLALCHEMY_TEST_DATABASE_URL, Base, DatabaseSessionManager
1111
from officers.constants import OfficerPosition
12-
from officers.crud import update_officer_info, update_officer_term
13-
from officers.schemas import OfficerInfoData, OfficerTermData
12+
from officers.crud import create_new_officer_info, create_new_officer_term, update_officer_info, update_officer_term
13+
from officers.types import OfficerInfoData, OfficerTermData
1414
from sqlalchemy.ext.asyncio import AsyncSession
1515

1616

@@ -68,7 +68,7 @@ async def load_test_officers_data(db_session: AsyncSession):
6868

6969
print("add officer info")
7070
# this person has uploaded all of their info
71-
update_officer_info(db_session, OfficerInfoData(
71+
await create_new_officer_info(db_session, OfficerInfoData(
7272
legal_name="Person A",
7373
discord_id=str(88_1234_7182_4877_1111),
7474
discord_name="person_a_yeah",
@@ -80,7 +80,7 @@ async def load_test_officers_data(db_session: AsyncSession):
8080
google_drive_email="[email protected]",
8181
))
8282
# this person has not joined the CSSS discord, so their discord name & nickname could not be found
83-
update_officer_info(db_session, OfficerInfoData(
83+
await create_new_officer_info(db_session, OfficerInfoData(
8484
legal_name="Person B",
8585
discord_id=str(88_1234_7182_4877_2222),
8686
discord_name=None,
@@ -92,7 +92,7 @@ async def load_test_officers_data(db_session: AsyncSession):
9292
google_drive_email="[email protected]",
9393
))
9494
# this person has uploaded the minimal amount of information
95-
update_officer_info(db_session, OfficerInfoData(
95+
await create_new_officer_info(db_session, OfficerInfoData(
9696
legal_name="Person C",
9797
discord_id=None,
9898
discord_name=None,
@@ -105,13 +105,12 @@ async def load_test_officers_data(db_session: AsyncSession):
105105
))
106106
await db_session.commit()
107107

108-
109-
update_officer_term(db_session, OfficerTermData(
108+
await create_new_officer_term(db_session, OfficerTermData(
110109
computing_id="abc11",
111110

112111
position=OfficerPosition.VicePresident.value,
113-
start_date=datetime.today() - timedelta(days=365),
114-
end_date=datetime.today() - timedelta(days=1),
112+
start_date=date.today() - timedelta(days=365),
113+
end_date=date.today() - timedelta(days=1),
115114

116115
nickname="the A",
117116
favourite_course_0="CMPT 125",
@@ -123,11 +122,11 @@ async def load_test_officers_data(db_session: AsyncSession):
123122
biography="Hi! I'm person A and I do lots of cool things! :)",
124123
photo_url=None, # TODO: this should be replaced with a default image
125124
))
126-
update_officer_term(db_session, OfficerTermData(
125+
await create_new_officer_term(db_session, OfficerTermData(
127126
computing_id="abc11",
128127

129128
position=OfficerPosition.ExecutiveAtLarge.value,
130-
start_date=datetime.today(),
129+
start_date=date.today(),
131130
end_date=None,
132131

133132
nickname="the holy A",
@@ -140,12 +139,12 @@ async def load_test_officers_data(db_session: AsyncSession):
140139
biography="Hi! I'm person A and I want school to be over ; _ ;",
141140
photo_url=None, # TODO: this should be replaced with a default image
142141
))
143-
update_officer_term(db_session, OfficerTermData(
142+
await create_new_officer_term(db_session, OfficerTermData(
144143
computing_id="abc33",
145144

146145
position=OfficerPosition.President.value,
147-
start_date=datetime.today(),
148-
end_date=datetime.today() + timedelta(days=365),
146+
start_date=date.today(),
147+
end_date=date.today() + timedelta(days=365),
149148

150149
nickname="CC",
151150
favourite_course_0="CMPT 999",
@@ -157,13 +156,98 @@ async def load_test_officers_data(db_session: AsyncSession):
157156
biography="I'm person C...",
158157
photo_url=None, # TODO: this should be replaced with a default image
159158
))
159+
# this officer term is not fully filled in
160+
await create_new_officer_term(db_session, OfficerTermData(
161+
computing_id="abc22",
162+
163+
position=OfficerPosition.DirectorOfArchives.value,
164+
start_date=date.today(),
165+
end_date=date.today() + timedelta(days=365),
166+
167+
nickname="Bee",
168+
favourite_course_0="CMPT 604",
169+
favourite_course_1=None,
170+
171+
favourite_pl_0="B",
172+
favourite_pl_1="N/A",
173+
174+
biography=None,
175+
photo_url=None, # TODO: this should be replaced with a default image
176+
))
177+
await db_session.commit()
178+
179+
await update_officer_info(db_session, OfficerInfoData(
180+
legal_name="Person C ----",
181+
discord_id=None,
182+
discord_name=None,
183+
discord_nickname=None,
184+
185+
computing_id="abc33",
186+
# adds a phone number
187+
phone_number="123-456-7890",
188+
github_username=None,
189+
google_drive_email=None,
190+
))
191+
await update_officer_term(db_session, OfficerTermData(
192+
computing_id="abc33",
193+
194+
position=OfficerPosition.President.value,
195+
start_date=date.today(),
196+
end_date=date.today() + timedelta(days=365),
197+
198+
nickname="SEE SEE",
199+
favourite_course_0="CMPT 999",
200+
favourite_course_1="CMPT 354",
201+
202+
favourite_pl_0="C++",
203+
favourite_pl_1="C",
204+
205+
biography="You see, I'm person C...",
206+
photo_url=None,
207+
))
208+
await db_session.commit()
209+
210+
async def load_sysadmin(db_session: AsyncSession):
211+
print("loading new sysadmin")
212+
# put your computing id here for testing purposes
213+
SYSADMIN_COMPUTING_ID = "gsa92"
214+
215+
await create_new_officer_info(db_session, OfficerInfoData(
216+
legal_name="Gabe Schulz",
217+
discord_id=None,
218+
discord_name=None,
219+
discord_nickname=None,
220+
221+
computing_id=SYSADMIN_COMPUTING_ID,
222+
phone_number=None,
223+
github_username=None,
224+
google_drive_email=None,
225+
))
226+
await create_new_officer_term(db_session, OfficerTermData(
227+
computing_id=SYSADMIN_COMPUTING_ID,
228+
229+
position=OfficerPosition.SystemAdministrator.value,
230+
start_date=date.today() - timedelta(days=365),
231+
end_date=None,
232+
233+
nickname="Gabe",
234+
favourite_course_0="CMPT 379",
235+
favourite_course_1="CMPT 295",
236+
237+
favourite_pl_0="Rust",
238+
favourite_pl_1="C",
239+
240+
biography="The systems are good o7",
241+
photo_url=None,
242+
))
160243
await db_session.commit()
161244

162245
async def async_main(sessionmanager):
163246
await reset_db(sessionmanager._engine)
164247
async with sessionmanager.session() as db_session:
165248
# load_test_auth_data
166249
await load_test_officers_data(db_session)
250+
await load_sysadmin(db_session)
167251

168252
if __name__ == "__main__":
169253
response = input(f"This will reset the {SQLALCHEMY_TEST_DATABASE_URL} database, are you okay with this? (y/N): ")

src/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
logging.basicConfig(level=logging.DEBUG)
1212
database.setup_database()
1313

14-
app = FastAPI(lifespan=database.lifespan, title="CSSS Site Backend")
14+
app = FastAPI(lifespan=database.lifespan, title="CSSS Site Backend", root_path="/api")
1515

1616
app.include_router(auth.urls.router)
1717
app.include_router(officers.urls.router)

src/officers/constants.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
_logger = logging.getLogger(__name__)
66

7-
7+
# TODO: remove enum, b/d python enums suck
88
class OfficerPosition(Enum):
99
President = "president"
1010
VicePresident = "vice-president"
@@ -29,6 +29,10 @@ class OfficerPosition(Enum):
2929
Webmaster = "webmaster"
3030
SocialMediaManager = "social media manager"
3131

32+
@staticmethod
33+
def position_values() -> list[str]:
34+
return _OFFICER_POSITION_VALUES
35+
3236
@staticmethod
3337
def from_string(position: str) -> Self | None:
3438
for item in OfficerPosition:
@@ -140,3 +144,7 @@ def expected_positions() -> list[Self]:
140144
OfficerPosition.SystemAdministrator,
141145
OfficerPosition.Webmaster,
142146
]
147+
148+
_OFFICER_POSITION_VALUES = [
149+
pos.value for pos in OfficerPosition.__members__.values()
150+
]

0 commit comments

Comments
 (0)