mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender.git
synced 2025-07-24 13:38:48 +02:00
Merge branch 'development' into 'main'
Development See merge request htwk-software/htwkalender!53
This commit is contained in:
1845
frontend/package-lock.json
generated
1845
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,26 +19,24 @@
|
|||||||
"@fullcalendar/timegrid": "^6.1.11",
|
"@fullcalendar/timegrid": "^6.1.11",
|
||||||
"@fullcalendar/vue3": "^6.1.11",
|
"@fullcalendar/vue3": "^6.1.11",
|
||||||
"@tanstack/vue-query": "^5.28.9",
|
"@tanstack/vue-query": "^5.28.9",
|
||||||
"@tanstack/vue-query-devtools": "^5.28.10",
|
|
||||||
"@unhead/ssr": "^1.9.14",
|
"@unhead/ssr": "^1.9.14",
|
||||||
"@unhead/vue": "^1.9.10",
|
|
||||||
"@vueuse/core": "^10.9.0",
|
"@vueuse/core": "^10.9.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"primeflex": "^3.3.1",
|
"primeflex": "^3.3.1",
|
||||||
"primeicons": "^6.0.1",
|
"primeicons": "^6.0.1",
|
||||||
"primevue": "^3.50.0",
|
"primevue": "^3.50.0",
|
||||||
"source-sans": "^3.46.0",
|
"source-sans": "^3.46.0",
|
||||||
"vite-ssg": "^0.23.7",
|
|
||||||
"vue": "^3.4.11",
|
"vue": "^3.4.11",
|
||||||
"vue-i18n": "^9.10.2",
|
"vue-i18n": "^9.10.2"
|
||||||
"vue-router": "^4.3.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@types/node": "^20.12.2",
|
"@types/node": "^20.12.2",
|
||||||
|
"@unhead/vue": "^1.9.15",
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"@vue/eslint-config-typescript": "^12.0.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
|
"@tanstack/vue-query-devtools": "^5.28.10",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-vue": "^9.24.0",
|
"eslint-plugin-vue": "^9.24.0",
|
||||||
@ -48,8 +46,11 @@
|
|||||||
"terser": "^5.31.0",
|
"terser": "^5.31.0",
|
||||||
"typescript": "^5.4.3",
|
"typescript": "^5.4.3",
|
||||||
"vite": "^5.2.7",
|
"vite": "^5.2.7",
|
||||||
|
"vite-plugin-vue-devtools": "^7.3.1",
|
||||||
|
"vite-ssg": "^0.23.7",
|
||||||
"vite-ssg-sitemap": "^0.7.1",
|
"vite-ssg-sitemap": "^0.7.1",
|
||||||
"vitest": "^1.4.0",
|
"vitest": "^1.4.0",
|
||||||
|
"vue-router": "^4.4.0",
|
||||||
"vue-tsc": "^1.8.27"
|
"vue-tsc": "^1.8.27"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
<div class="col">{{ $t("faqView.ninthQuestion") }}</div>
|
<div class="col">{{ $t("faqView.ninthQuestion") }}</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{{ $t("faqView.ninthAnswer") }}
|
{{ $t("faqView.ninthAnswer") }}
|
||||||
<a href="https://git.imn.htwk-leipzig.de/ekresse/htwkalender"
|
<a href="https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender"
|
||||||
>Gitlab</a
|
>Gitlab</a
|
||||||
>.
|
>.
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,6 +22,7 @@ import {resolve as pathResolver} from "path";
|
|||||||
import terser from "@rollup/plugin-terser";
|
import terser from "@rollup/plugin-terser";
|
||||||
import ViteSSGOptions from "vite-ssg";
|
import ViteSSGOptions from "vite-ssg";
|
||||||
import generateSitemap from 'vite-ssg-sitemap'
|
import generateSitemap from 'vite-ssg-sitemap'
|
||||||
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
|
|
||||||
const hostname = "https://cal.htwk-leipzig.de";
|
const hostname = "https://cal.htwk-leipzig.de";
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ export default defineConfig({
|
|||||||
vue(),
|
vue(),
|
||||||
resolve(),
|
resolve(),
|
||||||
terser(),
|
terser(),
|
||||||
|
vueDevTools(),
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias:
|
alias:
|
||||||
|
@ -51,5 +51,9 @@ http {
|
|||||||
location / {
|
location / {
|
||||||
proxy_pass http://htwkalender-frontend:8000;
|
proxy_pass http://htwkalender-frontend:8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /__devtools__ {
|
||||||
|
proxy_pass http://htwkalender-frontend:8000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ import (
|
|||||||
"github.com/pocketbase/pocketbase"
|
"github.com/pocketbase/pocketbase"
|
||||||
"github.com/pocketbase/pocketbase/plugins/migratecmd"
|
"github.com/pocketbase/pocketbase/plugins/migratecmd"
|
||||||
_ "htwkalender/data-manager/migrations"
|
_ "htwkalender/data-manager/migrations"
|
||||||
|
"htwkalender/data-manager/model/serviceModel"
|
||||||
"htwkalender/data-manager/service"
|
"htwkalender/data-manager/service"
|
||||||
|
"htwkalender/data-manager/service/events"
|
||||||
"htwkalender/data-manager/service/grpc"
|
"htwkalender/data-manager/service/grpc"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
@ -29,6 +31,14 @@ import (
|
|||||||
|
|
||||||
func setupApp() *pocketbase.PocketBase {
|
func setupApp() *pocketbase.PocketBase {
|
||||||
app := pocketbase.New()
|
app := pocketbase.New()
|
||||||
|
courseService := events.NewPocketBaseCourseService(app)
|
||||||
|
eventService := events.NewPocketBaseEventService(app)
|
||||||
|
|
||||||
|
services := serviceModel.Service{
|
||||||
|
CourseService: courseService,
|
||||||
|
EventService: eventService,
|
||||||
|
App: app,
|
||||||
|
}
|
||||||
|
|
||||||
// loosely check if it was executed using "go run"
|
// loosely check if it was executed using "go run"
|
||||||
isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
|
isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
|
||||||
@ -41,8 +51,8 @@ func setupApp() *pocketbase.PocketBase {
|
|||||||
// (the isGoRun check is to enable it only during development)
|
// (the isGoRun check is to enable it only during development)
|
||||||
Automigrate: isGoRun,
|
Automigrate: isGoRun,
|
||||||
})
|
})
|
||||||
service.AddRoutes(app)
|
service.AddRoutes(services)
|
||||||
service.AddSchedules(app)
|
service.AddSchedules(services)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
@ -37,25 +37,25 @@ func TestEventsContains(t *testing.T) {
|
|||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty events",
|
name: "event contains empty events",
|
||||||
m: Events{},
|
m: Events{},
|
||||||
args: args{event: Event{}},
|
args: args{event: Event{}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one event",
|
name: "event contains one event",
|
||||||
m: Events{{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}},
|
m: Events{{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}},
|
||||||
args: args{event: Event{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}},
|
args: args{event: Event{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "two events",
|
name: "event contains two events",
|
||||||
m: Events{{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, {Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}},
|
m: Events{{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, {Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}},
|
||||||
args: args{event: Event{Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}},
|
args: args{event: Event{Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "two events with different values",
|
name: "event contains two events with different values",
|
||||||
m: Events{{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test", UUID: "439ßu56rf8u9ijn4f4-2345345"}, {Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2", UUID: "432a39ßu545349ijn4f4-23dsa45"}},
|
m: Events{{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test", UUID: "439ßu56rf8u9ijn4f4-2345345"}, {Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2", UUID: "432a39ßu545349ijn4f4-23dsa45"}},
|
||||||
args: args{event: Event{Day: "test3", Week: "test3", Start: specificTime, End: specificTime, Name: "test3", Course: "test3", Prof: "test3", Rooms: "test3", EventType: "test3", UUID: "934mf43r34f-g68h7655tg3"}},
|
args: args{event: Event{Day: "test3", Week: "test3", Start: specificTime, End: specificTime, Name: "test3", Course: "test3", Prof: "test3", Rooms: "test3", EventType: "test3", UUID: "934mf43r34f-g68h7655tg3"}},
|
||||||
want: false,
|
want: false,
|
||||||
@ -99,25 +99,25 @@ func TestEventEquals(t *testing.T) {
|
|||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty events",
|
name: "event equals empty events",
|
||||||
fields: fields{},
|
fields: fields{},
|
||||||
args: args{event: Event{}},
|
args: args{event: Event{}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one empty one not",
|
name: "event equals one empty one not",
|
||||||
fields: fields{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"},
|
fields: fields{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"},
|
||||||
args: args{event: Event{}},
|
args: args{event: Event{}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one event",
|
name: "event equals one event",
|
||||||
fields: fields{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"},
|
fields: fields{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"},
|
||||||
args: args{event: Event{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}},
|
args: args{event: Event{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "two events",
|
name: "event equals two events",
|
||||||
fields: fields{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"},
|
fields: fields{Day: "test", Week: "test", Start: specificTime, End: specificTime, Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"},
|
||||||
args: args{event: Event{Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}},
|
args: args{event: Event{Day: "test2", Week: "test2", Start: specificTime, End: specificTime, Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}},
|
||||||
want: false,
|
want: false,
|
||||||
@ -172,22 +172,22 @@ func TestEventAnonymizeEvent(t *testing.T) {
|
|||||||
want AnonymizedEventDTO
|
want AnonymizedEventDTO
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty event",
|
name: "event anonymize empty event",
|
||||||
fields: fields{},
|
fields: fields{},
|
||||||
want: AnonymizedEventDTO{Day: "", Week: "", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "", Free: false},
|
want: AnonymizedEventDTO{Day: "", Week: "", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "", Free: false},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one event",
|
name: "event anonymize one event",
|
||||||
fields: fields{Name: "Event", Day: "test", Week: "test", Rooms: "test"},
|
fields: fields{Name: "Event", Day: "test", Week: "test", Rooms: "test"},
|
||||||
want: AnonymizedEventDTO{Day: "test", Week: "test", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "test", Free: false},
|
want: AnonymizedEventDTO{Day: "test", Week: "test", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "test", Free: false},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one event with free",
|
name: "event anonymize one event with free",
|
||||||
fields: fields{Name: "Räume zur freien Verfügung", Day: "test", Week: "test", Rooms: "test", Course: "test"},
|
fields: fields{Name: "Räume zur freien Verfügung", Day: "test", Week: "test", Rooms: "test", Course: "test"},
|
||||||
want: AnonymizedEventDTO{Day: "test", Week: "test", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "test", Free: true},
|
want: AnonymizedEventDTO{Day: "test", Week: "test", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "test", Free: true},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "another free event",
|
name: "event anonymize another free event",
|
||||||
fields: fields{Name: "Zur freien Verfügung", Day: "Montag", Week: "5", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "TR_A1.28-S", Course: "42INM-3"},
|
fields: fields{Name: "Zur freien Verfügung", Day: "Montag", Week: "5", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "TR_A1.28-S", Course: "42INM-3"},
|
||||||
want: AnonymizedEventDTO{Day: "Montag", Week: "5", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "TR_A1.28-S", Free: true},
|
want: AnonymizedEventDTO{Day: "Montag", Week: "5", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "TR_A1.28-S", Free: true},
|
||||||
},
|
},
|
||||||
@ -242,12 +242,12 @@ func TestEventGetName(t *testing.T) {
|
|||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty event",
|
name: "event get name - empty event",
|
||||||
fields: fields{},
|
fields: fields{},
|
||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one event",
|
name: "event get name - one event",
|
||||||
fields: fields{Name: "Event"},
|
fields: fields{Name: "Event"},
|
||||||
want: "Event",
|
want: "Event",
|
||||||
},
|
},
|
||||||
@ -464,7 +464,7 @@ func TestEventsContains1(t *testing.T) {
|
|||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty events",
|
name: "event contains - empty events",
|
||||||
m: Events{},
|
m: Events{},
|
||||||
args: args{event: Event{}},
|
args: args{event: Event{}},
|
||||||
want: false,
|
want: false,
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFeed_SetModules(t *testing.T) {
|
func TestFeedSetModules(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
Modules string
|
Modules string
|
||||||
Retrieved types.DateTime
|
Retrieved types.DateTime
|
||||||
|
@ -2,7 +2,7 @@ package model
|
|||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestModuleDTO_GetName(t *testing.T) {
|
func TestModuleDTOGetName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
UUID string
|
UUID string
|
||||||
Name string
|
Name string
|
||||||
@ -41,7 +41,7 @@ func TestModuleDTO_GetName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModuleDTO_SetName(t *testing.T) {
|
func TestModuleDTOSetName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
UUID string
|
UUID string
|
||||||
Name string
|
Name string
|
||||||
@ -83,7 +83,7 @@ func TestModuleDTO_SetName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModule_SetName(t *testing.T) {
|
func TestModuleSetName(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
UUID string
|
UUID string
|
||||||
Name string
|
Name string
|
||||||
|
12
services/data-manager/model/serviceModel/serviceModel.go
Normal file
12
services/data-manager/model/serviceModel/serviceModel.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package serviceModel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase"
|
||||||
|
"htwkalender/data-manager/service/events"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
App *pocketbase.PocketBase
|
||||||
|
EventService events.EventService
|
||||||
|
CourseService events.CourseService
|
||||||
|
}
|
@ -17,8 +17,8 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"htwkalender/data-manager/model/serviceModel"
|
||||||
"htwkalender/data-manager/service/course"
|
"htwkalender/data-manager/service/course"
|
||||||
"htwkalender/data-manager/service/events"
|
|
||||||
"htwkalender/data-manager/service/fetch/sport"
|
"htwkalender/data-manager/service/fetch/sport"
|
||||||
v1 "htwkalender/data-manager/service/fetch/v1"
|
v1 "htwkalender/data-manager/service/fetch/v1"
|
||||||
v2 "htwkalender/data-manager/service/fetch/v2"
|
v2 "htwkalender/data-manager/service/fetch/v2"
|
||||||
@ -28,19 +28,18 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/labstack/echo/v5"
|
"github.com/labstack/echo/v5"
|
||||||
"github.com/pocketbase/pocketbase"
|
|
||||||
"github.com/pocketbase/pocketbase/apis"
|
"github.com/pocketbase/pocketbase/apis"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddRoutes(app *pocketbase.PocketBase) {
|
func AddRoutes(services serviceModel.Service) {
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/fetch/events",
|
Path: "/api/fetch/events",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
savedEvents, err := v2.ParseEventsFromRemote(app)
|
savedEvents, err := v2.ParseEventsFromRemote(services.App)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to parse events from remote: ", "error", err)
|
slog.Error("Failed to parse events from remote: ", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to parse events from remote")
|
return c.JSON(http.StatusBadRequest, "Failed to parse events from remote")
|
||||||
@ -49,7 +48,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
apis.RequireAdminAuth(),
|
apis.RequireAdminAuth(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -59,16 +58,16 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/fetch/daily/events",
|
Path: "/api/fetch/daily/events",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
course.UpdateCourse(app)
|
course.UpdateCourse(services)
|
||||||
return c.JSON(http.StatusOK, "Daily events fetched")
|
return c.JSON(http.StatusOK, "Daily events fetched")
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
apis.RequireAdminAuth(),
|
apis.RequireAdminAuth(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -78,19 +77,19 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/fetch/groups",
|
Path: "/api/fetch/groups",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
groups, err := v1.FetchSeminarGroups(app)
|
groups, err := v1.FetchSeminarGroups(services.App)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to fetch seminar groups")
|
return c.JSON(http.StatusBadRequest, "Failed to fetch seminar groups")
|
||||||
}
|
}
|
||||||
return c.JSON(http.StatusOK, groups)
|
return c.JSON(http.StatusOK, groups)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
apis.RequireAdminAuth(),
|
apis.RequireAdminAuth(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -100,20 +99,20 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/fetch/sports",
|
Path: "/api/fetch/sports",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
|
|
||||||
sportEvents, err := sport.FetchAndUpdateSportEvents(app)
|
sportEvents, err := sport.FetchAndUpdateSportEvents(services.App)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to fetch sport events")
|
return c.JSON(http.StatusBadRequest, "Failed to fetch sport events")
|
||||||
}
|
}
|
||||||
return c.JSON(http.StatusOK, sportEvents)
|
return c.JSON(http.StatusOK, sportEvents)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
apis.RequireAdminAuth(),
|
apis.RequireAdminAuth(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -123,19 +122,19 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodDelete,
|
Method: http.MethodDelete,
|
||||||
Path: "/api/modules",
|
Path: "/api/modules",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
err := events.DeleteAllEvents(app)
|
err := services.EventService.DeleteAllEvents()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to delete events")
|
return c.JSON(http.StatusBadRequest, "Failed to delete events")
|
||||||
}
|
}
|
||||||
return c.JSON(http.StatusOK, "Events deleted")
|
return c.JSON(http.StatusOK, "Events deleted")
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
apis.RequireAdminAuth(),
|
apis.RequireAdminAuth(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -145,19 +144,19 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/rooms",
|
Path: "/api/rooms",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
rooms, err := room.GetRooms(app)
|
rooms, err := room.GetRooms(services.App)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get rooms")
|
return c.JSON(http.StatusBadRequest, "Failed to get rooms")
|
||||||
}
|
}
|
||||||
return c.JSON(http.StatusOK, rooms)
|
return c.JSON(http.StatusOK, rooms)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -167,14 +166,14 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// API Endpoint to get all events for a specific room on a specific day
|
// API Endpoint to get all events for a specific room on a specific day
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/schedule/day",
|
Path: "/api/schedule/day",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
roomParam := c.QueryParam("room")
|
roomParam := c.QueryParam("room")
|
||||||
date := c.QueryParam("date")
|
date := c.QueryParam("date")
|
||||||
roomSchedule, err := room.GetRoomScheduleForDay(app, roomParam, date)
|
roomSchedule, err := room.GetRoomScheduleForDay(services.App, roomParam, date)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get room schedule for day: ", "error", err)
|
slog.Error("Failed to get room schedule for day: ", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get room schedule for day")
|
return c.JSON(http.StatusBadRequest, "Failed to get room schedule for day")
|
||||||
@ -182,7 +181,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return c.JSON(http.StatusOK, roomSchedule)
|
return c.JSON(http.StatusOK, roomSchedule)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -192,7 +191,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// API Endpoint to create a new iCal feed
|
// API Endpoint to create a new iCal feed
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/schedule",
|
Path: "/api/schedule",
|
||||||
@ -200,7 +199,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
roomParam := c.QueryParam("room")
|
roomParam := c.QueryParam("room")
|
||||||
to := c.QueryParam("to")
|
to := c.QueryParam("to")
|
||||||
from := c.QueryParam("from")
|
from := c.QueryParam("from")
|
||||||
roomSchedule, err := room.GetRoomSchedule(app, roomParam, from, to)
|
roomSchedule, err := room.GetRoomSchedule(services.App, roomParam, from, to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get room schedule:", "error", err)
|
slog.Error("Failed to get room schedule:", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get room schedule")
|
return c.JSON(http.StatusBadRequest, "Failed to get room schedule")
|
||||||
@ -208,7 +207,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return c.JSON(http.StatusOK, roomSchedule)
|
return c.JSON(http.StatusOK, roomSchedule)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -218,7 +217,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// API Endpoint to get all rooms that have no events in a specific time frame
|
// API Endpoint to get all rooms that have no events in a specific time frame
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/rooms/free",
|
Path: "/api/rooms/free",
|
||||||
@ -233,7 +232,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
slog.Error("Failed to parse time: ", "error", err)
|
slog.Error("Failed to parse time: ", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to parse time")
|
return c.JSON(http.StatusBadRequest, "Failed to parse time")
|
||||||
}
|
}
|
||||||
rooms, err := room.GetFreeRooms(app, from, to)
|
rooms, err := room.GetFreeRooms(services.App, from, to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get free rooms: ", "error", err)
|
slog.Error("Failed to get free rooms: ", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get free rooms")
|
return c.JSON(http.StatusBadRequest, "Failed to get free rooms")
|
||||||
@ -241,7 +240,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return c.JSON(http.StatusOK, rooms)
|
return c.JSON(http.StatusOK, rooms)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -250,15 +249,14 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
addFeedRoutes(app)
|
addFeedRoutes(services.App)
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/course/modules",
|
Path: "/api/course/modules",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
modules, err := events.GetModulesForCourseDistinct(
|
modules, err := services.EventService.GetModulesForCourseDistinct(
|
||||||
app,
|
|
||||||
c.QueryParam("course"),
|
c.QueryParam("course"),
|
||||||
c.QueryParam("semester"),
|
c.QueryParam("semester"),
|
||||||
)
|
)
|
||||||
@ -271,7 +269,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -280,12 +278,12 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/modules",
|
Path: "/api/modules",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
modules, err := events.GetAllModulesDistinct(app)
|
modules, err := services.EventService.GetAllModulesDistinct()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get modules: ", "error", err)
|
slog.Error("Failed to get modules: ", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get modules")
|
return c.JSON(http.StatusBadRequest, "Failed to get modules")
|
||||||
@ -293,7 +291,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return c.JSON(http.StatusOK, modules)
|
return c.JSON(http.StatusOK, modules)
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -302,13 +300,13 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/module",
|
Path: "/api/module",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
requestModule := c.QueryParam("uuid")
|
requestModule := c.QueryParam("uuid")
|
||||||
module, err := events.GetModuleByUUID(app, requestModule)
|
module, err := services.EventService.GetModuleByUUID(requestModule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get module: ", "error", err)
|
slog.Error("Failed to get module: ", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get module")
|
return c.JSON(http.StatusBadRequest, "Failed to get module")
|
||||||
@ -317,7 +315,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -326,22 +324,26 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/courses",
|
Path: "/api/courses",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
semester := c.QueryParam("semester")
|
semester := c.QueryParam("semester")
|
||||||
if semester == "" {
|
if semester == "" {
|
||||||
courses := events.GetAllCourses(app)
|
courses := services.CourseService.GetAllCourses()
|
||||||
return c.JSON(200, courses)
|
return c.JSON(200, courses)
|
||||||
} else {
|
} else {
|
||||||
courses := events.GetAllCoursesForSemester(app, semester)
|
seminarGroups := services.CourseService.GetAllCoursesForSemester(semester)
|
||||||
return c.JSON(200, courses)
|
courseStringList := make([]string, 0)
|
||||||
|
for _, seminarGroup := range seminarGroups {
|
||||||
|
courseStringList = append(courseStringList, seminarGroup.Course)
|
||||||
|
}
|
||||||
|
return c.JSON(200, courseStringList)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -351,14 +353,13 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// api end point to get all courses for a specific semester with courses that have events
|
// api end point to get all courses for a specific semester with courses that have events
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/courses/events",
|
Path: "/api/courses/events",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
semester := c.QueryParam("semester")
|
semester := c.QueryParam("semester")
|
||||||
courses, err := events.GetAllCoursesForSemesterWithEvents(app, semester)
|
courses, err := services.CourseService.GetAllCoursesForSemesterWithEvents(semester)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get courses for semester with events: ", "error", err)
|
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")
|
return c.JSON(http.StatusBadRequest, "Failed to get courses for semester with events")
|
||||||
@ -367,7 +368,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -377,12 +378,12 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// API Endpoint to get all eventTypes from the database distinct
|
// API Endpoint to get all eventTypes from the database distinct
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/api/events/types",
|
Path: "/api/events/types",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
eventTypes, err := events.GetEventTypes(app)
|
eventTypes, err := services.EventService.GetEventTypes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get event types", "error", err)
|
slog.Error("Failed to get event types", "error", err)
|
||||||
return c.JSON(http.StatusBadRequest, "Failed to get event types")
|
return c.JSON(http.StatusBadRequest, "Failed to get event types")
|
||||||
@ -391,7 +392,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -400,13 +401,12 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
_, err := e.Router.AddRoute(echo.Route{
|
_, err := e.Router.AddRoute(echo.Route{
|
||||||
Method: http.MethodDelete,
|
Method: http.MethodDelete,
|
||||||
Path: "/api/events",
|
Path: "/api/events",
|
||||||
Handler: func(c echo.Context) error {
|
Handler: func(c echo.Context) error {
|
||||||
err := events.DeleteAllEventsByCourseAndSemester(
|
err := services.EventService.DeleteAllEventsByCourseAndSemester(
|
||||||
app,
|
|
||||||
c.QueryParam("course"),
|
c.QueryParam("course"),
|
||||||
c.QueryParam("semester"),
|
c.QueryParam("semester"),
|
||||||
)
|
)
|
||||||
@ -418,7 +418,7 @@ func AddRoutes(app *pocketbase.PocketBase) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Middlewares: []echo.MiddlewareFunc{
|
Middlewares: []echo.MiddlewareFunc{
|
||||||
apis.ActivityLogger(app),
|
apis.ActivityLogger(services.App),
|
||||||
apis.RequireAdminAuth(),
|
apis.RequireAdminAuth(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pocketbase/pocketbase"
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/tools/cron"
|
"github.com/pocketbase/pocketbase/tools/cron"
|
||||||
|
"htwkalender/data-manager/model/serviceModel"
|
||||||
"htwkalender/data-manager/service/course"
|
"htwkalender/data-manager/service/course"
|
||||||
"htwkalender/data-manager/service/feed"
|
"htwkalender/data-manager/service/feed"
|
||||||
"htwkalender/data-manager/service/fetch/sport"
|
"htwkalender/data-manager/service/fetch/sport"
|
||||||
@ -30,9 +30,9 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddSchedules(app *pocketbase.PocketBase) {
|
func AddSchedules(services serviceModel.Service) {
|
||||||
|
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
services.App.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
scheduler := cron.New()
|
scheduler := cron.New()
|
||||||
|
|
||||||
// !! IMPORTANT !! CRON is based on UTC time zone so in Germany it is UTC+2 in summer and UTC+1 in winter
|
// !! IMPORTANT !! CRON is based on UTC time zone so in Germany it is UTC+2 in summer and UTC+1 in winter
|
||||||
@ -40,7 +40,7 @@ func AddSchedules(app *pocketbase.PocketBase) {
|
|||||||
// Every sunday at 10pm update all courses (5 segments - minute, hour, day, month, weekday) "0 22 * * 0"
|
// Every sunday at 10pm update all courses (5 segments - minute, hour, day, month, weekday) "0 22 * * 0"
|
||||||
scheduler.MustAdd("updateCourses", "0 22 * * 0", func() {
|
scheduler.MustAdd("updateCourses", "0 22 * * 0", func() {
|
||||||
slog.Info("Started updating courses schedule")
|
slog.Info("Started updating courses schedule")
|
||||||
groups, err := v1.FetchSeminarGroups(app)
|
groups, err := v1.FetchSeminarGroups(services.App)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Warn("Failed to fetch seminar groups: ", "error", err)
|
slog.Warn("Failed to fetch seminar groups: ", "error", err)
|
||||||
}
|
}
|
||||||
@ -51,20 +51,20 @@ func AddSchedules(app *pocketbase.PocketBase) {
|
|||||||
// In Germany it is 7am and 7pm, syllabus gets updated twice a day at German 5:00 Uhr and 17:00 Uhr
|
// In Germany it is 7am and 7pm, syllabus gets updated twice a day at German 5:00 Uhr and 17:00 Uhr
|
||||||
scheduler.MustAdd("updateEventsByCourse", "0 5,17 * * *", func() {
|
scheduler.MustAdd("updateEventsByCourse", "0 5,17 * * *", func() {
|
||||||
slog.Info("Started updating courses schedule")
|
slog.Info("Started updating courses schedule")
|
||||||
course.UpdateCourse(app)
|
course.UpdateCourse(services)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Every sunday at 1am clean all courses (5 segments - minute, hour, day, month, weekday) "0 3 * * 0"
|
// Every sunday at 1am clean all courses (5 segments - minute, hour, day, month, weekday) "0 3 * * 0"
|
||||||
scheduler.MustAdd("cleanFeeds", "0 1 * * 0", func() {
|
scheduler.MustAdd("cleanFeeds", "0 1 * * 0", func() {
|
||||||
// clean feeds older than 6 months
|
// clean feeds older than 6 months
|
||||||
slog.Info("Started cleaning feeds schedule")
|
slog.Info("Started cleaning feeds schedule")
|
||||||
feed.ClearFeeds(app.Dao(), 6, time.RealClock{})
|
feed.ClearFeeds(services.App.Dao(), 6, time.RealClock{})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Every sunday at 3am fetch all sport events (5 segments - minute, hour, day, month, weekday) "0 2 * * 0"
|
// Every sunday at 3am fetch all sport events (5 segments - minute, hour, day, month, weekday) "0 2 * * 0"
|
||||||
scheduler.MustAdd("fetchSportEvents", "0 3 * * 0", func() {
|
scheduler.MustAdd("fetchSportEvents", "0 3 * * 0", func() {
|
||||||
slog.Info("Started fetching sport events schedule")
|
slog.Info("Started fetching sport events schedule")
|
||||||
sportEvents, err := sport.FetchAndUpdateSportEvents(app)
|
sportEvents, err := sport.FetchAndUpdateSportEvents(services.App)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to fetch and save sport events:", "error", err)
|
slog.Error("Failed to fetch and save sport events:", "error", err)
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ func AddSchedules(app *pocketbase.PocketBase) {
|
|||||||
|
|
||||||
//fetch all events for semester and delete from remote this should be done every sunday at 2am
|
//fetch all events for semester and delete from remote this should be done every sunday at 2am
|
||||||
scheduler.MustAdd("fetchEvents", "0 22 * * 6", func() {
|
scheduler.MustAdd("fetchEvents", "0 22 * * 6", func() {
|
||||||
savedEvents, err := v2.FetchAllEventsAndSave(app, time.RealClock{})
|
savedEvents, err := v2.FetchAllEventsAndSave(services.App, time.RealClock{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to fetch and save events: ", "error", err)
|
slog.Error("Failed to fetch and save events: ", "error", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,17 +17,26 @@
|
|||||||
package course
|
package course
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pocketbase/pocketbase"
|
"htwkalender/data-manager/model"
|
||||||
"htwkalender/data-manager/service/events"
|
"htwkalender/data-manager/model/serviceModel"
|
||||||
|
"htwkalender/data-manager/service/functions"
|
||||||
|
"htwkalender/data-manager/service/functions/time"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UpdateCourse(app *pocketbase.PocketBase) {
|
func UpdateCourse(service serviceModel.Service) {
|
||||||
courses := events.GetAllCourses(app)
|
currentSemesters := functions.CalculateSemesterList(time.RealClock{})
|
||||||
for _, course := range courses {
|
|
||||||
_, err := events.UpdateModulesForCourse(app, course)
|
var seminarGroups []model.SeminarGroup
|
||||||
|
|
||||||
|
for _, semester := range currentSemesters {
|
||||||
|
seminarGroups = append(seminarGroups, service.CourseService.GetAllCoursesForSemester(semester)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, seminarGroup := range seminarGroups {
|
||||||
|
_, err := service.EventService.UpdateModulesForCourse(seminarGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Warn("Update Course: "+course+" failed:", "error", err)
|
slog.Warn("Update Course: "+seminarGroup.Course+" failed:", "error", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
97
services/data-manager/service/course/courseFunctions_test.go
Normal file
97
services/data-manager/service/course/courseFunctions_test.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package course
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"htwkalender/data-manager/model"
|
||||||
|
"htwkalender/data-manager/model/serviceModel"
|
||||||
|
"htwkalender/data-manager/service/events/mock"
|
||||||
|
"log/slog"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomWriter is a custom writer to capture log output
|
||||||
|
type CustomWriter struct {
|
||||||
|
Buffer bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CustomWriter) Write(p []byte) (n int, err error) {
|
||||||
|
return w.Buffer.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateCourse(t *testing.T) {
|
||||||
|
// Create mock services
|
||||||
|
mockCourseService := new(mock.MockCourseService)
|
||||||
|
mockEventService := new(mock.MockEventService)
|
||||||
|
|
||||||
|
events := model.Events{}
|
||||||
|
|
||||||
|
// Set up expectations
|
||||||
|
mockCourseService.On("GetAllCoursesForSemester", "ss").Return([]model.SeminarGroup{{Course: "Course1", Semester: ""}, {Course: "Course2", Semester: ""}})
|
||||||
|
mockEventService.On("UpdateModulesForCourse", model.SeminarGroup{Course: "Course1", Semester: ""}).Return(events, nil)
|
||||||
|
mockEventService.On("UpdateModulesForCourse", model.SeminarGroup{Course: "Course2", Semester: ""}).Return(events, nil)
|
||||||
|
|
||||||
|
// Inject mocks into the UpdateCourse function
|
||||||
|
service := serviceModel.Service{
|
||||||
|
CourseService: mockCourseService,
|
||||||
|
EventService: mockEventService,
|
||||||
|
App: nil,
|
||||||
|
}
|
||||||
|
UpdateCourse(service)
|
||||||
|
|
||||||
|
// Assert that the expectations were met
|
||||||
|
mockCourseService.AssertExpectations(t)
|
||||||
|
mockEventService.AssertExpectations(t)
|
||||||
|
|
||||||
|
// Assert that the UpdateCourse function was called twice
|
||||||
|
mockCourseService.AssertNumberOfCalls(t, "GetAllCoursesForSemester", 1)
|
||||||
|
mockEventService.AssertNumberOfCalls(t, "UpdateModulesForCourse", 2)
|
||||||
|
|
||||||
|
// Assert that the UpdateCourse function was called with the correct arguments
|
||||||
|
mockEventService.AssertCalled(t, "UpdateModulesForCourse", model.SeminarGroup{Course: "Course1", Semester: ""})
|
||||||
|
mockEventService.AssertCalled(t, "UpdateModulesForCourse", model.SeminarGroup{Course: "Course2", Semester: ""})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateCourseErr(t *testing.T) {
|
||||||
|
// Create mock services
|
||||||
|
mockCourseService := new(mock.MockCourseService)
|
||||||
|
mockEventService := new(mock.MockEventService)
|
||||||
|
|
||||||
|
events := model.Events{}
|
||||||
|
|
||||||
|
// Set up expectations
|
||||||
|
mockCourseService.On("GetAllCoursesForSemester", "ss").Return([]model.SeminarGroup{{Course: "Course1", Semester: ""}, {Course: "Course2", Semester: ""}})
|
||||||
|
mockEventService.On("UpdateModulesForCourse", model.SeminarGroup{Course: "Course1", Semester: ""}).Return(events, fmt.Errorf("error"))
|
||||||
|
mockEventService.On("UpdateModulesForCourse", model.SeminarGroup{Course: "Course2", Semester: ""}).Return(events, fmt.Errorf("error"))
|
||||||
|
|
||||||
|
// Create a custom writer to capture log output
|
||||||
|
customWriter := &CustomWriter{}
|
||||||
|
originalLogger := slog.Default()
|
||||||
|
defer slog.SetDefault(originalLogger)
|
||||||
|
|
||||||
|
// Replace the default logger with a custom logger
|
||||||
|
slog.SetDefault(slog.New(slog.NewTextHandler(customWriter, nil)))
|
||||||
|
|
||||||
|
// Inject mocks into the UpdateCourse function
|
||||||
|
service := serviceModel.Service{
|
||||||
|
CourseService: mockCourseService,
|
||||||
|
EventService: mockEventService,
|
||||||
|
App: nil,
|
||||||
|
}
|
||||||
|
UpdateCourse(service)
|
||||||
|
|
||||||
|
// Assert that the expectations were met
|
||||||
|
mockCourseService.AssertExpectations(t)
|
||||||
|
mockEventService.AssertExpectations(t)
|
||||||
|
|
||||||
|
// Assert that the UpdateCourse function was called twice
|
||||||
|
mockCourseService.AssertNumberOfCalls(t, "GetAllCoursesForSemester", 1)
|
||||||
|
mockEventService.AssertNumberOfCalls(t, "UpdateModulesForCourse", 2)
|
||||||
|
|
||||||
|
// Check the captured log output for the expected messages
|
||||||
|
logOutput := customWriter.Buffer.String()
|
||||||
|
require.Regexp(t, regexp.MustCompile(`Update Course: Course1 failed:.*error`), logOutput)
|
||||||
|
require.Regexp(t, regexp.MustCompile(`Update Course: Course2 failed:.*error`), logOutput)
|
||||||
|
}
|
@ -24,56 +24,68 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SaveGroups(seminarGroup []model.SeminarGroup, collection *models.Collection, app *pocketbase.PocketBase) ([]*models.Record, error) {
|
type SeminarGroup struct {
|
||||||
var savedRecords []*models.Record
|
University string `db:"university" json:"university"`
|
||||||
var tobeSavedGroups []model.SeminarGroup
|
GroupShortcut string `db:"shortcut" json:"shortcut"`
|
||||||
var insertRecords []*models.Record
|
GroupId string `db:"groupId" json:"groupId"`
|
||||||
|
Course string `db:"course" json:"course"`
|
||||||
for _, group := range seminarGroup {
|
Faculty string `db:"faculty" json:"faculty"`
|
||||||
dbGroup, err := FindGroupByCourseAndSemester(group.Course, group.Semester, app)
|
FacultyId string `db:"facultyId" json:"facultyId"`
|
||||||
|
Semester string `db:"semester" json:"semester"`
|
||||||
if dbGroup == nil && err.Error() == "sql: no rows in result set" {
|
models.BaseModel
|
||||||
tobeSavedGroups = append(tobeSavedGroups, group)
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create record for each group that's not already in the database
|
|
||||||
for _, group := range tobeSavedGroups {
|
|
||||||
record := models.NewRecord(collection)
|
|
||||||
record.Set("university", group.University)
|
|
||||||
record.Set("shortcut", group.GroupShortcut)
|
|
||||||
record.Set("groupId", group.GroupId)
|
|
||||||
record.Set("course", group.Course)
|
|
||||||
record.Set("faculty", group.Faculty)
|
|
||||||
record.Set("facultyId", group.FacultyId)
|
|
||||||
record.Set("semester", group.Semester)
|
|
||||||
insertRecords = append(insertRecords, record)
|
|
||||||
}
|
|
||||||
|
|
||||||
// save all records
|
|
||||||
for _, record := range insertRecords {
|
|
||||||
if record != nil {
|
|
||||||
err := app.Dao().SaveRecord(record)
|
|
||||||
if err == nil {
|
|
||||||
savedRecords = append(savedRecords, record)
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return savedRecords, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindGroupByCourseAndSemester(course string, semester string, app *pocketbase.PocketBase) (*model.SeminarGroup, error) {
|
func (s *SeminarGroup) TableName() string {
|
||||||
var group model.SeminarGroup
|
return "groups"
|
||||||
err := app.Dao().DB().Select("*").From("groups").Where(dbx.NewExp("course = {:course} AND semester = {:semester}", dbx.Params{"course": course, "semester": semester})).One(&group)
|
}
|
||||||
|
|
||||||
|
// UniqueKey Should be same as unique constraint in the database
|
||||||
|
func (s *SeminarGroup) UniqueKey() string {
|
||||||
|
return s.Course + s.Semester
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SeminarGroup) toSeminarGroupModel() model.SeminarGroup {
|
||||||
|
return model.SeminarGroup{
|
||||||
|
University: s.University,
|
||||||
|
GroupShortcut: s.GroupShortcut,
|
||||||
|
GroupId: s.GroupId,
|
||||||
|
Course: s.Course,
|
||||||
|
Faculty: s.Faculty,
|
||||||
|
FacultyId: s.FacultyId,
|
||||||
|
Semester: s.Semester,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SeminarGroups) toSeminarGroupModels() []model.SeminarGroup {
|
||||||
|
var seminarGroups []model.SeminarGroup
|
||||||
|
for _, group := range *s {
|
||||||
|
seminarGroups = append(seminarGroups, group.toSeminarGroupModel())
|
||||||
|
}
|
||||||
|
return seminarGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
type SeminarGroups []*SeminarGroup
|
||||||
|
|
||||||
|
func SaveGroups(seminarGroups SeminarGroups, app *pocketbase.PocketBase) (SeminarGroups, error) {
|
||||||
|
|
||||||
|
// delete all groups from the database
|
||||||
|
execute, err := app.Dao().DB().Delete("groups", dbx.NewExp("1 = 1")).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &group, nil
|
rowCount, _ := execute.RowsAffected()
|
||||||
|
|
||||||
|
savedGroups := SeminarGroups{}
|
||||||
|
for _, group := range seminarGroups {
|
||||||
|
saveErr := app.Dao().Save(group)
|
||||||
|
if saveErr != nil {
|
||||||
|
return nil, saveErr
|
||||||
|
}
|
||||||
|
savedGroups = append(savedGroups, group)
|
||||||
|
}
|
||||||
|
slog.Info("Saved all groups to the database", "insert", len(savedGroups), "deleted", rowCount)
|
||||||
|
|
||||||
|
return savedGroups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllCourses(app *pocketbase.PocketBase) []string {
|
func GetAllCourses(app *pocketbase.PocketBase) []string {
|
||||||
@ -98,26 +110,18 @@ func GetAllCourses(app *pocketbase.PocketBase) []string {
|
|||||||
return courseArray
|
return courseArray
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllCoursesForSemester(app *pocketbase.PocketBase, semester string) []string {
|
func GetAllCoursesForSemester(app *pocketbase.PocketBase, semester string) []model.SeminarGroup {
|
||||||
|
|
||||||
var courses []struct {
|
var courses SeminarGroups
|
||||||
CourseShortcut string `db:"course" json:"course"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all courses for a specific semester
|
// get all courses for a specific semester
|
||||||
err := app.Dao().DB().Select("course").From("groups").Where(dbx.NewExp("semester = {:semester}", dbx.Params{"semester": semester})).All(&courses)
|
err := app.Dao().DB().Select("*").From("groups").Where(dbx.NewExp("semester = {:semester}", dbx.Params{"semester": semester})).All(&courses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Error while getting groups from database: ", "error", err)
|
slog.Error("Error while getting groups from database: ", "error", err)
|
||||||
return []string{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var courseArray []string
|
return courses.toSeminarGroupModels()
|
||||||
|
|
||||||
for _, course := range courses {
|
|
||||||
courseArray = append(courseArray, course.CourseShortcut)
|
|
||||||
}
|
|
||||||
|
|
||||||
return courseArray
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,36 +18,56 @@ package events
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pocketbase/pocketbase"
|
"github.com/pocketbase/pocketbase"
|
||||||
|
"htwkalender/data-manager/model"
|
||||||
"htwkalender/data-manager/service/db"
|
"htwkalender/data-manager/service/db"
|
||||||
"htwkalender/data-manager/service/functions"
|
"htwkalender/data-manager/service/functions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetAllCourses(app *pocketbase.PocketBase) []string {
|
// CourseService defines the methods to be implemented
|
||||||
return db.GetAllCourses(app)
|
type CourseService interface {
|
||||||
|
GetAllCourses() []string
|
||||||
|
GetAllCoursesForSemester(semester string) []model.SeminarGroup
|
||||||
|
GetAllCoursesForSemesterWithEvents(semester string) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllCoursesForSemester(app *pocketbase.PocketBase, semester string) []string {
|
// PocketBaseCourseService is a struct that implements the CourseService interface
|
||||||
return db.GetAllCoursesForSemester(app, semester)
|
type PocketBaseCourseService struct {
|
||||||
|
app *pocketbase.PocketBase
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllCoursesForSemesterWithEvents(app *pocketbase.PocketBase, semester string) ([]string, error) {
|
// NewPocketBaseCourseService creates a new PocketBaseCourseService
|
||||||
courses, err := db.GetAllCoursesForSemesterWithEvents(app, semester)
|
func NewPocketBaseCourseService(app *pocketbase.PocketBase) *PocketBaseCourseService {
|
||||||
|
return &PocketBaseCourseService{app: app}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllCourses returns all courses
|
||||||
|
func (s *PocketBaseCourseService) GetAllCourses() []string {
|
||||||
|
return db.GetAllCourses(s.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllCoursesForSemester returns all courses for a specific semester
|
||||||
|
func (s *PocketBaseCourseService) GetAllCoursesForSemester(semester string) []model.SeminarGroup {
|
||||||
|
return db.GetAllCoursesForSemester(s.app, semester)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllCoursesForSemesterWithEvents returns all courses for a specific semester with events
|
||||||
|
func (s *PocketBaseCourseService) GetAllCoursesForSemesterWithEvents(semester string) ([]string, error) {
|
||||||
|
courses, err := db.GetAllCoursesForSemesterWithEvents(s.app, semester)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
|
||||||
// remove empty courses like " " or ""
|
|
||||||
courses = removeEmptyCourses(courses)
|
|
||||||
return courses, nil
|
|
||||||
}
|
}
|
||||||
|
// remove empty courses like " " or ""
|
||||||
|
courses = removeEmptyCourses(courses)
|
||||||
|
return courses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeEmptyCourses removes empty courses from the list of courses
|
// removeEmptyCourses removes empty courses from the list of courses
|
||||||
func removeEmptyCourses(courses []string) []string {
|
func removeEmptyCourses(courses []string) []string {
|
||||||
var filteredCourses []string
|
var filteredCourses []string
|
||||||
|
|
||||||
for index, course := range courses {
|
for _, course := range courses {
|
||||||
if !functions.OnlyWhitespace(course) || len(course) != 0 {
|
if !functions.OnlyWhitespace(course) || len(course) != 0 {
|
||||||
filteredCourses = append(filteredCourses, courses[index])
|
filteredCourses = append(filteredCourses, course)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filteredCourses
|
return filteredCourses
|
||||||
|
@ -26,9 +26,31 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetModulesForCourseDistinct(app *pocketbase.PocketBase, course string, semester string) (model.Events, error) {
|
type EventService interface {
|
||||||
|
GetModulesForCourseDistinct(course string, semester string) (model.Events, error)
|
||||||
|
GetAllModulesDistinct() ([]model.ModuleDTO, error)
|
||||||
|
GetModuleByUUID(uuid string) (model.Module, error)
|
||||||
|
DeleteAllEventsByCourseAndSemester(course string, semester string) error
|
||||||
|
DeleteAllEvents() error
|
||||||
|
UpdateModulesForCourse(seminarGroup model.SeminarGroup) (model.Events, error)
|
||||||
|
GetEventTypes() ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
modules, err := db.GetAllModulesForCourse(app, course, semester)
|
type Named interface {
|
||||||
|
GetName() string
|
||||||
|
SetName(name string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PocketBaseEventService struct {
|
||||||
|
app *pocketbase.PocketBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPocketBaseEventService(app *pocketbase.PocketBase) *PocketBaseEventService {
|
||||||
|
return &PocketBaseEventService{app: app}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PocketBaseEventService) GetModulesForCourseDistinct(course string, semester string) (model.Events, error) {
|
||||||
|
modules, err := db.GetAllModulesForCourse(s.app, course, semester)
|
||||||
|
|
||||||
// Convert the []model.Module to []Named
|
// Convert the []model.Module to []Named
|
||||||
var namedEvents []Named
|
var namedEvents []Named
|
||||||
@ -40,11 +62,6 @@ func GetModulesForCourseDistinct(app *pocketbase.PocketBase, course string, seme
|
|||||||
return modules, err
|
return modules, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type Named interface {
|
|
||||||
GetName() string
|
|
||||||
SetName(name string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// replaceEmptyEntry replaces an empty entry in a module with a replacement string
|
// replaceEmptyEntry replaces an empty entry in a module with a replacement string
|
||||||
// If the module is not empty, nothing happens
|
// If the module is not empty, nothing happens
|
||||||
func replaceEmptyEntry(namedList []Named, replacement string) {
|
func replaceEmptyEntry(namedList []Named, replacement string) {
|
||||||
@ -57,8 +74,8 @@ func replaceEmptyEntry(namedList []Named, replacement string) {
|
|||||||
|
|
||||||
// GetAllModulesDistinct returns all modules distinct by name and course from the database
|
// GetAllModulesDistinct returns all modules distinct by name and course from the database
|
||||||
// That means you get all modules with duplicates if they have different courses
|
// That means you get all modules with duplicates if they have different courses
|
||||||
func GetAllModulesDistinct(app *pocketbase.PocketBase) ([]model.ModuleDTO, error) {
|
func (s *PocketBaseEventService) GetAllModulesDistinct() ([]model.ModuleDTO, error) {
|
||||||
modules, err := db.GetAllModulesDistinctByNameAndCourse(app)
|
modules, err := db.GetAllModulesDistinctByNameAndCourse(s.app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -70,13 +87,13 @@ func GetAllModulesDistinct(app *pocketbase.PocketBase) ([]model.ModuleDTO, error
|
|||||||
return modules, nil
|
return modules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetModuleByUUID(app *pocketbase.PocketBase, uuid string) (model.Module, error) {
|
func (s *PocketBaseEventService) GetModuleByUUID(uuid string) (model.Module, error) {
|
||||||
module, findModuleErr := db.FindModuleByUUID(app, uuid)
|
module, findModuleErr := db.FindModuleByUUID(s.app, uuid)
|
||||||
if findModuleErr != nil {
|
if findModuleErr != nil {
|
||||||
return model.Module{}, findModuleErr
|
return model.Module{}, findModuleErr
|
||||||
}
|
}
|
||||||
|
|
||||||
events, findEventsError := db.FindAllEventsByModule(app, module)
|
events, findEventsError := db.FindAllEventsByModule(s.app, module)
|
||||||
if findEventsError != nil || len(events) == 0 {
|
if findEventsError != nil || len(events) == 0 {
|
||||||
return model.Module{}, findEventsError
|
return model.Module{}, findEventsError
|
||||||
} else {
|
} else {
|
||||||
@ -94,8 +111,8 @@ func GetModuleByUUID(app *pocketbase.PocketBase, uuid string) (model.Module, err
|
|||||||
// DeleteAllEventsByCourseAndSemester deletes all events for a course and a semester
|
// DeleteAllEventsByCourseAndSemester deletes all events for a course and a semester
|
||||||
// If the deletion was successful, nil is returned
|
// If the deletion was successful, nil is returned
|
||||||
// If the deletion was not successful, an error is returned
|
// If the deletion was not successful, an error is returned
|
||||||
func DeleteAllEventsByCourseAndSemester(app *pocketbase.PocketBase, course string, semester string) error {
|
func (s *PocketBaseEventService) DeleteAllEventsByCourseAndSemester(course string, semester string) error {
|
||||||
err := db.DeleteAllEventsByCourse(app.Dao(), course, semester)
|
err := db.DeleteAllEventsByCourse(s.app.Dao(), course, semester)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
@ -103,8 +120,8 @@ func DeleteAllEventsByCourseAndSemester(app *pocketbase.PocketBase, course strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteAllEvents(app *pocketbase.PocketBase) error {
|
func (s *PocketBaseEventService) DeleteAllEvents() error {
|
||||||
err := db.DeleteAllEvents(app)
|
err := db.DeleteAllEvents(s.app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
@ -120,14 +137,12 @@ func DeleteAllEvents(app *pocketbase.PocketBase) error {
|
|||||||
// 3. Save all events for the course and the semester
|
// 3. Save all events for the course and the semester
|
||||||
// If the update was successful, nil is returned
|
// If the update was successful, nil is returned
|
||||||
// If the update was not successful, an error is returned
|
// If the update was not successful, an error is returned
|
||||||
func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) (model.Events, error) {
|
func (s *PocketBaseEventService) UpdateModulesForCourse(seminarGroup model.SeminarGroup) (model.Events, error) {
|
||||||
|
|
||||||
seminarGroup, err := v1.GetSeminarGroupEventsFromHTML(course)
|
seminarGroup, err := v1.FetchAndParse(seminarGroup.Semester, seminarGroup.Course)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
seminarGroup = v1.ClearEmptySeminarGroups(seminarGroup)
|
|
||||||
seminarGroup = v1.ReplaceEmptyEventNames(seminarGroup)
|
seminarGroup = v1.ReplaceEmptyEventNames(seminarGroup)
|
||||||
|
|
||||||
//check if events in the seminarGroups Events are already in the database
|
//check if events in the seminarGroups Events are already in the database
|
||||||
@ -136,14 +151,14 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) (model.Ev
|
|||||||
//if there are no events in the database, save the new events
|
//if there are no events in the database, save the new events
|
||||||
|
|
||||||
//get all events for the course and the semester
|
//get all events for the course and the semester
|
||||||
dbEvents, err := db.GetAllEventsForCourse(app, course)
|
dbEvents, err := db.GetAllEventsForCourse(s.app, seminarGroup.Course)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//if there are no events in the database, save the new events
|
//if there are no events in the database, save the new events
|
||||||
if len(dbEvents) == 0 {
|
if len(dbEvents) == 0 {
|
||||||
events, dbError := db.SaveSeminarGroupEvents(seminarGroup, app)
|
events, dbError := db.SaveSeminarGroupEvents(seminarGroup, s.app)
|
||||||
if dbError != nil {
|
if dbError != nil {
|
||||||
return nil, dbError
|
return nil, dbError
|
||||||
}
|
}
|
||||||
@ -156,37 +171,37 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) (model.Ev
|
|||||||
|
|
||||||
// check which events are not already in the database and need to be inserted/saved
|
// check which events are not already in the database and need to be inserted/saved
|
||||||
for _, event := range seminarGroup.Events {
|
for _, event := range seminarGroup.Events {
|
||||||
if !ContainsEvent(dbEvents, event) {
|
if !containsEvent(dbEvents, event) {
|
||||||
insertList = append(insertList, event)
|
insertList = append(insertList, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check which events are in the database but not in the seminarGroup and need to be deleted
|
// check which events are in the database but not in the seminarGroup and need to be deleted
|
||||||
for _, dbEvent := range dbEvents {
|
for _, dbEvent := range dbEvents {
|
||||||
if !ContainsEvent(seminarGroup.Events, dbEvent) {
|
if !containsEvent(seminarGroup.Events, dbEvent) {
|
||||||
deleteList = append(deleteList, dbEvent)
|
deleteList = append(deleteList, dbEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all events that are in the deleteList
|
// delete all events that are in the deleteList
|
||||||
err = db.DeleteEvents(deleteList, app)
|
err = db.DeleteEvents(deleteList, s.app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to delete events:", "error", err)
|
slog.Error("Failed to delete events:", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// save all events that are in the insertList
|
// save all events that are in the insertList
|
||||||
savedEvents, err := db.SaveEvents(insertList, app.Dao())
|
savedEvents, err := db.SaveEvents(insertList, s.app.Dao())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to save events: ", "error", err)
|
slog.Error("Failed to save events: ", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("Course: " + course + " - Event changes: " + strconv.FormatInt(int64(len(insertList)), 10) + " new events, " + strconv.FormatInt(int64(len(deleteList)), 10) + " deleted events")
|
slog.Info("Course: " + seminarGroup.Course + " - Event changes: " + strconv.FormatInt(int64(len(insertList)), 10) + " new events, " + strconv.FormatInt(int64(len(deleteList)), 10) + " deleted events")
|
||||||
return savedEvents, nil
|
return savedEvents, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContainsEvent(events model.Events, event model.Event) bool {
|
func containsEvent(events model.Events, event model.Event) bool {
|
||||||
for _, e := range events {
|
for _, e := range events {
|
||||||
if e.Name == event.Name &&
|
if e.Name == event.Name &&
|
||||||
e.Prof == event.Prof &&
|
e.Prof == event.Prof &&
|
||||||
@ -201,8 +216,8 @@ func ContainsEvent(events model.Events, event model.Event) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEventTypes(app *pocketbase.PocketBase) ([]string, error) {
|
func (s *PocketBaseEventService) GetEventTypes() ([]string, error) {
|
||||||
dbEventTypes, err := db.GetAllEventTypes(app)
|
dbEventTypes, err := db.GetAllEventTypes(s.app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,8 @@ func TestContainsEvent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := ContainsEvent(tt.args.events, tt.args.event); got != tt.want {
|
if got := containsEvent(tt.args.events, tt.args.event); got != tt.want {
|
||||||
t.Errorf("ContainsEvent() = %v, want %v", got, tt.want)
|
t.Errorf("containsEvent() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
66
services/data-manager/service/events/mock/courseMock.go
Normal file
66
services/data-manager/service/events/mock/courseMock.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package mock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"htwkalender/data-manager/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockCourseService is a mock implementation of the CourseService interface
|
||||||
|
type MockCourseService struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockCourseService) GetAllCourses() []string {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockCourseService) GetAllCoursesForSemester(semester string) []model.SeminarGroup {
|
||||||
|
args := m.Called(semester)
|
||||||
|
return args.Get(0).([]model.SeminarGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockCourseService) GetAllCoursesForSemesterWithEvents(semester string) ([]string, error) {
|
||||||
|
args := m.Called(semester)
|
||||||
|
return args.Get(0).([]string), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockEventService is a mock implementation of the EventService interface
|
||||||
|
type MockEventService struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) GetModulesForCourseDistinct(course string, semester string) (model.Events, error) {
|
||||||
|
args := m.Called(course, semester)
|
||||||
|
return args.Get(0).(model.Events), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) GetAllModulesDistinct() ([]model.ModuleDTO, error) {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]model.ModuleDTO), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) GetModuleByUUID(uuid string) (model.Module, error) {
|
||||||
|
args := m.Called(uuid)
|
||||||
|
return args.Get(0).(model.Module), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) DeleteAllEventsByCourseAndSemester(course string, semester string) error {
|
||||||
|
args := m.Called(course, semester)
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) DeleteAllEvents() error {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) UpdateModulesForCourse(seminarGroup model.SeminarGroup) (model.Events, error) {
|
||||||
|
args := m.Called(seminarGroup)
|
||||||
|
return args.Get(0).(model.Events), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockEventService) GetEventTypes() ([]string, error) {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]string), args.Error(1)
|
||||||
|
}
|
@ -41,16 +41,12 @@ func ReplaceEmptyEventNames(group model.SeminarGroup) model.SeminarGroup {
|
|||||||
return group
|
return group
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClearEmptySeminarGroups(seminarGroup model.SeminarGroup) model.SeminarGroup {
|
|
||||||
var newSeminarGroup = model.SeminarGroup{}
|
|
||||||
|
|
||||||
if len(seminarGroup.Events) > 0 && seminarGroup.Course != "" {
|
|
||||||
newSeminarGroup = seminarGroup
|
|
||||||
}
|
|
||||||
return newSeminarGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchHTMLFromURL(semester, seminarGroupLabel string) (string, error) {
|
func fetchHTMLFromURL(semester, seminarGroupLabel string) (string, error) {
|
||||||
|
// check that semester and seminarGroupLabel are not empty
|
||||||
|
if semester == "" || seminarGroupLabel == "" {
|
||||||
|
return "", fmt.Errorf("semester or seminarGroupLabel is empty")
|
||||||
|
}
|
||||||
|
|
||||||
url := "https://stundenplan.htwk-leipzig.de/" + semester + "/Berichte/Text-Listen;Studenten-Sets;name;" + seminarGroupLabel + "?template=sws_semgrp&weeks=1-65"
|
url := "https://stundenplan.htwk-leipzig.de/" + semester + "/Berichte/Text-Listen;Studenten-Sets;name;" + seminarGroupLabel + "?template=sws_semgrp&weeks=1-65"
|
||||||
result, err := fetch.GetHTML(url)
|
result, err := fetch.GetHTML(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,22 +56,6 @@ func fetchHTMLFromURL(semester, seminarGroupLabel string) (string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSeminarGroupEventsFromHTML(seminarGroupLabel string) (model.SeminarGroup, error) {
|
|
||||||
var seminarGroup [2]model.SeminarGroup
|
|
||||||
var errSS, errWS error
|
|
||||||
|
|
||||||
currentMonth := time.Now().Month()
|
|
||||||
|
|
||||||
if isSummerSemester(currentMonth) {
|
|
||||||
seminarGroup[0], errSS = fetchAndParse("ss", seminarGroupLabel)
|
|
||||||
}
|
|
||||||
if isWinterSemester(currentMonth) {
|
|
||||||
seminarGroup[1], errWS = fetchAndParse("ws", seminarGroupLabel)
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkForSuccessfulFetch(errSS, errWS, seminarGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSummerSemester(month time.Month) bool {
|
func isSummerSemester(month time.Month) bool {
|
||||||
return month >= 3 && month <= 10
|
return month >= 3 && month <= 10
|
||||||
}
|
}
|
||||||
@ -84,7 +64,7 @@ func isWinterSemester(month time.Month) bool {
|
|||||||
return month >= 9 || month <= 4
|
return month >= 9 || month <= 4
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAndParse(season, label string) (model.SeminarGroup, error) {
|
func FetchAndParse(season, label string) (model.SeminarGroup, error) {
|
||||||
result, err := fetchHTMLFromURL(season, label)
|
result, err := fetchHTMLFromURL(season, label)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.SeminarGroup{}, err
|
return model.SeminarGroup{}, err
|
||||||
@ -92,20 +72,6 @@ func fetchAndParse(season, label string) (model.SeminarGroup, error) {
|
|||||||
return parseSeminarGroup(result), nil
|
return parseSeminarGroup(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkForSuccessfulFetch(errSS error, errWS error, seminarGroup [2]model.SeminarGroup) (model.SeminarGroup, error) {
|
|
||||||
switch {
|
|
||||||
case errSS != nil && errWS != nil:
|
|
||||||
return model.SeminarGroup{}, errWS
|
|
||||||
case errSS != nil:
|
|
||||||
return seminarGroup[1], nil
|
|
||||||
case errWS != nil:
|
|
||||||
return seminarGroup[0], nil
|
|
||||||
default:
|
|
||||||
seminarGroup[0].Events = append(seminarGroup[0].Events, seminarGroup[1].Events...)
|
|
||||||
return seminarGroup[0], nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SplitEventType(events []model.Event) ([]model.Event, error) {
|
func SplitEventType(events []model.Event) ([]model.Event, error) {
|
||||||
re, err := regexp.Compile("^([VPS])([wp])$")
|
re, err := regexp.Compile("^([VPS])([wp])$")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -135,15 +101,21 @@ func parseSeminarGroup(result string) model.SeminarGroup {
|
|||||||
eventTables := getEventTables(doc)
|
eventTables := getEventTables(doc)
|
||||||
allDayLabels := getAllDayLabels(doc)
|
allDayLabels := getAllDayLabels(doc)
|
||||||
|
|
||||||
if eventTables == nil || allDayLabels == nil {
|
|
||||||
return model.SeminarGroup{}
|
|
||||||
}
|
|
||||||
course := findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data
|
course := findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data
|
||||||
|
semesterString := findFirstSpanWithClass(table, "header-0-2-0").FirstChild.Data
|
||||||
|
semester, year := extractSemesterAndYear(semesterString)
|
||||||
|
|
||||||
|
if eventTables == nil || allDayLabels == nil {
|
||||||
|
return model.SeminarGroup{
|
||||||
|
University: findFirstSpanWithClass(table, "header-1-0-0").FirstChild.Data,
|
||||||
|
Course: course,
|
||||||
|
Events: []model.Event{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eventsWithCombinedWeeks := toEvents(eventTables, allDayLabels, course)
|
eventsWithCombinedWeeks := toEvents(eventTables, allDayLabels, course)
|
||||||
splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks)
|
splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks)
|
||||||
events := splitEventsBySingleWeek(splitEventsByWeekVal)
|
events := splitEventsBySingleWeek(splitEventsByWeekVal)
|
||||||
semesterString := findFirstSpanWithClass(table, "header-0-2-0").FirstChild.Data
|
|
||||||
semester, year := extractSemesterAndYear(semesterString)
|
|
||||||
events = convertWeeksToDates(events, semester, year)
|
events = convertWeeksToDates(events, semester, year)
|
||||||
events = generateUUIDs(events, course)
|
events = generateUUIDs(events, course)
|
||||||
events, err = SplitEventType(events)
|
events, err = SplitEventType(events)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pocketbase/pocketbase"
|
"github.com/pocketbase/pocketbase"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
|
||||||
"htwkalender/data-manager/model"
|
"htwkalender/data-manager/model"
|
||||||
"htwkalender/data-manager/service/db"
|
"htwkalender/data-manager/service/db"
|
||||||
"htwkalender/data-manager/service/functions"
|
"htwkalender/data-manager/service/functions"
|
||||||
@ -58,8 +57,8 @@ func getSeminarHTML(semester string) (string, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchSeminarGroups(app *pocketbase.PocketBase) ([]*models.Record, error) {
|
func FetchSeminarGroups(app *pocketbase.PocketBase) (db.SeminarGroups, error) {
|
||||||
var groups []model.SeminarGroup
|
var groups db.SeminarGroups
|
||||||
|
|
||||||
semesterString := functions.CalculateSemesterList(time.RealClock{})
|
semesterString := functions.CalculateSemesterList(time.RealClock{})
|
||||||
var results [2]string
|
var results [2]string
|
||||||
@ -77,26 +76,24 @@ func FetchSeminarGroups(app *pocketbase.PocketBase) ([]*models.Record, error) {
|
|||||||
// filter duplicates
|
// filter duplicates
|
||||||
groups = removeDuplicates(groups)
|
groups = removeDuplicates(groups)
|
||||||
|
|
||||||
collection, dbError := db.FindCollection(app, "groups")
|
insertedGroups, dbError := db.SaveGroups(groups, app)
|
||||||
if dbError != nil {
|
if dbError != nil {
|
||||||
slog.Error("Error while searching collection groups", "error", dbError)
|
slog.Error("FetchSeminarGroups", "error", dbError)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var insertedGroups []*models.Record
|
|
||||||
|
|
||||||
insertedGroups, dbError = db.SaveGroups(groups, collection, app)
|
|
||||||
if dbError != nil {
|
|
||||||
slog.Error("Error while saving groups", "error", dbError)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return insertedGroups, nil
|
return insertedGroups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeDuplicates(groups []model.SeminarGroup) []model.SeminarGroup {
|
func removeDuplicates(groups db.SeminarGroups) db.SeminarGroups {
|
||||||
var uniqueGroups []model.SeminarGroup
|
uniqueGroups := make(db.SeminarGroups, 0, len(groups))
|
||||||
|
seen := make(map[string]struct{}) // Use an empty struct to minimize memory usage
|
||||||
|
|
||||||
|
// unique Identifier is the course and semester
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
if !contains(uniqueGroups, group) {
|
key := group.UniqueKey()
|
||||||
|
if _, exists := seen[key]; !exists {
|
||||||
|
seen[key] = struct{}{}
|
||||||
uniqueGroups = append(uniqueGroups, group)
|
uniqueGroups = append(uniqueGroups, group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +109,7 @@ func contains(groups []model.SeminarGroup, group model.SeminarGroup) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSeminarGroups(result string, semester string) []model.SeminarGroup {
|
func parseSeminarGroups(result string, semester string) db.SeminarGroups {
|
||||||
|
|
||||||
var studium model.Studium
|
var studium model.Studium
|
||||||
err := xml.Unmarshal([]byte(result), &studium)
|
err := xml.Unmarshal([]byte(result), &studium)
|
||||||
@ -120,11 +117,11 @@ func parseSeminarGroups(result string, semester string) []model.SeminarGroup {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var seminarGroups []model.SeminarGroup
|
var seminarGroups db.SeminarGroups
|
||||||
for _, faculty := range studium.Faculty {
|
for _, faculty := range studium.Faculty {
|
||||||
for _, Studiengang := range faculty.Studiengang {
|
for _, Studiengang := range faculty.Studiengang {
|
||||||
for _, Studienrichtung := range Studiengang.Semgrp {
|
for _, Studienrichtung := range Studiengang.Semgrp {
|
||||||
seminarGroup := model.SeminarGroup{
|
seminarGroup := db.SeminarGroup{
|
||||||
University: "HTWK-Leipzig",
|
University: "HTWK-Leipzig",
|
||||||
GroupShortcut: Studiengang.Name,
|
GroupShortcut: Studiengang.Name,
|
||||||
GroupId: Studiengang.ID,
|
GroupId: Studiengang.ID,
|
||||||
@ -133,7 +130,7 @@ func parseSeminarGroups(result string, semester string) []model.SeminarGroup {
|
|||||||
FacultyId: faculty.ID,
|
FacultyId: faculty.ID,
|
||||||
Semester: semester,
|
Semester: semester,
|
||||||
}
|
}
|
||||||
seminarGroups = append(seminarGroups, seminarGroup)
|
seminarGroups = append(seminarGroups, &seminarGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ require (
|
|||||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
||||||
github.com/pocketbase/dbx v1.10.1
|
github.com/pocketbase/dbx v1.10.1
|
||||||
github.com/pocketbase/pocketbase v0.22.12
|
github.com/pocketbase/pocketbase v0.22.12
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
golang.org/x/net v0.26.0
|
golang.org/x/net v0.26.0
|
||||||
google.golang.org/grpc v1.63.2
|
google.golang.org/grpc v1.63.2
|
||||||
google.golang.org/protobuf v1.34.1
|
google.golang.org/protobuf v1.34.1
|
||||||
@ -41,6 +42,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.0 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.7 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.28.7 // indirect
|
||||||
github.com/aws/smithy-go v1.20.2 // indirect
|
github.com/aws/smithy-go v1.20.2 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/disintegration/imaging v1.6.2 // indirect
|
github.com/disintegration/imaging v1.6.2 // indirect
|
||||||
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
@ -62,10 +64,12 @@ require (
|
|||||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/cobra v1.8.0 // indirect
|
github.com/spf13/cobra v1.8.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.52.0 // indirect
|
github.com/valyala/fasthttp v1.52.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
@ -83,6 +87,7 @@ require (
|
|||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||||
google.golang.org/api v0.180.0 // indirect
|
google.golang.org/api v0.180.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
|
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
|
||||||
modernc.org/libc v1.50.5 // indirect
|
modernc.org/libc v1.50.5 // indirect
|
||||||
modernc.org/mathutil v1.6.0 // indirect
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
@ -218,6 +218,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
@ -366,6 +368,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
Reference in New Issue
Block a user