feat: move done bucket setting to project

This commit is contained in:
kolaente 2023-09-03 15:01:35 +02:00
parent 97b5cd306f
commit bbbb45d224
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
7 changed files with 137 additions and 49 deletions

View File

@ -18,7 +18,6 @@
title: testbucket3
project_id: 1
created_by_id: 1
is_done_bucket: 1
position: 3
created: 2020-04-18 21:13:52
updated: 2020-04-18 21:13:52
@ -26,7 +25,6 @@
title: testbucket4 - other project
project_id: 2
created_by_id: 1
is_done_bucket: 1
created: 2020-04-18 21:13:52
updated: 2020-04-18 21:13:52
# The following are not or only partly owned by user 1

View File

@ -5,6 +5,7 @@
identifier: test1
owner_id: 1
position: 3
done_bucket_id: 3
updated: 2018-12-02 15:13:12
created: 2018-12-01 15:13:12
-
@ -14,6 +15,7 @@
identifier: test2
owner_id: 3
position: 2
done_bucket_id: 4
updated: 2018-12-02 15:13:12
created: 2018-12-01 15:13:12
-

View File

@ -0,0 +1,118 @@
// 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 <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
type projects20230903143017 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 (projects20230903143017) TableName() string {
return "projects"
}
type bucket20230903143017 struct {
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"bucket"`
IsDoneBucket bool `xorm:"BOOL" json:"is_done_bucket"`
ProjectID int64 `xorm:"bigint not null" json:"project_id" param:"project"`
}
func (bucket20230903143017) TableName() string {
return "buckets"
}
const dropIsDoneBucketColSqlite20230903143017 = `
create table buckets_dg_tmp
(
id INTEGER not null
primary key autoincrement,
title TEXT not null,
project_id INTEGER not null,
"limit" INTEGER default 0,
position REAL,
created DATETIME not null,
updated DATETIME not null,
created_by_id INTEGER not null
);
insert into buckets_dg_tmp(id, title, project_id, "limit", position, created, updated, created_by_id)
select id,
title,
project_id,
"limit",
position,
created,
updated,
created_by_id
from buckets;
drop table buckets;
alter table buckets_dg_tmp
rename to buckets;
create unique index UQE_buckets_id
on buckets (id);
`
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20230903143017",
Description: "Move done bucket state to project + add default bucket setting",
Migrate: func(tx *xorm.Engine) (err error) {
err = tx.Sync2(projects20230903143017{})
if err != nil {
return
}
doneBuckets := []*bucket20230903143017{}
err = tx.Where("is_done_bucket = true").
Find(&doneBuckets)
if err != nil {
return
}
for _, bucket := range doneBuckets {
_, err = tx.Where("id = ?", bucket.ProjectID).
Cols("done_bucket_id").
Update(&projects20230903143017{
DoneBucketID: bucket.ID,
})
if err != nil {
return
}
}
if tx.Dialect().URI().DBType == schemas.SQLITE {
_, err = tx.Exec(dropIsDoneBucketColSqlite20230903143017)
return err
}
return dropTableColum(tx, "buckets", "is_done_bucket")
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -38,8 +38,6 @@ type Bucket struct {
// How many tasks can be at the same time on this board max
Limit int64 `xorm:"default 0" json:"limit" minimum:"0" valid:"range(0|9223372036854775807)"`
// If this bucket is the "done bucket". All tasks moved into this bucket will automatically marked as done. All tasks marked as done from elsewhere will be moved into this bucket.
IsDoneBucket bool `xorm:"BOOL" json:"is_done_bucket"`
// The number of tasks currently in this bucket
Count int64 `xorm:"-" json:"count"`
@ -92,7 +90,7 @@ func getDefaultBucket(s *xorm.Session, projectID int64) (bucket *Bucket, err err
func getDoneBucketForProject(s *xorm.Session, projectID int64) (bucket *Bucket, err error) {
bucket = &Bucket{}
exists, err := s.
Where("project_id = ? and is_done_bucket = ?", projectID, true).
Where("id = (select done_bucket_id from projects where id = ?)", projectID).
Get(bucket)
if err != nil {
return nil, err
@ -287,29 +285,11 @@ func (b *Bucket) Create(s *xorm.Session, a web.Auth) (err error) {
// @Failure 500 {object} models.Message "Internal error"
// @Router /projects/{projectID}/buckets/{bucketID} [post]
func (b *Bucket) Update(s *xorm.Session, _ web.Auth) (err error) {
doneBucket, err := getDoneBucketForProject(s, b.ProjectID)
if err != nil {
return err
}
if doneBucket != nil && doneBucket.IsDoneBucket && b.IsDoneBucket && doneBucket.ID != b.ID {
// When the current bucket will be the new done bucket, the old one should not be the done bucket anymore
doneBucket.IsDoneBucket = false
_, err = s.
Where("id = ?", doneBucket.ID).
Cols("is_done_bucket").
Update(doneBucket)
if err != nil {
return
}
}
_, err = s.
Where("id = ?", b.ID).
Cols(
"title",
"limit",
"is_done_bucket",
"position",
).
Update(b)

View File

@ -217,28 +217,4 @@ func TestBucket_Update(t *testing.T) {
testAndAssertBucketUpdate(t, b, s)
})
t.Run("old done bucket should be unset", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
defer s.Close()
b := &Bucket{
ID: 1,
ProjectID: 1,
IsDoneBucket: true,
}
err := b.Update(s, &user.User{ID: 1})
assert.NoError(t, err)
db.AssertExists(t, "buckets", map[string]interface{}{
"id": 1,
"project_id": 1,
"is_done_bucket": true,
}, false)
db.AssertExists(t, "buckets", map[string]interface{}{
"id": 3,
"project_id": 1,
"is_done_bucket": false,
}, false)
})
}

View File

@ -51,6 +51,11 @@ 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.
DoneBucketID int64 `xorm:"bigint INDEX null" json:"done_bucket_id"`
// The user who created this project.
Owner *user.User `xorm:"-" json:"owner" valid:"-"`

View File

@ -676,7 +676,12 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke
}
}
if bucket.IsDoneBucket && originalTask != nil && !originalTask.Done {
project, err := GetProjectSimpleByID(s, task.ProjectID)
if err != nil {
return nil, err
}
if bucket.ID == project.DoneBucketID && originalTask != nil && !originalTask.Done {
task.Done = true
}
@ -845,7 +850,11 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
// If the task was moved into the done bucket and the task has a repeating cycle we should not update
// the bucket.
if targetBucket.IsDoneBucket && t.RepeatAfter > 0 {
project, err := GetProjectSimpleByID(s, t.ProjectID)
if err != nil {
return err
}
if targetBucket.ID == project.DoneBucketID && t.RepeatAfter > 0 {
t.Done = true // This will trigger the correct re-scheduling of the task (happening in updateDone later)
t.BucketID = ot.BucketID
}