Skip to content

Commit

Permalink
allow setting favorites, mtime and a temporary etag (#1393)
Browse files Browse the repository at this point in the history
  • Loading branch information
butonic authored Jan 14, 2021
1 parent 96e60b8 commit c212a4e
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 75 deletions.
7 changes: 7 additions & 0 deletions changelog/unreleased/ocis-favorites-etags-mtime-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: allow setting favorites, mtime and a temporary etag

We now let the ocis driver persist favorites, set temporary etags and the mtime as arbitrary metadata.

https://github.com/cs3org/reva/pull/1393
https://github.com/owncloud/ocis/issues/567
https://github.com/cs3org/reva/issues/1394
69 changes: 53 additions & 16 deletions internal/http/services/owncloud/ocdav/propfind.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ import (
"github.com/pkg/errors"
)

const (
_nsDav = "DAV:"
_nsOwncloud = "http://owncloud.org/ns"
_nsOCS = "http://open-collaboration-services.org/ns"

_propOcFavorite = "http://owncloud.org/ns/favorite"
)

// ns is the namespace that is prefixed to the path in the cs3 namespace
func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string) {
ctx := r.Context()
Expand Down Expand Up @@ -98,14 +106,23 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string)
return
}

metadataKeys := []string{}
if pf.Allprop != nil {
metadataKeys = append(metadataKeys, "*")
} else {
for i := range pf.Prop {
if requiresExplicitFetching(&pf.Prop[i]) {
metadataKeys = append(metadataKeys, metadataKeyOf(&pf.Prop[i]))
}
}
}

info := res.Info
infos := []*provider.ResourceInfo{info}
if info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER && depth == "1" {
req := &provider.ListContainerRequest{
Ref: ref,
ArbitraryMetadataKeys: []string{
"http://owncloud.org/ns/share-types",
},
Ref: ref,
ArbitraryMetadataKeys: metadataKeys,
}
res, err := client.ListContainer(ctx, req)
if err != nil {
Expand All @@ -130,10 +147,8 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string)
Spec: &provider.Reference_Path{Path: path},
}
req := &provider.ListContainerRequest{
Ref: ref,
ArbitraryMetadataKeys: []string{
"http://owncloud.org/ns/share-types",
},
Ref: ref,
ArbitraryMetadataKeys: metadataKeys,
}
res, err := client.ListContainer(ctx, req)
if err != nil {
Expand Down Expand Up @@ -188,6 +203,23 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string)
}
}

func requiresExplicitFetching(n *xml.Name) bool {
switch n.Space {
case _nsDav:
return false
case _nsOwncloud:
switch n.Local {
case "favorite", "share-types":
return true
default:
return false
}
case _nsOCS:
return false
}
return true
}

// from https://github.com/golang/net/blob/e514e69ffb8bc3c76a71ae40de0118d794855992/webdav/xml.go#L178-L205
func readPropfind(r io.Reader) (pf propfindXML, status int, err error) {
c := countingReader{r: r}
Expand Down Expand Up @@ -253,6 +285,7 @@ func (s *svc) newPropNS(namespace string, local string, val string) *propertyXML
}
}

// TODO properly use the space
func (s *svc) newProp(key, val string) *propertyXML {
return &propertyXML{
XMLName: xml.Name{Space: "", Local: key},
Expand Down Expand Up @@ -368,8 +401,8 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:favorite", "0"))
} else if amd := k.GetMetadata(); amd == nil {
response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:favorite", "0"))
} else if v, ok := amd["http://owncloud.org/ns/favorite"]; ok && v != "" {
response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:favorite", "1"))
} else if v, ok := amd[_propOcFavorite]; ok && v != "" {
response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:favorite", v))
} else {
response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:favorite", "0"))
}
Expand All @@ -387,7 +420,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
size := fmt.Sprintf("%d", md.Size)
for i := range pf.Prop {
switch pf.Prop[i].Space {
case "http://owncloud.org/ns":
case _nsOwncloud:
switch pf.Prop[i].Local {
// TODO(jfd): maybe phoenix and the other clients can just use this id as an opaque string?
// I tested the desktop client and phoenix to annotate which properties are requestted, see below cases
Expand Down Expand Up @@ -491,7 +524,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "0"))
} else if amd := k.GetMetadata(); amd == nil {
propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "0"))
} else if v, ok := amd["http://owncloud.org/ns/favorite"]; ok && v != "" {
} else if v, ok := amd[_propOcFavorite]; ok && v != "" {
propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "1"))
} else {
propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "0"))
Expand All @@ -511,7 +544,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
case "share-types": // desktop
k := md.GetArbitraryMetadata()
amd := k.GetMetadata()
if amdv, ok := amd[fmt.Sprintf("%s/%s", pf.Prop[i].Space, pf.Prop[i].Local)]; ok {
if amdv, ok := amd[metadataKeyOf(&pf.Prop[i])]; ok {
st := fmt.Sprintf("<oc:share-type>%s</oc:share-type>", amdv)
propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:share-types", st))
} else {
Expand Down Expand Up @@ -546,7 +579,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
default:
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, ""))
}
case "DAV:":
case _nsDav:
switch pf.Prop[i].Local {
case "getetag": // both
if md.Etag != "" {
Expand Down Expand Up @@ -586,7 +619,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
default:
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("d:"+pf.Prop[i].Local, ""))
}
case "http://open-collaboration-services.org/ns":
case _nsOCS:
switch pf.Prop[i].Local {
// ocs:share-permissions indicate clients the maximum permissions that can be granted:
// 1 = read
Expand Down Expand Up @@ -614,7 +647,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newPropNS(pf.Prop[i].Space, pf.Prop[i].Local, ""))
} else if amd := k.GetMetadata(); amd == nil {
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newPropNS(pf.Prop[i].Space, pf.Prop[i].Local, ""))
} else if v, ok := amd[fmt.Sprintf("%s/%s", pf.Prop[i].Space, pf.Prop[i].Local)]; ok && v != "" {
} else if v, ok := amd[metadataKeyOf(&pf.Prop[i])]; ok && v != "" {
propstatOK.Prop = append(propstatOK.Prop, s.newPropNS(pf.Prop[i].Space, pf.Prop[i].Local, v))
} else {
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newPropNS(pf.Prop[i].Space, pf.Prop[i].Local, ""))
Expand Down Expand Up @@ -654,6 +687,10 @@ func (c *countingReader) Read(p []byte) (int, error) {
return n, err
}

func metadataKeyOf(n *xml.Name) string {
return fmt.Sprintf("%s/%s", n.Space, n.Local)
}

// http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for propfind)
type propfindProps []xml.Name

Expand Down
6 changes: 3 additions & 3 deletions internal/http/services/owncloud/ocdav/proppatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func (s *svc) formatProppatchResponse(ctx context.Context, acceptedProps []xml.N

func (s *svc) isBooleanProperty(prop string) bool {
// TODO add other properties we know to be boolean?
return prop == "http://owncloud.org/ns/favorite"
return prop == _propOcFavorite
}

func (s *svc) as0or1(val string) string {
Expand Down Expand Up @@ -307,9 +307,9 @@ func readProppatch(r io.Reader) (patches []Proppatch, status int, err error) {
for _, op := range pu.SetRemove {
remove := false
switch op.XMLName {
case xml.Name{Space: "DAV:", Local: "set"}:
case xml.Name{Space: _nsDav, Local: "set"}:
// No-op.
case xml.Name{Space: "DAV:", Local: "remove"}:
case xml.Name{Space: _nsDav, Local: "remove"}:
for _, p := range op.Prop {
if len(p.InnerXML) > 0 {
return nil, http.StatusBadRequest, errInvalidProppatch
Expand Down
4 changes: 2 additions & 2 deletions internal/http/services/owncloud/ocdav/trashbin.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, pf *pr
size := fmt.Sprintf("%d", item.Size)
for i := range pf.Prop {
switch pf.Prop[i].Space {
case "http://owncloud.org/ns":
case _nsOwncloud:
switch pf.Prop[i].Local {
case "oc:size":
if item.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
Expand All @@ -314,7 +314,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, pf *pr
default:
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, ""))
}
case "DAV:":
case _nsDav:
switch pf.Prop[i].Local {
case "getcontentlength":
if item.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
Expand Down
1 change: 1 addition & 0 deletions internal/http/services/owncloud/ocs/data/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type CapabilitiesFiles struct {
BigFileChunking ocsBool `json:"bigfilechunking" xml:"bigfilechunking"`
Undelete ocsBool `json:"undelete" xml:"undelete"`
Versioning ocsBool `json:"versioning" xml:"versioning"`
Favorites ocsBool `json:"favorites" xml:"favorites"`
BlacklistedFiles []string `json:"blacklisted_files" xml:"blacklisted_files>element" mapstructure:"blacklisted_files"`
TusSupport *CapabilitiesFilesTusSupport `json:"tus_support" xml:"tus_support" mapstructure:"tus_support"`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func (h *Handler) Init(c *config.Config) {
}
// h.c.Capabilities.Files.Undelete is boolean
// h.c.Capabilities.Files.Versioning is boolean
// h.c.Capabilities.Files.Favorites is boolean

// dav

Expand Down
Loading

0 comments on commit c212a4e

Please sign in to comment.