mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-07-16 14:52:35 -05:00
iOS Reminders (and other RFC 6578 clients) never learned about tasks deleted on the Vikunja side: caldav-go answers unknown REPORT types with 412, which makes iOS silently stop syncing, and deleted tasks left no protocol-level trace a client could observe. Intercept sync-collection REPORTs before caldav-go sees them and answer per RFC 6578: tasks changed since the sync token as 200 entries and deleted tasks as 404 entries. Deletion records come from task soft-deletes, which are kept for 30 days before being purged. Token edge cases: delta comparisons are inclusive because tokens have second granularity (re-reported items keep their etag, so clients skip the download), and tokens older than the soft-delete retention answer 403 + valid-sync-token to force a full resync instead of a delta that would silently miss purged deletions.
86 lines
2.3 KiB
Go
86 lines
2.3 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 (
|
|
"time"
|
|
|
|
"code.vikunja.io/api/pkg/cron"
|
|
"code.vikunja.io/api/pkg/db"
|
|
"code.vikunja.io/api/pkg/log"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
// TaskDeleteRetention is how long soft-deleted tasks are kept before permanent
|
|
// removal. Hard-coded like the user deletion grace period.
|
|
const TaskDeleteRetention = 30 * 24 * time.Hour
|
|
|
|
// RegisterTaskCleanupCron registers the cron job that permanently removes
|
|
// tasks which were soft-deleted more than TaskDeleteRetention ago.
|
|
func RegisterTaskCleanupCron() {
|
|
err := cron.Schedule("0 * * * *", func() {
|
|
deleteExpiredTasks(time.Now())
|
|
})
|
|
if err != nil {
|
|
log.Errorf("Could not register task cleanup cron: %s", err.Error())
|
|
}
|
|
}
|
|
|
|
func deleteExpiredTasks(now time.Time) {
|
|
s := db.NewSession()
|
|
tasks := []*Task{}
|
|
err := s.Unscoped().
|
|
Where(builder.And(
|
|
builder.NotNull{"deleted_at"},
|
|
builder.Lt{"deleted_at": now.Add(-TaskDeleteRetention)},
|
|
)).
|
|
Find(&tasks)
|
|
s.Close()
|
|
if err != nil {
|
|
log.Errorf("Could not get tasks scheduled for permanent deletion: %s", err)
|
|
return
|
|
}
|
|
|
|
if len(tasks) == 0 {
|
|
return
|
|
}
|
|
|
|
log.Debugf("Found %d tasks scheduled for permanent deletion", len(tasks))
|
|
|
|
for _, task := range tasks {
|
|
func() {
|
|
ts := db.NewSession()
|
|
defer ts.Close()
|
|
|
|
err = hardDeleteTask(ts, task)
|
|
if err != nil {
|
|
_ = ts.Rollback()
|
|
log.Errorf("Could not permanently delete task %d: %s", task.ID, err)
|
|
return
|
|
}
|
|
|
|
log.Debugf("Permanently deleted task %d", task.ID)
|
|
|
|
err = ts.Commit()
|
|
if err != nil {
|
|
log.Errorf("Could not commit transaction: %s", err)
|
|
}
|
|
}()
|
|
}
|
|
}
|