diff --git a/changelog/unreleased/align-href-url-encoding-with-oc10.md b/changelog/unreleased/align-href-url-encoding-with-oc10.md new file mode 100644 index 0000000000..e79ef2db01 --- /dev/null +++ b/changelog/unreleased/align-href-url-encoding-with-oc10.md @@ -0,0 +1,8 @@ +Bugfix: Align href URL encoding with oc10 + +We now use the same percent encoding for URLs in WebDAV href properties as ownCloud 10. + +https://github.com/cs3org/reva/pull/1425 +https://github.com/owncloud/ocis/issues/1120 +https://github.com/owncloud/ocis/issues/1296 +https://github.com/owncloud/ocis/issues/1307 \ No newline at end of file diff --git a/internal/http/services/owncloud/ocdav/ocdav.go b/internal/http/services/owncloud/ocdav/ocdav.go index ba82880388..48ae4b53f4 100644 --- a/internal/http/services/owncloud/ocdav/ocdav.go +++ b/internal/http/services/owncloud/ocdav/ocdav.go @@ -25,6 +25,7 @@ import ( "net/http" "net/url" "path" + "regexp" "strings" "time" @@ -272,3 +273,36 @@ func extractDestination(dstHeader, baseURI string) (string, error) { return urlSplit[1], nil } + +// replaceAllStringSubmatchFunc is taken from 'Go: Replace String with Regular Expression Callback' +// see: https://elliotchance.medium.com/go-replace-string-with-regular-expression-callback-f89948bad0bb +func replaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string { + result := "" + lastIndex := 0 + for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) { + groups := []string{} + for i := 0; i < len(v); i += 2 { + groups = append(groups, str[v[i]:v[i+1]]) + } + result += str[lastIndex:v[0]] + repl(groups) + lastIndex = v[1] + } + return result + str[lastIndex:] +} + +var hrefre = regexp.MustCompile(`([^A-Za-z0-9_\-.~()/:@])`) + +// encodePath encodes the path of a url. +// +// slashes (/) are treated as path-separators. +// ported from https://github.com/sabre-io/http/blob/bb27d1a8c92217b34e778ee09dcf79d9a2936e84/lib/functions.php#L369-L379 +func encodePath(path string) string { + return replaceAllStringSubmatchFunc(hrefre, path, func(groups []string) string { + b := groups[1] + var sb strings.Builder + for i := 0; i < len(b); i++ { + sb.WriteString(fmt.Sprintf("%%%x", b[i])) + } + return sb.String() + }) +} diff --git a/internal/http/services/owncloud/ocdav/propfind.go b/internal/http/services/owncloud/ocdav/propfind.go index 32d4b1082a..39dec0ff39 100644 --- a/internal/http/services/owncloud/ocdav/propfind.go +++ b/internal/http/services/owncloud/ocdav/propfind.go @@ -26,11 +26,9 @@ import ( "fmt" "io" "net/http" - "net/url" "path" "strconv" "strings" - "time" "go.opencensus.io/trace" @@ -51,6 +49,9 @@ const ( _nsOCS = "http://open-collaboration-services.org/ns" _propOcFavorite = "http://owncloud.org/ns/favorite" + + // RFC1123 time that mimics oc10. time.RFC1123 would end in "UTC", see https://github.com/golang/go/issues/13781 + RFC1123 = "Mon, 02 Jan 2006 15:04:05 GMT" ) // ns is the namespace that is prefixed to the path in the cs3 namespace @@ -281,22 +282,31 @@ func (s *svc) formatPropfind(ctx context.Context, pf *propfindXML, mds []*provid return msg, nil } -func (s *svc) xmlEscaped(val string) string { +func (s *svc) xmlEscaped(val string) []byte { buf := new(bytes.Buffer) xml.Escape(buf, []byte(val)) - return buf.String() + return buf.Bytes() } func (s *svc) newPropNS(namespace string, local string, val string) *propertyXML { return &propertyXML{ XMLName: xml.Name{Space: namespace, Local: local}, Lang: "", - InnerXML: []byte(val), + InnerXML: s.xmlEscaped(val), } } // TODO properly use the space func (s *svc) newProp(key, val string) *propertyXML { + return &propertyXML{ + XMLName: xml.Name{Space: "", Local: key}, + Lang: "", + InnerXML: s.xmlEscaped(val), + } +} + +// TODO properly use the space +func (s *svc) newPropRaw(key, val string) *propertyXML { return &propertyXML{ XMLName: xml.Name{Space: "", Local: key}, Lang: "", @@ -319,7 +329,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide } response := responseXML{ - Href: (&url.URL{Path: ref}).EscapedPath(), // url encode response.Href + Href: encodePath(ref), Propstat: []propstatXML{}, } @@ -336,7 +346,11 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide isShared := !isCurrentUserOwner(ctx, md.Owner) var wdp string - if md.PermissionSet != nil { + switch { + case ls != nil: + // link share only appears on root collection + wdp = "" + case md.PermissionSet != nil: wdp = role.WebDAVPermissions( md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER, isShared, @@ -346,17 +360,21 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide sublog.Debug().Interface("role", role).Str("dav-permissions", wdp).Msg("converted PermissionSet") } + propstatOK := propstatXML{ + Status: "HTTP/1.1 200 OK", + Prop: []*propertyXML{}, + } + propstatNotFound := propstatXML{ + Status: "HTTP/1.1 404 Not Found", + Prop: []*propertyXML{}, + } // when allprops has been requested if pf.Allprop != nil { // return all known properties - response.Propstat = append(response.Propstat, propstatXML{ - Status: "HTTP/1.1 200 OK", - Prop: []*propertyXML{}, - }) if md.Id != nil { id := wrapResourceID(md.Id) - response.Propstat[0].Prop = append(response.Propstat[0].Prop, + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:id", id), s.newProp("oc:fileid", id), ) @@ -366,35 +384,35 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide // etags must be enclosed in double quotes and cannot contain them. // See https://tools.ietf.org/html/rfc7232#section-2.3 for details // TODO(jfd) handle weak tags that start with 'W/' - response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("d:getetag", md.Etag)) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getetag", md.Etag)) } if md.PermissionSet != nil { - response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:permissions", wdp)) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:permissions", wdp)) } - // always return size + // always return size, well nearly always ... public link shares are a little weird size := fmt.Sprintf("%d", md.Size) if md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER { - response.Propstat[0].Prop = append(response.Propstat[0].Prop, - s.newProp("d:resourcetype", ""), - s.newProp("d:getcontenttype", "httpd/unix-directory"), - s.newProp("oc:size", size), - ) + propstatOK.Prop = append(propstatOK.Prop, s.newPropRaw("d:resourcetype", "")) + if ls == nil { + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:size", size)) + } } else { - response.Propstat[0].Prop = append(response.Propstat[0].Prop, + propstatOK.Prop = append(propstatOK.Prop, + s.newProp("d:resourcetype", ""), s.newProp("d:getcontentlength", size), ) if md.MimeType != "" { - response.Propstat[0].Prop = append(response.Propstat[0].Prop, - s.newProp("d:getcontenttype", md.MimeType), - ) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getcontenttype", md.MimeType)) } } // Finder needs the getLastModified property to work. - t := utils.TSToTime(md.Mtime).UTC() - lastModifiedString := t.Format(time.RFC1123Z) - response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("d:getlastmodified", lastModifiedString)) + if md.Mtime != nil { + t := utils.TSToTime(md.Mtime).UTC() + lastModifiedString := t.Format(RFC1123) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getlastmodified", lastModifiedString)) + } // stay bug compatible with oc10, see https://github.com/owncloud/core/pull/38304#issuecomment-762185241 var checksums strings.Builder @@ -424,30 +442,25 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide } if checksums.Len() > 0 { checksums.WriteString("") - response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:checksums", checksums.String())) + propstatOK.Prop = append(propstatOK.Prop, s.newPropRaw("oc:checksums", checksums.String())) } - // favorites from arbitrary metadata - if k := md.GetArbitraryMetadata(); k == nil { - 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[_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")) + // ls do not report any properties as missing by default + if ls == nil { + // favorites from arbitrary metadata + if k := md.GetArbitraryMetadata(); k == nil { + 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[_propOcFavorite]; ok && v != "" { + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", v)) + } else { + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "0")) + } } // TODO return other properties ... but how do we put them in a namespace? } else { // otherwise return only the requested properties - propstatOK := propstatXML{ - Status: "HTTP/1.1 200 OK", - Prop: []*propertyXML{}, - } - propstatNotFound := propstatXML{ - Status: "HTTP/1.1 404 Not Found", - Prop: []*propertyXML{}, - } size := fmt.Sprintf("%d", md.Size) for i := range pf.Prop { switch pf.Prop[i].Space { @@ -504,7 +517,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide case "public-link-share-datetime": if ls != nil && ls.Mtime != nil { t := utils.TSToTime(ls.Mtime).UTC() // TODO or ctime? - shareTimeString := t.Format(time.RFC1123Z) + shareTimeString := t.Format(RFC1123) propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:public-link-share-datetime", shareTimeString)) } else { propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:public-link-share-datetime", "")) @@ -525,7 +538,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide case "public-link-expiration": if ls != nil && ls.Expiration != nil { t := utils.TSToTime(ls.Expiration).UTC() - expireTimeString := t.Format(time.RFC1123Z) + expireTimeString := t.Format(RFC1123) propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:public-link-expiration", expireTimeString)) } else { propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:public-link-expiration", "")) @@ -534,12 +547,17 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide case "size": // phoenix only // TODO we cannot find out if md.Size is set or not because ints in go default to 0 // oc:size is also available on folders - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:size", size)) + if ls == nil { + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:size", size)) + } else { + // link share root collection has no size + propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:size", "")) + } case "owner-id": // phoenix only if md.Owner != nil { if isCurrentUserOwner(ctx, md.Owner) { u := ctxuser.ContextMustGetUser(ctx) - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:owner-id", s.xmlEscaped(u.Username))) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:owner-id", u.Username)) } else { sublog.Debug().Msg("TODO fetch user username") propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:owner-id", "")) @@ -551,14 +569,19 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide // TODO: can be 0 or 1?, in oc10 it is present or not // TODO: read favorite via separate call? that would be expensive? I hope it is in the md // TODO: this boolean favorite property is so horribly wrong ... either it is presont, or it is not ... unless ... it is possible to have a non binary value ... we need to double check - if k := md.GetArbitraryMetadata(); k == nil { - 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[_propOcFavorite]; ok && v != "" { - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "1")) + if ls == nil { + if k := md.GetArbitraryMetadata(); k == nil { + 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[_propOcFavorite]; ok && v != "" { + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "1")) + } else { + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "0")) + } } else { - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:favorite", "0")) + // link share root collection has no favorite + propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:favorite", "")) } case "checksums": // desktop ... not really ... the desktop sends the OC-Checksum header @@ -590,7 +613,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide } if checksums.Len() > 13 { checksums.WriteString("") - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:checksums", checksums.String())) + propstatOK.Prop = append(propstatOK.Prop, s.newPropRaw("oc:checksums", checksums.String())) } else { propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:checksums", "")) } @@ -599,7 +622,7 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide amd := k.GetMetadata() if amdv, ok := amd[metadataKeyOf(&pf.Prop[i])]; ok { st := fmt.Sprintf("%s", amdv) - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:share-types", st)) + propstatOK.Prop = append(propstatOK.Prop, s.newPropRaw("oc:share-types", st)) } else { propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, "")) } @@ -653,22 +676,27 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide } case "resourcetype": // both if md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER { - propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:resourcetype", "")) + propstatOK.Prop = append(propstatOK.Prop, s.newPropRaw("d:resourcetype", "")) } else { propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:resourcetype", "")) // redirectref is another option } case "getcontenttype": // phoenix if md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER { - propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getcontenttype", "httpd/unix-directory")) + // directories have no contenttype + propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("d:getcontenttype", "")) } else if md.MimeType != "" { propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getcontenttype", md.MimeType)) } case "getlastmodified": // both // TODO we cannot find out if md.Mtime is set or not because ints in go default to 0 - t := utils.TSToTime(md.Mtime).UTC() - lastModifiedString := t.Format(time.RFC1123Z) - propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getlastmodified", lastModifiedString)) + if md.Mtime != nil { + t := utils.TSToTime(md.Mtime).UTC() + lastModifiedString := t.Format(RFC1123) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("d:getlastmodified", lastModifiedString)) + } else { + propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("d:getlastmodified", "")) + } default: propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("d:"+pf.Prop[i].Local, "")) } @@ -707,12 +735,13 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide } } } - if len(propstatOK.Prop) > 0 { - response.Propstat = append(response.Propstat, propstatOK) - } - if len(propstatNotFound.Prop) > 0 { - response.Propstat = append(response.Propstat, propstatNotFound) - } + } + + if len(propstatOK.Prop) > 0 { + response.Propstat = append(response.Propstat, propstatOK) + } + if len(propstatNotFound.Prop) > 0 { + response.Propstat = append(response.Propstat, propstatNotFound) } return &response, nil @@ -820,7 +849,7 @@ type propertyXML struct { Lang string `xml:"xml:lang,attr,omitempty"` // InnerXML contains the XML representation of the property value. - // See http://www.ocwebdav.org/specs/rfc4918.html#property_values + // See http://www.webdav.org/specs/rfc4918.html#property_values // // Property values of complex type or mixed-content must have fully // expanded XML namespaces or be self-contained with according diff --git a/internal/http/services/owncloud/ocdav/proppatch.go b/internal/http/services/owncloud/ocdav/proppatch.go index fd83cd762a..a8fe5933a0 100644 --- a/internal/http/services/owncloud/ocdav/proppatch.go +++ b/internal/http/services/owncloud/ocdav/proppatch.go @@ -24,7 +24,6 @@ import ( "fmt" "io" "net/http" - "net/url" "path" "strings" @@ -176,7 +175,7 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string) func (s *svc) formatProppatchResponse(ctx context.Context, acceptedProps []xml.Name, removedProps []xml.Name, ref string) (string, error) { responses := make([]responseXML, 0, 1) response := responseXML{ - Href: (&url.URL{Path: ref}).EscapedPath(), // url encode response.Href + Href: encodePath(ref), Propstat: []propstatXML{}, } diff --git a/internal/http/services/owncloud/ocdav/publicfile.go b/internal/http/services/owncloud/ocdav/publicfile.go index cbb3bc944b..a87e84c8da 100644 --- a/internal/http/services/owncloud/ocdav/publicfile.go +++ b/internal/http/services/owncloud/ocdav/publicfile.go @@ -24,12 +24,13 @@ import ( rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/rhttp/router" "go.opencensus.io/trace" ) -// PublicFileHandler handles trashbin requests +// PublicFileHandler handles requests on a shared file. it needs to be wrapped in a collection type PublicFileHandler struct { namespace string } @@ -177,39 +178,15 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s return } - infos := []*provider.ResourceInfo{} - - if onContainer { - // TODO: filter out metadata like favorite and arbitrary metadata - if depth != "0" { - // if the request is to a public link, we need to add yet another value for the file entry. - infos = append(infos, &provider.ResourceInfo{ - // append the shared as a container. Annex to OC10 standards. - Id: tokenStatInfo.Id, - Path: tokenStatInfo.Path, - Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER, - Mtime: tokenStatInfo.Mtime, - Size: tokenStatInfo.Size, - Etag: tokenStatInfo.Etag, - PermissionSet: tokenStatInfo.PermissionSet, - }) - } - } else if path.Base(r.URL.Path) != path.Base(pathRes.Path) { + if !onContainer && path.Base(r.URL.Path) != path.Base(pathRes.Path) { // if queried on the wrong path, return not found w.WriteHeader(http.StatusNotFound) return } + // adjust path + tokenStatInfo.Path = path.Join("/", tokenStatInfo.Path, path.Base(pathRes.Path)) - infos = append(infos, &provider.ResourceInfo{ - Id: tokenStatInfo.Id, - Path: path.Join("/", tokenStatInfo.Path, path.Base(pathRes.Path)), - Type: tokenStatInfo.Type, - Size: tokenStatInfo.Size, - MimeType: tokenStatInfo.MimeType, - Mtime: tokenStatInfo.Mtime, - Etag: tokenStatInfo.Etag, - PermissionSet: tokenStatInfo.PermissionSet, - }) + infos := s.getPublicFileInfos(onContainer, depth == "0", tokenStatInfo) propRes, err := s.formatPropfind(ctx, &pf, infos, ns) if err != nil { @@ -225,3 +202,40 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s sublog.Err(err).Msg("error writing response") } } + +// there are only two possible entries +// 1. the non existing collection +// 2. the shared file +func (s *svc) getPublicFileInfos(onContainer, onlyRoot bool, i *provider.ResourceInfo) []*provider.ResourceInfo { + infos := []*provider.ResourceInfo{} + if onContainer { + // copy link-share data if present + // we don't copy everything because the checksum should not be present + var o *typesv1beta1.Opaque + if i.Opaque != nil && i.Opaque.Map != nil && i.Opaque.Map["link-share"] != nil { + o = &typesv1beta1.Opaque{ + Map: map[string]*typesv1beta1.OpaqueEntry{ + "link-share": i.Opaque.Map["link-share"], + }, + } + } + // always add collection + infos = append(infos, &provider.ResourceInfo{ + // Opaque carries the link-share data we need when rendering the collection root href + Opaque: o, + Path: path.Dir(i.Path), + Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER, + }) + if onlyRoot { + return infos + } + } + + // link share only appears on root collection + delete(i.Opaque.Map, "link-share") + + // add the file info + infos = append(infos, i) + + return infos +} diff --git a/internal/http/services/owncloud/ocdav/trashbin.go b/internal/http/services/owncloud/ocdav/trashbin.go index c734f7ab71..23c258c230 100644 --- a/internal/http/services/owncloud/ocdav/trashbin.go +++ b/internal/http/services/owncloud/ocdav/trashbin.go @@ -23,8 +23,8 @@ import ( "encoding/xml" "fmt" "net/http" - "net/url" "path" + "path/filepath" "strings" "time" @@ -203,7 +203,7 @@ func (h *TrashbinHandler) formatTrashPropfind(ctx context.Context, s *svc, u *us responses := make([]*responseXML, 0, len(items)+1) // add trashbin dir . entry responses = append(responses, &responseXML{ - Href: (&url.URL{Path: ctx.Value(ctxKeyBaseURI).(string) + "/"}).EscapedPath(), // url encode response.Href TODO (jfd) really? /should be ok ... we may actually only need to escape the username + Href: encodePath(ctx.Value(ctxKeyBaseURI).(string) + "/"), // url encode response.Href TODO Propstat: []propstatXML{ { Status: "HTTP/1.1 200 OK", @@ -224,7 +224,7 @@ func (h *TrashbinHandler) formatTrashPropfind(ctx context.Context, s *svc, u *us }) for i := range items { - res, err := h.itemToPropResponse(ctx, s, pf, items[i]) + res, err := h.itemToPropResponse(ctx, s, u, pf, items[i]) if err != nil { return "", err } @@ -244,16 +244,16 @@ func (h *TrashbinHandler) formatTrashPropfind(ctx context.Context, s *svc, u *us // itemToPropResponse needs to create a listing that contains a key and destination // the key is the name of an entry in the trash listing // for now we need to limit trash to the users home, so we can expect all trash keys to have the home storage as the opaque id -func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, pf *propfindXML, item *provider.RecycleItem) (*responseXML, error) { +func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, u *userpb.User, pf *propfindXML, item *provider.RecycleItem) (*responseXML, error) { baseURI := ctx.Value(ctxKeyBaseURI).(string) - ref := path.Join(baseURI, item.Key) + ref := path.Join(baseURI, u.Username, item.Key) if item.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER { ref += "/" } response := responseXML{ - Href: (&url.URL{Path: ref}).EscapedPath(), // url encode response.Href + Href: encodePath(ref), // url encode response.Href Propstat: []propstatXML{}, } @@ -270,7 +270,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, pf *pr Prop: []*propertyXML{}, }) // yes this is redundant, can be derived from oc:trashbin-original-location which contains the full path, clients should not fetch it - response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-original-filename", strings.TrimPrefix(item.Path, "/"))) + response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-original-filename", filepath.Base(item.Path))) response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-original-location", strings.TrimPrefix(item.Path, "/"))) response.Propstat[0].Prop = append(response.Propstat[0].Prop, s.newProp("oc:trashbin-delete-datetime", dTime)) if item.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER { @@ -306,7 +306,7 @@ func (h *TrashbinHandler) itemToPropResponse(ctx context.Context, s *svc, pf *pr } case "trashbin-original-filename": // yes this is redundant, can be derived from oc:trashbin-original-location which contains the full path, clients should not fetch it - propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:trashbin-original-filename", strings.TrimPrefix(item.Path, "/"))) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:trashbin-original-filename", filepath.Base(item.Path))) case "trashbin-original-location": // TODO (jfd) double check and clarify the cs3 spec what the Key is about and if Path is only the folder that contains the file or if it includes the filename propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:trashbin-original-location", strings.TrimPrefix(item.Path, "/"))) diff --git a/tests/acceptance/expected-failures-on-OCIS-storage.md b/tests/acceptance/expected-failures-on-OCIS-storage.md index 4bd837e0a9..74bfc36869 100644 --- a/tests/acceptance/expected-failures-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-on-OCIS-storage.md @@ -5,12 +5,8 @@ Basic file management like up and download, move, copy, properties, trash, versi #### [Implement Trashbin Feature for ocis storage](https://github.com/owncloud/product/issues/209) -- [apiWebdavEtagPropagation2/restoreFromTrash.feature:26](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L26) -- [apiWebdavEtagPropagation2/restoreFromTrash.feature:27](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L27) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:48](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L48) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:49](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L49) -- [apiWebdavEtagPropagation2/restoreFromTrash.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L68) -- [apiWebdavEtagPropagation2/restoreFromTrash.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L69) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:90](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L90) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:91](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L91) @@ -18,24 +14,10 @@ Basic file management like up and download, move, copy, properties, trash, versi - [apiTrashbin/trashbinFilesFolders.feature:284](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L284) - [apiTrashbin/trashbinFilesFolders.feature:285](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L285) -#### [empty trashbin does not work](https://github.com/owncloud/product/issues/254) -- [apiTrashbin/trashbinDelete.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L37) - -#### [href in trashbin PROPFIND response is wrong](https://github.com/owncloud/ocis/issues/1120) -- [apiTrashbin/trashbinDelete.feature:50](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L50) -- [apiTrashbin/trashbinDelete.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L67) - -#### [href in trashbin PROPFIND response is wrong](https://github.com/owncloud/ocis/issues/1120) #### [QA trashcan cannot delete a deep tree](https://github.com/owncloud/ocis/issues/1077) - [apiTrashbin/trashbinDelete.feature:107](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L107) - [apiTrashbin/trashbinDelete.feature:123](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L123) -#### [trashbin filename invalid for nested files/folders](https://github.com/owncloud/product/issues/255) -- [apiTrashbin/trashbinFilesFolders.feature:44](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L44) -- [apiTrashbin/trashbinFilesFolders.feature:45](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L45) -- [apiTrashbin/trashbinFilesFolders.feature:60](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L60) -- [apiTrashbin/trashbinFilesFolders.feature:61](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L61) - #### [invalid webdav responses for unauthorized requests.](https://github.com/owncloud/product/issues/273) - [apiTrashbin/trashbinFilesFolders.feature:154](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L154) - [apiTrashbin/trashbinFilesFolders.feature:155](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L155) @@ -331,35 +313,7 @@ Scenario Outline: try to create a folder with a name of an existing file - [apiWebdavProperties1/createFolder.feature:99](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L99) - [apiWebdavProperties1/createFolder.feature:100](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L100) -#### [XML properties in webdav response not properly encoded](https://github.com/owncloud/ocis/issues/1296) -Scenario Outline: Do a PROPFIND of various file names -- [apiWebdavProperties2/getFileProperties.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L37) -- [apiWebdavProperties2/getFileProperties.feature:39](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L39) -- [apiWebdavProperties2/getFileProperties.feature:40](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L40) -- [apiWebdavProperties2/getFileProperties.feature:41](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L41) -- [apiWebdavProperties2/getFileProperties.feature:43](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L43) -- [apiWebdavProperties2/getFileProperties.feature:44](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L44) - -Scenario Outline: Do a PROPFIND of various folder names -- [apiWebdavProperties2/getFileProperties.feature:59](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L59) -- [apiWebdavProperties2/getFileProperties.feature:60](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L60) -- [apiWebdavProperties2/getFileProperties.feature:61](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L61) -- [apiWebdavProperties2/getFileProperties.feature:63](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L63) -- [apiWebdavProperties2/getFileProperties.feature:64](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L64) -- [apiWebdavProperties2/getFileProperties.feature:66](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L66) -- [apiWebdavProperties2/getFileProperties.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L67) -- [apiWebdavProperties2/getFileProperties.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L68) -- [apiWebdavProperties2/getFileProperties.feature:70](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L70) -- [apiWebdavProperties2/getFileProperties.feature:71](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L71) - ### [Different webdav properties from core](https://github.com/owncloud/ocis/issues/1302) -Scenario Outline: Propfind the last modified date of a folder using webdav api `Property "d:getlastmodified" found with value "Wed, 20 Jan 2021 14:39:31 +0000", expected "/^[MTWFS][uedhfriatno]{2},\s(\d){2}\s[JFMAJSOND][anebrpyulgctov]{2}\s\d{4}\s\d{2}:\d{2}:\d{2} GMT$/"` -- [apiWebdavProperties2/getFileProperties.feature:301](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L301) -- [apiWebdavProperties2/getFileProperties.feature:302](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L302) -Scenario Outline: Propfind the content type of a folder using webdav api `Property "d:getcontenttype" found with value "httpd/unix-directory", expected "#^$#" or "#^$#"` -- [apiWebdavProperties2/getFileProperties.feature:314](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L314) -- [apiWebdavProperties2/getFileProperties.feature:315](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L315) -Scenario Outline: Propfind the content type of a file using webdav api `Property "d:getcontenttype" found with value "text/plain; charset=utf-8", expected "#^text/plain$#" or "#^text/plain$#"` - [apiWebdavProperties2/getFileProperties.feature:327](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L327) - [apiWebdavProperties2/getFileProperties.feature:328](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L328) Scenario Outline: Propfind the size of a folder using webdav api `Property "oc:size" found with value "10", expected "#^0$#" or "#^0$#"` @@ -1387,6 +1341,9 @@ File and sync features in a shared scenario - [apiTrashbin/trashbinSharingToShares.feature:103](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinSharingToShares.feature#L103) - [apiTrashbin/trashbinSharingToShares.feature:104](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinSharingToShares.feature#L104) +#### shared trash status code +- [apiTrashbin/trashbinDelete.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L67) Scenario: User tries to delete another user's trashbin `status code: expected 401, actual 405` + #### [remote.php/dav/uploads endpoint does not exist](https://github.com/owncloud/ocis/issues/1321) - [apiShareOperationsToShares/uploadToShare.feature:246](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares/uploadToShare.feature#L246) diff --git a/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md b/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md index af45ead12f..848d8a1329 100644 --- a/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md +++ b/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md @@ -4,9 +4,6 @@ Basic file management like up and download, move, copy, properties, trash, versions and chunking. #### [Implement Trashbin Feature for ocis storage](https://github.com/owncloud/product/issues/209) - -- [apiWebdavEtagPropagation2/restoreFromTrash.feature:26](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L26) -- [apiWebdavEtagPropagation2/restoreFromTrash.feature:27](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L27) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:48](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L48) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:49](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L49) - [apiWebdavEtagPropagation2/restoreFromTrash.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation2/restoreFromTrash.feature#L68) @@ -18,24 +15,10 @@ Basic file management like up and download, move, copy, properties, trash, versi - [apiTrashbin/trashbinFilesFolders.feature:284](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L284) - [apiTrashbin/trashbinFilesFolders.feature:285](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L285) -#### [empty trashbin does not work](https://github.com/owncloud/product/issues/254) -- [apiTrashbin/trashbinDelete.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L37) - -#### [href in trashbin PROPFIND response is wrong](https://github.com/owncloud/ocis/issues/1120) -- [apiTrashbin/trashbinDelete.feature:50](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L50) -- [apiTrashbin/trashbinDelete.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L67) - -#### [href in trashbin PROPFIND response is wrong](https://github.com/owncloud/ocis/issues/1120) #### [QA trashcan cannot delete a deep tree](https://github.com/owncloud/ocis/issues/1077) - [apiTrashbin/trashbinDelete.feature:107](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L107) - [apiTrashbin/trashbinDelete.feature:123](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L123) -#### [trashbin filename invalid for nested files/folders](https://github.com/owncloud/product/issues/255) -- [apiTrashbin/trashbinFilesFolders.feature:44](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L44) -- [apiTrashbin/trashbinFilesFolders.feature:45](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L45) -- [apiTrashbin/trashbinFilesFolders.feature:60](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L60) -- [apiTrashbin/trashbinFilesFolders.feature:61](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L61) - ### [Review and fix the tests that have sharing step to work with ocis](https://github.com/owncloud/core/issues/38006) The following scenarios fail on OWNCLOUD storage but not on OCIS storage: @@ -350,44 +333,17 @@ Scenario Outline: try to create a folder that already exists - [apiWebdavProperties1/createFolder.feature:99](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L99) - [apiWebdavProperties1/createFolder.feature:100](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L100) -#### [XML properties in webdav response not properly encoded](https://github.com/owncloud/ocis/issues/1296) -Scenario Outline: Do a PROPFIND of various file names -- [apiWebdavProperties2/getFileProperties.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L37) -- [apiWebdavProperties2/getFileProperties.feature:39](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L39) -- [apiWebdavProperties2/getFileProperties.feature:40](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L40) -- [apiWebdavProperties2/getFileProperties.feature:41](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L41) -- [apiWebdavProperties2/getFileProperties.feature:43](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L43) -- [apiWebdavProperties2/getFileProperties.feature:44](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L44) - -Scenario Outline: Do a PROPFIND of various folder names -- [apiWebdavProperties2/getFileProperties.feature:59](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L59) -- [apiWebdavProperties2/getFileProperties.feature:60](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L60) -- [apiWebdavProperties2/getFileProperties.feature:61](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L61) -- [apiWebdavProperties2/getFileProperties.feature:63](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L63) -- [apiWebdavProperties2/getFileProperties.feature:64](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L64) -- [apiWebdavProperties2/getFileProperties.feature:66](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L66) -- [apiWebdavProperties2/getFileProperties.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L67) -- [apiWebdavProperties2/getFileProperties.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L68) -- [apiWebdavProperties2/getFileProperties.feature:70](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L70) -- [apiWebdavProperties2/getFileProperties.feature:71](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L71) - ### [Different webdav properties from core](https://github.com/owncloud/ocis/issues/1302) -Scenario Outline: Propfind the last modified date of a folder using webdav api `Property "d:getlastmodified" found with value "Wed, 20 Jan 2021 14:39:31 +0000", expected "/^[MTWFS][uedhfriatno]{2},\s(\d){2}\s[JFMAJSOND][anebrpyulgctov]{2}\s\d{4}\s\d{2}:\d{2}:\d{2} GMT$/"` -- [apiWebdavProperties2/getFileProperties.feature:301](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L301) -- [apiWebdavProperties2/getFileProperties.feature:302](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L302) - Scenario Outline: Propfind the content type of a folder using webdav api `Property "d:getcontenttype" found with value "httpd/unix-directory", expected "#^$#" or "#^$#"` -- [apiWebdavProperties2/getFileProperties.feature:314](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L314) -- [apiWebdavProperties2/getFileProperties.feature:315](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L315) - Scenario Outline: Propfind the content type of a file using webdav api `Property "d:getcontenttype" found with value "text/plain; charset=utf-8", expected "#^text/plain$#" or "#^text/plain$#"` +Scenario Outline: Propfind the content type of a file using webdav api `Property "d:getcontenttype" found with value "text/plain; charset=utf-8", expected "#^text/plain$#" or "#^text/plain$#"` - [apiWebdavProperties2/getFileProperties.feature:327](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L327) - [apiWebdavProperties2/getFileProperties.feature:328](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L328) - Scenario Outline: Propfind the size of a folder using webdav api `Property "oc:size" found with value "10", expected "#^0$#" or "#^0$#"` +Scenario Outline: Propfind the size of a folder using webdav api `Property "oc:size" found with value "10", expected "#^0$#" or "#^0$#"` - [apiWebdavProperties2/getFileProperties.feature:376](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L376) - [apiWebdavProperties2/getFileProperties.feature:377](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L377) - Scenario Outline: Propfind the permissions on a file using webdav api `Property "oc:permissions" found with value "DNVWR", expected "/RM{0,1}DNVW/"` +Scenario Outline: Propfind the permissions on a file using webdav api `Property "oc:permissions" found with value "DNVWR", expected "/RM{0,1}DNVW/"` - [apiWebdavProperties2/getFileProperties.feature:441](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L441) - [apiWebdavProperties2/getFileProperties.feature:442](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L442) - Scenario Outline: Propfind the permissions on a folder using webdav api `Property "oc:permissions" found with value "DNVCKR", expected "/RM{0,1}DNVCK/"` +Scenario Outline: Propfind the permissions on a folder using webdav api `Property "oc:permissions" found with value "DNVCKR", expected "/RM{0,1}DNVCK/"` - [apiWebdavProperties2/getFileProperties.feature:454](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L454) - [apiWebdavProperties2/getFileProperties.feature:455](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L455) @@ -1487,6 +1443,9 @@ The following scenarios fail on OWNCLOUD storage but not on OCIS storage: - [apiTrashbin/trashbinSharingToShares.feature:103](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinSharingToShares.feature#L103) - [apiTrashbin/trashbinSharingToShares.feature:104](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinSharingToShares.feature#L104) +#### shared trash status code +- [apiTrashbin/trashbinDelete.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinDelete.feature#L67) Scenario: User tries to delete another user's trashbin `status code: expected 401, actual 405` + #### [remote.php/dav/uploads endpoint does not exist](https://github.com/owncloud/ocis/issues/1321) - [apiShareOperationsToShares/uploadToShare.feature:246](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares/uploadToShare.feature#L246) diff --git a/tests/acceptance/features/apiOcisSpecific/apiTrashbin-trashbinDelete.feature b/tests/acceptance/features/apiOcisSpecific/apiTrashbin-trashbinDelete.feature deleted file mode 100644 index 21cb15a6fb..0000000000 --- a/tests/acceptance/features/apiOcisSpecific/apiTrashbin-trashbinDelete.feature +++ /dev/null @@ -1,30 +0,0 @@ -@api @files_trashbin-app-required -Feature: files and folders can be deleted from the trashbin - As a user - I want to delete files and folders from the trashbin - So that I can control my trashbin space and which files are kept in that space - - Background: - Given user "Alice" has been created with default attributes and without skeleton files - And user "Alice" has uploaded file with content "to delete" to "/textfile0.txt" - And user "Alice" has uploaded file with content "to delete" to "/textfile1.txt" - And user "Alice" has created folder "PARENT" - And user "Alice" has created folder "PARENT/CHILD" - And user "Alice" has uploaded file with content "to delete" to "/PARENT/parent.txt" - And user "Alice" has uploaded file with content "to delete" to "/PARENT/CHILD/child.txt" - - @smokeTest - @issue-ocis-reva-118 - @issue-product-179 @skipOnOcis-OCIS-Storage - # after fixing all issues delete this Scenario and use the one from oC10 core - Scenario: delete a single file from the trashbin - Given user "Alice" has deleted file "/textfile0.txt" - And user "Alice" has deleted file "/textfile1.txt" - And user "Alice" has deleted file "/PARENT/parent.txt" - And user "Alice" has deleted file "/PARENT/CHILD/child.txt" - When user "Alice" deletes the file with original path "textfile1.txt" from the trashbin using the trashbin API - Then the HTTP status code should be "405" - And as "Alice" the file with original path "/textfile1.txt" should exist in the trashbin - But as "Alice" the file with original path "/textfile0.txt" should exist in the trashbin - And as "Alice" the file with original path "/PARENT/parent.txt" should exist in the trashbin - And as "Alice" the file with original path "/PARENT/CHILD/child.txt" should exist in the trashbin diff --git a/tests/acceptance/features/apiOcisSpecific/apiWebdavProperties2-getFileProperties.feature b/tests/acceptance/features/apiOcisSpecific/apiWebdavProperties2-getFileProperties.feature index 0379ea9e08..545ddb01d9 100644 --- a/tests/acceptance/features/apiOcisSpecific/apiWebdavProperties2-getFileProperties.feature +++ b/tests/acceptance/features/apiOcisSpecific/apiWebdavProperties2-getFileProperties.feature @@ -8,36 +8,6 @@ Feature: get file properties Given using OCS API version "1" And user "Alice" has been created with default attributes and without skeleton files - @issue-ocis-reva-214 @skipOnOcis-OCIS-Storage - # after fixing all issues delete this Scenario and use the one from oC10 core - Scenario Outline: Do a PROPFIND of various file names - Given using DAV path - And user "Alice" has uploaded file with content "uploaded content" to "" - When user "Alice" gets the properties of file "" using the WebDAV API - Then the properties response should contain an etag - And the value of the item "//d:response/d:href" in the response to user "Alice" should match "/remote\.php\//" - Examples: - | dav_version | file_name | expected_href | - | old | /C++ file.cpp | webdav\/C\+\+%20file\.cpp | - | old | /file #2.txt | webdav\/file%20%232\.txt | - | old | /file &2.txt | webdav\/file%20&2\.txt | - | new | /C++ file.cpp | dav\/files\/%username%\/C\+\+%20file\.cpp | - | new | /file #2.txt | dav\/files\/%username%\/file%20%232\.txt | - | new | /file &2.txt | dav\/files\/%username%\/file%20&2\.txt | - - @issue-ocis-reva-214 @issue-ocis-reva-265 @skipOnOcis-EOS-Storage @skipOnOcis-OCIS-Storage - # after fixing all issues delete this Scenario and use the one from oC10 core - Scenario Outline: Do a PROPFIND of various file names - Given using DAV path - And user "Alice" has uploaded file with content "uploaded content" to "" - When user "Alice" gets the properties of file "" using the WebDAV API - Then the properties response should contain an etag - And the value of the item "//d:response/d:href" in the response to user "Alice" should match "/remote\.php\//" - Examples: - | dav_version | file_name | expected_href | - | old | /file ?2.txt | webdav\/file%20%3F2\.txt | - | new | /file ?2.txt | dav\/files\/%username%\/file%20%3F2\.txt | - @skipOnOcis-OC-Storage @issue-ocis-reva-265 @skipOnOcis-OCIS-Storage # after fixing all issues delete this Scenario and use the one from oC10 core Scenario Outline: upload a file to content @@ -49,62 +19,6 @@ Feature: get file properties | old | /file ?2.txt | | new | /file ?2.txt | - @issue-ocis-reva-214 @skipOnOcis-OCIS-Storage - # after fixing all issues delete this Scenario and use the one from oC10 core - Scenario Outline: Do a PROPFIND of various folder names - Given using DAV path - And user "Alice" has created folder "" - And user "Alice" has uploaded file with content "uploaded content" to "/file1.txt" - And user "Alice" has uploaded file with content "uploaded content" to "/file2.txt" - When user "Alice" gets the properties of folder "" with depth 1 using the WebDAV API - Then the value of the item "//d:response[1]/d:href" in the response to user "Alice" should match "/remote\.php\/\//" - And the value of the item "//d:response[2]/d:href" in the response to user "Alice" should match "/remote\.php\/\/file1.txt/" - And the value of the item "//d:response[3]/d:href" in the response to user "Alice" should match "/remote\.php\/\/file2.txt/" - Examples: - | dav_version | folder_name | expected_href | - | old | /upload | webdav\/upload | - | old | /strängé folder | webdav\/str%C3%A4ng%C3%A9%20folder | - | old | /C++ folder | webdav\/C\+\+%20folder | - | old | /नेपाली | webdav\/%E0%A4%A8%E0%A5%87%E0%A4%AA%E0%A4%BE%E0%A4%B2%E0%A5%80 | - | old | /folder #2.txt | webdav\/folder%20%232\.txt | - | old | /folder &2.txt | webdav\/folder%20&2\.txt | - - @issue-ocis-reva-214 @skipOnOcis-OCIS-Storage - # after fixing all issues delete this Scenario and use the one from oC10 core - Scenario Outline: Do a PROPFIND of various folder names - Given using DAV path - And user "Alice" has created folder "" - And user "Alice" has uploaded file with content "uploaded content" to "/file1.txt" - And user "Alice" has uploaded file with content "uploaded content" to "/file2.txt" - When user "Alice" gets the properties of folder "" with depth 1 using the WebDAV API - Then the value of the item "//d:response[1]/d:href" in the response to user "Alice" should match "/remote\.php\/\//" - And the value of the item "//d:response[2]/d:href" in the response to user "Alice" should match "/remote\.php\/\/file1.txt/" - And the value of the item "//d:response[3]/d:href" in the response to user "Alice" should match "/remote\.php\/\/file2.txt/" - Examples: - | dav_version | folder_name | expected_href | - | new | /upload | dav\/files\/%username%\/upload | - | new | /strängé folder | dav\/files\/%username%\/str%C3%A4ng%C3%A9%20folder | - | new | /C++ folder | dav\/files\/%username%\/C\+\+%20folder | - | new | /नेपाली | dav\/files\/%username%\/%E0%A4%A8%E0%A5%87%E0%A4%AA%E0%A4%BE%E0%A4%B2%E0%A5%80 | - | new | /folder #2.txt | dav\/files\/%username%\/folder%20%232\.txt | - | new | /folder &2.txt | dav\/files\/%username%\/folder%20&2\.txt | - - @issue-ocis-reva-214 @skipOnOcis-EOS-Storage @issue-ocis-reva-265 @skipOnOcis-OCIS-Storage - # after fixing all issues delete this Scenario and use the one from oC10 core - Scenario Outline: Do a PROPFIND of various folder names - Given using DAV path - And user "Alice" has created folder "" - And user "Alice" has uploaded file with content "uploaded content" to "/file1.txt" - And user "Alice" has uploaded file with content "uploaded content" to "/file2.txt" - When user "Alice" gets the properties of folder "" with depth 1 using the WebDAV API - Then the value of the item "//d:response[1]/d:href" in the response to user "Alice" should match "/remote\.php\/\//" - And the value of the item "//d:response[2]/d:href" in the response to user "Alice" should match "/remote\.php\/\/file1.txt/" - And the value of the item "//d:response[3]/d:href" in the response to user "Alice" should match "/remote\.php\/\/file2.txt/" - Examples: - | dav_version | folder_name | expected_href | - | old | /folder ?2.txt | webdav\/folder%20%3F2\.txt | - | new | /folder ?2.txt | dav\/files\/%username%\/folder%20%3F2\.txt | - @skipOnOcis-OC-Storage @issue-ocis-reva-265 @skipOnOcis-OCIS-Storage # after fixing all issues delete this Scenario and use the one from oC10 core Scenario Outline: Do a PROPFIND of various folder names