88import database
99import elections
1010import elections .tables
11- from elections .tables import Election , NomineeApplication , election_types
11+ from elections .tables import Election , NomineeApplication , NomineeInfo , election_types
1212from officers .constants import OfficerPosition
1313from permission .types import ElectionOfficer , WebsiteAdmin
1414from utils .urls import is_logged_in
@@ -32,6 +32,7 @@ async def _validate_user(
3232 if not logged_in :
3333 return False , None , None
3434
35+ # where valid means elections officer or website admin
3536 has_permission = await ElectionOfficer .has_permission (db_session , computing_id )
3637 if not has_permission :
3738 has_permission = await WebsiteAdmin .has_permission (db_session , computing_id )
@@ -65,7 +66,11 @@ async def list_elections(
6566
6667@router .get (
6768 "/by_name/{name:str}" ,
68- description = "Retrieves the election data for an election by name. Returns private details when the time is allowed."
69+ description = """
70+ Retrieves the election data for an election by name.
71+ Returns private details when the time is allowed.
72+ If user is an admin or elections officer, returns computing ids for each candidate as well.
73+ """
6974)
7075async def get_election (
7176 request : Request ,
@@ -80,16 +85,45 @@ async def get_election(
8085 status_code = status .HTTP_400_BAD_REQUEST ,
8186 detail = f"election with slug { _slugify (name )} does not exist"
8287 )
83- elif current_time >= election .datetime_start_voting :
84- # after the voting period starts, all election data becomes public
85- return JSONResponse (election .private_details (current_time ))
86-
87- # TODO: include nominees and speeches
88- # TODO: ignore any empty mappings
8988
9089 is_valid_user , _ , _ = await _validate_user (request , db_session )
91- if is_valid_user :
90+ if current_time >= election .datetime_start_voting or is_valid_user :
91+
9292 election_json = election .private_details (current_time )
93+ all_nominations = elections .crud .get_all_registrations_in_election (db_session , _slugify (name ))
94+ election_json ["candidates" ] = []
95+
96+ avaliable_positions_list = election .avaliable_positions .split ("," )
97+ for nomination in all_nominations :
98+ if nomination .position not in avaliable_positions_list :
99+ # ignore any positions that are **no longer** active
100+ continue
101+
102+ # NOTE: if a nominee does not input their legal name, they are not considered a nominee
103+ nominee_info = elections .crud .get_nominee_info (db_session , nomination .computing_id )
104+ if nominee_info is None :
105+ print ("unreachable" )
106+ continue
107+
108+ candidate_entry = {
109+ "position" : nomination .position ,
110+ "full_name" : nominee_info .full_name ,
111+ "linked_in" : nominee_info .linked_in ,
112+ "instagram" : nominee_info .instagram ,
113+ "email" : nominee_info .email ,
114+ "discord_username" : nominee_info .discord_username ,
115+ "speech" : (
116+ "No speech provided by this candidate"
117+ if nomination .speech is None
118+ else nomination .speech
119+ ),
120+ }
121+ if is_valid_user :
122+ candidate_entry ["computing_id" ] = nomination .computing_id
123+ election_json ["candidates" ].append (candidate_entry )
124+
125+ # after the voting period starts, all election data becomes public
126+ return JSONResponse ()
93127 else :
94128 election_json = election .public_details (current_time )
95129
@@ -353,6 +387,13 @@ async def register_in_election(
353387 detail = f"invalid position { position } "
354388 )
355389
390+ if await elections .crud .get_nominee_info (db_session , computing_id ) is None :
391+ # ensure that the user has a nominee info entry before allowing registration to occur.
392+ raise HTTPException (
393+ status_code = status .HTTP_400_BAD_REQUEST ,
394+ detail = "must have submitted nominee info before registering"
395+ )
396+
356397 current_time = datetime .now ()
357398 election_slug = _slugify (election_name )
358399 election = await elections .crud .get_election (db_session , election_slug )
@@ -388,6 +429,7 @@ async def register_in_election(
388429 position = position ,
389430 speech = None
390431 ))
432+ await db_session .commit ()
391433
392434@router .patch (
393435 "/register/{election_name:str}" ,
@@ -437,6 +479,7 @@ async def update_registration(
437479 position = position ,
438480 speech = speech
439481 ))
482+ await db_session .commit ()
440483
441484@router .delete (
442485 "/register/{election_name:str}" ,
@@ -480,3 +523,68 @@ async def delete_registration(
480523 )
481524
482525 await elections .crud .delete_registration (db_session , computing_id , election_slug , position )
526+ await db_session .commit ()
527+
528+ # nominee info ------------------------------------------------------------- #
529+
530+ @router .get (
531+ "/nominee_info" ,
532+ description = "Nominee info is always publically tied to elections, so be careful!"
533+ )
534+ async def get_nominee_info (
535+ request : Request ,
536+ db_session : database .DBSession ,
537+ ):
538+ logged_in , _ , computing_id = await is_logged_in (request , db_session )
539+ if not logged_in :
540+ raise HTTPException (
541+ status_code = status .HTTP_401_UNAUTHORIZED ,
542+ detail = "must be logged in to get your nominee info"
543+ )
544+
545+ nominee_info = await elections .crud .get_nominee_info (db_session , computing_id )
546+ if nominee_info is None :
547+ raise HTTPException (
548+ status_code = status .HTTP_400_BAD_REQUEST ,
549+ detail = "You don't have any nominee info yet"
550+ )
551+
552+ return JSONResponse (nominee_info .as_serializable ())
553+
554+ @router .patch (
555+ "/nominee_info" ,
556+ description = "Will create or update nominee info. Returns an updated copy of their nominee info."
557+ )
558+ async def provide_nominee_info (
559+ request : Request ,
560+ db_session : database .DBSession ,
561+ full_name : str ,
562+ linked_in : str | None ,
563+ instagram : str | None ,
564+ email : str | None ,
565+ discord_username : str | None ,
566+ ):
567+ logged_in , _ , computing_id = await is_logged_in (request , db_session )
568+ if not logged_in :
569+ raise HTTPException (
570+ status_code = status .HTTP_401_UNAUTHORIZED ,
571+ detail = "must be logged in to update nominee info"
572+ )
573+
574+ pending_nominee_info = NomineeInfo (
575+ computing_id = computing_id ,
576+ full_name = full_name ,
577+ linked_in = linked_in ,
578+ instagram = instagram ,
579+ email = email ,
580+ discord_username = discord_username ,
581+ )
582+ if await elections .crud .get_nominee_info (db_session , computing_id ) is None :
583+ await elections .crud .create_nominee_info (db_session , pending_nominee_info )
584+ else :
585+ await elections .crud .update_nominee_info (db_session , pending_nominee_info )
586+
587+ await db_session .commit ()
588+
589+ new_nominee_info = await elections .crud .get_nominee_info (db_session , computing_id )
590+ return JSONResponse (new_nominee_info .as_serializable ())
0 commit comments