Skip to content

Commit c436799

Browse files
committed
load Google Sheets credentials from GOOGLE_CREDENTIALS_JSON env var
1 parent d2e2f7c commit c436799

File tree

1 file changed

+75
-89
lines changed

1 file changed

+75
-89
lines changed

app/db/crud.py

Lines changed: 75 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,37 @@
1-
from typing import Optional
2-
from app.schemas.submission import SubmissionOut
3-
from sqlalchemy.orm import Session,joinedload
4-
from app.db import models
1+
from typing import Optional, List
52
from datetime import date, timedelta
6-
from sqlalchemy import func
7-
from app.db.db import SessionLocal
3+
import os, json
4+
85
import gspread
6+
from gspread.exceptions import CellNotFound
97
from oauth2client.service_account import ServiceAccountCredentials
10-
import os
8+
from sqlalchemy.orm import Session
9+
from sqlalchemy import func
10+
11+
from app.schemas.submission import SubmissionOut
12+
from app.db import models
13+
from app.db.db import SessionLocal
1114

12-
SCOPE = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
13-
CREDS_FILE = "credentials.json"
15+
SCOPE = [
16+
"https://www.googleapis.com/auth/spreadsheets",
17+
"https://www.googleapis.com/auth/drive",
18+
]
19+
20+
def _gspread_client():
21+
raw = os.getenv("GOOGLE_CREDENTIALS_JSON")
22+
if not raw:
23+
raise RuntimeError("Missing GOOGLE_CREDENTIALS_JSON in environment")
24+
raw = raw.strip().strip("'").strip('"')
25+
creds_dict = json.loads(raw)
26+
credentials = ServiceAccountCredentials.from_json_keyfile_dict(creds_dict, scopes=SCOPE)
27+
return gspread.authorize(credentials)
28+
29+
def _to_date(d):
30+
if d is None:
31+
return None
32+
if isinstance(d, date):
33+
return d
34+
return getattr(d, "date", lambda: None)()
1435

1536
def get_user_by_email(db: Session, email: str):
1637
return db.query(models.User).filter(models.User.email == email).first()
@@ -21,91 +42,66 @@ def get_task(db: Session, track_id: int, task_no: int):
2142
def submit_task(db: Session, mentee_id: int, task_id: int, start_date: date, commit_hash: str):
2243
existing = db.query(models.Submission).filter_by(mentee_id=mentee_id, task_id=task_id).first()
2344
if existing:
24-
return None # Already submitted
25-
45+
return None
2646
mentee = db.query(models.User).filter(models.User.id == mentee_id).first()
27-
2847
task = db.query(models.Task).filter(models.Task.id == task_id).first()
2948
if not task:
3049
raise Exception("Task not found")
31-
32-
# convert start_date into a datetime object
33-
start_date = start_date
34-
deadline = start_date + timedelta(days=task.deadline_days)
3550
submitted_at = date.today()
36-
37-
# Check if the submission is late
38-
if deadline >= submitted_at:
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
51+
deadline = start_date + timedelta(days=task.deadline_days or 0) if task.deadline_days else None
52+
if deadline and submitted_at > deadline:
53+
return "late submission not allowed"
54+
submission = models.Submission(
55+
mentee_id=mentee_id,
56+
task_id=task.id,
57+
task_name=task.title,
58+
task_no=task.task_no,
59+
submitted_at=submitted_at,
60+
status="submitted",
61+
start_date=start_date,
62+
commit_hash=commit_hash,
63+
)
64+
client = _gspread_client()
65+
if task.track_id in (1, 2):
66+
sheet = client.open("Copy of Praveshan 2025 Master DB").worksheet(
67+
"S1 Submissions" if task.track_id == 1 else "S2 Submissions"
4868
)
49-
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")
69+
try:
6570
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
82-
else:
83-
return "late submission not allowed"
71+
row = cell.row
72+
except CellNotFound:
73+
name_column = sheet.col_values(1)
74+
row = len(name_column) + 1 if name_column else 1
75+
sheet.update_cell(row, 1, mentee.name)
76+
sheet.update_cell(row, task.task_no + 2, commit_hash)
77+
db.add(submission)
78+
db.commit()
79+
db.refresh(submission)
80+
return submission
8481

8582
def approve_submission(db: Session, submission_id: int, mentor_feedback: str, status: str):
8683
sub = db.query(models.Submission).filter_by(id=submission_id).first()
8784
if not sub:
8885
return None
89-
9086
sub.status = status
9187
sub.mentor_feedback = mentor_feedback
9288
if status == "approved":
9389
sub.approved_at = date.today()
94-
9590
db.commit()
9691
db.refresh(sub)
9792
return sub
9893

9994
def is_mentor_of(db: Session, mentor_id: int, mentee_id: int):
100-
return db.query(models.MentorMenteeMap).filter_by(mentor_id=mentor_id, mentee_id=mentee_id).first() is not None
95+
return db.query(models.MentorMenteeMap).filter_by(
96+
mentor_id=mentor_id, mentee_id=mentee_id
97+
).first() is not None
10198

10299
def get_leaderboard_data(db: Session, track_id: int):
103-
104100
return (
105101
db.query(
106102
models.User.name,
107103
func.sum(models.Task.points).label("total_points"),
108-
func.count(models.Submission.id).label("tasks_completed")
104+
func.count(models.Submission.id).label("tasks_completed"),
109105
)
110106
.join(models.Submission, models.Submission.mentee_id == models.User.id)
111107
.join(models.Task, models.Submission.task_id == models.Task.id)
@@ -115,6 +111,7 @@ def get_leaderboard_data(db: Session, track_id: int):
115111
.order_by(func.sum(models.Task.points).desc())
116112
.all()
117113
)
114+
118115
def get_otp_by_email(db, email):
119116
return db.query(models.OTP).filter(models.OTP.email == email).first()
120117

@@ -128,21 +125,14 @@ def create_or_update_otp(db, email, otp, expires_at):
128125
db.add(entry)
129126
db.commit()
130127

131-
132-
def get_submissions_for_user(db: Session, email: str, track_id: Optional[int] = None) -> list[SubmissionOut]:
128+
def get_submissions_for_user(db: Session, email: str, track_id: Optional[int] = None) -> List[SubmissionOut]:
133129
user = db.query(models.User).filter(models.User.email == email).first()
134130
if not user:
135131
return []
136-
137-
query = db.query(models.Submission).filter(
138-
models.Submission.mentee_id == user.id
139-
)
140-
132+
query = db.query(models.Submission).filter(models.Submission.mentee_id == user.id)
141133
if track_id is not None:
142134
query = query.join(models.Task).filter(models.Task.track_id == track_id)
143-
144135
submissions = query.all()
145-
146136
return [
147137
SubmissionOut(
148138
id=sub.id,
@@ -151,39 +141,35 @@ def get_submissions_for_user(db: Session, email: str, track_id: Optional[int] =
151141
task_name=sub.task_name,
152142
task_no=sub.task_no,
153143
status=sub.status,
154-
submitted_at=sub.submitted_at.date() if sub.submitted_at else None,
155-
approved_at=sub.approved_at.date() if sub.approved_at else None,
144+
submitted_at=_to_date(sub.submitted_at),
145+
approved_at=_to_date(sub.approved_at),
156146
mentor_feedback=sub.mentor_feedback,
157-
start_date=sub.start_date.date() if sub.start_date else None
147+
start_date=_to_date(sub.start_date),
158148
)
159149
for sub in submissions
160150
]
161-
151+
162152
def get_sheet_data():
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
153+
client = _gspread_client()
154+
worksheet = client.open_by_key(os.getenv("GOOGLE_SHEET_ID")).worksheet("Praveshan Phase 3")
166155
expected_headers = ["Name", "Email Address"]
167-
data = worksheet.get_all_records(expected_headers=expected_headers)
168-
return data
156+
return worksheet.get_all_records(expected_headers=expected_headers)
169157

170158
def sync_users_from_sheet():
171159
db: Session = SessionLocal()
172160
try:
173-
rows = get_sheet_data()
174-
print(f"Loaded {len(rows)} rows from sheet.")
161+
rows = get_sheet_data()
175162
inserted_count = 0
176163
for row in rows:
177164
email = row.get("Email Address", "").strip()
178165
name = row.get("Name", "").strip()
179166
if not email or not name:
180167
continue
181168
if get_user_by_email(db, email):
182-
continue
169+
continue
183170
user = models.User(name=name, email=email, role="mentee")
184171
db.add(user)
185172
inserted_count += 1
186-
187173
db.commit()
188174
print(f"Inserted {inserted_count} new users.")
189175
except Exception as e:

0 commit comments

Comments
 (0)