From 0c71a0ce4933f32d85a615ec2dc2f26b6273bae0 Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Sat, 18 May 2024 12:44:27 +0200 Subject: [PATCH 1/2] feat:#28 added api for eventTypes --- backend/model/eventModel.go | 4 ++++ backend/service/addRoute.go | 28 ++++++++++++++++++++++++-- backend/service/db/dbEvents.go | 11 ++++++++++ backend/service/events/eventService.go | 15 ++++++++++++++ reverseproxy.conf | 18 +++++++++++++++++ 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/backend/model/eventModel.go b/backend/model/eventModel.go index 8a492cf..2debe6d 100644 --- a/backend/model/eventModel.go +++ b/backend/model/eventModel.go @@ -57,6 +57,10 @@ type Event struct { models.BaseModel } +type EventType struct { + EventType string `db:"EventType" json:"eventType"` +} + func (e *Event) Equals(event Event) bool { return e.Day == event.Day && e.Week == event.Week && diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index eeb6884..0f131bf 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -363,7 +363,31 @@ func AddRoutes(app *pocketbase.PocketBase) { slog.Error("Failed to get courses for semester with events: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get courses for semester with events") } else { - return c.JSON(200, courses) + return c.JSON(http.StatusOK, courses) + } + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + // API Endpoint to get all eventTypes from the database distinct + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodGet, + Path: "/api/events/types", + Handler: func(c echo.Context) error { + eventTypes, err := events.GetEventTypes(app) + if err != nil { + slog.Error("Failed to get event types", "error", err) + return c.JSON(http.StatusBadRequest, "Failed to get event types") + } else { + return c.JSON(http.StatusOK, eventTypes) } }, Middlewares: []echo.MiddlewareFunc{ @@ -390,7 +414,7 @@ func AddRoutes(app *pocketbase.PocketBase) { slog.Error("Failed to delete events: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to delete events") } else { - return c.JSON(http.StatusBadRequest, "Events deleted") + return c.JSON(http.StatusOK, "Events deleted") } }, Middlewares: []echo.MiddlewareFunc{ diff --git a/backend/service/db/dbEvents.go b/backend/service/db/dbEvents.go index 0d1fe04..8db7b64 100644 --- a/backend/service/db/dbEvents.go +++ b/backend/service/db/dbEvents.go @@ -367,6 +367,17 @@ func GetEventsThatStartBeforeAndEndBefore(app *pocketbase.PocketBase, from types return events, nil } +func GetAllEventTypes(app *pocketbase.PocketBase) ([]model.EventType, error) { + var eventTypes []model.EventType + + err := app.Dao().DB().Select("EventType").From("events").GroupBy("EventType").Distinct(true).All(&eventTypes) + if err != nil { + return nil, err + } + + return eventTypes, nil +} + func GetEventsThatStartAfterAndEndAfter(app *pocketbase.PocketBase, from types.DateTime, to types.DateTime) (model.Events, error) { var events model.Events err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Start >= {:startDate} AND End >= {:endDate} AND Start <= {:endDate} AND End >= {:startDate}", dbx.Params{"startDate": from, "endDate": to})).All(&events) diff --git a/backend/service/events/eventService.go b/backend/service/events/eventService.go index fedfa51..77b8bb1 100644 --- a/backend/service/events/eventService.go +++ b/backend/service/events/eventService.go @@ -198,3 +198,18 @@ func ContainsEvent(events model.Events, event model.Event) bool { } return false } + +func GetEventTypes(app *pocketbase.PocketBase) ([]string, error) { + dbEventTypes, err := db.GetAllEventTypes(app) + if err != nil { + return nil, err + } + + // Convert the []model.EventType to []string + var eventTypes []string + for _, eventType := range dbEventTypes { + eventTypes = append(eventTypes, eventType.EventType) + } + + return eventTypes, nil +} diff --git a/reverseproxy.conf b/reverseproxy.conf index ff64ab2..0a6d63f 100644 --- a/reverseproxy.conf +++ b/reverseproxy.conf @@ -196,6 +196,24 @@ http { limit_req zone=modules burst=5 nodelay; } + location /api/events/types { + proxy_pass http://htwkalender-backend:8090; + client_max_body_size 20m; + proxy_connect_timeout 600s; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + send_timeout 600s; + proxy_cache_bypass 0; + proxy_no_cache 0; + proxy_cache mcache; # mcache=RAM + proxy_cache_valid 200 301 302 10m; + proxy_cache_valid 403 404 5m; + proxy_cache_lock on; + proxy_cache_use_stale timeout updating; + add_header X-Proxy-Cache $upstream_cache_status; + limit_req zone=modules burst=10 nodelay; + } + location /api/rooms { proxy_pass http://htwkalender-backend:8090; client_max_body_size 20m; From bb613dc5c4cf0192387c8c251acde40c468aeec9 Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Sat, 18 May 2024 12:44:41 +0200 Subject: [PATCH 2/2] feat:#28 rewrote frontend input for filter eventTypes --- frontend/src/api/fetchEvents.ts | 33 +++++++++++++++++++ .../src/components/AdditionalModuleTable.vue | 22 ++++++++++--- 2 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 frontend/src/api/fetchEvents.ts diff --git a/frontend/src/api/fetchEvents.ts b/frontend/src/api/fetchEvents.ts new file mode 100644 index 0000000..7738036 --- /dev/null +++ b/frontend/src/api/fetchEvents.ts @@ -0,0 +1,33 @@ +//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format. +//Copyright (C) 2024 HTWKalender support@htwkalender.de + +//This program is free software: you can redistribute it and/or modify +//it under the terms of the GNU Affero General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. + +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU Affero General Public License for more details. + +//You should have received a copy of the GNU Affero General Public License +//along with this program. If not, see . + +// function to fetch course data from the API + +export async function fetchEventTypes(): Promise { + const eventTypes: string[] = []; + await fetch("/api/events/types") + .then((response) => { + return response.json() as Promise; + }) + .then((responseModules: string[]) => { + responseModules.forEach((eventType: string) => { + eventTypes.push( + eventType, + ); + }); + }); + return eventTypes; +} \ No newline at end of file diff --git a/frontend/src/components/AdditionalModuleTable.vue b/frontend/src/components/AdditionalModuleTable.vue index e62e436..d437567 100644 --- a/frontend/src/components/AdditionalModuleTable.vue +++ b/frontend/src/components/AdditionalModuleTable.vue @@ -30,6 +30,7 @@ import { useDialog } from "primevue/usedialog"; import router from "../router"; import { fetchModule } from "../api/fetchModule.ts"; import { useI18n } from "vue-i18n"; +import { fetchEventTypes } from "../api/fetchEvents.ts"; const dialog = useDialog(); const { t } = useI18n({ useScope: "global" }); @@ -39,6 +40,9 @@ if (store.isEmpty()) { router.replace("/"); } +const eventTypes: Ref = ref([]); + + const mobilePage = inject("mobilePage") as Ref; const filters = ref({ course: { @@ -51,7 +55,7 @@ const filters = ref({ }, eventType: { value: null, - matchMode: FilterMatchMode.CONTAINS, + matchMode: FilterMatchMode.IN, }, prof: { value: null, @@ -63,7 +67,7 @@ const loadedModules: Ref = ref(new Array(10)); const loadingData = ref(true); -onMounted(() => { +onMounted( () => { fetchAllModules() .then( (data) => @@ -74,6 +78,10 @@ onMounted(() => { .finally(() => { loadingData.value = false; }); + + fetchEventTypes().then((data) => { + eventTypes.value = data; + }); }); const ModuleInformation = defineAsyncComponent( @@ -184,16 +192,20 @@ function unselectModule(event: DataTableRowUnselectEvent) {