diff options
author | Simon Ser <contact@emersion.fr> | 2020-02-12 21:13:51 +0100 |
---|---|---|
committer | Simon Ser <contact@emersion.fr> | 2020-02-12 21:14:18 +0100 |
commit | c4ff33e64522f9662f5356d96b3d68f17764b84a (patch) | |
tree | 01c3eeb0b311373841bdf8c996c976d6a4f3eb5f /plugins/carddav/routes.go | |
parent | e24e20e528faa4a80c3281811f004b0388f4500b (diff) | |
download | alps-c4ff33e64522f9662f5356d96b3d68f17764b84a.tar.gz alps-c4ff33e64522f9662f5356d96b3d68f17764b84a.zip |
plugins/carddav: add page to create new contact
Diffstat (limited to 'plugins/carddav/routes.go')
-rw-r--r-- | plugins/carddav/routes.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/plugins/carddav/routes.go b/plugins/carddav/routes.go index 45a6237..e05f32d 100644 --- a/plugins/carddav/routes.go +++ b/plugins/carddav/routes.go @@ -3,10 +3,13 @@ package koushincarddav import ( "fmt" "net/http" + "path" + "strings" "git.sr.ht/~emersion/koushin" "github.com/emersion/go-vcard" "github.com/emersion/go-webdav/carddav" + "github.com/google/uuid" ) type AddressBookRenderData struct { @@ -21,6 +24,12 @@ type AddressObjectRenderData struct { AddressObject *carddav.AddressObject } +type UpdateAddressObjectRenderData struct { + koushin.BaseRenderData + AddressObject *carddav.AddressObject // nil if creating a new contact + Card vcard.Card +} + func registerRoutes(p *plugin) { p.GET("/contacts", func(ctx *koushin.Context) error { queryText := ctx.QueryParam("query") @@ -107,4 +116,62 @@ func registerRoutes(p *plugin) { AddressObject: addr, }) }) + + createContact := func(ctx *koushin.Context) error { + card := make(vcard.Card) + + if ctx.Request().Method == "POST" { + fn := ctx.FormValue("fn") + emails := strings.Split(ctx.FormValue("emails"), ",") + + // Some CardDAV servers (e.g. Google) don't support vCard 4.0 + // TODO: get supported formats from server, use highest version + if _, ok := card[vcard.FieldVersion]; !ok { + card.SetValue(vcard.FieldVersion, "3.0") + } + + if field := card.Preferred(vcard.FieldFormattedName); field != nil { + field.Value = fn + } else { + card.Add(vcard.FieldFormattedName, &vcard.Field{Value: fn}) + } + + // TODO: Google wants a "N" field, fails with a 400 otherwise + + // TODO: params are lost here + var emailFields []*vcard.Field + for _, email := range emails { + emailFields = append(emailFields, &vcard.Field{ + Value: strings.TrimSpace(email), + }) + } + card[vcard.FieldEmail] = emailFields + + id := uuid.New() + if _, ok := card[vcard.FieldUID]; !ok { + card.SetValue(vcard.FieldUID, id.URN()) + } + + c, addressBook, err := p.clientWithAddressBook(ctx.Session) + if err != nil { + return err + } + + p := path.Join(addressBook.Path, id.String() + ".vcf") + _, 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.Render(http.StatusOK, "update-address-object.html", &UpdateAddressObjectRenderData{ + BaseRenderData: *koushin.NewBaseRenderData(ctx), + }) + } + p.GET("/contacts/create", createContact) + p.POST("/contacts/create", createContact) } |