From ce47ef1270e1b99c945108adc96696d07acb9a10 Mon Sep 17 00:00:00 2001 From: ce72 Date: Tue, 28 Feb 2023 16:17:46 +0100 Subject: [PATCH] feat(caldav): Import Labels from caldav categories --- docs/content/doc/usage/caldav.md | 6 +-- pkg/caldav/parsing.go | 15 +++++--- pkg/models/label.go | 28 +++++++------- pkg/models/label_task.go | 4 +- pkg/models/label_test.go | 23 ++++++++++-- pkg/routes/caldav/listStorageProvider.go | 48 ++++++++++++++++++++++-- 6 files changed, 93 insertions(+), 31 deletions(-) diff --git a/docs/content/doc/usage/caldav.md b/docs/content/doc/usage/caldav.md index a593227ea..ab101975e 100644 --- a/docs/content/doc/usage/caldav.md +++ b/docs/content/doc/usage/caldav.md @@ -10,9 +10,9 @@ menu: # Caldav -> **Warning:** The caldav integration is in an early alpha stage and has bugs. +> **Warning:** The caldav integration is in an early alpha stage and has bugs. > It works well with some clients while having issues with others. -> If you encounter issues, please [report them](https://code.vikunja.io/api/issues/new?body=[caldav]) +> If you encounter issues, please [report them](https://code.vikunja.io/api/issues/new?body=[caldav]) Vikunja supports managing tasks via the [caldav VTODO](https://tools.ietf.org/html/rfc5545#section-3.6.2) extension. @@ -37,6 +37,7 @@ Vikunja currently supports the following properties: * `SUMMARY` * `DESCRIPTION` * `PRIORITY` +* `CATEGORIES` * `COMPLETED` * `DUE` * `DTSTART` @@ -50,7 +51,6 @@ Vikunja currently supports the following properties: Vikunja **currently does not** support these properties: * `ATTACH` -* `CATEGORIES` * `CLASS` * `COMMENT` * `GEO` diff --git a/pkg/caldav/parsing.go b/pkg/caldav/parsing.go index 6cf3b025d..26efee04f 100644 --- a/pkg/caldav/parsing.go +++ b/pkg/caldav/parsing.go @@ -96,12 +96,15 @@ func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) { description := strings.ReplaceAll(task["DESCRIPTION"], "\\,", ",") description = strings.ReplaceAll(description, "\\n", "\n") - categories := strings.Split(task["CATEGORIES"], ",") - labels := make([]*models.Label, 0, len(categories)) - for _, category := range categories { - labels = append(labels, &models.Label{ - Title: category, - }) + var labels []*models.Label + if val, ok := task["CATEGORIES"]; ok { + categories := strings.Split(val, ",") + labels = make([]*models.Label, 0, len(categories)) + for _, category := range categories { + labels = append(labels, &models.Label{ + Title: category, + }) + } } vTask = &models.Task{ diff --git a/pkg/models/label.go b/pkg/models/label.go index 49da1acca..4bb5f6def 100644 --- a/pkg/models/label.go +++ b/pkg/models/label.go @@ -176,15 +176,15 @@ func (l *Label) ReadAll(s *xorm.Session, a web.Auth, search string, page int, pe // @Failure 500 {object} models.Message "Internal error" // @Router /labels/{id} [get] func (l *Label) ReadOne(s *xorm.Session, a web.Auth) (err error) { - label, err := getLabelByIDSimple(s, l.ID) + label, err := getLabelByExampleSimple(s, l) if err != nil { - return err + return } *l = *label u, err := user.GetUserByID(s, l.CreatedByID) if err != nil { - return err + return } l.CreatedBy = u @@ -192,14 +192,16 @@ func (l *Label) ReadOne(s *xorm.Session, a web.Auth) (err error) { } func getLabelByIDSimple(s *xorm.Session, labelID int64) (*Label, error) { - label := Label{} - exists, err := s.ID(labelID).Get(&label) - if err != nil { - return &label, err - } - - if !exists { - return &Label{}, ErrLabelDoesNotExist{labelID} - } - return &label, err + return getLabelByExampleSimple(s, &Label{ID: labelID}) +} + +func getLabelByExampleSimple(s *xorm.Session, l *Label) (*Label, error) { + exists, err := s.Get(l) + if err != nil { + return l, err + } + if !exists { + return &Label{}, ErrLabelDoesNotExist{l.ID} + } + return l, err } diff --git a/pkg/models/label_task.go b/pkg/models/label_task.go index 132c210d7..0d67c0994 100644 --- a/pkg/models/label_task.go +++ b/pkg/models/label_task.go @@ -264,7 +264,7 @@ func getLabelsByTaskIDs(s *xorm.Session, opts *LabelByTaskIDsOptions) (ls []*lab } // Create or update a bunch of task labels -func (t *Task) updateTaskLabels(s *xorm.Session, creator web.Auth, labels []*Label) (err error) { +func (t *Task) UpdateTaskLabels(s *xorm.Session, creator web.Auth, labels []*Label) (err error) { // If we don't have any new labels, delete everything right away. Saves us some hassle. if len(labels) == 0 && len(t.Labels) > 0 { @@ -390,5 +390,5 @@ func (ltb *LabelTaskBulk) Create(s *xorm.Session, a web.Auth) (err error) { for _, l := range labels { task.Labels = append(task.Labels, &l.Label) } - return task.updateTaskLabels(s, a, ltb.Labels) + return task.UpdateTaskLabels(s, a, ltb.Labels) } diff --git a/pkg/models/label_test.go b/pkg/models/label_test.go index a88cedb7a..a39898628 100644 --- a/pkg/models/label_test.go +++ b/pkg/models/label_test.go @@ -198,6 +198,21 @@ func TestLabel_ReadOne(t *testing.T) { }, auth: &user.User{ID: 1}, }, + { + name: "Get label by Title", + fields: fields{ + Title: "Label #2", + }, + want: &Label{ + ID: 2, + Title: "Label #2", + CreatedByID: 1, + CreatedBy: user1, + Created: testCreatedTime, + Updated: testUpdatedTime, + }, + auth: &user.User{ID: 1}, + }, { name: "Get nonexistant label", fields: fields{ @@ -259,9 +274,11 @@ func TestLabel_ReadOne(t *testing.T) { s := db.NewSession() - allowed, _, _ := l.CanRead(s, tt.auth) - if !allowed && !tt.wantForbidden { - t.Errorf("Label.CanRead() forbidden, want %v", tt.wantForbidden) + if l.ID != 0 { + allowed, _, _ := l.CanRead(s, tt.auth) + if !allowed && !tt.wantForbidden { + t.Errorf("Label.CanRead() forbidden, want %v", tt.wantForbidden) + } } err := l.ReadOne(s, tt.auth) if (err != nil) != tt.wantErr { diff --git a/pkg/routes/caldav/listStorageProvider.go b/pkg/routes/caldav/listStorageProvider.go index fd902bf00..3c2ff5c70 100644 --- a/pkg/routes/caldav/listStorageProvider.go +++ b/pkg/routes/caldav/listStorageProvider.go @@ -273,8 +273,28 @@ func (vcls *VikunjaCaldavListStorage) CreateResource(rpath, content string) (*da return nil, errs.ForbiddenError } - // Find or create Labels by title - // Insert label_task + for _, label := range vTask.Labels { + // Find or create Labels by title + err = label.ReadOne(s, vcls.user) + if err != nil { + err = label.Create(s, vcls.user) + if err != nil { + _ = s.Rollback() + return nil, err + } + err = label.ReadOne(s, vcls.user) + if err != nil { + _ = s.Rollback() + return nil, err + } + } + } + // Insert LabelTask relation + err = vcls.task.UpdateTaskLabels(s, vcls.user, vTask.Labels) + if err != nil { + _ = s.Rollback() + return nil, err + } // Create the task err = vTask.Create(s, vcls.user) @@ -321,8 +341,28 @@ func (vcls *VikunjaCaldavListStorage) UpdateResource(rpath, content string) (*da return nil, errs.ForbiddenError } - // Find or create Labels by title - // Update label_task + for _, label := range vTask.Labels { + // Find or create Labels by title + err = label.ReadOne(s, vcls.user) + if err != nil { + err = label.Create(s, vcls.user) + if err != nil { + _ = s.Rollback() + return nil, err + } + err = label.ReadOne(s, vcls.user) + if err != nil { + _ = s.Rollback() + return nil, err + } + } + } + // Update LabelTask relation + err = vcls.task.UpdateTaskLabels(s, vcls.user, vTask.Labels) + if err != nil { + _ = s.Rollback() + return nil, err + } // Update the task err = vTask.Update(s, vcls.user)