Skip to content

Commit a55eb85

Browse files
gregvclaude
andcommitted
Add server-side validation for hacker required screening questions
- Update validate_hackathon_data to accept and validate hacker_required_questions in constraints - Add server-side validation of required question answers in create_or_update_volunteer for hacker applications Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d9e9a86 commit a55eb85

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

common/utils/validators.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,21 @@ def validate_hackathon_data(data):
101101
if not all(isinstance(constraints.get(k), int) for k in ["max_people_per_team", "max_teams_per_problem", "min_people_per_team"]):
102102
raise ValueError("Constraints must be integers")
103103

104-
# Add more specific validations as needed
104+
# Validate hacker_required_questions if present
105+
hacker_required_questions = constraints.get("hacker_required_questions", {})
106+
if hacker_required_questions:
107+
questions = hacker_required_questions.get("questions", [])
108+
if not isinstance(questions, list):
109+
raise ValueError("hacker_required_questions.questions must be a list")
110+
for i, q in enumerate(questions):
111+
if not isinstance(q, dict):
112+
raise ValueError(f"Question {i} must be an object")
113+
if not isinstance(q.get("question"), str) or not q.get("question"):
114+
raise ValueError(f"Question {i} must have a non-empty 'question' string")
115+
if not isinstance(q.get("required_answer"), bool):
116+
raise ValueError(f"Question {i} must have a boolean 'required_answer'")
117+
if not isinstance(q.get("error"), str) or not q.get("error"):
118+
raise ValueError(f"Question {i} must have a non-empty 'error' string")
105119

106120
if __name__ == "__main__":
107121
# Simple tests

services/volunteers_service.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,32 @@ def create_or_update_volunteer(
720720
if not verify_recaptcha(recaptcha_token):
721721
warning(logger, "reCAPTCHA verification failed", email=email)
722722
return {"error": "reCAPTCHA verification failed"}
723-
723+
724+
# Validate required question answers for hacker applications
725+
if volunteer_data.get('volunteer_type') == 'hacker':
726+
submitted_answers = volunteer_data.get('requiredQuestionAnswers', [])
727+
if submitted_answers:
728+
try:
729+
db_temp = get_db()
730+
hackathon_docs = db_temp.collection('hackathons').where('event_id', '==', event_id).limit(1).stream()
731+
hackathon_data = None
732+
for doc in hackathon_docs:
733+
hackathon_data = doc.to_dict()
734+
break
735+
736+
if hackathon_data:
737+
questions = hackathon_data.get('constraints', {}).get('hacker_required_questions', {}).get('questions', [])
738+
if questions:
739+
if len(submitted_answers) != len(questions):
740+
warning(logger, "Required question answer count mismatch", email=email, event_id=event_id)
741+
return {"error": "Required question answers do not match the expected number of questions"}
742+
for i, q in enumerate(questions):
743+
if i >= len(submitted_answers) or submitted_answers[i] != q.get('required_answer'):
744+
warning(logger, "Required question answer incorrect", email=email, event_id=event_id, question_index=i)
745+
return {"error": q.get('error', 'You do not meet the eligibility requirements for this event.')}
746+
except Exception as e:
747+
exception(logger, "Error validating required questions", exc_info=e, email=email, event_id=event_id)
748+
724749
db = get_db()
725750
volunteer_type = volunteer_data.get('volunteer_type')
726751

0 commit comments

Comments
 (0)