From 9cf84646a1ac5662e45a1fac1355901dc13fcc50 Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 15 Mar 2024 11:27:31 +0100 Subject: [PATCH] feat(views)!: move done and default bucket setting to view --- pkg/migration/20240315104205.go | 158 ++++++++++++++++++++++++++++++++ pkg/models/kanban.go | 10 +- pkg/models/models.go | 2 + pkg/models/project.go | 4 +- pkg/models/project_view.go | 4 + pkg/models/tasks.go | 14 +-- 6 files changed, 177 insertions(+), 15 deletions(-) create mode 100644 pkg/migration/20240315104205.go diff --git a/pkg/migration/20240315104205.go b/pkg/migration/20240315104205.go new file mode 100644 index 000000000..6100af526 --- /dev/null +++ b/pkg/migration/20240315104205.go @@ -0,0 +1,158 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present 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 ( + "code.vikunja.io/api/pkg/config" + "src.techknowlogick.com/xormigrate" + "xorm.io/xorm" +) + +type projects20240315104205 struct { + ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"project"` + DefaultBucketID int64 `xorm:"bigint INDEX null" json:"default_bucket_id"` + DoneBucketID int64 `xorm:"bigint INDEX null" json:"done_bucket_id"` +} + +func (projects20240315104205) TableName() string { + return "projects" +} + +type projectView20240315104205 struct { + ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"project"` + ViewKind int `xorm:"not null" json:"view_kind"` + DefaultBucketID int64 `xorm:"bigint INDEX null" json:"default_bucket_id"` + DoneBucketID int64 `xorm:"bigint INDEX null" json:"done_bucket_id"` + ProjectID int64 `xorm:"not null index" json:"project_id" param:"project"` +} + +func (projectView20240315104205) TableName() string { + return "project_views" +} + +func init() { + migrations = append(migrations, &xormigrate.Migration{ + ID: "20240315104205", + Description: "Move done and default bucket id to views", + Migrate: func(tx *xorm.Engine) (err error) { + err = tx.Sync(projectView20240315104205{}) + if err != nil { + return + } + + projects := []*projects20240315104205{} + err = tx.Find(&projects) + if err != nil { + return + } + + views := []*projectView20240315104205{} + err = tx.Find(&views) + if err != nil { + return err + } + + viewMap := make(map[int64][]*projectView20240315104205) + for _, view := range views { + if _, has := viewMap[view.ProjectID]; !has { + viewMap[view.ProjectID] = []*projectView20240315104205{} + } + + viewMap[view.ProjectID] = append(viewMap[view.ProjectID], view) + } + + for _, project := range projects { + for _, view := range viewMap[project.ID] { + if view.ViewKind == 3 { // Kanban view + view.DefaultBucketID = project.DefaultBucketID + view.DoneBucketID = project.DoneBucketID + _, err = tx. + Where("id = ?", view.ID). + Cols("default_bucket_id", "done_bucket_id"). + Update(view) + if err != nil { + return + } + } + } + } + + if config.DatabaseType.GetString() == "sqlite" { + _, err = tx.Exec(` +create table projects_dg_tmp +( + id INTEGER not null + primary key autoincrement, + title TEXT not null, + description TEXT, + identifier TEXT, + hex_color TEXT, + owner_id INTEGER not null, + parent_project_id INTEGER, + is_archived INTEGER default 0 not null, + background_file_id INTEGER, + background_blur_hash TEXT, + position REAL, + created DATETIME not null, + updated DATETIME not null +); + +insert into projects_dg_tmp(id, title, description, identifier, hex_color, owner_id, parent_project_id, is_archived, + background_file_id, background_blur_hash, position, created, updated) +select id, + title, + description, + identifier, + hex_color, + owner_id, + parent_project_id, + is_archived, + background_file_id, + background_blur_hash, + position, + created, + updated +from projects; + +drop table projects; + +alter table projects_dg_tmp + rename to projects; + +create index IDX_projects_owner_id + on projects (owner_id); + +create index IDX_projects_parent_project_id + on projects (parent_project_id); + +create unique index UQE_projects_id + on projects (id); +`) + return err + } + + err = dropTableColum(tx, "projects", "done_bucket_id") + if err != nil { + return + } + return dropTableColum(tx, "projects", "default_bucket_id") + }, + Rollback: func(tx *xorm.Engine) error { + return nil + }, + }) +} diff --git a/pkg/models/kanban.go b/pkg/models/kanban.go index 9769d4904..aa3bd2b0f 100644 --- a/pkg/models/kanban.go +++ b/pkg/models/kanban.go @@ -82,14 +82,14 @@ func getBucketByID(s *xorm.Session, id int64) (b *Bucket, err error) { return } -func getDefaultBucketID(s *xorm.Session, project *Project) (bucketID int64, err error) { - if project.DefaultBucketID != 0 { - return project.DefaultBucketID, nil +func getDefaultBucketID(s *xorm.Session, view *ProjectView) (bucketID int64, err error) { + if view.DefaultBucketID != 0 { + return view.DefaultBucketID, nil } bucket := &Bucket{} _, err = s. - Where("project_id = ?", project.ID). + Where("project_view_id = ?", view.ID). OrderBy("position asc"). Get(bucket) if err != nil { @@ -369,7 +369,7 @@ func (b *Bucket) Delete(s *xorm.Session, a web.Auth) (err error) { } // Get the default bucket - p, err := GetProjectSimpleByID(s, b.ProjectID) + p, err := GetProjectViewByID(s, b.ProjectViewID, b.ProjectID) if err != nil { return } diff --git a/pkg/models/models.go b/pkg/models/models.go index 96d8b3b0f..a9d5d388d 100644 --- a/pkg/models/models.go +++ b/pkg/models/models.go @@ -63,6 +63,8 @@ func GetTables() []interface{} { &Webhook{}, &Reaction{}, &ProjectView{}, + &TaskPosition{}, + &TaskBucket{}, } } diff --git a/pkg/models/project.go b/pkg/models/project.go index 3cf13d600..1311b6eaa 100644 --- a/pkg/models/project.go +++ b/pkg/models/project.go @@ -52,9 +52,7 @@ type Project struct { ParentProjectID int64 `xorm:"bigint INDEX null" json:"parent_project_id"` ParentProject *Project `xorm:"-" json:"-"` - // The ID of the bucket where new tasks without a bucket are added to. By default, this is the leftmost bucket in a project. - DefaultBucketID int64 `xorm:"bigint INDEX null" json:"default_bucket_id"` - // If tasks are moved to the done bucket, they are marked as done. If they are marked as done individually, they are moved into the done bucket. + // Deprecated: If tasks are moved to the done bucket, they are marked as done. If they are marked as done individually, they are moved into the done bucket. DoneBucketID int64 `xorm:"bigint INDEX null" json:"done_bucket_id"` // The user who created this project. diff --git a/pkg/models/project_view.go b/pkg/models/project_view.go index f26a8df76..de9c90e37 100644 --- a/pkg/models/project_view.go +++ b/pkg/models/project_view.go @@ -133,6 +133,10 @@ type ProjectView struct { BucketConfigurationMode BucketConfigurationModeKind `xorm:"default 0" json:"bucket_configuration_mode"` // When the bucket configuration mode is not `manual`, this field holds the options of that configuration. BucketConfiguration []*ProjectViewBucketConfiguration `xorm:"json" json:"bucket_configuration"` + // The ID of the bucket where new tasks without a bucket are added to. By default, this is the leftmost bucket in a view. + DefaultBucketID int64 `xorm:"bigint INDEX null" json:"default_bucket_id"` + // If tasks are moved to the done bucket, they are marked as done. If they are marked as done individually, they are moved into the done bucket. + DoneBucketID int64 `xorm:"bigint INDEX null" json:"done_bucket_id"` // A timestamp when this view was updated. You cannot change this value. Updated time.Time `xorm:"updated not null" json:"updated"` diff --git a/pkg/models/tasks.go b/pkg/models/tasks.go index 48b5e1faf..04d22ccc5 100644 --- a/pkg/models/tasks.go +++ b/pkg/models/tasks.go @@ -648,10 +648,10 @@ func checkBucketLimit(s *xorm.Session, t *Task, bucket *Bucket) (err error) { } // Contains all the task logic to figure out what bucket to use for this task. -func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucketLimit bool, project *Project) (targetBucket *Bucket, err error) { +func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucketLimit bool, view *ProjectView) (targetBucket *Bucket, err error) { - if project == nil { - project, err = GetProjectSimpleByID(s, task.ProjectID) + if view == nil { + view, err = GetProjectViewByID(s, view.ID, task.ProjectID) if err != nil { return nil, err } @@ -660,7 +660,7 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke var bucket *Bucket if task.Done && originalTask != nil && (!originalTask.Done || task.ProjectID != originalTask.ProjectID) { - task.BucketID = project.DoneBucketID + task.BucketID = view.DoneBucketID } if task.BucketID == 0 && originalTask != nil && originalTask.BucketID != 0 { @@ -672,7 +672,7 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke // because then we have it already updated to the done bucket. if task.BucketID == 0 || (originalTask != nil && task.ProjectID != 0 && originalTask.ProjectID != task.ProjectID && !task.Done) { - task.BucketID, err = getDefaultBucketID(s, project) + task.BucketID, err = getDefaultBucketID(s, view) if err != nil { return } @@ -699,7 +699,7 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke } } - if bucket.ID == project.DoneBucketID && originalTask != nil && !originalTask.Done { + if bucket.ID == view.DoneBucketID && originalTask != nil && !originalTask.Done { task.Done = true } @@ -869,7 +869,7 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) { return err } - targetBucket, err := setTaskBucket(s, t, &ot, t.BucketID != 0 && t.BucketID != ot.BucketID, project) + targetBucket, err := setTaskBucket(s, t, &ot, t.BucketID != 0 && t.BucketID != ot.BucketID, nil) if err != nil { return err }