vikunja-api/pkg/caldav/caldav.go

220 lines
5.1 KiB
Go
Raw Permalink Normal View History

2020-02-07 17:27:45 +01:00
// Vikunja is a to-do list application to facilitate your life.
2020-01-09 18:33:22 +01:00
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
2018-11-26 21:17:33 +01:00
//
// 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.
2018-11-26 21:17:33 +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
// GNU General Public License for more details.
2018-11-26 21:17:33 +01:00
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2018-11-26 21:17:33 +01:00
2018-11-03 16:05:45 +01:00
package caldav
import (
"code.vikunja.io/api/pkg/timeutil"
"code.vikunja.io/api/pkg/user"
2018-11-03 16:05:45 +01:00
"code.vikunja.io/api/pkg/utils"
2019-05-22 19:48:48 +02:00
"fmt"
2018-11-03 16:05:45 +01:00
"strconv"
"time"
)
2019-05-22 19:48:48 +02:00
// DateFormat ist the caldav date format
const DateFormat = `20060102T150405`
2018-11-03 16:05:45 +01:00
// Event holds a single caldav event
type Event struct {
Summary string
Description string
UID string
Alarms []Alarm
Timestamp timeutil.TimeStamp
Start timeutil.TimeStamp
End timeutil.TimeStamp
2018-11-03 16:05:45 +01:00
}
2019-05-22 19:48:48 +02:00
// Todo holds a single VTODO
type Todo struct {
// Required
Timestamp timeutil.TimeStamp
UID string
2019-05-22 19:48:48 +02:00
// Optional
Summary string
Description string
Completed timeutil.TimeStamp
Organizer *user.User
Priority int64 // 0-9, 1 is highest
RelatedToUID string
Start timeutil.TimeStamp
End timeutil.TimeStamp
DueDate timeutil.TimeStamp
Duration time.Duration
Created timeutil.TimeStamp
Updated timeutil.TimeStamp // last-mod
2019-05-22 19:48:48 +02:00
}
2018-11-03 16:05:45 +01:00
// Alarm holds infos about an alarm from a caldav event
type Alarm struct {
Time timeutil.TimeStamp
2018-11-03 16:05:45 +01:00
Description string
}
// Config is the caldav calendar config
type Config struct {
Name string
ProdID string
}
// ParseEvents parses an array of caldav events and gives them back as string
func ParseEvents(config *Config, events []*Event) (caldavevents string) {
caldavevents += `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:` + config.Name + `
PRODID:-//` + config.ProdID + `//EN`
for _, e := range events {
if e.UID == "" {
e.UID = makeCalDavTimeFromTimeStamp(e.Timestamp) + utils.Sha256(e.Summary)
2018-11-03 16:05:45 +01:00
}
caldavevents += `
BEGIN:VEVENT
UID:` + e.UID + `
SUMMARY:` + e.Summary + `
DESCRIPTION:` + e.Description + `
DTSTAMP:` + makeCalDavTimeFromTimeStamp(e.Timestamp) + `
DTSTART:` + makeCalDavTimeFromTimeStamp(e.Start) + `
DTEND:` + makeCalDavTimeFromTimeStamp(e.End)
2018-11-03 16:05:45 +01:00
for _, a := range e.Alarms {
if a.Description == "" {
a.Description = e.Summary
}
caldavevents += `
BEGIN:VALARM
TRIGGER:` + calcAlarmDateFromReminder(e.Start, a.Time) + `
2018-11-03 16:05:45 +01:00
ACTION:DISPLAY
DESCRIPTION:` + a.Description + `
END:VALARM`
}
caldavevents += `
END:VEVENT`
}
caldavevents += `
END:VCALENDAR` // Need a line break
return
}
2019-05-22 19:48:48 +02:00
// ParseTodos returns a caldav vcalendar string with todos
func ParseTodos(config *Config, todos []*Todo) (caldavtodos string) {
caldavtodos = `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:` + config.Name + `
PRODID:-//` + config.ProdID + `//EN`
for _, t := range todos {
if t.UID == "" {
t.UID = makeCalDavTimeFromTimeStamp(t.Timestamp) + utils.Sha256(t.Summary)
2019-05-22 19:48:48 +02:00
}
caldavtodos += `
BEGIN:VTODO
UID:` + t.UID + `
DTSTAMP:` + makeCalDavTimeFromTimeStamp(t.Timestamp) + `
2019-05-22 19:48:48 +02:00
SUMMARY:` + t.Summary
if t.Start != 0 {
2019-05-22 19:48:48 +02:00
caldavtodos += `
DTSTART: ` + makeCalDavTimeFromTimeStamp(t.Start)
2019-05-22 19:48:48 +02:00
}
if t.End != 0 {
2019-05-22 19:48:48 +02:00
caldavtodos += `
DTEND: ` + makeCalDavTimeFromTimeStamp(t.End)
2019-05-22 19:48:48 +02:00
}
if t.Description != "" {
caldavtodos += `
DESCRIPTION:` + t.Description
}
if t.Completed != 0 {
2019-05-22 19:48:48 +02:00
caldavtodos += `
COMPLETED: ` + makeCalDavTimeFromTimeStamp(t.Completed)
2019-05-22 19:48:48 +02:00
}
if t.Organizer != nil {
caldavtodos += `
ORGANIZER;CN=:` + t.Organizer.Username
}
if t.RelatedToUID != "" {
caldavtodos += `
RELATED-TO:` + t.RelatedToUID
}
if t.DueDate != 0 {
2019-05-22 19:48:48 +02:00
caldavtodos += `
DUE:` + makeCalDavTimeFromTimeStamp(t.DueDate)
2019-05-22 19:48:48 +02:00
}
if t.Created != 0 {
2019-05-22 19:48:48 +02:00
caldavtodos += `
CREATED:` + makeCalDavTimeFromTimeStamp(t.Created)
2019-05-22 19:48:48 +02:00
}
if t.Duration != 0 {
caldavtodos += `
DURATION:PT` + fmt.Sprintf("%.6f", t.Duration.Hours()) + `H` + fmt.Sprintf("%.6f", t.Duration.Minutes()) + `M` + fmt.Sprintf("%.6f", t.Duration.Seconds()) + `S`
}
if t.Priority != 0 {
caldavtodos += `
PRIORITY:` + strconv.Itoa(int(t.Priority))
}
caldavtodos += `
LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated)
2019-05-22 19:48:48 +02:00
caldavtodos += `
END:VTODO`
}
caldavtodos += `
END:VCALENDAR` // Need a line break
return
}
func makeCalDavTimeFromTimeStamp(ts timeutil.TimeStamp) (caldavtime string) {
2018-12-16 14:21:32 +01:00
tz, _ := time.LoadLocation("UTC")
return ts.ToTime().In(tz).Format(DateFormat)
2018-11-03 16:05:45 +01:00
}
func calcAlarmDateFromReminder(eventStartUnix, reminderUnix timeutil.TimeStamp) (alarmTime string) {
2018-11-03 16:05:45 +01:00
if eventStartUnix > reminderUnix {
alarmTime += `-`
}
alarmTime += `PT`
diff := eventStartUnix - reminderUnix
if diff < 0 { // Make it positive
diff = diff * -1
}
alarmTime += strconv.Itoa(int(diff/60)) + "M"
return
}