diff --git a/backend/migrations/1700512738_updated_feeds.go b/backend/migrations/1700512738_updated_feeds.go new file mode 100644 index 0000000..61ea0bc --- /dev/null +++ b/backend/migrations/1700512738_updated_feeds.go @@ -0,0 +1,52 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models/schema" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db) + + collection, err := dao.FindCollectionByNameOrId("d65h4wh7zk13gxp") + if err != nil { + return err + } + + // add + new_retrieved := &schema.SchemaField{} + json.Unmarshal([]byte(`{ + "system": false, + "id": "wmmney8x", + "name": "retrieved", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }`), new_retrieved) + collection.Schema.AddField(new_retrieved) + + return dao.SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db) + + collection, err := dao.FindCollectionByNameOrId("d65h4wh7zk13gxp") + if err != nil { + return err + } + + // remove + collection.Schema.RemoveField("wmmney8x") + + return dao.SaveCollection(collection) + }) +} diff --git a/backend/migrations/1700512916_collections_snapshot.go b/backend/migrations/1700512916_collections_snapshot.go new file mode 100644 index 0000000..848483c --- /dev/null +++ b/backend/migrations/1700512916_collections_snapshot.go @@ -0,0 +1,444 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + jsonData := `[ + { + "id": "cfq9mqlmd97v8z5", + "created": "2023-09-19 17:31:15.957Z", + "updated": "2023-11-01 21:17:43.567Z", + "name": "groups", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "85msl21p", + "name": "university", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "2sii4dtp", + "name": "shortcut", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "uiwgo28f", + "name": "groupId", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "y0l1lrzs", + "name": "course", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "kr62mhbz", + "name": "faculty", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "ya6znpez", + "name": "facultyId", + "type": "text", + "required": false, + "presentable": false, + "unique": 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", + "created": "2023-09-19 17:31:15.957Z", + "updated": "2023-11-20 20:38:58.258Z", + "name": "feeds", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "cowxjfmc", + "name": "modules", + "type": "json", + "required": true, + "presentable": false, + "unique": false, + "options": {} + }, + { + "system": false, + "id": "wmmney8x", + "name": "retrieved", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + } + ], + "indexes": [], + "listRule": null, + "viewRule": "", + "createRule": null, + "updateRule": "", + "deleteRule": null, + "options": {} + }, + { + "id": "7her4515qsmrxe8", + "created": "2023-09-19 17:31:15.958Z", + "updated": "2023-11-01 21:17:43.567Z", + "name": "events", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "m8ne8e3m", + "name": "Day", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "xnsxqp7j", + "name": "Week", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "aeuskrjo", + "name": "Name", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "klrzqyw0", + "name": "EventType", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "5zltexoy", + "name": "Prof", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "gy3nvfmx", + "name": "Rooms", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "hn7b8dfy", + "name": "Notes", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "axskpwm8", + "name": "BookedAt", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "vyyefxp7", + "name": "course", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "vlbpm9fz", + "name": "semester", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "0kahthzr", + "name": "uuid", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "6hkjwgb4", + "name": "start", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }, + { + "system": false, + "id": "szbefpjf", + "name": "end", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }, + { + "system": false, + "id": "nlnnxu7x", + "name": "Compulsory", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + } + ], + "indexes": [ + "CREATE INDEX ` + "`" + `idx_4vOTAiC` + "`" + ` ON ` + "`" + `events` + "`" + ` (\n ` + "`" + `Name` + "`" + `,\n ` + "`" + `course` + "`" + `,\n ` + "`" + `start` + "`" + `,\n ` + "`" + `end` + "`" + `,\n ` + "`" + `semester` + "`" + `,\n ` + "`" + `EventType` + "`" + `,\n ` + "`" + `Compulsory` + "`" + `\n)" + ], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }, + { + "id": "_pb_users_auth_", + "created": "2023-11-01 21:17:43.390Z", + "updated": "2023-11-01 21:17:43.567Z", + "name": "users", + "type": "auth", + "system": false, + "schema": [ + { + "system": false, + "id": "users_name", + "name": "name", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "users_avatar", + "name": "avatar", + "type": "file", + "required": false, + "presentable": false, + "unique": 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 + } + } + ]` + + collections := []*models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collections); err != nil { + return err + } + + return daos.New(db).ImportCollections(collections, true, nil) + }, func(db dbx.Builder) error { + return nil + }) +} diff --git a/backend/model/feedModel.go b/backend/model/feedModel.go index e3920a2..516ae8a 100644 --- a/backend/model/feedModel.go +++ b/backend/model/feedModel.go @@ -1,9 +1,13 @@ package model -import "github.com/pocketbase/pocketbase/models" +import ( + "github.com/pocketbase/pocketbase/models" + "time" +) type Feed struct { - Modules string `db:"modules" json:"modules"` + Modules string `db:"modules" json:"modules"` + Retrieved time.Time `db:"retrieved" json:"retrieved"` models.BaseModel } diff --git a/backend/service/addSchedule.go b/backend/service/addSchedule.go index 4cf41bc..280cb32 100644 --- a/backend/service/addSchedule.go +++ b/backend/service/addSchedule.go @@ -4,8 +4,10 @@ import ( "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/tools/cron" + "htwkalender/service/db" "htwkalender/service/events" "log" + "time" ) func AddSchedules(app *pocketbase.PocketBase) { @@ -17,9 +19,7 @@ func AddSchedules(app *pocketbase.PocketBase) { // Every three hours update all courses (5 segments - minute, hour, day, month, weekday) "0 */3 * * *" // Every 10 minutes update all courses (5 segments - minute, hour, day, month, weekday) "*/10 * * * *" scheduler.MustAdd("updateCourse", "0 */3 * * *", func() { - courses := events.GetAllCourses(app) - for _, course := range courses { err := events.UpdateModulesForCourse(app, course) if err != nil { @@ -29,11 +29,29 @@ func AddSchedules(app *pocketbase.PocketBase) { log.Println("Update Course: " + course + " successful") } } - }) + // Every sunday at 3am clean all courses (5 segments - minute, hour, day, month, weekday) "0 3 * * 0" + scheduler.MustAdd("cleanFeeds", "0 3 * * 0", func() { + feeds, err := db.GetAllFeeds(app) + if err != nil { + log.Println("CleanFeeds: get all feeds failed") + return + } + for _, feed := range feeds { + // if retrieved time is older than a half year delete feed + if feed.GetTime("retrieved").Before(time.Now().AddDate(0, -6, 0)) { + err = app.Dao().DeleteRecord(feed) + if err != nil { + log.Println("CleanFeeds: delete feed " + feed.GetId() + " failed") + log.Println(err) + } else { + log.Println("CleanFeeds: delete feed " + feed.GetId() + " successful") + } + } + } + }) scheduler.Start() - return nil }) diff --git a/backend/service/db/dbFeeds.go b/backend/service/db/dbFeeds.go index b8109a3..f2f0804 100644 --- a/backend/service/db/dbFeeds.go +++ b/backend/service/db/dbFeeds.go @@ -1,10 +1,10 @@ package db import ( - "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/models" "htwkalender/model" + "time" ) func SaveFeed(feed model.Feed, collection *models.Collection, app *pocketbase.PocketBase) (*models.Record, error) { @@ -19,10 +19,29 @@ func SaveFeed(feed model.Feed, collection *models.Collection, app *pocketbase.Po } func FindFeedByToken(token string, app *pocketbase.PocketBase) (*model.Feed, error) { - var feed model.Feed - err := app.Dao().DB().Select("*").From("feeds").Where(dbx.NewExp("id = {:id}", dbx.Params{"id": token})).One(&feed) + + record, err := app.Dao().FindRecordById("feeds", token) + if err != nil { return nil, err } + + var feed model.Feed + feed.Modules = record.GetString("modules") + feed.Retrieved = record.GetTime("retrieved") + + //update retrieved time + record.Set("retrieved", time.Now()) + + err = app.Dao().SaveRecord(record) + return &feed, err } + +func GetAllFeeds(app *pocketbase.PocketBase) ([]*models.Record, error) { + feeds, err := app.Dao().FindRecordsByFilter("feeds", "", "", 0, 0) + if err != nil { + return nil, err + } + return feeds, nil +}