Merge branch '44-410-gone-is-any-better-than-404-not-found' into 'development'

Resolve "410 GONE is any better than 404 NOT FOUND"

See merge request htwk-software/htwkalender!57
This commit is contained in:
Elmar Kresse
2024-07-16 09:23:29 +00:00
22 changed files with 777 additions and 34 deletions

View File

@ -21,7 +21,7 @@ export async function getCalender(token: string): Promise<Module[]> {
if (import.meta.env.SSR) {
return [];
}
const request = new Request("/api/collections/feeds/records/" + token, {
const request = new Request("/api/feeds/records/" + token, {
method: "GET",
});

View File

@ -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 (

View File

@ -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
})
}

View File

@ -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)
})
}

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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)
}

View File

@ -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,
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
package model
import (

View File

@ -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
}

View File

@ -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 <https://www.gnu.org/licenses/>.
package model
type Module struct {

View File

@ -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 <https://www.gnu.org/licenses/>.
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

View File

@ -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 <https://www.gnu.org/licenses/>.
package grpc
import (

View File

@ -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 <https://www.gnu.org/licenses/>.
package grpc
import (

View File

@ -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 <https://www.gnu.org/licenses/>.
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
}

View File

@ -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 <https://www.gnu.org/licenses/>.
package grpc
import (

View File

@ -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 <https://www.gnu.org/licenses/>.
package connector
import (

View File

@ -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 <https://www.gnu.org/licenses/>.
package functions
import (

View File

@ -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 <https://www.gnu.org/licenses/>.
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

View File

@ -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 <https://www.gnu.org/licenses/>.
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")

View File

@ -12,6 +12,7 @@ message Feed {
string retrieved = 3;
string created = 4;
string updated = 5;
bool deleted = 6;
}
message GetFeedRequest {