Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Main #205

Merged
merged 57 commits into from
Feb 13, 2025
Merged

Main #205

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
281c458
Merge pull request #73 from NIAEFEUP/develop
LuisDuarte1 Jan 28, 2024
2e85bb4
Merge pull request #98 from NIAEFEUP/develop
tomaspalma Aug 24, 2024
9aac67d
Merge pull request #105 from NIAEFEUP/develop
tomaspalma Aug 25, 2024
f98619a
Merge pull request #107 from NIAEFEUP/develop
tomaspalma Aug 25, 2024
8cce50c
Merge pull request #172 from NIAEFEUP/develop
tomaspalma Feb 6, 2025
070e149
Merge pull request #176 from NIAEFEUP/develop
tomaspalma Feb 7, 2025
b422a14
Merge pull request #178 from NIAEFEUP/develop
tomaspalma Feb 7, 2025
067387c
Merge pull request #180 from NIAEFEUP/develop
tomaspalma Feb 7, 2025
8ab0a7d
Merge pull request #181 from NIAEFEUP/develop
tomaspalma Feb 7, 2025
cbdb1b7
fix: 500 error code course units
tomaspalma Feb 7, 2025
93633ec
Merge pull request #182 from NIAEFEUP/fix/500-error-code-course-units
tomaspalma Feb 7, 2025
e01287f
fix: course units not appearing
tomaspalma Feb 7, 2025
e8f1e5a
Merge pull request #183 from NIAEFEUP/fix/course-units-not-appearing
tomaspalma Feb 7, 2025
edd3379
fix: wrong tp classes
tomaspalma Feb 7, 2025
61fc0e4
Merge branch 'main' into fix/classes
tomaspalma Feb 7, 2025
3a355d2
Merge pull request #184 from NIAEFEUP/fix/classes
tomaspalma Feb 7, 2025
d718d7e
fix: server crashing sometimes
tomaspalma Feb 7, 2025
0d70479
Merge pull request #185 from NIAEFEUP/fix/server-crashing-sometimes
tomaspalma Feb 7, 2025
fd46699
fix: removed asgi for now
tomaspalma Feb 7, 2025
d609a2b
temporary remove asgi
tomaspalma Feb 7, 2025
d1e7a4e
Merge pull request #186 from NIAEFEUP/fix/temporary-remove-asgi
tomaspalma Feb 7, 2025
de52aa7
fix: wrong student not enrolled
tomaspalma Feb 8, 2025
653e549
Merge pull request #187 from NIAEFEUP/fix/wrong-student-not-enrolled
tomaspalma Feb 8, 2025
d969c1b
fix: bandage to profissional communication issue
tomaspalma Feb 8, 2025
c15088b
Merge pull request #188 from NIAEFEUP/hotfix/bandage-to-profissional-…
tomaspalma Feb 8, 2025
08c5c3f
Start resolving conflicts on original schedule
Process-ing Feb 8, 2025
272e981
fix: conflicts only with new classes
tomaspalma Feb 8, 2025
e9ac9da
Merge pull request #189 from NIAEFEUP/fix/original-schedule-conflicts
tomaspalma Feb 8, 2025
395c99e
fix: slow admin request fetching
tomaspalma Feb 8, 2025
69c6882
Merge pull request #190 from NIAEFEUP/fix/slow-admin-request-fetching
tomaspalma Feb 8, 2025
8277da0
fix: enrollments cannot be empty and not duplicated
tomaspalma Feb 8, 2025
bed77b3
Merge pull request #191 from NIAEFEUP/fix/course-unit-enrollment-issues
tomaspalma Feb 8, 2025
2a51f4d
fix: enrollments speed
tomaspalma Feb 8, 2025
1017923
Merge pull request #192 from NIAEFEUP/fix/enrollments-speed
tomaspalma Feb 8, 2025
54a81b5
fix: admin exchange speed
tomaspalma Feb 8, 2025
8718f70
Merge pull request #193 from NIAEFEUP/fix/admin-exchange-speed
tomaspalma Feb 8, 2025
f7ae0b2
fix: decrease documents per page
tomaspalma Feb 9, 2025
63a46cc
Merge pull request #195 from NIAEFEUP/fix/decrease-documents-per-page
tomaspalma Feb 9, 2025
ea563f3
fix: faulty conflict logic
tomaspalma Feb 9, 2025
f406e48
Merge pull request #196 from NIAEFEUP/fix/faulty-conflict-logic
tomaspalma Feb 9, 2025
3e25ff1
fix: faulty validation direct exchange logic
tomaspalma Feb 9, 2025
b0d870f
Merge pull request #197 from NIAEFEUP/fix/faulty-validation-direct-ex…
tomaspalma Feb 9, 2025
f5447b4
fix: unable to accept direct exchanges from marketplace
tomaspalma Feb 9, 2025
1530a4d
Merge pull request #198 from NIAEFEUP/fix/unable-to-accept-direct-exc…
tomaspalma Feb 9, 2025
1da0db4
fix: enrollment validation
tomaspalma Feb 9, 2025
e1cdb72
Merge pull request #199 from NIAEFEUP/fix/enrollment-validation
tomaspalma Feb 9, 2025
6a5df3c
fix: temporarily remove hashes
tomaspalma Feb 9, 2025
7fd826a
Merge pull request #200 from NIAEFEUP/fix/temporarily-remove-hashes
tomaspalma Feb 9, 2025
2d427d6
fix: urgent message no conflicts
tomaspalma Feb 9, 2025
2d238fd
Merge pull request #201 from NIAEFEUP/fix/urgent-message-no-conflicts
tomaspalma Feb 9, 2025
874845d
fix: some exchange view request crashing
tomaspalma Feb 9, 2025
e847455
fix: some exchange view request crashing
tomaspalma Feb 9, 2025
765b321
Merge pull request #202 from NIAEFEUP/fix/some-exchange-view-request-…
tomaspalma Feb 9, 2025
413a49f
feat: show marketplace requests
tomaspalma Feb 10, 2025
ad13085
Merge pull request #203 from NIAEFEUP/feat/show-marketplace-requests
tomaspalma Feb 10, 2025
2935c59
fix: null class
tomaspalma Feb 11, 2025
2dc2566
Merge pull request #204 from NIAEFEUP/fix/null-class
tomaspalma Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions django/tts_be/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
import os
from django.core.asgi import get_asgi_application

import socketio
from university.socket.views import sessions_server
# 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()
6 changes: 2 additions & 4 deletions django/tts_be/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
INSTALLED_APPS = [
'corsheaders',
'anymail',
'daphne',
# 'daphne',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand All @@ -84,7 +84,7 @@
'django.contrib.staticfiles',
'mozilla_django_oidc',
'university',
'channels',
# 'channels',
]

EMAIL_HOST = os.getenv("EMAIL_HOST", "tts-mailpit")
Expand Down Expand Up @@ -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

Expand Down
12 changes: 10 additions & 2 deletions django/university/controllers/CourseUnitController.py
Original file line number Diff line number Diff line change
@@ -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
27 changes: 23 additions & 4 deletions django/university/controllers/ExchangeController.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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:
Expand All @@ -153,9 +153,28 @@ 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'])

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

Expand Down
14 changes: 9 additions & 5 deletions django/university/controllers/ExchangeValidationController.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand All @@ -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)))

Expand Down Expand Up @@ -72,17 +76,17 @@ 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():
participant_entries = list(exchange_participants.filter(participant_nmec=username))

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
Expand Down
5 changes: 3 additions & 2 deletions django/university/controllers/StudentController.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion django/university/controllers/StudentScheduleController.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion django/university/exchange/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
20 changes: 11 additions & 9 deletions django/university/routes/MarketplaceExchangeView.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -133,22 +134,23 @@ 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 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()

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)
Expand Down
27 changes: 18 additions & 9 deletions django/university/routes/course_unit/CourseUnitEnrollmentView.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
)
Expand All @@ -56,16 +56,18 @@ 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')))

paginator = Paginator(enrollments, 48)
page_number = request.GET.get("page")
enrollments = [x for x in paginator.get_page(page_number if page_number != None else 1)]
enrollments = CourseUnitEnrollments.objects.all().order_by('date')

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({
"enrollments": enrollments,
"total_pages": paginator.num_pages
Expand All @@ -74,22 +76,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"]), 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:
return JsonResponse({"error": "Não te podes inscrever a disciplinas em que já tens uma inscrição!"}, status=400)

db_enrollment = CourseUnitEnrollmentOptions(
Expand All @@ -100,6 +107,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)
Loading
Loading