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/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) {