From ce0b0a7eeb35049a921e160920a7c279327db0ca Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 13 May 2020 19:42:41 +0200 Subject: [PATCH] plugins/caldav: add form to create new events --- go.mod | 2 +- plugins/caldav/plugin.go | 14 ++++ plugins/caldav/public/calendar.html | 1 + plugins/caldav/public/update-event.html | 30 +++++++ plugins/caldav/routes.go | 104 ++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 plugins/caldav/public/update-event.html diff --git a/go.mod b/go.mod index 6614a35..6d761e8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.13 require ( github.com/aymerick/douceur v0.2.0 github.com/chris-ramon/douceur v0.2.0 - github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1 // indirect + github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1 github.com/emersion/go-imap v1.0.4 github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915 github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 diff --git a/plugins/caldav/plugin.go b/plugins/caldav/plugin.go index 68de6cf..caeb12a 100644 --- a/plugins/caldav/plugin.go +++ b/plugins/caldav/plugin.go @@ -2,8 +2,10 @@ package alpscaldav import ( "fmt" + "html/template" "net/http" "net/url" + "time" "git.sr.ht/~emersion/alps" ) @@ -57,6 +59,18 @@ func newPlugin(srv *alps.Server) (alps.Plugin, error) { registerRoutes(&p, u) + p.TemplateFuncs(template.FuncMap{ + "formatinputdate": func(t time.Time) string { + return t.Format("2006-01-02") + }, + "ornow": func(t time.Time) time.Time { + if t.IsZero() { + return time.Now() + } + return t + }, + }) + return p.Plugin(), nil } diff --git a/plugins/caldav/public/calendar.html b/plugins/caldav/public/calendar.html index e9be003..396cafc 100644 --- a/plugins/caldav/public/calendar.html +++ b/plugins/caldav/public/calendar.html @@ -4,6 +4,7 @@

Back + ยท Create new event

Calendar: {{.Calendar.Name}}

diff --git a/plugins/caldav/public/update-event.html b/plugins/caldav/public/update-event.html new file mode 100644 index 0000000..1a4abcc --- /dev/null +++ b/plugins/caldav/public/update-event.html @@ -0,0 +1,30 @@ +{{template "head.html" .}} + +

alps

+ +

+ Back +

+ +

+ {{if .CalendarObject}}Edit{{else}}Create{{end}} event +

+ +
+ + +
+ + + + +
+ + + +
+ + +
+ +{{template "foot.html"}} diff --git a/plugins/caldav/routes.go b/plugins/caldav/routes.go index b9367b3..3e4fa71 100644 --- a/plugins/caldav/routes.go +++ b/plugins/caldav/routes.go @@ -4,10 +4,13 @@ import ( "fmt" "net/http" "net/url" + "path" "time" "git.sr.ht/~emersion/alps" + "github.com/emersion/go-ical" "github.com/emersion/go-webdav/caldav" + "github.com/google/uuid" "github.com/labstack/echo/v4" ) @@ -25,6 +28,12 @@ type EventRenderData struct { Event CalendarObject } +type UpdateEventRenderData struct { + alps.BaseRenderData + CalendarObject *caldav.CalendarObject // nil if creating a new contact + Event *ical.Event +} + var monthPageLayout = "2006-01" func parseObjectPath(s string) (string, error) { @@ -145,4 +154,99 @@ func registerRoutes(p *alps.GoPlugin, u *url.URL) { Event: CalendarObject{event}, }) }) + + updateEvent := func(ctx *alps.Context) error { + calendarObjectPath, err := parseObjectPath(ctx.Param("path")) + if err != nil { + return err + } + + c, err := newClient(u, ctx.Session) + if err != nil { + return err + } + + c, calendar, err := getCalendar(u, ctx.Session) + if err != nil { + return err + } + + var co *caldav.CalendarObject + var event *ical.Event + if calendarObjectPath != "" { + co, err := c.GetCalendarObject(calendarObjectPath) + if err != nil { + return fmt.Errorf("failed to get CalDAV event: %v", err) + } + events := co.Data.Events() + if len(events) != 1 { + return fmt.Errorf("expected exactly one event, got %d", len(events)) + } + event = &events[0] + } else { + event = ical.NewEvent() + } + + if ctx.Request().Method == "POST" { + summary := ctx.FormValue("summary") + start, err := time.Parse("2006-01-02", ctx.FormValue("start")) + if err != nil { + err = fmt.Errorf("malformed start date: %v", err) + return echo.NewHTTPError(http.StatusBadRequest, err) + } + end, err := time.Parse("2006-01-02", ctx.FormValue("end")) + if err != nil { + err = fmt.Errorf("malformed end date: %v", err) + return echo.NewHTTPError(http.StatusBadRequest, err) + } + if start.After(end) { + return echo.NewHTTPError(http.StatusBadRequest, "event start is after its end") + } + + if start == end { + end = start.Add(24 * time.Hour) + } + + event.Props.SetDateTime(ical.PropDateTimeStamp, time.Now()) + event.Props.SetText(ical.PropSummary, summary) + event.Props.SetDateTime(ical.PropDateTimeStart, start) + event.Props.SetDateTime(ical.PropDateTimeEnd, end) + event.Props.Del(ical.PropDuration) + + newID := uuid.New() + if prop := event.Props.Get(ical.PropUID); prop == nil { + event.Props.SetText(ical.PropUID, newID.String()) + } + + cal := ical.NewCalendar() + cal.Props.SetText(ical.PropProductID, "-//emersion.fr//alps//EN") + cal.Props.SetText(ical.PropVersion, "2.0") + cal.Children = append(cal.Children, event.Component) + + var p string + if co != nil { + p = co.Path + } else { + p = path.Join(calendar.Path, newID.String()+".ics") + } + co, err = c.PutCalendarObject(p, cal) + if err != nil { + return fmt.Errorf("failed to put calendar object: %v", err) + } + + return ctx.Redirect(http.StatusFound, CalendarObject{co}.URL()) + } + + return ctx.Render(http.StatusOK, "update-event.html", &UpdateEventRenderData{ + BaseRenderData: *alps.NewBaseRenderData(ctx), + CalendarObject: co, + Event: event, + }) + } + + p.GET("/calendar/create", updateEvent) + p.POST("/calendar/create", updateEvent) + + p.GET("/calendar/:path/update", updateEvent) + p.POST("/calendar/:path/update", updateEvent) }