Skip to content

Commit

Permalink
Assignments (#12)
Browse files Browse the repository at this point in the history
* assignments now viewable

* assignments now viewable
  • Loading branch information
chrissdelaney authored Feb 12, 2024
1 parent 58d7212 commit 8342237
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 17 deletions.
82 changes: 66 additions & 16 deletions app/spreadsheet_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@
import gspread
from gspread.exceptions import SpreadsheetNotFound

import time


load_dotenv()

DEFAULT_FILEPATH = os.path.join(os.path.dirname(__file__), "..", "gradebook-hero-google-credentials.json")
GOOGLE_CREDENTIALS_FILEPATH = os.getenv("GOOGLE_CREDENTIALS_FILEPATH", default=DEFAULT_FILEPATH)

GOOGLE_SHEETS_DOCUMENT_ID = os.getenv("GOOGLE_SHEETS_DOCUMENT_ID", default="OOPS Please get the spreadsheet identifier from its URL, and set the 'GOOGLE_SHEETS_DOCUMENT_ID' environment variable accordingly...")
GOOGLE_SHEETS_MASTER_DOCUMENT_ID = os.getenv("GOOGLE_SHEETS_MASTER_DOCUMENT_ID", default="OOPS Please get the spreadsheet identifier from its URL, and set the 'GOOGLE_SHEETS_DOCUMENT_ID' environment variable accordingly...")


class SpreadsheetService:

def __init__(self, credentials_filepath=GOOGLE_CREDENTIALS_FILEPATH, document_id=GOOGLE_SHEETS_DOCUMENT_ID):
def __init__(self, credentials_filepath=GOOGLE_CREDENTIALS_FILEPATH, document_id=GOOGLE_SHEETS_MASTER_DOCUMENT_ID):
print("INITIALIZING NEW SPREADSHEET SERVICE...")
self.client = gspread.service_account(filename=credentials_filepath)
self.document_id = document_id
Expand All @@ -43,32 +45,80 @@ def parse_timestamp(ts:str):
date_format = "%Y-%m-%d %H:%M:%S.%f%z"
return datetime.strptime(ts, date_format)

@staticmethod
def to_pct(frac):
return f'{float(frac)*100:.2f}%'

@property
def doc(self):
"""note: this will make an API call each time, to get the new data"""
return self.client.open_by_key(self.document_id) #> <class 'gspread.models.Spreadsheet'>

def set_active_document(self, document_id):
self.document_id = document_id

def get_sheet(self, sheet_name):
return self.doc.worksheet(sheet_name)

def get_final_grade(self, username):
"""
Gets all records from a sheet,
"""
#print(f"GETTING RECORDS FROM SHEET: '{sheet_name}'")
sheet = self.get_sheet("gradebook-final") #> <class 'gspread.models.Worksheet'>
row_index = sheet.col_values(1).index(f'#{username}') + 1
return sheet.row_values(row_index)

def get_assignment_grade(self, username, assignment_name):
sheet = self.get_sheet(f"{assignment_name}-mjr") #> <class 'gspread.models.Worksheet'>
row_index = sheet.col_values(3).index(username) + 1
return sheet.row_values(row_index)
#####################
# COURSES FUNCTIONS #
#####################

def get_student_courses(self, email:str) -> list:
self.set_active_document(GOOGLE_SHEETS_MASTER_DOCUMENT_ID)
students_sheet = self.get_sheet("students_roster")
all_student_course_ids = students_sheet.get_all_records()
student_course_ids = [course["COURSE_ID"] for course in all_student_course_ids if course["STUDENT_EMAIL"] == email]

courses_sheet = self.get_sheet("courses")
all_courses = courses_sheet.get_all_records()

student_courses_info = [course_info for course_info in all_courses if course_info["COURSE_ID"] in student_course_ids]

return student_courses_info


def get_course_assignments(self, student_email:str, course_id:str) -> list:
#if coming from "courses" page, the active document will be "MASTER"
#we want to change that to the document ID of the specific course
if self.doc.id == GOOGLE_SHEETS_MASTER_DOCUMENT_ID:
courses_sheet = self.get_sheet("courses")
courses_records = courses_sheet.get_all_records()

course_document_id_list = [c["SHEETS_DOCUMENT_ID"] for c in courses_records if c["COURSE_ID"] == int(course_id)]

if len(course_document_id_list) == 0:
raise Exception("course not found...")
#TODO: handle within the route
if len(course_document_id_list) > 1:
raise Exception("course duplicate found...error")
#TODO: handle within the route

self.set_active_document(course_document_id_list[0])

# now, get the assignments from the sheet
assignments_sheet = self.get_sheet("ASSIGNMENT_MASTER")
assignments_records = assignments_sheet.get_all_records()


#assign the student email to the sheet that calculates scores...
scores_sheet = self.get_sheet("STUDENT_SCORES")
scores_sheet.update_acell("K2", student_email)

#find the assignment scores...
for i in range(len(assignments_records)):
del assignments_records[i]["SHEET_NAME"]
assignments_records[i]["GRADE"] = self.to_pct(scores_sheet.cell(i + 2, 9).value)

#clear the email
scores_sheet.update_acell("K2", "")

return assignments_records



if __name__ == "__main__":

ss = SpreadsheetService()

ss.get_assignment_grade("mb6244", "stocks")
ss.get_course_assignments("[email protected]", "12345")
2 changes: 2 additions & 0 deletions web_app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from web_app.routes.home_routes import home_routes
from web_app.routes.auth_routes import auth_routes
from web_app.routes.user_routes import user_routes
from web_app.routes.courses_routes import courses_routes

load_dotenv()

Expand Down Expand Up @@ -95,6 +96,7 @@ def create_app(spreadsheet_service=None):
app.register_blueprint(home_routes)
app.register_blueprint(auth_routes)
app.register_blueprint(user_routes)
app.register_blueprint(courses_routes)

return app

Expand Down
15 changes: 15 additions & 0 deletions web_app/routes/courses_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from flask import Blueprint, render_template, flash, redirect, current_app, url_for, session, request #, jsonify

courses_routes = Blueprint("courses_routes", __name__)

from web_app.routes.wrappers import student_authenticated_route

@courses_routes.route("/courses/<course_id>")
@student_authenticated_route
def course(course_id):
ss = current_app.config["SPREADSHEET_SERVICE"]
current_user = session.get("current_user")
email = current_user["email"]
#TODO: change hard coded email to "email" fetched from session
assignments_list = ss.get_course_assignments("[email protected]", course_id)
return render_template("assignments.html", assignments=assignments_list)
3 changes: 3 additions & 0 deletions web_app/routes/home_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
def index():
return render_template("home.html")

<<<<<<< Updated upstream
@home_routes.route("/about")
def about():
return render_template("about.html")
Expand All @@ -16,3 +17,5 @@ def products():
service = current_app.config["SPREADSHEET_SERVICE"]
products = service.get_products()
return render_template("products.html", products=products)
=======
>>>>>>> Stashed changes
2 changes: 1 addition & 1 deletion web_app/routes/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import functools
from flask import session, redirect, flash

def authenticated_route(view):
def student_authenticated_route(view):
"""
Wrap a route with this decorator to prevent unauthenticated access.
Expand Down
37 changes: 37 additions & 0 deletions web_app/templates/assignments.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% extends "bootstrap_5_layout.html" %}
{% set active_page = "courses" %}

{% block content %}

<h1>My Assignments</h1>

<table class="table table-hover text-center">
<thead>
<tr>
<th scope="col">Assignment</th>
<th scope="col">Due Date</th>
<th scope="col">Points</th>
<th scope="col">Grade</th>
</tr>
<tbody>
{% for a in assignments %}
<tr>
<td>
{{ a.NAME }}
</td>
<td>
{{ a.DUE_DATE }}
</td>
<td>
{{ a.POINTS }}
</td>
<td>
{{ a.GRADE }}
</td>
</tr>
{% endfor %}
</tbody>
</thead>
</table>

{% endblock %}

0 comments on commit 8342237

Please sign in to comment.