From 76cac98666c9ceee7c565521c66318c4c7cf68e9 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 1 Aug 2023 14:35:46 +0530 Subject: [PATCH 01/18] added logging --- app/helpers.py | 5 +++++ app/logger_config.py | 35 +++++++++++++++++++++++++++++++++++ app/main.py | 29 +++++++++++++++++++++++++++++ app/router/student.py | 5 ++++- 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 app/logger_config.py diff --git a/app/helpers.py b/app/helpers.py index 0a773aa..ca5da64 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -1,5 +1,7 @@ from fastapi import HTTPException +from logger_config import get_logger +logger = get_logger() def is_response_valid(response, error_message=""): if response.status_code == 200: @@ -7,6 +9,7 @@ def is_response_valid(response, error_message=""): elif response.status_code == 201: return True if error_message: + logger.error(error_message) raise HTTPException(status_code=500, detail=error_message) return False @@ -16,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) else: return False @@ -26,6 +30,7 @@ def validate_and_build_query_params(data, valid_query_params): query_params = {} for key in data.keys(): if key not in valid_query_params: + logger.error("Query Parameter {key} is not allowed!") raise HTTPException( status_code=400, detail="Query Parameter {} is not allowed!".format(key) ) diff --git a/app/logger_config.py b/app/logger_config.py new file mode 100644 index 0000000..5dc3af2 --- /dev/null +++ b/app/logger_config.py @@ -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") \ No newline at end of file diff --git a/app/main.py b/app/main.py index c9d15ad..12c35f3 100644 --- a/app/main.py +++ b/app/main.py @@ -18,9 +18,38 @@ 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", "https://staging-auth.avantifellows.org", diff --git a/app/router/student.py b/app/router/student.py index 7d6c094..480933f 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -6,9 +6,10 @@ from router import routes, school, enrollment_record, user from id_generation import JNVIDGeneration from request import build_request +from logger_config import get_logger router = APIRouter(prefix="/student", tags=["Student"]) - +logger = get_logger() def build_enrollment_data(data): enrollment_data = {} @@ -133,6 +134,8 @@ async def verify_student(request: Request, student_id: str): request.query_params, mapping.STUDENT_QUERY_PARAMS + mapping.USER_QUERY_PARAMS ) + logger.info(f"Verifying student: {student_id}") + response = requests.get(routes.student_db_url, params={"student_id": student_id}) if helpers.is_response_valid(response): data = helpers.is_response_empty(response.json(), False) From b9fc9310bcb85375441074cc93265c7ee03bc423 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 1 Aug 2023 14:35:58 +0530 Subject: [PATCH 02/18] added logging --- app/helpers.py | 1 + app/logger_config.py | 2 +- app/main.py | 2 ++ app/router/student.py | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/helpers.py b/app/helpers.py index ca5da64..0a6ee4c 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -3,6 +3,7 @@ logger = get_logger() + def is_response_valid(response, error_message=""): if response.status_code == 200: return True diff --git a/app/logger_config.py b/app/logger_config.py index 5dc3af2..98fdbec 100644 --- a/app/logger_config.py +++ b/app/logger_config.py @@ -32,4 +32,4 @@ def setup_logger(): def get_logger(): - return logging.getLogger("portalbackendlogger") \ No newline at end of file + return logging.getLogger("portalbackendlogger") diff --git a/app/main.py b/app/main.py index 12c35f3..f12967c 100644 --- a/app/main.py +++ b/app/main.py @@ -27,6 +27,7 @@ app = FastAPI() + @app.middleware("http") async def log_requests(request: Request, call_next): """ @@ -50,6 +51,7 @@ async def log_requests(request: Request, call_next): return response + origins = [ "http://localhost:8080", "https://staging-auth.avantifellows.org", diff --git a/app/router/student.py b/app/router/student.py index 480933f..92ba4f2 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -11,6 +11,7 @@ router = APIRouter(prefix="/student", tags=["Student"]) logger = get_logger() + def build_enrollment_data(data): enrollment_data = {} for key in data.keys(): From 5948e2c7d9119b9b30d8aa3bd1ff2dcbc7c2373d Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 28 Nov 2023 11:38:29 +0530 Subject: [PATCH 03/18] pre-commit --- .env.example | 1 - app/helpers.py | 1 + app/router/form.py | 10 +++++----- docs/ENV.md | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 0dba97d..39e913d 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,3 @@ JWT_SECRET_KEY="" DB_SERVICE_URL="" DB_SERVICE_TOKEN="" - diff --git a/app/helpers.py b/app/helpers.py index 25c4d9e..85c8716 100644 --- a/app/helpers.py +++ b/app/helpers.py @@ -4,6 +4,7 @@ logger = get_logger() + def is_response_valid(response, error_message=""): if response.status_code == 200: return True diff --git a/app/router/form.py b/app/router/form.py index c67bd59..9393edd 100644 --- a/app/router/form.py +++ b/app/router/form.py @@ -184,14 +184,14 @@ async def get_student_fields(request: Request): in mapping.ENROLLMENT_RECORD_PARAMS and form_attributes[str(priority)]["key"] != "student_id" ): - + if form_attributes[str(priority)]["key"] != "school_name": - if ( - enrollment_record_data == [] - or (enrollment_record_data != [] and enrollment_record_data[ + if enrollment_record_data == [] or ( + enrollment_record_data != [] + and enrollment_record_data[ form_attributes[str(priority)]["key"] ] - is None) + is None ): ( returned_form_schema, diff --git a/docs/ENV.md b/docs/ENV.md index 9556c67..85eeaa4 100644 --- a/docs/ENV.md +++ b/docs/ENV.md @@ -10,4 +10,4 @@ The URL to connect to our database service ### `DB_SERVICE_TOKEN` -Token to authenticate DB service \ No newline at end of file +Token to authenticate DB service From edb21691c5e7e3ea3d86252eab4cd31df002712b Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 28 Nov 2023 13:04:46 +0530 Subject: [PATCH 04/18] precommit fail fix --- .github/workflows/CI.yml | 6 +++--- .pre-commit-config.yaml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index da0fd81..01350c3 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -10,6 +10,6 @@ jobs: name: Pre-commit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - - uses: pre-commit/action@v2.0.3 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - uses: pre-commit/action@v3.0.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2f1850d..a58dddd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -15,11 +15,11 @@ repos: - id: cfn-python-lint files: templates/.*\.(json|yml|yaml)$ - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 23.10.1 hooks: - id: black - repo: https://github.com/pycqa/flake8 - rev: "3.9.0" + rev: "6.1.0" hooks: - id: flake8 args: From a9d2429710337e574c3069e2711e39161b450fda Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 28 Nov 2023 13:05:26 +0530 Subject: [PATCH 05/18] precommit fail fix --- app/router/form.py | 6 ------ app/router/school.py | 1 - app/router/session_occurrence.py | 3 --- app/router/student.py | 2 -- 4 files changed, 12 deletions(-) diff --git a/app/router/form.py b/app/router/form.py index 9393edd..a80c5fb 100644 --- a/app/router/form.py +++ b/app/router/form.py @@ -137,7 +137,6 @@ async def get_student_fields(request: Request): ) if student_data: - student_data = student_data[0] # get enrollment data for the student @@ -159,15 +158,12 @@ async def get_student_fields(request: Request): returned_form_schema = {} for priority in priority_order: - if number_of_fields_left > 0: - if is_user_attribute_empty( form_attributes, priority, student_data ) or is_student_attribute_empty( form_attributes, priority, student_data ): - ( returned_form_schema, number_of_fields_left, @@ -184,7 +180,6 @@ async def get_student_fields(request: Request): in mapping.ENROLLMENT_RECORD_PARAMS and form_attributes[str(priority)]["key"] != "student_id" ): - if form_attributes[str(priority)]["key"] != "school_name": if enrollment_record_data == [] or ( enrollment_record_data != [] @@ -207,7 +202,6 @@ async def get_student_fields(request: Request): if enrollment_record_data == []: if student_data["user"]["state"]: if student_data["user"]["district"]: - ( returned_form_schema, number_of_fields_left, diff --git a/app/router/school.py b/app/router/school.py index 240b63a..681acc3 100644 --- a/app/router/school.py +++ b/app/router/school.py @@ -18,7 +18,6 @@ def get_school(request: Request): ) if helpers.is_response_valid(response, "School API could not fetch the data!"): - return helpers.is_response_empty( response.json(), False, "School does not exist" ) diff --git a/app/router/session_occurrence.py b/app/router/session_occurrence.py index 48a127b..fcaf1b1 100644 --- a/app/router/session_occurrence.py +++ b/app/router/session_occurrence.py @@ -37,7 +37,6 @@ def has_session_started(start_time: str): - Otherwise, returns False """ if start_time is not None: - session_start_date, session_start_time = build_date_and_time(start_time) current_date, current_time = get_current_datetime() @@ -99,7 +98,6 @@ async def get_session_occurrence_data(request: Request): if response.status_code == 200: if len(response.json()) != 0: - session_occurrence_data = response.json() matched_session_occurrences = [ session_occurrence @@ -109,7 +107,6 @@ async def get_session_occurrence_data(request: Request): ] if len(matched_session_occurrences) > 0: - response = requests.get( session_db_url, params=query_params, headers=db_request_token() ) diff --git a/app/router/student.py b/app/router/student.py index ab81a9d..484265b 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -152,9 +152,7 @@ async def verify_student(request: Request, student_id: str): if data: data = data[0] if len(query_params) != 0: - for key in query_params.keys(): - if key in mapping.USER_QUERY_PARAMS: if data["user"][key] != "": if data["user"][key] != query_params[key]: From 8e14c2c8a13524a0b1b0f9ef18de1a961e326347 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 28 Nov 2023 17:12:23 +0530 Subject: [PATCH 06/18] logging check --- app/router/session.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/router/session.py b/app/router/session.py index 7d713a6..e4cc648 100644 --- a/app/router/session.py +++ b/app/router/session.py @@ -3,10 +3,11 @@ from settings import settings from models import SessionResponse from helpers import db_request_token +from logger_config import get_logger router = APIRouter(prefix="/session", tags=["Session"]) session_db_url = settings.db_url + "/session/" - +logger = get_logger() @router.get("/", response_model=SessionResponse) async def get_session_data(request: Request): @@ -38,6 +39,12 @@ async def get_session_data(request: Request): ) query_params[key] = request.query_params[key] + + if "session_id" in query_params: + logger.info("Searching for session {} ...".format(query_params["session_id"])) + else: + logger.info("Searching for session {} ...".format(query_params["name"])) + response = requests.get( session_db_url, params=query_params, headers=db_request_token() ) From abe5a89a5d53f580dfbf1ea037ebfed8f4f5f5bb Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Tue, 28 Nov 2023 17:12:36 +0530 Subject: [PATCH 07/18] logging check --- app/router/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/router/session.py b/app/router/session.py index e4cc648..7cdae64 100644 --- a/app/router/session.py +++ b/app/router/session.py @@ -9,6 +9,7 @@ session_db_url = settings.db_url + "/session/" logger = get_logger() + @router.get("/", response_model=SessionResponse) async def get_session_data(request: Request): """ @@ -39,7 +40,6 @@ async def get_session_data(request: Request): ) query_params[key] = request.query_params[key] - if "session_id" in query_params: logger.info("Searching for session {} ...".format(query_params["session_id"])) else: From 85ae1fac4ba4717b7271e4056466702d9958a5a9 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 29 Nov 2023 13:49:14 +0530 Subject: [PATCH 08/18] session occurrence --- app/router/session_occurrence.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/router/session_occurrence.py b/app/router/session_occurrence.py index fcaf1b1..de830c9 100644 --- a/app/router/session_occurrence.py +++ b/app/router/session_occurrence.py @@ -5,12 +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): """ @@ -83,7 +84,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"]: @@ -92,6 +92,9 @@ 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() ) From b3423ab09610e591a1f481456cf55f1932a1dd17 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 29 Nov 2023 13:49:26 +0530 Subject: [PATCH 09/18] session occurrence --- app/router/session_occurrence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/router/session_occurrence.py b/app/router/session_occurrence.py index de830c9..f28b321 100644 --- a/app/router/session_occurrence.py +++ b/app/router/session_occurrence.py @@ -13,6 +13,7 @@ session_occurrence_db_url = settings.db_url + "/session-occurrence/" logger = get_logger() + def build_date_and_time(date_time: str): """ Parses string into date and time strings @@ -92,7 +93,6 @@ 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( From 8d18a58bf1682e4a60038a1b7a5e671792835056 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 12 Jun 2024 19:24:06 +0530 Subject: [PATCH 10/18] jnv id generation --- app/auth_group_classes.py | 104 ++++++++++++++++++++++++++++++++ app/mapping.py | 3 +- app/router/enrollment_record.py | 2 +- app/router/form.py | 2 +- app/router/student.py | 67 ++++++++++---------- app/router/user.py | 5 +- 6 files changed, 143 insertions(+), 40 deletions(-) create mode 100644 app/auth_group_classes.py diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py new file mode 100644 index 0000000..e0529ee --- /dev/null +++ b/app/auth_group_classes.py @@ -0,0 +1,104 @@ +from settings import settings +import random +from router import school, student, user, enrollment_record +import datetime +from dateutil.relativedelta import relativedelta +from request import build_request +from logger_config import get_logger + +logger = get_logger() + +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_user_exists() + + if self.student_id != "": + return self.student_id + + self.student_id = ( + self.get_class_code() + + self.get_jnv_code() + + self.generate_three_digit_code() + ) + + def check_if_user_exists(self,): + # First, we check if a user with the same DOB, gender and first_name already exists in the database + user_already_exists = user.get_users( + build_request( + query_params={ + "date_of_birth": self.date_of_birth, + "gender": self.gender, + "first_name": self. first_name, + } + ) + ) + + if len(user_already_exists) > 0: + # If the user already exists, we check if a student with the same grade, category already exists + student_already_exists = student.get_students( + build_request( + query_params={ + "grade": self.grade, + "category": self.category, + } + ) + ) + if len(student_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} + ) + ) + + if len(school_response) > 0: + # At this point, if there is a duplicate student, there should be only one, hence we return the student_id + student = student_already_exists[0] + enrollment_record_already_exists = enrollment_record.get_enrollment_records( + build_request( + query_params={"group_id": school_response[0].id, "group_type":"school", "user_id":student["user"]["id"]} + ) + ) + + if len(enrollment_record_already_exists) > 0: + logger.error("Student already exists in the database") + return 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 \ No newline at end of file diff --git a/app/mapping.py b/app/mapping.py index 833142b..4d57445 100644 --- a/app/mapping.py +++ b/app/mapping.py @@ -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"] @@ -93,5 +93,4 @@ "role", "date_of_birth", "country", - "consent_check", ] diff --git a/app/router/enrollment_record.py b/app/router/enrollment_record.py index c86bf53..e0537af 100644 --- a/app/router/enrollment_record.py +++ b/app/router/enrollment_record.py @@ -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!" ) diff --git a/app/router/form.py b/app/router/form.py index 9441e2d..585b096 100644 --- a/app/router/form.py +++ b/app/router/form.py @@ -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") diff --git a/app/router/student.py b/app/router/student.py index 0de50aa..2a60ea6 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -2,7 +2,7 @@ import requests from settings import settings from router import group, auth_group, group_user, user, school, grade, enrollment_record -from id_generation_classes import JNVIDGeneration +from auth_group_classes import EnableStudents from request import build_request from routes import student_db_url from helpers import ( @@ -11,6 +11,7 @@ is_response_valid, is_response_empty, ) +from logger_config import get_logger from dateutil.relativedelta import relativedelta from datetime import datetime from mapping import ( @@ -49,7 +50,7 @@ def generate_JNV_student_id(data): counter = settings.JNV_COUNTER_FOR_ID_GENERATION if counter > 0: - JNV_Id = JNVIDGeneration( + JNV_Id = EnableStudents( data["region"], data["school_name"], data["grade"] ).get_id counter -= 1 @@ -221,7 +222,7 @@ async def create_student(request: Request): + USER_QUERY_PARAMS + ENROLLMENT_RECORD_PARAMS + SCHOOL_QUERY_PARAMS - + ["id_generation"], + + ["id_generation", "region"], ) if not data["id_generation"]: @@ -236,39 +237,39 @@ async def create_student(request: Request): return query_params["student_id"] else: - check_if_email_or_phone_is_part_of_request(query_params) - - user_already_exists = user.get_users( - build_request( - query_params={ - "email": query_params["email"] if "email" in query_params else None, - "phone": query_params["phone"] if "phone" in query_params else None, - } - ) - ) - if user_already_exists: - response = get_students( - build_request(query_params={"user_id": user_already_exists["user_id"]}) - ) - return response["student_id"] + if data["auth_group"] == "EnableStudents": + student_id = EnableStudents(query_params).get_student_id() + query_params['student_id'] = student_id - else: - if data["auth_group"] == "JNVStudents": - student_id = generate_JNV_student_id(data) - - if ( - data["auth_group"] == "FeedingIndiaStudents" - or data["auth_group"] == "UttarakhandStudents" - ): - student_id = query_params["phone"] - query_params["student_id"] = student_id - - student_id_already_exists = await verify_student( - build_request(), student_id=student_id - ) + if student_id == "": + return student_id + + elif (data["auth_group"] == "FeedingIndiaStudents" or data["auth_group"] == "UttarakhandStudents"): + # Use phone number as student ID + query_params["student_id"] = query_params["phone"] + student_id = query_params["student_id"] + + student_id_already_exists = await verify_student(build_request(), student_id=student_id) if student_id_already_exists: return student_id + else: + check_if_email_or_phone_is_part_of_request(query_params) + + user_already_exists = user.get_users( + build_request( + query_params={ + "email": query_params["email"] if "email" in query_params else None, + "phone": query_params["phone"] if "phone" in query_params else None, + } + ) + ) + if user_already_exists: + response = get_students( + build_request(query_params={"user_id": user_already_exists["user_id"]}) + ) + return response["student_id"] + if "grade" in query_params: student_grade_id = grade.get_grade( @@ -280,7 +281,7 @@ async def create_student(request: Request): query_params["physically_handicapped"] = ( "true" if query_params["physically_handicapped"] == "Yes" else "false" ) - + new_student_data = create_new_student_record(query_params) await create_auth_group_user_record(new_student_data, data["auth_group"]) diff --git a/app/router/user.py b/app/router/user.py index 8b769f0..31a6d29 100644 --- a/app/router/user.py +++ b/app/router/user.py @@ -28,7 +28,7 @@ def get_users(request: Request): user_db_url, params=query_params, headers=db_request_token() ) if is_response_valid(response, "User API could not fetch the data!"): - return is_response_empty(response.json(), "User does not exist!") + return is_response_empty(response.json(), False, "User does not exist!") @router.post("/") @@ -40,8 +40,7 @@ async def create_user(request: Request): + USER_QUERY_PARAMS + ENROLLMENT_RECORD_PARAMS + SCHOOL_QUERY_PARAMS - + ["id_generation"] - + ["user_type"], + + ["id_generation", "user_type", "region"] ) if data["user_type"] == "student": From 5e2c51edeb1a473e7120042f91510ad4f3595273 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 12 Jun 2024 19:29:28 +0530 Subject: [PATCH 11/18] jnv id generation --- app/auth_group_classes.py | 33 ++++++++++++++++++++++++++------- app/router/student.py | 16 ---------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index e0529ee..e09b5d9 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -1,4 +1,5 @@ from settings import settings +from fastapi import HTTPException import random from router import school, student, user, enrollment_record import datetime @@ -28,13 +29,20 @@ def __init__(self, data): if self.student_id != "": return self.student_id - - self.student_id = ( - self.get_class_code() - + self.get_jnv_code() - + self.generate_three_digit_code() - ) + counter = settings.JNV_COUNTER_FOR_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 + + raise HTTPException(status_code=400, detail="JNV Student ID could not be generated. Max loops hit!") + def check_if_user_exists(self,): # First, we check if a user with the same DOB, gender and first_name already exists in the database user_already_exists = user.get_users( @@ -101,4 +109,15 @@ def generate_three_digit_code(self, code=""): return code def get_student_id(self): - return self.student_id \ No newline at end of file + 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 \ No newline at end of file diff --git a/app/router/student.py b/app/router/student.py index 2a60ea6..a71968e 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -45,22 +45,6 @@ def build_student_and_user_data(student_data): data[key] = student_data[key] return data - -def generate_JNV_student_id(data): - counter = settings.JNV_COUNTER_FOR_ID_GENERATION - - if counter > 0: - JNV_Id = EnableStudents( - data["region"], data["school_name"], data["grade"] - ).get_id - counter -= 1 - return JNV_Id - - raise HTTPException( - status_code=400, detail="JNV Student ID could not be generated. Max loops hit!" - ) - - async def create_school_user_record(data, school_name): school_data = school.get_school(build_request(query_params={"name": school_name})) group_data = group.get_group( From 71aa7efa5aa5ebd0afcf53cf7bc0589ad726352f Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 12 Jun 2024 19:30:44 +0530 Subject: [PATCH 12/18] jnv id generation --- app/auth_group_classes.py | 77 ++++++++++++++++++++++++--------------- app/router/form.py | 2 +- app/router/student.py | 33 +++++++++++------ app/router/user.py | 2 +- 4 files changed, 71 insertions(+), 43 deletions(-) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index e09b5d9..dc6732a 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -9,13 +9,22 @@ logger = get_logger() + class EnableStudents: def __init__(self, data): - for param in ['grade','date_of_birth','gender','school_name','category','first_name', 'region']: + 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"] @@ -26,35 +35,44 @@ def __init__(self, data): self.student_id = "" self.student_id = self.check_if_user_exists() - + if self.student_id != "": return self.student_id counter = settings.JNV_COUNTER_FOR_ID_GENERATION while counter > 0: - id = (self.get_class_code() + self.get_jnv_code() + self.generate_three_digit_code()) + 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 - - raise HTTPException(status_code=400, detail="JNV Student ID could not be generated. Max loops hit!") - - def check_if_user_exists(self,): + + raise HTTPException( + status_code=400, + detail="JNV Student ID could not be generated. Max loops hit!", + ) + + def check_if_user_exists( + self, + ): # First, we check if a user with the same DOB, gender and first_name already exists in the database user_already_exists = user.get_users( - build_request( - query_params={ - "date_of_birth": self.date_of_birth, - "gender": self.gender, - "first_name": self. first_name, - } - ) + build_request( + query_params={ + "date_of_birth": self.date_of_birth, + "gender": self.gender, + "first_name": self.first_name, + } ) - + ) + if len(user_already_exists) > 0: # If the user already exists, we check if a student with the same grade, category already exists student_already_exists = student.get_students( @@ -68,17 +86,21 @@ def check_if_user_exists(self,): if len(student_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} - ) + build_request(query_params={"name": self.school_name}) ) if len(school_response) > 0: # At this point, if there is a duplicate student, there should be only one, hence we return the student_id student = student_already_exists[0] - enrollment_record_already_exists = enrollment_record.get_enrollment_records( - build_request( - query_params={"group_id": school_response[0].id, "group_type":"school", "user_id":student["user"]["id"]} + enrollment_record_already_exists = ( + enrollment_record.get_enrollment_records( + build_request( + query_params={ + "group_id": school_response[0].id, + "group_type": "school", + "user_id": student["user"]["id"], + } + ) ) ) @@ -88,7 +110,6 @@ def check_if_user_exists(self,): return "" - def get_class_code(self): graduating_year = datetime.date.today() + relativedelta( years=12 - int(self.grade) @@ -101,7 +122,7 @@ def get_jnv_code(self): query_params={"region": self.region, "name": self.school_name} ) ) - return school_response['code'] + return school_response["code"] def generate_three_digit_code(self, code=""): for _ in range(3): @@ -113,11 +134,7 @@ def get_student_id(self): def check_if_generated_id_already_exists(self, id): student_response = student.get_students( - build_request( - query_params={ - "student_id": id - } - ) + build_request(query_params={"student_id": id}) ) - return len(student_response) != 0 \ No newline at end of file + return len(student_response) != 0 diff --git a/app/router/form.py b/app/router/form.py index 585b096..0888e10 100644 --- a/app/router/form.py +++ b/app/router/form.py @@ -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") diff --git a/app/router/student.py b/app/router/student.py index a71968e..910f452 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -45,6 +45,7 @@ def build_student_and_user_data(student_data): data[key] = student_data[key] return data + async def create_school_user_record(data, school_name): school_data = school.get_school(build_request(query_params={"name": school_name})) group_data = group.get_group( @@ -222,18 +223,23 @@ async def create_student(request: Request): else: if data["auth_group"] == "EnableStudents": - student_id = EnableStudents(query_params).get_student_id() - query_params['student_id'] = student_id + student_id = EnableStudents(query_params).get_student_id() + query_params["student_id"] = student_id - if student_id == "": + if student_id == "": return student_id - - elif (data["auth_group"] == "FeedingIndiaStudents" or data["auth_group"] == "UttarakhandStudents"): + + elif ( + data["auth_group"] == "FeedingIndiaStudents" + or data["auth_group"] == "UttarakhandStudents" + ): # Use phone number as student ID query_params["student_id"] = query_params["phone"] student_id = query_params["student_id"] - student_id_already_exists = await verify_student(build_request(), student_id=student_id) + student_id_already_exists = await verify_student( + build_request(), student_id=student_id + ) if student_id_already_exists: return student_id @@ -243,17 +249,22 @@ async def create_student(request: Request): user_already_exists = user.get_users( build_request( query_params={ - "email": query_params["email"] if "email" in query_params else None, - "phone": query_params["phone"] if "phone" in query_params else None, + "email": query_params["email"] + if "email" in query_params + else None, + "phone": query_params["phone"] + if "phone" in query_params + else None, } ) ) if user_already_exists: response = get_students( - build_request(query_params={"user_id": user_already_exists["user_id"]}) + build_request( + query_params={"user_id": user_already_exists["user_id"]} + ) ) return response["student_id"] - if "grade" in query_params: student_grade_id = grade.get_grade( @@ -265,7 +276,7 @@ async def create_student(request: Request): query_params["physically_handicapped"] = ( "true" if query_params["physically_handicapped"] == "Yes" else "false" ) - + new_student_data = create_new_student_record(query_params) await create_auth_group_user_record(new_student_data, data["auth_group"]) diff --git a/app/router/user.py b/app/router/user.py index 31a6d29..f5b2860 100644 --- a/app/router/user.py +++ b/app/router/user.py @@ -40,7 +40,7 @@ async def create_user(request: Request): + USER_QUERY_PARAMS + ENROLLMENT_RECORD_PARAMS + SCHOOL_QUERY_PARAMS - + ["id_generation", "user_type", "region"] + + ["id_generation", "user_type", "region"], ) if data["user_type"] == "student": From 515790b67f44204e2b1e1511139732967a4236c2 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 12 Jun 2024 19:33:01 +0530 Subject: [PATCH 13/18] jnv id generation --- app/auth_group_classes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index dc6732a..7ebf5bf 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -91,14 +91,13 @@ def check_if_user_exists( if len(school_response) > 0: # At this point, if there is a duplicate student, there should be only one, hence we return the student_id - student = student_already_exists[0] enrollment_record_already_exists = ( enrollment_record.get_enrollment_records( build_request( query_params={ "group_id": school_response[0].id, "group_type": "school", - "user_id": student["user"]["id"], + "user_id": student_already_exists[0]["user"]["id"], } ) ) From 80a6d95fe586cc2f471588609e7df8200689bbb9 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 12 Jun 2024 20:26:58 +0530 Subject: [PATCH 14/18] dedupe --- app/auth_group_classes.py | 117 +++++++++++++++++++++----------------- app/router/student.py | 3 +- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index 7ebf5bf..635f009 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -1,7 +1,7 @@ from settings import settings from fastapi import HTTPException import random -from router import school, student, user, enrollment_record +from router import school, student, user, enrollment_record, grade import datetime from dateutil.relativedelta import relativedelta from request import build_request @@ -34,38 +34,47 @@ def __init__(self, data): self.region = data["region"] self.student_id = "" - self.student_id = self.check_if_user_exists() + self.student_id = self.check_if_student_exists() - if self.student_id != "": - return self.student_id + if self.student_id == "": + counter = int(settings.JNV_COUNTER_FOR_ID_GENERATION) - counter = settings.JNV_COUNTER_FOR_ID_GENERATION + while counter > 0: + id = ( + self.get_class_code() + + self.get_jnv_code() + + self.generate_three_digit_code() + ) - 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 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!", + ) - 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, - ): - # First, we check if a user with the same DOB, gender and first_name already exists in the database + 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, @@ -73,39 +82,44 @@ def check_if_user_exists( ) ) - if len(user_already_exists) > 0: - # If the user already exists, we check if a student with the same grade, category already exists - student_already_exists = student.get_students( - build_request( - query_params={ - "grade": self.grade, - "category": self.category, - } - ) + 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: - # 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}) + ) + + 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(school_response) > 0: - # At this point, if there is a duplicate student, there should be only one, hence we return the student_id - enrollment_record_already_exists = ( - enrollment_record.get_enrollment_records( - build_request( - query_params={ - "group_id": school_response[0].id, - "group_type": "school", - "user_id": student_already_exists[0]["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"] ) ) - ) - - if len(enrollment_record_already_exists) > 0: - logger.error("Student already exists in the database") - return student["student_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 "" @@ -135,5 +149,4 @@ 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 diff --git a/app/router/student.py b/app/router/student.py index 910f452..8a4dcd7 100644 --- a/app/router/student.py +++ b/app/router/student.py @@ -138,11 +138,12 @@ def get_students(request: Request): request.query_params, STUDENT_QUERY_PARAMS + USER_QUERY_PARAMS + ENROLLMENT_RECORD_PARAMS, ) + response = requests.get( student_db_url, params=query_params, headers=db_request_token() ) if is_response_valid(response, "Student API could not fetch the student!"): - return is_response_empty(response.json(), True, "Student does not exist") + return is_response_empty(response.json(), False, "Student does not exist") @router.get("/verify") From d3fb6a1bd05c771cdd922ab9bc09f5f484d83480 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Wed, 12 Jun 2024 20:36:00 +0530 Subject: [PATCH 15/18] dedupe --- app/auth_group_classes.py | 4 ++-- app/settings.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index 635f009..e42e97d 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -9,7 +9,7 @@ logger = get_logger() - +COUNTER_FOR_JNV_ID_GENERATION = 1000 class EnableStudents: def __init__(self, data): for param in [ @@ -37,7 +37,7 @@ def __init__(self, data): self.student_id = self.check_if_student_exists() if self.student_id == "": - counter = int(settings.JNV_COUNTER_FOR_ID_GENERATION) + counter = COUNTER_FOR_JNV_ID_GENERATION while counter > 0: id = ( diff --git a/app/settings.py b/app/settings.py index b937fde..168441e 100644 --- a/app/settings.py +++ b/app/settings.py @@ -21,7 +21,6 @@ class Settings(BaseModel): # DB service base URL db_url: str = os.environ.get("DB_SERVICE_URL") TOKEN: str = os.environ.get("DB_SERVICE_TOKEN") - JNV_COUNTER_FOR_ID_GENERATION: int = os.environ.get("JNV_COUNTER_FOR_ID_GENERATION") # callback to get the configuration From de8eff5a6f2b9a559e4487d91c702522c0ff526a Mon Sep 17 00:00:00 2001 From: Krrupa <25496389+sudheshna-donthineni@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:12:41 +0530 Subject: [PATCH 16/18] Update auth_group_classes.py --- app/auth_group_classes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index e42e97d..9baaca9 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -10,6 +10,7 @@ logger = get_logger() COUNTER_FOR_JNV_ID_GENERATION = 1000 + class EnableStudents: def __init__(self, data): for param in [ From ec8aab01c9366768a15fe9dda03083c43b3a8d49 Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Thu, 13 Jun 2024 11:21:26 +0530 Subject: [PATCH 17/18] er --- app/router/enrollment_record.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/router/enrollment_record.py b/app/router/enrollment_record.py index e0537af..62b7cb8 100644 --- a/app/router/enrollment_record.py +++ b/app/router/enrollment_record.py @@ -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!" ) From ae689521199c4087dc04fc94bab36fcc7c800bdb Mon Sep 17 00:00:00 2001 From: Krrupa <“sudonthineni@gmail.com@users.noreply.github.com”> Date: Thu, 13 Jun 2024 11:24:59 +0530 Subject: [PATCH 18/18] er --- app/auth_group_classes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/auth_group_classes.py b/app/auth_group_classes.py index 9baaca9..3ed0be6 100644 --- a/app/auth_group_classes.py +++ b/app/auth_group_classes.py @@ -11,6 +11,7 @@ COUNTER_FOR_JNV_ID_GENERATION = 1000 + class EnableStudents: def __init__(self, data): for param in [