Files
vikunja/pkg/models/bulk_task_create.go
kolaente c6f18e405c fix(caldav): build iCalendar output linearly, cap reminders and titles
Every VALARM repeats the task title and the output was built with string
concatenation, so rendering cost grew quadratically with the number of
reminders. Build it with a strings.Builder instead.

Tasks may now have at most MaxRemindersPerTask (100) reminders and a
title of at most MaxTaskTitleLength (1000) characters, checked through
v1, v2 and CalDAV. On update the reminder limit only applies when the
count grows and the title limit only when the title changes, so existing
tasks stay editable.
2026-11-05 15:42:45 +01:00

61 lines
2.5 KiB
Go

// 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 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package models
import (
"code.vikunja.io/api/pkg/web"
"xorm.io/xorm"
)
// MaxTasksPerBulkCreation is the maximum number of tasks one bulk creation request may contain.
const MaxTasksPerBulkCreation = 100
// BulkTaskCreation is a helper struct to create multiple tasks in one project at once.
type BulkTaskCreation struct {
ProjectID int64 `json:"-"`
// The maxItems tag cannot reference MaxTasksPerBulkCreation; TestBulkTaskCreation_TaskLimitTag pins them together.
Tasks []*Task `json:"tasks" minItems:"1" maxItems:"100" doc:"The tasks to create. Each entry accepts the same fields as the single-task create endpoint. Creation is atomic: if one task is invalid, none are created."`
web.CRUDable `xorm:"-" json:"-"`
web.Permissions `xorm:"-" json:"-"`
}
// CanCreate checks if a user may create tasks in the project — one write check covers the whole batch since all tasks land in the same project.
func (btc *BulkTaskCreation) CanCreate(s *xorm.Session, a web.Auth) (bool, error) {
p := &Project{ID: btc.ProjectID}
return p.CanWrite(s, a)
}
// Create creates all tasks of the batch in one transaction — an invalid task rolls back everything and the error names its index.
func (btc *BulkTaskCreation) Create(s *xorm.Session, a web.Auth) (err error) {
if len(btc.Tasks) == 0 || len(btc.Tasks) > MaxTasksPerBulkCreation {
return ErrInvalidBulkTaskCreationCount{Count: len(btc.Tasks)}
}
for i, t := range btc.Tasks {
if t == nil {
return ErrInvalidTaskInBulkCreation{Index: i, Err: ErrTaskCannotBeEmpty{}}
}
if err := validateTaskLimits(t, nil); err != nil {
return ErrInvalidTaskInBulkCreation{Index: i, Err: err}
}
t.Position = 0
}
return createTasks(s, btc.ProjectID, btc.Tasks, a, true, true, false)
}