diff --git a/app/db/reports_db.py b/app/db/reports_db.py index e32069f..669860c 100644 --- a/app/db/reports_db.py +++ b/app/db/reports_db.py @@ -1,6 +1,6 @@ -from botocore.exceptions import ClientError -from boto3.resources.base import ServiceResource from boto3.dynamodb.conditions import Key +from boto3.resources.base import ServiceResource +from botocore.exceptions import ClientError class ReportsDB: @@ -33,6 +33,17 @@ def get_student_quiz_report(self, user_id, session_id): except ClientError as e: raise ValueError(e.response["Error"]["Message"]) + def get_student_quiz_report_v2(self, user_id, session_id): + try: + table = self.__db.Table("student_quiz_reports_v2") + response = table.query( + KeyConditionExpression=Key("session_id").eq(session_id) + & Key("user_id").eq(user_id) + ) + return response["Items"] + except ClientError as e: + raise ValueError(e.response["Error"]["Message"]) + def get_student_reports(self, user_id): """ Returns all student reports for a given user ID. diff --git a/app/db/sessions_db.py b/app/db/sessions_db.py index f67bd58..ee552fb 100644 --- a/app/db/sessions_db.py +++ b/app/db/sessions_db.py @@ -1,8 +1,9 @@ +import base64 +import json +import os + from dotenv import load_dotenv from google.cloud import firestore -import os -import json -import base64 from google.cloud.firestore_v1.base_query import FieldFilter diff --git a/app/routers/student_quiz_reports.py b/app/routers/student_quiz_reports.py index 21374da..3bf1d90 100644 --- a/app/routers/student_quiz_reports.py +++ b/app/routers/student_quiz_reports.py @@ -1,12 +1,12 @@ -from fastapi import APIRouter, Request -from fastapi.templating import Jinja2Templates -from fastapi import HTTPException, Depends from collections import OrderedDict +from typing import Optional, Union from urllib.parse import unquote -from typing import Union, Optional -from db.reports_db import ReportsDB + from auth import verify_token +from db.reports_db import ReportsDB +from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.security.api_key import APIKeyHeader +from fastapi.templating import Jinja2Templates ROW_NAMES = OrderedDict() ROW_NAMES = { @@ -220,4 +220,86 @@ def student_quiz_report(request: Request, session_id: str, user_id: str): {"request": request, "report_data": report_data}, ) + @api_router.get("/student_quiz_report/v2/{session_id}/{user_id}") + def student_quiz_report_v2(request: Request, session_id: str, user_id: str): + """ + Returns a student quiz report (V2) for a given session ID and user ID. + + Args: + request (Request): The request object. + session_id (str): The session ID. + user_id (str): The user ID. + + Raises: + HTTPException: If session ID or user ID is not specified. + + Returns: + TemplateResponse: The student quiz report template response. + """ + if session_id is None or user_id is None: + raise HTTPException( + status_code=400, + detail="Session ID and User ID have to be specified", + ) + # decoding URL encoded values. As this information is coming through a URL, + # it's possible that the strings are URL encoded. + session_id = unquote(session_id) + user_id = unquote(user_id) + try: + data = self.__reports_db.get_student_quiz_report_v2(user_id, session_id) + except KeyError: + raise HTTPException( + status_code=400, + detail="No student_quiz_report found. Unknown error occurred.", + ) + + if len(data) == 0: + # no data + error_data = { + "session_id": session_id, + "user_id": user_id, + "error_message": "No report found. Please contact admin.", + "status_code": 404, + } + return self._templates.TemplateResponse( + "error.html", {"request": request, "error_data": error_data} + ) + + return self._templates.TemplateResponse( + "student_quiz_report_v2.html", + {"request": request, "report_data": data[0]}, + ) + + # return data + # report_data = {} + # report_data["student_name"] = "" + # test_id = data[0]["test_id"] + # user_id = data[0]["user_id"] + + # report_data["student_id"] = user_id + # if "platform" in data[0] and data[0]["platform"] == "quizengine": + # report_data["test_link"] = QUIZ_URL.format( + # quiz_id=test_id, user_id=user_id, api_key=AF_API_KEY + # ) + + # section_reports = [] + # overall_performance = {} + # for section in data: + # parsed_section_data = _parse_section_data(section) + # if section["section"] == "overall": + # overall_performance = parsed_section_data + # report_data["percentage"] = parsed_section_data["table_data"][ + # "Percentage" + # ] + # report_data["test_name"] = section["test_name"] + # report_data["test_date"] = section["start_date"] + # else: + # section_reports.append(parsed_section_data) + # report_data["overall_performance"] = overall_performance + # report_data["section_reports"] = section_reports + # return self._templates.TemplateResponse( + # "student_quiz_report.html", + # {"request": request, "report_data": report_data}, + # ) + return api_router diff --git a/app/templates/student_quiz_report_v2.html b/app/templates/student_quiz_report_v2.html new file mode 100644 index 0000000..8c82957 --- /dev/null +++ b/app/templates/student_quiz_report_v2.html @@ -0,0 +1,80 @@ +{% extends "layout.html" %} +{% block title %}Index{% endblock %} + +{% block content %} + +
Name: {{report_data["name"]}} + {% endif %} +
Student ID: {{report_data["user_id"]}} +
+ {% for subject in score_details %} + | {{ 'Total' if subject == 'overall' else subject }} | + {% endfor %} +
---|---|
Score | + {% for subject in score_details %} +{{ score_details[subject]['marks_scored']|round(0, 'floor')|int }} | + {% endfor %} +
Attempt Rate | + {% for subject in score_details %} +{{ "%.2f%%"|format(score_details[subject]['attempt_rate']) }} | + {% endfor %} +
Accuracy | + {% for subject in score_details %} + {% set accuracy = score_details[subject]['accuracy']|float %} + {% set green = 255 * (accuracy / 100.0) %} + {% set red = 255 * (1 - accuracy / 100.0) %} + {% set color = "rgb({},{},0)".format(red|int, green|int) %} ++ {{ "%.2f%%"|format(accuracy) }} + | + + {% endfor %} +
Chapter | +Question No. | +Your Response | +
---|---|---|
{{ detail.chapter }} | +{{ detail.question_number }} | +{{ detail.response }} | +