feat:#11 merge conflicts

This commit is contained in:
survellow
2023-10-25 21:45:11 +02:00
17 changed files with 224 additions and 187 deletions

27
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,27 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch file",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "backend/main.go",
"args": ["serve"],
"showLog": true
},
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "backend",
"env": {},
"args": ["serve"],
"showLog": true
}
]
}

View File

@@ -1,8 +1,13 @@
package model package model
import "github.com/pocketbase/pocketbase/models"
type Feed struct { type Feed struct {
Id string `db:"id" json:"id"`
Modules string `db:"modules" json:"modules"` Modules string `db:"modules" json:"modules"`
Created string `db:"created" json:"created"` models.BaseModel
Updated string `db:"updated" json:"updated"` }
// SetModules set modules field
func (f *Feed) SetModules(modules string) {
f.Modules = modules
} }

View File

@@ -23,6 +23,7 @@ type Entry struct {
type Entries []*Entry type Entries []*Entry
type FeedCollection struct { type FeedCollection struct {
UUID string `db:"uuid" json:"uuid"`
Name string `db:"Name" json:"name"` Name string `db:"Name" json:"name"`
Course string `db:"course" json:"course"` Course string `db:"course" json:"course"`
UserDefinedName string `db:"userDefinedName" json:"userDefinedName"` UserDefinedName string `db:"userDefinedName" json:"userDefinedName"`

View File

@@ -1,6 +1,7 @@
package model package model
type Module struct { type Module struct {
UUID string `json:"uuid"`
Name string `json:"name"` Name string `json:"name"`
Prof string `json:"prof"` Prof string `json:"prof"`
Course string `json:"course"` Course string `json:"course"`

View File

@@ -1,172 +1,4 @@
[ [
{
"id": "_pb_users_auth_",
"name": "users",
"type": "auth",
"system": false,
"schema": [
{
"id": "users_name",
"name": "name",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"id": "users_avatar",
"name": "avatar",
"type": "file",
"system": false,
"required": false,
"options": {
"maxSelect": 1,
"maxSize": 5242880,
"mimeTypes": [
"image/jpeg",
"image/png",
"image/svg+xml",
"image/gif",
"image/webp"
],
"thumbs": null,
"protected": false
}
}
],
"indexes": [],
"listRule": "id = @request.auth.id",
"viewRule": "id = @request.auth.id",
"createRule": "",
"updateRule": "id = @request.auth.id",
"deleteRule": "id = @request.auth.id",
"options": {
"allowEmailAuth": true,
"allowOAuth2Auth": true,
"allowUsernameAuth": true,
"exceptEmailDomains": null,
"manageRule": null,
"minPasswordLength": 8,
"onlyEmailDomains": null,
"requireEmail": false
}
},
{
"id": "cfq9mqlmd97v8z5",
"name": "groups",
"type": "base",
"system": false,
"schema": [
{
"id": "85msl21p",
"name": "university",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"id": "2sii4dtp",
"name": "shortcut",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"id": "uiwgo28f",
"name": "groupId",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"id": "y0l1lrzs",
"name": "course",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"id": "kr62mhbz",
"name": "faculty",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
},
{
"id": "ya6znpez",
"name": "facultyId",
"type": "text",
"system": false,
"required": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
}
],
"indexes": [
"CREATE UNIQUE INDEX `idx_rcaN2Oq` ON `groups` (`course`)"
],
"listRule": null,
"viewRule": null,
"createRule": null,
"updateRule": null,
"deleteRule": null,
"options": {}
},
{
"id": "d65h4wh7zk13gxp",
"name": "feeds",
"type": "base",
"system": false,
"schema": [
{
"id": "cowxjfmc",
"name": "modules",
"type": "json",
"system": false,
"required": true,
"options": {}
}
],
"indexes": [],
"listRule": null,
"viewRule": null,
"createRule": null,
"updateRule": null,
"deleteRule": null,
"options": {}
},
{ {
"id": "7her4515qsmrxe8", "id": "7her4515qsmrxe8",
"name": "events", "name": "events",

View File

@@ -12,16 +12,10 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"os"
) )
func AddRoutes(app *pocketbase.PocketBase) { func AddRoutes(app *pocketbase.PocketBase) {
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
return nil
})
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { 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,
@@ -39,6 +33,24 @@ func AddRoutes(app *pocketbase.PocketBase) {
return nil return nil
}) })
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
_, err := e.Router.AddRoute(echo.Route{
Method: http.MethodDelete,
Path: "/api/modules",
Handler: func(c echo.Context) error {
return events.DeleteAllEvents(app)
},
Middlewares: []echo.MiddlewareFunc{
apis.ActivityLogger(app),
apis.RequireAdminAuth(),
},
})
if err != nil {
return err
}
return nil
})
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { 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,
@@ -243,4 +255,27 @@ func AddRoutes(app *pocketbase.PocketBase) {
} }
return nil return nil
}) })
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
_, err := e.Router.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/api/feed/migrate",
Handler: func(c echo.Context) error {
err := ical.MigrateFeedJson(app)
if err != nil {
return c.JSON(500, err)
} else {
return c.JSON(200, "Migrated")
}
},
Middlewares: []echo.MiddlewareFunc{
apis.ActivityLogger(app),
},
})
if err != nil {
return err
}
return nil
})
} }

View File

@@ -180,6 +180,17 @@ func DeleteAllEventsForCourse(app *pocketbase.PocketBase, course string, semeste
return nil return nil
} }
func DeleteAllEvents(app *pocketbase.PocketBase) error {
_, err := app.Dao().DB().Delete("events", dbx.NewExp("1=1")).Execute()
if err != nil {
return err
}
return nil
}
func FindAllEventsByModule(app *pocketbase.PocketBase, moduleName string) (model.Events, error) { func FindAllEventsByModule(app *pocketbase.PocketBase, moduleName string) (model.Events, error) {
var events model.Events var events model.Events

View File

@@ -53,6 +53,7 @@ func GetModuleByName(app *pocketbase.PocketBase, name string) (model.Module, err
return model.Module{}, err return model.Module{}, err
} else { } else {
return model.Module{ return model.Module{
UUID: events[0].UUID,
Name: name, Name: name,
Events: events, Events: events,
Prof: events[0].Prof, Prof: events[0].Prof,
@@ -74,6 +75,15 @@ func DeleteAllEventsByCourseAndSemester(app *pocketbase.PocketBase, course strin
} }
} }
func DeleteAllEvents(app *pocketbase.PocketBase) error {
err := db.DeleteAllEvents(app)
if err != nil {
return err
} else {
return nil
}
}
// UpdateModulesForCourse updates all modules for a course // UpdateModulesForCourse updates all modules for a course
// Does Updates for ws and ss semester sequentially // Does Updates for ws and ss semester sequentially
// Update runs through the following steps: // Update runs through the following steps:

View File

@@ -113,22 +113,23 @@ func parseSeminarGroup(result string) model.SeminarGroup {
splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks) splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks)
events := splitEventsBySingleWeek(splitEventsByWeekVal) events := splitEventsBySingleWeek(splitEventsByWeekVal)
semesterString := findFirstSpanWithClass(table, "header-0-2-0").FirstChild.Data semesterString := findFirstSpanWithClass(table, "header-0-2-0").FirstChild.Data
course := findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data
semester, year := extractSemesterAndYear(semesterString) semester, year := extractSemesterAndYear(semesterString)
events = convertWeeksToDates(events, semester, year) events = convertWeeksToDates(events, semester, year)
events = generateUUIDs(events) events = generateUUIDs(events, course)
events = splitEventType(events) events = splitEventType(events)
var seminarGroup = model.SeminarGroup{ var seminarGroup = model.SeminarGroup{
University: findFirstSpanWithClass(table, "header-1-0-0").FirstChild.Data, University: findFirstSpanWithClass(table, "header-1-0-0").FirstChild.Data,
Course: findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data, Course: course,
Events: events, Events: events,
} }
return seminarGroup return seminarGroup
} }
func generateUUIDs(events []model.Event) []model.Event { func generateUUIDs(events []model.Event, course string) []model.Event {
for i, event := range events { for i, event := range events {
// generate a hash value from the event name, course and semester // generate a hash value from the event name, course and semester
hash := uuid.NewSHA1(uuid.NameSpaceOID, []byte(event.Name+event.Course+event.Semester)) hash := uuid.NewSHA1(uuid.NameSpaceOID, []byte(event.Name+course))
events[i].UUID = hash.String() events[i].UUID = hash.String()
} }
return events return events

View File

@@ -208,3 +208,57 @@ func Test_splitEventType(t *testing.T) {
}) })
} }
} }
func Test_generateUUIDs(t *testing.T) {
type args struct {
events []model.Event
course string
}
tests := []struct {
name string
args args
want []model.Event
}{
{
name: "Test 1",
args: args{
events: []model.Event{
{
Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS",
},
},
course: "21BIB-2a",
},
want: []model.Event{
{
Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS",
UUID: "3720afdc-10c7-5b72-9489-cffb70cb0c13",
},
},
},
{
name: "Test 2",
args: args{
events: []model.Event{
{
Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS",
},
},
course: "21BIB-2b",
},
want: []model.Event{
{
Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS",
UUID: "81083480-bcf1-5452-af84-bb27d79282d8",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := generateUUIDs(tt.args.events, tt.args.course); !reflect.DeepEqual(got, tt.want) {
t.Errorf("generateUUIDs() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -16,8 +16,6 @@ import (
const expirationTime = 5 * time.Minute const expirationTime = 5 * time.Minute
func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error {
layout := "2006-01-02 15:04:05 -0700 MST"
var result string var result string
var responseWriter = c.Response().Writer var responseWriter = c.Response().Writer
feed, err := db.FindFeedByToken(token, app) feed, err := db.FindFeedByToken(token, app)
@@ -25,11 +23,11 @@ func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error {
return c.JSON(http.StatusNotFound, err) return c.JSON(http.StatusNotFound, err)
} }
created, _ := time.Parse(layout, feed.Created) created := feed.Created
var modules []model.FeedCollection var modules []model.FeedCollection
_ = json.Unmarshal([]byte(feed.Modules), &modules) _ = json.Unmarshal([]byte(feed.Modules), &modules)
if created.Add(time.Hour * 265).Before(time.Now()) { if created.Time().Add(time.Hour * 265).Before(time.Now()) {
newFeed, err := createFeedForToken(app, modules) newFeed, err := createFeedForToken(app, modules)
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, err) return c.JSON(http.StatusInternalServerError, err)

View File

@@ -0,0 +1,58 @@
package ical
import (
"encoding/json"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase"
"htwkalender/model"
)
//update ical feed json
//add uuid field
//remove module name field
func MigrateFeedJson(app *pocketbase.PocketBase) error {
records, err := app.Dao().FindRecordsByFilter("feeds", "1=1", "-created", 0, 0)
if err != nil {
return err
}
for _, feed := range records {
var modules []model.FeedCollection
err := json.Unmarshal([]byte(feed.GetString("modules")), &modules)
if err != nil {
return err
}
var uuidFeedCollections []model.FeedCollection
for _, module := range modules {
uuid := searchUUIDForModule(app, module)
if uuid != "" {
uuidFeedCollections = append(uuidFeedCollections, model.FeedCollection{UUID: uuid, Name: module.Name, Course: module.Course, UserDefinedName: module.UserDefinedName})
}
}
jsonModules, _ := json.Marshal(uuidFeedCollections)
feed.Set("modules", string(jsonModules))
err = app.Dao().SaveRecord(feed)
if err != nil {
return err
}
}
return nil
}
func searchUUIDForModule(app *pocketbase.PocketBase, module model.FeedCollection) string {
var event model.Event
err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Name = {:name} AND course = {:course}", dbx.Params{"name": module.Name, "course": module.Course})).One(&event)
if err != nil {
return ""
}
return event.UUID
}

View File

@@ -27,6 +27,7 @@ export async function fetchModulesByCourseAndSemester(
modulesResponse.forEach((module: Module) => modulesResponse.forEach((module: Module) =>
modules.push( modules.push(
new Module( new Module(
module.uuid,
module.name, module.name,
course, course,
module.name, module.name,
@@ -50,6 +51,7 @@ export async function fetchAllModules(): Promise<Module[]> {
responseModules.forEach((module: Module) => { responseModules.forEach((module: Module) => {
modules.push( modules.push(
new Module( new Module(
module.uuid,
module.name, module.name,
module.course, module.course,
module.name, module.name,

View File

@@ -16,6 +16,7 @@ export async function fetchModule(name: string): Promise<Module> {
.then( .then(
(module: Module) => (module: Module) =>
new Module( new Module(
module.uuid,
module.name, module.name,
module.course, module.course,
module.name, module.name,

View File

@@ -39,7 +39,7 @@ const ModuleInformation = defineAsyncComponent(
); );
async function showInfo(moduleName: string) { async function showInfo(moduleName: string) {
const module: Ref<Module> = ref(new Module("", "", "", "", "", [])); const module: Ref<Module> = ref(new Module("", "", "", "", "", "", []));
await fetchModule(moduleName).then((data) => { await fetchModule(moduleName).then((data) => {
module.value = data; module.value = data;
}); });

View File

@@ -37,7 +37,7 @@ const ModuleInformation = defineAsyncComponent(
); );
async function showInfo(moduleName: string) { async function showInfo(moduleName: string) {
const module: Ref<Module> = ref(new Module("", "", "", "", "", [])); const module: Ref<Module> = ref(new Module("", "", "", "", "", "", []));
await fetchModule(moduleName).then((data) => { await fetchModule(moduleName).then((data) => {
module.value = data; module.value = data;
}); });

View File

@@ -2,6 +2,7 @@ import { Event } from "./event";
export class Module { export class Module {
constructor( constructor(
public uuid: string,
public name: string, public name: string,
public course: string, public course: string,
public userDefinedName: string, public userDefinedName: string,