2020-02-07 17:27:45 +01:00
|
|
|
// Vikunja is a to-do list application to facilitate your life.
|
2021-02-02 20:19:13 +01:00
|
|
|
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
2019-05-22 19:48:48 +02:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
2020-12-23 16:41:52 +01:00
|
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
2019-12-04 20:39:56 +01:00
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2019-05-22 19:48:48 +02:00
|
|
|
//
|
2019-12-04 20:39:56 +01:00
|
|
|
// 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
|
2020-12-23 16:41:52 +01:00
|
|
|
// GNU Affero General Public Licensee for more details.
|
2019-05-22 19:48:48 +02:00
|
|
|
//
|
2020-12-23 16:41:52 +01:00
|
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
2019-12-04 20:39:56 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-05-22 19:48:48 +02:00
|
|
|
|
|
|
|
package caldav
|
|
|
|
|
|
|
|
import (
|
2020-10-11 22:10:03 +02:00
|
|
|
"strconv"
|
2020-10-19 11:11:15 +02:00
|
|
|
"strings"
|
2020-10-11 22:10:03 +02:00
|
|
|
"time"
|
|
|
|
|
2019-05-22 19:48:48 +02:00
|
|
|
"code.vikunja.io/api/pkg/log"
|
|
|
|
"code.vikunja.io/api/pkg/models"
|
2019-05-24 19:45:33 +02:00
|
|
|
"github.com/laurent22/ical-go"
|
2019-05-22 19:48:48 +02:00
|
|
|
)
|
|
|
|
|
2021-09-04 21:26:31 +02:00
|
|
|
func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*models.TaskWithComments) string {
|
2019-05-22 19:48:48 +02:00
|
|
|
|
|
|
|
// Make caldav todos from Vikunja todos
|
2021-07-11 15:03:50 +02:00
|
|
|
var caldavtodos []*Todo
|
2020-10-18 12:40:50 +02:00
|
|
|
for _, t := range listTasks {
|
2019-05-22 19:48:48 +02:00
|
|
|
|
2020-06-27 19:04:01 +02:00
|
|
|
duration := t.EndDate.Sub(t.StartDate)
|
2019-05-22 19:48:48 +02:00
|
|
|
|
2021-07-11 15:03:50 +02:00
|
|
|
caldavtodos = append(caldavtodos, &Todo{
|
2020-02-08 13:48:49 +01:00
|
|
|
Timestamp: t.Updated,
|
|
|
|
UID: t.UID,
|
2020-05-16 12:17:44 +02:00
|
|
|
Summary: t.Title,
|
2020-02-08 13:48:49 +01:00
|
|
|
Description: t.Description,
|
|
|
|
Completed: t.DoneAt,
|
2019-05-22 19:48:48 +02:00
|
|
|
// Organizer: &t.CreatedBy, // Disabled until we figure out how this works
|
2020-02-08 13:48:49 +01:00
|
|
|
Priority: t.Priority,
|
|
|
|
Start: t.StartDate,
|
|
|
|
End: t.EndDate,
|
|
|
|
Created: t.Created,
|
|
|
|
Updated: t.Updated,
|
|
|
|
DueDate: t.DueDate,
|
|
|
|
Duration: duration,
|
2019-05-22 19:48:48 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-11 15:03:50 +02:00
|
|
|
caldavConfig := &Config{
|
2019-05-22 19:48:48 +02:00
|
|
|
Name: list.Title,
|
|
|
|
ProdID: "Vikunja Todo App",
|
|
|
|
}
|
|
|
|
|
2021-07-11 15:03:50 +02:00
|
|
|
return ParseTodos(caldavConfig, caldavtodos)
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|
|
|
|
|
2021-07-11 15:03:50 +02:00
|
|
|
func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) {
|
2019-05-22 19:48:48 +02:00
|
|
|
parsed, err := ical.ParseCalendar(content)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// We put the task details in a map to be able to handle them more easily
|
|
|
|
task := make(map[string]string)
|
|
|
|
for _, c := range parsed.Children {
|
|
|
|
if c.Name == "VTODO" {
|
|
|
|
for _, entry := range c.Children {
|
|
|
|
task[entry.Name] = entry.Value
|
|
|
|
}
|
|
|
|
// Breaking, to only process the first task
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-11 15:03:50 +02:00
|
|
|
// Parse the priority
|
2019-05-22 19:48:48 +02:00
|
|
|
var priority int64
|
|
|
|
if _, ok := task["PRIORITY"]; ok {
|
2021-07-11 15:03:50 +02:00
|
|
|
priorityParsed, err := strconv.ParseInt(task["PRIORITY"], 10, 64)
|
2019-05-22 19:48:48 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-07-11 15:03:50 +02:00
|
|
|
|
|
|
|
priority = parseVTODOPriority(priorityParsed)
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the enddate
|
|
|
|
duration, _ := time.ParseDuration(task["DURATION"])
|
|
|
|
|
2019-08-14 22:19:04 +02:00
|
|
|
vTask = &models.Task{
|
2020-02-08 13:48:49 +01:00
|
|
|
UID: task["UID"],
|
2020-05-16 12:17:44 +02:00
|
|
|
Title: task["SUMMARY"],
|
2020-02-08 13:48:49 +01:00
|
|
|
Description: task["DESCRIPTION"],
|
|
|
|
Priority: priority,
|
|
|
|
DueDate: caldavTimeToTimestamp(task["DUE"]),
|
|
|
|
Updated: caldavTimeToTimestamp(task["DTSTAMP"]),
|
|
|
|
StartDate: caldavTimeToTimestamp(task["DTSTART"]),
|
|
|
|
DoneAt: caldavTimeToTimestamp(task["COMPLETED"]),
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if task["STATUS"] == "COMPLETED" {
|
|
|
|
vTask.Done = true
|
|
|
|
}
|
|
|
|
|
2020-06-27 19:04:01 +02:00
|
|
|
if duration > 0 && !vTask.StartDate.IsZero() {
|
|
|
|
vTask.EndDate = vTask.StartDate.Add(duration)
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-10-19 11:11:15 +02:00
|
|
|
// https://tools.ietf.org/html/rfc5545#section-3.3.5
|
2020-06-27 19:04:01 +02:00
|
|
|
func caldavTimeToTimestamp(tstring string) time.Time {
|
2019-05-22 19:48:48 +02:00
|
|
|
if tstring == "" {
|
2020-06-27 19:04:01 +02:00
|
|
|
return time.Time{}
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|
|
|
|
|
2021-07-11 15:03:50 +02:00
|
|
|
format := DateFormat
|
2020-10-19 11:11:15 +02:00
|
|
|
|
|
|
|
if strings.HasSuffix(tstring, "Z") {
|
|
|
|
format = `20060102T150405Z`
|
|
|
|
}
|
|
|
|
|
|
|
|
t, err := time.Parse(format, tstring)
|
2019-05-22 19:48:48 +02:00
|
|
|
if err != nil {
|
2020-02-08 13:48:49 +01:00
|
|
|
log.Warningf("Error while parsing caldav time %s to TimeStamp: %s", tstring, err)
|
2020-06-27 19:04:01 +02:00
|
|
|
return time.Time{}
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|
2020-06-27 19:04:01 +02:00
|
|
|
return t
|
2019-05-22 19:48:48 +02:00
|
|
|
}
|