150 lines
3.9 KiB
Go
150 lines
3.9 KiB
Go
// Vikunja is a to-do list application to facilitate your life.
|
|
// Copyright 2018-2020 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 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 General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package models
|
|
|
|
import (
|
|
"code.vikunja.io/web"
|
|
)
|
|
|
|
// ListDuplicate holds everything needed to duplicate a list
|
|
type ListDuplicate struct {
|
|
// The list id of the list to duplicate
|
|
ListID int64 `json:"list_id"`
|
|
// The target namespace
|
|
NamespaceID int64 `json:"namespace_id"`
|
|
|
|
List *List `json:"-"`
|
|
|
|
web.Rights `json:"-"`
|
|
web.CRUDable `json:"-"`
|
|
}
|
|
|
|
// CanCreate checks if a user has the right to duplicate a list
|
|
func (ld *ListDuplicate) CanCreate(a web.Auth) (canCreate bool, err error) {
|
|
// List Exists + user has read access to list
|
|
ld.List = &List{ID: ld.ListID}
|
|
canRead, err := ld.List.CanRead(a)
|
|
if err != nil || !canRead {
|
|
return canRead, err
|
|
}
|
|
|
|
// Namespace exists + user has write access to is (-> can create new lists)
|
|
ld.List.NamespaceID = ld.NamespaceID
|
|
return ld.List.CanCreate(a)
|
|
}
|
|
|
|
// Create duplicates a list
|
|
func (ld *ListDuplicate) Create(a web.Auth) (err error) {
|
|
|
|
ld.List.ID = 0
|
|
ld.List.Identifier = "" // Reset the identifier to trigger regenerating a new one
|
|
// Set the owner to the current user
|
|
ld.List.OwnerID = a.GetID()
|
|
if err := CreateOrUpdateList(ld.List); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Duplicate kanban buckets
|
|
// Old bucket ID as key, new id as value
|
|
// Used to map the newly created tasks to their new buckets
|
|
bucketMap := make(map[int64]int64)
|
|
buckets := []*Bucket{}
|
|
err = x.Where("list_id = ?", ld.ListID).Find(&buckets)
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, b := range buckets {
|
|
oldID := b.ID
|
|
b.ID = 0
|
|
b.ListID = ld.List.ID
|
|
if err := b.Create(a); err != nil {
|
|
return err
|
|
}
|
|
bucketMap[oldID] = b.ID
|
|
}
|
|
|
|
// Get all tasks + all task details
|
|
tasks, _, _, err := getTasksForLists([]*List{{ID: ld.ListID}}, &taskOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
taskMap := make(map[int64]int64)
|
|
// Create + update all tasks
|
|
oldTaskIDs := make([]int64, len(tasks))
|
|
for _, t := range tasks {
|
|
oldID := t.ID
|
|
t.ID = 0
|
|
t.ListID = ld.List.ID
|
|
t.BucketID = bucketMap[t.ID]
|
|
t.UID = ""
|
|
err := createTask(t, a, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
taskMap[oldID] = t.ID
|
|
oldTaskIDs = append(oldTaskIDs, oldID)
|
|
}
|
|
|
|
// Save all attachments
|
|
// We also duplicate all underlying files since they could be modified in one list which would result in
|
|
// file changes in the other list which is not something we want.
|
|
attachments, err := getTaskAttachmentsByTaskIDs(oldTaskIDs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, attachment := range attachments {
|
|
attachment.TaskID = oldTaskIDs[attachment.TaskID]
|
|
if err := attachment.File.LoadFileByID(); err != nil {
|
|
return err
|
|
}
|
|
|
|
err := attachment.NewAttachment(attachment.File.File, attachment.File.Name, attachment.File.Size, a)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_ = attachment.File.File.Close()
|
|
}
|
|
|
|
// Copy label tasks (not the labels)
|
|
labelTasks := []*LabelTask{}
|
|
err = x.In("task_id", oldTaskIDs).Find(&labelTasks)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, lt := range labelTasks {
|
|
lt.ID = 0
|
|
lt.TaskID = taskMap[lt.TaskID]
|
|
if _, err := x.Insert(lt); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// * assignees
|
|
// * comments
|
|
// * relations in that list
|
|
// * reminders
|
|
// * Background files + unsplash info
|
|
|
|
// * rights / shares
|
|
// * Generate new link shares if any are available
|
|
return
|
|
}
|