+
+
{{ $t("additionalModules.subTitle") }}
-
+
+
+
+
diff --git a/services/common/genproto/modules/feeds.pb.go b/services/common/genproto/modules/feeds.pb.go
index 97aaa32..7dfdaf7 100644
--- a/services/common/genproto/modules/feeds.pb.go
+++ b/services/common/genproto/modules/feeds.pb.go
@@ -30,6 +30,7 @@ type Feed struct {
Retrieved string `protobuf:"bytes,3,opt,name=retrieved,proto3" json:"retrieved,omitempty"`
Created string `protobuf:"bytes,4,opt,name=created,proto3" json:"created,omitempty"`
Updated string `protobuf:"bytes,5,opt,name=updated,proto3" json:"updated,omitempty"`
+ Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"`
}
func (x *Feed) Reset() {
@@ -99,6 +100,13 @@ func (x *Feed) GetUpdated() string {
return ""
}
+func (x *Feed) GetDeleted() bool {
+ if x != nil {
+ return x.Deleted
+ }
+ return false
+}
+
type GetFeedRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -196,7 +204,7 @@ func (x *GetFeedResponse) GetFeed() *Feed {
var File_feeds_proto protoreflect.FileDescriptor
var file_feeds_proto_rawDesc = []byte{
- 0x0a, 0x0b, 0x66, 0x65, 0x65, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x01,
+ 0x0a, 0x0b, 0x66, 0x65, 0x65, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9c, 0x01,
0x0a, 0x04, 0x46, 0x65, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73,
@@ -205,18 +213,20 @@ var file_feeds_proto_rawDesc = []byte{
0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61,
0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74,
- 0x65, 0x64, 0x22, 0x20, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x04, 0x66, 0x65,
- 0x65, 0x64, 0x32, 0x3d, 0x0a, 0x0b, 0x46, 0x65, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
- 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x12, 0x0f, 0x2e, 0x47,
- 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e,
- 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
- 0x00, 0x42, 0x1c, 0x5a, 0x1a, 0x68, 0x74, 0x77, 0x6b, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x65, 0x72,
- 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x62,
- 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x20, 0x0a, 0x0e,
+ 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e,
+ 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c,
+ 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x19, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x05, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x52, 0x04, 0x66, 0x65, 0x65, 0x64, 0x32, 0x3d, 0x0a, 0x0b,
+ 0x46, 0x65, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x47,
+ 0x65, 0x74, 0x46, 0x65, 0x65, 0x64, 0x12, 0x0f, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65, 0x64,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x65, 0x65,
+ 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1c, 0x5a, 0x1a, 0x68,
+ 0x74, 0x77, 0x6b, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
+ 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
}
var (
diff --git a/services/data-manager/migrations/1720871249_collections_snapshot.go b/services/data-manager/migrations/1720871249_collections_snapshot.go
new file mode 100644
index 0000000..4075f65
--- /dev/null
+++ b/services/data-manager/migrations/1720871249_collections_snapshot.go
@@ -0,0 +1,461 @@
+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": "2024-07-13 11:37:49.151Z",
+ "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": true,
+ "presentable": false,
+ "unique": false,
+ "options": {
+ "min": 2,
+ "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": ""
+ }
+ },
+ {
+ "system": false,
+ "id": "bdhcrksy",
+ "name": "semester",
+ "type": "text",
+ "required": true,
+ "presentable": false,
+ "unique": false,
+ "options": {
+ "min": 2,
+ "max": 2,
+ "pattern": "ws|ss"
+ }
+ }
+ ],
+ "indexes": [
+ "CREATE UNIQUE INDEX ` + "`" + `idx_rcaN2Oq` + "`" + ` ON ` + "`" + `groups` + "`" + ` (\n ` + "`" + `course` + "`" + `,\n ` + "`" + `semester` + "`" + `\n)"
+ ],
+ "listRule": null,
+ "viewRule": null,
+ "createRule": null,
+ "updateRule": null,
+ "deleteRule": null,
+ "options": {}
+ },
+ {
+ "id": "d65h4wh7zk13gxp",
+ "created": "2023-09-19 17:31:15.957Z",
+ "updated": "2024-07-13 11:37:49.145Z",
+ "name": "feeds",
+ "type": "base",
+ "system": false,
+ "schema": [
+ {
+ "system": false,
+ "id": "cowxjfmc",
+ "name": "modules",
+ "type": "json",
+ "required": true,
+ "presentable": false,
+ "unique": false,
+ "options": {
+ "maxSize": 2000000
+ }
+ },
+ {
+ "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": "2024-07-13 11:37:49.145Z",
+ "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": "2024-07-13 11:37:48.913Z",
+ "updated": "2024-07-13 11:37:49.145Z",
+ "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": {
+ "mimeTypes": [
+ "image/jpeg",
+ "image/png",
+ "image/svg+xml",
+ "image/gif",
+ "image/webp"
+ ],
+ "thumbs": null,
+ "maxSelect": 1,
+ "maxSize": 5242880,
+ "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,
+ "onlyVerified": false,
+ "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/services/data-manager/migrations/1720871405_updated_feeds.go b/services/data-manager/migrations/1720871405_updated_feeds.go
new file mode 100644
index 0000000..1a9e561
--- /dev/null
+++ b/services/data-manager/migrations/1720871405_updated_feeds.go
@@ -0,0 +1,51 @@
+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_deleted := &schema.SchemaField{}
+ if err := json.Unmarshal([]byte(`{
+ "system": false,
+ "id": "5d7vjjgo",
+ "name": "deleted",
+ "type": "bool",
+ "required": false,
+ "presentable": false,
+ "unique": false,
+ "options": {}
+ }`), new_deleted); err != nil {
+ return err
+ }
+ collection.Schema.AddField(new_deleted)
+
+ 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("5d7vjjgo")
+
+ return dao.SaveCollection(collection)
+ })
+}
diff --git a/services/data-manager/model/feedModel.go b/services/data-manager/model/feedModel.go
index 1306ab1..106d38e 100644
--- a/services/data-manager/model/feedModel.go
+++ b/services/data-manager/model/feedModel.go
@@ -24,9 +24,14 @@ import (
type Feed struct {
Modules string `db:"modules" json:"modules"`
Retrieved types.DateTime `db:"retrieved" json:"retrieved"`
+ Deleted bool `db:"deleted" json:"deleted"`
models.BaseModel
}
+func (f *Feed) TableName() string {
+ return "feeds"
+}
+
// SetModules set modules field
func (f *Feed) SetModules(modules string) {
f.Modules = modules
diff --git a/services/data-manager/service/addCalDavRoutes.go b/services/data-manager/service/addCalDavRoutes.go
index f487031..18271f2 100644
--- a/services/data-manager/service/addCalDavRoutes.go
+++ b/services/data-manager/service/addCalDavRoutes.go
@@ -21,7 +21,7 @@ import (
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
- "htwkalender/data-manager/service/db"
+ "htwkalender/data-manager/service/feed"
"htwkalender/data-manager/service/ical"
"io"
"log/slog"
@@ -58,7 +58,7 @@ func addFeedRoutes(app *pocketbase.PocketBase) {
Path: "/api/feed",
Handler: func(c echo.Context) error {
token := c.QueryParam("token")
- err := db.DeleteFeed(app.Dao(), token)
+ err := feed.MarkFeedForDeletion(app.Dao(), token)
if err != nil {
return c.JSON(http.StatusNotFound, err)
} else {
diff --git a/services/data-manager/service/db/dbFeeds.go b/services/data-manager/service/db/dbFeeds.go
index 2ae46e1..3def9b0 100644
--- a/services/data-manager/service/db/dbFeeds.go
+++ b/services/data-manager/service/db/dbFeeds.go
@@ -48,11 +48,13 @@ func FindFeedByToken(app *pocketbase.PocketBase, token string) (*model.Feed, err
var feed model.Feed
feed.Modules = record.GetString("modules")
feed.Retrieved = record.GetDateTime("retrieved")
+ feed.Deleted = record.GetBool("deleted")
- //update retrieved time
- record.Set("retrieved", time.Now())
-
- err = app.Dao().SaveRecord(record)
+ //update retrieved time if the is not marked as deleted
+ if !record.GetBool("deleted") {
+ record.Set("retrieved", time.Now())
+ err = app.Dao().SaveRecord(record)
+ }
return &feed, err
}
@@ -84,3 +86,22 @@ func GetAllFeeds(db *daos.Dao) ([]model.Feed, error) {
}
return feeds, nil
}
+
+func MarkForDelete(db *daos.Dao, token string) error {
+ // get record from db
+ feed := model.Feed{}
+ err := db.DB().Select("*").From("feeds").Where(dbx.NewExp("id = {:id}", dbx.Params{"id": token})).One(&feed)
+ if err != nil {
+ return err
+ }
+ // set delete flag
+ feed.Deleted = true
+ feed.Modules = "[\n {\n \"uuid\": \"\",\n \"name\": \"Deleted\",\n \"course\": \"\",\n \"userDefinedName\": \"Deleted\",\n \"reminder\": false\n }\n]"
+
+ // save record
+ err = db.Save(&feed)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/services/data-manager/service/feed/feedFunctions.go b/services/data-manager/service/feed/feedFunctions.go
index 6c3da36..6c16c7e 100644
--- a/services/data-manager/service/feed/feedFunctions.go
+++ b/services/data-manager/service/feed/feedFunctions.go
@@ -17,8 +17,6 @@
package feed
import (
- "database/sql"
- "github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
"htwkalender/data-manager/model"
database "htwkalender/data-manager/service/db"
@@ -41,13 +39,9 @@ func ClearFeeds(db *daos.Dao, months int, clock localTime.Clock) {
if feedRetrievedTime.Before(timeShift) {
// delete feed
- var sqlResult sql.Result
- sqlResult, err = db.DB().Delete("feeds", dbx.NewExp("id = {:id}", dbx.Params{"id": feed.GetId()})).Execute()
- if err != nil {
- slog.Error("CleanFeeds: delete feed "+feed.GetId()+" failed", "error", err)
- slog.Error("SQL Result: ", "error", sqlResult)
- } else {
- slog.Info("CleanFeeds: delete feed " + feed.GetId() + " successful")
+ feedErr := database.DeleteFeed(db, feed.GetId())
+ if feedErr != nil {
+ slog.Error("CleanFeeds: failed to delete feed: "+feed.GetId(), "error", feedErr)
}
}
}
@@ -124,3 +118,7 @@ func combineRooms(events model.Events, index1 int, combinedEvents model.Events,
}
return combinedEvents[index2].Rooms
}
+
+func MarkFeedForDeletion(db *daos.Dao, feedId string) error {
+ return database.MarkForDelete(db, feedId)
+}
diff --git a/services/data-manager/service/grpc/mapper.go b/services/data-manager/service/grpc/mapper.go
index ee3ea58..4981044 100644
--- a/services/data-manager/service/grpc/mapper.go
+++ b/services/data-manager/service/grpc/mapper.go
@@ -39,5 +39,6 @@ func feedToProto(feed *model.Feed) *pb.Feed {
Updated: feed.Updated.String(),
Retrieved: feed.Retrieved.String(),
Modules: feed.Modules,
+ Deleted: feed.Deleted,
}
}
diff --git a/services/ical/model/appModel.go b/services/ical/model/appModel.go
index 2238b09..40f481d 100644
--- a/services/ical/model/appModel.go
+++ b/services/ical/model/appModel.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package model
import (
diff --git a/services/ical/model/icalModel.go b/services/ical/model/icalModel.go
index 7ff9263..14121fd 100644
--- a/services/ical/model/icalModel.go
+++ b/services/ical/model/icalModel.go
@@ -61,6 +61,7 @@ type FeedModule struct {
type FeedRecord struct {
Modules []FeedModule `db:"modules" json:"modules"`
Retrieved JSONTime `db:"retrieved" json:"retrieved"`
+ Deleted bool `db:"deleted" json:"deleted"`
BaseModel
}
diff --git a/services/ical/model/moduleModel.go b/services/ical/model/moduleModel.go
index eddb839..558801f 100644
--- a/services/ical/model/moduleModel.go
+++ b/services/ical/model/moduleModel.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package model
type Module struct {
diff --git a/services/ical/service/connector/feedConnector.go b/services/ical/service/connector/feedConnector.go
index e545791..9ff12f4 100644
--- a/services/ical/service/connector/feedConnector.go
+++ b/services/ical/service/connector/feedConnector.go
@@ -1,8 +1,25 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package connector
import (
"encoding/json"
"errors"
+ "fmt"
"htwkalender/ical/model"
"log/slog"
)
@@ -13,9 +30,9 @@ func GetFeedByToken(host string, token string) (model.FeedRecord, error) {
// /api/collections/feeds/records/{id}
response, err := RequestApi(host, "/api/collections/feeds/records/"+token)
- if err != nil {
+ if err != nil || response.StatusCode() != 200 {
slog.Error("Failed to get feed record", "error", err)
- return model.FeedRecord{}, err
+ return model.FeedRecord{}, fmt.Errorf("failed to get feed record")
}
// parse the response body json to FeedRecord struct
diff --git a/services/ical/service/connector/grpc/client.go b/services/ical/service/connector/grpc/client.go
index f9c7275..066d62b 100644
--- a/services/ical/service/connector/grpc/client.go
+++ b/services/ical/service/connector/grpc/client.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package grpc
import (
diff --git a/services/ical/service/connector/grpc/events.go b/services/ical/service/connector/grpc/events.go
index fc82755..bcb6b1b 100644
--- a/services/ical/service/connector/grpc/events.go
+++ b/services/ical/service/connector/grpc/events.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package grpc
import (
diff --git a/services/ical/service/connector/grpc/feeds.go b/services/ical/service/connector/grpc/feeds.go
index 0f1f082..a8a16f6 100644
--- a/services/ical/service/connector/grpc/feeds.go
+++ b/services/ical/service/connector/grpc/feeds.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package grpc
import (
@@ -48,5 +64,6 @@ func protoToFeed(feed *pb.Feed) (model.FeedRecord, error) {
},
Retrieved: model.ToJSONTime(feed.Retrieved),
Modules: modules,
+ Deleted: feed.Deleted,
}, nil
}
diff --git a/services/ical/service/connector/grpc/modules.go b/services/ical/service/connector/grpc/modules.go
index aa47d79..d1bb195 100644
--- a/services/ical/service/connector/grpc/modules.go
+++ b/services/ical/service/connector/grpc/modules.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package grpc
import (
diff --git a/services/ical/service/connector/restHandler.go b/services/ical/service/connector/restHandler.go
index 4af7ba0..9cc58a8 100644
--- a/services/ical/service/connector/restHandler.go
+++ b/services/ical/service/connector/restHandler.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package connector
import (
diff --git a/services/ical/service/functions/semester_test.go b/services/ical/service/functions/semester_test.go
index 9595ede..6200a75 100644
--- a/services/ical/service/functions/semester_test.go
+++ b/services/ical/service/functions/semester_test.go
@@ -1,3 +1,19 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package functions
import (
diff --git a/services/ical/service/ical/ical.go b/services/ical/service/ical/ical.go
index baa6160..7582fa6 100644
--- a/services/ical/service/ical/ical.go
+++ b/services/ical/service/ical/ical.go
@@ -1,7 +1,24 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package ical
import (
"bytes"
+ "fmt"
"github.com/jordic/goics"
"htwkalender/ical/model"
"htwkalender/ical/service/connector"
@@ -12,6 +29,8 @@ import (
const expirationTime = 5 * time.Minute
+var FeedDeletedError = fmt.Errorf("feed deleted")
+
func Feed(app model.AppType, token string) (string, error) {
// get feed by token
feed, err := htwkalenderGrpc.GetFeed(token, app.GrpcClient)
@@ -19,6 +38,10 @@ func Feed(app model.AppType, token string) (string, error) {
return "", err
}
+ if feed.Deleted {
+ return "", FeedDeletedError
+ }
+
var events model.Events
// Get all events for modules
diff --git a/services/ical/service/routes.go b/services/ical/service/routes.go
index 3aa0381..c92a0f7 100644
--- a/services/ical/service/routes.go
+++ b/services/ical/service/routes.go
@@ -1,7 +1,24 @@
+//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
+//Copyright (C) 2024 HTWKalender support@htwkalender.de
+
+//This program is free software: you can redistribute it and/or modify
+//it under the terms of the GNU Affero General Public License as published by
+//the Free Software Foundation, either version 3 of the License, or
+//(at your option) any later version.
+
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU Affero General Public License for more details.
+
+//You should have received a copy of the GNU Affero General Public License
+//along with this program. If not, see
.
+
package service
import (
"encoding/json"
+ "errors"
"github.com/gofiber/fiber/v3"
"htwkalender/ical/model"
"htwkalender/ical/service/ical"
@@ -19,9 +36,13 @@ func AddFeedRoutes(app model.AppType) {
token := c.Query("token")
results, err := ical.Feed(app, token)
+ if errors.Is(err, ical.FeedDeletedError) {
+ return c.SendStatus(fiber.StatusGone)
+ }
+
if err != nil {
slog.Error("Failed to get feed", "error", err, "token", token)
- return c.SendStatus(fiber.StatusBadRequest)
+ return c.SendStatus(fiber.StatusNotFound)
}
c.Response().Header.Set("Content-type", "text/calendar")
c.Response().Header.Set("charset", "utf-8")
@@ -53,13 +74,17 @@ func AddFeedRoutes(app model.AppType) {
})
// Define a route for the GET method on the root path '/'
- app.Fiber.Get("/api/collections/feeds/records/:token", func(c fiber.Ctx) error {
+ app.Fiber.Get("/api/feeds/records/:token", func(c fiber.Ctx) error {
token := c.Params("token")
results, err := ical.FeedRecord(app, token)
+ if results.Deleted {
+ return c.SendStatus(fiber.StatusNotFound)
+ }
+
if err != nil {
- slog.Error("Failed to get feed", "error", err, "token", token)
+ slog.Error("Failed to get feed record", "error", err, "token", token)
return c.SendStatus(fiber.StatusBadRequest)
}
c.Response().Header.Set("Content-type", "application/json; charset=UTF-8")
diff --git a/services/protobuf/feeds.proto b/services/protobuf/feeds.proto
index 7580cbd..243b83a 100644
--- a/services/protobuf/feeds.proto
+++ b/services/protobuf/feeds.proto
@@ -12,6 +12,7 @@ message Feed {
string retrieved = 3;
string created = 4;
string updated = 5;
+ bool deleted = 6;
}
message GetFeedRequest {