diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/caldav/plugin.go | 14 | ||||
-rw-r--r-- | plugins/caldav/public/calendar.html | 1 | ||||
-rw-r--r-- | plugins/caldav/public/update-event.html | 30 | ||||
-rw-r--r-- | plugins/caldav/routes.go | 104 |
4 files changed, 149 insertions, 0 deletions
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 @@ <p> <a href="/">Back</a> + ยท <a href="/calendar/create">Create new event</a> </p> <h2>Calendar: {{.Calendar.Name}}</h2> 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" .}} + +<h1>alps</h1> + +<p> + <a href="/calendar">Back</a> +</p> + +<h2> + {{if .CalendarObject}}Edit{{else}}Create{{end}} event +</h2> + +<form method="post"> + <label for="summary">Name:</label> + <input type="text" name="summary" id="summary" value="{{.Event.Props.Text "SUMMARY"}}"> + <br> + + <!-- TODO: inputs with time --> + <label for="start">Start date:</label> + <input type="date" name="start" id="start" value="{{.Event.DateTimeStart nil | ornow | formatinputdate}}"/> + <br> + + <label for="end">End date:</label> + <input type="date" name="end" id="end" value="{{.Event.DateTimeEnd nil | ornow | formatinputdate}}"/> + <br> + + <input type="submit" value="Save"> +</form> + +{{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) } |