feat: implement caldav search
This commit is contained in:
119
vendor/github.com/dolanor/caldav-go/webdav/client.go
generated
vendored
Normal file
119
vendor/github.com/dolanor/caldav-go/webdav/client.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
package webdav
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dolanor/caldav-go/http"
|
||||
"github.com/dolanor/caldav-go/utils"
|
||||
"github.com/dolanor/caldav-go/webdav/entities"
|
||||
nhttp "net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
StatusMulti = 207
|
||||
)
|
||||
|
||||
// a client for making WebDAV requests
|
||||
type Client http.Client
|
||||
|
||||
// downcasts the client to the local HTTP interface
|
||||
func (c *Client) Http() *http.Client {
|
||||
return (*http.Client)(c)
|
||||
}
|
||||
|
||||
// returns the embedded WebDav server reference
|
||||
func (c *Client) Server() *Server {
|
||||
return (*Server)(c.Http().Server())
|
||||
}
|
||||
|
||||
// executes a WebDAV request
|
||||
func (c *Client) Do(req *Request) (*Response, error) {
|
||||
if resp, err := c.Http().Do((*http.Request)(req)); err != nil {
|
||||
return nil, utils.NewError(c.Do, "unable to execute WebDAV request", c, err)
|
||||
} else {
|
||||
return NewResponse(resp), nil
|
||||
}
|
||||
}
|
||||
|
||||
// checks if a resource exists given a particular path
|
||||
func (c *Client) Exists(path string) (bool, error) {
|
||||
if req, err := c.Server().NewRequest("HEAD", path); err != nil {
|
||||
return false, utils.NewError(c.Exists, "unable to create request", c, err)
|
||||
} else if resp, err := c.Do(req); err != nil {
|
||||
return false, utils.NewError(c.Exists, "unable to execute request", c, err)
|
||||
} else {
|
||||
return resp.StatusCode != nhttp.StatusNotFound, nil
|
||||
}
|
||||
}
|
||||
|
||||
// deletes a resource if it exists on a particular path
|
||||
func (c *Client) Delete(path string) error {
|
||||
if req, err := c.Server().NewRequest("DELETE", path); err != nil {
|
||||
return utils.NewError(c.Delete, "unable to create request", c, err)
|
||||
} else if resp, err := c.Do(req); err != nil {
|
||||
return utils.NewError(c.Delete, "unable to execute request", c, err)
|
||||
} else if resp.StatusCode != nhttp.StatusNoContent && resp.StatusCode != nhttp.StatusNotFound {
|
||||
err := new(entities.Error)
|
||||
resp.Decode(err)
|
||||
msg := fmt.Sprintf("unexpected server response %s", resp.Status)
|
||||
return utils.NewError(c.Delete, msg, c, err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// fetches a list of WebDAV features supported by the server
|
||||
// returns an error if the server does not support DAV
|
||||
func (c *Client) Features(path string) ([]string, error) {
|
||||
if req, err := c.Server().NewRequest("OPTIONS", path); err != nil {
|
||||
return []string{}, utils.NewError(c.Features, "unable to create request", c, err)
|
||||
} else if resp, err := c.Do(req); err != nil {
|
||||
return []string{}, utils.NewError(c.Features, "unable to execute request", c, err)
|
||||
} else {
|
||||
return resp.Features(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// returns an error if the server does not support WebDAV
|
||||
func (c *Client) ValidateServer(path string) error {
|
||||
if features, err := c.Features(path); err != nil {
|
||||
return utils.NewError(c.ValidateServer, "feature detection failed", c, err)
|
||||
} else if len(features) <= 0 {
|
||||
return utils.NewError(c.ValidateServer, "no DAV headers found", c, err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// executes a PROPFIND request against the WebDAV server
|
||||
// returns a multistatus XML entity
|
||||
func (c *Client) Propfind(path string, depth Depth, pf *entities.Propfind) (*entities.Multistatus, error) {
|
||||
|
||||
ms := new(entities.Multistatus)
|
||||
|
||||
if req, err := c.Server().NewRequest("PROPFIND", path, pf); err != nil {
|
||||
return nil, utils.NewError(c.Propfind, "unable to create request", c, err)
|
||||
} else if req.Http().Native().Header.Set("Depth", string(depth)); depth == "" {
|
||||
return nil, utils.NewError(c.Propfind, "search depth must be defined", c, nil)
|
||||
} else if resp, err := c.Do(req); err != nil {
|
||||
return nil, utils.NewError(c.Propfind, "unable to execute request", c, err)
|
||||
} else if resp.StatusCode != StatusMulti {
|
||||
msg := fmt.Sprintf("unexpected status: %s", resp.Status)
|
||||
return nil, utils.NewError(c.Propfind, msg, c, nil)
|
||||
} else if err := resp.Decode(ms); err != nil {
|
||||
return nil, utils.NewError(c.Propfind, "unable to decode response", c, err)
|
||||
}
|
||||
|
||||
return ms, nil
|
||||
|
||||
}
|
||||
|
||||
// creates a new client for communicating with an WebDAV server
|
||||
func NewClient(server *Server, native *nhttp.Client) *Client {
|
||||
return (*Client)(http.NewClient((*http.Server)(server), native))
|
||||
}
|
||||
|
||||
// creates a new client for communicating with a WebDAV server
|
||||
// uses the default HTTP client from net/http
|
||||
func NewDefaultClient(server *Server) *Client {
|
||||
return NewClient(server, nhttp.DefaultClient)
|
||||
}
|
9
vendor/github.com/dolanor/caldav-go/webdav/depth.go
generated
vendored
Normal file
9
vendor/github.com/dolanor/caldav-go/webdav/depth.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package webdav
|
||||
|
||||
type Depth string
|
||||
|
||||
const (
|
||||
Depth0 Depth = "0"
|
||||
Depth1 = "1"
|
||||
DepthInfinity = "infinity"
|
||||
)
|
18
vendor/github.com/dolanor/caldav-go/webdav/entities/error.go
generated
vendored
Normal file
18
vendor/github.com/dolanor/caldav-go/webdav/entities/error.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package entities
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// a WebDAV error
|
||||
type Error struct {
|
||||
XMLName xml.Name `xml:"DAV: error"`
|
||||
Description string `xml:"error-description,omitempty"`
|
||||
Message string `xml:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e.Description != "" {
|
||||
return e.Description
|
||||
} else {
|
||||
return e.Message
|
||||
}
|
||||
}
|
23
vendor/github.com/dolanor/caldav-go/webdav/entities/multistatus.go
generated
vendored
Normal file
23
vendor/github.com/dolanor/caldav-go/webdav/entities/multistatus.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
package entities
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// metadata about a property
|
||||
type PropStat struct {
|
||||
XMLName xml.Name `xml:"propstat"`
|
||||
Status string `xml:"status"`
|
||||
Prop *Prop `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// a multistatus response entity
|
||||
type Response struct {
|
||||
XMLName xml.Name `xml:"response"`
|
||||
Href string `xml:"href"`
|
||||
PropStats []*PropStat `xml:"propstat,omitempty"`
|
||||
}
|
||||
|
||||
// a request to find properties on an an entity or collection
|
||||
type Multistatus struct {
|
||||
XMLName xml.Name `xml:"DAV: multistatus"`
|
||||
Responses []*Response `xml:"response,omitempty"`
|
||||
}
|
32
vendor/github.com/dolanor/caldav-go/webdav/entities/prop.go
generated
vendored
Normal file
32
vendor/github.com/dolanor/caldav-go/webdav/entities/prop.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// a property of a resource
|
||||
type Prop struct {
|
||||
XMLName xml.Name `xml:"DAV: prop"`
|
||||
GetContentType string `xml:"getcontenttype,omitempty"`
|
||||
DisplayName string `xml:"displayname,omitempty"`
|
||||
ResourceType *ResourceType `xml:",omitempty"`
|
||||
CTag string `xml:"http://calendarserver.org/ns/ getctag,omitempty"`
|
||||
ETag string `xml:"http://calendarserver.org/ns/ getetag,omitempty"`
|
||||
}
|
||||
|
||||
// the type of a resource
|
||||
type ResourceType struct {
|
||||
XMLName xml.Name `xml:"resourcetype"`
|
||||
Collection *ResourceTypeCollection `xml:",omitempty"`
|
||||
Calendar *ResourceTypeCalendar `xml:",omitempty"`
|
||||
}
|
||||
|
||||
// A calendar resource type
|
||||
type ResourceTypeCalendar struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:caldav calendar"`
|
||||
}
|
||||
|
||||
// A collection resource type
|
||||
type ResourceTypeCollection struct {
|
||||
XMLName xml.Name `xml:"collection"`
|
||||
}
|
20
vendor/github.com/dolanor/caldav-go/webdav/entities/propfind.go
generated
vendored
Normal file
20
vendor/github.com/dolanor/caldav-go/webdav/entities/propfind.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
package entities
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// a request to find properties on an an entity or collection
|
||||
type Propfind struct {
|
||||
XMLName xml.Name `xml:"DAV: propfind"`
|
||||
AllProp *AllProp `xml:",omitempty"`
|
||||
Props []*Prop `xml:"prop,omitempty"`
|
||||
}
|
||||
|
||||
// a propfind property representing all properties
|
||||
type AllProp struct {
|
||||
XMLName xml.Name `xml:"allprop"`
|
||||
}
|
||||
|
||||
// a convenience method for searching all properties
|
||||
func NewAllPropsFind() *Propfind {
|
||||
return &Propfind{AllProp: new(AllProp)}
|
||||
}
|
56
vendor/github.com/dolanor/caldav-go/webdav/request.go
generated
vendored
Normal file
56
vendor/github.com/dolanor/caldav-go/webdav/request.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
package webdav
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"github.com/dolanor/caldav-go/http"
|
||||
"github.com/dolanor/caldav-go/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ = log.Print
|
||||
|
||||
// an WebDAV request object
|
||||
type Request http.Request
|
||||
|
||||
// downcasts the request to the local HTTP interface
|
||||
func (r *Request) Http() *http.Request {
|
||||
return (*http.Request)(r)
|
||||
}
|
||||
|
||||
// creates a new WebDAV request object
|
||||
func NewRequest(method string, urlstr string, xmldata ...interface{}) (*Request, error) {
|
||||
if buffer, length, err := xmlToReadCloser(xmldata); err != nil {
|
||||
return nil, utils.NewError(NewRequest, "unable to encode xml data", xmldata, err)
|
||||
} else if r, err := http.NewRequest(method, urlstr, buffer); err != nil {
|
||||
return nil, utils.NewError(NewRequest, "unable to create request", urlstr, err)
|
||||
} else {
|
||||
if buffer != nil {
|
||||
// set the content type to XML if we have a body
|
||||
r.Native().Header.Set("Content-Type", "text/xml; charset=UTF-8")
|
||||
r.ContentLength = int64(length)
|
||||
}
|
||||
return (*Request)(r), nil
|
||||
}
|
||||
}
|
||||
|
||||
func xmlToReadCloser(xmldata ...interface{}) (io.ReadCloser, int, error) {
|
||||
var buffer []string
|
||||
for _, xmldatum := range xmldata {
|
||||
if encoded, err := xml.Marshal(xmldatum); err != nil {
|
||||
return nil, 0, utils.NewError(xmlToReadCloser, "unable to encode as xml", xmldatum, err)
|
||||
} else {
|
||||
buffer = append(buffer, string(encoded))
|
||||
}
|
||||
}
|
||||
if len(buffer) > 0 {
|
||||
var encoded = strings.Join(buffer, "\n")
|
||||
// log.Printf("[WebDAV Request]\n%+v\n", encoded)
|
||||
return ioutil.NopCloser(bytes.NewBuffer([]byte(encoded))), len(encoded), nil
|
||||
} else {
|
||||
return nil, 0, nil
|
||||
}
|
||||
}
|
54
vendor/github.com/dolanor/caldav-go/webdav/response.go
generated
vendored
Normal file
54
vendor/github.com/dolanor/caldav-go/webdav/response.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package webdav
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"github.com/dolanor/caldav-go/http"
|
||||
"github.com/dolanor/caldav-go/utils"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ = log.Print
|
||||
var _ = ioutil.ReadAll
|
||||
|
||||
// a WebDAV response object
|
||||
type Response http.Response
|
||||
|
||||
// downcasts the response to the local HTTP interface
|
||||
func (r *Response) Http() *http.Response {
|
||||
return (*http.Response)(r)
|
||||
}
|
||||
|
||||
// returns a list of WebDAV features found in the response
|
||||
func (r *Response) Features() (features []string) {
|
||||
if dav := r.Header.Get("DAV"); dav != "" {
|
||||
features = strings.Split(dav, ", ")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// decodes a WebDAV XML response into the provided interface
|
||||
func (r *Response) Decode(into interface{}) error {
|
||||
// data, _ := ioutil.ReadAll(r.Body)
|
||||
// log.Printf("[WebDAV Response]\n%+v\n", string(data))
|
||||
// if err := xml.Unmarshal(data, into); err != nil {
|
||||
// return utils.NewError(r.Decode, "unable to decode response body", r, err)
|
||||
// } else {
|
||||
// return nil
|
||||
// }
|
||||
if body := r.Body; body == nil {
|
||||
return nil
|
||||
} else if decoder := xml.NewDecoder(body); decoder == nil {
|
||||
return nil
|
||||
} else if err := decoder.Decode(into); err != nil {
|
||||
return utils.NewError(r.Decode, "unable to decode response body", r, err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// creates a new WebDAV response object
|
||||
func NewResponse(response *http.Response) *Response {
|
||||
return (*Response)(response)
|
||||
}
|
28
vendor/github.com/dolanor/caldav-go/webdav/server.go
generated
vendored
Normal file
28
vendor/github.com/dolanor/caldav-go/webdav/server.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
package webdav
|
||||
|
||||
import (
|
||||
"github.com/dolanor/caldav-go/http"
|
||||
"github.com/dolanor/caldav-go/utils"
|
||||
)
|
||||
|
||||
// a server that accepts WebDAV requests
|
||||
type Server http.Server
|
||||
|
||||
// creates a reference to an WebDAV server
|
||||
func NewServer(baseUrlStr string) (*Server, error) {
|
||||
if s, err := http.NewServer(baseUrlStr); err != nil {
|
||||
return nil, utils.NewError(NewServer, "unable to create WebDAV server", baseUrlStr, err)
|
||||
} else {
|
||||
return (*Server)(s), nil
|
||||
}
|
||||
}
|
||||
|
||||
// downcasts the server to the local HTTP interface
|
||||
func (s *Server) Http() *http.Server {
|
||||
return (*http.Server)(s)
|
||||
}
|
||||
|
||||
// creates a new WebDAV request object
|
||||
func (s *Server) NewRequest(method string, path string, xmldata ...interface{}) (*Request, error) {
|
||||
return NewRequest(method, s.Http().AbsUrlStr(path), xmldata...)
|
||||
}
|
Reference in New Issue
Block a user