aboutsummaryrefslogtreecommitdiff
path: root/plugins/caldav
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2020-05-13 19:42:41 +0200
committerSimon Ser <contact@emersion.fr>2020-05-13 19:44:08 +0200
commitce0b0a7eeb35049a921e160920a7c279327db0ca (patch)
tree8afd8dfbbab16473a33345aaf95c56ea0f96b59c /plugins/caldav
parentea12ffcc4ce74d68fbe1387ec6668126982ec11e (diff)
downloadalps-ce0b0a7eeb35049a921e160920a7c279327db0ca.tar.gz
alps-ce0b0a7eeb35049a921e160920a7c279327db0ca.zip
plugins/caldav: add form to create new events
Diffstat (limited to 'plugins/caldav')
-rw-r--r--plugins/caldav/plugin.go14
-rw-r--r--plugins/caldav/public/calendar.html1
-rw-r--r--plugins/caldav/public/update-event.html30
-rw-r--r--plugins/caldav/routes.go104
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)
}