mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-05 19:59:37 -06:00
@@ -0,0 +1,5 @@
|
||||
Change: Return not found when updating non existent space
|
||||
|
||||
If a spaceid of a space which is updated doesn't exist, handle it as a not found error.
|
||||
|
||||
https://github.com/cs3org/reva/pull/2869
|
||||
@@ -47,16 +47,16 @@ This is an extract of an element of the list spaces response. An entire object h
|
||||
Having introduced the above, one can refer to a Drive with the following URL format:
|
||||
|
||||
```console
|
||||
'https://localhost:9200/graph/v1.0/Drive(1284d238-aa92-42ce-bdc4-0b0000009157!07c26b3a-9944-4f2b-ab33-b0b326fc7570")
|
||||
'https://localhost:9200/graph/v1.0/drives/1284d238-aa92-42ce-bdc4-0b0000009157!07c26b3a-9944-4f2b-ab33-b0b326fc7570
|
||||
```
|
||||
|
||||
Updating an entity attribute:
|
||||
|
||||
```console
|
||||
curl -X PATCH 'https://localhost:9200/graph/v1.0/Drive("1284d238-aa92-42ce-bdc4-0b0000009157!07c26b3a-9944-4f2b-ab33-b0b326fc7570)' -d '{"name":"42"}' -v
|
||||
curl -X PATCH 'https://localhost:9200/graph/v1.0/drives/1284d238-aa92-42ce-bdc4-0b0000009157!07c26b3a-9944-4f2b-ab33-b0b326fc7570' -d '{"name":"42"}' -v
|
||||
```
|
||||
|
||||
The previous URL resource path segment (`Drive(1284d238-aa92-42ce-bdc4-0b0000009157!07c26b3a-9944-4f2b-ab33-b0b326fc7570)`) is parsed and handed over to the storage registry in order to apply the patch changes in the body, in this case update the space name attribute to `42`. Since space names are not unique we only support addressing them by their unique identifiers, any other query would render too ambiguous and explode in complexity.
|
||||
The previous URL resource path segment (`1284d238-aa92-42ce-bdc4-0b0000009157!07c26b3a-9944-4f2b-ab33-b0b326fc7570`) is parsed and handed over to the storage registry in order to apply the patch changes in the body, in this case update the space name attribute to `42`. Since space names are not unique we only support addressing them by their unique identifiers, any other query would render too ambiguous and explode in complexity.
|
||||
|
||||
|
||||
### Updating a space description
|
||||
|
||||
@@ -45,7 +45,7 @@ This the DRAFT for the API.
|
||||
|
||||
ownCloud servers provide an API to query for available spaces of an user.
|
||||
|
||||
See the openAPI Specification for the [open Graph API](https://owncloud.dev/open-graph-api/).
|
||||
See the openAPI Specification for the [Libre Graph API](https://owncloud.dev/libre-graph-api/).
|
||||
|
||||
Most important, the API returns the WebDAV endpoint for each space. With that, clients do not have to make assumptions about WebDAV routes any more.
|
||||
|
||||
@@ -80,8 +80,7 @@ The reply to both calls is either one or a list of [Drive representation objects
|
||||
"owner": { "@odata.type": "microsoft.graph.identitySet" },
|
||||
"quota": { "@odata.type": "microsoft.graph.quota" },
|
||||
"root": { "@odata.type": "microsoft.graph.driveItem" },
|
||||
"webUrl": "url",
|
||||
"ocCoOwner": [ { "@odata.type": "microsoft.graph.identitySet" } ]
|
||||
"webUrl": "url"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -93,7 +92,6 @@ The meaning of the objects in Open Graph API context are:
|
||||
4. **quota** - quota information about this space
|
||||
5. **root** - the root driveItem object.
|
||||
6. **webUrl** - The URL to make this space visible in the browser.
|
||||
7. **ocCoOwner** - optional array owner objects of the co-owners of a space (*)
|
||||
|
||||
The following *driveType* values are available in the first step, but might be enhanced later:
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@@ -19,7 +19,7 @@ require (
|
||||
github.com/blevesearch/bleve/v2 v2.2.2
|
||||
github.com/coreos/go-oidc/v3 v3.1.0
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20211104090126-8e972dca8304
|
||||
github.com/cs3org/reva v1.17.0
|
||||
github.com/cs3org/reva v1.17.1-0.20211212151213-778de37266ff
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
|
||||
4
go.sum
4
go.sum
@@ -299,8 +299,8 @@ github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S
|
||||
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20211104090126-8e972dca8304 h1:e/nIPR518vyvrulo9goAZTtYD6gFfu/2/9MDe6mTGcw=
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20211104090126-8e972dca8304/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
|
||||
github.com/cs3org/reva v1.17.0 h1:UVdiiK6gUF2pb7qN9TKhMuf55sUKVnCcVjiVSzodluw=
|
||||
github.com/cs3org/reva v1.17.0/go.mod h1:gtsVzMfDrUiUjH6qlHx+QqiRKsSYjVO6wEcCzANiqUg=
|
||||
github.com/cs3org/reva v1.17.1-0.20211212151213-778de37266ff h1:IUj5GfxDa8WgNzeH+5MnJREzjoneejygmnMgU2hAWCg=
|
||||
github.com/cs3org/reva v1.17.1-0.20211212151213-778de37266ff/go.mod h1:gtsVzMfDrUiUjH6qlHx+QqiRKsSYjVO6wEcCzANiqUg=
|
||||
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
|
||||
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
@@ -21,6 +20,7 @@ import (
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
ctxpkg "github.com/cs3org/reva/pkg/ctx"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
|
||||
@@ -240,7 +240,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
newDrive, err := cs3StorageSpaceToDrive(wdu, resp.StorageSpace)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("error parsing url")
|
||||
g.logger.Error().Err(err).Msg("error parsing space")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -249,22 +249,14 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
// wildcards however addressed here is not yet supported. We want to address drives by their unique
|
||||
// identifiers. Any open queries need to be implemented. Same applies for sub-entities.
|
||||
// For further reading: http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_AddressingaSubsetofaCollection
|
||||
|
||||
// strip "/graph/v1.0/" out and parse the rest. This is how godata input is expected.
|
||||
//https://github.com/CiscoM31/godata/blob/d70e191d2908191623be84401fecc40d6af4afde/url_parser_test.go#L10
|
||||
sanitized := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
||||
|
||||
req, err := godata.ParseRequest(r.Context(), sanitized, r.URL.Query())
|
||||
driveID, err := url.PathUnescape(chi.URLParam(r, "driveID"))
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping drive id failed")
|
||||
return
|
||||
}
|
||||
|
||||
if req.FirstSegment.Identifier.Get() == "" {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusBadRequest, "identifier cannot be empty")
|
||||
if driveID == "" {
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing drive id")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -274,9 +266,9 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
identifierParts := strings.Split(req.FirstSegment.Identifier.Get(), "!")
|
||||
identifierParts := strings.Split(driveID, "!")
|
||||
if len(identifierParts) != 2 {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusBadRequest, fmt.Sprintf("invalid resource id: %v", req.FirstSegment.Identifier.Get()))
|
||||
errorcode.GeneralException.Render(w, r, http.StatusBadRequest, fmt.Sprintf("invalid resource id: %v", driveID))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -294,7 +286,7 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
// the original storage space.
|
||||
StorageSpace: &provider.StorageSpace{
|
||||
Id: &storageprovider.StorageSpaceId{
|
||||
OpaqueId: req.FirstSegment.Identifier.Get(),
|
||||
OpaqueId: driveID,
|
||||
},
|
||||
Root: &provider.ResourceId{
|
||||
StorageId: storageID,
|
||||
@@ -330,11 +322,32 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if resp.GetStatus().GetCode() != v1beta11.Code_CODE_OK {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "")
|
||||
switch resp.Status.GetCode() {
|
||||
case v1beta11.Code_CODE_NOT_FOUND:
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, resp.GetStatus().GetMessage())
|
||||
return
|
||||
default:
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, resp.GetStatus().GetMessage())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
wdu, err := url.Parse(g.config.Spaces.WebDavBase + g.config.Spaces.WebDavPath)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("error parsing url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
updatedDrive, err := cs3StorageSpaceToDrive(wdu, resp.StorageSpace)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("error parsing space")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, updatedDrive)
|
||||
}
|
||||
|
||||
func cs3TimestampToTime(t *types.Timestamp) time.Time {
|
||||
|
||||
@@ -85,9 +85,9 @@ func NewService(opts ...Option) Service {
|
||||
r.Route("/drives", func(r chi.Router) {
|
||||
r.Get("/", svc.GetDrives)
|
||||
r.Post("/", svc.CreateDrive)
|
||||
})
|
||||
r.Route("/Drive({firstSegmentIdentifier})", func(r chi.Router) {
|
||||
r.Patch("/*", svc.UpdateDrive)
|
||||
r.Route("/{driveID}", func(r chi.Router) {
|
||||
r.Patch("/", svc.UpdateDrive)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,9 +11,9 @@ Feature: Change data of space
|
||||
And the administrator has given "Alice" the role "Admin" using the settings api
|
||||
|
||||
Scenario: Alice changes a name of the space via the Graph api, she expects a 204 code and checks that the space name has changed
|
||||
Given user "Alice" has created a space "Project Jupiter" of type "project" with quota "20"
|
||||
Given user "Alice" has created a space "Project Jupiter" of type "project" with quota "20"
|
||||
When user "Alice" changes the name of the "Project Jupiter" space to "Project Death Star"
|
||||
Then the HTTP status code should be "204"
|
||||
Then the HTTP status code should be "200"
|
||||
When user "Alice" lists all available spaces via the GraphApi
|
||||
Then the json responded should contain a space "Project Death Star" with these key and value pairs:
|
||||
| key | value |
|
||||
@@ -23,12 +23,11 @@ Feature: Change data of space
|
||||
| root@@@webDavUrl | %base_url%/dav/spaces/%space_id% |
|
||||
|
||||
Scenario: Alice increases quota of the space via the Graph api, she expects a 204 code and checks that the quota has changed
|
||||
Given user "Alice" has created a space "Project Earth" of type "project" with quota "20"
|
||||
Given user "Alice" has created a space "Project Earth" of type "project" with quota "20"
|
||||
When user "Alice" changes the quota of the "Project Earth" space to "100"
|
||||
Then the HTTP status code should be "204"
|
||||
Then the HTTP status code should be "200"
|
||||
When user "Alice" lists all available spaces via the GraphApi
|
||||
Then the json responded should contain a space "Project Earth" with these key and value pairs:
|
||||
| key | value |
|
||||
| name | Project Earth |
|
||||
| quota@@@total | 100 |
|
||||
|
||||
@@ -187,11 +187,11 @@ class SpacesContext implements Context {
|
||||
*/
|
||||
public function getSpaceByName(string $user, string $name): array {
|
||||
$this->theUserListsAllHisAvailableSpacesUsingTheGraphApi($user);
|
||||
|
||||
|
||||
$spaces = $this->getAvailableSpaces();
|
||||
Assert::assertIsArray($spaces[$name], "Space with name $name for user $user not found");
|
||||
Assert::assertNotEmpty($spaces[$name]["root"]["webDavUrl"], "WebDavUrl for space with name $name for user $user not found");
|
||||
|
||||
|
||||
return $spaces[$name];
|
||||
}
|
||||
|
||||
@@ -802,7 +802,7 @@ class SpacesContext implements Context {
|
||||
string $spaceName
|
||||
): void {
|
||||
$space = $this->getSpaceByName($user, $spaceName);
|
||||
|
||||
|
||||
$baseUrl = $this->featureContext->getBaseUrl();
|
||||
if (!str_ends_with($baseUrl, '/')) {
|
||||
$baseUrl .= '/';
|
||||
@@ -838,7 +838,7 @@ class SpacesContext implements Context {
|
||||
string $ownerUser
|
||||
): void {
|
||||
$space = $this->getSpaceByName($ownerUser, $spaceName);
|
||||
|
||||
|
||||
$baseUrl = $this->featureContext->getBaseUrl();
|
||||
if (!str_ends_with($baseUrl, '/')) {
|
||||
$baseUrl .= '/';
|
||||
@@ -1044,7 +1044,7 @@ class SpacesContext implements Context {
|
||||
if (!str_ends_with($fullUrl, '/')) {
|
||||
$fullUrl .= '/';
|
||||
}
|
||||
$fullUrl .= "graph/v1.0/Drive($spaceId)";
|
||||
$fullUrl .= "graph/v1.0/drives/$spaceId";
|
||||
$method = 'PATCH';
|
||||
|
||||
return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, $method, $user, $password, $headers, $body);
|
||||
@@ -1090,7 +1090,7 @@ class SpacesContext implements Context {
|
||||
*/
|
||||
public function userHasUploadedFile(string $user, string $spaceName, string $fileContent, string $destination):void {
|
||||
$this->theUserListsAllHisAvailableSpacesUsingTheGraphApi($user);
|
||||
|
||||
|
||||
$space = $this->getSpaceByName($user, $spaceName);
|
||||
Assert::assertIsArray($space, "Space with name $spaceName not found");
|
||||
Assert::assertNotEmpty($space["root"]["webDavUrl"], "WebDavUrl for space with name $spaceName not found");
|
||||
|
||||
Reference in New Issue
Block a user