diff --git a/backend/api/serializers/group_serializer.py b/backend/api/serializers/group_serializer.py index e929b1cc..ae2e474f 100644 --- a/backend/api/serializers/group_serializer.py +++ b/backend/api/serializers/group_serializer.py @@ -7,6 +7,7 @@ from api.serializers.project_serializer import ProjectSerializer from api.serializers.student_serializer import StudentIDSerializer from django.utils.translation import gettext +from notifications.signals import NotificationType, notification_create from rest_framework import serializers from rest_framework.exceptions import ValidationError diff --git a/backend/api/serializers/project_serializer.py b/backend/api/serializers/project_serializer.py index b4493229..caa2cec9 100644 --- a/backend/api/serializers/project_serializer.py +++ b/backend/api/serializers/project_serializer.py @@ -2,6 +2,7 @@ from api.models.group import Group from api.models.project import Project from api.models.submission import Submission, ExtraCheckResult, StructureCheckResult, StateEnum +from api.models.checks import ExtraCheck, StructureCheck from api.serializers.course_serializer import CourseSerializer from django.core.files.uploadedfile import InMemoryUploadedFile from django.utils import timezone @@ -33,6 +34,22 @@ def to_representation(self, instance: Project): if (groups_submitted > non_empty_groups): non_empty_groups = groups_submitted + extra_checks_count = instance.extra_checks.count() + + if extra_checks_count: + passed_extra_checks_submission_ids = ExtraCheckResult.objects.filter( + submission__group__project=instance, + submission__is_valid=True, + result=StateEnum.SUCCESS + ).values_list('submission__id', flat=True) + + passed_extra_checks_group_ids = Submission.objects.filter( + id__in=passed_extra_checks_submission_ids + ).values_list('group_id', flat=True) + + unique_groups = set(passed_extra_checks_group_ids) + extra_checks_passed = len(unique_groups) + passed_structure_checks_submission_ids = StructureCheckResult.objects.filter( submission__group__project=instance, submission__is_valid=True, @@ -46,18 +63,12 @@ def to_representation(self, instance: Project): unique_groups = set(passed_structure_checks_group_ids) structure_checks_passed = len(unique_groups) - passed_extra_checks_submission_ids = ExtraCheckResult.objects.filter( - submission__group__project=instance, - submission__is_valid=True, - result=StateEnum.SUCCESS - ).values_list('submission__id', flat=True) - - passed_extra_checks_group_ids = Submission.objects.filter( - id__in=passed_extra_checks_submission_ids - ).values_list('group_id', flat=True) + # If there are no extra checks, we can set extra_checks_passed equal to structure_checks_passed + if not extra_checks_count: + extra_checks_passed = structure_checks_passed - unique_groups = set(passed_extra_checks_group_ids) - extra_checks_passed = len(unique_groups) + # If the extra checks succeed, the structure checks also succeed + structure_checks_passed -= extra_checks_passed # The total number of passed extra checks combined with the number of passed structure checks # can never exceed the total number of submissions (the seeder does not account for this restriction) diff --git a/backend/api/signals.py b/backend/api/signals.py index b705255a..234e3dfd 100644 --- a/backend/api/signals.py +++ b/backend/api/signals.py @@ -14,6 +14,7 @@ from authentication.signals import user_created from django.db.models.signals import post_delete, post_save from django.dispatch import Signal, receiver +from notifications.signals import NotificationType, notification_create # Signals @@ -113,6 +114,13 @@ def hook_submission(sender, instance: Submission, created: bool, **kwargs): run_all_checks.send(sender=Submission, submission=instance) pass + notification_create.send( + sender=Submission, + type=NotificationType.SUBMISSION_RECEIVED, + queryset=list(instance.group.students.all()), + arguments={} + ) + @receiver(post_save, sender=DockerImage) def hook_docker_image(sender, instance: DockerImage, created: bool, **kwargs): diff --git a/backend/api/tasks/docker_image.py b/backend/api/tasks/docker_image.py index cf614a0d..9109f874 100644 --- a/backend/api/tasks/docker_image.py +++ b/backend/api/tasks/docker_image.py @@ -3,6 +3,7 @@ from api.logic.get_file_path import get_docker_image_tag from api.models.docker import DockerImage, StateEnum from celery import shared_task +from notifications.signals import NotificationType, notification_create from ypovoli.settings import MEDIA_ROOT @@ -13,6 +14,8 @@ def task_docker_image_build(docker_image: DockerImage): docker_image.state = StateEnum.BUILDING docker_image.save() + notification_type = NotificationType.DOCKER_IMAGE_BUILD_SUCCESS + # Build the image try: client = docker.from_env() @@ -21,7 +24,26 @@ def task_docker_image_build(docker_image: DockerImage): docker_image.state = StateEnum.READY except (docker.errors.APIError, docker.errors.BuildError, docker.errors.APIError, TypeError): docker_image.state = StateEnum.ERROR - # TODO: Sent notification + notification_type = NotificationType.DOCKER_IMAGE_BUILD_ERROR + finally: + # Update the state + docker_image.save() # Update the state docker_image.save() + # Send notification + notification_create.send( + sender=DockerImage, + type=notification_type, + queryset=[docker_image.owner], + arguments={"name": docker_image.name}, + ) + + +@shared_task +def task_docker_image_remove(docker_image: DockerImage): + try: + client = docker.from_env() + client.images.remove(get_docker_image_tag(docker_image)) + except docker.errors.APIError: + pass diff --git a/backend/api/tasks/extra_check.py b/backend/api/tasks/extra_check.py index 7ad94afc..8ace1794 100644 --- a/backend/api/tasks/extra_check.py +++ b/backend/api/tasks/extra_check.py @@ -14,6 +14,7 @@ from django.core.files.base import ContentFile from docker.models.containers import Container from docker.types import LogConfig +from notifications.signals import NotificationType, notification_create from requests.exceptions import ConnectionError @@ -33,12 +34,22 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext extra_check_result.error_message = ErrorMessageEnum.DOCKER_IMAGE_ERROR extra_check_result.save() + notification_create.send( + sender=ExtraCheckResult, + type=NotificationType.EXTRA_CHECK_FAIL, + queryset=list(extra_check_result.submission.group.students.all()), + arguments={"name": extra_check_result.extra_check.name}, + ) + return structure_check_result # Will probably never happen but doesn't hurt to check while extra_check_result.submission.running_checks: sleep(1) + # Notification type + notification_type = NotificationType.EXTRA_CHECK_SUCCESS + # Lock extra_check_result.submission.running_checks = True @@ -104,41 +115,49 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext case 1: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.CHECK_ERROR + notification_type = NotificationType.EXTRA_CHECK_FAIL # Time limit case 2: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.TIME_LIMIT + notification_type = NotificationType.EXTRA_CHECK_FAIL # Memory limit case 3: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.MEMORY_LIMIT + notification_type = NotificationType.EXTRA_CHECK_FAIL # Catch all non zero exit codes case _: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.RUNTIME_ERROR + notification_type = NotificationType.EXTRA_CHECK_FAIL # Docker image error except (docker.errors.APIError, docker.errors.ImageNotFound): extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.DOCKER_IMAGE_ERROR + notification_type = NotificationType.EXTRA_CHECK_FAIL # Runtime error except docker.errors.ContainerError: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.RUNTIME_ERROR + notification_type = NotificationType.EXTRA_CHECK_FAIL # Timeout error except ConnectionError: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.TIME_LIMIT + notification_type = NotificationType.EXTRA_CHECK_FAIL # Unknown error except Exception: extra_check_result.result = StateEnum.FAILED extra_check_result.error_message = ErrorMessageEnum.UNKNOWN + notification_type = NotificationType.EXTRA_CHECK_FAIL # Cleanup and data saving finally: @@ -155,6 +174,27 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext extra_check_result.log_file.save(submission_uuid, content=ContentFile(logs), save=False) extra_check_result.save() + # Send notification + notification_create.send( + sender=ExtraCheckResult, + type=notification_type, + queryset=list(extra_check_result.submission.group.students.all()), + arguments={"name": extra_check_result.extra_check.name}, + ) + + # Zip and save any possible artifacts + memory_zip = io.BytesIO() + if os.listdir(artifacts_directory): + with zipfile.ZipFile(memory_zip, 'w') as zip: + for root, _, files in os.walk(artifacts_directory): + for file in files: + zip.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), artifacts_directory)) + + memory_zip.seek(0) + extra_check_result.artifact.save(submission_uuid, ContentFile(memory_zip.read()), False) + + extra_check_result.save() + # Remove directory try: shutil.rmtree(submission_directory) diff --git a/backend/api/tasks/structure_check.py b/backend/api/tasks/structure_check.py index 8adce52a..d22cd866 100644 --- a/backend/api/tasks/structure_check.py +++ b/backend/api/tasks/structure_check.py @@ -5,6 +5,7 @@ from api.models.submission import (ErrorMessageEnum, StateEnum, StructureCheckResult) from celery import shared_task +from notifications.signals import NotificationType, notification_create @shared_task() @@ -19,6 +20,9 @@ def task_structure_check_start(structure_check_results: list[StructureCheckResul # Lock structure_check_results[0].submission.running_checks = True + # Notification type + notification_type = NotificationType.STRUCTURE_CHECK_SUCCESS + all_checks_passed = True # Boolean to check if all structure checks passed name_ext = _get_all_name_ext(structure_check_results[0].submission.zip.path) # Dict with file name and extension @@ -38,6 +42,7 @@ def task_structure_check_start(structure_check_results: list[StructureCheckResul if len(extensions) == 0: structure_check_result.result = StateEnum.FAILED structure_check_result.error_message = ErrorMessageEnum.FILE_DIR_NOT_FOUND + notification_type = NotificationType.STRUCTURE_CHECK_FAIL # Check if no blocked extension is present if structure_check_result.result == StateEnum.SUCCESS: @@ -45,6 +50,7 @@ def task_structure_check_start(structure_check_results: list[StructureCheckResul if extension.extension in extensions: structure_check_result.result = StateEnum.FAILED structure_check_result.error_message = ErrorMessageEnum.BLOCKED_EXTENSION + notification_type = NotificationType.STRUCTURE_CHECK_FAIL # Check if all obligated extensions are present if structure_check_result.result == StateEnum.SUCCESS: @@ -52,6 +58,7 @@ def task_structure_check_start(structure_check_results: list[StructureCheckResul if extension.extension not in extensions: structure_check_result.result = StateEnum.FAILED structure_check_result.error_message = ErrorMessageEnum.OBLIGATED_EXTENSION_NOT_FOUND + notification_type = NotificationType.STRUCTURE_CHECK_FAIL all_checks_passed = all_checks_passed and structure_check_result.result == StateEnum.SUCCESS structure_check_result.save() @@ -59,6 +66,14 @@ def task_structure_check_start(structure_check_results: list[StructureCheckResul # Release structure_check_results[0].submission.running_checks = False + # Send notification + notification_create.send( + sender=StructureCheckResult, + type=notification_type, + queryset=list(structure_check_results[0].submission.group.students.all()), + arguments={}, + ) + return all_checks_passed diff --git a/backend/api/views/group_view.py b/backend/api/views/group_view.py index c3595f4d..c85fea46 100644 --- a/backend/api/views/group_view.py +++ b/backend/api/views/group_view.py @@ -9,6 +9,7 @@ from api.serializers.submission_serializer import SubmissionSerializer from django.utils.translation import gettext from drf_yasg.utils import swagger_auto_schema +from notifications.signals import NotificationType, notification_create from rest_framework.decorators import action from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin) @@ -28,6 +29,22 @@ class GroupViewSet(CreateModelMixin, serializer_class = GroupSerializer permission_classes = [IsAdminUser | GroupPermission] + def update(self, request, *args, **kwargs): + old_group = self.get_object() + response = super().update(request, *args, **kwargs) + if response.status_code == 200: + new_group = self.get_object() + if "score" in request.data and old_group.score != new_group.score: + # Partial updates end up in the update function as well + notification_create.send( + sender=Group, + type=NotificationType.SCORE_UPDATED, + queryset=list(new_group.students.all()), + arguments={"score": str(new_group.score)}, + ) + + return response + @action(detail=True, methods=["get"], permission_classes=[IsAdminUser | GroupStudentPermission]) def students(self, request, **_): """Returns a list of students for the given group""" diff --git a/backend/notifications/fixtures/realistic/realistic.yaml b/backend/notifications/fixtures/realistic/realistic.yaml index e69de29b..0e37a039 100644 --- a/backend/notifications/fixtures/realistic/realistic.yaml +++ b/backend/notifications/fixtures/realistic/realistic.yaml @@ -0,0 +1,45 @@ +- model: notifications.notificationtemplate + pk: 1 + fields: + title_key: "Title: Score added" + description_key: "Description: Score added %(score)s" +- model: notifications.notificationtemplate + pk: 2 + fields: + title_key: "Title: Score updated" + description_key: "Description: Score updated %(score)s" +- model: notifications.notificationtemplate + pk: 3 + fields: + title_key: "Title: Docker image build success" + description_key: "Description: Docker image build success %(name)s" +- model: notifications.notificationtemplate + pk: 4 + fields: + title_key: "Title: Docker image build error" + description_key: "Description: Docker image build error %(name)s" +- model: notifications.notificationtemplate + pk: 5 + fields: + title_key: "Title: Extra check success" + description_key: "Description: Extra check success %(name)s" +- model: notifications.notificationtemplate + pk: 6 + fields: + title_key: "Title: Extra check error" + description_key: "Description: Extra check error %(name)s" +- model: notifications.notificationtemplate + pk: 7 + fields: + title_key: "Title: Structure checks success" + description_key: "Description: Structure checks success" +- model: notifications.notificationtemplate + pk: 8 + fields: + title_key: "Title: Structure checks error" + description_key: "Description: Structure checks" +- model: notifications.notificationtemplate + pk: 9 + fields: + title_key: "Title: Submission received" + description_key: "Description: Submission received" diff --git a/backend/notifications/locale/en/LC_MESSAGES/django.po b/backend/notifications/locale/en/LC_MESSAGES/django.po index 465520e9..d9ee882e 100644 --- a/backend/notifications/locale/en/LC_MESSAGES/django.po +++ b/backend/notifications/locale/en/LC_MESSAGES/django.po @@ -30,3 +30,38 @@ msgid "Title: Score updated" msgstr "New score" msgid "Description: Score updated %(score)s" msgstr "Your score has been updated.\nNew score: %(score)s" +# Docker Image Build Succes +msgid "Title: Docker image build success" +msgstr "Docker image successfully build" +msgid "Description: Docker image build success %(name)s" +msgstr "Your docker image, $(name)s, has successfully been build" +# Docker Image Build Error +msgid "Title: Docker image build error" +msgstr "Docker image failed to build" +msgid "Description: Docker image build error %(name)s" +msgstr "Failed to build your docker image, %(name)s" +# Extra Check Succes +msgid "Title: Extra check success" +msgstr "Passed an extra check" +msgid "Description: Extra check success %(name)s" +msgstr "Your submission passed the extra check, $(name)s" +# Extra Check Error +msgid "Title: Extra check error" +msgstr "Failed an extra check" +msgid "Description: Extra check error %(name)s" +msgstr "Your submission failed to pass the extra check, %(name)s" +# Structure Checks Succes +msgid "Title: Structure checks success" +msgstr "Passed all structure checks" +msgid "Description: Structure checks success" +msgstr "Your submission passed all structure checks" +# Structure Checks Error +msgid "Title: Structure checks error" +msgstr "Failed a structure check" +msgid "Description: Structure checks" +msgstr "Your submission failed one or more structure checks" +# Submission received +msgid "Title: Submission received" +msgstr "Received submission" +msgid "Description: Submission received" +msgstr "We have received your submission" diff --git a/backend/notifications/locale/nl/LC_MESSAGES/django.po b/backend/notifications/locale/nl/LC_MESSAGES/django.po index 5a854108..7d9633d0 100644 --- a/backend/notifications/locale/nl/LC_MESSAGES/django.po +++ b/backend/notifications/locale/nl/LC_MESSAGES/django.po @@ -30,3 +30,38 @@ msgid "Title: Score updated" msgstr "Nieuwe score" msgid "Description: Score updated %(score)s" msgstr "Je score is geupdate.\nNieuwe score: %(score)s" +# Docker Image Build Succes +msgid "Title: Docker image build success" +msgstr "Docker image succesvol gebouwd" +msgid "Description: Docker image build success %(name)s" +msgstr "Jouw docker image, $(name)s, is succesvol gebouwd" +# Docker Image Build Error +msgid "Title: Docker image build error" +msgstr "Docker image is gefaald om te bouwen" +msgid "Description: Docker image build error %(name)s" +msgstr "Gefaald om jouw docker image, %(name)s, te bouwen" +# Extra Check Succes +msgid "Title: Extra check success" +msgstr "Geslaagd voor een extra check" +msgid "Description: Extra check success %(name)s" +msgstr "Jouw indiening is geslaagd voor de extra check: $(name)s" +# Extra Check Error +msgid "Title: Extra check error" +msgstr "Gefaald voor een extra check" +msgid "Description: Extra check error %(name)s" +msgstr "Jouw indiening is gefaald voor de extra check: %(name)s" +# Structure Checks Succes +msgid "Title: Structure checks success" +msgstr "Geslaagd voor de structuur checks" +msgid "Description: Structure checks success" +msgstr "Jouw indiening is geslaagd voor alle structuur checks" +# Structure Checks Error +msgid "Title: Structure checks error" +msgstr "Gefaald voor een structuur check" +msgid "Description: Structure checks" +msgstr "Jouw indiening is gefaald voor een structuur check" +# Submission received +msgid "Title: Submission received" +msgstr "Indiening ontvangen" +msgid "Description: Submission received" +msgstr "We hebben jouw indiening ontvangen" diff --git a/backend/notifications/logic.py b/backend/notifications/logic.py index e2061a87..0f7133a3 100644 --- a/backend/notifications/logic.py +++ b/backend/notifications/logic.py @@ -22,7 +22,7 @@ def get_message_dict(notification: Notification) -> Dict[str, str]: # Call the function after 60 seconds and no more than once in that period def schedule_send_mails(): - if not cache.get("notifications_send_mails"): + if not cache.get("notifications_send_mails", False): cache.set("notifications_send_mails", True) _send_mails.apply_async(countdown=60) @@ -41,7 +41,7 @@ def _send_mail(mail: mail.EmailMessage, result: List[bool]): # TODO: Retry 3 # https://docs.celeryq.dev/en/v5.3.6/getting-started/next-steps.html#next-steps # Send all unsent emails -@shared_task(ignore_result=True) +@shared_task() def _send_mails(): # All notifications that need to be sent notifications = Notification.objects.filter(is_sent=False) diff --git a/backend/notifications/serializers.py b/backend/notifications/serializers.py index d4c488ba..2e3d7c75 100644 --- a/backend/notifications/serializers.py +++ b/backend/notifications/serializers.py @@ -1,5 +1,4 @@ import re -from typing import Dict, List from authentication.models import User from notifications.logic import get_message_dict @@ -23,14 +22,14 @@ class NotificationSerializer(serializers.ModelSerializer): message = serializers.SerializerMethodField() # Check if the required arguments are present - def _get_missing_keys(self, string: str, arguments: Dict[str, str]) -> List[str]: - required_keys: List[str] = re.findall(r"%\((\w+)\)", string) + def _get_missing_keys(self, string: str, arguments: dict[str, str]) -> list[str]: + required_keys: list[str] = re.findall(r"%\((\w+)\)", string) missing_keys = [key for key in required_keys if key not in arguments] return missing_keys - def validate(self, data: Dict[str, str]) -> Dict[str, str]: - data: Dict[str, str] = super().validate(data) + def validate(self, data: dict[str, str | int | dict[str, str]]) -> dict[str, str]: + data: dict[str, str] = super().validate(data) # Validate the arguments if "arguments" not in data: @@ -56,7 +55,7 @@ def validate(self, data: Dict[str, str]) -> Dict[str, str]: return data # Get the message from the template and arguments - def get_message(self, obj: Notification) -> Dict[str, str]: + def get_message(self, obj: Notification) -> dict[str, str]: return get_message_dict(obj) class Meta: diff --git a/backend/notifications/signals.py b/backend/notifications/signals.py index f8203f39..979184bb 100644 --- a/backend/notifications/signals.py +++ b/backend/notifications/signals.py @@ -15,25 +15,27 @@ @receiver(notification_create) def notification_creation( + sender: type, type: NotificationType, - queryset: QuerySet[User], + queryset: list[User], arguments: Dict[str, str], **kwargs, # Required by django ) -> bool: data: List[Dict[str, Union[str, int, Dict[str, str]]]] = [] for user in queryset: - data.append( - { - "template_id": type.value, - "user": reverse("user-detail", kwargs={"pk": user.id}), - "arguments": arguments, - } - ) + if user: + data.append( + { + "template_id": type.value, + "user": reverse("user-detail", kwargs={"pk": user.id}), + "arguments": arguments, + } + ) serializer = NotificationSerializer(data=data, many=True) - if not serializer.is_valid(): + if not serializer.is_valid(raise_exception=False): return False serializer.save() @@ -46,3 +48,10 @@ def notification_creation( class NotificationType(Enum): SCORE_ADDED = 1 # Arguments: {"score": int} SCORE_UPDATED = 2 # Arguments: {"score": int} + DOCKER_IMAGE_BUILD_SUCCESS = 3 # Arguments: {"name": str} + DOCKER_IMAGE_BUILD_ERROR = 4 # Arguments: {"name": str} + EXTRA_CHECK_SUCCESS = 5 # Arguments: {"name": str} + EXTRA_CHECK_FAIL = 6 # Arguments: {"name": str} + STRUCTURE_CHECK_SUCCESS = 7 # Arguments: {} + STRUCTURE_CHECK_FAIL = 8 # Arguments: {} + SUBMISSION_RECEIVED = 9 # Arguments: {} diff --git a/backend/poetry.lock b/backend/poetry.lock index efb7f1f0..de94c864 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -1317,13 +1317,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.0" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, + {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, ] [package.dependencies] @@ -1626,4 +1626,4 @@ brotli = ["Brotli"] [metadata] lock-version = "2.0" python-versions = "^3.11.4" -content-hash = "eb154813d38b776ea62b72172e5127abd79f4006005d097421c14dfe40c557df" +content-hash = "fe59ecb1d9eb60d2f1cce90067f18cf9cac4748498c357640a8ab39f38a9a9e5" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 3e5e66a0..d1eba8fc 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -13,7 +13,7 @@ django-sslserver = "^0.22" djangorestframework = "^3.15.1" django-rest-swagger = "^2.2.0" drf-yasg = "^1.21.7" -requests = "^2.31.0" +requests = "^2.32.0" cas-client = "^1.0.0" psycopg2-binary = "^2.9.9" djangorestframework-simplejwt = "^5.3.1" diff --git a/development.sh b/development.sh index 70dfe9fe..5a83cf9d 100755 --- a/development.sh +++ b/development.sh @@ -135,7 +135,7 @@ if [ "$data" != "" ]; then echo "Clearing, Migrating & Populating the database" # We have nog fixtures for notification yet. - docker-compose -f development.yml run backend sh -c "python manage.py flush --no-input; python manage.py migrate; python manage.py loaddata authentication/fixtures/$data/*; python manage.py loaddata api/fixtures/$data/*;" + docker-compose -f development.yml run backend sh -c "python manage.py flush --no-input; python manage.py migrate; python manage.py loaddata notifications/fixtures/$data/*; python manage.py loaddata authentication/fixtures/$data/*; python manage.py loaddata api/fixtures/$data/*;" echo "Stopping the services" docker-compose -f development.yml down