@@ -547,6 +547,60 @@ def get_ballot(db: Session, token: str) -> schemas.BallotGet:
547547 return schemas .BallotGet (token = token , votes = votes_get , election = election )
548548
549549
550+ def get_detailed_results (db :Session , election_ref :str , token : str ) -> str :
551+ payload = jws_verify (token )
552+
553+ if payload ["election" ] != election_ref :
554+ raise errors .UnauthorizedError ("Wrong authentication for this election" )
555+
556+ db_election = get_election (db , election_ref )
557+ votes = db_election .votes
558+ candidates = db_election .candidates
559+ candidates_count = len (candidates )
560+ filtered_votes = [v for v in votes if v .candidate_id is not None and v .grade_id is not None ]
561+ vote_count = len (filtered_votes )
562+ filtered_votes .sort (key = lambda v : v .id )
563+
564+ if vote_count % candidates_count != 0 :
565+ raise errors .ForbiddenError ("The number of votes is not a multiple of the number of candidates" )
566+
567+ # Build a table header: first cell empty, then candidate names
568+ header = ["" ] + [c .name for c in candidates ]
569+ table = []
570+
571+ # Group votes by voter (each group has candidates_count votes)
572+ for i in range (vote_count // candidates_count ):
573+ group = filtered_votes [i * candidates_count : (i + 1 ) * candidates_count ]
574+ # Check all votes in group have the same timestamp
575+ timestamps = {v .date_created for v in group }
576+
577+ if len (timestamps ) != 1 :
578+ raise errors .ForbiddenError ("Votes in a ballot must have the same timestamp" )
579+
580+ # Check all candidates are present
581+ candidate_ids = {v .candidate_id for v in group }
582+ expected_ids = {c .id for c in candidates }
583+
584+ if candidate_ids != expected_ids :
585+ raise errors .ForbiddenError ("Each ballot must contain all candidates" )
586+
587+ # Build row: first cell is timestamp, then grade label for each candidate
588+ row = ['-' ]
589+
590+ for c in candidates :
591+ vote = next (v for v in group if v .candidate_id == c .id )
592+ # Find grade label from header/table
593+ grade = next ((g for g in db_election .grades if g .id == vote .grade_id ), None )
594+ row .append (grade .label if grade else "" )
595+
596+ table .insert (random .randint (0 , len (table )), row )
597+
598+ table .insert (0 , header )
599+ return table
600+
601+
602+
603+
550604def get_results (db : Session , election_ref : str , token : t .Optional [str ]) -> schemas .ResultsGet :
551605 db_election = get_election (db , election_ref )
552606 if db_election is None :
0 commit comments