File tree Expand file tree Collapse file tree 3 files changed +913
-460
lines changed
Expand file tree Collapse file tree 3 files changed +913
-460
lines changed Original file line number Diff line number Diff line change @@ -522,6 +522,47 @@ def is_organizer(self, username):
522522 username = username .strip ()
523523 return username in self .get_organizers ()
524524
525+ def can_change_scoring_system (self ):
526+ """
527+ Determine if scoring system can be changed.
528+
529+ Rules:
530+ - Cannot change if contest has any reviewed submissions
531+ - Can change if contest is brand new (no submissions)
532+ - Can change if only pending submissions exist
533+
534+ Returns:
535+ tuple: (can_change: bool, reason: str or None)
536+ """
537+ from app .models .submission import Submission
538+
539+ # Check if any submissions have been reviewed
540+ reviewed_count = (
541+ Submission .query .filter (Submission .contest_id == self .id )
542+ .filter (Submission .status .in_ (["accepted" , "rejected" ]))
543+ .count ()
544+ )
545+
546+ if reviewed_count > 0 :
547+ return (
548+ False ,
549+ f"Cannot change scoring system: { reviewed_count } submissions have already been reviewed" ,
550+ )
551+
552+ return True , None
553+
554+ def get_scoring_mode (self ):
555+ """
556+ Get the current scoring mode for this contest.
557+
558+ Returns:
559+ str: 'simple' or 'multi_parameter'
560+ """
561+ params = self .get_scoring_parameters ()
562+ if params and params .get ("enabled" ) is True :
563+ return "multi_parameter"
564+ return "simple"
565+
525566 # ------------------------------------------------------------------------
526567 # SERIALIZATION
527568 # ------------------------------------------------------------------------
Original file line number Diff line number Diff line change @@ -744,6 +744,38 @@ def update_contest(contest_id):
744744 ):
745745 return jsonify ({"error" : "Permission denied" }), 403
746746
747+ # --- CRITICAL: Scoring System Change Validation ---
748+ if "scoring_parameters" in data :
749+ # Get current and proposed scoring modes
750+ current_mode = contest .get_scoring_mode ()
751+
752+ proposed_params = data .get ("scoring_parameters" )
753+ if proposed_params is None :
754+ proposed_mode = "simple"
755+ elif (
756+ isinstance (proposed_params , dict )
757+ and proposed_params .get ("enabled" ) is True
758+ ):
759+ proposed_mode = "multi_parameter"
760+ else :
761+ proposed_mode = "simple"
762+
763+ # Check if mode is changing
764+ if current_mode != proposed_mode :
765+ can_change , reason = contest .can_change_scoring_system ()
766+ if not can_change :
767+ return (
768+ jsonify (
769+ {
770+ "error" : reason ,
771+ "current_mode" : current_mode ,
772+ "attempted_mode" : proposed_mode ,
773+ "locked" : True ,
774+ }
775+ ),
776+ 400 ,
777+ )
778+
747779 # --- Basic Metadata Fields ---
748780 if "name" in data :
749781 contest .name = data .get ("name" ) or contest .name
You can’t perform that action at this time.
0 commit comments