Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
JM-Lemmi committed Mar 14, 2023
2 parents 9b107b2 + 205367c commit 28d9af3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 6 deletions.
15 changes: 15 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# v1.3.1

- basic RRULE handling in delete-timeframe Module
- waiting for upstream RRULE Handling in golang-ical
- cannot handle COUNT
- cannot handle when timeframe is inbetween or only in the beginning of the RRULE
- fix "invalid start time" in delete-timeframe with only "before"-option

# v1.3.0

- Immutable past is now a profile boolean option. Simply add `immutable-past: true` to your profile configuration.
- Query Parameters can be used to start a module with parameters given at runtime.
- `?reminder=15m` adds an Alarm to every Entry of 15 minutes before. It is not supported in dynamic calendars from Outlook or Google.
- Notification Mails now look much more readable and don't deliver the whole ICS Event.

# v1.2.0

- add Notifiers: Get Notifications per Mail, if a calendar changes
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
log "github.com/sirupsen/logrus"
)

var version = "1.2.0"
var version = "1.3.1"

var configPath string
var conf Config
Expand Down
66 changes: 61 additions & 5 deletions modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ func callModule(module func(*ics.Calendar, map[string]string) (int, error), para

// This modules delete all events whose summary match the regex and are in the time range from the calendar.
// Parameters:
// - 'regex', mandatory: regular expression to remove.
// - 'from' & 'until', optional parameters: If timeframe is not given, all events matching the regex are removed.
// Currenty if only either "from" or "until" is set, the timeframe will be ignored. TODO
// - 'regex', mandatory: regular expression to remove.
// - 'from' & 'until', optional parameters: If timeframe is not given, all events matching the regex are removed.
// Currenty if only either "from" or "until" is set, the timeframe will be ignored. TODO
//
// Returns the number of events removed. This number should always be negative.
func moduleDeleteSummaryRegex(cal *ics.Calendar, params map[string]string) (int, error) {
var count int
Expand Down Expand Up @@ -201,7 +202,7 @@ func addMultiURL(cal *ics.Calendar, urls []string, header map[string]string) (in

func moduleAddFile(cal *ics.Calendar, params map[string]string) (int, error) {
if params["filename"] == "" {
return 0, fmt.Errorf("missing mandatory Parameter 'file'")
return 0, fmt.Errorf("missing mandatory Parameter 'filename'")
}
return addEventsFile(cal, params["filename"])
}
Expand All @@ -228,6 +229,7 @@ func addMultiFile(cal *ics.Calendar, filenames []string) (int, error) {
}

// Removes all Events in a passed Timeframe.
// Sets UNTIL parameter to the end of the timeframe for RRULE events.
// Parameters: either "after" or "before" mandatory
// Format is RFC3339: "2006-01-02T15:04:05Z"
// or "now" for current time
Expand All @@ -246,7 +248,7 @@ func moduleDeleteTimeframe(cal *ics.Calendar, params map[string]string) (int, er
} else if params["after"] == "now" {
after = time.Now()
} else {
after, err = time.Parse(time.RFC3339, params["start"])
after, err = time.Parse(time.RFC3339, params["after"])
if err != nil {
return 0, fmt.Errorf("invalid start time: %s", err.Error())
}
Expand All @@ -269,6 +271,54 @@ func moduleDeleteTimeframe(cal *ics.Calendar, params map[string]string) (int, er
switch cal.Components[i].(type) {
case *ics.VEvent:
event := cal.Components[i].(*ics.VEvent)
if event.GetProperty(ics.ComponentPropertyRrule) != nil {
// event has RRULE
// TODO handle RRULEs in the past?
log.Debug("Event with RRULE: " + event.Id())
// read RRULE, split into different rule parts
props := strings.Split(event.GetProperty(ics.ComponentPropertyRrule).Value, ";")
// cast into map for easy queries
m := make(map[string]string)
for _, e := range props {
p := strings.Split(e, "=")
m[p[0]] = p[1]
}
// either UNTIL or COUNT is present, otherwise, add UNTIL
if v, ok := m["UNTIL"]; ok {
// time format from from golang-ical/components.go/icalTimestampFormatUtc
until, err := time.Parse("20060102T150405Z", v)
if err != nil {
return 0, fmt.Errorf("invalid UNTIL time: %s", err.Error())
}
// only checking after to not break RRULEs with UNTIL in the past
if until.After(after) {
// RRULE UNTIL is not in timeframe, shortening UNTIL
log.Debug("Shortening UNTIL in RRULE of event with id " + event.Id() + "\n")
m["UNTIL"] = after.Format("20060102T150405Z")
}
} else if _, ok := m["COUNT"]; ok {
// TODO implement calculating COUNT
log.Debug("COUNT in RRULE of event with id " + event.Id() + " not implemented\n")
} else {
// no UNTIL or COUNT, adding UNTIL
log.Debug("Adding UNTIL in RRULE of event with id " + event.Id() + "\n")
m["UNTIL"] = after.Format("20060102T150405Z")
}
// reassemble RRULE
rrulestring := ""
for k, v := range m {
rrulestring += k + "=" + v + ";"
}
// delete old RRULE. TODO upstream function to delete property
for i, p := range event.Properties {
if ics.ComponentProperty(p.IANAToken) == ics.ComponentPropertyRrule {
removeProperty(event.Properties, i)
}
}
event.AddRrule(rrulestring)
// adding edited event back to calendar
cal.Components[i] = event
}
date, _ := event.GetStartAt()
if date.After(after) && before.After(date) {
cal.Components = remove(cal.Components, i)
Expand Down Expand Up @@ -580,6 +630,12 @@ func remove(slice []ics.Component, s int) []ics.Component {
return append(slice[:s], slice[s+1:]...)
}

// removes the element at index i from ics.Component slice
// warning: if you iterate over []ics.IANAProperty forward, this remove will lead to mistakes. Iterate backwards instead!
func removeProperty(slice []ics.IANAProperty, s int) []ics.IANAProperty {
return append(slice[:s], slice[s+1:]...)
}

// returns true, if a is in list b
func stringInSlice(a string, list []string) bool {
for _, b := range list {
Expand Down

0 comments on commit 28d9af3

Please sign in to comment.