fix: review findings
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
cernst 2023-03-29 19:24:33 +02:00
parent 7bd6e910c3
commit 3e49c27ad1
5 changed files with 106 additions and 75 deletions

View File

@ -62,7 +62,7 @@ type Todo struct {
type Alarm struct {
Time time.Time
Duration time.Duration
RelativeTo string
RelativeTo models.ReminderRelation
Description string
}
@ -204,13 +204,13 @@ func ParseAlarms(alarms []Alarm, taskDescription string) (caldavalarms string) {
caldavalarms += `
BEGIN:VALARM`
switch a.RelativeTo {
case "due_date":
case models.ReminderRelationDueDate:
caldavalarms += `
TRIGGER:` + makeCalDavDuration(a.Duration)
case "start_date":
case models.ReminderRelationStartDate:
caldavalarms += `
TRIGGER;RELATED=START:` + makeCalDavDuration(a.Duration)
case "end_date":
case models.ReminderRelationEndDate:
caldavalarms += `
TRIGGER;RELATED=END:` + makeCalDavDuration(a.Duration)
default:

View File

@ -18,13 +18,13 @@ package caldav
import (
"errors"
"regexp"
"strconv"
"strings"
"time"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/utils"
ics "github.com/arran4/golang-ical"
)
@ -45,7 +45,7 @@ func GetCaldavTodosForTasks(project *models.ProjectWithTasksAndBuckets, projectT
alarms = append(alarms, Alarm{
Time: reminder.Reminder,
Duration: time.Duration(reminder.RelativePeriod) * time.Second,
RelativeTo: string(reminder.RelativeTo),
RelativeTo: reminder.RelativeTo,
})
}
@ -165,7 +165,7 @@ func parseVAlarm(vAlarm *ics.VAlarm, reminders []*models.TaskReminder) []*models
Reminder: caldavTimeToTimestamp(property.Value)})
}
case len(property.ICalParameters["RELATED"]) > 0:
duration := parseDuration(property.Value)
duration := utils.ParseISO8601Duration(property.Value)
switch property.ICalParameters["RELATED"][0] {
case "START":
// Example: TRIGGER;RELATED=START:-P2D
@ -179,7 +179,7 @@ func parseVAlarm(vAlarm *ics.VAlarm, reminders []*models.TaskReminder) []*models
RelativeTo: models.ReminderRelationEndDate})
}
default:
duration := parseDuration(property.Value)
duration := utils.ParseISO8601Duration(property.Value)
// Example: TRIGGER:-PT60M
reminders = append(reminders, &models.TaskReminder{
RelativePeriod: int64(duration.Seconds()),
@ -213,37 +213,3 @@ func caldavTimeToTimestamp(tstring string) time.Time {
}
return t
}
var durationRegex = regexp.MustCompile(`([-+])?P([\d\.]+Y)?([\d\.]+M)?([\d\.]+D)?T?([\d\.]+H)?([\d\.]+M)?([\d\.]+?S)?`)
// ParseDuration converts a ISO8601 duration into a time.Duration
func parseDuration(str string) time.Duration {
matches := durationRegex.FindStringSubmatch(str)
if len(matches) == 0 {
return 0
}
years := parseDurationPart(matches[2], time.Hour*24*365)
months := parseDurationPart(matches[3], time.Hour*24*30)
days := parseDurationPart(matches[4], time.Hour*24)
hours := parseDurationPart(matches[5], time.Hour)
minutes := parseDurationPart(matches[6], time.Second*60)
seconds := parseDurationPart(matches[7], time.Second)
duration := years + months + days + hours + minutes + seconds
if matches[1] == "-" {
return -duration
}
return duration
}
func parseDurationPart(value string, unit time.Duration) time.Duration {
if len(value) != 0 {
if parsed, err := strconv.ParseFloat(value[:len(value)-1], 64); err == nil {
return time.Duration(float64(unit) * parsed)
}
}
return 0
}

View File

@ -20,9 +20,7 @@ import (
"encoding/csv"
"errors"
"io"
"regexp"
"sort"
"strconv"
"strings"
"time"
@ -30,6 +28,7 @@ import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/modules/migration"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"github.com/gocarina/gocsv"
)
@ -75,36 +74,6 @@ func (date *tickTickTime) UnmarshalCSV(csv string) (err error) {
return err
}
// Copied from https://stackoverflow.com/a/57617885
var durationRegex = regexp.MustCompile(`P([\d\.]+Y)?([\d\.]+M)?([\d\.]+D)?T?([\d\.]+H)?([\d\.]+M)?([\d\.]+?S)?`)
// ParseDuration converts a ISO8601 duration into a time.Duration
func parseDuration(str string) time.Duration {
matches := durationRegex.FindStringSubmatch(str)
if len(matches) == 0 {
return 0
}
years := parseDurationPart(matches[1], time.Hour*24*365)
months := parseDurationPart(matches[2], time.Hour*24*30)
days := parseDurationPart(matches[3], time.Hour*24)
hours := parseDurationPart(matches[4], time.Hour)
minutes := parseDurationPart(matches[5], time.Second*60)
seconds := parseDurationPart(matches[6], time.Second)
return years + months + days + hours + minutes + seconds
}
func parseDurationPart(value string, unit time.Duration) time.Duration {
if len(value) != 0 {
if parsed, err := strconv.ParseFloat(value[:len(value)-1], 64); err == nil {
return time.Duration(float64(unit) * parsed)
}
}
return 0
}
func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.NamespaceWithProjectsAndTasks) {
namespace := &models.NamespaceWithProjectsAndTasks{
Namespace: models.Namespace{
@ -231,7 +200,7 @@ func (m *Migrator) Migrate(user *user.User, file io.ReaderAt, size int64) error
task.IsChecklist = true
}
reminder := parseDuration(task.ReminderDuration)
reminder := utils.ParseISO8601Duration(task.ReminderDuration)
if reminder > 0 {
task.Reminder = reminder
}

57
pkg/utils/duration.go Normal file
View File

@ -0,0 +1,57 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2021 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 Licensee 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 Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package utils
import (
"regexp"
"strconv"
"time"
)
// ParseISO8601Duration converts a ISO8601 duration into a time.Duration
func ParseISO8601Duration(str string) time.Duration {
matches := durationRegex.FindStringSubmatch(str)
if len(matches) == 0 {
return 0
}
years := parseDurationPart(matches[2], time.Hour*24*365)
months := parseDurationPart(matches[3], time.Hour*24*30)
days := parseDurationPart(matches[4], time.Hour*24)
hours := parseDurationPart(matches[5], time.Hour)
minutes := parseDurationPart(matches[6], time.Second*60)
seconds := parseDurationPart(matches[7], time.Second)
duration := years + months + days + hours + minutes + seconds
if matches[1] == "-" {
return -duration
}
return duration
}
var durationRegex = regexp.MustCompile(`([-+])?P([\d\.]+Y)?([\d\.]+M)?([\d\.]+D)?T?([\d\.]+H)?([\d\.]+M)?([\d\.]+?S)?`)
func parseDurationPart(value string, unit time.Duration) time.Duration {
if len(value) != 0 {
if parsed, err := strconv.ParseFloat(value[:len(value)-1], 64); err == nil {
return time.Duration(float64(unit) * parsed)
}
}
return 0
}

View File

@ -0,0 +1,39 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2021 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 Licensee 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 Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package utils
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestParseISO8601Duration(t *testing.T) {
t.Run("full example", func(t *testing.T) {
dur := ParseISO8601Duration("P1DT1H1M1S")
expected, _ := time.ParseDuration("25h1m1s")
assert.Equal(t, expected, dur)
})
t.Run("negative duration", func(t *testing.T) {
dur := ParseISO8601Duration("-P1DT1H1M1S")
expected, _ := time.ParseDuration("-25h1m1s")
assert.Equal(t, expected, dur)
})
}