1- import os
2- import json
3- import gspread
41from typing import Optional
52from app .schemas .submission import SubmissionOut
6- from sqlalchemy .orm import Session
3+ from sqlalchemy .orm import Session , joinedload
74from app .db import models
8- from datetime import datetime , date , timedelta
5+ from datetime import date , timedelta
96from sqlalchemy import func
107from app .db .db import SessionLocal
8+ import gspread
9+ from oauth2client .service_account import ServiceAccountCredentials
10+ import os
1111
12- def _get_gspread_client ():
13- creds_json_str = os .getenv ("GOOGLE_CREDENTIALS_JSON" )
14- if not creds_json_str :
15- raise ValueError ("GOOGLE_CREDENTIALS_JSON environment variable is not set." )
16-
17- creds_info = json .loads (creds_json_str )
18- client = gspread .service_account_from_dict (creds_info )
19- return client
12+ SCOPE = ["https://spreadsheets.google.com/feeds" , "https://www.googleapis.com/auth/drive" ]
13+ CREDS_FILE = "credentials.json"
2014
2115def get_user_by_email (db : Session , email : str ):
2216 return db .query (models .User ).filter (models .User .email == email ).first ()
2317
2418def get_task (db : Session , track_id : int , task_no : int ):
2519 return db .query (models .Task ).filter_by (track_id = track_id , task_no = task_no ).first ()
2620
27- def submit_task (db : Session , mentee_id : int , task_id : int , reference_link : str , start_date : date , commit_hash : str ):
21+ def submit_task (db : Session , mentee_id : int , task_id : int , start_date : date , commit_hash : str ):
2822 existing = db .query (models .Submission ).filter_by (mentee_id = mentee_id , task_id = task_id ).first ()
2923 if existing :
30- return None
24+ return None # Already submitted
3125
3226 mentee = db .query (models .User ).filter (models .User .id == mentee_id ).first ()
27+
3328 task = db .query (models .Task ).filter (models .Task .id == task_id ).first ()
3429 if not task :
3530 raise Exception ("Task not found" )
3631
37- start_date = datetime .combine (start_date , datetime .min .time ())
32+ # convert start_date into a datetime object
33+ start_date = start_date
3834 deadline = start_date + timedelta (days = task .deadline_days )
39- submitted_at = datetime . now ()
35+ submitted_at = date . today ()
4036
37+ # Check if the submission is late
4138 if deadline >= submitted_at :
42- submitted_late = False
43- elif deadline + timedelta (hours = 12 ) >= submitted_at :
44- submitted_late = True
45- else :
46- return "late submission not allowed"
47-
48- submission = models .Submission (
49- mentee_id = mentee_id ,
50- task_id = task .id ,
51- task_name = task .title ,
52- task_no = task .task_no ,
53- reference_link = reference_link ,
54- submitted_at = date .today (),
55- status = "submitted" ,
56- start_date = start_date ,
57- submitted_late = submitted_late ,
58- commit_hash = commit_hash
59- )
39+ submission = models .Submission (
40+ mentee_id = mentee_id ,
41+ task_id = task .id ,
42+ task_name = task .title ,
43+ task_no = task .task_no ,
44+ submitted_at = date .today (),
45+ status = "submitted" ,
46+ start_date = start_date ,
47+ commit_hash = commit_hash
48+ )
6049
61- client = _get_gspread_client ()
62- sheet_name = "Copy of Praveshan 2025 Master DB"
63-
64- if task .track_id == 1 :
65- worksheet_name = "S1 Submissions"
66- elif task .track_id == 2 :
67- worksheet_name = "S2 Submissions"
50+ credentials = ServiceAccountCredentials .from_json_keyfile_name (CREDS_FILE , SCOPE )
51+ client = gspread .authorize (credentials )
52+ if (task .track_id == 1 ):
53+ sheet = client .open ("Copy of Praveshan 2025 Master DB" ).worksheet ("S1 Submissions" )
54+ cell = sheet .find (mentee .name )
55+ if not cell :
56+ name_column = sheet .col_values (1 )
57+ row = len (name_column ) + 1
58+ sheet .update_cell (row , 1 , mentee .name )
59+ sheet .update_cell (row , task .task_no + 2 , commit_hash )
60+ else :
61+ row = cell .row
62+ sheet .update_cell (row , task .task_no + 2 , commit_hash )
63+ elif (task .track_id == 2 ):
64+ sheet = client .open ("Copy of Praveshan 2025 Master DB" ).worksheet ("S2 Submissions" )
65+ cell = sheet .find (mentee .name )
66+ if not cell :
67+ name_column = sheet .col_values (1 )
68+ row = len (name_column ) + 1
69+ sheet .update_cell (row , 1 , mentee .name )
70+ sheet .update_cell (row , task .task_no + 2 , commit_hash )
71+ else :
72+ row = cell .row
73+ sheet .update_cell (row , task .task_no + 2 , commit_hash )
74+
75+
76+
77+ db .add (submission )
78+ db .commit ()
79+ db .refresh (submission )
80+
81+ return submission
6882 else :
69- worksheet_name = None
70-
71- if worksheet_name :
72- sheet = client .open (sheet_name ).worksheet (worksheet_name )
73- cell = sheet .find (mentee .name )
74- if not cell :
75- row = len (sheet .col_values (1 )) + 1
76- sheet .update_cell (row , 1 , mentee .name )
77- sheet .update_cell (row , task .task_no + 2 , commit_hash )
78- else :
79- row = cell .row
80- sheet .update_cell (row , task .task_no + 2 , commit_hash )
81-
82- db .add (submission )
83- db .commit ()
84- db .refresh (submission )
85-
86- return submission
83+ return "late submission not allowed"
8784
8885def approve_submission (db : Session , submission_id : int , mentor_feedback : str , status : str ):
8986 sub = db .query (models .Submission ).filter_by (id = submission_id ).first ()
@@ -103,6 +100,7 @@ def is_mentor_of(db: Session, mentor_id: int, mentee_id: int):
103100 return db .query (models .MentorMenteeMap ).filter_by (mentor_id = mentor_id , mentee_id = mentee_id ).first () is not None
104101
105102def get_leaderboard_data (db : Session , track_id : int ):
103+
106104 return (
107105 db .query (
108106 models .User .name ,
@@ -117,7 +115,6 @@ def get_leaderboard_data(db: Session, track_id: int):
117115 .order_by (func .sum (models .Task .points ).desc ())
118116 .all ()
119117 )
120-
121118def get_otp_by_email (db , email ):
122119 return db .query (models .OTP ).filter (models .OTP .email == email ).first ()
123120
@@ -131,6 +128,7 @@ def create_or_update_otp(db, email, otp, expires_at):
131128 db .add (entry )
132129 db .commit ()
133130
131+
134132def get_submissions_for_user (db : Session , email : str , track_id : Optional [int ] = None ) -> list [SubmissionOut ]:
135133 user = db .query (models .User ).filter (models .User .email == email ).first ()
136134 if not user :
@@ -152,7 +150,6 @@ def get_submissions_for_user(db: Session, email: str, track_id: Optional[int] =
152150 task_id = sub .task_id ,
153151 task_name = sub .task_name ,
154152 task_no = sub .task_no ,
155- reference_link = sub .reference_link ,
156153 status = sub .status ,
157154 submitted_at = sub .submitted_at .date () if sub .submitted_at else None ,
158155 approved_at = sub .approved_at .date () if sub .approved_at else None ,
@@ -163,12 +160,9 @@ def get_submissions_for_user(db: Session, email: str, track_id: Optional[int] =
163160 ]
164161
165162def get_sheet_data ():
166- client = _get_gspread_client ()
167- sheet_id = os .getenv ("GOOGLE_SHEET_ID" )
168- if not sheet_id :
169- raise ValueError ("GOOGLE_SHEET_ID environment variable not set." )
170-
171- worksheet = client .open_by_key (sheet_id ).worksheet ("Form Responses" )
163+ creds = ServiceAccountCredentials .from_json_keyfile_name (CREDS_FILE , SCOPE )
164+ client = gspread .authorize (creds )
165+ worksheet = client .open_by_key (os .getenv ("GOOGLE_SHEET_ID" )).worksheet ("Praveshan Phase 3" ) # Change sheet name
172166 expected_headers = ["Name" , "Email Address" ]
173167 data = worksheet .get_all_records (expected_headers = expected_headers )
174168 return data
@@ -177,6 +171,7 @@ def sync_users_from_sheet():
177171 db : Session = SessionLocal ()
178172 try :
179173 rows = get_sheet_data ()
174+ print (f"Loaded { len (rows )} rows from sheet." )
180175 inserted_count = 0
181176 for row in rows :
182177 email = row .get ("Email Address" , "" ).strip ()
@@ -190,5 +185,8 @@ def sync_users_from_sheet():
190185 inserted_count += 1
191186
192187 db .commit ()
188+ print (f"Inserted { inserted_count } new users." )
189+ except Exception as e :
190+ print (f"Error syncing users: { e } " )
193191 finally :
194192 db .close ()
0 commit comments