From a10cd2f1735a597bb33c1c7427057810bfb7a254 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Wed, 12 Apr 2023 22:50:48 +0200 Subject: [PATCH 001/340] start send mail --- .../src/components/admin/mail/SendMail.vue | 54 +++++++++++++++++++ .../components/syndicus/FotoCardSyndicus.vue | 4 +- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 frontend/src/components/admin/mail/SendMail.vue diff --git a/frontend/src/components/admin/mail/SendMail.vue b/frontend/src/components/admin/mail/SendMail.vue new file mode 100644 index 00000000..5eb4c4a1 --- /dev/null +++ b/frontend/src/components/admin/mail/SendMail.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/frontend/src/components/syndicus/FotoCardSyndicus.vue b/frontend/src/components/syndicus/FotoCardSyndicus.vue index d85692d3..ad5f54da 100644 --- a/frontend/src/components/syndicus/FotoCardSyndicus.vue +++ b/frontend/src/components/syndicus/FotoCardSyndicus.vue @@ -4,7 +4,7 @@ -

{{ data.description }}

+

{{ data.description }}

@@ -14,7 +14,7 @@ -

{{ data.timeStamp }}

+

{{ data.timeStamp }}

From 16d5a2658b55c290d13542fead1570f404e69fa9 Mon Sep 17 00:00:00 2001 From: Arthur Deruytter Date: Mon, 24 Apr 2023 02:45:10 +0200 Subject: [PATCH 002/340] add dependabot --- .github/dependabot.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..e69de29b From 93a704272810e2f7c08eed86167fd3223a702826 Mon Sep 17 00:00:00 2001 From: Arthur Deruytter Date: Mon, 24 Apr 2023 02:46:16 +0200 Subject: [PATCH 003/340] actually add the contents.... --- .github/dependabot.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e69de29b..33a42bc1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/frontend" + schedule: + interval: "daily" + - package-ecosystem: "pip" + directory: "/backend" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" \ No newline at end of file From 9108473766ad12042f5b7a4d3d9bebb8247b68e1 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Mon, 24 Apr 2023 09:03:51 +0200 Subject: [PATCH 004/340] small backend fixes + admin dashboard fix --- backend/backend/settings.py | 2 +- backend/planning/views.py | 4 ++-- backend/ronde/views.py | 2 +- frontend/src/views/admin/DashboardView.vue | 5 ++++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/backend/settings.py b/backend/backend/settings.py index c97d84b1..1850a14c 100644 --- a/backend/backend/settings.py +++ b/backend/backend/settings.py @@ -27,7 +27,7 @@ SECRET_KEY = 'django-insecure-mz0gymvj@n5wl2p0yau(vj0e3jdx_wok78+ead*=p4)$w)g5(z' # TODO generate new one and keep secret # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = True ALLOWED_HOSTS = [ 'sel2-5.ugent.be', '157.193.244.115', diff --git a/backend/planning/views.py b/backend/planning/views.py index 79b67531..721b9797 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -205,7 +205,7 @@ def put(self, request, *args, **kwargs): "infoPerBuilding", InfoPerBuilding) handler.check() - super().put(request, *args, **kwargs) + return super().put(request, *args, **kwargs) def patch(self, request, *args, **kwargs): data = request.data @@ -216,7 +216,7 @@ def patch(self, request, *args, **kwargs): handler.check_primary_key(data.get("infoPerBuilding"), "infoPerBuilding", InfoPerBuilding) handler.check() - super().patch(request, *args, **kwargs) + return super().patch(request, *args, **kwargs) class InfoPerBuildingCLAPIView(generics.ListCreateAPIView): diff --git a/backend/ronde/views.py b/backend/ronde/views.py index c09a6bb5..fda9e97c 100644 --- a/backend/ronde/views.py +++ b/backend/ronde/views.py @@ -188,7 +188,7 @@ def patch(self, request, *args, **kwargs): handler.check_file(data.get("file"), "file", request.FILES) handler.check_not_blank(data.get("fileType"), "fileType") handler.check_enum_value(data.get("manualStatus"), "manualStatus", - ManualStatusField.value) + ManualStatusField.values) return super().patch(request, *args, **kwargs) diff --git a/frontend/src/views/admin/DashboardView.vue b/frontend/src/views/admin/DashboardView.vue index 6316d481..015cbe22 100644 --- a/frontend/src/views/admin/DashboardView.vue +++ b/frontend/src/views/admin/DashboardView.vue @@ -74,7 +74,10 @@ export default { this.rounds = rounds; this.show = rounds; this.filter(); - }).catch(() => null); + }).catch(() => { + this.rounds = []; + this.show = []; + }); }, getWeek(d) { const date = new Date(d); From f212f80ced88e6ae6b764b062855c2c740308257 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Mon, 24 Apr 2023 10:14:07 +0200 Subject: [PATCH 005/340] student dayplan small fixes --- backend/planning/views.py | 4 +++- frontend/src/views/DayPlanView.vue | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 721b9797..8cc95778 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -23,7 +23,9 @@ def student_dayplan(request, year, week, day): days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'] day_name = days[day] - templates = StudentTemplate.objects.filter(year=year, week=week) + templates = get_student_templates(year, week) + if templates is None: + return Response(status=404) dayplan = None for template in templates: for plan in template.dag_planningen.all(): diff --git a/frontend/src/views/DayPlanView.vue b/frontend/src/views/DayPlanView.vue index a68cb60a..43cc555f 100644 --- a/frontend/src/views/DayPlanView.vue +++ b/frontend/src/views/DayPlanView.vue @@ -2,8 +2,8 @@

{{ time }}

-

{{ ronde }}

- +

{{ ronde }}

+
@@ -39,7 +39,7 @@ export default defineComponent({ for (let index in planning.status) buildings[index].status = statusMap[planning.status[index]]; this.buildings = buildings; - this.ronde = planning.ronde.name; + this.ronde = `Ronde ${planning.ronde.name}`; this.planning = planning.id; }).catch(() => {}); }, From d9b1b6ad85ae3b076de53d7c9d05f964615b424e Mon Sep 17 00:00:00 2001 From: jbvilla Date: Tue, 25 Apr 2023 00:03:01 +0200 Subject: [PATCH 006/340] kan argumenten al tonen en invulen --- .../src/components/admin/mail/SendMail.vue | 88 ++++++++++++++----- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/admin/mail/SendMail.vue b/frontend/src/components/admin/mail/SendMail.vue index 5eb4c4a1..400486f7 100644 --- a/frontend/src/components/admin/mail/SendMail.vue +++ b/frontend/src/components/admin/mail/SendMail.vue @@ -1,23 +1,34 @@ From 7db724b29435677834d5023886493e89cb43a1db Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Tue, 25 Apr 2023 16:12:15 +0200 Subject: [PATCH 008/340] - Support multiple rounds per student per day. - Remove status field on dayplanning so it can be reused. - Remove date field on infoPerBuilding so it can be reused. --- backend/planning/models.py | 24 --------- backend/planning/urls.py | 1 + backend/planning/views.py | 47 +++++++++++++---- frontend/src/api/services/PlanningService.ts | 28 +++++----- .../student/CreateEditPostStudent.vue | 26 +++------- frontend/src/views/BuildingPageStudent.vue | 35 +++++++------ frontend/src/views/DayPlanView.vue | 51 +++++++++++++------ frontend/src/views/StudentHomeView.vue | 2 +- frontend/src/views/StudentPostView.vue | 5 +- 9 files changed, 121 insertions(+), 98 deletions(-) diff --git a/backend/planning/models.py b/backend/planning/models.py index bc0ad551..5ec43113 100644 --- a/backend/planning/models.py +++ b/backend/planning/models.py @@ -21,9 +21,6 @@ class DagPlanning(models.Model): ronde : models.ForeignKey The round that the students will do this day - - status : ArrayField - Student status per building, according to building order """ students = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True) @@ -34,21 +31,6 @@ class DagPlanning(models.Model): on_delete=models.DO_NOTHING ) - class StatusEnum(models.TextChoices): - """ - enum for type of status - """ - NOT_STARTED = "NS", "Not started" - STARTED = "ST", "Started" - FINISHED = "FI", "Finished" - - status = ArrayField( - models.CharField( - max_length=2, - choices=StatusEnum.choices - ), default=list - ) - class StudentTemplate(models.Model): """ @@ -152,18 +134,12 @@ class InfoPerBuilding(models.Model): remark : models.TextField The remarks about the building - date : models.DateField - The date when this info was created. - Because of this we can reuse DagPlanning objects. - dagPlanning : models.ForeignKey The associated DagPlanning """ remark = models.TextField(default="") - date = models.DateField() - dagPlanning = models.ForeignKey(DagPlanning, on_delete=models.CASCADE) diff --git a/backend/planning/urls.py b/backend/planning/urls.py index d9a11a52..a8548c50 100644 --- a/backend/planning/urls.py +++ b/backend/planning/urls.py @@ -9,6 +9,7 @@ path("weekplanning///", views.week_planning_view), path("dagplanning////", views.student_dayplan), path("dagplanning//", views.DagPlanningRetrieveUpdateAPIView.as_view()), + path("dagplanning////status/", views.planning_status), path("studenttemplates/rondes/////", views.student_templates_rondes_view), path("studenttemplates/", views.student_templates_view), path("studenttemplates//", views.student_template_view), diff --git a/backend/planning/views.py b/backend/planning/views.py index 8cc95778..c9643b15 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -15,7 +15,7 @@ @api_view(["GET"]) -@permission_classes([StudentPermission]) +@permission_classes([StudentPermission | SuperstudentPermission]) def student_dayplan(request, year, week, day): if request.method == "GET": if day < 0 or day > 6: @@ -26,18 +26,40 @@ def student_dayplan(request, year, week, day): templates = get_student_templates(year, week) if templates is None: return Response(status=404) - dayplan = None + + dayplans = [] for template in templates: for plan in template.dag_planningen.all(): if plan.time.day == day_name and request.user in plan.students.all(): - dayplan = plan - break + dayplans.append(plan) + + data = DagPlanningSerializerFull(dayplans, many=True).data + return Response(data) - if dayplan is None: + +@api_view(["GET"]) +@permission_classes([StudentPermission | AdminPermission | SuperstudentPermission]) +def planning_status(request, year, week, pk): + if request.method == "GET": + try: + dayplan = DagPlanning.objects.get(pk=pk) + except DagPlanning.DoesNotExist: return Response(status=404) - data = DagPlanningSerializerFull(dayplan).data - return Response(data) + buildings = [building.id for building in dayplan.ronde.buildings.all()] + infos = InfoPerBuilding.objects.filter(dagPlanning=pk) + status = {} + for index, info in enumerate(infos): + pictures = BuildingPicture.objects.filter(infoPerBuilding=info.id, + time__year=year, + time__week=week) + if buildings[index] not in status: + status[buildings[index]] = {"AR": 0, "DE": 0, "ST": 0, "EX": 0} + + for picture in pictures: + status[buildings[index]][picture.pictureType] += 1 + + return Response(status) class DagPlanningRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView): @@ -155,12 +177,19 @@ class BuildingPictureCreateAndListAPIView(generics.ListCreateAPIView): def get(self, request, *args, **kwargs): infoPerBuilding = request.query_params[ 'infoPerBuilding'] if 'infoPerBuilding' in request.query_params else None + year = request.query_params[ + 'year'] if 'year' in request.query_params else None + week = request.query_params[ + 'week'] if 'week' in request.query_params else None - if infoPerBuilding is not None: + if infoPerBuilding is not None and year is not None and week is not None: try: InfoPerBuilding.objects.get(pk=infoPerBuilding) self.queryset = BuildingPicture.objects.filter( - infoPerBuilding=infoPerBuilding) + infoPerBuilding=infoPerBuilding, + time__year=year, + time__week=week + ) except Exception: raise serializers.ValidationError( { diff --git a/frontend/src/api/services/PlanningService.ts b/frontend/src/api/services/PlanningService.ts index a67dee62..dec610cd 100644 --- a/frontend/src/api/services/PlanningService.ts +++ b/frontend/src/api/services/PlanningService.ts @@ -18,11 +18,21 @@ class PlanningService extends EchoService { /** * Get a day planning */ - @GET("/dagplanning/{year}/{week}/{day}") + @GET("/dagplanning/{year}/{week}/{day}/") get(@Path('year') year: number, @Path('week') week: number, - @Path('day') day: number): EchoPromise { - return {} as EchoPromise; + @Path('day') day: number): EchoPromise<[DayPlanning]> { + return {} as EchoPromise<[DayPlanning]>; + } + + /** + * Get the statuses for a planning + */ + @GET("/dagplanning/{year}/{week}/{id}/status/") + getStatus(@Path('year') year: number, + @Path('week') week: number, + @Path('id') id: number): EchoPromise { + return {} as EchoPromise; } /** @@ -53,7 +63,9 @@ class PlanningService extends EchoService { * Get student images for building info */ @GET("/buildingpicture/") - getPictures(@Query('infoPerBuilding') infoPerBuilding: number): EchoPromise { + getPictures(@Query('infoPerBuilding') infoPerBuilding: number, + @Query('year') year: number, + @Query('week') week: number): EchoPromise { return {} as EchoPromise; } @@ -119,14 +131,6 @@ class PlanningService extends EchoService { return {} as EchoPromise; } - /** - * Update planning status - */ - @PATCH("/dagplanning/{id}/") - updatePlanningStatus(@Path('id') id: number, @Body() body: PlanningStatusWrapper) { - return {} as EchoPromise; - } - } export default new EchoServiceBuilder() diff --git a/frontend/src/components/student/CreateEditPostStudent.vue b/frontend/src/components/student/CreateEditPostStudent.vue index 6076acc5..a5b64f24 100644 --- a/frontend/src/components/student/CreateEditPostStudent.vue +++ b/frontend/src/components/student/CreateEditPostStudent.vue @@ -123,23 +123,11 @@ export default { style: "SNACKBAR" }).then(b => b).catch(() => null); - RequestHandler.handle(PlanningService.getPlanning(this.data.planning), { - id: "getDayplanningError", - style: "NONE" - }).then(async planning => { - const building_index = planning.ronde.buildings.findIndex(b => b.id == this.data.building_id); - planning.status[building_index] = this.data.type === 'Vertrek' ? 'FI' : 'ST'; - await RequestHandler.handle(PlanningService.updatePlanningStatus(this.data.planning, {status: planning.status}), { - id: 'updatePlanningError', - style: 'NONE' - }).then(() => {}).catch(() => null); - - this.imageUrl = ''; - input.value = ''; - input.remove(); + this.imageUrl = ''; + input.value = ''; + input.remove(); - router.go(-1); - }).catch(() => null); + router.go(-1); }, async editData() { if (!this.imageCheck()) return; @@ -168,11 +156,11 @@ export default { id: "editImageError", style: "SNACKBAR" }).then(b => b).catch(() => null); - this.imageUrl = ''; - input.value = ''; - input.remove(); } + this.imageUrl = ''; + input.value = ''; + input.remove(); router.go(-1); } }, diff --git a/frontend/src/views/BuildingPageStudent.vue b/frontend/src/views/BuildingPageStudent.vue index d4f0ef56..5ffc2347 100644 --- a/frontend/src/views/BuildingPageStudent.vue +++ b/frontend/src/views/BuildingPageStudent.vue @@ -38,13 +38,13 @@ + v-bind:append-icon="this.statuses.AR > 0 ? 'mdi-check' : ''"> + v-bind:append-icon="this.statuses.ST ? 'mdi-check' : ''"> + v-bind:append-icon="this.statuses.DE ? 'mdi-check' : ''"> @@ -75,19 +75,19 @@ export default defineComponent({ }).then(planning => planning).catch(() => null); if (!planning) return; + RequestHandler.handle(PlanningService.getStatus(this.year, this.week, planning.id), { + id: `getStatus${planning.id}Error`, + style: "NONE" + }).then(statuses => { + this.statuses = statuses[this.$route.query.building]; + }).catch(() => null); + const building_index = planning.ronde.buildings.findIndex(b => String(b.id) === this.$route.query.building); this.building = planning.ronde.buildings[building_index]; - const infos = await RequestHandler.handle(PlanningService.getInfo(planning.id), { + RequestHandler.handle(PlanningService.getInfo(planning.id), { id: "getBuildingInfoError", style: "NONE" - }).then(info => info).catch(() => null); - if (!infos) return; - this.info = infos[building_index].id; - - RequestHandler.handle(PlanningService.getPictures(this.info), { - id: "getPicturesError", - style: "NONE" - }).then(picture => this.pictures = picture.map(p => p.pictureType)).catch(() => null); + }).then(infos => this.info = infos[building_index].id).catch(() => null); const containers = await RequestHandler.handle(ContainerService.get(this.building.id, this.year, this.week), { id: "getContainersError", @@ -105,7 +105,7 @@ export default defineComponent({ building: {location: {name: ''}, adres: '', id: ''}, trashMap: {PM: 'PMD', GL: 'GLAS', RE: 'REST', GF: 'GFT', PK: 'PK'}, containers: [], - pictures: [], + statuses: {ST: 0, DE: 0, AR: 0}, info: '', planning: '', year: null, @@ -113,13 +113,16 @@ export default defineComponent({ }), methods: { clickArrival() { - router.push({path: '/student_post_view', query: {info: this.info, building: this.building.id, type: 'Aankomst', planning: this.planning}}); + router.push({path: '/student_post_view', query: + {info: this.info, building: this.building.id, type: 'Aankomst', planning: this.planning, year: this.year, week: this.week}}); }, clickStorage() { - router.push({path: '/student_post_view', query: {info: this.info, building: this.building.id, type: 'Berging', planning: this.planning}}); + router.push({path: '/student_post_view', query: + {info: this.info, building: this.building.id, type: 'Berging', planning: this.planning, year: this.year, week: this.week}}); }, clickDeparture() { - router.push({path: '/student_post_view', query: {info: this.info, building: this.building.id, type: 'Vertrek', planning: this.planning}}); + router.push({path: '/student_post_view', query: + {info: this.info, building: this.building.id, type: 'Vertrek', planning: this.planning, year: this.year, week: this.week}}); }, buildingInfo() { router.push({path: '/building_info', query: {building: this.building.id}}); diff --git a/frontend/src/views/DayPlanView.vue b/frontend/src/views/DayPlanView.vue index 43cc555f..251f3e97 100644 --- a/frontend/src/views/DayPlanView.vue +++ b/frontend/src/views/DayPlanView.vue @@ -1,10 +1,24 @@ @@ -33,14 +47,19 @@ export default defineComponent({ RequestHandler.handle(PlanningService.get(this.year, this.week, date.getUTCDay()), { id: "getDayplanningError", style: "NONE" - }).then(planning => { - const buildings = Object(planning.ronde.buildings); - const statusMap = {NS: 'Niet begonnen', ST: 'Bezig', FI: 'Voltooid'}; - for (let index in planning.status) buildings[index].status = statusMap[planning.status[index]]; - - this.buildings = buildings; - this.ronde = `Ronde ${planning.ronde.name}`; - this.planning = planning.id; + }).then(plannings => { + plannings.forEach(planning => { + RequestHandler.handle(PlanningService.getStatus(this.year, this.week, planning.id), { + id: `getStatus${planning.id}Error`, + style: "NONE" + }).then(statuses => { + const buildings = Object(planning.ronde.buildings); + for (let building of buildings) + building.status = statuses[building.id].AR === 0 ? 'Niet begonnen' : statuses[building.id].DE > 0 ? 'Voltooid' : 'Bezig'; + planning.ronde.buildings = buildings; + this.rondes.push(planning); + }).catch(() => null); + }); }).catch(() => {}); }, methods: { @@ -65,10 +84,10 @@ export default defineComponent({ time: '', date: new Date().toISOString().split('T')[0], ronde: 'Er is nog geen ronde ingepland.', - buildings: [], - planning: null, + rondes: [], year: null, - week: null + week: null, + panel: [0] }) }); diff --git a/frontend/src/views/StudentHomeView.vue b/frontend/src/views/StudentHomeView.vue index d1ff17f3..c495a083 100644 --- a/frontend/src/views/StudentHomeView.vue +++ b/frontend/src/views/StudentHomeView.vue @@ -2,7 +2,7 @@ -

Planning

+

Planning

pictures.filter(p => p.pictureType === typeMap[this.$route.query.type])).catch(() => null); From 6ea9252963083051399e2885a3d573c4fb14f2b4 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Tue, 25 Apr 2023 16:13:29 +0200 Subject: [PATCH 009/340] fix linter --- backend/planning/models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/planning/models.py b/backend/planning/models.py index 5ec43113..8ed0dfab 100644 --- a/backend/planning/models.py +++ b/backend/planning/models.py @@ -1,10 +1,9 @@ -from django.contrib.postgres.fields import ArrayField -from django.db import models from django.conf import settings -from ronde.models import Ronde -from trashtemplates.models import TrashContainerTemplate, Status +from django.db import models from pickupdays.models import PickUpDay from ronde.models import LocatieEnum +from ronde.models import Ronde +from trashtemplates.models import TrashContainerTemplate, Status class DagPlanning(models.Model): From 4f107191a181c3b3f14654cc2e3c0f6fccb8e489 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Tue, 25 Apr 2023 17:10:52 +0200 Subject: [PATCH 010/340] - Update admin dashboard with new planning status - Allow login/register with enter key --- .../src/components/admin/RoundViewCard.vue | 50 ++++++++++++++++--- frontend/src/views/LoginView.vue | 2 +- frontend/src/views/RegisterView.vue | 2 +- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/admin/RoundViewCard.vue b/frontend/src/components/admin/RoundViewCard.vue index 386f9bb5..1417a552 100644 --- a/frontend/src/components/admin/RoundViewCard.vue +++ b/frontend/src/components/admin/RoundViewCard.vue @@ -13,13 +13,13 @@ it displays the information of one round so that a list of round views can easil

{{data.date}}

- - @@ -44,27 +44,63 @@ it displays the information of one round so that a list of round views can easil diff --git a/frontend/src/components/admin/RoundViewCard.vue b/frontend/src/components/admin/RoundViewCard.vue index 1417a552..43bb70f7 100644 --- a/frontend/src/components/admin/RoundViewCard.vue +++ b/frontend/src/components/admin/RoundViewCard.vue @@ -22,18 +22,16 @@ it displays the information of one round so that a list of round views can easil - - - - -

{{student.first_name}} {{student.last_name}}

-
-
+ + + + +

+ {{ s.first_name }} {{ s.last_name }}

+
+
+
@@ -46,6 +44,7 @@ it displays the information of one round so that a list of round views can easil From 6e36c44f8c4504ea2e84ac9b4d37c87410ca86a7 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Wed, 26 Apr 2023 23:24:25 +0200 Subject: [PATCH 012/340] add mailto link --- .../src/api/services/MailTemplateService.ts | 9 ++++ .../src/components/admin/mail/SendMail.vue | 50 ++++++++++++++----- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/frontend/src/api/services/MailTemplateService.ts b/frontend/src/api/services/MailTemplateService.ts index fc727885..8c2b4cfb 100644 --- a/frontend/src/api/services/MailTemplateService.ts +++ b/frontend/src/api/services/MailTemplateService.ts @@ -29,6 +29,15 @@ class MailTemplateService extends EchoService { return {} as EchoPromise } + /** + * Get all mail templates + */ + + @GET('/mailtemplates/') + getMailTemplates(): EchoPromise { + return {} as EchoPromise + } + /** * Update mail template */ diff --git a/frontend/src/components/admin/mail/SendMail.vue b/frontend/src/components/admin/mail/SendMail.vue index 96e62e85..69e54a3e 100644 --- a/frontend/src/components/admin/mail/SendMail.vue +++ b/frontend/src/components/admin/mail/SendMail.vue @@ -2,13 +2,15 @@

Mail versturen

+ + {{ data.syndicusEmail }} @@ -20,6 +22,8 @@ +

Onderwerp

+

Bericht

@@ -27,20 +31,33 @@
+Send Email + + + diff --git a/frontend/src/components/admin/LocationHeader.vue b/frontend/src/components/admin/LocationHeader.vue new file mode 100644 index 00000000..8d6f4357 --- /dev/null +++ b/frontend/src/components/admin/LocationHeader.vue @@ -0,0 +1,29 @@ + + + + diff --git a/frontend/src/config.ts b/frontend/src/config.ts index 4d4f5637..ebb197cc 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -32,7 +32,7 @@ export default { 'create_mail-template', 'buildings', 'rounds', 'students', 'syndicusen', 'mailtemplates', 'trashtemplates', 'editTrashtemplates', 'createTrashtemplates', 'trashtemplateContainers', 'createTrashtemplateContainers', 'editTrashtemplateContainers', 'trashtemplateBuildings', 'editTrashtemplateBuildings', 'mail-template', 'admin_info_building', - 'admin_edit_building', 'admin_info_user', 'admin_edit_user', 'admin_user_register', 'syndicus_create', 'syndicus_adjust' + 'admin_edit_building', 'admin_info_user', 'admin_edit_user', 'admin_user_register', 'syndicus_create', 'syndicus_adjust', 'locations' ] } }; diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 3b87bd6d..75e71cbf 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -45,6 +45,7 @@ import TrashContainerCreate from '@/components/containerTemplates/containers/Tra import TrashContainerTemplateCreate from '@/components/containerTemplates/TrashContainerTemplateCreate.vue' import TrashContainerTemplateEdit from '@/components/containerTemplates/TrashContainerTemplateEdit.vue' import TrashContainerEdit from '@/components/containerTemplates/containers/TrashContainerEdit.vue' +import LocationList from "@/views/listViews/LocationList"; const routes = [ { @@ -97,6 +98,11 @@ const routes = [ name: 'users', component: UsersView }, + { + path: '/admin/locaties', + name: 'locations', + component: LocationList + }, { path: '/location/create', name: 'create_location', diff --git a/frontend/src/views/admin/CreateLocationView.vue b/frontend/src/views/admin/CreateLocationView.vue index eff2f1a4..c91e2069 100644 --- a/frontend/src/views/admin/CreateLocationView.vue +++ b/frontend/src/views/admin/CreateLocationView.vue @@ -21,6 +21,7 @@ import NormalButton from "@/components/NormalButton"; import {RequestHandler} from "@/api/RequestHandler"; import LocationService from "@/api/services/LocationService"; +import router from "@/router"; export default { name: "CreateLocationView.vue", @@ -45,6 +46,7 @@ export default { color: "success" }) ); + router.push({name: 'locations'}) } } } diff --git a/frontend/src/views/listViews/LocationList.vue b/frontend/src/views/listViews/LocationList.vue new file mode 100644 index 00000000..3ab186ae --- /dev/null +++ b/frontend/src/views/listViews/LocationList.vue @@ -0,0 +1,44 @@ + + + From 8197421dc88d1d934f74f9061424fc6f27178de3 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Sun, 30 Apr 2023 20:15:52 +0200 Subject: [PATCH 043/340] Added to the navbar --- frontend/src/components/NavigationBar.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/components/NavigationBar.vue b/frontend/src/components/NavigationBar.vue index 466edfea..e2957f9f 100644 --- a/frontend/src/components/NavigationBar.vue +++ b/frontend/src/components/NavigationBar.vue @@ -9,6 +9,8 @@ value="dashboard"> + Date: Sun, 30 Apr 2023 20:29:48 +0200 Subject: [PATCH 044/340] Fix styling --- .../src/components/admin/LocationCard.vue | 23 ++++++++++++------- .../src/components/admin/LocationHeader.vue | 9 ++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/admin/LocationCard.vue b/frontend/src/components/admin/LocationCard.vue index 2614e6d9..5d7841d9 100644 --- a/frontend/src/components/admin/LocationCard.vue +++ b/frontend/src/components/admin/LocationCard.vue @@ -6,14 +6,10 @@ @@ -30,13 +47,19 @@ import { DatePicker } from 'v-calendar'; import 'v-calendar/dist/style.css'; import {RequestHandler} from "@/api/RequestHandler"; import RoundService from "@/api/services/RoundService"; +import FotoCardAdmin from "@/components/admin/FotoCardAdmin.vue"; +import { getWeek } from "@/api/DateUtil"; +import PlanningService from "@/api/services/PlanningService"; export default { name: "SyndicusHome", - components: {DatePicker}, + components: {FotoCardAdmin, DatePicker}, data: () => ({ date: new Date().toISOString().split('T')[0], buildings: [], + arrivals: [], + departs: [], + storages: [], building: null, masks: { modelValue: 'YYYY-MM-DD' }, attrs: [ @@ -64,6 +87,63 @@ export default { this.buildings = buildings; if (buildings.length > 0) this.building = buildings[0]; }).catch(() => null); + }, + methods: { + changed() { + this.getStudentPosts(); + }, + async getStudentPosts(){ + const date = new Date(this.date) + let week = getWeek(date) + if (date.getUTCDay() === 0) week -= 1; + await RequestHandler.handle(PlanningService.getRounds(date.getFullYear(), week, date.getUTCDay(), this.building.location), { + id: 'getRoundsError', + style: 'NONE' + }).then(async rounds => { + console.log(rounds, this.building.id) + for(const round of rounds){ + if(round.ronde.buildings.map(building => building.id).includes(this.building.id)){ + console.log('INCLUDES!') + await RequestHandler.handle(PlanningService.getInfoOfBuilding(round.id, this.building.id), { + id: 'getInfoOfBuildingError', + style: 'NONE' + }).then(async info => { + console.log(info) + await RequestHandler.handle(PlanningService.getPictures(info[0].id, date.getFullYear(), week), { + id: 'getPicturesError', + style: 'NONE' + }).then(async pictures => { + console.log(pictures) + this.arrivals = [] + this.departs = [] + this.storages = [] + for(const picture of pictures){ + if(picture.pictureType === "AR"){ + this.arrivals.push(picture) + } else if(picture.pictureType === "DE"){ + this.departs.push(picture) + } else if(picture.pictureType === "ST"){ + this.storages.push(picture) + } + } + }).catch(() => { + this.arrivals = [] + this.departs = [] + this.storages = [] + }) + }).catch(() => { + this.arrivals = [] + this.departs = [] + this.storages = [] + }) + } + } + }).catch(() => { + this.arrivals = [] + this.departs = [] + this.storages = [] + }); + } } } From 45565bb2463da6840ba1e70dffb321df819c86e3 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Fri, 12 May 2023 01:30:12 +0200 Subject: [PATCH 123/340] standaard version done; --- frontend/src/api/services/PlanningService.ts | 19 +++++++++-- .../src/components/admin/BuildingFollowUp.vue | 34 +++++++++++-------- frontend/src/router/index.js | 3 +- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/frontend/src/api/services/PlanningService.ts b/frontend/src/api/services/PlanningService.ts index 935b0820..d50a829b 100644 --- a/frontend/src/api/services/PlanningService.ts +++ b/frontend/src/api/services/PlanningService.ts @@ -69,6 +69,17 @@ class PlanningService extends EchoService { return {} as EchoPromise<[Round]>; } + @GET("/studenttemplates/rondes/{year}/{week}/{day}/{location}/") + getRoundFromBuilding( + @Path('year') year: number, + @Path('week') week: number, + @Path('day') day: number, + @Path('location') location: number, + building: number): EchoPromise { + return {} as EchoPromise; + } + + /** * Get building info for a day planning */ @@ -77,12 +88,14 @@ class PlanningService extends EchoService { return {} as EchoPromise; } + /** - * Get building info for a building and date + *Get building info for a day planning and building */ @GET("/infoperbuilding/") - getInfoFromBuilding(@Query('building') building: number, @Query('date') date: string): EchoPromise { - return {} as EchoPromise; + getInfoOfBuilding(@Query('dagPlanning') dagPlanning: number, + @Query('building') building: number): EchoPromise { + return {} as EchoPromise } diff --git a/frontend/src/components/admin/BuildingFollowUp.vue b/frontend/src/components/admin/BuildingFollowUp.vue index 8c656140..9a3a0898 100644 --- a/frontend/src/components/admin/BuildingFollowUp.vue +++ b/frontend/src/components/admin/BuildingFollowUp.vue @@ -8,18 +8,21 @@
- -

{{ this.name }}

+
+ +
+

{{ this.name }}

+
@@ -81,10 +84,11 @@ import PlanningService from "@/api/services/PlanningService"; import {getWeek} from "@/api/DateUtil"; import RoundBuildingCard from "@/components/admin/RoundBuildingCard.vue"; import FotoCardAdmin from "@/components/admin/FotoCardAdmin.vue"; +import NormalButton from "@/components/NormalButton.vue"; export default { name: "BuildingFollowUp", - components: {FotoCardAdmin, RoundBuildingCard, DatePicker}, + components: {NormalButton, FotoCardAdmin, RoundBuildingCard, DatePicker}, data: () => { return { id: 0, @@ -98,7 +102,8 @@ export default { buildings: [], arrivals: [], departs: [], - storages: [] + storages: [], + search: false, } }, @@ -140,6 +145,7 @@ export default { window.open(this.manual.file) }, buildingChange(building) { + this.search = false router.push({name: "admin_info_building", params: {id: building}}) this.getBuildingInformation(building).then(() => this.getStudentPosts()) }, diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 3e908dde..81b47562 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -46,6 +46,7 @@ import TrashContainerTemplateCreate from '@/components/containerTemplates/TrashC import TrashContainerTemplateEdit from '@/components/containerTemplates/TrashContainerTemplateEdit.vue' import TrashContainerEdit from '@/components/containerTemplates/containers/TrashContainerEdit.vue' import AdminRoundView from "@/views/admin/AdminRoundView.vue"; +import BuildingFollowUp from "@/components/admin/BuildingFollowUp.vue"; const routes = [ { @@ -163,7 +164,7 @@ const routes = [ path: '/admin/gebouw/:id', name: 'admin_info_building', props: true, - component: AdminBuildingInfoView + component: BuildingFollowUp }, { path: '/admin/gebouw/:id/aanpassen', From 3e363b939d4a54020059974d7d9b67f469a85231 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 13 May 2023 14:19:13 +0200 Subject: [PATCH 124/340] testen toegevoegd studetPost --- .../student/CreateEditPostStudent.vue | 16 ++-- .../Components/admin/mail/mailTests.spec.ts | 11 +-- .../Components/student/studentPosts.spec.ts | 85 +++++++++++++++++++ frontend/tests/utils/testHelper.ts | 9 ++ 4 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 frontend/tests/unit/Components/student/studentPosts.spec.ts create mode 100644 frontend/tests/utils/testHelper.ts diff --git a/frontend/src/components/student/CreateEditPostStudent.vue b/frontend/src/components/student/CreateEditPostStudent.vue index a5b64f24..46073d70 100644 --- a/frontend/src/components/student/CreateEditPostStudent.vue +++ b/frontend/src/components/student/CreateEditPostStudent.vue @@ -3,7 +3,7 @@
-
+
mdi-image @@ -15,25 +15,25 @@
- +
-
-

{{ data.buildingName }}

-

{{ data.type }}

+
+

{{ data.buildingName }}

+

{{ data.type }}

- +
- - + +
diff --git a/frontend/tests/unit/Components/admin/mail/mailTests.spec.ts b/frontend/tests/unit/Components/admin/mail/mailTests.spec.ts index 284b6ce2..d9314e3c 100644 --- a/frontend/tests/unit/Components/admin/mail/mailTests.spec.ts +++ b/frontend/tests/unit/Components/admin/mail/mailTests.spec.ts @@ -1,16 +1,7 @@ import {mount} from '@vue/test-utils' import CreateEditMailTemplate from '@/components/admin/mail/CreateEditMailTemplate.vue' import SendMail from '@/components/admin/mail/SendMail.vue' - -/** - * Gaat het v-model van een input veld triggeren (omdat de gewone manier niet werkt hebben - * we deze functie gemaakt) - */ -function triggerInput(input, model, activator) { - const data = activator(input.element.value) - model.setData(data) -} - +import {triggerInput} from "../../../../utils/testHelper"; describe('CreateEditMailTemplate.vue', () => { diff --git a/frontend/tests/unit/Components/student/studentPosts.spec.ts b/frontend/tests/unit/Components/student/studentPosts.spec.ts new file mode 100644 index 00000000..f6dbf15f --- /dev/null +++ b/frontend/tests/unit/Components/student/studentPosts.spec.ts @@ -0,0 +1,85 @@ +import {mount} from '@vue/test-utils' +import CreateEditPostStudent from "@/components/student/CreateEditPostStudent.vue"; +import {triggerInput} from "../../../utils/testHelper"; + +describe('CreateEditPostStudent.vue', () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(CreateEditPostStudent) + }) + + it('renders the component', () => { + expect(wrapper.exists()).toBe(true); + }); + + it('Render "Klik om een foto toe te voegen"', () => { + expect(wrapper.find('p').text()).toMatch('Klik om een foto toe te voegen') + }); + + it('remove image is called when the remove button is clicked and deleted the image', async () => { + await wrapper.setData({imageUrl: 'test'}) + await wrapper.vm.$nextTick(); + const removeButton = wrapper.find('[data-test="delete-button"]'); + await removeButton.trigger('click') + await wrapper.vm.$nextTick(); + expect(wrapper.vm.imageUrl).toBe("") + }) + + it('call selectImage when clicked in the square', async () => { + CreateEditPostStudent.methods.selectImage = jest.fn() + const wrapper = mount(CreateEditPostStudent) + const square = wrapper.find('[data-test="square-button"]'); + await square.trigger('click') + await wrapper.vm.$nextTick(); + expect(CreateEditPostStudent.methods.selectImage).toHaveBeenCalled() + }) + + it('call uploadData when clicked on the upload button', async () => { + CreateEditPostStudent.methods.uploadData = jest.fn() + const wrapper = mount(CreateEditPostStudent) + const uploadButton = wrapper.find('[data-test="upload-button"]'); + await uploadButton.trigger('click') + await wrapper.vm.$nextTick(); + expect(CreateEditPostStudent.methods.uploadData).toHaveBeenCalled() + }) + + it('call editData when clicked on the edit button', async () => { + CreateEditPostStudent.methods.editData = jest.fn() + const wrapper = mount(CreateEditPostStudent) + await wrapper.setProps({data: {edit: true}}) + await wrapper.vm.$nextTick(); + const editButton = wrapper.find('[data-test="edit-button"]'); + await editButton.trigger('click') + await wrapper.vm.$nextTick(); + expect(CreateEditPostStudent.methods.editData).toHaveBeenCalled() + }) + + it('image check', async () => { + await wrapper.setData({imageUrl: 'test'}) + await wrapper.vm.$nextTick(); + expect(wrapper.vm.imageCheck).toBeTruthy() + }) + + it('set description', async () => { + const description = wrapper.find('[data-test="description"]'); + description.element.value = 'test'; + const activator = (x) => { + return {description: x} + } + triggerInput(description, wrapper, activator) + expect(wrapper.vm.description).toBe('test') + }) + + /*it('show building name and type', async () => { + const data = {nameBuilding: 'test', type: 'test', info: '', edit: false, id: '', planning: '', building_id: ''} + await wrapper.setProps({data: {nameBuilding: 'test', type: 'test', info: '', edit: false, id: '', planning: '', building_id: ''}}) + wrapper.vm.$forceUpdate() + const buildingName = wrapper.findComponent('[data-test="buildingName"]') + const buildingType = wrapper.find('[data-test="buildingType"]') + + expect(buildingName.text()).toBe(data.nameBuilding) + expect(buildingType.text()).toBe(data.type) + })*/ +}) diff --git a/frontend/tests/utils/testHelper.ts b/frontend/tests/utils/testHelper.ts new file mode 100644 index 00000000..127d3aa1 --- /dev/null +++ b/frontend/tests/utils/testHelper.ts @@ -0,0 +1,9 @@ + +/** + * Gaat het v-model van een input veld triggeren (omdat de gewone manier niet werkt hebben + * we deze functie gemaakt) + */ +export function triggerInput(input, model, activator) { + const data = activator(input.element.value) + model.setData(data) +} From 259884ff29de1dc390442d08a2f3ee798a1009d5 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sat, 13 May 2023 15:36:18 +0200 Subject: [PATCH 125/340] new action runner attempt --- .github/workflows/backend.yml | 24 +++++++++++++++++++++-- .github/workflows/frontend.yml | 35 ++++++++++++++++++++++++++++++++++ frontend/src/api/EchoFetch | 2 +- 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/frontend.yml diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index a7b6dee2..025917c6 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -2,7 +2,7 @@ name: backend-tests run-name: backend-tests on: [push] jobs: - Backend-linter-and-tests: + Backend-tests: runs-on: self-hosted environment: django tests strategy: @@ -32,7 +32,27 @@ jobs: python manage.py migrate python manage.py test working-directory: ./backend + + Backend-linter: + runs-on: self-hosted + environment: django tests + strategy: + max-parallel: 4 + matrix: + python-version: [ 3.11 ] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 + working-directory: ./backend - name: Run Linter run: | flake8 --ignore=F405,F403,E501 . - working-directory: ./backend + working-directory: ./backend \ No newline at end of file diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml new file mode 100644 index 00000000..904cbca9 --- /dev/null +++ b/.github/workflows/frontend.yml @@ -0,0 +1,35 @@ +name: frontend-tests +run-name: frontend-tests +on: [push] +jobs: + Frontend-tests: + runs-on: self-hosted + environment: vue tests + strategy: + max-parallel: 4 + + steps: + - uses: actions/checkout@v3 + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: latest + - name: Empty EchoFetch directory + run: | + rm -rf EchoFetch + working-directory: ./frontend/src/api + - name: Checkout submodules + run: git submodule update --init --recursive + - name: Setup EchoFetch + run: | + npm install + npm run build + working-directory: ./frontend/src/api/EchoFetch + - name: Install Dependencies + run: | + npm install --force + working-directory: ./frontend + - name: Run Tests + run: | + npm run test:unit + working-directory: ./frontend \ No newline at end of file diff --git a/frontend/src/api/EchoFetch b/frontend/src/api/EchoFetch index ec332734..c66ca1aa 160000 --- a/frontend/src/api/EchoFetch +++ b/frontend/src/api/EchoFetch @@ -1 +1 @@ -Subproject commit ec332734a8affe447f7cf7283ce808652e7a990d +Subproject commit c66ca1aa83455e4e5f1391843ccdb996285dbd7a From c47a3ab28739fe5bb473dc44f5c870524b0fc76c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 13:39:38 +0000 Subject: [PATCH 126/340] Bump actions/setup-python from 3 to 4 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/backend.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 025917c6..3d2d9b0d 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies @@ -44,7 +44,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies From 3f1b7064ade4c79640add1e6ae7a2d3a43f5033a Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 13 May 2023 17:27:23 +0200 Subject: [PATCH 127/340] OverviewScreenStudentPosts test toegevoegd --- .../student/OverviewScreenStudentPosts.vue | 4 +- .../Components/student/studentPosts.spec.ts | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/student/OverviewScreenStudentPosts.vue b/frontend/src/components/student/OverviewScreenStudentPosts.vue index 464a1c3d..6200ca9d 100644 --- a/frontend/src/components/student/OverviewScreenStudentPosts.vue +++ b/frontend/src/components/student/OverviewScreenStudentPosts.vue @@ -4,11 +4,11 @@

{{ data.buildingName }}

{{ data.type }}

- mdi-camera-outline + mdi-camera-outline - + diff --git a/frontend/tests/unit/Components/student/studentPosts.spec.ts b/frontend/tests/unit/Components/student/studentPosts.spec.ts index f6dbf15f..894c83b3 100644 --- a/frontend/tests/unit/Components/student/studentPosts.spec.ts +++ b/frontend/tests/unit/Components/student/studentPosts.spec.ts @@ -1,6 +1,7 @@ import {mount} from '@vue/test-utils' import CreateEditPostStudent from "@/components/student/CreateEditPostStudent.vue"; import {triggerInput} from "../../../utils/testHelper"; +import OverviewScreenStudentPosts from "@/components/student/OverviewScreenStudentPosts.vue"; describe('CreateEditPostStudent.vue', () => { @@ -83,3 +84,50 @@ describe('CreateEditPostStudent.vue', () => { expect(buildingType.text()).toBe(data.type) })*/ }) + +describe('OverviewScreenStudentPost.vue', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(OverviewScreenStudentPosts) + }) + + it('renders the component', () => { + expect(wrapper.exists()).toBe(true); + }) + + it('check building name', async () => { + await wrapper.setProps({ + data: {buildingName: 'test', type: 'test', images: [], info: '', planning: '', building_id: ''} + }) + + expect(wrapper.find('h1').text()).toBe('test') + }) + + it('check type', async () => { + await wrapper.setProps({ + data: {buildingName: 'test', type: 'test2', images: [], info: '', planning: '', building_id: ''} + }) + + expect(wrapper.find('h4').text()).toBe('test2') + }) + + it('goToPhotoPage is called when clicked on the icon', async () => { + OverviewScreenStudentPosts.methods.goToPhotoPage = jest.fn() + const wrapper = mount(OverviewScreenStudentPosts) + const icon = wrapper.find('[data-test="goToFotoPage-button"]'); + await icon.trigger('click') + await wrapper.vm.$nextTick(); + expect(OverviewScreenStudentPosts.methods.goToPhotoPage).toHaveBeenCalled() + }) + + it('completeTask is called when clicked on the icon', async () => { + OverviewScreenStudentPosts.methods.completeTask = jest.fn() + const wrapper = mount(OverviewScreenStudentPosts) + const icon = wrapper.find('[data-test="completeTask-button"]'); + await icon.trigger('click') + await wrapper.vm.$nextTick(); + expect(OverviewScreenStudentPosts.methods.completeTask).toHaveBeenCalled() + }) + +}) From a7c7d8afc4dad3a74dc9a61538e2ac37bf2a3b3b Mon Sep 17 00:00:00 2001 From: Robbe Van Rijsselberghe Date: Sat, 13 May 2023 23:38:39 +0200 Subject: [PATCH 128/340] fix required datetime field --- backend/planning/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/planning/views.py b/backend/planning/views.py index 4f144033..87613c62 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -189,6 +189,7 @@ def post(self, request, *args, **kwargs): handler.check_primary_key_value_required(data.get("infoPerBuilding"), "infoPerBuilding", InfoPerBuilding) + handler.check_date_time_value_required(data.get("time"), "time") handler.check() return super().post(request=request, args=args, kwargs=kwargs) From 3ae7ffbf59b9377070b354d5d7477c6d35c39202 Mon Sep 17 00:00:00 2001 From: Robbe Van Rijsselberghe Date: Sat, 13 May 2023 23:41:09 +0200 Subject: [PATCH 129/340] fix error --- backend/planning/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 87613c62..b292294a 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -213,7 +213,7 @@ def put(self, request, *args, **kwargs): "infoPerBuilding", InfoPerBuilding) handler.check() - super().put(request, *args, **kwargs) + return super().put(request, *args, **kwargs) def patch(self, request, *args, **kwargs): data = request.data @@ -224,7 +224,7 @@ def patch(self, request, *args, **kwargs): handler.check_primary_key(data.get("infoPerBuilding"), "infoPerBuilding", InfoPerBuilding) handler.check() - super().patch(request, *args, **kwargs) + return super().patch(request, *args, **kwargs) class InfoPerBuildingCLAPIView(generics.ListCreateAPIView): From e021680b99b489f35f75794ba8e9f3db6419b1a3 Mon Sep 17 00:00:00 2001 From: Robbe Van Rijsselberghe Date: Sat, 13 May 2023 23:57:13 +0200 Subject: [PATCH 130/340] permissions met "|" ipv "," --- backend/planning/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index b292294a..6864c273 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -1,6 +1,7 @@ from django.contrib.auth import get_user_model from django.http import HttpResponseNotFound from rest_framework import generics +from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework.serializers import ValidationError @@ -318,8 +319,9 @@ def get_student_templates(year, week): class WeekplanningView(generics.RetrieveAPIView): - permission_classes = [StudentReadOnly, AdminPermission, - SuperstudentPermission] + permission_classes = [AdminPermission | + SuperstudentPermission | + StudentReadOnly] def get(self, request, *args, **kwargs): year = kwargs["year"] From 0731606cf48f2c970a1994d19818799d85d1c9ee Mon Sep 17 00:00:00 2001 From: Robbe Van Rijsselberghe Date: Sat, 13 May 2023 23:57:52 +0200 Subject: [PATCH 131/340] permissions met "|" ipv "," --- backend/planning/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 6864c273..8ce0bcbc 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -1,7 +1,6 @@ from django.contrib.auth import get_user_model from django.http import HttpResponseNotFound from rest_framework import generics -from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework.serializers import ValidationError @@ -334,7 +333,7 @@ def get(self, request, *args, **kwargs): class StudentTemplateRondeView(generics.RetrieveAPIView): - permission_classes = [AdminPermission, SuperstudentPermission] + permission_classes = [AdminPermission | SuperstudentPermission] def get(self, request, *args, **kwargs): year, week, day, location = kwargs["year"], kwargs["week"], kwargs[ @@ -357,7 +356,7 @@ def get(self, request, *args, **kwargs): class StudentTemplateView(generics.RetrieveAPIView, generics.CreateAPIView): - permission_classes = [AdminPermission, SuperstudentPermission] + permission_classes = [AdminPermission | SuperstudentPermission] def get(self, request, *args, **kwargs): """ From 9bc2c199f36b45dee61b2e7370da7c3ebf958d4f Mon Sep 17 00:00:00 2001 From: Robbe Van Rijsselberghe Date: Sun, 14 May 2023 00:03:31 +0200 Subject: [PATCH 132/340] fix linter --- backend/planning/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 8ce0bcbc..0695b75b 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -318,9 +318,8 @@ def get_student_templates(year, week): class WeekplanningView(generics.RetrieveAPIView): - permission_classes = [AdminPermission | - SuperstudentPermission | - StudentReadOnly] + permission_classes = [AdminPermission | SuperstudentPermission + | StudentReadOnly] def get(self, request, *args, **kwargs): year = kwargs["year"] From 09a352f04ef12a916d17eef879313b1c3c727222 Mon Sep 17 00:00:00 2001 From: Robbe Van Rijsselberghe Date: Sun, 14 May 2023 00:04:31 +0200 Subject: [PATCH 133/340] linter nog altijd niet content --- backend/planning/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 0695b75b..42676f13 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -318,8 +318,8 @@ def get_student_templates(year, week): class WeekplanningView(generics.RetrieveAPIView): - permission_classes = [AdminPermission | SuperstudentPermission - | StudentReadOnly] + permission_classes = \ + [AdminPermission | SuperstudentPermission | StudentReadOnly] def get(self, request, *args, **kwargs): year = kwargs["year"] From 1d098a5473cc8994d4c4a8e00e07b3e8c82f189f Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sun, 14 May 2023 10:59:38 +0200 Subject: [PATCH 134/340] Action runner linter --- .github/workflows/frontend.yml | 26 ++++++++++++++++++++++++++ frontend/.eslintignore | 2 ++ frontend/.eslintrc.js | 11 ++++++----- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 frontend/.eslintignore diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 904cbca9..8bc517d1 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -32,4 +32,30 @@ jobs: - name: Run Tests run: | npm run test:unit + working-directory: ./frontend + + Frontend-linter: + runs-on: self-hosted + environment: vue tests + strategy: + max-parallel: 4 + + steps: + - uses: actions/checkout@v3 + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: latest + - name: Empty EchoFetch directory + run: | + rm -rf EchoFetch + working-directory: ./frontend/src/api + - name: Install Dependencies + run: | + npm install --force + npm i -D @vue/cli-plugin-eslint @vue/eslint-config-typescript --force + working-directory: ./frontend + - name: Run Tests + run: | + npm run lint working-directory: ./frontend \ No newline at end of file diff --git a/frontend/.eslintignore b/frontend/.eslintignore new file mode 100644 index 00000000..b2ac10e0 --- /dev/null +++ b/frontend/.eslintignore @@ -0,0 +1,2 @@ +node_modules/ +EchoFetch/ \ No newline at end of file diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 725f896f..43eb523a 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -5,14 +5,15 @@ module.exports = { }, extends: [ 'plugin:vue/vue3-essential', - '@vue/standard' + '@vue/standard', + '@vue/typescript/recommended' ], - parserOptions: { - parser: '@babel/eslint-parser' - }, rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' + 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + camelcase: 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-types': 'off' }, overrides: [ { From 536a38f63ecfe09576a684b7bcba93158b5294cc Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sun, 14 May 2023 11:07:45 +0200 Subject: [PATCH 135/340] linter first fixes test --- .github/workflows/frontend.yml | 2 +- frontend/.eslintrc.js | 3 ++- frontend/src/api/error/ErrorHandler.ts | 5 +---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 8bc517d1..03b54559 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -55,7 +55,7 @@ jobs: npm install --force npm i -D @vue/cli-plugin-eslint @vue/eslint-config-typescript --force working-directory: ./frontend - - name: Run Tests + - name: Run Linter run: | npm run lint working-directory: ./frontend \ No newline at end of file diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 43eb523a..bbc8726f 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -13,7 +13,8 @@ module.exports = { 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', camelcase: 'off', '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-types': 'off' + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-var-requires': 'off' }, overrides: [ { diff --git a/frontend/src/api/error/ErrorHandler.ts b/frontend/src/api/error/ErrorHandler.ts index 56193b65..657d20c6 100644 --- a/frontend/src/api/error/ErrorHandler.ts +++ b/frontend/src/api/error/ErrorHandler.ts @@ -105,10 +105,7 @@ export class ErrorHandler { // Set the new error message, when available. if (fieldNewError) { fieldValue.error = fieldNewError.message; - } - - // Otherwise set an empty error. (necessary for reset of previous error) - else { + } else { // Otherwise set an empty error. (necessary for reset of previous error) fieldValue.error = ""; } } From 0436c3157b2372ed85478852757985c2cbf5b16d Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sun, 14 May 2023 11:17:16 +0200 Subject: [PATCH 136/340] linter fix several files --- frontend/.eslintrc.js | 3 ++- .../src/components/AccountInformation.vue | 19 ++++++++----------- frontend/src/components/NormalButton.vue | 2 +- frontend/src/components/admin/ListPage.vue | 10 ++++------ .../components/admin/RoundBuildingCard.vue | 4 ++-- .../src/components/admin/RoundViewCard.vue | 2 +- .../src/components/admin/mail/SendMail.vue | 2 +- .../student_template/DagPlanningCard.vue | 2 +- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index bbc8726f..19500614 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -14,7 +14,8 @@ module.exports = { camelcase: 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/ban-types': 'off', - '@typescript-eslint/no-var-requires': 'off' + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-unused-vars': 'off' }, overrides: [ { diff --git a/frontend/src/components/AccountInformation.vue b/frontend/src/components/AccountInformation.vue index e531b053..2408cb2f 100644 --- a/frontend/src/components/AccountInformation.vue +++ b/frontend/src/components/AccountInformation.vue @@ -61,7 +61,7 @@ ----> -
+
@@ -70,7 +70,7 @@
- @@ -89,17 +89,13 @@ export default { components: {ConfirmDialog, NormalButton}, props: { get_data: { - type: Function, default: () => { - } + type: Function }, save_data: { - type: Function, default: () => { - } + type: Function }, delete_current: { - type: Function, default: () => { - - } + type: Function }, not_admin: {type: Boolean, default: true}, can_edit_permission: {type: Boolean, default: true} @@ -123,17 +119,18 @@ export default { {name: 'Syndicus', value: 'SY'}], edit: false, smallScreen: false, - can_edit_permission: true + edit_permission: true } }, async beforeMount() { + this.edit_permission = this.can_edit_permission this.data = await this.get_data() const currentUser = await this.$store.getters['session/currentUser'] if (!this.not_admin) { const currentUserRole = currentUser.role if (currentUserRole === 'SU') { if (this.data.role === 'AD') { - this.can_edit_permission = false + this.edit_permission = false } else { this.roles = [{name: 'Aanvrager', value: 'AA'}, {name: 'Student', value: 'ST'}, {name: 'Superstudent', value: 'SU'}] diff --git a/frontend/src/components/NormalButton.vue b/frontend/src/components/NormalButton.vue index 1ff3c256..f2a8b7b0 100644 --- a/frontend/src/components/NormalButton.vue +++ b/frontend/src/components/NormalButton.vue @@ -37,7 +37,7 @@ export default defineComponent({ props: { text: { type: String }, dropdown: { type: Boolean, default: false }, - parentFunction: { type: Function, default: () => {} } + parentFunction: { type: Function } } }) diff --git a/frontend/src/components/admin/ListPage.vue b/frontend/src/components/admin/ListPage.vue index ce8eede4..0fb8d345 100644 --- a/frontend/src/components/admin/ListPage.vue +++ b/frontend/src/components/admin/ListPage.vue @@ -66,12 +66,12 @@ export default { required: true }, headComponent: { - type: Object, + type: String, default: 'div', required: false }, childComponent: { - type: Object, + type: String, default: 'div', required: true }, @@ -90,9 +90,7 @@ export default { default: false }, refresh_function: { - type: Function, - default: () => { - } + type: Function }, search: { type: Boolean, @@ -118,8 +116,8 @@ export default { filtered.push(el) } } - return filtered } + return filtered } }, data() { diff --git a/frontend/src/components/admin/RoundBuildingCard.vue b/frontend/src/components/admin/RoundBuildingCard.vue index 7b196839..a6c7ac38 100644 --- a/frontend/src/components/admin/RoundBuildingCard.vue +++ b/frontend/src/components/admin/RoundBuildingCard.vue @@ -32,7 +32,7 @@ - @@ -34,18 +27,19 @@ import {RequestHandler} from "@/api/RequestHandler"; import buildingService from "@/api/services/BuildingService"; import TrashTemplateService from "@/api/services/TrashTemplateService"; import router from "@/router"; +import StateButtons from "@/components/StateButtons.vue"; export default { name: "TrashTemplateBuildingAdd", - components: {}, + components: {StateButtons}, props: {}, data() { return { building_options: [], building_chosen: [], building_originals: [], - permanent: true + status: "I" } }, @@ -62,16 +56,25 @@ export default { return result.map(buildingContainer => buildingContainer.building.id) }) this.building_chosen = this.building_originals + + RequestHandler.handle( + TrashTemplateService.getTrashTemplate(this.$route.params.id), + { + id: 'getTrashtemplateError', + style: 'SNACKBAR' + } + ).then(result => { + this.status = result.status + }) }, methods: { - async aanpassen() { - console.log(this.building_originals) - console.log(this.building_chosen) + async aanpassen(eenmalig) { + /* Al de gebouwen die niet in de originele lijst zaten en dus nieuw toegevoegd moeten worden. */ this.building_chosen.forEach(building_id => { if (!this.building_originals.includes(building_id)) { - if (this.permanent) { + if (!eenmalig) { RequestHandler.handle(TrashTemplateService.newBuildingToTemplate(this.$route.params.id, { building: building_id, selection: [] diff --git a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue index 41c95a53..c1dc9877 100644 --- a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue +++ b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue @@ -14,9 +14,6 @@

{{ building.building.adres }}

- - - - - - - Aanpassen - - + @@ -44,15 +36,17 @@ import {RequestHandler} from "@/api/RequestHandler"; import TrashTemplateService from "@/api/services/TrashTemplateService"; import router from "@/router"; import BuildingContainer from "@/api/models/BuildingContainer"; +import StateButtons from "@/components/StateButtons.vue"; export default { name: "TrashTemplateEditView", + components: {StateButtons}, data() { return { - permanent: true, building: BuildingContainer, trash_ids: [], - container_choices: [] + container_choices: [], + status: "I" } }, async beforeMount() { @@ -61,16 +55,27 @@ export default { id: 'getBuildingError', style: 'SNACKBAR' }) + this.trash_ids = this.building.trash_ids this.container_choices = await RequestHandler.handle( TrashTemplateService.getTrashContainersOfTemplate(this.$route.params.id), { id: 'getContainersForTemplateError', style: 'SNACKBAR' }).then(result => result).catch(() => []); + + RequestHandler.handle( + TrashTemplateService.getTrashTemplate(this.$route.params.id), + { + id: 'getTrashtemplateError', + style: 'SNACKBAR' + } + ).then(result => { + this.status = result.status + }) }, methods: { - async update() { - if (this.permanent) { + async update(eenmalig) { + if (!eenmalig) { RequestHandler.handle(TrashTemplateService.updateBuildingTemplate(this.$route.params.id, this.$route.params.gebouwId, { selection: this.trash_ids }), { diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue index 5e343aa6..bcb06d4a 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue @@ -26,11 +26,12 @@
- + Aanmaken +
Om deze template aan te passen moeten eerst de eenmalige aanpassingen ongedaan worden.
@@ -41,9 +42,11 @@ import TrashTemplateService from "@/api/services/TrashTemplateService"; import {container_to_api, ContainerType} from "@/api/models/ContainerType"; import {Weekday, weekday_to_api} from "@/api/models/Weekday"; import router from "@/router"; +import StateButtons from "@/components/StateButtons.vue"; export default { name: 'CreateTrashContainerView', + components: {StateButtons}, computed: { Weekday() { return Weekday @@ -62,6 +65,7 @@ export default { start_hour: '', end_hour: '', smallScreen: false, + status: "I", types: [ ContainerType.GFT, ContainerType.PMD, @@ -80,8 +84,20 @@ export default { ] } }, + beforeMount() { + RequestHandler.handle( + TrashTemplateService.getTrashTemplate(this.id), + { + id: 'getTrashtemplateError', + style: 'SNACKBAR' + } + ).then(result => { + this.status = result.status + }) + }, methods: { createContainer() { + RequestHandler.handle( TrashTemplateService.newContainerToTemplate(this.id, { type: container_to_api(this.type), diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue index c06a7564..2f163a98 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue @@ -26,12 +26,8 @@
- - - Aanpassen - - - + + @@ -41,9 +37,11 @@ import TrashTemplateService from "@/api/services/TrashTemplateService"; import {container_from_api, container_to_api, ContainerType} from "@/api/models/ContainerType"; import {Weekday, weekday_from_api, weekday_to_api} from "@/api/models/Weekday"; import router from '@/router'; +import StateButtons from "@/components/StateButtons.vue"; export default { name: 'CreateTrashContainerView', + components: {StateButtons}, computed: { Weekday() { return Weekday @@ -63,6 +61,7 @@ export default { day: '', start_hour: '', end_hour: '', + status: "I", smallScreen: false, types: [ ContainerType.GFT, @@ -96,11 +95,21 @@ export default { this.start_hour = result.trash_container.collection_day.start_hour this.end_hour = result.trash_container.collection_day.end_hour }) + RequestHandler.handle( + TrashTemplateService.getTrashTemplate(this.id_), + { + id: 'getTrashtemplateError', + style: 'SNACKBAR' + } + ).then(result => { + this.status = result.status + }) }, methods: { - async editContainer() { - RequestHandler.handle( - TrashTemplateService.updateContainerTemplate(this.id_, this.$route.params.containerId, { + async editContainer(eenmalig) { + if(eenmalig) { + RequestHandler.handle( + TrashTemplateService.updateContainerTemplateEenmalig(this.id_, this.$route.params.containerId, { type: container_to_api(this.type), collection_day: { day: weekday_to_api(this.day), @@ -108,14 +117,33 @@ export default { end_hour: this.end_hour }, }), { - id: 'editContainerTemplateError', + id: 'editContainerTemplateEenmaligError', style: 'SNACKBAR' } ).then(() => this.$store.dispatch("snackbar/open", { - message: "De container is aangepast", + message: "De container is eenmalig aangepast", color: "success" })) + } else { + RequestHandler.handle( + TrashTemplateService.updateContainerTemplate(this.id_, this.$route.params.containerId, { + type: container_to_api(this.type), + collection_day: { + day: weekday_to_api(this.day), + start_hour: this.start_hour, + end_hour: this.end_hour + }, + }), { + id: 'editContainerTemplateError', + style: 'SNACKBAR' + } + ).then(() => + this.$store.dispatch("snackbar/open", { + message: "De container is aangepast", + color: "success" + })) + } await router.push({name: 'trashtemplateContainers', params: {id: this.$router.params.id}}) }, } diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerHeader.vue b/frontend/src/components/containerTemplates/containers/TrashContainerHeader.vue index 68e74a1d..f21ef752 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerHeader.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerHeader.vue @@ -11,7 +11,7 @@

Type

- + Acties From 07c75ad54ab7a24536d2cb4b23f8008c631e9563 Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 13:21:26 +0200 Subject: [PATCH 162/340] backend error handling voor vervangen afvaltemplate Signed-off-by: novdamme --- backend/exceptions/exceptionHandler.py | 13 +++++++++++++ backend/trashtemplates/views.py | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/backend/exceptions/exceptionHandler.py b/backend/exceptions/exceptionHandler.py index 21ac15ca..e5ce1a14 100644 --- a/backend/exceptions/exceptionHandler.py +++ b/backend/exceptions/exceptionHandler.py @@ -21,6 +21,7 @@ class ExceptionHandler: integer_error = "Veld moet een positief getal zijn." boolean_error = "Veld moet een Boolse waarde zijn." inactive_error = "Object is verwijderd." + vervangen_error = "Kan geen aanpassingen doen aan vervangen template" def __init__(self): self.errors = [] @@ -222,3 +223,15 @@ def check_not_inactive(self, template, fieldname): "field": fieldname }) return False + + def check_vervangen(self, template): + self.checked = False + if template is None: + return True + + if template.status == Status.VERVANGEN: + self.errors.append({ + "message": ExceptionHandler.vervangen_error, + "field": "template" + }) + return False diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index 76b30490..3a02fc71 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -8,6 +8,8 @@ from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny +from exceptions.exceptionHandler import ExceptionHandler + @api_view(["GET", "POST"]) @permission_classes([AllowAny]) @@ -50,6 +52,7 @@ def trash_template_view(request, template_id): template = get_trash_template(template_id) current_year, current_week = get_current_time() planning = get_current_week_planning() + handler = ExceptionHandler() if request.method == "GET": """ @@ -57,6 +60,8 @@ def trash_template_view(request, template_id): """ return Response(TrashContainerTemplateSerializerFull(template).data) + handler.check_vervangen(template) + handler.check() if request.method == "DELETE": """ Verwijderd de TrashContainerTemplate. @@ -147,6 +152,7 @@ def trash_template_view(request, template_id): @permission_classes([AllowAny]) def trash_containers_view(request, template_id, permanent): template = get_trash_template(template_id) + handler = ExceptionHandler() if request.method == "GET": """ @@ -155,6 +161,8 @@ def trash_containers_view(request, template_id, permanent): data = TrashContainerIdWrapperSerializer(template.trash_containers.all(), many=True).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "POST": """ Voegt de nieuwe TrashContainer toe aan de template adhv een TrashContainerIdWrapper. @@ -180,6 +188,7 @@ def trash_container_view(request, template_id, extra_id, permanent): template = get_trash_template(template_id) tc_id_wrapper = template.trash_containers.get(extra_id=extra_id) + handler = ExceptionHandler() if request.method == "GET": """ @@ -188,6 +197,8 @@ def trash_container_view(request, template_id, extra_id, permanent): data = TrashContainerIdWrapperSerializer(tc_id_wrapper).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "DELETE": """ Verwijderd de TrashContainer van de template. @@ -238,8 +249,8 @@ def trash_container_view(request, template_id, extra_id, permanent): @permission_classes([AllowAny]) def buildings_view(request, template_id, permanent): data = request.data - template = get_trash_template(template_id) + handler = ExceptionHandler() if request.method == "GET": """ @@ -248,6 +259,8 @@ def buildings_view(request, template_id, permanent): data = BuildingTrashContainerListSerializer(template.buildings.all(), many=True).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "POST": """ Voegt een nieuw gebouw samen met zijn selectie toe aan de template. @@ -275,6 +288,7 @@ def building_view(request, template_id, building_id, permanent): template = get_trash_template(template_id) building_list = template.buildings.get(building=building_id) + handler = ExceptionHandler() if request.method == "GET": """ @@ -283,6 +297,8 @@ def building_view(request, template_id, building_id, permanent): data = BuildingTrashContainerListSerializer(building_list).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "DELETE": """ Verwijderd het gebouw en zijn selectie van de template. From 8825ce8c9f5b65c3a8f017ed3d6373f13a59a572 Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 13:31:57 +0200 Subject: [PATCH 163/340] backend error handling voor vervangen studenttemplate Signed-off-by: novdamme --- backend/planning/views.py | 18 ++++++++++++++++-- .../TrashContainerTemplateCard.vue | 3 ++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index c4023e14..bb57d8ea 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -465,6 +465,8 @@ def student_templates_view(request): @permission_classes([AllowAny]) def student_template_view(request, template_id): template = get_student_template(template_id) + handler = ExceptionHandler() + if request.method == "GET": """ Geeft de StudentTemplate terug. @@ -472,6 +474,8 @@ def student_template_view(request, template_id): return Response(StudentTemplateSerializer(template).data) current_year, current_week = get_current_time() + handler.check_vervangen(template) + handler.check() if request.method == "DELETE": """ Verwijderd de StudentTemplate. @@ -571,6 +575,7 @@ def student_template_view(request, template_id): @permission_classes([AllowAny]) def rondes_view(request, template_id): template = get_student_template(template_id) + handler = ExceptionHandler() if request.method == "GET": """ @@ -579,6 +584,8 @@ def rondes_view(request, template_id): data = RondeSerializer(template.rondes.all(), many=True).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "POST": """ Voegt een nieuwe Ronde toe aan de template. @@ -621,9 +628,11 @@ def rondes_view(request, template_id): def ronde_view(request, template_id, ronde_id): template = get_student_template(template_id) ronde = Ronde.objects.get(id=ronde_id) - + handler = ExceptionHandler() current_year, current_week = get_current_time() + handler.check_vervangen(template) + handler.check() if request.method == "DELETE": """ Verwijderd een ronde en al zijn dagplanningen uit de template. @@ -648,6 +657,7 @@ def ronde_view(request, template_id, ronde_id): @permission_classes([AllowAny]) def dagplanningen_view(request, template_id, ronde_id): template = get_student_template(template_id) + handler = ExceptionHandler() if request.method == "GET": """ @@ -657,6 +667,8 @@ def dagplanningen_view(request, template_id, ronde_id): data = DagPlanningSerializer(dag_planningen, many=True).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "POST": """ Maakt een nieuwe DagPlanning aan. @@ -684,7 +696,7 @@ def dagplanningen_view(request, template_id, ronde_id): @permission_classes([AllowAny]) def dagplanning_view(request, template_id, dag_id, permanent): template = get_student_template(template_id) - + handler = ExceptionHandler() dag_planning = DagPlanning.objects.get(id=dag_id) if request.method == "GET": @@ -694,6 +706,8 @@ def dagplanning_view(request, template_id, dag_id, permanent): data = DagPlanningSerializer(dag_planning).data return Response(data) + handler.check_vervangen(template) + handler.check() if request.method == "DELETE": """ Verwijder een DagPlanning van de template diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue index 23ad7c90..9d438959 100644 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue +++ b/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue @@ -70,8 +70,9 @@ export default { RequestHandler.handle(TrashTemplateService.deleteTrashTemplate(this.data.id), { id: 'deleteTrashTemplateError', style: 'SNACKBAR' + }).then(() => { + router.go(0) // refresh the page }) - router.go(0) // refresh the page }, goToTrashTemplateBuildingsPage: function () { router.push({ From 9e60b9e3e7b11159ed1128529b1e150f75108c97 Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 13:34:48 +0200 Subject: [PATCH 164/340] linter Signed-off-by: novdamme --- .../containerTemplates/containers/TrashContainerCreate.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue index bcb06d4a..42aa50be 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue @@ -42,11 +42,9 @@ import TrashTemplateService from "@/api/services/TrashTemplateService"; import {container_to_api, ContainerType} from "@/api/models/ContainerType"; import {Weekday, weekday_to_api} from "@/api/models/Weekday"; import router from "@/router"; -import StateButtons from "@/components/StateButtons.vue"; export default { name: 'CreateTrashContainerView', - components: {StateButtons}, computed: { Weekday() { return Weekday From b39901ecd41ef5bb51affd90c266332aa6cdd7c9 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Mon, 15 May 2023 13:39:50 +0200 Subject: [PATCH 165/340] clear migrations --- backend/planning/migrations/0001_initial.py | 175 ------------------ backend/planning/migrations/0002_initial.py | 40 ---- .../0003_infoperbuilding_building.py | 25 --- ...0004_remove_dagplanning_status_and_more.py | 21 --- 4 files changed, 261 deletions(-) delete mode 100644 backend/planning/migrations/0001_initial.py delete mode 100644 backend/planning/migrations/0002_initial.py delete mode 100644 backend/planning/migrations/0003_infoperbuilding_building.py delete mode 100644 backend/planning/migrations/0004_remove_dagplanning_status_and_more.py diff --git a/backend/planning/migrations/0001_initial.py b/backend/planning/migrations/0001_initial.py deleted file mode 100644 index 4c55ee1e..00000000 --- a/backend/planning/migrations/0001_initial.py +++ /dev/null @@ -1,175 +0,0 @@ -# Generated by Django 4.2 on 2023-04-17 13:53 - -import django.contrib.postgres.fields -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("trashtemplates", "0001_initial"), - ("ronde", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="BuildingPicture", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "pictureType", - models.CharField( - choices=[ - ("AR", "Arrival"), - ("ST", "Storage"), - ("DE", "Departure"), - ("EX", "Extra"), - ], - max_length=2, - ), - ), - ("image", models.ImageField(upload_to="")), - ("time", models.DateTimeField()), - ("remark", models.TextField(default="")), - ], - ), - migrations.CreateModel( - name="DagPlanning", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "status", - django.contrib.postgres.fields.ArrayField( - base_field=models.CharField( - choices=[ - ("NS", "Not started"), - ("ST", "Started"), - ("FI", "Finished"), - ], - max_length=2, - ), - default=list, - size=None, - ), - ), - ( - "ronde", - models.ForeignKey( - on_delete=django.db.models.deletion.DO_NOTHING, to="ronde.ronde" - ), - ), - ], - ), - migrations.CreateModel( - name="StudentTemplate", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.TextField()), - ("even", models.BooleanField()), - ( - "status", - models.CharField( - choices=[ - ("E", "Eenmalig"), - ("V", "Vervangen"), - ("A", "Actief"), - ("I", "Inactief"), - ], - max_length=1, - ), - ), - ("start_hour", models.TimeField()), - ("end_hour", models.TimeField()), - ("year", models.IntegerField()), - ("week", models.IntegerField()), - ( - "dag_planningen", - models.ManyToManyField(blank=True, to="planning.dagplanning"), - ), - ( - "location", - models.ForeignKey( - on_delete=django.db.models.deletion.DO_NOTHING, - to="ronde.locatieenum", - ), - ), - ("rondes", models.ManyToManyField(blank=True, to="ronde.ronde")), - ], - ), - migrations.CreateModel( - name="WeekPlanning", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("week", models.IntegerField()), - ("year", models.IntegerField()), - ( - "student_templates", - models.ManyToManyField(blank=True, to="planning.studenttemplate"), - ), - ( - "trash_templates", - models.ManyToManyField( - blank=True, to="trashtemplates.trashcontainertemplate" - ), - ), - ], - ), - migrations.CreateModel( - name="InfoPerBuilding", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("remark", models.TextField(default="")), - ("date", models.DateField()), - ( - "dagPlanning", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="planning.dagplanning", - ), - ), - ], - ), - ] diff --git a/backend/planning/migrations/0002_initial.py b/backend/planning/migrations/0002_initial.py deleted file mode 100644 index 65544f67..00000000 --- a/backend/planning/migrations/0002_initial.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 4.2 on 2023-04-17 13:53 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ("pickupdays", "0001_initial"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("planning", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="dagplanning", - name="students", - field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name="dagplanning", - name="time", - field=models.ForeignKey( - on_delete=django.db.models.deletion.DO_NOTHING, - to="pickupdays.pickupday", - ), - ), - migrations.AddField( - model_name="buildingpicture", - name="infoPerBuilding", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="planning.infoperbuilding", - ), - ), - ] diff --git a/backend/planning/migrations/0003_infoperbuilding_building.py b/backend/planning/migrations/0003_infoperbuilding_building.py deleted file mode 100644 index d95dfa0d..00000000 --- a/backend/planning/migrations/0003_infoperbuilding_building.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2023-05-02 10:18 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("ronde", "0004_building_syndicus"), - ("planning", "0002_initial"), - ] - - operations = [ - migrations.AddField( - model_name="infoperbuilding", - name="building", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="ronde.building", - ), - ), - ] diff --git a/backend/planning/migrations/0004_remove_dagplanning_status_and_more.py b/backend/planning/migrations/0004_remove_dagplanning_status_and_more.py deleted file mode 100644 index 2d11921e..00000000 --- a/backend/planning/migrations/0004_remove_dagplanning_status_and_more.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2023-05-06 13:34 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("planning", "0003_infoperbuilding_building"), - ] - - operations = [ - migrations.RemoveField( - model_name="dagplanning", - name="status", - ), - migrations.RemoveField( - model_name="infoperbuilding", - name="date", - ), - ] From 1bd3c0e2c6315e6a1b1bf9e9b98bf602329b2fe8 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Mon, 15 May 2023 13:42:15 +0200 Subject: [PATCH 166/340] fix too many blank lines 228 linter --- backend/planning/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index d55c9e88..ebc8e569 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -223,8 +223,6 @@ def get(self, request, *args, **kwargs): week = request.query_params[ 'week'] if 'week' in request.query_params else None - - if infoPerBuilding is not None and year is not None and week is not None: try: print(week) From fa357bcfb6e9d3ddafb3de0b7ab4a7a3c88a6adf Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 13:57:44 +0200 Subject: [PATCH 167/340] backend inactief check Signed-off-by: novdamme --- backend/planning/views.py | 5 +++++ backend/trashtemplates/views.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/backend/planning/views.py b/backend/planning/views.py index bb57d8ea..0b000cad 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -474,6 +474,7 @@ def student_template_view(request, template_id): return Response(StudentTemplateSerializer(template).data) current_year, current_week = get_current_time() + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "DELETE": @@ -584,6 +585,7 @@ def rondes_view(request, template_id): data = RondeSerializer(template.rondes.all(), many=True).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "POST": @@ -631,6 +633,7 @@ def ronde_view(request, template_id, ronde_id): handler = ExceptionHandler() current_year, current_week = get_current_time() + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "DELETE": @@ -667,6 +670,7 @@ def dagplanningen_view(request, template_id, ronde_id): data = DagPlanningSerializer(dag_planningen, many=True).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "POST": @@ -706,6 +710,7 @@ def dagplanning_view(request, template_id, dag_id, permanent): data = DagPlanningSerializer(dag_planning).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "DELETE": diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index 3a02fc71..1b4ee874 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -60,6 +60,7 @@ def trash_template_view(request, template_id): """ return Response(TrashContainerTemplateSerializerFull(template).data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "DELETE": @@ -161,6 +162,7 @@ def trash_containers_view(request, template_id, permanent): data = TrashContainerIdWrapperSerializer(template.trash_containers.all(), many=True).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "POST": @@ -197,6 +199,7 @@ def trash_container_view(request, template_id, extra_id, permanent): data = TrashContainerIdWrapperSerializer(tc_id_wrapper).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "DELETE": @@ -259,6 +262,7 @@ def buildings_view(request, template_id, permanent): data = BuildingTrashContainerListSerializer(template.buildings.all(), many=True).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "POST": @@ -297,6 +301,7 @@ def building_view(request, template_id, building_id, permanent): data = BuildingTrashContainerListSerializer(building_list).data return Response(data) + handler.check_not_inactive(template, "template") handler.check_vervangen(template) handler.check() if request.method == "DELETE": From 7c46cbc566ad442a35d35584211a12b06fae240a Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 14:18:34 +0200 Subject: [PATCH 168/340] little fix Signed-off-by: novdamme --- backend/trashtemplates/views.py | 3 +-- .../containerTemplates/TrashContainerTemplateEdit.vue | 10 +++------- .../containers/TrashContainerEdit.vue | 5 +++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index 1b4ee874..75416523 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -98,7 +98,6 @@ def trash_template_view(request, template_id): Neemt een copy van de template om de geschiedenis te behouden als dit nodig is. """ data = request.data - permanent = data["permanent"] if "name" in data: pass @@ -118,7 +117,7 @@ def trash_template_view(request, template_id): else: data["location"] = template.location - if no_copy(template, permanent, current_year, current_week): + if no_copy(template, True, current_year, current_week): template.name = data["name"] template.even = data["even"] template.location = data["location"] diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue index d97ae818..05dd03b2 100644 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue +++ b/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue @@ -23,7 +23,7 @@ /> - + @@ -74,12 +74,8 @@ export default { await RequestHandler.handle(TrashTemplateService.updateTrashTemplate(this.$route.params.id, body), { id: 'CreateNewTrashTemplateError', style: 'SNACKBAR' - }).then(result => { - if (result['new_id'] !== null || result['new_id'] !== undefined) { - return router.push({name: 'editTrashtemplates', params: {id: result['new_id']}}) - } else { - return router.push({name: 'trashtemplates'}) - } + }).then(async () => { + return await router.push({name: 'trashtemplates'}) }) } } diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue index 2f163a98..9b1193f8 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue @@ -108,7 +108,7 @@ export default { methods: { async editContainer(eenmalig) { if(eenmalig) { - RequestHandler.handle( + await RequestHandler.handle( TrashTemplateService.updateContainerTemplateEenmalig(this.id_, this.$route.params.containerId, { type: container_to_api(this.type), collection_day: { @@ -125,6 +125,7 @@ export default { message: "De container is eenmalig aangepast", color: "success" })) + await router.replace({name: 'trashtemplates'}) } else { RequestHandler.handle( TrashTemplateService.updateContainerTemplate(this.id_, this.$route.params.containerId, { @@ -143,8 +144,8 @@ export default { message: "De container is aangepast", color: "success" })) + await router.replace({name: 'trashtemplateContainers', params: {id: this.id_}}) } - await router.push({name: 'trashtemplateContainers', params: {id: this.$router.params.id}}) }, } } From 74228e9acfea9ce705754cf098657496360d73f7 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Mon, 15 May 2023 14:24:44 +0200 Subject: [PATCH 169/340] fix frontend linter --- frontend/src/components/admin/AdminBuildingInfo.vue | 6 ++++-- frontend/src/components/admin/AdminBuildingInfoEdit.vue | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/admin/AdminBuildingInfo.vue b/frontend/src/components/admin/AdminBuildingInfo.vue index 202903be..9f249c19 100644 --- a/frontend/src/components/admin/AdminBuildingInfo.vue +++ b/frontend/src/components/admin/AdminBuildingInfo.vue @@ -135,7 +135,7 @@ import TrashPickupCard from "@/components/admin/TrashPickupCard.vue"; export default { name: "AdminBuildingInfo", - components: {TrashPickupCard, EditIcon, DeleteIcon, NormalButton, FotoCardAdmin, RoundBuildingCard, DatePicker}, + components: {TrashPickupCard, EditIcon, DeleteIcon, NormalButton, FotoCardAdmin, DatePicker}, data: () => { return { id: 0, @@ -159,7 +159,9 @@ export default { this.getBuildingInformation(this.$route.params.id).then(() => this.getStudentPosts()) this.getTrashPickUps() RequestHandler.handle(BuildingService.getBuildings(), {id: 'getBuildingsError', style: 'SNACKBAR'}) - .then(async result => this.buildings = result) + .then(async result => { + this.buildings = result + }) }, methods: { changed() { diff --git a/frontend/src/components/admin/AdminBuildingInfoEdit.vue b/frontend/src/components/admin/AdminBuildingInfoEdit.vue index 3962011c..e5190220 100644 --- a/frontend/src/components/admin/AdminBuildingInfoEdit.vue +++ b/frontend/src/components/admin/AdminBuildingInfoEdit.vue @@ -118,7 +118,9 @@ export default { this.manual.manualStatus), { id: 'updateManualFileError', style: 'SNACKBAR' - }).then(manual => this.manual = manual) + }).then(manual => { + this.manual = manual + }) } else { await RequestHandler.handle(BuildingService.updateManualStatusById(this.manual.id, { manualStatus: this.manual.manualStatus From bd6aff703020881bdbdd14ec9041fcb4126cee26 Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 15:18:04 +0200 Subject: [PATCH 170/340] linters fix Signed-off-by: novdamme --- backend/planning/views.py | 1 - frontend/src/api/EchoFetch | 2 +- frontend/src/components/AccountInformation.vue | 11 ++++++----- frontend/src/components/admin/AdminBuildingInfo.vue | 2 +- .../components/admin/mail/CreateEditMailTemplate.vue | 4 ++-- frontend/src/views/RegisterView.vue | 2 +- frontend/src/views/admin/CreateBuildingView.vue | 2 +- frontend/src/views/admin/CreateEditRoundView.vue | 4 ++-- frontend/src/views/admin/CreateLocationView.vue | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 60a7dade..36c2b929 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -10,7 +10,6 @@ from trashtemplates.util import add_if_match, remove_if_match, no_copy, update from users.permissions import StudentReadOnly, AdminPermission, \ SuperstudentPermission, StudentPermission -from trashtemplates.models import Status from .util import * from ronde.models import LocatieEnum diff --git a/frontend/src/api/EchoFetch b/frontend/src/api/EchoFetch index c66ca1aa..ec332734 160000 --- a/frontend/src/api/EchoFetch +++ b/frontend/src/api/EchoFetch @@ -1 +1 @@ -Subproject commit c66ca1aa83455e4e5f1391843ccdb996285dbd7a +Subproject commit ec332734a8affe447f7cf7283ce808652e7a990d diff --git a/frontend/src/components/AccountInformation.vue b/frontend/src/components/AccountInformation.vue index 073a7b9d..13538c52 100644 --- a/frontend/src/components/AccountInformation.vue +++ b/frontend/src/components/AccountInformation.vue @@ -61,7 +61,7 @@ ----> -
+
@@ -70,7 +70,7 @@
- @@ -108,6 +108,7 @@ export default { ], edit: false, smallScreen: false, + can_edit: true, errors: null }), async beforeMount() { @@ -127,11 +128,12 @@ export default { this.phone_nr = this.user.phone_nr this.role = this.user.role + this.can_edit = this.can_edit_permission if (!this.not_admin) { const currentUserRole = currentUser.role if (currentUserRole === 'SU') { if (this.role === 'AD') { - this.can_edit_permission = false + this.can_edit = false } else { this.roles = [{name: 'Aanvrager', value: 'AA'}, {name: 'Student', value: 'ST'}, {name: 'Superstudent', value: 'SU'}] @@ -170,8 +172,7 @@ export default { }).then(() => { this.edit = !this.edit this.errors = null - }) - .catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); }, delete_current() { UserService.deleteUserById(this.id) diff --git a/frontend/src/components/admin/AdminBuildingInfo.vue b/frontend/src/components/admin/AdminBuildingInfo.vue index 1bc7c693..5722d07e 100644 --- a/frontend/src/components/admin/AdminBuildingInfo.vue +++ b/frontend/src/components/admin/AdminBuildingInfo.vue @@ -158,7 +158,7 @@ export default { this.errors = null; await router.push({name: 'buildings'}) }) - .catch(async (error) => this.errors = await get_errors(error)); + .catch(async (error) => {this.errors = await get_errors(error)} ); }, async cancel_save() { diff --git a/frontend/src/components/admin/mail/CreateEditMailTemplate.vue b/frontend/src/components/admin/mail/CreateEditMailTemplate.vue index e02ef766..efcf69e1 100644 --- a/frontend/src/components/admin/mail/CreateEditMailTemplate.vue +++ b/frontend/src/components/admin/mail/CreateEditMailTemplate.vue @@ -106,7 +106,7 @@ export default { color: "success" }) router.push({name: 'mailtemplates'}) - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); }, editTemplate () { MailTemplateService.updateMailTemplate(this.$route.params.id,{ @@ -118,7 +118,7 @@ export default { color: "success" }) router.push({name: 'mailtemplates'}) - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); }, closeDialog: function () { diff --git a/frontend/src/views/RegisterView.vue b/frontend/src/views/RegisterView.vue index a8daa203..b5b5f49d 100644 --- a/frontend/src/views/RegisterView.vue +++ b/frontend/src/views/RegisterView.vue @@ -97,7 +97,7 @@ export default defineComponent({ await this.$store.dispatch("session/fetch"); await router.push({ name: 'home' }); - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); } } }) diff --git a/frontend/src/views/admin/CreateBuildingView.vue b/frontend/src/views/admin/CreateBuildingView.vue index eb7a8407..57a0752e 100644 --- a/frontend/src/views/admin/CreateBuildingView.vue +++ b/frontend/src/views/admin/CreateBuildingView.vue @@ -102,7 +102,7 @@ export default { color: "success" }) router.push({name: 'buildings'}) - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); }, async createManual() { diff --git a/frontend/src/views/admin/CreateEditRoundView.vue b/frontend/src/views/admin/CreateEditRoundView.vue index 9f2767e4..dc1b0b10 100644 --- a/frontend/src/views/admin/CreateEditRoundView.vue +++ b/frontend/src/views/admin/CreateEditRoundView.vue @@ -94,7 +94,7 @@ export default defineComponent({ color: "success" }); router.push({ name: 'rounds' }); - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); } else { RoundService.updateRoundById(Number(this.id), { name: this.name, @@ -106,7 +106,7 @@ export default defineComponent({ color: "success" }); router.push({ name: 'rounds' }); - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); } } } diff --git a/frontend/src/views/admin/CreateLocationView.vue b/frontend/src/views/admin/CreateLocationView.vue index c6977c96..d8d3392d 100644 --- a/frontend/src/views/admin/CreateLocationView.vue +++ b/frontend/src/views/admin/CreateLocationView.vue @@ -44,7 +44,7 @@ export default { message: "De locatie is toegevoegd", color: "success" }) - }).catch(async (error) => this.errors = await get_errors(error)); + }).catch(async (error) => {this.errors = await get_errors(error)}); router.push({name: 'locations'}) } } From 2c3974fea8f0e74c5421fdf5ab573f98609dd6c6 Mon Sep 17 00:00:00 2001 From: novdamme Date: Mon, 15 May 2023 15:20:27 +0200 Subject: [PATCH 171/340] fix Signed-off-by: novdamme --- frontend/src/views/student_template/StudentTemplateAddView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/student_template/StudentTemplateAddView.vue b/frontend/src/views/student_template/StudentTemplateAddView.vue index 6c599df1..44560636 100644 --- a/frontend/src/views/student_template/StudentTemplateAddView.vue +++ b/frontend/src/views/student_template/StudentTemplateAddView.vue @@ -81,7 +81,7 @@ export default { this.errors = null; router.push({name: 'studenttemplates', params: {id: response["new_id"]}}) }) - .catch(async (error) => this.errors = await get_errors(error)); + .catch(async (error) => {this.errors = await get_errors(error)}); } } } From 59b1a93bea325fee3efd319cfca9c4c49715208c Mon Sep 17 00:00:00 2001 From: jbvilla Date: Mon, 15 May 2023 19:55:12 +0200 Subject: [PATCH 172/340] test remarks --- .../src/components/student/InfoScreenBuilding.vue | 2 +- .../student/InfoScreenBuildingTest.spec.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/student/InfoScreenBuilding.vue b/frontend/src/components/student/InfoScreenBuilding.vue index eb9164d9..31404adf 100644 --- a/frontend/src/components/student/InfoScreenBuilding.vue +++ b/frontend/src/components/student/InfoScreenBuilding.vue @@ -16,7 +16,7 @@

Opmerkingen:

- {{ remark }} + {{ remark }}
diff --git a/frontend/tests/unit/Components/student/InfoScreenBuildingTest.spec.ts b/frontend/tests/unit/Components/student/InfoScreenBuildingTest.spec.ts index f83b5979..68e4d12d 100644 --- a/frontend/tests/unit/Components/student/InfoScreenBuildingTest.spec.ts +++ b/frontend/tests/unit/Components/student/InfoScreenBuildingTest.spec.ts @@ -37,4 +37,19 @@ describe("InfoScreenBuilding.vue", () => { }) + it('renders remarks correct', async () => { + const remarks = ['Remark 1', 'Remark 2', 'Remark 3'] + + await wrapper.setData({building: {remarks: remarks}}) + wrapper.vm.$nextTick(); + wrapper.vm.$forceUpdate() + + const remarkItems = wrapper.findAll('[data-test="remarks"]'); + expect(remarkItems).toHaveLength(remarks.length); + + remarkItems.forEach((item, index) => { + expect(item.text()).toBe(remarks[index]); + }); + }); + }) From 10e1e45961c340d09aed5ecaa10e6fa9a339a64c Mon Sep 17 00:00:00 2001 From: jbvilla Date: Mon, 15 May 2023 20:19:50 +0200 Subject: [PATCH 173/340] fotoCardStudentTest toegevoegd --- .../components/student/FotoCardStudent.vue | 10 ++-- .../student/fotoCardStudentTest.spec.ts | 54 +++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 frontend/tests/unit/Components/student/fotoCardStudentTest.spec.ts diff --git a/frontend/src/components/student/FotoCardStudent.vue b/frontend/src/components/student/FotoCardStudent.vue index deb1a907..f7d9726d 100644 --- a/frontend/src/components/student/FotoCardStudent.vue +++ b/frontend/src/components/student/FotoCardStudent.vue @@ -4,25 +4,25 @@ -

{{ data.remark }}

+

{{ data.remark }}

- +
-

{{ new Date(data.time).toLocaleString() }}

+

{{ new Date(data.time).toLocaleString() }}

- - + diff --git a/frontend/tests/unit/Components/student/fotoCardStudentTest.spec.ts b/frontend/tests/unit/Components/student/fotoCardStudentTest.spec.ts new file mode 100644 index 00000000..53a77a5f --- /dev/null +++ b/frontend/tests/unit/Components/student/fotoCardStudentTest.spec.ts @@ -0,0 +1,54 @@ +import { mount } from "@vue/test-utils"; +import FotoCardStudent from "@/components/student/FotoCardStudent.vue"; + +describe("InfoScreenBuilding.vue", () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(FotoCardStudent); + }) + + it("renders the component", () => { + expect(wrapper.exists()).toBe(true); + }) + + it("goToEditPage is called when clicked on the edit button", async () => { + FotoCardStudent.methods.goToEditPage = jest.fn() + wrapper = mount(FotoCardStudent) + const editButton = wrapper.find('[data-test="edit-button"]'); + await editButton.trigger('click') + await wrapper.vm.$nextTick(); + expect(FotoCardStudent.methods.goToEditPage).toHaveBeenCalled() + }) + + it("deletPost is called when clicked on the delete button", async () => { + FotoCardStudent.methods.deletePost = jest.fn() + wrapper = mount(FotoCardStudent) + const deleteButton = wrapper.find('[data-test="delete-button"]'); + await deleteButton.trigger('click') + await wrapper.vm.$nextTick(); + expect(FotoCardStudent.methods.deletePost).toHaveBeenCalled() + }) + + it("renders the important information", () => { + expect(wrapper.find('v-card')).toBeTruthy() + expect(wrapper.find('v-card-text')).toBeTruthy() + expect(wrapper.find('[data-test="edit-button"]')).toBeTruthy() + expect(wrapper.find('[data-test="delete-button"]')).toBeTruthy() + }) + + it("renders the props data", async () => { + const data = {time: new Date(), remark: "testRemark", image: "test",id: 1} + await wrapper.setProps({data: data}) + await wrapper.vm.$nextTick(); + const remark = wrapper.find('[data-test="remark"]'); + const image = wrapper.find('[data-test="image"]'); + const time = wrapper.find('[data-test="time"]'); + expect(remark.text()).toMatch(data.remark) + expect(image.attributes().src).toMatch(data.image) + expect(time.text()).toMatch(data.time.toLocaleString()) + }) + + +}) From fe2784c2fd685ded1c84b7f0a8e1523684e89938 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Mon, 15 May 2023 21:42:27 +0200 Subject: [PATCH 174/340] dayPlanBuilding test toegevoegd --- .../components/student/DayPlanBuilding.vue | 10 +-- .../student/dayPlanBuildingTest.spec.ts | 80 +++++++++++++++++++ 2 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 frontend/tests/unit/Components/student/dayPlanBuildingTest.spec.ts diff --git a/frontend/src/components/student/DayPlanBuilding.vue b/frontend/src/components/student/DayPlanBuilding.vue index 5ca8e0ff..f16b3f88 100644 --- a/frontend/src/components/student/DayPlanBuilding.vue +++ b/frontend/src/components/student/DayPlanBuilding.vue @@ -7,17 +7,17 @@ Example usage: diff --git a/frontend/tests/unit/Components/admin/BuildingCard.spec.ts b/frontend/tests/unit/Components/admin/BuildingCard.spec.ts index b13f9e3f..1179fa6d 100644 --- a/frontend/tests/unit/Components/admin/BuildingCard.spec.ts +++ b/frontend/tests/unit/Components/admin/BuildingCard.spec.ts @@ -5,18 +5,24 @@ describe('BuildingCard.vue', () => { let wrapper - const data = { - name: 'Test Gebouw', - id: 1, - adres: 'TestStraat 1', - ivago_klantnr: 1, - buildingID: "test", - manual: 1, - } beforeEach(async () => { BuildingCard.beforeMount = () => Promise.resolve(); + BuildingCard.methods.downloadDocument = jest.fn() + BuildingCard.methods.goToEditBuilding = jest.fn() + BuildingCard.methods.deletePost = jest.fn(); wrapper = mount(BuildingCard, { - props: data + props: { + data: { + name: 'Test Gebouw', + adres: 'TestStraat 1', + id: 0, + ivago_klantnr: 0, + buildingID: '', + manual: null, + containers: null, + location: null + } + } }); }); @@ -24,4 +30,37 @@ describe('BuildingCard.vue', () => { expect(wrapper.exists()).toBeTruthy(); }) + it('check for name', () => { + expect(wrapper.find('[data-test="name"]').text()).toBe('Test Gebouw'); + }); + + it('check for adress', () => { + expect(wrapper.find('[data-test="adres"]').text()).toBe('TestStraat 1'); + }); + + it('check for manual', () => { + expect(wrapper.find('[data-test="manual"]').text()).toBe('Handleiding'); + }); + + it('download manual', async () => { + const manualMenu = wrapper.find('[data-test="manual"]'); + await manualMenu.trigger('click'); + await wrapper.vm.$nextTick(); + expect(BuildingCard.methods.downloadDocument).toHaveBeenCalled(); + }); + + it('go to edit page', async () => { + const editButton = wrapper.find('[data-test="edit"]'); + await editButton.trigger('click'); + await wrapper.vm.$nextTick(); + expect(BuildingCard.methods.goToEditBuilding).toHaveBeenCalled(); + }); + + it('delete building', async () => { + const editButton = wrapper.find('[data-test="delete"]'); + await editButton.trigger('click'); + await wrapper.vm.$nextTick(); + expect(BuildingCard.methods.deletePost).toHaveBeenCalled(); + }); + }) From 942795a98970c5b9a6e3e4f8a3a8d99d5050a492 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Thu, 18 May 2023 15:38:12 +0200 Subject: [PATCH 212/340] Start AdminBuildingInfo.spec.ts --- .../Components/admin/AdminBuildingInfo.spec.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts diff --git a/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts b/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts new file mode 100644 index 00000000..4b31d14d --- /dev/null +++ b/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts @@ -0,0 +1,16 @@ +import {mount} from "@vue/test-utils" +import AdminBuildingInfo from "@/components/admin/AdminBuildingInfo.vue" + +describe('AdminBuildingInfo.vue', () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(AdminBuildingInfo); + }) + + it('render of component', () => { + expect(wrapper.exists()).toBeTruthy(); + }) + +}); From 053c88a081533baf28ded19e6ab6aee13e7d32f6 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Thu, 18 May 2023 15:39:11 +0200 Subject: [PATCH 213/340] fix jest.config --- frontend/jest.config.js | 13 ++++---- .../trashContainerTests.spec.js | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 8bb49b7d..c173297a 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -7,11 +7,10 @@ module.exports = { "moduleNameMapper": { "\\.(css|less)$": "/__mocks__/styleMock.js" }, - //collectCoverage: true, - // collectCoverageFrom: [ - // 'src/**/*.{js,vue,ts}', - // '!src/main.js', // Exclude the main.js file or other entry points - // '!**/node_modules/**', - // ], - // coverageReporters: ['html', 'text-summary'], + collectCoverageFrom: [ + 'src/**/*.{js,vue,ts}', + '!src/main.ts', // Exclude the main.js file or other entry points + '!**/node_modules/**', + '!src/api/EchoFetch/**', + ], } diff --git a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js new file mode 100644 index 00000000..bddaaac0 --- /dev/null +++ b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js @@ -0,0 +1,30 @@ +import { mount } from '@vue/test-utils'; +import TrashContainerCard from "@/components/containerTemplates/containers/TrashContainerCard.vue"; + +describe('trashContainerCard.vue', () => { + + let wrapper; + + beforeEach(() => { + TrashContainerCard.beforeMount = jest.fn(); + wrapper = mount(TrashContainerCard, { + propsData: { + data: { + trash_container: { + collection_day: { + day: 'Monday', + start_hour: '10 AM', + end_hour: '12 PM', + }, + type: 'Type A', + }, + extra_id: 1, + }, + }, + }); + }) + + it('render', () => { + expect(wrapper.exists()).toBe(true); + }) +}) From 8a02e5e42f0f27c43391e0d7ee7bff06c766502d Mon Sep 17 00:00:00 2001 From: jbvilla Date: Thu, 18 May 2023 15:46:40 +0200 Subject: [PATCH 214/340] TrasContainerCard test toegevoegd --- .../containers/TrashContainerCard.vue | 4 +-- .../trashContainerTests.spec.js | 31 +++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerCard.vue b/frontend/src/components/containerTemplates/containers/TrashContainerCard.vue index ab00b9a3..ddf70e49 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerCard.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerCard.vue @@ -14,12 +14,12 @@ - + - + diff --git a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js index bddaaac0..8152a6ff 100644 --- a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js +++ b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js @@ -1,4 +1,4 @@ -import { mount } from '@vue/test-utils'; +import {mount} from '@vue/test-utils'; import TrashContainerCard from "@/components/containerTemplates/containers/TrashContainerCard.vue"; describe('trashContainerCard.vue', () => { @@ -7,6 +7,8 @@ describe('trashContainerCard.vue', () => { beforeEach(() => { TrashContainerCard.beforeMount = jest.fn(); + TrashContainerCard.methods.editContainer = jest.fn(); + TrashContainerCard.methods.deleteContainer = jest.fn(); wrapper = mount(TrashContainerCard, { propsData: { data: { @@ -24,7 +26,32 @@ describe('trashContainerCard.vue', () => { }); }) - it('render', () => { + it('renders the component correctly', () => { expect(wrapper.exists()).toBe(true); + expect(TrashContainerCard.beforeMount).toBeCalled(); + + expect(wrapper.find('.container-border').exists()).toBe(true); + expect(wrapper.find('v-row[align="center"][justify="center"]').exists()).toBe(true); + expect(wrapper.findAll('v-col').length).toBe(6); + + expect(wrapper.find('v-col:nth-child(1) p.text-style-title').text()).toBe('Monday'); + expect(wrapper.find('v-col:nth-child(2) p').text()).toBe('10 AM - 12 PM'); + expect(wrapper.find('v-col:nth-child(3) p').text()).toBe('Type A'); + + expect(wrapper.find('v-col:nth-child(5) .button-style').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(6) .button-style').exists()).toBe(true); + }); + + it('edit button is called', async () => { + const editButton = wrapper.find('[data-test="edit"]'); + await editButton.trigger('click'); + expect(TrashContainerCard.methods.editContainer).toBeCalled(); }) + + it('delete button is called', async () => { + const deleteButton = wrapper.find('[data-test="delete"]'); + await deleteButton.trigger('click'); + expect(TrashContainerCard.methods.deleteContainer).toBeCalled(); + }) + }) From 93da89ea7de7fb8d353b1e1c0cdddbc24bd0b7d3 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Thu, 18 May 2023 16:21:52 +0200 Subject: [PATCH 215/340] Changed coverage config --- frontend/jest.config.js | 3 ++- frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/jest.config.js b/frontend/jest.config.js index c173297a..fd78d146 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -8,7 +8,8 @@ module.exports = { "\\.(css|less)$": "/__mocks__/styleMock.js" }, collectCoverageFrom: [ - 'src/**/*.{js,vue,ts}', + 'src/components/**/*.{js,vue,ts}', + 'src/views/**/*.{js,vue,ts}', '!src/main.ts', // Exclude the main.js file or other entry points '!**/node_modules/**', '!src/api/EchoFetch/**', diff --git a/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts b/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts index 4b31d14d..2a678147 100644 --- a/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts +++ b/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts @@ -6,6 +6,7 @@ describe('AdminBuildingInfo.vue', () => { let wrapper; beforeEach(() => { + AdminBuildingInfo.beforeMount = () => Promise.resolve(); wrapper = mount(AdminBuildingInfo); }) From 6c04ec532997dcd52e4eb343e13293b868da6e04 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Thu, 18 May 2023 17:11:42 +0200 Subject: [PATCH 216/340] Removed code comments --- frontend/src/components/admin/BuildingCard.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/components/admin/BuildingCard.vue b/frontend/src/components/admin/BuildingCard.vue index 77df39e4..34ff5033 100644 --- a/frontend/src/components/admin/BuildingCard.vue +++ b/frontend/src/components/admin/BuildingCard.vue @@ -109,7 +109,6 @@ export default { }, }, async beforeMount() { - /* await RequestHandler.handle(BuildingService.getManualById(this.data.id), { id: 'BuildingCardGetManual', style: 'SNACKBAR' @@ -117,7 +116,6 @@ export default { this.status = result.manualStatus this.manual = result.file.substring(result.file.indexOf('/api/')) }) - */ } } From 92534bf0e2115649941ebe223fa22d63f8b6364a Mon Sep 17 00:00:00 2001 From: jbvilla Date: Thu, 18 May 2023 17:21:30 +0200 Subject: [PATCH 217/340] trashContainerCreate test toegevoegd --- .../trashContainerTests.spec.js | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js index 8152a6ff..026dcd19 100644 --- a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js +++ b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js @@ -1,5 +1,8 @@ import {mount} from '@vue/test-utils'; import TrashContainerCard from "@/components/containerTemplates/containers/TrashContainerCard.vue"; +import TrashContainerCreate from "@/components/containerTemplates/containers/TrashContainerCreate.vue"; +import {triggerInput} from "../../../utils/testHelper"; + describe('trashContainerCard.vue', () => { @@ -55,3 +58,66 @@ describe('trashContainerCard.vue', () => { }) }) + +describe('trashContainerCreate.vue', () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(TrashContainerCreate); + }) + + it('renders the component correctly', () => { + expect(wrapper.exists()).toBe(true); + + expect(wrapper.find('.justify-center.my-10').exists()).toBe(true); + expect(wrapper.find('.text-h2').text()).toBe('Maak een nieuwe container aan'); + + expect(wrapper.find('.my-10.py-5.mx-auto.w-75').exists()).toBe(true); + expect(wrapper.find('v-form[fast-fail]').exists()).toBe(true); + expect(wrapper.findAll('.justify-space-between.mx-auto v-col').length).toBe(4); + + expect(wrapper.find('v-col:nth-child(1) v-select[label="type container"]').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(2) v-select[label="Dag van de week"]').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(3) v-text-field[label="Beginuur"]').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(4) v-text-field[label="Einduur"]').exists()).toBe(true); + + expect(wrapper.find('.overflow-hidden').text()).toBe('Aanmaken'); + }); + + it('createContainer is called', async () => { + TrashContainerCreate.methods.createContainer = jest.fn(); + wrapper = mount(TrashContainerCreate); + const createButton = wrapper.find('.overflow-hidden'); + await createButton.trigger('click'); + expect(TrashContainerCreate.methods.createContainer).toBeCalled(); + }) + + it('sets textfield values correctly', async () => { + const beginUur = wrapper.find('v-col:nth-child(3) v-text-field[label="Beginuur"]'); + const eindUur = wrapper.find('v-col:nth-child(4) v-text-field[label="Einduur"]'); + + const activator1 = (x) => { + return {start_hour: x} + } + + const activator2 = (x) => { + return {end_hour: x} + } + beginUur.element.value = '10 AM'; + eindUur.element.value = '12 PM'; + + await triggerInput(beginUur, wrapper,activator1); + await triggerInput(eindUur, wrapper,activator2); + + expect(wrapper.vm.start_hour).toBe('10 AM'); + expect(wrapper.vm.end_hour).toBe('12 PM'); + }) + + it('check v-select is rendered correctly', () => { + const vSelects = wrapper.findAll('v-select'); + + expect(vSelects.length).toBe(2); + }) + +}) From a596b92377cd4d67bcfda394b4aafc0d613d64c6 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Thu, 18 May 2023 17:33:38 +0200 Subject: [PATCH 218/340] testen aangepast --- .../TrashContainerTemplateEdit.vue | 2 +- .../trashContainerTemplateTests.spec.js | 6 +- .../trashContainerTests.spec.js | 66 ++++++++++++++++++- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue index 28d6c7f6..d1bd7ddc 100644 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue +++ b/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue @@ -39,7 +39,7 @@
- Aanpassen + Aanpassen diff --git a/frontend/tests/unit/Components/containerTemplates/trashContainerTemplateTests.spec.js b/frontend/tests/unit/Components/containerTemplates/trashContainerTemplateTests.spec.js index 957a632a..4f5d760d 100644 --- a/frontend/tests/unit/Components/containerTemplates/trashContainerTemplateTests.spec.js +++ b/frontend/tests/unit/Components/containerTemplates/trashContainerTemplateTests.spec.js @@ -208,11 +208,11 @@ describe('trashContainerTemplateEdit.vue', () => { }) it('create button is called', async () => { - TrashContainerTemplateCreate.methods.create = jest.fn(); - wrapper = mount(TrashContainerTemplateCreate); + TrashContainerTemplateEdit.methods.create = jest.fn(); + wrapper = mount(TrashContainerTemplateEdit); const createButton = wrapper.find('[data-test="create"]'); await createButton.trigger('click'); - expect(TrashContainerTemplateCreate.methods.create).toBeCalled(); + expect(TrashContainerTemplateEdit.methods.create).toBeCalled(); }) it('v-select exists', () => { diff --git a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js index 026dcd19..fdc37a63 100644 --- a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js +++ b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js @@ -1,6 +1,7 @@ import {mount} from '@vue/test-utils'; import TrashContainerCard from "@/components/containerTemplates/containers/TrashContainerCard.vue"; import TrashContainerCreate from "@/components/containerTemplates/containers/TrashContainerCreate.vue"; +import TrashContainerEdit from "@/components/containerTemplates/containers/TrashContainerEdit.vue"; import {triggerInput} from "../../../utils/testHelper"; @@ -107,8 +108,8 @@ describe('trashContainerCreate.vue', () => { beginUur.element.value = '10 AM'; eindUur.element.value = '12 PM'; - await triggerInput(beginUur, wrapper,activator1); - await triggerInput(eindUur, wrapper,activator2); + await triggerInput(beginUur, wrapper, activator1); + await triggerInput(eindUur, wrapper, activator2); expect(wrapper.vm.start_hour).toBe('10 AM'); expect(wrapper.vm.end_hour).toBe('12 PM'); @@ -121,3 +122,64 @@ describe('trashContainerCreate.vue', () => { }) }) + +describe('trashContainerEdit.vue', () => { + let wrapper; + + beforeEach(() => { + TrashContainerEdit.beforeMount = jest.fn(); + wrapper = mount(TrashContainerEdit); + }) + + it('renders the component correctly', () => { + expect(wrapper.exists()).toBe(true); + + expect(wrapper.find('.justify-center.my-10').exists()).toBe(true); + expect(wrapper.find('.text-h2').text()).toBe('Pas de container aan'); + + expect(wrapper.find('v-form[fast-fail]').exists()).toBe(true); + expect(wrapper.findAll('.justify-space-between.mx-auto v-col').length).toBe(4); + + expect(wrapper.find('v-col:nth-child(1) v-select[label="containerType"]').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(2) v-select[label="containerType"]').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(3) v-text-field[label="Beginuur"]').exists()).toBe(true); + expect(wrapper.find('v-col:nth-child(4) v-text-field[label="Einduur"]').exists()).toBe(true); + + expect(wrapper.find('.overflow-hidden').text()).toBe('Aanpassen'); + }); + + it('editContainer is called', async () => { + TrashContainerEdit.methods.editContainer = jest.fn(); + wrapper = mount(TrashContainerEdit); + const createButton = wrapper.find('.overflow-hidden'); + await createButton.trigger('click'); + expect(TrashContainerEdit.methods.editContainer).toBeCalled(); + }) + + it('sets textfield values correctly', async () => { + const beginUur = wrapper.find('v-col:nth-child(3) v-text-field[label="Beginuur"]'); + const eindUur = wrapper.find('v-col:nth-child(4) v-text-field[label="Einduur"]'); + + const activator1 = (x) => { + return {start_hour: x} + } + + const activator2 = (x) => { + return {end_hour: x} + } + beginUur.element.value = '10 AM'; + eindUur.element.value = '12 PM'; + + await triggerInput(beginUur, wrapper, activator1); + await triggerInput(eindUur, wrapper, activator2); + + expect(wrapper.vm.start_hour).toBe('10 AM'); + expect(wrapper.vm.end_hour).toBe('12 PM'); + }) + + it('check v-select is rendered correctly', () => { + const vSelects = wrapper.findAll('v-select'); + + expect(vSelects.length).toBe(2); + }) +}) From 216d4ece3de36cc6698e5d3961a6e04a6c0bb9fb Mon Sep 17 00:00:00 2001 From: jbvilla Date: Thu, 18 May 2023 17:37:21 +0200 Subject: [PATCH 219/340] TrashContainerHeader test toegevoegd --- .../trashContainerTests.spec.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js index fdc37a63..3ea92f7c 100644 --- a/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js +++ b/frontend/tests/unit/Components/containerTemplates/trashContainerTests.spec.js @@ -2,6 +2,7 @@ import {mount} from '@vue/test-utils'; import TrashContainerCard from "@/components/containerTemplates/containers/TrashContainerCard.vue"; import TrashContainerCreate from "@/components/containerTemplates/containers/TrashContainerCreate.vue"; import TrashContainerEdit from "@/components/containerTemplates/containers/TrashContainerEdit.vue"; +import TrashContainerHeader from "@/components/containerTemplates/containers/TrashContainerHeader.vue"; import {triggerInput} from "../../../utils/testHelper"; @@ -183,3 +184,41 @@ describe('trashContainerEdit.vue', () => { expect(vSelects.length).toBe(2); }) }) + +describe('TrashContainerHeader', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(TrashContainerHeader, { + propsData: { + round: true, + }, + }); + }); + + + it('renders the component correctly', () => { + expect(wrapper.exists()).toBe(true); + + expect(wrapper.find('.border').exists()).toBe(true); + expect(wrapper.find('.col').exists()).toBe(true); + expect(wrapper.findAll('.col').length).toBe(4); + + expect(wrapper.find('.col:nth-child(1) p[title="Dag"]').exists()).toBe(true); + expect(wrapper.find('.col:nth-child(2) p[title="Uren"]').exists()).toBe(true); + expect(wrapper.find('.col:nth-child(3) p[title="Type"]').exists()).toBe(true); + + expect(wrapper.find('.text-right').exists()).toBe(true); + expect(wrapper.find('.text-right').text()).toBe('Acties'); + }); + + it('sets the "round" prop correctly', async () => { + expect(wrapper.props('round')).toBe(true); + + await wrapper.setProps({ + round: false, + }); + + expect(wrapper.props('round')).toBe(false); + }); +}); From 1b9557b925d6366433322aec1813ec125b298ca9 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Thu, 18 May 2023 17:44:48 +0200 Subject: [PATCH 220/340] trashTemplateContainersList test toegevoegd --- .../TrashTemplateContainersList.vue | 2 +- .../trashContainerTests.spec.js | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/containerTemplates/containers/TrashTemplateContainersList.vue b/frontend/src/components/containerTemplates/containers/TrashTemplateContainersList.vue index a40378b3..5b3a251f 100644 --- a/frontend/src/components/containerTemplates/containers/TrashTemplateContainersList.vue +++ b/frontend/src/components/containerTemplates/containers/TrashTemplateContainersList.vue @@ -1,5 +1,5 @@ @@ -106,7 +106,6 @@ export default { this.adres = result.adres this.ivago_klantnr = result.ivago_klantnr this.selectedLocation = result.location - console.log(result.manual); if (result.manual != null) { this.manual = result.manual; this.manual.file = this.manual.file.substring(this.manual.file.indexOf('/api/')) diff --git a/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts b/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts index afb6d39d..b68c0b9f 100644 --- a/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts +++ b/frontend/tests/unit/Components/admin/AdminBuildingInfo.spec.ts @@ -19,6 +19,9 @@ describe('AdminBuildingInfo.vue', () => { beforeEach(() => { AdminBuildingInfo.beforeMount = () => Promise.resolve(); + AdminBuildingInfo.methods.open_manual = jest.fn(); + AdminBuildingInfo.methods.goEditPage = jest.fn(); + AdminBuildingInfo.methods.cancel_save = jest.fn(); wrapper = mount(AdminBuildingInfo); }) @@ -35,4 +38,48 @@ describe('AdminBuildingInfo.vue', () => { expect(wrapper.find('[data-test="client-nr"]').attributes().modelvalue).toBe("34"); }); + it('check for manual button and been pressed', async () => { + const manualButton = wrapper.find('[data-test="manual-button"]') + expect(manualButton.exists()).toBeTruthy(); + expect(wrapper.find('v-file-input ').exists()).toBeFalsy(); + await manualButton.trigger('click'); + expect(AdminBuildingInfo.methods.open_manual).toHaveBeenCalled(); + }) + + it('check for afvalcontainer add', () => { + expect(wrapper.find('[data-test="afval-button"]').exists()).toBeTruthy(); + }) + + it('should not have edit button', () => { + expect(wrapper.find('[data-test="save-button"]').exists()).toBeFalsy(); + }) + + it('check for edit mode', async () => { + await wrapper.setProps({edit: true}); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="afval-button"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test="save-button"]').exists()).toBeTruthy(); + }) + + it('check for confirmdialog', () => { + expect(wrapper.find('[data-test="dialog"]').exists()).toBeTruthy() + }) + + it('test if go to edit page works', async () => { + await wrapper.vm.$nextTick(); + const editButton = wrapper.find('[data-test="edit-button"]'); + expect(editButton.exists()).toBeTruthy(); + await editButton.trigger('click'); + expect(AdminBuildingInfo.methods.goEditPage).toHaveBeenCalled(); + }) + + it('cancel edit', async () => { + await wrapper.setProps({edit: true}); + await wrapper.vm.$nextTick(); + const editButton = wrapper.find('[data-test="cancel-button"]'); + expect(editButton.exists()).toBeTruthy(); + await editButton.trigger('click'); + expect(AdminBuildingInfo.methods.cancel_save).toHaveBeenCalled(); + }) + }); From 5a1dbbf6aebcb24a93fc3a64332c90d41d6a2ed0 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Thu, 18 May 2023 22:53:05 +0200 Subject: [PATCH 223/340] Added buildingHeader test --- .../src/components/admin/BuildingHeader.vue | 10 +++--- .../Components/admin/BuildingHeader.spec.ts | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 frontend/tests/unit/Components/admin/BuildingHeader.spec.ts diff --git a/frontend/src/components/admin/BuildingHeader.vue b/frontend/src/components/admin/BuildingHeader.vue index 92086044..54f3d762 100644 --- a/frontend/src/components/admin/BuildingHeader.vue +++ b/frontend/src/components/admin/BuildingHeader.vue @@ -2,20 +2,20 @@ -

Gebouw

+

Gebouw

-

Adres

+

Adres

-

Efficiëntie

+

Efficiëntie

-

Handleiding

+

Handleiding

-

Document status

+

Document status

diff --git a/frontend/tests/unit/Components/admin/BuildingHeader.spec.ts b/frontend/tests/unit/Components/admin/BuildingHeader.spec.ts new file mode 100644 index 00000000..2ef5fd57 --- /dev/null +++ b/frontend/tests/unit/Components/admin/BuildingHeader.spec.ts @@ -0,0 +1,31 @@ +import {mount} from "@vue/test-utils" +import BuildingHeader from "@/components/admin/BuildingHeader.vue" + +describe('BuildingHeader.vue', () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(BuildingHeader); + }) + + it('render of comonent', () => { + expect(wrapper.exists()).toBeTruthy(); + }) + + it('check field are present', async () => { + await wrapper.setProps({round: true}); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="title"]').text()).toBe('Gebouw') + expect(wrapper.find('[data-test="adres"]').text()).toBe('Adres') + expect(wrapper.find('[data-test="round"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test="manual"]').text()).toBe('Handleiding'); + expect(wrapper.find('[data-test="status"]').text()).toBe('Document status') + }); + + it('test for round', () => { + expect(wrapper.find('[data-test="round"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test="round"]').text()).toBe('Efficiëntie') + }) + +}) From 3e6d5fadd70f292a60c467806616173e8b164001 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Fri, 19 May 2023 00:36:52 +0200 Subject: [PATCH 224/340] Added DagPlanningCard.spec.ts test --- .../student_template/DagPlanningCard.vue | 14 ++-- .../student_template/DagPlanningCard.spec.ts | 68 +++++++++++++++++++ 2 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 frontend/tests/unit/Components/admin/student_template/DagPlanningCard.spec.ts diff --git a/frontend/src/components/admin/student_template/DagPlanningCard.vue b/frontend/src/components/admin/student_template/DagPlanningCard.vue index 8aa76dbb..066cacb4 100644 --- a/frontend/src/components/admin/student_template/DagPlanningCard.vue +++ b/frontend/src/components/admin/student_template/DagPlanningCard.vue @@ -7,20 +7,20 @@
-
+
{{ data.students.length > 0 ? data.students.map(student => student.first_name).join(", ") : 'Er zijn geen studenten aangewezen' }}
-
+
{{ format_day(data.day) }}
-
+
{{ data.start_hour + ' - ' }}
-
+
{{ data.end_hour }}
@@ -28,15 +28,15 @@ - Dagplanning aanpassen - + Verwijderen -
Om deze template aan te passen moeten eerst +
Om deze template aan te passen moeten eerst de eenmalige aanpassingen ongedaan worden.
diff --git a/frontend/tests/unit/Components/admin/student_template/DagPlanningCard.spec.ts b/frontend/tests/unit/Components/admin/student_template/DagPlanningCard.spec.ts new file mode 100644 index 00000000..244788e4 --- /dev/null +++ b/frontend/tests/unit/Components/admin/student_template/DagPlanningCard.spec.ts @@ -0,0 +1,68 @@ +import {mount} from "@vue/test-utils"; +import DagPlanningCard from "@/components/admin/student_template/DagPlanningCard.vue" + +describe('DagPlanningCard.vue', () => { + + let wrapper; + + beforeEach(() => { + DagPlanningCard.methods.remove_dagplanning = jest.fn() + wrapper = mount(DagPlanningCard); + }) + + it('render of component', () => { + expect(wrapper.exists()).toBeTruthy(); + }) + + it('check if the data gets rendered without "Vervaning"', async () => { + await wrapper.setProps({ + data: { + template_id: 1, + ronde_id: 1, + status: "Actief", + dag_id: 0, + students: [{first_name: 'Test'}], + day: 'MO', + start_hour: '17:00', + end_hour: '20:00' + } + }); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="students"]').text()).toBe('Test'); + expect(wrapper.find('[data-test="format"]').text()).toBe('Maandag'); + expect(wrapper.find('[data-test="start-hour"]').text()).toBe('17:00 -'); + expect(wrapper.find('[data-test="end-hour"]').text()).toBe('20:00'); + expect(wrapper.find('[data-test="edit"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test="remove-button"]').exists()).toBeTruthy(); + + expect(wrapper.find('[data-test="message"]').exists()).toBeFalsy(); + }); + + it('test delete button', async () => { + const deleteButton = wrapper.find('[data-test="remove-button"]'); + expect(deleteButton.exists()).toBeTruthy(); + await deleteButton.trigger('click'); + expect(DagPlanningCard.methods.remove_dagplanning).toHaveBeenCalled(); + }) + + it('vervanging render', async () => { + await wrapper.setProps({ + data: { + template_id: 1, + ronde_id: 1, + status: "Vervangen", + dag_id: 0, + students: [{first_name: 'Test'}], + day: 'MO', + start_hour: '17:00', + end_hour: '20:00' + } + }); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="edit"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test="remove-button"]').exists()).toBeFalsy(); + + expect(wrapper.find('[data-test="message"]').exists()).toBeTruthy(); + }) + +}); From 84834392631838d7e28abe1dd05a9695d5389b3c Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Fri, 19 May 2023 01:00:12 +0200 Subject: [PATCH 225/340] Added StudentTemplateCard.spec.ts test --- .../student_template/StudentTemplateCard.vue | 14 ++--- .../StudentTemplateCard.spec.ts | 63 +++++++++++++++++++ 2 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 frontend/tests/unit/Components/admin/student_template/StudentTemplateCard.spec.ts diff --git a/frontend/src/components/admin/student_template/StudentTemplateCard.vue b/frontend/src/components/admin/student_template/StudentTemplateCard.vue index 6d50dbaf..6305586c 100644 --- a/frontend/src/components/admin/student_template/StudentTemplateCard.vue +++ b/frontend/src/components/admin/student_template/StudentTemplateCard.vue @@ -7,31 +7,31 @@
-
+
{{ data.location }}
-
+
{{ data.even ? "even" : "oneven" }}
-
+
{{ data.name }}
-
{{ data.status }}
+
{{ data.status }}
- + Aanpassen - + Verwijderen -
Om deze template aan te passen moeten eerst de eenmalige aanpassingen ongedaan worden.
+
Om deze template aan te passen moeten eerst de eenmalige aanpassingen ongedaan worden.
diff --git a/frontend/tests/unit/Components/admin/student_template/StudentTemplateCard.spec.ts b/frontend/tests/unit/Components/admin/student_template/StudentTemplateCard.spec.ts new file mode 100644 index 00000000..a07e7d4a --- /dev/null +++ b/frontend/tests/unit/Components/admin/student_template/StudentTemplateCard.spec.ts @@ -0,0 +1,63 @@ +import {mount} from "@vue/test-utils"; +import StudentTemplateCard from "@/components/admin/student_template/StudentTemplateCard.vue"; + +describe('StudentTemplateCard.vue', () => { + + let wrapper; + + beforeEach(() => { + StudentTemplateCard.methods.delete_template = jest.fn(); + wrapper = mount(StudentTemplateCard); + }); + + it('render of component', () => { + expect(wrapper.exists()).toBeTruthy(); + }); + + it('render of data', async () => { + await wrapper.setProps({ + data: { + template_id: 0, + name: 'Test template', + location: 'Gent', + even: true, + status: 'Actief' + } + }); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="location"]').text()).toBe('Gent'); + expect(wrapper.find('[data-test="even"]').text()).toBe('even'); + expect(wrapper.find('[data-test="name"]').text()).toBe('Test template'); + expect(wrapper.find('[data-test="status"]').text()).toBe('Actief'); + + expect(wrapper.find('[data-test="edit"]').exists()).toBeTruthy() + expect(wrapper.find('[data-test="delete-button"]').exists()).toBeTruthy() + + expect(wrapper.find('[data-test="message"]').exists()).toBeFalsy() + }); + + it('delete template', async () => { + const deleteButton = wrapper.find('[data-test="delete-button"]'); + await deleteButton.trigger('click'); + expect(StudentTemplateCard.methods.delete_template).toHaveBeenCalled(); + }); + + it('vervangen render', async () => { + await wrapper.setProps({ + data: { + template_id: 0, + name: 'Test template', + location: 'Gent', + even: true, + status: 'Vervangen' + } + }); + await wrapper.vm.$nextTick(); + + expect(wrapper.find('[data-test="edit"]').exists()).toBeFalsy() + expect(wrapper.find('[data-test="delete-button"]').exists()).toBeFalsy() + + expect(wrapper.find('[data-test="message"]').exists()).toBeTruthy() + }) + +}); From 5784d2f5b7a4fc92354c14a850f75d6a0a9ba15b Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Fri, 19 May 2023 01:18:09 +0200 Subject: [PATCH 226/340] Added TemplateRondeCard.spec.ts test --- .../student_template/TemplateRondeCard.vue | 8 +-- .../TemplateRondeCard.spec.ts | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 frontend/tests/unit/Components/admin/student_template/TemplateRondeCard.spec.ts diff --git a/frontend/src/components/admin/student_template/TemplateRondeCard.vue b/frontend/src/components/admin/student_template/TemplateRondeCard.vue index 740e8254..a5de9c90 100644 --- a/frontend/src/components/admin/student_template/TemplateRondeCard.vue +++ b/frontend/src/components/admin/student_template/TemplateRondeCard.vue @@ -7,12 +7,12 @@
-
+
{{ data.location }}
-
+
{{ data.name }}
@@ -20,10 +20,10 @@ - + Dagplanningen - + Verwijderen diff --git a/frontend/tests/unit/Components/admin/student_template/TemplateRondeCard.spec.ts b/frontend/tests/unit/Components/admin/student_template/TemplateRondeCard.spec.ts new file mode 100644 index 00000000..d0e0e640 --- /dev/null +++ b/frontend/tests/unit/Components/admin/student_template/TemplateRondeCard.spec.ts @@ -0,0 +1,55 @@ +import {mount} from "@vue/test-utils"; +import TemplateRondeCard from "@/components/admin/student_template/TemplateRondeCard.vue"; + +describe('TemplateRondeCard.vue', () => { + + let wrapper; + + beforeEach(() => { + TemplateRondeCard.methods.on_delete = jest.fn(); + wrapper = mount(TemplateRondeCard); + }); + + it('render of component', () => { + expect(wrapper.exists()).toBeTruthy(); + }) + + it('render of data', async () => { + await wrapper.setProps({ + data: { + template_id: 0, + ronde_id: 0, + status: "Actief", + name: 'Test Template Ronde', + location: 'Gent' + } + }); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="location"]').text()).toBe('Gent'); + expect(wrapper.find('[data-test="name"]').text()).toBe('Test Template Ronde'); + + expect(wrapper.find('[data-test="dagplanning-button"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test="delete-button"]').exists()).toBeTruthy(); + }); + + it('delete template', async () => { + const deleteButton = wrapper.find('[data-test="delete-button"]'); + await deleteButton.trigger('click'); + expect(TemplateRondeCard.methods.on_delete).toHaveBeenCalled(); + }); + + it('template can not delete', async () => { + await wrapper.setProps({ + data: { + template_id: 0, + ronde_id: 0, + status: "Vervangen", + name: 'Test Template Ronde', + location: 'Gent' + } + }); + await wrapper.vm.$nextTick(); + expect(wrapper.find('[data-test="delete-button"]').exists()).toBeFalsy(); + }) + +}); From a94888302026c8c664da5fcc9788f4faf591fb9e Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Fri, 19 May 2023 08:50:43 +0200 Subject: [PATCH 227/340] all email to lowercase --- backend/users/views.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/users/views.py b/backend/users/views.py index a760b0f0..9ecf3f73 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -46,7 +46,7 @@ def user_view(request): def login_view(request): data = request.data response = Response() - email = data.get('email', None) + email = data.get('email', None).lower() password = data.get('password', None) handler = ExceptionHandler() @@ -124,7 +124,7 @@ def registration_view(request): }]}) user = get_user_model().objects.create_user( - request.data['email'], + request.data['email'].lower(), request.data['first_name'], request.data['last_name'], request.data['phone_nr'], @@ -162,7 +162,7 @@ def forgot_password(request): """ data = request.data - email = data["email"] + email = data["email"].lower() handler = ExceptionHandler() handler.check_not_blank_required(email, "email") @@ -188,7 +188,7 @@ def reset_password(request): Reset the password with the otp that is received via email. """ data = request.data - email = data.get("email") + email = data.get("email").lower() otp = data.get("otp") password = data.get("password") password2 = data.get("password2") @@ -235,7 +235,7 @@ def role_assignment_view(request): try: user = get_user_model().objects.get( - email=request.data['email']) + email=request.data['email'].lower()) except get_user_model().DoesNotExist: user = None @@ -277,7 +277,7 @@ def patch(self, request, *args, **kwargs): user = get_user_model().objects.get(id=id) - if user.email != data.get("email") and get_user_model().objects.filter(email=data["email"]).exists(): + if user.email.lower() != data.get("email").lower() and get_user_model().objects.filter(email=data["email"].lower()).exists(): raise serializers.ValidationError({ "errors": [{ "message": "Dit email adres is al in gebruik.", From d1096fde2e565819b274590653d0e594892ec3c7 Mon Sep 17 00:00:00 2001 From: novdamme Date: Fri, 19 May 2023 09:57:37 +0200 Subject: [PATCH 228/340] alleen rondes met matching locaties in studenttemplates Signed-off-by: novdamme --- frontend/src/views/student_template/StudentTemplateEditView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/student_template/StudentTemplateEditView.vue b/frontend/src/views/student_template/StudentTemplateEditView.vue index 99429b68..b0c1782e 100644 --- a/frontend/src/views/student_template/StudentTemplateEditView.vue +++ b/frontend/src/views/student_template/StudentTemplateEditView.vue @@ -60,7 +60,7 @@ Date: Fri, 19 May 2023 10:04:41 +0200 Subject: [PATCH 229/340] building order in round is now preserved --- backend/requirements.txt | 3 ++- backend/ronde/models.py | 3 ++- backend/ronde/views.py | 1 + docs/config.toml | 2 +- frontend/src/views/admin/CreateEditRoundView.vue | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 1e801183..54e7d573 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -9,4 +9,5 @@ Pillow model_bakery djangorestframework-simplejwt requests -django-cors-headers \ No newline at end of file +django-cors-headers +django-sortedm2m \ No newline at end of file diff --git a/backend/ronde/models.py b/backend/ronde/models.py index ce61b300..5b3c1766 100644 --- a/backend/ronde/models.py +++ b/backend/ronde/models.py @@ -1,6 +1,7 @@ from django.contrib.postgres.fields import ArrayField from django.db import models from django.conf import settings +from sortedm2m.fields import SortedManyToManyField import uuid @@ -121,4 +122,4 @@ class Ronde(models.Model): on_delete=models.DO_NOTHING, verbose_name="Locatie" ) - buildings = models.ManyToManyField(Building, blank=True) + buildings = SortedManyToManyField(Building, blank=True) diff --git a/backend/ronde/views.py b/backend/ronde/views.py index a9b9583c..30521183 100644 --- a/backend/ronde/views.py +++ b/backend/ronde/views.py @@ -1,3 +1,4 @@ +from django.http import HttpResponseNotFound from rest_framework.permissions import IsAuthenticatedOrReadOnly from .models import * diff --git a/docs/config.toml b/docs/config.toml index b0002194..c7c9dd0e 100644 --- a/docs/config.toml +++ b/docs/config.toml @@ -1,4 +1,4 @@ -baseURL = "/docs" +baseURL = "" title = "Documentatie van Dr Trottoir project" # Language settings diff --git a/frontend/src/views/admin/CreateEditRoundView.vue b/frontend/src/views/admin/CreateEditRoundView.vue index dc1b0b10..d985fea6 100644 --- a/frontend/src/views/admin/CreateEditRoundView.vue +++ b/frontend/src/views/admin/CreateEditRoundView.vue @@ -50,7 +50,7 @@ export default defineComponent({ locations: [], buildings: [], location: null, - selected: null, + selected: [], name: '', errors: null }), From 8cc1131bb44620b56f14a0f28c5f93e7f19c26c4 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 10:07:23 +0200 Subject: [PATCH 230/340] linter --- backend/ronde/views.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/backend/ronde/views.py b/backend/ronde/views.py index 30521183..672f0601 100644 --- a/backend/ronde/views.py +++ b/backend/ronde/views.py @@ -1,19 +1,16 @@ -from django.http import HttpResponseNotFound -from rest_framework.permissions import IsAuthenticatedOrReadOnly - -from .models import * -from .serializers import * - -from exceptions.exceptionHandler import ExceptionHandler import os -from django.conf import settings +from exceptions.exceptionHandler import ExceptionHandler from rest_framework import generics, status from rest_framework.parsers import MultiPartParser, FormParser +from rest_framework.permissions import IsAuthenticatedOrReadOnly from rest_framework.response import Response from users.permissions import StudentReadOnly, AdminPermission, \ SuperstudentPermission, SyndicusPermission +from .models import * +from .serializers import * + class LocatieEnumListCreateView(generics.ListCreateAPIView): queryset = LocatieEnum.objects.all() From 0bae870b7bb27dc32576e688856c452d4276ef70 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 10:27:27 +0200 Subject: [PATCH 231/340] do router push after buildings are updated so page always gets updated. --- .../buildings/TrashTemplateBuildingAdd.vue | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingAdd.vue b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingAdd.vue index 8ea24731..2de401ae 100644 --- a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingAdd.vue +++ b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingAdd.vue @@ -72,10 +72,10 @@ export default { async aanpassen(eenmalig) { /* Al de gebouwen die niet in de originele lijst zaten en dus nieuw toegevoegd moeten worden. */ - this.building_chosen.forEach(building_id => { + for (const building_id of this.building_chosen) { if (!this.building_originals.includes(building_id)) { if (!eenmalig) { - RequestHandler.handle(TrashTemplateService.newBuildingToTemplate(this.$route.params.id, { + await RequestHandler.handle(TrashTemplateService.newBuildingToTemplate(this.$route.params.id, { building: building_id, selection: [] }), { @@ -83,7 +83,7 @@ export default { style: 'SNACKBAR' }) } else { - RequestHandler.handle(TrashTemplateService.newBuildingToTemplateEenmalig(this.$route.params.id, { + await RequestHandler.handle(TrashTemplateService.newBuildingToTemplateEenmalig(this.$route.params.id, { building: building_id, selection: [] }), { @@ -92,16 +92,16 @@ export default { }) } } - }) + } /* Al de gebouwen die niet in de geselecteerde lijst zitten en dus verwijderd moeten worden. */ - this.building_originals.forEach((building) => { + for (const building of this.building_originals) { if (!this.building_chosen.includes(building)) { RequestHandler.handle(TrashTemplateService.deleteBuildingTemplate(this.$route.params.id, building), { id: 'deletebuildingError', style: 'SNACKBAR' }) } - }) + } return await router.push({name: 'trashtemplateBuildings', params: {id: this.$route.params.id}}) } } From 0bd9a3bbe13806a7a3a9328b6d26328acec275b2 Mon Sep 17 00:00:00 2001 From: novdamme Date: Fri, 19 May 2023 11:08:23 +0200 Subject: [PATCH 232/340] user heeft locations + filter op locations en AA role bij inplanning + locatie niet aanpasbaar Signed-off-by: novdamme --- backend/planning/views.py | 8 +---- backend/ronde/views.py | 5 ++-- backend/users/models.py | 12 ++------ backend/users/permissions.py | 5 ++++ backend/users/serializers.py | 3 +- backend/users/views.py | 3 ++ frontend/src/api/wrappers/AuthWrappers.ts | 5 +++- frontend/src/views/RegisterView.vue | 23 +++++++++++++-- .../student_template/DagplanningEditView.vue | 5 ++-- .../StudentTemplateEditView.vue | 29 ++++++------------- 10 files changed, 52 insertions(+), 46 deletions(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index 7059f6b0..28f2ee46 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -542,11 +542,6 @@ def patch(self, request, *args, **kwargs): if "name" not in data: data["name"] = template.name - if "location" not in data: - data["location"] = template.location - else: - data["location"] = LocatieEnum.objects.get(id=data["location"]) - if "start_hour" not in data: data["start_hour"] = template.start_hour else: @@ -566,7 +561,6 @@ def patch(self, request, *args, **kwargs): response = {"message": "Success"} if no_copy(template, True, current_year, current_week): template.name = data["name"] - template.location = data["location"] template.start_hour = data["start_hour"] template.end_hour = data["end_hour"] template.save() @@ -576,7 +570,7 @@ def patch(self, request, *args, **kwargs): name=data["name"], even=template.even, status=template.status, - location=data["location"], + location=template.location, start_hour=data["start_hour"], end_hour=data["end_hour"], year=current_year, diff --git a/backend/ronde/views.py b/backend/ronde/views.py index 50bb6f2e..eea34ffb 100644 --- a/backend/ronde/views.py +++ b/backend/ronde/views.py @@ -9,7 +9,7 @@ from rest_framework.parsers import MultiPartParser, FormParser from rest_framework.response import Response from users.permissions import StudentReadOnly, AdminPermission, \ - SuperstudentPermission, SyndicusPermission + SuperstudentPermission, SyndicusPermission, AllowAnyReadOnly from trashtemplates.util import update from planning.util import get_current_week_planning, make_copy @@ -17,8 +17,7 @@ class LocatieEnumListCreateView(generics.ListCreateAPIView): queryset = LocatieEnum.objects.all() serializer_class = LocatieEnumSerializer - permission_classes = [ - StudentReadOnly | AdminPermission | SuperstudentPermission] + permission_classes = [ AllowAnyReadOnly ] def post(self, request, *args, **kwargs): data = request.data diff --git a/backend/users/models.py b/backend/users/models.py index ff91fca8..ae6894af 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -1,6 +1,6 @@ from django.db import models from django.contrib.auth.models import AbstractUser, BaseUserManager -from rest_framework import serializers +from ronde.models import LocatieEnum import random import string @@ -33,15 +33,6 @@ class RoleAssignment(models.Model): class CustomUserManager(BaseUserManager): def create_user(self, email, first_name, last_name, phone_nr, password): - if not email: - raise serializers.ValidationError( - { - "errors": [ - { - "message": "email is required", "field": "email" - } - ] - }, code='invalid') user = self.model( email=self.normalize_email(email), @@ -100,6 +91,7 @@ class User(AbstractUser): max_length=25, default="" ) + locations = models.ManyToManyField(LocatieEnum) objects = CustomUserManager() diff --git a/backend/users/permissions.py b/backend/users/permissions.py index 224e34c7..8474fa0e 100644 --- a/backend/users/permissions.py +++ b/backend/users/permissions.py @@ -2,6 +2,11 @@ from planning.models import InfoPerBuilding, DagPlanning +class AllowAnyReadOnly(permissions.BasePermission): + def has_permission(self, request, view): + return request.method in permissions.SAFE_METHODS + + class ReadOnly(permissions.BasePermission): def has_permission(self, request, view): return request.method in permissions.SAFE_METHODS and request.user and not request.user.is_anonymous diff --git a/backend/users/serializers.py b/backend/users/serializers.py index 1be1191b..371e8e68 100644 --- a/backend/users/serializers.py +++ b/backend/users/serializers.py @@ -27,7 +27,8 @@ class Meta: 'first_name', 'last_name', 'phone_nr', - 'role' + 'role', + 'locations' ] diff --git a/backend/users/views.py b/backend/users/views.py index a760b0f0..8a0c8092 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -114,6 +114,7 @@ def registration_view(request): handler.check_not_blank_required(data.get("password2"), "password2") handler.check_integer_required(data.get("phone_nr"), "phone_nr") handler.check_equal(data.get("password"), data.get("password2"), "password2") + handler.check_required(data.get("locations"), "locations") handler.check() if get_user_model().objects.filter(email=data["email"]).exists(): @@ -130,6 +131,8 @@ def registration_view(request): request.data['phone_nr'], request.data['password'] ) + user.locations.set(request.data['locations']) + refresh = RefreshToken.for_user(user) response.set_cookie( key=settings.SIMPLE_JWT['AUTH_COOKIE'], diff --git a/frontend/src/api/wrappers/AuthWrappers.ts b/frontend/src/api/wrappers/AuthWrappers.ts index 2fc8dd62..3b3b15f7 100644 --- a/frontend/src/api/wrappers/AuthWrappers.ts +++ b/frontend/src/api/wrappers/AuthWrappers.ts @@ -6,13 +6,16 @@ export class AuthRegisterWrapper { public last_name: string; public phone_nr: string; - constructor(email: string, password: string, password2: string, first_name: string, last_name: string, phone_nr: string) { + public locations: []; + + constructor(email: string, password: string, password2: string, first_name: string, last_name: string, phone_nr: string, locations: []) { this.email = email; this.password = password; this.password2 = password2; this.first_name = first_name; this.last_name = last_name; this.phone_nr = phone_nr; + this.locations = locations; } } diff --git a/frontend/src/views/RegisterView.vue b/frontend/src/views/RegisterView.vue index b5b5f49d..9ddcda86 100644 --- a/frontend/src/views/RegisterView.vue +++ b/frontend/src/views/RegisterView.vue @@ -26,7 +26,13 @@ @@ -55,6 +61,8 @@ import NormalButton from '@/components/NormalButton.vue'; import LoginTopBar from "@/components/LoginTopBar.vue"; import router from '@/router'; import {check_errors, get_errors} from "@/error_handling"; +import {RequestHandler} from "@/api/RequestHandler"; +import RoundService from "@/api/services/RoundService"; export default defineComponent({ name: 'RegisterView', @@ -71,8 +79,18 @@ export default defineComponent({ password: '', password2: '', phone_nr: '', + locations: [], + selected_locations: null, errors: null }), + beforeCreate() { + RequestHandler.handle(RoundService.getLocations(), { + id: 'getLocationsError', + style: 'SNACKBAR' + }).then(l => { + this.locations = l; + }).catch(() => null); + }, methods: { check_errors, async apiRegister () { @@ -82,7 +100,8 @@ export default defineComponent({ this.password2, this.firstname, this.lastname, - this.phone_nr + this.phone_nr, + this.selected_locations ); AuthService.register(wrapper).then(async () => { diff --git a/frontend/src/views/student_template/DagplanningEditView.vue b/frontend/src/views/student_template/DagplanningEditView.vue index 8a303be8..bb67df2d 100644 --- a/frontend/src/views/student_template/DagplanningEditView.vue +++ b/frontend/src/views/student_template/DagplanningEditView.vue @@ -12,7 +12,7 @@ result).catch(() => null); this.status = this.state_mapping[template.status] + this.location = template.location // get all users this.all_students = await RequestHandler.handle(UserService.getUsers(), { @@ -99,7 +101,6 @@ export default { style: 'SNACKBAR' }).then(result => result).catch(() => []); - }, methods: { format_day(day) { diff --git a/frontend/src/views/student_template/StudentTemplateEditView.vue b/frontend/src/views/student_template/StudentTemplateEditView.vue index b0c1782e..0f8d9fb4 100644 --- a/frontend/src/views/student_template/StudentTemplateEditView.vue +++ b/frontend/src/views/student_template/StudentTemplateEditView.vue @@ -11,7 +11,12 @@ - + @@ -21,15 +26,8 @@ - - + + @@ -81,7 +79,6 @@ diff --git a/frontend/src/components/admin/ListPage.vue b/frontend/src/components/admin/ListPage.vue index 0fb8d345..e474b606 100644 --- a/frontend/src/components/admin/ListPage.vue +++ b/frontend/src/components/admin/ListPage.vue @@ -62,7 +62,7 @@ export default { }, addFunction: { type: Function, - default: null, + default: () => null, required: true }, headComponent: { @@ -90,7 +90,8 @@ export default { default: false }, refresh_function: { - type: Function + type: Function, + default: () => null }, search: { type: Boolean, diff --git a/frontend/src/components/admin/RoundListPage.vue b/frontend/src/components/admin/RoundListPage.vue index bf965699..d5a6bad1 100644 --- a/frontend/src/components/admin/RoundListPage.vue +++ b/frontend/src/components/admin/RoundListPage.vue @@ -55,7 +55,7 @@ export default { }, addFunction: { type: Function, - default: null, + default: () => null, required: true }, headComponent: { diff --git a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue index c1dc9877..f19e3033 100644 --- a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue +++ b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue @@ -17,10 +17,10 @@ @@ -35,7 +35,6 @@ import {RequestHandler} from "@/api/RequestHandler"; import TrashTemplateService from "@/api/services/TrashTemplateService"; import router from "@/router"; -import BuildingContainer from "@/api/models/BuildingContainer"; import StateButtons from "@/components/StateButtons.vue"; export default { @@ -43,10 +42,17 @@ export default { components: {StateButtons}, data() { return { - building: BuildingContainer, + building: null, trash_ids: [], container_choices: [], - status: "I" + status: "I", + mapping: { + GL: 'GLAS', + GF: 'GFT', + PM: 'PMD', + PK: 'PK', + RE: 'REST' + } } }, async beforeMount() { diff --git a/frontend/src/components/util/ConfirmDialog.vue b/frontend/src/components/util/ConfirmDialog.vue index d51092c2..7eaef00c 100644 --- a/frontend/src/components/util/ConfirmDialog.vue +++ b/frontend/src/components/util/ConfirmDialog.vue @@ -35,7 +35,7 @@ export default { components: {NormalButton}, props: { text: { type: String }, - confirm_function: { type: Function } + confirm_function: { type: Function, default: () => null } }, data: () => { return { diff --git a/frontend/src/views/BuildingView.vue b/frontend/src/views/BuildingView.vue index c83f667b..8cb9be58 100644 --- a/frontend/src/views/BuildingView.vue +++ b/frontend/src/views/BuildingView.vue @@ -3,7 +3,9 @@ + :first-day-of-week="1" :masks="masks" :attributes="attrs" view="weekly" v-on:dayclick="changed" + v-on:did-move="(e) => {setWeek(e); getContainers()}" + />

Opmerkingen voor {{building.name}} op {{new Date(date).toLocaleDateString('nl-BE', {weekday: 'long', day: 'numeric', month: 'long'})}} @@ -88,6 +90,7 @@ import {DatePicker} from "v-calendar"; import FotoCardAdmin from "@/components/admin/FotoCardAdmin.vue"; import {getWeek} from "@/api/DateUtil"; import PlanningService from "@/api/services/PlanningService"; +import TrashTemplateService from "@/api/services/TrashTemplateService"; export default { name: "BuildingView", @@ -97,25 +100,27 @@ export default { building: null, masks: { modelValue: 'YYYY-MM-DD' }, date: new Date().toISOString().split('T')[0], + week: new Date(), arrivals: [], departs: [], storages: [], - attrs: [ - { - dates: new Date(), - popover: { - label: 'Glas' - }, - dot: 'yellow' - }, - { - dates: new Date(), - popover: { - label: 'GFT' - }, - dot: 'green' - } - ] + attrs: [], + mapping: { + GL: {type: 'GLAS', color: 'yellow'}, + GF: {type: 'GFT', color: 'green'}, + PM: {type: 'PMD', color: 'orange'}, + PK: {type: 'PK', color: 'blue'}, + RE: {type: 'REST', color: 'gray'} + }, + day_map: { + MO: 1, + TU: 2, + WE: 3, + TH: 4, + FR: 5, + SA: 6, + SU: 0, + } }), beforeMount() { RequestHandler.handle(RoundService.getBuildingByUUID(this.id), { @@ -124,12 +129,39 @@ export default { }).then(building => { this.building = building; this.changed(); + this.getContainers(); }).catch(() => null) }, methods: { changed() { this.getStudentPosts(); }, + setWeek(e) { + this.week = new Date(e[0].viewDays[1].id); + }, + getContainers() { + let week = getWeek(this.week); + if (this.week.getUTCDay() === 0) week -= 1; + RequestHandler.handle(TrashTemplateService.getContainers(this.week.getFullYear(), week), { + id: "getContainersError", + style: "NONE" + }).then(containers => { + if (this.building !== null && this.building.id.toString() in containers) { + const cs = containers[this.building.id.toString()]; + this.attrs = cs.map(container => { + const container_date = new Date(this.week); + const dist = this.day_map[container.collection_day.day] - container_date.getDay(); + container_date.setDate(container_date.getDate() + dist); + return { + dates: container_date, + popover: { + label: this.mapping[container.type].type + }, + dot: this.mapping[container.type].color + }}); + } + }).catch(() => null); + }, async getStudentPosts(){ const date = new Date(this.date) let week = getWeek(date) diff --git a/frontend/src/views/syndicus/SyndicusHome.vue b/frontend/src/views/syndicus/SyndicusHome.vue index b4f7ceb1..b81cccd0 100644 --- a/frontend/src/views/syndicus/SyndicusHome.vue +++ b/frontend/src/views/syndicus/SyndicusHome.vue @@ -5,7 +5,9 @@ + :first-day-of-week="1" :masks="masks" :attributes="attrs" view="weekly" v-on:dayclick="changed" + v-on:did-move="(e) => {setWeek(e); getContainers()}" + />

@@ -15,7 +17,7 @@ @@ -115,12 +117,14 @@ import { getWeek } from "@/api/DateUtil"; import PlanningService from "@/api/services/PlanningService"; import QRCodeVue3 from "qrcode-vue3"; import NormalButton from "@/components/NormalButton.vue"; +import TrashTemplateService from "@/api/services/TrashTemplateService"; export default { name: "SyndicusHome", components: {NormalButton, FotoCardAdmin, DatePicker, QRCodeVue3}, data: () => ({ date: new Date().toISOString().split('T')[0], + week: new Date(), buildings: [], arrivals: [], departs: [], @@ -128,22 +132,23 @@ export default { building: null, dialog: false, masks: { modelValue: 'YYYY-MM-DD' }, - attrs: [ - { - dates: new Date(), - popover: { - label: 'Glas' - }, - dot: 'yellow' - }, - { - dates: new Date(), - popover: { - label: 'GFT' - }, - dot: 'green' - } - ] + mapping: { + GL: {type: 'GLAS', color: 'yellow'}, + GF: {type: 'GFT', color: 'green'}, + PM: {type: 'PMD', color: 'orange'}, + PK: {type: 'PK', color: 'blue'}, + RE: {type: 'REST', color: 'gray'} + }, + day_map: { + MO: 1, + TU: 2, + WE: 3, + TH: 4, + FR: 5, + SA: 6, + SU: 0, + }, + attrs: [] }), beforeMount() { RequestHandler.handle(RoundService.getBuildingsForSyndicus(), { @@ -153,12 +158,16 @@ export default { this.buildings = buildings; if (buildings.length > 0) this.building = buildings[0]; this.changed(); + this.getContainers(); }).catch(() => null); }, methods: { changed() { this.getStudentPosts(); }, + setWeek(e) { + this.week = new Date(e[0].viewDays[1].id); + }, resetQR() { RequestHandler.handle(RoundService.resetBuilding(this.building.buildingID), { id: 'resetBuildingError', @@ -200,6 +209,29 @@ export default { iframe.parentNode.removeChild(iframe); }); }, + getContainers() { + let week = getWeek(this.week); + if (this.week.getUTCDay() === 0) week -= 1; + RequestHandler.handle(TrashTemplateService.getContainers(this.week.getFullYear(), week), { + id: "getContainersError", + style: "NONE" + }).then(containers => { + if (this.building !== null && this.building.id.toString() in containers) { + const cs = containers[this.building.id.toString()]; + this.attrs = cs.map(container => { + const container_date = new Date(this.week); + const dist = this.day_map[container.collection_day.day] - container_date.getDay(); + container_date.setDate(container_date.getDate() + dist); + return { + dates: container_date, + popover: { + label: this.mapping[container.type].type + }, + dot: this.mapping[container.type].color + }}); + } + }).catch(() => null); + }, async getStudentPosts(){ const date = new Date(this.date) let week = getWeek(date) From 5c82456f30c6d20c6d1835fc22b76e57f25fc5ca Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 20:01:32 +0200 Subject: [PATCH 247/340] add containers to student planning --- frontend/src/views/BuildingPageStudent.vue | 14 +++---- frontend/src/views/DayPlanView.vue | 48 ++++++++++++++++------ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/frontend/src/views/BuildingPageStudent.vue b/frontend/src/views/BuildingPageStudent.vue index dc905308..365d4146 100644 --- a/frontend/src/views/BuildingPageStudent.vue +++ b/frontend/src/views/BuildingPageStudent.vue @@ -58,6 +58,7 @@ import PlanningService from "@/api/services/PlanningService"; import NormalButton from "@/components/NormalButton"; import ContainerService from "@/api/services/ContainerService"; import router from "@/router"; +import TrashTemplateService from "@/api/services/TrashTemplateService"; export default defineComponent({ name: "BuildingPageStudent", @@ -89,19 +90,18 @@ export default defineComponent({ style: "NONE" }).then(infos => { this.info = infos.find(i => i.building === this.building.id).id }).catch(() => null); - const containers = await RequestHandler.handle(ContainerService.get(this.building.id, this.year, this.week), { + const containers = await RequestHandler.handle(TrashTemplateService.getContainers(this.year, this.week), { id: "getContainersError", style: "NONE" - }).then(c => c).catch(() => null); + }).then(containers => { + if (this.building.id.toString() in containers) return containers[this.building.id.toString()]; + return []; + }).catch(() => null); if (!containers) return; - - const weekDays = ['SU','MO','TU','WE','TH','FR','SA']; - const day = weekDays[new Date(this.date).getDay()]; - this.containers = containers.filter(c => c.collection_day.day === day); + this.containers = containers.filter(c => c.collection_day.day === planning.time.day); } }, data: () => ({ - date: new Date().toISOString().split('T')[0], building: {location: {name: ''}, adres: '', id: ''}, trashMap: {PM: 'PMD', GL: 'GLAS', RE: 'REST', GF: 'GFT', PK: 'PK'}, containers: [], diff --git a/frontend/src/views/DayPlanView.vue b/frontend/src/views/DayPlanView.vue index bde60873..d3fc71e1 100644 --- a/frontend/src/views/DayPlanView.vue +++ b/frontend/src/views/DayPlanView.vue @@ -31,6 +31,7 @@ import PlanningService from "@/api/services/PlanningService"; import NormalButton from "@/components/NormalButton.vue"; import router from '@/router'; import {getWeek} from "@/api/DateUtil"; +import TrashTemplateService from "@/api/services/TrashTemplateService"; export default defineComponent({ name: "DayPlanView", @@ -44,23 +45,35 @@ export default defineComponent({ const date = new Date(this.date); this.year = date.getFullYear(); this.week = getWeek(date); + const day = this.daymap[date.getUTCDay()]; RequestHandler.handle(PlanningService.get(this.year, this.week, date.getUTCDay()), { id: "getDayplanningError", style: "NONE" }).then(plannings => { - plannings.forEach(planning => { - RequestHandler.handle(PlanningService.getStatus(this.year, this.week, planning.id), { - id: `getStatus${planning.id}Error`, - style: "NONE" - }).then(statuses => { - const buildings = Object(planning.ronde.buildings); - for (let building of buildings) - building.status = statuses[building.id].AR === 0 ? 'Niet begonnen' : statuses[building.id].DE > 0 ? 'Voltooid' : 'Bezig'; - planning.ronde.buildings = buildings; - this.rondes.push(planning); - }).catch(() => null); - }); + RequestHandler.handle(TrashTemplateService.getContainers(this.year, this.week), { + id: "getContainersError", + style: "NONE" + }).then(containers => { + plannings.forEach(planning => { + RequestHandler.handle(PlanningService.getStatus(this.year, this.week, planning.id), { + id: `getStatus${planning.id}Error`, + style: "NONE" + }).then(statuses => { + const buildings = Object(planning.ronde.buildings); + for (let building of buildings) + building.status = statuses[building.id].AR === 0 ? 'Niet begonnen' : statuses[building.id].DE > 0 ? 'Voltooid' : 'Bezig'; + planning.ronde.buildings = buildings.filter(building => { + if (building.id.toString() in containers) { + return containers[building.id.toString()].some(container => { + return container.collection_day.day === day; + }); + } + }); + this.rondes.push(planning); + }).catch(() => null); + }); + }).catch(() => null); }).catch(() => null); }, methods: { @@ -78,7 +91,16 @@ export default defineComponent({ rondes: [], year: null, week: null, - panel: [0] + panel: [0], + daymap: { + 1: 'MO', + 2: 'TU', + 3: 'WE', + 4: 'TH', + 5: 'FR', + 6: 'SA', + 0: 'SU' + } }) }); From dd4aeb2af403b592bef097e4671244b7d9abc6e4 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 20:05:50 +0200 Subject: [PATCH 248/340] fix linter and add trashtemplates to navbar --- frontend/src/components/NavigationBar.vue | 2 ++ frontend/src/views/DayPlanView.vue | 1 + 2 files changed, 3 insertions(+) diff --git a/frontend/src/components/NavigationBar.vue b/frontend/src/components/NavigationBar.vue index 18e61146..7500589f 100644 --- a/frontend/src/components/NavigationBar.vue +++ b/frontend/src/components/NavigationBar.vue @@ -9,6 +9,8 @@ value="dashboard"> + null); From 702a2e8a62b4d549e032953fd4adfab077ad364e Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 20:11:43 +0200 Subject: [PATCH 249/340] remove mail icon on post card for syndicus --- frontend/src/views/syndicus/SyndicusHome.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/views/syndicus/SyndicusHome.vue b/frontend/src/views/syndicus/SyndicusHome.vue index b81cccd0..cb00a1c8 100644 --- a/frontend/src/views/syndicus/SyndicusHome.vue +++ b/frontend/src/views/syndicus/SyndicusHome.vue @@ -254,6 +254,7 @@ export default { this.departs = [] this.storages = [] for(const picture of pictures){ + picture.admin = false; if(picture.pictureType === "AR"){ this.arrivals.push(picture) } else if(picture.pictureType === "DE"){ From dab8d25a954d44cc96307e632ae27145f6c46894 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 20:21:21 +0200 Subject: [PATCH 250/340] merge development --- frontend/src/views/syndicus/SyndicusHome.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/syndicus/SyndicusHome.vue b/frontend/src/views/syndicus/SyndicusHome.vue index cb00a1c8..10651f6a 100644 --- a/frontend/src/views/syndicus/SyndicusHome.vue +++ b/frontend/src/views/syndicus/SyndicusHome.vue @@ -254,7 +254,7 @@ export default { this.departs = [] this.storages = [] for(const picture of pictures){ - picture.admin = false; + picture.admin = false if(picture.pictureType === "AR"){ this.arrivals.push(picture) } else if(picture.pictureType === "DE"){ From 1eb48d8a2a4d2e74c41030afe1f906b8690ce4da Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 20:22:42 +0200 Subject: [PATCH 251/340] linter --- backend/trashtemplates/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index 114ee158..2c35e23d 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -8,8 +8,6 @@ from planning.models import WeekPlanning from .util import * -import datetime - class BuildingTrashPlan(generics.ListAPIView): permission_classes = [BewonerPermission | SyndicusPermission | StudentPermission] From 927939061089f2c7de56e7fc2202021a5f9c53ec Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Fri, 19 May 2023 20:25:21 +0200 Subject: [PATCH 252/340] only show rounds to student if there are buildings with trash containers --- frontend/src/views/DayPlanView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/DayPlanView.vue b/frontend/src/views/DayPlanView.vue index d35b59c5..4c01fb1f 100644 --- a/frontend/src/views/DayPlanView.vue +++ b/frontend/src/views/DayPlanView.vue @@ -71,7 +71,7 @@ export default defineComponent({ } return false; }); - this.rondes.push(planning); + if (planning.ronde.buildings.length > 0) this.rondes.push(planning); }).catch(() => null); }); }).catch(() => null); From 4500b6c58f70585b4ee9331a76ee7f51760216d0 Mon Sep 17 00:00:00 2001 From: novdamme Date: Fri, 19 May 2023 20:48:55 +0200 Subject: [PATCH 253/340] error handling bij afvaltemplates Signed-off-by: novdamme --- backend/exceptions/exceptionHandler.py | 8 +- backend/trashtemplates/util.py | 9 ++ backend/trashtemplates/views.py | 94 +++++-------------- .../TrashContainerTemplateCard.vue | 7 +- .../TrashContainerTemplateCreate.vue | 16 ++-- .../TrashContainerTemplateEdit.vue | 83 ---------------- .../buildings/TrashTemplateBuildingEdit.vue | 4 +- .../containers/TrashContainerCreate.vue | 23 +++-- .../containers/TrashContainerEdit.vue | 55 ++++++----- frontend/src/router/index.js | 7 -- 10 files changed, 89 insertions(+), 217 deletions(-) delete mode 100644 frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue diff --git a/backend/exceptions/exceptionHandler.py b/backend/exceptions/exceptionHandler.py index f9802b73..cd4c9ad9 100644 --- a/backend/exceptions/exceptionHandler.py +++ b/backend/exceptions/exceptionHandler.py @@ -84,8 +84,12 @@ def check_time_value(self, value, fieldname): self.checked = False if value is None: return True - return self.check_time_format(value, fieldname, "%H:%M", - ExceptionHandler.time_format_error) + if not self.check_time_format(value, fieldname, "%H:%M", ExceptionHandler.time_format_error): + if self.check_time_format(value, fieldname, "%H:%M:%S", ExceptionHandler.time_format_error): + self.errors.pop() + return True + return False + def check_time_value_required(self, value, fieldname): if not self.check_required(value, fieldname): diff --git a/backend/trashtemplates/util.py b/backend/trashtemplates/util.py index 1ef3d314..771c1343 100644 --- a/backend/trashtemplates/util.py +++ b/backend/trashtemplates/util.py @@ -5,6 +5,8 @@ from planning.util import get_current_time from exceptions.exceptionHandler import ExceptionHandler +from pickupdays.models import WeekDayEnum + def get_trash_template(template_id): handler = ExceptionHandler() @@ -21,6 +23,13 @@ def make_new_tc_id_wrapper(data, extra_id): Maakt nieuwe TrashContainerIdWrapper aan. TODO checks """ + handler = ExceptionHandler() + handler.check_time_value_required(data.get("collection_day").get("start_hour"), "start_hour") + handler.check_time_value_required(data.get("collection_day").get("end_hour"), "end_hour") + handler.check_enum_value_required(data.get("collection_day").get("day"), "day", WeekDayEnum) + handler.check_enum_value_required(data.get("type"), "type", TrashContainer.TrashType) + handler.check() + # maak nieuwe pickupday met de aangepaste data new_pickup_day, _ = PickUpDay.objects.get_or_create( day=data["collection_day"]["day"], diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index de4e8f51..762a71ae 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -5,6 +5,13 @@ from planning.util import filter_templates, get_current_week_planning, get_current_time from users.permissions import * from .util import * +from exceptions.exceptionHandler import ExceptionHandler + +from ronde.models import LocatieEnum + +from trashcontainers.models import TrashContainer + +from pickupdays.models import WeekDayEnum class TrashTemplatesView(generics.RetrieveAPIView, generics.CreateAPIView): @@ -22,9 +29,14 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): """ Maakt een nieuwe TrashContainerTemplate aan. - TODO checks """ data = request.data + handler = ExceptionHandler() + handler.check_not_blank_required(data.get("name"), "name") + handler.check_boolean_required(data.get("even"), "even") + handler.check_primary_key_value_required(data.get("location"), "location", LocatieEnum) + handler.check() + current_year, current_week = get_current_time() location = LocatieEnum.objects.get(id=data["location"]) @@ -43,71 +55,13 @@ def post(self, request, *args, **kwargs): return Response({"id": new_template.id}) -class TrashTemplateView(generics.RetrieveUpdateDestroyAPIView): +class TrashTemplateView(generics.RetrieveDestroyAPIView): permission_classes = [SuperstudentPermission | AdminPermission] def get(self, request, *args, **kwargs): template = TrashContainerTemplate.objects.get(id=kwargs["template_id"]) return Response(TrashContainerTemplateSerializerFull(template).data) - def patch(self, request, *args, **kwargs): - """ - Past de TrashContainerTemplate aan. - Neemt een copy van de template om de geschiedenis te behouden als dit nodig is. - """ - template = TrashContainerTemplate.objects.get(id=kwargs["template_id"]) - current_year, current_week = get_current_time() - planning = get_current_week_planning() - - data = request.data - permanent = data["permanent"] - - if "name" in data: - pass - # checks - else: - data["name"] = template.name - - if "even" in data: - pass - # checks - else: - data["even"] = template.even - - if "location" in data: - data["location"] = LocatieEnum.objects.get(id=data["location"]) - # checks - else: - data["location"] = template.location - - if no_copy(template, permanent, current_year, current_week): - template.name = data["name"] - template.even = data["even"] - template.location = data["location"] - template.save() - add_if_match(planning.trash_templates, template, current_week) - return Response({"message": "Success"}) - - new_template = TrashContainerTemplate.objects.create( - name=data["name"], - even=data["even"], - status=Status.ACTIEF, - location=data["location"], - year=current_year, - week=current_week - ) - add_if_match(planning.trash_templates, new_template, current_week) - - # oude template op inactief zetten - template.status = Status.INACTIEF - template.save() - remove_if_match(planning.trash_templates, template) - - return Response({"message": "Success"}) - - def put(self, request, *args, **kwargs): - raise ValidationError("no PUT allowed") - def delete(self, request, *args, **kwargs): """ Verwijderd de TrashContainerTemplate. @@ -203,22 +157,22 @@ def patch(self, request, *args, **kwargs): permanent = kwargs["permanent"] data = request.data + if "collection_day" not in data: + data["collection_day"] = {} + if "day" not in data: - data["day"] = tc_id_wrapper.trash_container.collection_day.day + data["collection_day"]["day"] = tc_id_wrapper.trash_container.collection_day.day - if "start_hour" not in data: - data[ - "start_hour"] = tc_id_wrapper.trash_container.collection_day.start_hour + if "start_hour" not in data.get("collection_day"): + data["collection_day"]["start_hour"] = tc_id_wrapper.trash_container.collection_day.start_hour - if "end_hour" not in data: - data[ - "end_hour"] = tc_id_wrapper.trash_container.collection_day.end_hour + if "end_hour" not in data.get("collection_day"): + data["collection_day"]["end_hour"] = tc_id_wrapper.trash_container.collection_day.end_hour - if "type" not in data: + if "type" not in data.get("collection_day"): data["type"] = tc_id_wrapper.trash_container.type - new_tc_id_wrapper = make_new_tc_id_wrapper(data, - tc_id_wrapper.extra_id) + new_tc_id_wrapper = make_new_tc_id_wrapper(data, tc_id_wrapper.extra_id) update( template, diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue index 9d438959..c1193967 100644 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue +++ b/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue @@ -19,12 +19,7 @@ {{ this.data.even }} - - - - - - + diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateCreate.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateCreate.vue index 26c21e17..647722b4 100644 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateCreate.vue +++ b/frontend/src/components/containerTemplates/TrashContainerTemplateCreate.vue @@ -6,16 +6,17 @@ - + - + result).catch(() => []); }, methods: { + check_errors, async create() { const body = { name: this.name, even: this.even, location: this.location } - const response = await RequestHandler.handle(TrashTemplateService.newTrashTemplate(body), { - id: 'CreateNewTrashTemplateError', - style: 'SNACKBAR' - }) - return await router.push({name: 'trashtemplates'}) + TrashTemplateService.newTrashTemplate(body) + .then(async () => {await router.push({name: 'trashtemplates'})}) + .catch(async (error) => {this.errors = await get_errors(error)}) } } } diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue deleted file mode 100644 index 05dd03b2..00000000 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateEdit.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - diff --git a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue index 18a8e138..8644aabd 100644 --- a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue +++ b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingEdit.vue @@ -88,8 +88,8 @@ export default { "PM": "PMD", "GL": "GLAS", "GF": "GFT", - "RE": "Rest", - "PK": "Papier & Karton" + "RE": "REST", + "PK": "PK" } if(!Number.isInteger(container)) { return `${format_type[container.trash_container.type]} ${format_day[container.trash_container.collection_day.day]}` diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue index 42aa50be..0720bf2d 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue @@ -10,20 +10,22 @@ v-model="type" :items="types.map(type => ContainerType[type])" label="type container" + :error-messages="check_errors(this.errors, 'type')" > - + - + @@ -42,6 +44,7 @@ import TrashTemplateService from "@/api/services/TrashTemplateService"; import {container_to_api, ContainerType} from "@/api/models/ContainerType"; import {Weekday, weekday_to_api} from "@/api/models/Weekday"; import router from "@/router"; +import {check_errors, get_errors} from "@/error_handling"; export default { name: 'CreateTrashContainerView', @@ -64,6 +67,7 @@ export default { end_hour: '', smallScreen: false, status: "I", + errors: null, types: [ ContainerType.GFT, ContainerType.PMD, @@ -94,28 +98,23 @@ export default { }) }, methods: { + check_errors, createContainer() { - - RequestHandler.handle( TrashTemplateService.newContainerToTemplate(this.id, { type: container_to_api(this.type), collection_day: { day: weekday_to_api(this.day), start_hour: this.start_hour, end_hour: this.end_hour - }, - }), { - id: 'createContainerTemplateError', - style: 'SNACKBAR' - } - ).then(() => { + } + }).then(() => { this.$store.dispatch("snackbar/open", { message: "De container is aangemaakt", color: "success" }) router.push({name: 'trashtemplateContainers', params: {id: this.id}}) - } - ) + }).catch(async (error) => this.errors = await get_errors(error)) + }, } } diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue index 9b1193f8..e2503425 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue @@ -7,6 +7,7 @@ - + - + @@ -38,6 +40,7 @@ import {container_from_api, container_to_api, ContainerType} from "@/api/models/ import {Weekday, weekday_from_api, weekday_to_api} from "@/api/models/Weekday"; import router from '@/router'; import StateButtons from "@/components/StateButtons.vue"; +import {check_errors, get_errors} from "@/error_handling"; export default { name: 'CreateTrashContainerView', @@ -63,6 +66,7 @@ export default { end_hour: '', status: "I", smallScreen: false, + errors: null, types: [ ContainerType.GFT, ContainerType.PMD, @@ -106,9 +110,9 @@ export default { }) }, methods: { + check_errors, async editContainer(eenmalig) { if(eenmalig) { - await RequestHandler.handle( TrashTemplateService.updateContainerTemplateEenmalig(this.id_, this.$route.params.containerId, { type: container_to_api(this.type), collection_day: { @@ -116,35 +120,30 @@ export default { start_hour: this.start_hour, end_hour: this.end_hour }, - }), { - id: 'editContainerTemplateEenmaligError', - style: 'SNACKBAR' } - ).then(() => + ).then(() =>{ this.$store.dispatch("snackbar/open", { - message: "De container is eenmalig aangepast", + message: "De container is aangepast", color: "success" - })) - await router.replace({name: 'trashtemplates'}) + }) + router.replace({name: 'trashtemplates'}) + }).catch(async (error) => this.errors = await get_errors(error)) } else { - RequestHandler.handle( - TrashTemplateService.updateContainerTemplate(this.id_, this.$route.params.containerId, { - type: container_to_api(this.type), - collection_day: { - day: weekday_to_api(this.day), - start_hour: this.start_hour, - end_hour: this.end_hour - }, - }), { - id: 'editContainerTemplateError', - style: 'SNACKBAR' - } - ).then(() => - this.$store.dispatch("snackbar/open", { - message: "De container is aangepast", - color: "success" - })) - await router.replace({name: 'trashtemplateContainers', params: {id: this.id_}}) + TrashTemplateService.updateContainerTemplate(this.id_, this.$route.params.containerId, { + type: container_to_api(this.type), + collection_day: { + day: weekday_to_api(this.day), + start_hour: this.start_hour, + end_hour: this.end_hour + }, + } + ).then( () =>{ + this.$store.dispatch("snackbar/open", { + message: "De container is aangepast", + color: "success" + }) + router.replace({name: 'trashtemplateContainers', params: {id: this.id_}}) + }).catch(async (error) => this.errors = await get_errors(error)) } }, } diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index ee90503d..e3643155 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -44,7 +44,6 @@ import TrashTemplateContainersList from '@/components/containerTemplates/contain import TrashContainerTemplateList from '@/components/containerTemplates/TrashContainerTemplateList.vue' import TrashContainerCreate from '@/components/containerTemplates/containers/TrashContainerCreate.vue' import TrashContainerTemplateCreate from '@/components/containerTemplates/TrashContainerTemplateCreate.vue' -import TrashContainerTemplateEdit from '@/components/containerTemplates/TrashContainerTemplateEdit.vue' import TrashContainerEdit from '@/components/containerTemplates/containers/TrashContainerEdit.vue' import LocationList from "@/views/listViews/LocationList"; import CreateEditRoundView from "@/views/admin/CreateEditRoundView.vue"; @@ -277,12 +276,6 @@ const routes = [ name: 'trashtemplates', component: TrashContainerTemplateList }, - { - path: '/admin/afvaltemplate/:id/aanpassen', - name: 'editTrashtemplates', - component: TrashContainerTemplateEdit, - props: true - }, { path: '/admin/afvaltemplate/aanmaken', name: 'createTrashtemplates', From a2cfd405993124e8d9ac66c4db4f75882702123f Mon Sep 17 00:00:00 2001 From: novdamme Date: Fri, 19 May 2023 20:54:31 +0200 Subject: [PATCH 254/340] fix actions Signed-off-by: novdamme --- backend/exceptions/exceptionHandler.py | 5 +++-- .../containerTemplates/TrashContainerTemplateCard.vue | 2 +- .../containerTemplates/containers/TrashContainerCreate.vue | 2 +- .../containerTemplates/containers/TrashContainerEdit.vue | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/exceptions/exceptionHandler.py b/backend/exceptions/exceptionHandler.py index cd4c9ad9..658ca1d5 100644 --- a/backend/exceptions/exceptionHandler.py +++ b/backend/exceptions/exceptionHandler.py @@ -88,8 +88,9 @@ def check_time_value(self, value, fieldname): if self.check_time_format(value, fieldname, "%H:%M:%S", ExceptionHandler.time_format_error): self.errors.pop() return True - return False - + else: + return False + return True def check_time_value_required(self, value, fieldname): if not self.check_required(value, fieldname): diff --git a/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue b/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue index c1193967..e3625263 100644 --- a/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue +++ b/frontend/src/components/containerTemplates/TrashContainerTemplateCard.vue @@ -39,7 +39,7 @@ import TrashTemplateService from "@/api/services/TrashTemplateService"; export default { name: 'TrashContainerTemplateCard', - components: {EditIcon, DeleteIcon}, + components: {DeleteIcon}, props: { data: { type: TrashTemplate, diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue index 0720bf2d..c7986d31 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerCreate.vue @@ -113,7 +113,7 @@ export default { color: "success" }) router.push({name: 'trashtemplateContainers', params: {id: this.id}}) - }).catch(async (error) => this.errors = await get_errors(error)) + }).catch(async (error) => {this.errors = await get_errors(error)}) }, } diff --git a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue index e2503425..963e117b 100644 --- a/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue +++ b/frontend/src/components/containerTemplates/containers/TrashContainerEdit.vue @@ -127,7 +127,7 @@ export default { color: "success" }) router.replace({name: 'trashtemplates'}) - }).catch(async (error) => this.errors = await get_errors(error)) + }).catch(async (error) => {this.errors = await get_errors(error)}) } else { TrashTemplateService.updateContainerTemplate(this.id_, this.$route.params.containerId, { type: container_to_api(this.type), @@ -143,7 +143,7 @@ export default { color: "success" }) router.replace({name: 'trashtemplateContainers', params: {id: this.id_}}) - }).catch(async (error) => this.errors = await get_errors(error)) + }).catch(async (error) => {this.errors = await get_errors(error)}) } }, } From ec9db9efdaa8624cc8172b523c4a5fae0bc3e9ec Mon Sep 17 00:00:00 2001 From: novdamme Date: Fri, 19 May 2023 20:55:15 +0200 Subject: [PATCH 255/340] fix actions Signed-off-by: novdamme --- backend/trashtemplates/views.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index 762a71ae..c6abd65b 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -9,10 +9,6 @@ from ronde.models import LocatieEnum -from trashcontainers.models import TrashContainer - -from pickupdays.models import WeekDayEnum - class TrashTemplatesView(generics.RetrieveAPIView, generics.CreateAPIView): permission_classes = [SuperstudentPermission | AdminPermission] From 5d8af31e2a43628a357ebd1c449e95cb3770cb7c Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Fri, 19 May 2023 21:43:57 +0200 Subject: [PATCH 256/340] add send mail to all syndici --- backend/planning/views.py | 7 ++- frontend/src/api/services/PlanningService.ts | 7 +++ .../components/admin/AdminBuildingInfo.vue | 15 +++--- .../src/components/admin/FotoCardAdmin.vue | 43 ++++++++++++++-- .../src/components/admin/mail/SendMail.vue | 50 ++++++++++++------- .../student/CreateEditPostStudent.vue | 4 +- .../components/syndicus/FotoCardSyndicus.vue | 17 +++++-- frontend/src/config.ts | 4 +- frontend/src/router/index.js | 9 +++- frontend/src/views/DayPlanView.vue | 2 + frontend/src/views/admin/SendMailView.vue | 16 ++++++ 11 files changed, 133 insertions(+), 41 deletions(-) create mode 100644 frontend/src/views/admin/SendMailView.vue diff --git a/backend/planning/views.py b/backend/planning/views.py index f5de4ae4..8a5c28ce 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -43,9 +43,14 @@ def get(self, request, *args, **kwargs): if plan.time.day == day_name and request.user in plan.students.all(): dayplans.append(plan) - if dayplan is None: + if len(dayplans) == 0: return HttpResponseNotFound() + data = [] + for dayplan in dayplans: + data.append(DagPlanningSerializerFull(dayplan).data) + return Response(data) + @api_view(["GET"]) @permission_classes( diff --git a/frontend/src/api/services/PlanningService.ts b/frontend/src/api/services/PlanningService.ts index d50a829b..44792069 100644 --- a/frontend/src/api/services/PlanningService.ts +++ b/frontend/src/api/services/PlanningService.ts @@ -88,6 +88,13 @@ class PlanningService extends EchoService { return {} as EchoPromise; } + /** + * Get building info by id + */ + @GET("/infoperbuilding/{id}/") + getInfoById(@Path('id') id: number): EchoPromise { + return {} as EchoPromise + } /** *Get building info for a day planning and building diff --git a/frontend/src/components/admin/AdminBuildingInfo.vue b/frontend/src/components/admin/AdminBuildingInfo.vue index 9334820a..095fa90b 100644 --- a/frontend/src/components/admin/AdminBuildingInfo.vue +++ b/frontend/src/components/admin/AdminBuildingInfo.vue @@ -107,7 +107,7 @@
  • - +
@@ -156,14 +156,15 @@ export default { new_manual: null, selectedLocation: null, locations: [], - errors: null + errors: null, + // syndici: 0 } }, - beforeMount() { - this.getBuildingInformation(this.$route.params.id).then(() => this.getStudentPosts()) - this.getTrashPickUps() - RequestHandler.handle(BuildingService.getBuildings(), {id: 'getBuildingsError', style: 'SNACKBAR'}) + async beforeMount() { + await this.getBuildingInformation(this.$route.params.id).then(() => this.getStudentPosts()) + await this.getTrashPickUps() + await RequestHandler.handle(BuildingService.getBuildings(), {id: 'getBuildingsError', style: 'SNACKBAR'}) .then(async result => { this.buildings = result }) @@ -184,6 +185,7 @@ export default { this.location = result.location this.ivago_klantnr = result.ivago_klantnr this.selectedLocation = result.location + // this.syndici = result.syndicus.length() if (result.manual != null) { this.manual = result.manual; @@ -194,6 +196,7 @@ export default { color: "error" }) } + console.log(this.id) }).catch(async () => { await router.push({name: 'buildings'}) }) diff --git a/frontend/src/components/admin/FotoCardAdmin.vue b/frontend/src/components/admin/FotoCardAdmin.vue index f52dd87f..7c91f926 100644 --- a/frontend/src/components/admin/FotoCardAdmin.vue +++ b/frontend/src/components/admin/FotoCardAdmin.vue @@ -27,26 +27,59 @@ - diff --git a/frontend/src/config.ts b/frontend/src/config.ts index d73bc714..a9986575 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -24,7 +24,7 @@ export default { 'create_mail-template', 'buildings', 'rounds', 'students', 'syndici', 'mailtemplates', 'trashtemplates', 'editTrashtemplates', 'createTrashtemplates', 'trashtemplateContainers', 'createTrashtemplateContainers', 'editTrashtemplateContainers', 'trashtemplateBuildings', 'editTrashtemplateBuildings', 'mail-template-edit', 'edit_round', - 'admin_info_user', 'admin_edit_user', 'admin_user_register' + 'admin_info_user', 'admin_edit_user', 'admin_user_register', 'send_mail' ], AD: [ 'admin_home', 'account', 'unauthorized', 'home', 'create_building', 'create_location', 'create_round', @@ -33,7 +33,7 @@ export default { 'createTrashtemplates', 'trashtemplateContainers', 'createTrashtemplateContainers', 'editTrashtemplateContainers', 'trashtemplateBuildings', 'editTrashtemplateBuildings', 'mail-template-edit', 'admin_info_building', 'admin_edit_building', 'admin_info_user', 'admin_edit_user', 'admin_user_register', 'syndicus_create', 'syndicus_adjust', 'locations', - 'edit_round', 'adminRoundView' + 'edit_round', 'adminRoundView', 'send_mail' ] } }; diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index fdcf4480..b782c1ea 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -47,8 +47,7 @@ import TrashContainerEdit from '@/components/containerTemplates/containers/Trash import LocationList from "@/views/listViews/LocationList"; import CreateEditRoundView from "@/views/admin/CreateEditRoundView.vue"; import AdminRoundView from "@/views/admin/AdminRoundView.vue"; -import BuildingFollowUp from "@/components/admin/AdminBuildingInfo.vue"; -import AdminBuildingInfo from "@/components/admin/AdminBuildingInfoEdit.vue"; +import SendMailView from "@/views/admin/SendMailView.vue"; const routes = [ { @@ -260,6 +259,12 @@ const routes = [ name: 'mailtemplates', component: TemplateList }, + { + path: '/admin/send_mail/:id/post/:postId', + name: 'send_mail', + props: true, + component: SendMailView + }, { path: '/admin/gebruiker/:id', name: 'admin_info_user', diff --git a/frontend/src/views/DayPlanView.vue b/frontend/src/views/DayPlanView.vue index bde60873..ea3769aa 100644 --- a/frontend/src/views/DayPlanView.vue +++ b/frontend/src/views/DayPlanView.vue @@ -49,11 +49,13 @@ export default defineComponent({ id: "getDayplanningError", style: "NONE" }).then(plannings => { + console.log(plannings) plannings.forEach(planning => { RequestHandler.handle(PlanningService.getStatus(this.year, this.week, planning.id), { id: `getStatus${planning.id}Error`, style: "NONE" }).then(statuses => { + console.log(statuses) const buildings = Object(planning.ronde.buildings); for (let building of buildings) building.status = statuses[building.id].AR === 0 ? 'Niet begonnen' : statuses[building.id].DE > 0 ? 'Voltooid' : 'Bezig'; diff --git a/frontend/src/views/admin/SendMailView.vue b/frontend/src/views/admin/SendMailView.vue new file mode 100644 index 00000000..3f4f1405 --- /dev/null +++ b/frontend/src/views/admin/SendMailView.vue @@ -0,0 +1,16 @@ + + + + + From 152edd71cd6d86aa8d7f3ddc2a5abfa601dfea88 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Fri, 19 May 2023 21:48:49 +0200 Subject: [PATCH 257/340] fix linter: spaces before == --- backend/planning/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/planning/views.py b/backend/planning/views.py index ed70df0a..1194d865 100644 --- a/backend/planning/views.py +++ b/backend/planning/views.py @@ -43,7 +43,7 @@ def get(self, request, *args, **kwargs): if plan.time.day == day_name and request.user in plan.students.all(): dayplans.append(plan) - if len(dayplans) == 0: + if len(dayplans) == 0: return HttpResponseNotFound() data = [] From e058397d062084601bb6d3333abea7217a32a33c Mon Sep 17 00:00:00 2001 From: jbvilla Date: Fri, 19 May 2023 23:37:15 +0200 Subject: [PATCH 258/340] testen TrashTemplateBuilding toegevoegd --- .../buildings/TrashTemplateBuildingsList.vue | 2 +- .../trashTemplateBuildingAddTests.spec.js | 179 ++++++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 frontend/tests/unit/Components/containerTemplates/trashTemplateBuildingAddTests.spec.js diff --git a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingsList.vue b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingsList.vue index 1aee017f..c93e05aa 100644 --- a/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingsList.vue +++ b/frontend/src/components/containerTemplates/buildings/TrashTemplateBuildingsList.vue @@ -1,5 +1,5 @@
- - + + diff --git a/frontend/tests/unit/Components/admin/createEditSyndicusTest.spec.js b/frontend/tests/unit/Components/admin/createEditSyndicusTest.spec.js new file mode 100644 index 00000000..4ba37371 --- /dev/null +++ b/frontend/tests/unit/Components/admin/createEditSyndicusTest.spec.js @@ -0,0 +1,54 @@ +import {mount} from '@vue/test-utils' +import CreateEditSyndicus from "@/components/admin/CreateEditSyndicus.vue"; + +describe('CreateEditSyndicus.vue', () => { + let wrapper; + + beforeEach(() => { + CreateEditSyndicus.mounted = jest.fn() + wrapper = mount(CreateEditSyndicus) + }) + + + it('renders props.msg when passed', () => { + expect(wrapper.exists()).toBe(true); + expect(CreateEditSyndicus.mounted).toHaveBeenCalled(); + }) + + it('show right title', async () => { + expect(wrapper.find('h1').text()).toBe('Maak nieuwe Syndicus aan'); + await wrapper.setProps({edit: true}); + await wrapper.vm.$forceUpdate(); + expect(wrapper.find('h1').text()).toBe('Syndicus aanpassen'); + }) + + it('call addSyndicus when submit', async () => { + CreateEditSyndicus.methods.addSyndicus = jest.fn(); + wrapper = mount(CreateEditSyndicus); + const button = await wrapper.find('[data-test="add"]') + await button.trigger('click'); + expect(CreateEditSyndicus.methods.addSyndicus).toHaveBeenCalled(); + }) + + it('call editSyndicus when submit', async () => { + CreateEditSyndicus.methods.editSyndicus = jest.fn(); + wrapper = mount(CreateEditSyndicus, { + propsData: { + edit: true + } + }); + const button = await wrapper.find('[data-test="edit"]') + await button.trigger('click'); + expect(CreateEditSyndicus.methods.editSyndicus).toHaveBeenCalled(); + }) + + it('render component correctly', () => { + const labels = wrapper.findAll('label'); + expect(labels.length).toBe(3); + expect(labels.at(0).text()).toBe('Syndicus'); + expect(labels.at(1).text()).toBe('Locatie'); + expect(labels.at(2).text()).toBe('Gebouwen'); + + expect(wrapper.findAll('v-autocomplete').length).toBe(3); + }) +}) From 152f91d7d88c96bff77c4f60d91f75702149d34d Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Sat, 20 May 2023 12:05:22 +0200 Subject: [PATCH 266/340] Fixed permission bug for AccountInformation.vue --- backend/users/tests.py | 10 +-- backend/users/views.py | 34 +++++--- frontend/src/api/services/AuthService.ts | 3 +- frontend/src/api/services/UserService.ts | 9 +- .../src/components/AccountInformation.vue | 82 ++++++++++++------- 5 files changed, 87 insertions(+), 51 deletions(-) diff --git a/backend/users/tests.py b/backend/users/tests.py index 9863c1a7..ae5edc34 100644 --- a/backend/users/tests.py +++ b/backend/users/tests.py @@ -113,31 +113,31 @@ def testUserRoleAssignment(self): registration_view(request) # Test permission for role assignment - request = factory.post("/api/role/", {"role": "AD", "email": ""}) + request = factory.patch("/api/role/", {"role": "AD", "email": ""}) force_authenticate(request, user=self.user) response = role_assignment_view(request).data self.assertEqual(response["detail"].code, "permission_denied") # Test if error is returned when email is empty - request = factory.post("/api/role/", {"role": "AD", "email": ""}) + request = factory.patch("/api/role/", {"role": "AD", "email": ""}) force_authenticate(request, user=self.su) response = role_assignment_view(request).data self.assertEqual(response["email"][0], "This field may not be blank.") # Make sure a superstudent can't promote a user to admin - request = factory.post("/api/role/", {"role": "AD", "email": "test@test.com"}) + request = factory.patch("/api/role/", {"role": "AD", "email": "test@test.com"}) force_authenticate(request, user=self.su) response = role_assignment_view(request).data self.assertIn("errors", response) # Make sure a non-existent user cannot be promoted - request = factory.post("/api/role/", {"role": "ST", "email": "test2@test.com"}) + request = factory.patch("/api/role/", {"role": "ST", "email": "test2@test.com"}) force_authenticate(request, user=self.su) response = role_assignment_view(request).data self.assertIn("errors", response) # Make sure a non-existent user cannot be promoted - request = factory.post("/api/role/", {"role": "ST", "email": "test@test.com"}) + request = factory.patch("/api/role/", {"role": "ST", "email": "test@test.com"}) force_authenticate(request, user=self.su) response = role_assignment_view(request).data self.assertEqual(response["message"], "test@test.com is nu een Student") diff --git a/backend/users/views.py b/backend/users/views.py index a760b0f0..3c747165 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -10,7 +10,8 @@ from rest_framework_simplejwt.tokens import RefreshToken from .models import User from exceptions.exceptionHandler import ExceptionHandler -from .permissions import AdminPermission, SuperstudentPermission, ReadOnly +from .permissions import AdminPermission, SuperstudentPermission, ReadOnly, StudentPermission, \ + SyndicusPermission from .serializers import RoleAssignmentSerializer, \ UserPublicSerializer, UserSerializer @@ -29,16 +30,27 @@ def get_tokens_for_user(user): } -@api_view(['GET']) -@permission_classes([ReadOnly]) +@api_view(['GET', 'PATCH']) +@permission_classes([SyndicusPermission | StudentPermission | SuperstudentPermission | AdminPermission]) def user_view(request): response = Response() - if request.user.is_authenticated: - response.data = UserSerializer(request.user).data - return response - else: - response.data = "{'error': 'no user'}" - return response + if request.method == 'GET': + if request.user.is_authenticated: + response.data = UserSerializer(request.user).data + else: + response.data = "{'error': 'no user'}" + elif request.method == 'PATCH': + if request.user.is_authenticated: + data = request.data + serializer = UserSerializer(request.user, data=data, partial=True) + if serializer.is_valid(): + serializer.save() + response.data = serializer.data + else: + response.data = serializer.errors + else: + response.data = "{'error': 'no user'}" + return response @api_view(['POST']) @@ -212,13 +224,13 @@ def reset_password(request): return Response({'message': 'New password is created'}) -@api_view(['POST', 'GET']) +@api_view(['PATCH', 'GET']) @permission_classes([AdminPermission | SuperstudentPermission | ReadOnly]) def role_assignment_view(request): if request.method == "GET": # return role of user return Response({'role': request.user.role}) - if request.method == "POST": # change the role of a user + if request.method == "PATCH": # change the role of a user serializer = RoleAssignmentSerializer(data=request.data) if serializer.is_valid(raise_exception=True): diff --git a/frontend/src/api/services/AuthService.ts b/frontend/src/api/services/AuthService.ts index 65dd8c2a..be9ce928 100644 --- a/frontend/src/api/services/AuthService.ts +++ b/frontend/src/api/services/AuthService.ts @@ -3,6 +3,7 @@ import { EchoPromise, EchoService, EchoServiceBuilder, + PATCH, POST, } from 'echofetch'; import { ErrorHandler } from "@/api/error/ErrorHandler"; @@ -95,7 +96,7 @@ class AuthService extends EchoService { /** * Change the role of a user */ - @POST('/role/') + @PATCH('/role/') updateRoleOfUser(@Body() body : {}) : EchoPromise { return {} as EchoPromise } diff --git a/frontend/src/api/services/UserService.ts b/frontend/src/api/services/UserService.ts index d505c627..80d7ac66 100644 --- a/frontend/src/api/services/UserService.ts +++ b/frontend/src/api/services/UserService.ts @@ -24,11 +24,11 @@ class UserService extends EchoService { } /** - * Patch user by id + * Patch data of logged-in user */ - @PATCH("/user/{id}/") - updateUserById(@Path('id') id: number, @Body() body: {}): EchoPromise { - return {} as EchoPromise + @PATCH("/user/") + patchLoggedInUser(@Body() body : {}) : EchoPromise { + return {} as EchoPromise } /** @@ -41,7 +41,6 @@ class UserService extends EchoService { /** - * Get the logged in user. * Get all users. */ @GET("/users/") diff --git a/frontend/src/components/AccountInformation.vue b/frontend/src/components/AccountInformation.vue index 13538c52..e3cc5e3c 100644 --- a/frontend/src/components/AccountInformation.vue +++ b/frontend/src/components/AccountInformation.vue @@ -10,7 +10,9 @@
- - - @@ -38,7 +44,9 @@ - @@ -46,21 +54,12 @@

Rol

- -
@@ -85,6 +84,8 @@ import NormalButton from '@/components/NormalButton' import ConfirmDialog from '@/components/util/ConfirmDialog' import UserService from "@/api/services/UserService"; import {check_errors, get_errors} from "@/error_handling"; +import AuthService from "@/api/services/AuthService"; +import {RequestHandler} from "@/api/RequestHandler"; export default { name: 'AccountInformation', @@ -102,9 +103,9 @@ export default { role: '', rondes: [], roles: [ - {name: 'Aanvrager', value: 'AA'}, {name: 'Student', value: 'ST'}, - {name: 'Superstudent', value: 'SU'}, {name: 'Admin', value: 'AD'}, - {name: 'Syndicus', value: 'SY'} + {name: 'Aanvrager', value: 'AA'}, {name: 'Student', value: 'ST'}, + {name: 'Superstudent', value: 'SU'}, {name: 'Admin', value: 'AD'}, + {name: 'Syndicus', value: 'SY'} ], edit: false, smallScreen: false, @@ -116,10 +117,14 @@ export default { const currentUser = await this.$store.getters['session/currentUser'] this.user = currentUser - if(id !== undefined) { + if (id !== undefined) { await UserService.getUserById(id) - .then(async data => {this.user = data}) - .catch(async (error) => {this.errors = await get_errors(error)}); + .then(async data => { + this.user = data + }) + .catch(async (error) => { + this.errors = await get_errors(error) + }); } this.first_name = this.user.first_name @@ -163,16 +168,35 @@ export default { this.role = this.user.role }, async save() { - UserService.updateUserById(this.user.id, { - first_name: this.first_name, - last_name: this.last_name, - email: this.email, - role: this.role, - phone_nr: this.phone_nr - }).then(() => { + let id = this.$route.params.id + + let handle + if (id !== undefined) { + handle = RequestHandler.handle(AuthService.updateRoleOfUser({ + role: this.role, + email: this.email + }), { + id: 'updateRoleOfUserAccountInformation', + style: 'SNACKBAR', + }).then() + } else { + handle = RequestHandler.handle(UserService.patchLoggedInUser({ + first_name: this.first_name, + last_name: this.last_name, + email: this.email, + role: this.role, + phone_nr: this.phone_nr + }), { + id: 'patchLoggedInUserAccountInformation', + style: 'SNACKBAR' + }) + } + handle.then(() => { this.edit = !this.edit this.errors = null - }).catch(async (error) => {this.errors = await get_errors(error)}); + }).catch(async (error) => { + this.errors = await get_errors(error) + }) }, delete_current() { UserService.deleteUserById(this.id) From acc49a4bd3da66dcd6d05122d630f59d0ca61adf Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Sat, 20 May 2023 12:07:21 +0200 Subject: [PATCH 267/340] trashtemplates --- backend/trashtemplates/urls.py | 4 +- backend/trashtemplates/views.py | 57 ++++++++++++++++++- frontend/package-lock.json | 14 +++++ .../src/api/services/TrashTemplateService.ts | 5 ++ .../components/admin/AdminBuildingInfo.vue | 43 +++++++++++++- 5 files changed, 119 insertions(+), 4 deletions(-) diff --git a/backend/trashtemplates/urls.py b/backend/trashtemplates/urls.py index 3bbf9689..8966eedf 100644 --- a/backend/trashtemplates/urls.py +++ b/backend/trashtemplates/urls.py @@ -23,5 +23,7 @@ {'permanent': True}), path('/buildings//eenmalig/', views.BuildingView.as_view(), - {'permanent': False}) + {'permanent': False}), + path("//", + views.BuildingTrashPlan.as_view()), ] diff --git a/backend/trashtemplates/views.py b/backend/trashtemplates/views.py index e3cfa819..3b4face5 100644 --- a/backend/trashtemplates/views.py +++ b/backend/trashtemplates/views.py @@ -1,12 +1,67 @@ from rest_framework import generics from rest_framework.response import Response from rest_framework.serializers import ValidationError - from planning.util import filter_templates, get_current_week_planning, get_current_time +from trashcontainers.serializers import TrashContainerSerializer from users.permissions import * +from ronde.models import LocatieEnum, Building +from planning.models import WeekPlanning from .util import * +class BuildingTrashPlan(generics.ListAPIView): + permission_classes = [BewonerPermission | SyndicusPermission | StudentPermission | SuperstudentPermission | AdminPermission] + + def get(self, request, *args, **kwargs): + """ + Geeft de vuilnisplanning voor een bepaalde week + """ + year = kwargs.get("year") + week = kwargs.get("week") + templates = get_trash_templates(year, week) + active_exists = 'A' in [t.status for t in templates] + result = {} + for template in templates: + if (active_exists and template.status == 'A') or not active_exists: + buildings = template.buildings.all() + for building in buildings: + containers = TrashContainerIdWrapper.objects.filter(extra_id__in=building.trash_ids.all()) + result[building.building.id] = TrashContainerSerializer([c.trash_container for c in containers], many=True).data + break + return Response(result) + + +def get_trash_templates(year, week): + current_year, current_week = get_current_time() + + if year > current_year or (current_year == year and week > current_week): + # dit is een week die nog moet komen dus geven we alleen de actieve of nu tijdelijk vervangen templates terug + # buiten als de template vervangen is voor de volgende week + trash_templates_actief = TrashContainerTemplate.objects.filter( + status=Status.ACTIEF) + trash_templates_vervangen = TrashContainerTemplate.objects.filter( + status=Status.VERVANGEN).exclude(week=week, year=year) + trash_templates_eenmalig = TrashContainerTemplate.objects.filter( + status=Status.EENMALIG, week=week, year=year) + + even = week % 2 == 0 + trash_templates = trash_templates_actief | trash_templates_vervangen | trash_templates_eenmalig + trash_templates = trash_templates.filter(even=even) + else: + # weekplanning is al voorbij of bezig + get_current_week_planning() # nodig voor moest de weekplanning nog niet gemaakt zijn + try: + week_planning = WeekPlanning.objects.get( + week=week, + year=year + ) + trash_templates = week_planning.trash_templates.all() + except WeekPlanning.DoesNotExist: + trash_templates = [] + + return trash_templates + + class TrashTemplatesView(generics.RetrieveAPIView, generics.CreateAPIView): permission_classes = [SuperstudentPermission | AdminPermission] diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 44274122..ecf8e884 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,6 +11,7 @@ "@mdi/font": "5.9.55", "core-js": "^3.8.3", "echofetch": "file:src/api/EchoFetch", + "qrcode-vue3": "^1.5.40", "register-service-worker": "^1.7.2", "roboto-fontface": "*", "tiny-emitter": "^2.1.0", @@ -14746,6 +14747,19 @@ "node": ">=6" } }, + "node_modules/qrcode-generator": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.4.4.tgz", + "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==" + }, + "node_modules/qrcode-vue3": { + "version": "1.5.40", + "resolved": "https://registry.npmjs.org/qrcode-vue3/-/qrcode-vue3-1.5.40.tgz", + "integrity": "sha512-quy3SV+WT5uRFuscoBjYQxYmVvfj7dPQ+zvRbmnaQ/Kn2zmcFpFbHggckD6PDCAKGLZkrphUlmsrUOsnDGaCAg==", + "dependencies": { + "qrcode-generator": "^1.4.4" + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", diff --git a/frontend/src/api/services/TrashTemplateService.ts b/frontend/src/api/services/TrashTemplateService.ts index b0f3611d..d73ccc3d 100644 --- a/frontend/src/api/services/TrashTemplateService.ts +++ b/frontend/src/api/services/TrashTemplateService.ts @@ -21,6 +21,11 @@ class TrashTemplateService extends EchoService { return {} as EchoPromise; } + @GET("/trashtemplates/{year}/{week}/") + getContainers(@Path('year') year: number, @Path('week') week: number): EchoPromise { + return {} as EchoPromise; + } + @GET("/trashtemplates/{id}/trashcontainers/") getTrashContainersOfTemplate(@Path('id') id: number): EchoPromise { return {} as EchoPromise; diff --git a/frontend/src/components/admin/AdminBuildingInfo.vue b/frontend/src/components/admin/AdminBuildingInfo.vue index 095fa90b..a2d0efd4 100644 --- a/frontend/src/components/admin/AdminBuildingInfo.vue +++ b/frontend/src/components/admin/AdminBuildingInfo.vue @@ -130,6 +130,7 @@ import NormalButton from "@/components/NormalButton.vue"; import DeleteIcon from "@/components/icons/DeleteIcon.vue"; import EditIcon from "@/components/icons/EditIcon.vue"; import TrashPickupCard from "@/components/admin/TrashPickupCard.vue"; +import TrashTemplateService from "@/api/services/TrashTemplateService"; export default { @@ -157,6 +158,15 @@ export default { selectedLocation: null, locations: [], errors: null, + day_map: { + MO: 1, + TU: 2, + WE: 3, + TH: 4, + FR: 5, + SA: 6, + SU: 0, + } // syndici: 0 } }, @@ -168,6 +178,8 @@ export default { .then(async result => { this.buildings = result }) + const containers = await this.getContainers() + console.log(containers) }, methods: { changed() { @@ -178,7 +190,6 @@ export default { id: 'getBuildingError', style: 'SNACKBAR' }).then(async result => { - console.log(result) this.id = result.id this.name = result.name this.adres = result.adres @@ -281,7 +292,35 @@ export default { this.departs = [] this.storages = [] }); - } + }, + async getContainers() { + const date = new Date(this.date) + let week = getWeek(date) + + if (date.getUTCDay() === 0) { + week -= 1; + } + await RequestHandler.handle(TrashTemplateService.getContainers(date.getFullYear(), week), { + id: "getContainersError", + style: "NONE" + }).then(containers => { + console.log(containers) + if (this.id.toString() in containers) { + const cs = containers[this.id.toString()]; + this.attrs = cs.map(container => { + const container_date = new Date(week); + const dist = this.day_map[container.collection_day.day] - container_date.getDay(); + container_date.setDate(container_date.getDate() + dist); + return { + dates: container_date, + popover: { + label: this.mapping[container.type].type + }, + dot: this.mapping[container.type].color + }}); + } + }).catch(() => null); + }, } } From 78d50602c80e4755a8f1e1415ac71dae0633dfb4 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 20 May 2023 12:21:37 +0200 Subject: [PATCH 268/340] deel test adminRoundVieuwTest gemaakt --- .../views/admin/adminRoundViewTest.spec.js | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 frontend/tests/unit/views/admin/adminRoundViewTest.spec.js diff --git a/frontend/tests/unit/views/admin/adminRoundViewTest.spec.js b/frontend/tests/unit/views/admin/adminRoundViewTest.spec.js new file mode 100644 index 00000000..4e7e3694 --- /dev/null +++ b/frontend/tests/unit/views/admin/adminRoundViewTest.spec.js @@ -0,0 +1,59 @@ +import { mount } from '@vue/test-utils' +import AdminRoundView from '@/views/admin/AdminRoundView.vue' + +describe('AdminRoundView.vue', () => { + let wrapper; + beforeEach(() => { + AdminRoundView.created = jest.fn(); + wrapper = mount(AdminRoundView); + }) + + it('renders the correct', () => { + expect(wrapper.exists()).toBe(true); + expect(AdminRoundView.created).toHaveBeenCalled(); + }) + + it('sets initial data correctly', () => { + const initialData = wrapper.vm.$data; + expect(initialData.date).toBeNull(); + expect(initialData.dateString).toBe(''); + expect(initialData.planning).toBeNull(); + expect(initialData.pictures).toBeNull(); + expect(initialData.duration).toBeNull(); + expect(initialData.template).toBeNull(); + expect(initialData.status).toBe('Niet voltooid'); + }); + + it('renders the component correctly', async() => { + const wrapper = mount(AdminRoundView, { + data() { + return { + planning: { + students: [ + { id: 1, first_name: 'John', last_name: 'Doe' }, + { id: 2, first_name: 'Jane', last_name: 'Smith' }, + ], + ronde:{name: 'Ronde 1'} + }, + pictures: [], + }; + }, + }); + + await wrapper.vm.$forceUpdate(); + const studentNames = wrapper.findAll('h2'); + expect(studentNames.length).toBe(2); + expect(studentNames[0].text()).toBe('John Doe'); + expect(studentNames[1].text()).toBe('Jane Smith'); + + expect(wrapper.find('h1').text()).toBe('Ronde Ronde 1 op door'); + + const titles = wrapper.findAll('h5'); + expect(titles.at(0).text()).toBe('Gebouw'); + expect(titles.at(1).text()).toBe('Status'); + expect(titles.at(2).text()).toBe('Opmerkingen'); + expect(titles.at(3).text()).toBe('Tijd'); + expect(titles.at(4).text()).toBe('Locatie'); + }); + +}) From d6f3a5752f240c95a9448d9954f5617d1238d762 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 20 May 2023 12:35:57 +0200 Subject: [PATCH 269/340] CreateBuildingView test geschreven --- .../src/views/admin/CreateBuildingView.vue | 2 +- .../admin/createBuildingViewTest.spec.js | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 frontend/tests/unit/views/admin/createBuildingViewTest.spec.js diff --git a/frontend/src/views/admin/CreateBuildingView.vue b/frontend/src/views/admin/CreateBuildingView.vue index 57a0752e..3a4a2837 100644 --- a/frontend/src/views/admin/CreateBuildingView.vue +++ b/frontend/src/views/admin/CreateBuildingView.vue @@ -41,7 +41,7 @@ ----> - + diff --git a/frontend/tests/unit/views/admin/createBuildingViewTest.spec.js b/frontend/tests/unit/views/admin/createBuildingViewTest.spec.js new file mode 100644 index 00000000..a3bfb1f1 --- /dev/null +++ b/frontend/tests/unit/views/admin/createBuildingViewTest.spec.js @@ -0,0 +1,43 @@ +import { mount } from '@vue/test-utils' +import CreateBuildingView from '@/views/admin/CreateBuildingView.vue' + +describe('CreateBuildingView.vue', () => { + + let wrapper; + + beforeEach(() => { + CreateBuildingView.beforeMount = jest.fn(); + wrapper = mount(CreateBuildingView); + }) + + it('renders the correct', () => { + expect(wrapper.exists()).toBe(true); + expect(CreateBuildingView.beforeMount).toHaveBeenCalled(); + }) + + it('initializes the data properties correctly', () => { + expect(wrapper.vm.name).toBe(''); + expect(wrapper.vm.adres).toBe(''); + expect(wrapper.vm.klant_nr).toBe(null); + expect(wrapper.vm.file).toBe(null); + expect(wrapper.vm.smallScreen).toBe(false); + expect(wrapper.vm.locations).toEqual([]); + expect(wrapper.vm.selectedLocation).toBe(null); + expect(wrapper.vm.errors).toBe(null); + }); + + it('call createBuilding when form is submitted', async () => { + CreateBuildingView.methods.createBuilding = jest.fn(); + wrapper = mount(CreateBuildingView); + const button = wrapper.find('[date-test="create"]'); + await button.trigger('click'); + expect(CreateBuildingView.methods.createBuilding).toHaveBeenCalled(); + }) + + it('renders the component correctly', async() => { + expect(wrapper.find('h1').text()).toBe('Nieuw gebouw aanmaken'); + expect(wrapper.find('v-select[label="Locatie"]').exists()).toBeTruthy(); + expect(wrapper.find('v-text-field[label="Klanten nummer"]').exists()).toBeTruthy(); + expect(wrapper.find('v-file-input[label="Handleiding"]').exists()).toBeTruthy(); + }) +}) From 0d17252bacaf344267558cc0e250abaf9137b3ca Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 20 May 2023 12:46:44 +0200 Subject: [PATCH 270/340] CreateEditRoundView test toegevoegd --- .../src/views/admin/CreateEditRoundView.vue | 4 +- .../views/admin/CreateEditRoundView.spec.js | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 frontend/tests/unit/views/admin/CreateEditRoundView.spec.js diff --git a/frontend/src/views/admin/CreateEditRoundView.vue b/frontend/src/views/admin/CreateEditRoundView.vue index dc1b0b10..972fb3fb 100644 --- a/frontend/src/views/admin/CreateEditRoundView.vue +++ b/frontend/src/views/admin/CreateEditRoundView.vue @@ -24,8 +24,8 @@ > - - + + diff --git a/frontend/tests/unit/views/admin/CreateEditRoundView.spec.js b/frontend/tests/unit/views/admin/CreateEditRoundView.spec.js new file mode 100644 index 00000000..717faadc --- /dev/null +++ b/frontend/tests/unit/views/admin/CreateEditRoundView.spec.js @@ -0,0 +1,57 @@ +import { mount } from '@vue/test-utils' +import CreateEditRoundView from '@/views/admin/CreateEditRoundView.vue' + +describe('CreateEditRoundView.vue', () => { + + let wrapper; + + beforeEach(() => { + CreateEditRoundView.beforeCreate = jest.fn(); + wrapper = mount(CreateEditRoundView); + }) + + it('renders the correct', () => { + expect(wrapper.exists()).toBe(true); + expect(CreateEditRoundView.beforeCreate).toHaveBeenCalled(); + }) + + it('renders the correct title when id is undefined', () => { + const title = wrapper.find('h4.text-h4'); + expect(title.text()).toBe('Nieuwe ronde aanmaken'); + }); + + it('renders the correct title when id is defined', () => { + const wrapper = mount(CreateEditRoundView, { + propsData: { + id: '123' + } + }); + const title = wrapper.find('h4.text-h4'); + expect(title.text()).toBe('Ronde bewerken'); + }); + + it('calls createRound method when "Aanmaken" button is clicked', async () => { + CreateEditRoundView.methods.createRound = jest.fn(); + wrapper = mount(CreateEditRoundView); + const createButton = wrapper.find('[data-test="create"]'); + await createButton.trigger('click'); + expect(CreateEditRoundView.methods.createRound).toHaveBeenCalled(); + }); + + it('calls createRound method when "Opslaan" button is clicked', async () => { + CreateEditRoundView.methods.createRound = jest.fn(); + const wrapper = mount(CreateEditRoundView, { + propsData: { + id: '123' + } + }); + const saveButton = wrapper.find('[data-test="save"]'); + await saveButton.trigger('click'); + expect(CreateEditRoundView.methods.createRound).toHaveBeenCalled(); + }); + + it('renders the component correctly', async() => { + expect(wrapper.find('v-autocomplete[label="Locatie"]').exists()).toBeTruthy(); + expect(wrapper.find('v-autocomplete[label="Gebouwen"]').exists()).toBeTruthy(); + }) +}) From 431f2a7fc4808a89f35bd7331c332d933229d2da Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sat, 20 May 2023 12:47:42 +0200 Subject: [PATCH 271/340] enable the use of 'python manage.py createsuperuser' --- backend/users/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/users/models.py b/backend/users/models.py index ae6894af..a9dc7122 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -45,6 +45,12 @@ def create_user(self, email, first_name, last_name, phone_nr, password): user.save() return user + def create_superuser(self, **args): + user = self.create_user(**args, first_name='admin', last_name='admin', phone_nr='') + user.role = 'AD' + user.save() + return user + class User(AbstractUser): """ From 874b063afa5f751179fcd8f48b771f1d792e77f9 Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 20 May 2023 14:52:39 +0200 Subject: [PATCH 272/340] CreateLocationView test toegevoegd --- .../src/views/admin/CreateLocationView.vue | 2 +- .../admin/createLocationViewTest.spec.js | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 frontend/tests/unit/views/admin/createLocationViewTest.spec.js diff --git a/frontend/src/views/admin/CreateLocationView.vue b/frontend/src/views/admin/CreateLocationView.vue index d8d3392d..2c607fbf 100644 --- a/frontend/src/views/admin/CreateLocationView.vue +++ b/frontend/src/views/admin/CreateLocationView.vue @@ -11,7 +11,7 @@ - + diff --git a/frontend/tests/unit/views/admin/createLocationViewTest.spec.js b/frontend/tests/unit/views/admin/createLocationViewTest.spec.js new file mode 100644 index 00000000..dd5110dc --- /dev/null +++ b/frontend/tests/unit/views/admin/createLocationViewTest.spec.js @@ -0,0 +1,45 @@ +import { mount } from '@vue/test-utils' +import CreateLocationView from '@/views/admin/CreateLocationView.vue' +import {triggerInput} from "../../../utils/testHelper"; + +describe('CreateLocationView.vue', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(CreateLocationView); + }) + + it('renders the correct', () => { + expect(wrapper.exists()).toBe(true); + }) + + it('initializes data correctly', () => { + expect(wrapper.vm.name).toBe(''); + expect(wrapper.vm.errors).toBe(null); + }); + + it('calls addLocation method on button click', async () => { + CreateLocationView.methods.addLocation = jest.fn(); + wrapper = mount(CreateLocationView); + await wrapper.find('[data-test="add"]').trigger('click'); + + expect(CreateLocationView.methods.addLocation).toHaveBeenCalled(); + }); + + it('renders the component correctly', async() => { + const h1s = wrapper.findAll('h1'); + expect(h1s.at(0).text()).toBe('Nieuwe locatie aanmaken'); + expect(h1s.at(1).text()).toBe('Naam'); + }) + + it('updates name when v-model is changed', async () => { + const input = wrapper.find('v-text-field'); + input.element.value = 'New Location'; + const activator = (x) => { + return {name: x} + } + triggerInput(input, wrapper, activator) + + expect(wrapper.vm.name).toBe('New Location'); + }); +}) From d6d5d1c5d4a086865b5e4fc6df8e8b85ff11e60a Mon Sep 17 00:00:00 2001 From: jbvilla Date: Sat, 20 May 2023 15:37:04 +0200 Subject: [PATCH 273/340] testen toegevoegd --- frontend/src/views/RegisterView.vue | 2 +- frontend/src/views/Unauthorized.vue | 2 +- frontend/tests/unit/views/otherTests.spec.js | 55 +++++++++++++++++++ .../tests/unit/views/registerViewTest.spec.js | 47 ++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 frontend/tests/unit/views/otherTests.spec.js create mode 100644 frontend/tests/unit/views/registerViewTest.spec.js diff --git a/frontend/src/views/RegisterView.vue b/frontend/src/views/RegisterView.vue index b5b5f49d..ede6064c 100644 --- a/frontend/src/views/RegisterView.vue +++ b/frontend/src/views/RegisterView.vue @@ -34,7 +34,7 @@ - + diff --git a/frontend/src/views/Unauthorized.vue b/frontend/src/views/Unauthorized.vue index b691bb1b..62dec626 100644 --- a/frontend/src/views/Unauthorized.vue +++ b/frontend/src/views/Unauthorized.vue @@ -18,7 +18,7 @@
U heeft onvoldoende rechten om deze pagina te bezoeken.
- + diff --git a/frontend/tests/unit/views/otherTests.spec.js b/frontend/tests/unit/views/otherTests.spec.js new file mode 100644 index 00000000..c227e3a9 --- /dev/null +++ b/frontend/tests/unit/views/otherTests.spec.js @@ -0,0 +1,55 @@ +import { mount } from '@vue/test-utils'; +import HomeView from "@/views/HomeView.vue"; +import Unauthorized from "@/views/Unauthorized.vue"; + +describe('HomeView', () => { + + + it('create is called when component is mounted', () => { + HomeView.created = jest.fn(); + mount(HomeView); + expect(HomeView.created).toHaveBeenCalled(); + }) + + it('renders the correct', () => { + HomeView.created = jest.fn(); + const wrapper = mount(HomeView); + expect(wrapper.exists()).toBe(true); + }) + +}); + +describe('Unauthorized.vue', () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(Unauthorized); + }) + + it('renders the correct', () => { + expect(wrapper.exists()).toBe(true); + }) + + it('displays the "Unauthorized" message', () => { + const message = wrapper.find('.mx-1'); + expect(message.text()).toBe('Geen toegang!'); + }); + + it('goBack is called when button is clicked', async () => { + Unauthorized.methods.goBack = jest.fn(); + wrapper = mount(Unauthorized); + const button = await wrapper.find('[data-test="goBack"]'); + await button.trigger('click'); + expect(Unauthorized.methods.goBack).toHaveBeenCalled(); + }) + + it('renders the component correctly', async() => { + const divs = wrapper.findAll('div[class="mx-1"]'); + expect(divs.at(0).text()).toBe('Geen toegang!'); + expect(divs.at(1).text()).toBe('U heeft onvoldoende rechten om deze pagina te bezoeken.'); + }) + +}) + + diff --git a/frontend/tests/unit/views/registerViewTest.spec.js b/frontend/tests/unit/views/registerViewTest.spec.js new file mode 100644 index 00000000..13dd1bed --- /dev/null +++ b/frontend/tests/unit/views/registerViewTest.spec.js @@ -0,0 +1,47 @@ +import { mount } from '@vue/test-utils' +import RegisterView from "@/views/RegisterView.vue"; + +describe('RegisterView.vue', () => { + + let wrapper; + + beforeEach(() => { + wrapper = mount(RegisterView); + }) + + it('renders the correct', () => { + expect(wrapper.exists()).toBe(true); + }) + + it('initializes data correctly', () => { + expect(wrapper.vm.valid).toBe(true); + expect(wrapper.vm.showPassword).toBe(false); + expect(wrapper.vm.firstname).toBe(''); + expect(wrapper.vm.lastname).toBe(''); + expect(wrapper.vm.email).toBe(''); + expect(wrapper.vm.password).toBe(''); + expect(wrapper.vm.password2).toBe(''); + expect(wrapper.vm.phone_nr).toBe(''); + expect(wrapper.vm.errors).toBeNull(); + }); + + it('calls apiRegister method on button click', async () => { + RegisterView.methods.apiRegister = jest.fn(); + wrapper = mount(RegisterView); + await wrapper.find('[data-test="register"]').trigger('click'); + + expect(RegisterView.methods.apiRegister).toHaveBeenCalled(); + }) + + it('render correctly', async () => { + expect(wrapper.find('v-text-field[label="Voornaam"]').exists()).toBe(true); + expect(wrapper.find('v-text-field[label="Achternaam"]').exists()).toBe(true); + expect(wrapper.find('v-text-field[label="E-mail"]').exists()).toBe(true); + expect(wrapper.find('v-text-field[label="Wachtwoord"]').exists()).toBe(true); + expect(wrapper.find('v-text-field[label="Bevestig wachtwoord"]').exists()).toBe(true); + expect(wrapper.find('v-autocomplete[label="Locatie"]').exists()).toBe(true); + expect(wrapper.find('v-text-field[label="GSM-nummer"]').exists()).toBe(true); + expect(wrapper.find('div[class="mx-1"]').exists()).toBe(true); + }) + +}) From 60eb65bc98748297742759bb2679d6047ee01900 Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sat, 20 May 2023 16:32:30 +0200 Subject: [PATCH 274/340] syndicus home fix --- frontend/src/views/syndicus/SyndicusHome.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/views/syndicus/SyndicusHome.vue b/frontend/src/views/syndicus/SyndicusHome.vue index 10651f6a..b293682a 100644 --- a/frontend/src/views/syndicus/SyndicusHome.vue +++ b/frontend/src/views/syndicus/SyndicusHome.vue @@ -233,6 +233,7 @@ export default { }).catch(() => null); }, async getStudentPosts(){ + if (this.building === null) return; const date = new Date(this.date) let week = getWeek(date) if (date.getUTCDay() === 0) week -= 1; From 3b62449c51d28cd32e44c5c46ca4ac125821f3a5 Mon Sep 17 00:00:00 2001 From: Kai Hozee Date: Sat, 20 May 2023 16:48:34 +0200 Subject: [PATCH 275/340] Added coverage to gitignore --- frontend/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/.gitignore b/frontend/.gitignore index 403adbc1..3c24141c 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -21,3 +21,6 @@ pnpm-debug.log* *.njsproj *.sln *.sw? + +# Coverage html files +coverage/ \ No newline at end of file From c6447b78e32a50512bd88ba2a68692efb8a5ee9e Mon Sep 17 00:00:00 2001 From: pjotrvisman Date: Sat, 20 May 2023 17:04:29 +0200 Subject: [PATCH 276/340] change lib for viewing qr code --- frontend/package.json | 2 +- frontend/src/views/syndicus/SyndicusHome.vue | 21 ++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 475a9c51..92d93421 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,10 +10,10 @@ "force": "npm install --force" }, "dependencies": { + "@chenfengyuan/vue-qrcode": "^2.0.0", "@mdi/font": "5.9.55", "core-js": "^3.8.3", "echofetch": "file:src/api/EchoFetch", - "qrcode-vue3": "^1.5.40", "register-service-worker": "^1.7.2", "roboto-fontface": "*", "tiny-emitter": "^2.1.0", diff --git a/frontend/src/views/syndicus/SyndicusHome.vue b/frontend/src/views/syndicus/SyndicusHome.vue index b293682a..02c712ae 100644 --- a/frontend/src/views/syndicus/SyndicusHome.vue +++ b/frontend/src/views/syndicus/SyndicusHome.vue @@ -24,7 +24,7 @@
QR-code voor gebouw {{building.name}}
- + />--> +
+ +

@@ -115,13 +122,13 @@ import RoundService from "@/api/services/RoundService"; import FotoCardAdmin from "@/components/admin/FotoCardAdmin.vue"; import { getWeek } from "@/api/DateUtil"; import PlanningService from "@/api/services/PlanningService"; -import QRCodeVue3 from "qrcode-vue3"; import NormalButton from "@/components/NormalButton.vue"; import TrashTemplateService from "@/api/services/TrashTemplateService"; +import VueQrcode from '@chenfengyuan/vue-qrcode'; export default { name: "SyndicusHome", - components: {NormalButton, FotoCardAdmin, DatePicker, QRCodeVue3}, + components: {NormalButton, FotoCardAdmin, DatePicker, VueQrcode}, data: () => ({ date: new Date().toISOString().split('T')[0], week: new Date(), @@ -186,8 +193,10 @@ export default { iframe.addEventListener('load', function () { // Clone the image - const image = document.getElementsByClassName('qr')[0].cloneNode(); - image.style.width = '80vw'; + const url = document.getElementsByTagName('canvas')[0].toDataURL(); + const image = document.createElement('img'); + image.src = url; + image.style.width = '70vw'; // Add text to page const text = document.createElement('h1'); From 7377b5cc3a8b2a07096660f9a1bf09609d05f628 Mon Sep 17 00:00:00 2001 From: novdamme Date: Sat, 20 May 2023 17:13:25 +0200 Subject: [PATCH 277/340] toon achternaam bij studenten voor dagplanning Signed-off-by: novdamme --- frontend/src/views/student_template/DagplanningEditView.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/student_template/DagplanningEditView.vue b/frontend/src/views/student_template/DagplanningEditView.vue index 617d7d45..548e1bcb 100644 --- a/frontend/src/views/student_template/DagplanningEditView.vue +++ b/frontend/src/views/student_template/DagplanningEditView.vue @@ -14,7 +14,7 @@ :readonly="this.status === 'Vervangen'" label="Studenten" :items="all_students.filter(student => student.role !== 'AA' && student.locations.includes(this.location.id))" - item-title="first_name" + :item-title="getTitle" item-value="id" multiple chips @@ -107,6 +107,9 @@ export default { }, methods: { check_errors, + getTitle(item) { + return `${item.first_name} ${item.last_name}` + }, format_day(day) { const day_mapping = { "MO": "Maandag", From f5dee8a36d22fb0521d85fd490ced3d011dcff59 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Sat, 20 May 2023 18:04:06 +0200 Subject: [PATCH 278/340] fix getContainers --- .../components/admin/AdminBuildingInfo.vue | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/admin/AdminBuildingInfo.vue b/frontend/src/components/admin/AdminBuildingInfo.vue index a2d0efd4..da1e1ae0 100644 --- a/frontend/src/components/admin/AdminBuildingInfo.vue +++ b/frontend/src/components/admin/AdminBuildingInfo.vue @@ -11,8 +11,10 @@ - + @@ -32,7 +34,7 @@ item-title="name" item-value="id" v-model="this.name" - v-on:update:modelValue="(el) => this.buildingChange(el)" + v-on:update:modelValue="(el) => {this.buildingChange(el); this.getContainers()}" > @@ -121,6 +123,7 @@ From ad5beb1fc1991c28e04aaaa06e2a404802ef8ec2 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Sun, 21 May 2023 01:15:19 +0200 Subject: [PATCH 296/340] change syndicussen to syndici --- frontend/src/components/NavigationBar.vue | 4 ++-- frontend/src/components/admin/CreateEditSyndicus.vue | 6 +++--- frontend/src/components/admin/ListPage.vue | 2 +- frontend/src/views/listViews/SyndicusList.vue | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/NavigationBar.vue b/frontend/src/components/NavigationBar.vue index f05abdab..91dcd030 100644 --- a/frontend/src/components/NavigationBar.vue +++ b/frontend/src/components/NavigationBar.vue @@ -19,8 +19,8 @@ value="gebouwen"> - + diff --git a/frontend/src/components/admin/CreateEditSyndicus.vue b/frontend/src/components/admin/CreateEditSyndicus.vue index 7804671a..27bf10db 100644 --- a/frontend/src/components/admin/CreateEditSyndicus.vue +++ b/frontend/src/components/admin/CreateEditSyndicus.vue @@ -89,7 +89,7 @@ export default { async update(building_id, syndicus) { /** * This method is the request we send to the backend. The body exists of an updated list - * of syndicussen for a specific building. + * of syndici for a specific building. */ await RequestHandler.handle(BuildingService.updateBuildingById(Number(building_id), { 'syndicus': syndicus @@ -187,8 +187,8 @@ export default { customMessages: [ { code: '500', - message: 'Kon alle syndicussen niet ophalen.', - description: 'Kon syndicussen niet ophalen.' + message: 'Kon alle syndici niet ophalen.', + description: 'Kon syndici niet ophalen.' } ] }).then(users => { diff --git a/frontend/src/components/admin/ListPage.vue b/frontend/src/components/admin/ListPage.vue index e474b606..7647708f 100644 --- a/frontend/src/components/admin/ListPage.vue +++ b/frontend/src/components/admin/ListPage.vue @@ -16,7 +16,7 @@ Heeft als nodige argumenten nodig:

{{ this.title }}

-
+
diff --git a/frontend/src/views/listViews/SyndicusList.vue b/frontend/src/views/listViews/SyndicusList.vue index 34084659..aa99144d 100644 --- a/frontend/src/views/listViews/SyndicusList.vue +++ b/frontend/src/views/listViews/SyndicusList.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/components/admin/StudentCard.vue b/frontend/src/components/admin/StudentCard.vue index e1c49050..c88b56af 100644 --- a/frontend/src/components/admin/StudentCard.vue +++ b/frontend/src/components/admin/StudentCard.vue @@ -81,7 +81,7 @@ export default { description: 'Kon gebruiker niet verwijderen' }] }) - location.reload() + // location.reload() }, goToInfoPage: async function () { await this.$router.push({name: 'admin_info_user', params: {id: this.data.id}}) diff --git a/frontend/src/components/admin/TemplateMailCard.vue b/frontend/src/components/admin/TemplateMailCard.vue index d79dd3a3..7701a27e 100644 --- a/frontend/src/components/admin/TemplateMailCard.vue +++ b/frontend/src/components/admin/TemplateMailCard.vue @@ -49,8 +49,8 @@ export default { goToEditPage: function () { router.push({name: 'mail-template-edit', params: {id: this.data.id}}) }, - deletePost: function () { - RequestHandler.handle(EmailTemplateService.deleteEmailTemplateById(this.data.id)) + deletePost: async function () { + await RequestHandler.handle(EmailTemplateService.deleteEmailTemplateById(this.data.id)) .then( () => window.location.reload()) } }, diff --git a/frontend/src/components/admin/mail/CreateEditMailTemplate.vue b/frontend/src/components/admin/mail/CreateEditMailTemplate.vue index efcf69e1..3ad213b7 100644 --- a/frontend/src/components/admin/mail/CreateEditMailTemplate.vue +++ b/frontend/src/components/admin/mail/CreateEditMailTemplate.vue @@ -108,8 +108,8 @@ export default { router.push({name: 'mailtemplates'}) }).catch(async (error) => {this.errors = await get_errors(error)}); }, - editTemplate () { - MailTemplateService.updateMailTemplate(this.$route.params.id,{ + async editTemplate () { + await MailTemplateService.updateMailTemplate(this.$route.params.id,{ name: this.template.name, content: this.template.text }).then(() => { diff --git a/frontend/src/views/admin/CreateBuildingView.vue b/frontend/src/views/admin/CreateBuildingView.vue index 57a0752e..d7556048 100644 --- a/frontend/src/views/admin/CreateBuildingView.vue +++ b/frontend/src/views/admin/CreateBuildingView.vue @@ -88,7 +88,7 @@ export default { // TODO Milestone 3 Add geschatte tijd const manual = await this.createManual() - BuildingService.createBuilding({ + await BuildingService.createBuilding({ name: this.name, adres: this.adres, ivago_klantnr: this.klant_nr, diff --git a/frontend/src/views/listViews/SyndicusList.vue b/frontend/src/views/listViews/SyndicusList.vue index b76829f9..f7b29cf0 100644 --- a/frontend/src/views/listViews/SyndicusList.vue +++ b/frontend/src/views/listViews/SyndicusList.vue @@ -27,7 +27,6 @@ export default { } }, async beforeMount () { - this.headComponent.props.student = false await RequestHandler.handle(UserService.getUsers(), {id: 'getUsers', style: 'SNACKBAR'}) .then(async result => { for (const user of result) { From bbbe72ad42d5cbf058d152e3844526e8b3ec2de8 Mon Sep 17 00:00:00 2001 From: WouterDeBolle Date: Sun, 21 May 2023 04:38:42 +0200 Subject: [PATCH 307/340] fix linter: wrong default arguments --- frontend/src/components/SearchDropdown.vue | 2 +- frontend/src/components/admin/ListPage.vue | 2 +- frontend/src/components/admin/RoundBuildingCard.vue | 3 --- frontend/src/components/admin/RoundListPage.vue | 2 +- frontend/src/components/util/RoundSearchDropdown.vue | 2 +- 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/SearchDropdown.vue b/frontend/src/components/SearchDropdown.vue index e2e0ac8b..16865869 100644 --- a/frontend/src/components/SearchDropdown.vue +++ b/frontend/src/components/SearchDropdown.vue @@ -79,7 +79,7 @@ export default { }, mapKeys: { type: Map, - default: () => {}, + default: {}, required: true }, placeholder: { diff --git a/frontend/src/components/admin/ListPage.vue b/frontend/src/components/admin/ListPage.vue index c5237ad9..8f36982e 100644 --- a/frontend/src/components/admin/ListPage.vue +++ b/frontend/src/components/admin/ListPage.vue @@ -87,7 +87,7 @@ export default { }, mapKeys: { type: Map, - default: () => {}, + default: {}, required: true }, refresh: { diff --git a/frontend/src/components/admin/RoundBuildingCard.vue b/frontend/src/components/admin/RoundBuildingCard.vue index 225282ce..18079e6b 100644 --- a/frontend/src/components/admin/RoundBuildingCard.vue +++ b/frontend/src/components/admin/RoundBuildingCard.vue @@ -37,12 +37,10 @@