aboutsummaryrefslogtreecommitdiff
path: root/plugins/carddav/routes.go
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/carddav/routes.go')
-rw-r--r--plugins/carddav/routes.go80
1 files changed, 37 insertions, 43 deletions
diff --git a/plugins/carddav/routes.go b/plugins/carddav/routes.go
index 88b471a..b276944 100644
--- a/plugins/carddav/routes.go
+++ b/plugins/carddav/routes.go
@@ -3,6 +3,7 @@ package koushincarddav
import (
"fmt"
"net/http"
+ "net/url"
"path"
"strings"
@@ -10,18 +11,19 @@ import (
"github.com/emersion/go-vcard"
"github.com/emersion/go-webdav/carddav"
"github.com/google/uuid"
+ "github.com/labstack/echo/v4"
)
type AddressBookRenderData struct {
koushin.BaseRenderData
AddressBook *carddav.AddressBook
- AddressObjects []carddav.AddressObject
+ AddressObjects []AddressObject
Query string
}
type AddressObjectRenderData struct {
koushin.BaseRenderData
- AddressObject *carddav.AddressObject
+ AddressObject AddressObject
}
type UpdateAddressObjectRenderData struct {
@@ -30,6 +32,15 @@ type UpdateAddressObjectRenderData struct {
Card vcard.Card
}
+func parseObjectPath(s string) (string, error) {
+ p, err := url.PathUnescape(s)
+ if err != nil {
+ err = fmt.Errorf("failed to parse path: %v", err)
+ return "", echo.NewHTTPError(http.StatusBadRequest, err)
+ }
+ return string(p), nil
+}
+
func registerRoutes(p *plugin) {
p.GET("/contacts", func(ctx *koushin.Context) error {
queryText := ctx.QueryParam("query")
@@ -65,7 +76,7 @@ func registerRoutes(p *plugin) {
}
}
- addrs, err := c.QueryAddressBook(addressBook.Path, &query)
+ aos, err := c.QueryAddressBook(addressBook.Path, &query)
if err != nil {
return fmt.Errorf("failed to query CardDAV addresses: %v", err)
}
@@ -73,20 +84,23 @@ func registerRoutes(p *plugin) {
return ctx.Render(http.StatusOK, "address-book.html", &AddressBookRenderData{
BaseRenderData: *koushin.NewBaseRenderData(ctx),
AddressBook: addressBook,
- AddressObjects: addrs,
+ AddressObjects: newAddressObjectList(aos),
Query: queryText,
})
})
- p.GET("/contacts/:uid", func(ctx *koushin.Context) error {
- uid := ctx.Param("uid")
+ p.GET("/contacts/:path", func(ctx *koushin.Context) error {
+ path, err := parseObjectPath(ctx.Param("path"))
+ if err != nil {
+ return err
+ }
- c, addressBook, err := p.clientWithAddressBook(ctx.Session)
+ c, err := p.client(ctx.Session)
if err != nil {
return err
}
- query := carddav.AddressBookQuery{
+ multiGet := carddav.AddressBookMultiGet{
DataRequest: carddav.AddressDataRequest{
Props: []string{
vcard.FieldFormattedName,
@@ -94,31 +108,27 @@ func registerRoutes(p *plugin) {
vcard.FieldUID,
},
},
- PropFilters: []carddav.PropFilter{{
- Name: vcard.FieldUID,
- TextMatches: []carddav.TextMatch{{
- Text: uid,
- MatchType: carddav.MatchEquals,
- }},
- }},
}
- addrs, err := c.QueryAddressBook(addressBook.Path, &query)
+ aos, err := c.MultiGetAddressBook(path, &multiGet)
if err != nil {
return fmt.Errorf("failed to query CardDAV address: %v", err)
}
- if len(addrs) != 1 {
- return fmt.Errorf("expected exactly one address object with UID %q, got %v", uid, len(addrs))
+ if len(aos) != 1 {
+ return fmt.Errorf("expected exactly one address object with path %q, got %v", path, len(aos))
}
- addr := &addrs[0]
+ ao := &aos[0]
return ctx.Render(http.StatusOK, "address-object.html", &AddressObjectRenderData{
BaseRenderData: *koushin.NewBaseRenderData(ctx),
- AddressObject: addr,
+ AddressObject: AddressObject{ao},
})
})
updateContact := func(ctx *koushin.Context) error {
- uid := ctx.Param("uid")
+ addressObjectPath, err := parseObjectPath(ctx.Param("path"))
+ if err != nil {
+ return err
+ }
c, addressBook, err := p.clientWithAddressBook(ctx.Session)
if err != nil {
@@ -127,25 +137,11 @@ func registerRoutes(p *plugin) {
var ao *carddav.AddressObject
var card vcard.Card
- if uid != "" {
- query := carddav.AddressBookQuery{
- DataRequest: carddav.AddressDataRequest{AllProp: true},
- PropFilters: []carddav.PropFilter{{
- Name: vcard.FieldUID,
- TextMatches: []carddav.TextMatch{{
- Text: uid,
- MatchType: carddav.MatchEquals,
- }},
- }},
- }
- aos, err := c.QueryAddressBook(addressBook.Path, &query)
+ if addressObjectPath != "" {
+ ao, err := c.GetAddressObject(addressObjectPath)
if err != nil {
return fmt.Errorf("failed to query CardDAV address: %v", err)
}
- if len(aos) != 1 {
- return fmt.Errorf("expected exactly one address object with UID %q, got %v", uid, len(aos))
- }
- ao = &aos[0]
card = ao.Card
} else {
card = make(vcard.Card)
@@ -189,14 +185,12 @@ func registerRoutes(p *plugin) {
} else {
p = path.Join(addressBook.Path, id.String()+".vcf")
}
- _, err = c.PutAddressObject(p, card)
+ ao, err = c.PutAddressObject(p, card)
if err != nil {
return fmt.Errorf("failed to put address object: %v", err)
}
- // TODO: check if the returned AddressObject's path matches, if not
- // fetch the new UID (the server may mutate it)
- return ctx.Redirect(http.StatusFound, "/contacts/"+card.Value(vcard.FieldUID))
+ return ctx.Redirect(http.StatusFound, AddressObject{ao}.URL())
}
return ctx.Render(http.StatusOK, "update-address-object.html", &UpdateAddressObjectRenderData{
@@ -209,6 +203,6 @@ func registerRoutes(p *plugin) {
p.GET("/contacts/create", updateContact)
p.POST("/contacts/create", updateContact)
- p.GET("/contacts/:uid/edit", updateContact)
- p.POST("/contacts/:uid/edit", updateContact)
+ p.GET("/contacts/:path/edit", updateContact)
+ p.POST("/contacts/:path/edit", updateContact)
}