From cbdb1b789de81384e093b9ecfefff0ad3147a637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Fri, 7 Feb 2025 21:27:37 +0000 Subject: [PATCH 01/25] fix: 500 error code course units --- django/university/routes/MarketplaceExchangeView.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/django/university/routes/MarketplaceExchangeView.py b/django/university/routes/MarketplaceExchangeView.py index 305ee24..e2fb782 100644 --- a/django/university/routes/MarketplaceExchangeView.py +++ b/django/university/routes/MarketplaceExchangeView.py @@ -79,8 +79,9 @@ def remove_invalid_dest_class_exchanges(self, marketplace_exchanges, nmec): for option in exchange.options: course_unit_id = option.course_unit_id class_issuer_goes_to = option.class_issuer_goes_to - if Class.objects.filter(course_unit_id=course_unit_id, name=class_issuer_goes_to).get().id == user_ucs_map[int(course_unit_id)].class_field.id: - add_to_result = True + if int(course_unit_id) in user_ucs_map.keys(): + if Class.objects.filter(course_unit_id=course_unit_id, name=class_issuer_goes_to).get().id == user_ucs_map[int(course_unit_id)].class_field.id: + add_to_result = True if add_to_result: exchanges_with_valid_dest_class.append(exchange) From e01287f1f98270d475184918a956f331a42fa5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Fri, 7 Feb 2025 22:08:46 +0000 Subject: [PATCH 02/25] fix: course units not appearing --- django/university/controllers/ExchangeController.py | 2 +- django/university/controllers/StudentController.py | 5 +++-- .../university/controllers/StudentScheduleController.py | 8 +++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/django/university/controllers/ExchangeController.py b/django/university/controllers/ExchangeController.py index a560647..2686c14 100644 --- a/django/university/controllers/ExchangeController.py +++ b/django/university/controllers/ExchangeController.py @@ -51,7 +51,7 @@ class ExchangeController: @staticmethod def eligible_course_units(nmec): course_units = UserCourseUnits.objects.filter(user_nmec=nmec).values_list("course_unit_id", flat=True) - + exchange_expirations = ExchangeExpirations.objects.filter( course_unit_id__in=course_units, active_date__lte=timezone.now(), diff --git a/django/university/controllers/StudentController.py b/django/university/controllers/StudentController.py index 4b4bab2..f7925a3 100644 --- a/django/university/controllers/StudentController.py +++ b/django/university/controllers/StudentController.py @@ -31,11 +31,12 @@ def populate_user_course_unit_data(nmec: int, erase_previous: bool = False): for item in course_units: (course_unit_id, class_acronym) = item - corresponding_class = Class.objects.filter(course_unit__id=course_unit_id, name=class_acronym).first() + + corresponding_class = Class.objects.filter(course_unit__id=course_unit_id, name=class_acronym.split("+")[0]).first() if not corresponding_class: continue - + user_course_unit = UserCourseUnits( user_nmec=nmec, course_unit_id=course_unit_id, diff --git a/django/university/controllers/StudentScheduleController.py b/django/university/controllers/StudentScheduleController.py index 6584649..2921285 100644 --- a/django/university/controllers/StudentScheduleController.py +++ b/django/university/controllers/StudentScheduleController.py @@ -14,9 +14,15 @@ def retrieveCourseUnitClasses(sigarra_controller, username): ExchangeController.update_schedule_accepted_exchanges(username, schedule_data) + ids = set() course_unit_classes = set() for scheduleItem in schedule_data: - course_unit_classes.add((scheduleItem["ocorrencia_id"], scheduleItem["turma_sigla"])) + if scheduleItem["tipo"] != "T" or scheduleItem["tipo"] != 'O': + if int(scheduleItem["ocorrencia_id"]) in ids: + continue + else: + course_unit_classes.add((scheduleItem["ocorrencia_id"], scheduleItem["turma_sigla"])) + ids.add(int(scheduleItem["ocorrencia_id"])) return course_unit_classes From edd33792bfd794ef11433fb6e8e0ff998a634ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Fri, 7 Feb 2025 22:19:44 +0000 Subject: [PATCH 03/25] fix: wrong tp classes --- .../university/controllers/StudentScheduleController.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/django/university/controllers/StudentScheduleController.py b/django/university/controllers/StudentScheduleController.py index 6584649..8e9f5b5 100644 --- a/django/university/controllers/StudentScheduleController.py +++ b/django/university/controllers/StudentScheduleController.py @@ -14,9 +14,15 @@ def retrieveCourseUnitClasses(sigarra_controller, username): ExchangeController.update_schedule_accepted_exchanges(username, schedule_data) + ids = set() course_unit_classes = set() for scheduleItem in schedule_data: - course_unit_classes.add((scheduleItem["ocorrencia_id"], scheduleItem["turma_sigla"])) + if scheduleItem["tipo"] != "T" and scheduleItem["tipo"] != 'O': + if int(scheduleItem["ocorrencia_id"]) in ids: + continue + else: + course_unit_classes.add((scheduleItem["ocorrencia_id"], scheduleItem["turma_sigla"])) + ids.add(int(scheduleItem["ocorrencia_id"])) return course_unit_classes From d718d7e1cbf0641d6e87ffcfab3fb0397b2b4948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Fri, 7 Feb 2025 23:29:59 +0000 Subject: [PATCH 04/25] fix: server crashing sometimes --- django/university/controllers/SigarraController.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/django/university/controllers/SigarraController.py b/django/university/controllers/SigarraController.py index cfb5c46..19a3888 100644 --- a/django/university/controllers/SigarraController.py +++ b/django/university/controllers/SigarraController.py @@ -47,7 +47,7 @@ def course_unit_schedule_url(self, ocorrencia_id, semana_ini, semana_fim): return f"https://sigarra.up.pt/feup/pt/mob_hor_geral.ucurr?pv_ocorrencia_id={ocorrencia_id}&pv_semana_ini={semana_ini}&pv_semana_fim={semana_fim}" def retrieve_student_photo(self, nmec): - response = requests.get(self.get_student_photo_url(nmec), cookies=self.cookies) + response = requests.get(self.get_student_photo_url(nmec), cookies=self.cookies, timeout=5) if response.status_code != 200: return SigarraResponse(None, response.status_code) @@ -55,7 +55,7 @@ def retrieve_student_photo(self, nmec): return SigarraResponse(response.content, 200) def get_student_profile(self, nmec): - response = requests.get(self.student_profile_url(nmec), cookies=self.cookies) + response = requests.get(self.student_profile_url(nmec), cookies=self.cookies, timeout=5) if response.status_code != 200: return SigarraResponse(None, response.status_code) @@ -84,7 +84,7 @@ def login(self): response = requests.post("https://sigarra.up.pt/feup/pt/mob_val_geral.autentica/", data={ "pv_login": self.username, "pv_password": self.password - }) + }, timeout=5) self.cookies = response.cookies except requests.exceptions.RequestException as e: @@ -97,7 +97,7 @@ def get_student_schedule(self, nmec: int) -> SigarraResponse: nmec, semana_ini, semana_fim - ), cookies=self.cookies) + ), cookies=self.cookies, timeout=5) if(response.status_code != 200): return SigarraResponse(None, response.status_code) @@ -118,7 +118,7 @@ def get_student_course_units(self, nmec: int) -> SigarraResponse: def get_course_unit_classes(self, course_unit_id: int) -> SigarraResponse: url = f"https://sigarra.up.pt/feup/pt/mob_ucurr_geral.uc_inscritos?pv_ocorrencia_id={course_unit_id}" - response = requests.get(url, cookies=self.cookies) + response = requests.get(url, cookies=self.cookies, timeout=5) if response.status_code != 200: return SigarraResponse(None, response.status_code) @@ -135,7 +135,7 @@ def get_class_schedule(self, course_unit_id: int, class_name: str) -> SigarraRes course_unit_id, semana_ini, semana_fim - ), cookies=self.cookies) + ), cookies=self.cookies, timeout=5) if(response.status_code != 200): return SigarraResponse(None, response.status_code) From fd46699b71809199063aff697332ccb22984b042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Fri, 7 Feb 2025 23:41:15 +0000 Subject: [PATCH 05/25] fix: removed asgi for now --- django/tts_be/asgi.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/django/tts_be/asgi.py b/django/tts_be/asgi.py index e5d2d74..9e5b2fb 100644 --- a/django/tts_be/asgi.py +++ b/django/tts_be/asgi.py @@ -10,11 +10,9 @@ import os from django.core.asgi import get_asgi_application -import socketio +# import socketio from university.socket.views import sessions_server os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tts_be.settings') -django_app = get_asgi_application() - -application = socketio.ASGIApp(sessions_server.sio, django_app) +application = get_asgi_application() From d609a2bd75dbd298ac3c4bb0eb43cceff512d0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Fri, 7 Feb 2025 23:54:42 +0000 Subject: [PATCH 06/25] temporary remove asgi --- django/tts_be/asgi.py | 2 +- django/tts_be/settings.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/django/tts_be/asgi.py b/django/tts_be/asgi.py index 9e5b2fb..a835b63 100644 --- a/django/tts_be/asgi.py +++ b/django/tts_be/asgi.py @@ -11,7 +11,7 @@ from django.core.asgi import get_asgi_application # import socketio -from university.socket.views import sessions_server +# from university.socket.views import sessions_server os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tts_be.settings') diff --git a/django/tts_be/settings.py b/django/tts_be/settings.py index a42739d..9118360 100644 --- a/django/tts_be/settings.py +++ b/django/tts_be/settings.py @@ -74,7 +74,7 @@ INSTALLED_APPS = [ 'corsheaders', 'anymail', - 'daphne', + # 'daphne', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -84,7 +84,7 @@ 'django.contrib.staticfiles', 'mozilla_django_oidc', 'university', - 'channels', + # 'channels', ] EMAIL_HOST = os.getenv("EMAIL_HOST", "tts-mailpit") @@ -169,8 +169,6 @@ OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS = 3600 * 60 -ASGI_APPLICATION = 'tts_be.asgi.application' - # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases From de52aa7fe0f032f0363e6b5adf4f2c07f5d93805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 13:02:17 +0000 Subject: [PATCH 07/25] fix: wrong student not enrolled --- django/university/exchange/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django/university/exchange/utils.py b/django/university/exchange/utils.py index f73cbd5..c209acf 100644 --- a/django/university/exchange/utils.py +++ b/django/university/exchange/utils.py @@ -108,7 +108,7 @@ def build_student_schedule_dicts(student_schedules, exchanges): def build_student_schedule_dict(schedule: list): return { - (class_schedule["turma_sigla"], class_schedule["ocorrencia_id"]): class_schedule for class_schedule in schedule if (class_schedule["tipo"] == "TP" or class_schedule["tipo"] == "PL") + (class_schedule["turma_sigla"].split("+")[0], class_schedule["ocorrencia_id"]): class_schedule for class_schedule in schedule if (class_schedule["tipo"] == "TP" or class_schedule["tipo"] == "PL") } def check_class_schedule_overlap(day_1: int, start_1: int, end_1: int, day_2: int, start_2: int, end_2: int) -> bool: From d969c1b591fd277fdf3fa40342512e5b1fcb2c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 13:55:55 +0000 Subject: [PATCH 08/25] fix: bandage to profissional communication issue --- django/university/controllers/SigarraController.py | 12 ++++++------ .../routes/student/schedule/StudentScheduleView.py | 11 ++++++++++- postgres/sql/00_schema_postgres.sql | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/django/university/controllers/SigarraController.py b/django/university/controllers/SigarraController.py index 19a3888..cfb5c46 100644 --- a/django/university/controllers/SigarraController.py +++ b/django/university/controllers/SigarraController.py @@ -47,7 +47,7 @@ def course_unit_schedule_url(self, ocorrencia_id, semana_ini, semana_fim): return f"https://sigarra.up.pt/feup/pt/mob_hor_geral.ucurr?pv_ocorrencia_id={ocorrencia_id}&pv_semana_ini={semana_ini}&pv_semana_fim={semana_fim}" def retrieve_student_photo(self, nmec): - response = requests.get(self.get_student_photo_url(nmec), cookies=self.cookies, timeout=5) + response = requests.get(self.get_student_photo_url(nmec), cookies=self.cookies) if response.status_code != 200: return SigarraResponse(None, response.status_code) @@ -55,7 +55,7 @@ def retrieve_student_photo(self, nmec): return SigarraResponse(response.content, 200) def get_student_profile(self, nmec): - response = requests.get(self.student_profile_url(nmec), cookies=self.cookies, timeout=5) + response = requests.get(self.student_profile_url(nmec), cookies=self.cookies) if response.status_code != 200: return SigarraResponse(None, response.status_code) @@ -84,7 +84,7 @@ def login(self): response = requests.post("https://sigarra.up.pt/feup/pt/mob_val_geral.autentica/", data={ "pv_login": self.username, "pv_password": self.password - }, timeout=5) + }) self.cookies = response.cookies except requests.exceptions.RequestException as e: @@ -97,7 +97,7 @@ def get_student_schedule(self, nmec: int) -> SigarraResponse: nmec, semana_ini, semana_fim - ), cookies=self.cookies, timeout=5) + ), cookies=self.cookies) if(response.status_code != 200): return SigarraResponse(None, response.status_code) @@ -118,7 +118,7 @@ def get_student_course_units(self, nmec: int) -> SigarraResponse: def get_course_unit_classes(self, course_unit_id: int) -> SigarraResponse: url = f"https://sigarra.up.pt/feup/pt/mob_ucurr_geral.uc_inscritos?pv_ocorrencia_id={course_unit_id}" - response = requests.get(url, cookies=self.cookies, timeout=5) + response = requests.get(url, cookies=self.cookies) if response.status_code != 200: return SigarraResponse(None, response.status_code) @@ -135,7 +135,7 @@ def get_class_schedule(self, course_unit_id: int, class_name: str) -> SigarraRes course_unit_id, semana_ini, semana_fim - ), cookies=self.cookies, timeout=5) + ), cookies=self.cookies) if(response.status_code != 200): return SigarraResponse(None, response.status_code) diff --git a/django/university/routes/student/schedule/StudentScheduleView.py b/django/university/routes/student/schedule/StudentScheduleView.py index d323dab..9d89717 100644 --- a/django/university/routes/student/schedule/StudentScheduleView.py +++ b/django/university/routes/student/schedule/StudentScheduleView.py @@ -53,6 +53,11 @@ def fetch_from_db(self, request, username): classes = ClassController.get_classes(course_unit.course_unit.id) classes = list(filter(lambda class_: class_["id"] in class_ids, classes)) + if course_unit.course_unit.id == 548052: + sigarra_schedule = SigarraController().get_student_schedule(username).data + schedule.extend(convert_sigarra_schedule([list(filter(lambda schedule: schedule["ocorrencia_id"] == 548052, sigarra_schedule))[0]])) + continue + for class_ in classes: for slot in class_["slots"]: schedule.append({ @@ -97,7 +102,11 @@ def fetch_from_sigarra(self, request, username): sigarra_synchronized = old_schedule == new_schedule - new_response = JsonResponse({"schedule": convert_sigarra_schedule(schedule_data), "noChanges": sigarra_synchronized}, safe=False) + converted_schedule = convert_sigarra_schedule(schedule_data) + for item in converted_schedule: + item["classInfo"]["name"] = item["classInfo"]["name"].split("+")[0] + + new_response = JsonResponse({"schedule": converted_schedule, "noChanges": sigarra_synchronized}, safe=False) new_response.status_code = sigarra_res.status_code return new_response diff --git a/postgres/sql/00_schema_postgres.sql b/postgres/sql/00_schema_postgres.sql index 396b111..998aa28 100644 --- a/postgres/sql/00_schema_postgres.sql +++ b/postgres/sql/00_schema_postgres.sql @@ -186,7 +186,7 @@ CREATE TABLE "public"."marketplace_exchange" ( CREATE TABLE "public"."direct_exchange" ( "id" SERIAL PRIMARY KEY, - "issuer_name" varchar(32) NOT NULL, + "issuer_name" varchar(256) NOT NULL, "issuer_nmec" varchar(32) NOT NULL, "accepted" boolean NOT NULL, "canceled" boolean DEFAULT false, @@ -198,7 +198,7 @@ CREATE TABLE "public"."direct_exchange" ( CREATE TABLE "public"."direct_exchange_participants" ( "id" SERIAL PRIMARY KEY, - "participant_name" varchar(32) NOT NULL, + "participant_name" varchar(256) NOT NULL, "participant_nmec" varchar(32) NOT NULL, "class_participant_goes_from" varchar(16) NOT NULL, "class_participant_goes_to" varchar(16) NOT NULL, From 08c5c3f20e1a5219ef4c42f8013c36541b9b5a1f Mon Sep 17 00:00:00 2001 From: Process-ing Date: Sat, 8 Feb 2025 15:13:18 +0000 Subject: [PATCH 09/25] Start resolving conflicts on original schedule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomás Palma --- django/university/controllers/ExchangeController.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/django/university/controllers/ExchangeController.py b/django/university/controllers/ExchangeController.py index 2686c14..5c55d1b 100644 --- a/django/university/controllers/ExchangeController.py +++ b/django/university/controllers/ExchangeController.py @@ -140,7 +140,7 @@ def create_direct_exchange_participants(student_schedules, exchanges, inserted_e return (ExchangeStatus.SUCCESS, None) """ - Checks if schedule for a user with a given username has overlpas + Checks if schedule for a user with a given username has overlaps """ @staticmethod def exchange_overlap(student_schedules, username) -> bool: @@ -152,6 +152,10 @@ def exchange_overlap(student_schedules, username) -> bool: (class_schedule_day, class_schedule_start, class_schedule_end, class_schedule_type) = (class_schedule["dia"], class_schedule["hora_inicio"] / 3600, class_schedule["aula_duracao"] + class_schedule["hora_inicio"] / 3600, class_schedule['tipo']) (overlap_param_day, overlap_param_start, overlap_param_end, overlap_param_type) = (other_class_schedule["dia"], other_class_schedule["hora_inicio"] / 3600, other_class_schedule["aula_duracao"] + other_class_schedule["hora_inicio"] / 3600, other_class_schedule['tipo']) + + original_class = UserCourseUnits.objects.filter(user_nmec=username, course_unit__id=int(class_schedule["ocorrencia_id"])).class_field.id + original_other_class = UserCourseUnits.objects.filter(user_nmec=username, course_unit__id=int(other_class_schedule["ocorrencia_id"])).class_field.id + if (check_class_mandatory(class_schedule_type) and check_class_mandatory(overlap_param_type) and check_class_schedule_overlap(class_schedule_day, class_schedule_start, class_schedule_end, overlap_param_day, overlap_param_start, overlap_param_end)): From 272e981877bdcf60c7613047bed4b7fe8ea6a9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 16:21:31 +0000 Subject: [PATCH 10/25] fix: conflicts only with new classes --- .../controllers/ExchangeController.py | 25 +++++++++++++++---- .../routes/MarketplaceExchangeView.py | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/django/university/controllers/ExchangeController.py b/django/university/controllers/ExchangeController.py index 5c55d1b..6dddde9 100644 --- a/django/university/controllers/ExchangeController.py +++ b/django/university/controllers/ExchangeController.py @@ -9,7 +9,7 @@ from django.utils import timezone from enum import Enum -from university.models import UserCourseUnits +from university.models import UserCourseUnits, Class from university.serializers.DirectExchangeParticipantsSerializer import DirectExchangeParticipantsSerializer from university.serializers.MarketplaceExchangeClassSerializer import MarketplaceExchangeClassSerializer @@ -152,14 +152,29 @@ def exchange_overlap(student_schedules, username) -> bool: (class_schedule_day, class_schedule_start, class_schedule_end, class_schedule_type) = (class_schedule["dia"], class_schedule["hora_inicio"] / 3600, class_schedule["aula_duracao"] + class_schedule["hora_inicio"] / 3600, class_schedule['tipo']) (overlap_param_day, overlap_param_start, overlap_param_end, overlap_param_type) = (other_class_schedule["dia"], other_class_schedule["hora_inicio"] / 3600, other_class_schedule["aula_duracao"] + other_class_schedule["hora_inicio"] / 3600, other_class_schedule['tipo']) - - original_class = UserCourseUnits.objects.filter(user_nmec=username, course_unit__id=int(class_schedule["ocorrencia_id"])).class_field.id - original_other_class = UserCourseUnits.objects.filter(user_nmec=username, course_unit__id=int(other_class_schedule["ocorrencia_id"])).class_field.id + class_changed = False + other_class_changed = False + + # Obtain ids of classes before change in the new schedule + original_class = UserCourseUnits.objects.filter(user_nmec=username, course_unit__id=int(class_schedule["ocorrencia_id"])).first() + if original_class is not None: + original_class = original_class.class_field.id + new_class_id = Class.objects.filter(name=class_schedule["turma_sigla"].split("+")[0], course_unit_id=int(class_schedule["ocorrencia_id"])).first().id + class_changed = new_class_id != original_class + + original_other_class = UserCourseUnits.objects.filter(user_nmec=username, course_unit__id=int(other_class_schedule["ocorrencia_id"])).first() + if original_other_class is not None: + original_other_class = original_other_class.class_field.id + # Need to check if the classes are the same as the previous ]ones or not + new_other_class_id = Class.objects.filter(name=other_class_schedule["turma_sigla"].split("+")[0], course_unit_id=int(other_class_schedule["ocorrencia_id"])).first().id + + other_class_changed = new_other_class_id != original_other_class if (check_class_mandatory(class_schedule_type) and check_class_mandatory(overlap_param_type) and check_class_schedule_overlap(class_schedule_day, class_schedule_start, class_schedule_end, overlap_param_day, overlap_param_start, overlap_param_end)): - return True + if class_changed or other_class_changed: + return True return False diff --git a/django/university/routes/MarketplaceExchangeView.py b/django/university/routes/MarketplaceExchangeView.py index e2fb782..a59c70e 100644 --- a/django/university/routes/MarketplaceExchangeView.py +++ b/django/university/routes/MarketplaceExchangeView.py @@ -139,7 +139,7 @@ def submit_marketplace_exchange_request(self, request): if status == ExchangeStatus.STUDENTS_NOT_ENROLLED: return JsonResponse({"error": incorrect_class_error()}, status=400, safe=False) - if exchange_overlap(student_schedules, curr_student): + if ExchangeController.exchange_overlap(student_schedules, curr_student): return JsonResponse({"error": "classes-overlap"}, status=400, safe=False) exchange_data_str = json.dumps(exchanges, sort_keys=True) From 395c99eee6e3c3039985d237a2283b563cd8da4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 19:22:44 +0000 Subject: [PATCH 11/25] fix: slow admin request fetching --- .../university/controllers/CourseUnitController.py | 12 ++++++++++-- .../routes/course_unit/CourseUnitEnrollmentView.py | 2 +- .../university/routes/exchange/DirectExchangeView.py | 2 +- .../university/routes/exchange/ExchangeUrgentView.py | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/django/university/controllers/CourseUnitController.py b/django/university/controllers/CourseUnitController.py index d8bf7f0..38fe780 100644 --- a/django/university/controllers/CourseUnitController.py +++ b/django/university/controllers/CourseUnitController.py @@ -1,14 +1,22 @@ from university.models import CourseMetadata class CourseUnitController: + available_courses = [22862, 22841] + @staticmethod def course_unit_curricular_year(course_unit_id): - course_metadata = CourseMetadata.objects.filter(course_unit_id=course_unit_id).get() + course_metadata = CourseMetadata.objects.filter( + course_unit_id=course_unit_id, + course_id__in=CourseUnitController.available_courses + ).first() + return course_metadata.course_unit_year @staticmethod def course_unit_major(course_unit_id): - course_metadata = CourseMetadata.objects.filter(course_unit_id=course_unit_id).get() + course_metadata = CourseMetadata.objects.filter( + course_id__in=CourseUnitController.available_courses, + course_unit_id=course_unit_id).first() return course_metadata.course.id \ No newline at end of file diff --git a/django/university/routes/course_unit/CourseUnitEnrollmentView.py b/django/university/routes/course_unit/CourseUnitEnrollmentView.py index 787476e..439a55c 100644 --- a/django/university/routes/course_unit/CourseUnitEnrollmentView.py +++ b/django/university/routes/course_unit/CourseUnitEnrollmentView.py @@ -58,7 +58,7 @@ def get(self, request): enrollments = list(map(lambda enrollment: CourseUnitEnrollmentsSerializer(enrollment).data, CourseUnitEnrollments.objects.all().order_by('date'))) - paginator = Paginator(enrollments, 48) + paginator = Paginator(enrollments, 20) page_number = request.GET.get("page") enrollments = [x for x in paginator.get_page(page_number if page_number != None else 1)] diff --git a/django/university/routes/exchange/DirectExchangeView.py b/django/university/routes/exchange/DirectExchangeView.py index 4f28e72..43a842e 100644 --- a/django/university/routes/exchange/DirectExchangeView.py +++ b/django/university/routes/exchange/DirectExchangeView.py @@ -76,7 +76,7 @@ def get(self, request): direct_exchanges = list(map(lambda exchange: DirectExchangeSerializer(exchange).data, DirectExchange.objects.filter(accepted=True).order_by('date'))) - paginator = Paginator(direct_exchanges, 48) + paginator = Paginator(direct_exchanges, 20) page_number = request.GET.get("page") page_obj = paginator.get_page(page_number if page_number != None else 1) direct_exchanges = [x for x in page_obj] diff --git a/django/university/routes/exchange/ExchangeUrgentView.py b/django/university/routes/exchange/ExchangeUrgentView.py index 15911df..44927ee 100644 --- a/django/university/routes/exchange/ExchangeUrgentView.py +++ b/django/university/routes/exchange/ExchangeUrgentView.py @@ -59,7 +59,7 @@ def get(self, request): exchanges = list(map(lambda exchange: ExchangeUrgentRequestSerializer(exchange).data, ExchangeUrgentRequests.objects.all().order_by('date'))) - paginator = Paginator(exchanges, 48) + paginator = Paginator(exchanges, 20) page_number = request.GET.get("page") exchanges = [x for x in paginator.get_page(page_number if page_number != None else 1)] From 8277da0d654770ffa1d2d36b2a254e8e9cee72e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 21:45:45 +0000 Subject: [PATCH 12/25] fix: enrollments cannot be empty and not duplicated --- .../course_unit/CourseUnitEnrollmentView.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/django/university/routes/course_unit/CourseUnitEnrollmentView.py b/django/university/routes/course_unit/CourseUnitEnrollmentView.py index 439a55c..cb333b5 100644 --- a/django/university/routes/course_unit/CourseUnitEnrollmentView.py +++ b/django/university/routes/course_unit/CourseUnitEnrollmentView.py @@ -58,7 +58,7 @@ def get(self, request): enrollments = list(map(lambda enrollment: CourseUnitEnrollmentsSerializer(enrollment).data, CourseUnitEnrollments.objects.all().order_by('date'))) - paginator = Paginator(enrollments, 20) + paginator = Paginator(enrollments, 10) page_number = request.GET.get("page") enrollments = [x for x in paginator.get_page(page_number if page_number != None else 1)] @@ -74,22 +74,27 @@ def get(self, request): def post(self, request): enrollments = request.POST.getlist("enrollCourses[]") + if(len(enrollments) == 0): + return JsonResponse({"error": "Pedido vazio"}, status=400) + student_course_units = list(UserCourseUnits.objects.filter(user_nmec=request.user.username).all()) with transaction.atomic(): - course_unit_enrollment = CourseUnitEnrollments.objects.create( + course_unit_enrollment = CourseUnitEnrollments( user_nmec=request.user.username, accepted=False, admin_state="untreated", date=timezone.now() ) - course_unit_enrollment.save() models_to_save = [] for enrollment in enrollments: enrollment_metadata = json.loads(enrollment) - if enrollment_metadata["enrolling"] and len(list(filter(lambda x: x.course_unit_id == enrollment_metadata["course_unit_id"], student_course_units))) > 0: + if len(list(CourseUnitEnrollmentOptions.objects.filter(course_unit__id=int(enrollment_metadata["course_unit_id"]), enrolling=enrollment_metadata["enrolling"]))) > 0: + return JsonResponse({"error": "Não podes fazer pedidos com disciplinas em que já pediste noutros!"}, status=400) + + if enrollment_metadata["enrolling"] and len(list(filter(lambda x: int(x.course_unit_id) == int(enrollment_metadata["course_unit_id"]), student_course_units))) > 0: return JsonResponse({"error": "Não te podes inscrever a disciplinas em que já tens uma inscrição!"}, status=400) db_enrollment = CourseUnitEnrollmentOptions( @@ -100,6 +105,8 @@ def post(self, request): ) models_to_save.append(db_enrollment) + + course_unit_enrollment.save() CourseUnitEnrollmentOptions.objects.bulk_create(models_to_save) return HttpResponse(status=200) \ No newline at end of file From 2a51f4d2cb3ebea7ee91fdee1072f397ec8cfaaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 23:04:29 +0000 Subject: [PATCH 13/25] fix: enrollments speed --- .../university/routes/course_unit/CourseUnitEnrollmentView.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/django/university/routes/course_unit/CourseUnitEnrollmentView.py b/django/university/routes/course_unit/CourseUnitEnrollmentView.py index cb333b5..6e2f3d2 100644 --- a/django/university/routes/course_unit/CourseUnitEnrollmentView.py +++ b/django/university/routes/course_unit/CourseUnitEnrollmentView.py @@ -56,7 +56,7 @@ def get(self, request): if not(is_admin): return HttpResponse(status=403) - enrollments = list(map(lambda enrollment: CourseUnitEnrollmentsSerializer(enrollment).data, CourseUnitEnrollments.objects.all().order_by('date'))) + enrollments = CourseUnitEnrollments.objects.all().order_by('date') paginator = Paginator(enrollments, 10) page_number = request.GET.get("page") @@ -66,6 +66,8 @@ def get(self, request): if request.GET.get(filter): enrollments = self.filter_actions[filter](enrollments, request.GET.get(filter)) + enrollments = CourseUnitEnrollmentsSerializer(enrollments, many=True).data + return JsonResponse({ "enrollments": enrollments, "total_pages": paginator.num_pages From 54a81b50d3f38e95413d0356fa84c3e8a0f1fe43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sat, 8 Feb 2025 23:38:38 +0000 Subject: [PATCH 14/25] fix: admin exchange speed --- .../routes/course_unit/CourseUnitEnrollmentView.py | 10 +++++----- .../routes/exchange/DirectExchangeView.py | 14 ++++++++------ .../routes/exchange/ExchangeUrgentView.py | 12 +++++++----- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/django/university/routes/course_unit/CourseUnitEnrollmentView.py b/django/university/routes/course_unit/CourseUnitEnrollmentView.py index 6e2f3d2..953a436 100644 --- a/django/university/routes/course_unit/CourseUnitEnrollmentView.py +++ b/django/university/routes/course_unit/CourseUnitEnrollmentView.py @@ -46,7 +46,7 @@ def filter_active_state(self, exchanges, state): states = state.split(",") return list( filter( - lambda exchange: exchange.get("admin_state") in states, + lambda exchange: exchange.admin_state in states, exchanges ) ) @@ -58,14 +58,14 @@ def get(self, request): enrollments = CourseUnitEnrollments.objects.all().order_by('date') - paginator = Paginator(enrollments, 10) - page_number = request.GET.get("page") - enrollments = [x for x in paginator.get_page(page_number if page_number != None else 1)] - for filter in AdminRequestFiltersController.filter_values(): if request.GET.get(filter): enrollments = self.filter_actions[filter](enrollments, request.GET.get(filter)) + paginator = Paginator(enrollments, 10) + page_number = request.GET.get("page") + enrollments = [x for x in paginator.get_page(page_number if page_number != None else 1)] + enrollments = CourseUnitEnrollmentsSerializer(enrollments, many=True).data return JsonResponse({ diff --git a/django/university/routes/exchange/DirectExchangeView.py b/django/university/routes/exchange/DirectExchangeView.py index 43a842e..e76f723 100644 --- a/django/university/routes/exchange/DirectExchangeView.py +++ b/django/university/routes/exchange/DirectExchangeView.py @@ -60,7 +60,7 @@ def filter_active_state(self, exchanges, state): states = state.split(",") return list( filter( - lambda exchange: exchange.get("admin_state") in states, + lambda exchange: exchange.admin_state in states, exchanges ) ) @@ -74,17 +74,19 @@ def get(self, request): if not(is_admin): return HttpResponse(status=403) - direct_exchanges = list(map(lambda exchange: DirectExchangeSerializer(exchange).data, DirectExchange.objects.filter(accepted=True).order_by('date'))) + direct_exchanges = DirectExchange.objects.filter(accepted=True).order_by('date') + + for filter in AdminRequestFiltersController.filter_values(): + if request.GET.get(filter): + direct_exchanges = self.filter_actions[filter](direct_exchanges, request.GET.get(filter)) paginator = Paginator(direct_exchanges, 20) page_number = request.GET.get("page") page_obj = paginator.get_page(page_number if page_number != None else 1) direct_exchanges = [x for x in page_obj] - for filter in AdminRequestFiltersController.filter_values(): - if request.GET.get(filter): - direct_exchanges = self.filter_actions[filter](direct_exchanges, request.GET.get(filter)) - + direct_exchanges = DirectExchangeSerializer(direct_exchanges, many=True).data + return JsonResponse({ "exchanges": direct_exchanges, "total_pages": paginator.num_pages diff --git a/django/university/routes/exchange/ExchangeUrgentView.py b/django/university/routes/exchange/ExchangeUrgentView.py index 44927ee..ba843b0 100644 --- a/django/university/routes/exchange/ExchangeUrgentView.py +++ b/django/university/routes/exchange/ExchangeUrgentView.py @@ -47,7 +47,7 @@ def filter_active_state(self, exchanges, state): states = state.split(",") return list( filter( - lambda exchange: exchange.get("admin_state") in states, + lambda exchange: exchange.admin_state in states, exchanges ) ) @@ -57,15 +57,17 @@ def get(self, request): if not(is_admin): return HttpResponse(status=403) - exchanges = list(map(lambda exchange: ExchangeUrgentRequestSerializer(exchange).data, ExchangeUrgentRequests.objects.all().order_by('date'))) + exchanges = ExchangeUrgentRequests.objects.all().order_by('date') + + for filter in AdminRequestFiltersController.filter_values(): + if request.GET.get(filter): + exchanges = self.filter_actions[filter](exchanges, request.GET.get(filter)) paginator = Paginator(exchanges, 20) page_number = request.GET.get("page") exchanges = [x for x in paginator.get_page(page_number if page_number != None else 1)] - for filter in AdminRequestFiltersController.filter_values(): - if request.GET.get(filter): - exchanges = self.filter_actions[filter](exchanges, request.GET.get(filter)) + exchanges = ExchangeUrgentRequestSerializer(exchanges, many=True).data return JsonResponse({ "exchanges": exchanges, From f7ae0b27e505be69c3ef07184b28aa5af19dd38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 00:06:16 +0000 Subject: [PATCH 15/25] fix: decrease documents per page --- django/university/routes/exchange/DirectExchangeView.py | 2 +- django/university/routes/exchange/ExchangeUrgentView.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/django/university/routes/exchange/DirectExchangeView.py b/django/university/routes/exchange/DirectExchangeView.py index e76f723..7d2b7c5 100644 --- a/django/university/routes/exchange/DirectExchangeView.py +++ b/django/university/routes/exchange/DirectExchangeView.py @@ -80,7 +80,7 @@ def get(self, request): if request.GET.get(filter): direct_exchanges = self.filter_actions[filter](direct_exchanges, request.GET.get(filter)) - paginator = Paginator(direct_exchanges, 20) + paginator = Paginator(direct_exchanges, 10) page_number = request.GET.get("page") page_obj = paginator.get_page(page_number if page_number != None else 1) direct_exchanges = [x for x in page_obj] diff --git a/django/university/routes/exchange/ExchangeUrgentView.py b/django/university/routes/exchange/ExchangeUrgentView.py index ba843b0..f6896ab 100644 --- a/django/university/routes/exchange/ExchangeUrgentView.py +++ b/django/university/routes/exchange/ExchangeUrgentView.py @@ -63,7 +63,7 @@ def get(self, request): if request.GET.get(filter): exchanges = self.filter_actions[filter](exchanges, request.GET.get(filter)) - paginator = Paginator(exchanges, 20) + paginator = Paginator(exchanges, 10) page_number = request.GET.get("page") exchanges = [x for x in paginator.get_page(page_number if page_number != None else 1)] From ea563f3d787929025ebe214be0be48903c455d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 12:04:09 +0000 Subject: [PATCH 16/25] fix: faulty conflict logic --- .../university/controllers/ExchangeValidationController.py | 6 +++++- django/university/routes/exchange/DirectExchangeView.py | 2 +- .../university/routes/exchange/verify/ExchangeVerifyView.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/django/university/controllers/ExchangeValidationController.py b/django/university/controllers/ExchangeValidationController.py index 3100385..748b1c2 100644 --- a/django/university/controllers/ExchangeValidationController.py +++ b/django/university/controllers/ExchangeValidationController.py @@ -25,6 +25,9 @@ class ExchangeValidationController: All of the exchanges that include classes that were changed by the accepted exchange need to be revalidated or even canceled. """ def cancel_conflicting_exchanges(self, accepted_exchange_id: int): + if(DirectExchange.objects.filter(id=accepted_exchange_id).first().canceled): + return + conflicting_exchanges = [] with transaction.atomic(): @@ -33,7 +36,8 @@ def cancel_conflicting_exchanges(self, accepted_exchange_id: int): # 1. Are there any exchanges that include classes that a participant changed from? conflicting = DirectExchangeParticipants.objects.exclude(direct_exchange__id=accepted_exchange_id).filter( participant_nmec=participant.participant_nmec, - class_participant_goes_from=participant.class_participant_goes_from + class_participant_goes_from=participant.class_participant_goes_from, + direct_exchange__accepted=True ) conflicting_exchanges.extend(list(map(lambda conflicting_exchange: conflicting_exchange.direct_exchange, conflicting))) diff --git a/django/university/routes/exchange/DirectExchangeView.py b/django/university/routes/exchange/DirectExchangeView.py index 7d2b7c5..9773159 100644 --- a/django/university/routes/exchange/DirectExchangeView.py +++ b/django/university/routes/exchange/DirectExchangeView.py @@ -216,7 +216,7 @@ def put(self, request, id): if exchange.marketplace_exchange: exchange.marketplace_exchange.delete() - ExchangeValidationController().cancel_conflicting_exchanges(exchange.id) + ExchangeValidationController().cancel_conflicting_exchanges(int(exchange.id)) return JsonResponse({"success": True}, safe=False) except Exception as e: diff --git a/django/university/routes/exchange/verify/ExchangeVerifyView.py b/django/university/routes/exchange/verify/ExchangeVerifyView.py index 13cd516..c88c43e 100644 --- a/django/university/routes/exchange/verify/ExchangeVerifyView.py +++ b/django/university/routes/exchange/verify/ExchangeVerifyView.py @@ -56,7 +56,7 @@ def post(self, request, token): if direct_exchange.marketplace_exchange: direct_exchange.marketplace_exchange.delete() - ExchangeValidationController().cancel_conflicting_exchanges(exchange_info["exchange_id"]) + ExchangeValidationController().cancel_conflicting_exchanges(int(exchange_info["exchange_id"])) if cache.get(token) is not None: return JsonResponse({"verified": False}, safe=False, status=403) From 3e25ff148f2d94a267c081389e40d7fc99c3717b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 14:20:33 +0000 Subject: [PATCH 17/25] fix: faulty validation direct exchange logic --- .../controllers/ExchangeValidationController.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/django/university/controllers/ExchangeValidationController.py b/django/university/controllers/ExchangeValidationController.py index 748b1c2..4c5fe36 100644 --- a/django/university/controllers/ExchangeValidationController.py +++ b/django/university/controllers/ExchangeValidationController.py @@ -76,10 +76,9 @@ def validate_direct_exchange(self, exchange_id: int) -> ExchangeValidationRespon schedule = {} for participant in exchange_participants: if participant.participant_nmec not in schedule.keys(): - schedule[participant.participant_nmec] = build_student_schedule_dict(SigarraController().get_student_schedule(int(participant.participant_nmec)).data) - - # Get new schedule from accepted changes - ExchangeController.update_schedule_accepted_exchanges(participant.participant_nmec, list(schedule[participant.participant_nmec].values())) + new_schedule = SigarraController().get_student_schedule(int(participant.participant_nmec)).data + ExchangeController.update_schedule_accepted_exchanges(participant.participant_nmec, new_schedule) + schedule[participant.participant_nmec] = build_student_schedule_dict(new_schedule) # 2. Check if users are inside classes they will exchange from with for username in schedule.keys(): @@ -87,6 +86,7 @@ def validate_direct_exchange(self, exchange_id: int) -> ExchangeValidationRespon for entry in participant_entries: if (entry.class_participant_goes_from, int(entry.course_unit_id)) not in list(schedule[username].keys()): + return ExchangeValidationResponse(False, ExchangeStatus.STUDENTS_NOT_ENROLLED) # 3. Alter the schedule of the users according to the exchange metadata From f5447b408ea4c5f6e3237703c31201ba57a68fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 15:52:36 +0000 Subject: [PATCH 18/25] fix: unable to accept direct exchanges from marketplace --- django/university/routes/exchange/DirectExchangeView.py | 5 ++++- .../university/routes/exchange/verify/ExchangeVerifyView.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/django/university/routes/exchange/DirectExchangeView.py b/django/university/routes/exchange/DirectExchangeView.py index 9773159..3e63f5e 100644 --- a/django/university/routes/exchange/DirectExchangeView.py +++ b/django/university/routes/exchange/DirectExchangeView.py @@ -214,7 +214,10 @@ def put(self, request, id): StudentController.populate_user_course_unit_data(int(participant.participant_nmec), erase_previous=True) if exchange.marketplace_exchange: - exchange.marketplace_exchange.delete() + marketplace_exchange = exchange.marketplace_exchange + exchange.marketplace_exchange = None + exchange.save() + marketplace_exchange.delete() ExchangeValidationController().cancel_conflicting_exchanges(int(exchange.id)) diff --git a/django/university/routes/exchange/verify/ExchangeVerifyView.py b/django/university/routes/exchange/verify/ExchangeVerifyView.py index c88c43e..55ab2bd 100644 --- a/django/university/routes/exchange/verify/ExchangeVerifyView.py +++ b/django/university/routes/exchange/verify/ExchangeVerifyView.py @@ -54,7 +54,10 @@ def post(self, request, token): StudentController.populate_user_course_unit_data(int(participant.participant_nmec), erase_previous=True) if direct_exchange.marketplace_exchange: - direct_exchange.marketplace_exchange.delete() + marketplace_exchange = direct_exchange.marketplace_exchange + direct_exchange.marketplace_exchange = None + direct_exchange.save() + marketplace_exchange.delete() ExchangeValidationController().cancel_conflicting_exchanges(int(exchange_info["exchange_id"])) From 1da0db4cbdddcd590d37ea2d095ebbb92ba4e97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 17:12:30 +0000 Subject: [PATCH 19/25] fix: enrollment validation --- .../university/routes/course_unit/CourseUnitEnrollmentView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django/university/routes/course_unit/CourseUnitEnrollmentView.py b/django/university/routes/course_unit/CourseUnitEnrollmentView.py index 953a436..cc5940f 100644 --- a/django/university/routes/course_unit/CourseUnitEnrollmentView.py +++ b/django/university/routes/course_unit/CourseUnitEnrollmentView.py @@ -93,7 +93,7 @@ def post(self, request): for enrollment in enrollments: enrollment_metadata = json.loads(enrollment) - if len(list(CourseUnitEnrollmentOptions.objects.filter(course_unit__id=int(enrollment_metadata["course_unit_id"]), enrolling=enrollment_metadata["enrolling"]))) > 0: + if len(list(CourseUnitEnrollmentOptions.objects.filter(course_unit__id=int(enrollment_metadata["course_unit_id"]), course_unit_enrollment__user_nmec=request.user.username, enrolling=enrollment_metadata["enrolling"]))) > 0: return JsonResponse({"error": "Não podes fazer pedidos com disciplinas em que já pediste noutros!"}, status=400) if enrollment_metadata["enrolling"] and len(list(filter(lambda x: int(x.course_unit_id) == int(enrollment_metadata["course_unit_id"]), student_course_units))) > 0: From 6a5df3c57a4449a597a55703a3e412220c3626a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 19:54:21 +0000 Subject: [PATCH 20/25] fix: temporarily remove hashes --- django/university/routes/MarketplaceExchangeView.py | 8 ++++---- django/university/routes/exchange/DirectExchangeView.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/django/university/routes/MarketplaceExchangeView.py b/django/university/routes/MarketplaceExchangeView.py index a59c70e..212c448 100644 --- a/django/university/routes/MarketplaceExchangeView.py +++ b/django/university/routes/MarketplaceExchangeView.py @@ -145,11 +145,11 @@ def submit_marketplace_exchange_request(self, request): exchange_data_str = json.dumps(exchanges, sort_keys=True) exchange_hash = hashlib.sha256(exchange_data_str.encode('utf-8')).hexdigest() - if MarketplaceExchange.objects.filter(hash=exchange_hash).exists(): - return JsonResponse({"error": "duplicate-request"}, status=400, safe=False) + # if MarketplaceExchange.objects.filter(hash=exchange_hash).exists(): + # return JsonResponse({"error": "duplicate-request"}, status=400, safe=False) - if ExchangeUrgentRequests.objects.filter(hash=exchange_hash).exists(): - return JsonResponse({"error": "duplicate-request"}, status=400, safe=False) + # if ExchangeUrgentRequests.objects.filter(hash=exchange_hash).exists(): + # return JsonResponse({"error": "duplicate-request"}, status=400, safe=False) if urgentMessage: return self.add_urgent_exchange(request, exchanges, urgentMessage, exchange_hash) diff --git a/django/university/routes/exchange/DirectExchangeView.py b/django/university/routes/exchange/DirectExchangeView.py index 3e63f5e..0cc11ac 100644 --- a/django/university/routes/exchange/DirectExchangeView.py +++ b/django/university/routes/exchange/DirectExchangeView.py @@ -125,8 +125,8 @@ def post(self, request): exchange_data_str = json.dumps(exchanges, sort_keys=True) exchange_hash = hashlib.sha256(exchange_data_str.encode('utf-8')).hexdigest() - if DirectExchange.objects.filter(hash=exchange_hash).exists(): - return JsonResponse({"error": "duplicate-request"}, status=400, safe=False) + # if DirectExchange.objects.filter(hash=exchange_hash).exists(): + # return JsonResponse({"error": "duplicate-request"}, status=400, safe=False) with transaction.atomic(): exchange_model = DirectExchange( From 2d427d674ae9090e24c9ade106028a9fbe299123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 20:53:20 +0000 Subject: [PATCH 21/25] fix: urgent message no conflicts --- django/university/routes/MarketplaceExchangeView.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/django/university/routes/MarketplaceExchangeView.py b/django/university/routes/MarketplaceExchangeView.py index 212c448..341b2c4 100644 --- a/django/university/routes/MarketplaceExchangeView.py +++ b/django/university/routes/MarketplaceExchangeView.py @@ -134,13 +134,14 @@ def submit_marketplace_exchange_request(self, request): student_schedule = list(student_schedules[curr_student].values()) ExchangeController.update_schedule_accepted_exchanges(curr_student, student_schedule) student_schedules[curr_student] = build_student_schedule_dict(student_schedule) - + (status, new_marketplace_schedule) = build_marketplace_submission_schedule(student_schedules, exchanges, curr_student) if status == ExchangeStatus.STUDENTS_NOT_ENROLLED: return JsonResponse({"error": incorrect_class_error()}, status=400, safe=False) - if ExchangeController.exchange_overlap(student_schedules, curr_student): - return JsonResponse({"error": "classes-overlap"}, status=400, safe=False) + if not urgentMessage or urgentMessage == "": + if ExchangeController.exchange_overlap(student_schedules, curr_student): + return JsonResponse({"error": "classes-overlap"}, status=400, safe=False) exchange_data_str = json.dumps(exchanges, sort_keys=True) exchange_hash = hashlib.sha256(exchange_data_str.encode('utf-8')).hexdigest() From 874845d60f7f0ab1c56e4d5563187e28f3f13724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 23:02:56 +0000 Subject: [PATCH 22/25] fix: some exchange view request crashing --- .../university/serializers/ExchangeUrgentRequestSerializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django/university/serializers/ExchangeUrgentRequestSerializer.py b/django/university/serializers/ExchangeUrgentRequestSerializer.py index 17baf45..ef7774a 100644 --- a/django/university/serializers/ExchangeUrgentRequestSerializer.py +++ b/django/university/serializers/ExchangeUrgentRequestSerializer.py @@ -33,7 +33,7 @@ def get_course_unit(self, obj): return None def get_class_user_goes_from(self, obj): - class_issuer_id = obj.class_user_goes_from + class_issuer_id = obj.class_user_goes_from.split("+")[0] classes = ClassController.get_classes(obj.course_unit_id) filtered_classes = list(filter(lambda x: x['name'] == class_issuer_id, classes)) From e847455c6ff6bfc282dee0222b15ee1503a7a217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Sun, 9 Feb 2025 23:07:20 +0000 Subject: [PATCH 23/25] fix: some exchange view request crashing --- .../university/serializers/ExchangeUrgentRequestSerializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django/university/serializers/ExchangeUrgentRequestSerializer.py b/django/university/serializers/ExchangeUrgentRequestSerializer.py index ef7774a..40001c7 100644 --- a/django/university/serializers/ExchangeUrgentRequestSerializer.py +++ b/django/university/serializers/ExchangeUrgentRequestSerializer.py @@ -43,7 +43,7 @@ def get_class_user_goes_from(self, obj): return None def get_class_user_goes_to(self, obj): - class_issuer_id = obj.class_user_goes_to + class_issuer_id = obj.class_user_goes_to.split("+")[0] classes = ClassController.get_classes(obj.course_unit_id) filtered_classes = list(filter(lambda x: x['name'] == class_issuer_id, classes)) From 413a49f107f8455a89b84c2922f80e5ad5540da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Mon, 10 Feb 2025 18:08:37 +0000 Subject: [PATCH 24/25] feat: show marketplace requests --- .../routes/exchange/AdminMarketplaceView.py | 87 +++++++++++++++++++ .../MarketplaceExchangeClassSerializer.py | 9 ++ django/university/urls.py | 2 + postgres/sql/00_schema_postgres.sql | 7 +- scripts/marketplace/mock_data.sql | 1 - 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 django/university/routes/exchange/AdminMarketplaceView.py diff --git a/django/university/routes/exchange/AdminMarketplaceView.py b/django/university/routes/exchange/AdminMarketplaceView.py new file mode 100644 index 0000000..79222b2 --- /dev/null +++ b/django/university/routes/exchange/AdminMarketplaceView.py @@ -0,0 +1,87 @@ +from django.http import JsonResponse +from django.views import View + +from django.core.paginator import Paginator + +from django.db.models import Prefetch + +from university.serializers.MarketplaceExchangeClassSerializer import MarketplaceExchangeClassSerializer + +from university.models import MarketplaceExchange, DirectExchange + +from university.controllers.ExchangeController import ExchangeController +from university.controllers.CourseUnitController import CourseUnitController +from university.controllers.AdminRequestFiltersController import AdminRequestFiltersController + +class AdminMarketplaceView(View): + def __init__(self): + self.filter_actions = { + "activeCourse": self.filter_active_course, + "activeCurricularYear": self.filter_active_curricular_year, + "activeStates": self.filter_active_state + } + + def filter_active_course(self, exchanges, major_id): + return list( + filter( + lambda exchange: len(list( + filter( + lambda course_unit: int(CourseUnitController.course_unit_major(course_unit.get("course_unit").get("id"))) == int(major_id), exchange.get("options")) + )) > 0, + exchanges + ) + ) + + def filter_active_curricular_year(self, exchanges, curricular_year): + return list( + filter( + lambda exchange: len(list( + filter( + lambda course_unit: int(CourseUnitController.course_unit_curricular_year(course_unit.get("course_unit").get("id"))) == int(curricular_year), exchange.get("options")) + )) > 0, + exchanges + ) + ) + + def filter_active_state(self, exchanges, state): + states = state.split(",") + return list( + filter( + lambda exchange: exchange.get("admin_state") in states, + exchanges + ) + ) + + def get(self, request): + exchanges = MarketplaceExchange.objects.prefetch_related( + Prefetch( + 'marketplaceexchangeclass_set', + to_attr='options' + )).all() + + paginator = Paginator(exchanges, 10) + page = request.GET.get('page') + page_obj = paginator.get_page(page) + + exchanges = [{ + "id": exchange.id, + "type": "marketplaceexchange", + "issuer_name": exchange.issuer_name, + "issuer_nmec": exchange.issuer_nmec, + "options": [ + MarketplaceExchangeClassSerializer(exchange_class).data for exchange_class in exchange.options + ], + "classes": list(ExchangeController.getExchangeOptionClasses(exchange.options)), + "date": exchange.date, + "admin_state": exchange.admin_state, + "accepted": exchange.accepted + } for exchange in page_obj if not DirectExchange.objects.filter(marketplace_exchange=exchange).exists()] + + for filter in AdminRequestFiltersController.filter_values(): + if request.GET.get(filter): + exchanges = self.filter_actions[filter](exchanges, request.GET.get(filter)) + + return JsonResponse({ + "exchanges": exchanges, + "total_pages": paginator.num_pages + }, safe = False) \ No newline at end of file diff --git a/django/university/serializers/MarketplaceExchangeClassSerializer.py b/django/university/serializers/MarketplaceExchangeClassSerializer.py index dc64239..5a8a887 100644 --- a/django/university/serializers/MarketplaceExchangeClassSerializer.py +++ b/django/university/serializers/MarketplaceExchangeClassSerializer.py @@ -4,6 +4,15 @@ from university.models import CourseUnit from university.controllers.ClassController import ClassController +class MarketplaceExchangeSerializer(serializers.Serializer): + issuer_nmec = serializers.CharField(max_length=32) + issuer_name = serializers.CharField(max_length=256) + accepted = serializers.BooleanField() + canceled = serializers.BooleanField() + admin_state = serializers.CharField(max_length=32) + hash = serializers.CharField(max_length=64) + date = serializers.DateTimeField() + class MarketplaceExchangeClassSerializer(serializers.Serializer): course_info = serializers.SerializerMethodField() class_issuer_goes_from = serializers.SerializerMethodField() diff --git a/django/university/urls.py b/django/university/urls.py index 892bc3c..1b71a91 100644 --- a/django/university/urls.py +++ b/django/university/urls.py @@ -1,6 +1,7 @@ from django.urls import path, include from university.routes.course_unit.CourseUnitEnrollmentView import CourseUnitEnrollmentView +from university.routes.exchange.AdminMarketplaceView import AdminMarketplaceView from university.routes.MarketplaceExchangeView import MarketplaceExchangeView from university.routes.auth.Csrf import Csrf from university.routes.exchange.DirectExchangeView import DirectExchangeView @@ -64,6 +65,7 @@ path('course_unit/enrollment/', CourseUnitEnrollmentView.as_view()), path('oidc-auth/', include('mozilla_django_oidc.urls')), path('exchange/admin/courses/', exchange_admin_required(AdminExchangeCoursesView.as_view())), + path('exchange/admin/marketplace', exchange_admin_required(AdminMarketplaceView.as_view())), path('exchange/admin/request///reject/', exchange_admin_required(AdminExchangeRequestRejectView.as_view())), path('exchange/admin/request///accept/', exchange_admin_required(AdminExchangeRequestAcceptView.as_view())), path('exchange/admin/request///awaiting-information/', exchange_admin_required(AdminRequestAwaitingInformationView.as_view())), diff --git a/postgres/sql/00_schema_postgres.sql b/postgres/sql/00_schema_postgres.sql index 998aa28..63fafe4 100644 --- a/postgres/sql/00_schema_postgres.sql +++ b/postgres/sql/00_schema_postgres.sql @@ -181,7 +181,8 @@ CREATE TABLE "public"."marketplace_exchange" ( "accepted" boolean NOT NULL, "canceled" boolean DEFAULT false, "date" TIMESTAMP DEFAULT now(), - "hash" varchar(64) UNIQUE + "admin_state" varchar(32) NOT NULL DEFAULT 'untreated', + "hash" varchar(64) ); CREATE TABLE "public"."direct_exchange" ( @@ -193,7 +194,7 @@ CREATE TABLE "public"."direct_exchange" ( "date" TIMESTAMP DEFAULT now(), "admin_state" varchar(32) NOT NULL DEFAULT 'untreated', "marketplace_exchange" INTEGER REFERENCES "public"."marketplace_exchange"("id"), - "hash" varchar(64) UNIQUE + "hash" varchar(64) ); CREATE TABLE "public"."direct_exchange_participants" ( @@ -258,7 +259,7 @@ CREATE TABLE "public"."exchange_urgent_requests" ( "accepted" boolean DEFAULT false, "admin_state" varchar(32) NOT NULL DEFAULT 'untreated', "date" TIMESTAMP DEFAULT now(), - "hash" varchar(64) UNIQUE + "hash" varchar(64) ); CREATE TABLE "public"."exchange_urgent_request_options" ( diff --git a/scripts/marketplace/mock_data.sql b/scripts/marketplace/mock_data.sql index 3f95b9e..1e6e7a7 100644 --- a/scripts/marketplace/mock_data.sql +++ b/scripts/marketplace/mock_data.sql @@ -32,7 +32,6 @@ INSERT INTO direct_exchange_participants (id, participant_name, participant_nmec INSERT INTO direct_exchange_participants (id, participant_name, participant_nmec, class_participant_goes_from, class_participant_goes_to, course_unit, course_unit_id, direct_exchange, accepted) VALUES (5, 'Armindo Osório', 202108880, '1MEIC01', '1MEIC06', 'DS', 540677, 2, true); INSERT INTO direct_exchange_participants (id, participant_name, participant_nmec, class_participant_goes_from, class_participant_goes_to, course_unit, course_unit_id, direct_exchange, accepted) VALUES (6, 'José Santos', 202109260, '1MEIC06', '1MEIC01', 'DS', 540677, 2, true); - INSERT INTO exchange_admin(id, username) VALUES (1, '202109260'); --INSERT INTO marketplace_exchange (id, issuer_name, issuer_nmec, accepted) VALUES (1, 'Armindo Santos', '202108881', false); From 2935c591c4725f00fdfcddfc9a8c54253c46a098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Palma?= Date: Tue, 11 Feb 2025 13:40:40 +0000 Subject: [PATCH 25/25] fix: null class --- .../serializers/MarketplaceExchangeClassSerializer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django/university/serializers/MarketplaceExchangeClassSerializer.py b/django/university/serializers/MarketplaceExchangeClassSerializer.py index 5a8a887..19372a0 100644 --- a/django/university/serializers/MarketplaceExchangeClassSerializer.py +++ b/django/university/serializers/MarketplaceExchangeClassSerializer.py @@ -27,7 +27,7 @@ def get_course_info(self, obj): return None def get_class_issuer_goes_from(self, obj): - class_issuer_id = obj.class_issuer_goes_from + class_issuer_id = obj.class_issuer_goes_from.split("+")[0] classes = ClassController.get_classes(obj.course_unit_id) filtered_classes = list(filter(lambda x: x['name'] == class_issuer_id, classes)) try: @@ -36,7 +36,7 @@ def get_class_issuer_goes_from(self, obj): return None def get_class_issuer_goes_to(self, obj): - class_issuer_id = obj.class_issuer_goes_to + class_issuer_id = obj.class_issuer_goes_to.split("+")[0] classes = ClassController.get_classes(obj.course_unit_id) filtered_classes = list(filter(lambda x: x['name'] == class_issuer_id, classes)) try: