Skip to content

Commit

Permalink
Merge branch 'main' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
Krrupa committed Jun 14, 2024
2 parents f69b5d8 + bb66b09 commit 545ef30
Show file tree
Hide file tree
Showing 11 changed files with 277 additions and 52 deletions.
154 changes: 154 additions & 0 deletions app/auth_group_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
from settings import settings
from fastapi import HTTPException
import random
from router import school, student, user, enrollment_record, grade
import datetime
from dateutil.relativedelta import relativedelta
from request import build_request
from logger_config import get_logger

logger = get_logger()

COUNTER_FOR_JNV_ID_GENERATION = 1000


class EnableStudents:
def __init__(self, data):
for param in [
"grade",
"date_of_birth",
"gender",
"school_name",
"category",
"first_name",
"region",
]:
if param not in data:
logger.error(f"{param} is required")
raise ValueError(f"{param} is required")

self.grade = data["grade"]
self.date_of_birth = data["date_of_birth"]
self.gender = data["gender"]
self.school_name = data["school_name"]
self.category = data["category"]
self.first_name = data["first_name"]
self.region = data["region"]
self.student_id = ""

self.student_id = self.check_if_student_exists()

if self.student_id == "":
counter = COUNTER_FOR_JNV_ID_GENERATION

while counter > 0:
id = (
self.get_class_code()
+ self.get_jnv_code()
+ self.generate_three_digit_code()
)

if self.check_if_generated_id_already_exists(id):
counter -= 1
else:
self.student_id = id
break

if counter == 0:
raise HTTPException(
status_code=400,
detail="JNV Student ID could not be generated. Max loops hit!",
)

def check_if_enrolled_in_school(self, school_id, user_id):
enrollment_record_already_exists = enrollment_record.get_enrollment_record(
build_request(
query_params={
"group_id": school_id,
"group_type": "school",
"user_id": user_id,
}
)
)
return enrollment_record_already_exists

def check_if_user_exists(self, user_id):
user_already_exists = user.get_users(
build_request(
query_params={
"id": user_id,
"date_of_birth": self.date_of_birth,
"gender": self.gender,
"first_name": self.first_name,
}
)
)

return user_already_exists

def check_if_student_exists(self):
grade_response = grade.get_grade(
build_request(query_params={"number": self.grade})
)
# First, we check if a student with the same grade and category already exists in the database
student_already_exists = student.get_students(
build_request(
query_params={
"grade_id": grade_response["id"],
"category": self.category,
}
)
)

if len(student_already_exists) > 0:
for existing_student in student_already_exists:
# If the student already exists, we check if a user with the same DOB, gender and first_name already exists
user_already_exists = self.check_if_user_exists(
existing_student["user"]["id"]
)

if len(user_already_exists) > 0:
# If the student already exists, we check if the student is already enrolled in the given school
school_response = school.get_school(
build_request(query_params={"name": self.school_name})
)
for existing_user in user_already_exists:
enrollment_record_already_exists = (
self.check_if_enrolled_in_school(
school_response["id"], existing_user["id"]
)
)
# At this point, if there is a duplicate student, there should be only one, hence we return the student_id
if len(enrollment_record_already_exists) > 0:
logger.error("Student already exists in the database")
return existing_student["student_id"]

return ""

def get_class_code(self):
graduating_year = datetime.date.today() + relativedelta(
years=12 - int(self.grade)
)
return str(graduating_year.year)[-2:]

def get_jnv_code(self):
school_response = school.get_school(
build_request(
query_params={"region": self.region, "name": self.school_name}
)
)
return school_response["code"]

def generate_three_digit_code(self, code=""):
for _ in range(3):
code += str(random.randint(0, 9))
return code

def get_student_id(self):
return self.student_id

def check_if_generated_id_already_exists(self, id):
student_response = student.get_students(
build_request(query_params={"student_id": id})
)
return len(student_response) != 0
5 changes: 5 additions & 0 deletions app/helpers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from fastapi import HTTPException
from logger_config import get_logger
from settings import settings

logger = get_logger()


def is_response_valid(response, error_message=""):
if response.status_code in [200, 201]:
return True
if error_message:
logger.error(error_message)
raise HTTPException(status_code=500, detail=error_message)
return False

Expand All @@ -15,6 +19,7 @@ def is_response_empty(response_data, return_boolean, error_message=""):
return response_data
if return_boolean:
if error_message:
logger.error(error_message)
raise HTTPException(status_code=404, detail=error_message)
return False
return []
Expand Down
35 changes: 35 additions & 0 deletions app/logger_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import logging
from datetime import datetime, timedelta, timezone

IST = timezone(timedelta(hours=5, minutes=30))


class ISTFormatter(logging.Formatter):
@staticmethod
def _converter(*args):
return datetime.now(tz=IST).timetuple()

converter = _converter


def setup_logger():
logger = logging.getLogger("portalbackendlogger")

# https://stackoverflow.com/questions/50909824/getting-logs-twice-in-aws-lambda-function
logger.propagate = False

logger_format = "%(asctime)s IST loglevel=%(levelname)-6s filename=%(filename)s funcName=%(funcName)s() L%(lineno)-4d %(message)s call_trace=%(pathname)s L%(lineno)-4d"

formatter = ISTFormatter(fmt=logger_format, datefmt="%Y-%m-%d %H:%M:%S")

consoleHandler = logging.StreamHandler()
consoleHandler.setLevel(logging.DEBUG)
consoleHandler.setFormatter(formatter)
logger.addHandler(consoleHandler)
logger.setLevel(logging.DEBUG)

return logger


def get_logger():
return logging.getLogger("portalbackendlogger")
31 changes: 31 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,40 @@
from fastapi_jwt_auth.exceptions import AuthJWTException
from mangum import Mangum
import settings
import random
import string
import time
from logger_config import setup_logger

logger = setup_logger()

app = FastAPI()


@app.middleware("http")
async def log_requests(request: Request, call_next):
"""
Intercepts all http requests and logs their details like
path, method, headers, time taken by request etc.
Each request is assigned a random id (rid) which is used
to track the request in logs.
"""
# random id for request so that we can track it in logs
idem = "".join(random.choices(string.ascii_uppercase + string.digits, k=6))
logger.info(
f"rid={idem} start request path={request.url.path} method={request.method} headers={request.headers}"
)
start_time = time.time()
response = await call_next(request)
process_time = (time.time() - start_time) * 1000
formatted_process_time = "{0:.2f}".format(process_time)
logger.info(
f"rid={idem} completed_in={formatted_process_time}ms status_code={response.status_code}"
)

return response


origins = [
"http://localhost:8080",
"http://localhost:3000",
Expand Down
3 changes: 1 addition & 2 deletions app/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

GROUP_USER_QUERY_PARAMS = ["id", "group_id", "user_id"]

SCHOOL_QUERY_PARAMS = ["id", "name", "school_name", "code", "board_medium"]
SCHOOL_QUERY_PARAMS = ["id", "name", "school_name", "code", "board_medium", "region"]

SESSION_QUERY_PARAMS = ["id", "name", "session_id"]

Expand Down Expand Up @@ -93,5 +93,4 @@
"role",
"date_of_birth",
"country",
"consent_check",
]
4 changes: 2 additions & 2 deletions app/router/enrollment_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def get_enrollment_record(request: Request):

if is_response_valid(response, "Enrollment API could not fetch the data!"):
return is_response_empty(
response.json(), True, "Enrollment record does not exist!"
response.json(), False, "Enrollment record does not exist!"
)


Expand All @@ -36,5 +36,5 @@ async def create_enrollment_record(request: Request):
)
if is_response_valid(response, "Enrollment API could not post the data!"):
return is_response_empty(
response.json(), "Enrollment API could not fetch the created record!"
response.json(), False, "Enrollment API could not fetch the created record!"
)
2 changes: 1 addition & 1 deletion app/router/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def get_form_schema(request: Request):
form_db_url, params=query_params, headers=db_request_token()
)
if is_response_valid(response, "Form API could not fetch the data!"):
return is_response_empty(response.json()[0], "True", "Form does not exist!")
return is_response_empty(response.json()[0], True, "Form does not exist!")


@router.get("/student")
Expand Down
5 changes: 4 additions & 1 deletion app/router/session_occurrence.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
from models import SessionResponse
import pytz
from helpers import db_request_token
from logger_config import get_logger

IST = pytz.timezone("Asia/Kolkata")
router = APIRouter(prefix="/session-occurrence", tags=["Session Occurrence"])
session_db_url = settings.db_url + "/session/"
session_occurrence_db_url = settings.db_url + "/session-occurrence/"
logger = get_logger()


def build_date_and_time(date_time: str):
Expand Down Expand Up @@ -83,7 +85,6 @@ async def get_session_occurrence_data(request: Request):
"headers": null
}
"""

query_params = {}
for key in request.query_params.keys():
if key not in ["name", "session_id"]:
Expand All @@ -92,6 +93,8 @@ async def get_session_occurrence_data(request: Request):
)
query_params[key] = request.query_params[key]

logger.info("Searching for session {} ...".format(query_params["session_id"]))

response = requests.get(
session_occurrence_db_url, params=query_params, headers=db_request_token()
)
Expand Down
Loading

0 comments on commit 545ef30

Please sign in to comment.