diff --git a/pkg/migration/20210709211508.go b/pkg/migration/20210709211508.go
new file mode 100644
index 000000000..cf1a0d27d
--- /dev/null
+++ b/pkg/migration/20210709211508.go
@@ -0,0 +1,45 @@
+// Vikunja is a to-do list application to facilitate your life.
+// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public Licensee 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 Licensee for more details.
+//
+// You should have received a copy of the GNU Affero General Public Licensee
+// along with this program. If not, see .
+
+package migration
+
+import (
+ "src.techknowlogick.com/xormigrate"
+ "xorm.io/xorm"
+)
+
+type taskfavorites20210709211508 struct {
+ EntityID int64 `xorm:"bigint not null pk"`
+ UserID int64 `xorm:"bigint not null pk"`
+ Kind int `xorm:"int not null"`
+}
+
+func (taskfavorites20210709211508) TableName() string {
+ return "favorites"
+}
+
+func init() {
+ migrations = append(migrations, &xormigrate.Migration{
+ ID: "20210709211508",
+ Description: "",
+ Migrate: func(tx *xorm.Engine) error {
+ return tx.Sync2(taskfavorites20210709211508{})
+ },
+ Rollback: func(tx *xorm.Engine) error {
+ return nil
+ },
+ })
+}
diff --git a/pkg/models/favorites.go b/pkg/models/favorites.go
new file mode 100644
index 000000000..3d12ca787
--- /dev/null
+++ b/pkg/models/favorites.go
@@ -0,0 +1,83 @@
+// Vikunja is a to-do list application to facilitate your life.
+// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public Licensee 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 Licensee for more details.
+//
+// You should have received a copy of the GNU Affero General Public Licensee
+// along with this program. If not, see .
+
+package models
+
+import (
+ "code.vikunja.io/api/pkg/user"
+ "code.vikunja.io/web"
+ "xorm.io/xorm"
+)
+
+type FavoriteKind int
+
+const (
+ FavoriteKindUnknown FavoriteKind = iota
+ FavoriteKindTask = 1
+ FavoriteKindList = 2
+)
+
+type Favorite struct {
+ EntityID int64 `xorm:"bigint not null pk"`
+ UserID int64 `xorm:"bigint not null pk"`
+ Kind FavoriteKind `xorm:"int not null"`
+}
+
+func (t *Favorite) TableName() string {
+ return "favorites"
+}
+
+func addToFavorites(s *xorm.Session, entityID int64, a web.Auth, kind FavoriteKind) error {
+ u, err := user.GetFromAuth(a)
+ if err != nil {
+ // Only error GetFromAuth is if it's a link share and we want to ignore that
+ return nil
+ }
+
+ fav := &Favorite{
+ EntityID: entityID,
+ UserID: u.ID,
+ Kind: kind,
+ }
+
+ _, err = s.Insert(fav)
+ return err
+}
+
+func removeFromFavorite(s *xorm.Session, entityID int64, a web.Auth, kind FavoriteKind) error {
+ u, err := user.GetFromAuth(a)
+ if err != nil {
+ // Only error GetFromAuth is if it's a link share and we want to ignore that
+ return nil
+ }
+
+ _, err = s.
+ Where("task_id = ? AND user_id = ? AND kind = ?", entityID, u.ID, kind).
+ Delete(&Favorite{})
+ return err
+}
+
+func isFavorite(s *xorm.Session, entityID int64, a web.Auth, kind FavoriteKind) (is bool, err error) {
+ u, err := user.GetFromAuth(a)
+ if err != nil {
+ // Only error GetFromAuth is if it's a link share and we want to ignore that
+ return
+ }
+
+ return s.
+ Where("task_id = ? AND user_id = ? AND kind = ?", entityID, u.ID, kind).
+ Exist(&Favorite{})
+}
diff --git a/pkg/models/tasks.go b/pkg/models/tasks.go
index b016b982d..86e4a41bf 100644
--- a/pkg/models/tasks.go
+++ b/pkg/models/tasks.go
@@ -874,6 +874,12 @@ func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err
t.setIdentifier(l)
+ if t.IsFavorite {
+ if err := addToFavorites(s, t.ID, createdBy, FavoriteKindTask); err != nil {
+ return err
+ }
+ }
+
err = events.Dispatch(&TaskCreatedEvent{
Task: t,
Doer: createdBy,
@@ -950,7 +956,6 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
"list_id",
"bucket_id",
"position",
- "is_favorite",
"repeat_mode",
}
@@ -974,6 +979,19 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
colsToUpdate = append(colsToUpdate, "index")
}
+ wasFavorite, err := isFavorite(s, t.ID, a, FavoriteKindTask)
+ if t.IsFavorite && !wasFavorite {
+ if err := addToFavorites(s, t.ID, a, FavoriteKindTask); err != nil {
+ return err
+ }
+ }
+
+ if !t.IsFavorite && wasFavorite {
+ if err := removeFromFavorite(s, t.ID, a, FavoriteKindTask); err != nil {
+ return err
+ }
+ }
+
// Update the labels
//
// Maybe FIXME: