plugins/caldav: add form to create new events
This commit is contained in:
parent
ea12ffcc4c
commit
ce0b0a7eeb
5 changed files with 150 additions and 1 deletions
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.13
|
||||||
require (
|
require (
|
||||||
github.com/aymerick/douceur v0.2.0
|
github.com/aymerick/douceur v0.2.0
|
||||||
github.com/chris-ramon/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 v1.0.4
|
||||||
github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915
|
github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915
|
||||||
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
|
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
|
||||||
|
|
|
@ -2,8 +2,10 @@ package alpscaldav
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.sr.ht/~emersion/alps"
|
"git.sr.ht/~emersion/alps"
|
||||||
)
|
)
|
||||||
|
@ -57,6 +59,18 @@ func newPlugin(srv *alps.Server) (alps.Plugin, error) {
|
||||||
|
|
||||||
registerRoutes(&p, u)
|
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
|
return p.Plugin(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="/">Back</a>
|
<a href="/">Back</a>
|
||||||
|
· <a href="/calendar/create">Create new event</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Calendar: {{.Calendar.Name}}</h2>
|
<h2>Calendar: {{.Calendar.Name}}</h2>
|
||||||
|
|
30
plugins/caldav/public/update-event.html
Normal file
30
plugins/caldav/public/update-event.html
Normal file
|
@ -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"}}
|
|
@ -4,10 +4,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.sr.ht/~emersion/alps"
|
"git.sr.ht/~emersion/alps"
|
||||||
|
"github.com/emersion/go-ical"
|
||||||
"github.com/emersion/go-webdav/caldav"
|
"github.com/emersion/go-webdav/caldav"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,6 +28,12 @@ type EventRenderData struct {
|
||||||
Event CalendarObject
|
Event CalendarObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateEventRenderData struct {
|
||||||
|
alps.BaseRenderData
|
||||||
|
CalendarObject *caldav.CalendarObject // nil if creating a new contact
|
||||||
|
Event *ical.Event
|
||||||
|
}
|
||||||
|
|
||||||
var monthPageLayout = "2006-01"
|
var monthPageLayout = "2006-01"
|
||||||
|
|
||||||
func parseObjectPath(s string) (string, error) {
|
func parseObjectPath(s string) (string, error) {
|
||||||
|
@ -145,4 +154,99 @@ func registerRoutes(p *alps.GoPlugin, u *url.URL) {
|
||||||
Event: CalendarObject{event},
|
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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue