Merge pull request #2471 from owncloud/spaces-crud

This commit is contained in:
Alex Unger
2021-09-09 20:47:03 +02:00
committed by GitHub
8 changed files with 377 additions and 30 deletions

View File

@@ -0,0 +1,10 @@
Enhancement: Create a Space using the Graph API
Spaces can now be created on `POST /drives/{drive-name}`. Only users with the `create-space` permissions can perform this operation.
Allowed body form values are:
- `quota` (bytes) maximum amount of bytes stored in the space.
- `maxQuotaFiles` (integer) maximum amount of files supported by the space.
https://github.com/owncloud/ocis/pull/2471

View File

@@ -0,0 +1,257 @@
---
title: Spaces
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/graph
geekdocFilePath: spaces.md
---
{{< toc >}}
## Graph Service
The Graph service is a reference implementation of the MS Graph API. There are no libraries doing any work only a set of routes and handlers.
## Spaces API
The Spaces API makes use of the [MS Graph API Drive resource](https://docs.microsoft.com/en-us/graph/api/resources/drive?view=graph-rest-1.0) to represent the concept of a Storage Space. Natively the MS Graph Specification [does not provide a way for creating Drives](https://docs.microsoft.com/en-us/graph/api/resources/drive?view=graph-rest-1.0#methods), as a Drive is a read only resource.
We circumvented this limitation by adding a `POST /drive/{drive-name}` to the Graph router. A major drawback of this solution is that this endpoint does not have support from the official MS Graph SDK, however it is reachable by any HTTP clients.
### Methods
```
POST /drive/{drive-name}
```
Calls to the following endpoint will create a Space with all the default parameters since we do not parse the request body just yet.
## Examples
We can now create a `Marketing` space and retrieve its WebDAV endpoint. Let's see how to do this.
### Starting conditions
This is the status of a DecomposedFS `users` tree. As we can see it is empty because we have not yet logged in with any users. It is a fresh new installation.
```
tree -a /var/tmp/ocis/storage/users
/var/tmp/ocis/storage/users
├── blobs
├── nodes
│ └── root
├── spaces
│ ├── personal
│ └── share
├── trash
└── uploads
```
Let's start with creating a space:
`curl -k -X POST 'https://localhost:9200/graph/v1.0/drives/marketing' -u einstein:relativity -v`
```
tree -a /var/tmp/ocis/storage/users
/var/tmp/ocis/storage/users
├── blobs
├── nodes
│ ├── 02dc1ec5-28b5-41c5-a48a-fabd4fa0562e
│ │ └── .space -> ../e85d185f-cdaa-4618-a312-e33ea435acfe
│ ├── 52efe3c2-c95a-47a1-8f3d-924aa473c711
│ ├── e85d185f-cdaa-4618-a312-e33ea435acfe
│ └── root
│ ├── 4c510ada-c86b-4815-8820-42cdf82c3d51 -> ../52efe3c2-c95a-47a1-8f3d-924aa473c711
│ └── c42debb8-926e-4a46-83b0-39dba56e59a4 -> ../02dc1ec5-28b5-41c5-a48a-fabd4fa0562e
├── spaces
│ ├── personal
│ │ └── 52efe3c2-c95a-47a1-8f3d-924aa473c711 -> ../../nodes/52efe3c2-c95a-47a1-8f3d-924aa473c711
│ ├── project
│ │ └── 02dc1ec5-28b5-41c5-a48a-fabd4fa0562e -> ../../nodes/02dc1ec5-28b5-41c5-a48a-fabd4fa0562e
│ └── share
├── trash
└── uploads
```
we can see that the `project` folder was added to the spaces as well as the `.space` folder to the space node `02dc1ec5-28b5-41c5-a48a-fabd4fa0562e`. For demonstration purposes, let's list the extended attributes of the new node:
```
xattr -l /var/tmp/ocis/storage/users/nodes/root/c42debb8-926e-4a46-83b0-39dba56e59a4
user.ocis.blobid:
user.ocis.blobsize: 0
user.ocis.name: c42debb8-926e-4a46-83b0-39dba56e59a4
user.ocis.owner.id: 4c510ada-c86b-4815-8820-42cdf82c3d51
user.ocis.owner.idp: https://localhost:9200
user.ocis.owner.type: primary
user.ocis.parentid: root
user.ocis.quota: 65536
user.ocis.space.name: marketing
```
As seen here it contains the metadata from the default list of requirements for this ticket.
Let's list the drive we just created using the graph API:
```
curl -k 'https://localhost:9200/graph/v1.0/me/drives' -u einstein:relativity -v | jq .value
[
{
"driveType": "personal",
"id": "1284d238-aa92-42ce-bdc4-0b0000009157!52efe3c2-c95a-47a1-8f3d-924aa473c711",
"lastModifiedDateTime": "2021-09-07T14:42:39.025050471+02:00",
"name": "root",
"owner": {
"user": {
"id": "4c510ada-c86b-4815-8820-42cdf82c3d51"
}
},
"root": {
"id": "1284d238-aa92-42ce-bdc4-0b0000009157!52efe3c2-c95a-47a1-8f3d-924aa473c711",
"webDavUrl": "https://localhost:9200/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157!52efe3c2-c95a-47a1-8f3d-924aa473c711"
}
},
{
"driveType": "project",
"id": "1284d238-aa92-42ce-bdc4-0b0000009157!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e",
"lastModifiedDateTime": "2021-09-07T14:42:39.030705579+02:00",
"name": "root",
"owner": {
"user": {
"id": "4c510ada-c86b-4815-8820-42cdf82c3d51"
}
},
"quota": {
"total": 65536
},
"root": {
"id": "1284d238-aa92-42ce-bdc4-0b0000009157!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e",
"webDavUrl": "https://localhost:9200/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e"
}
}
]
As we can see the response already contains a space-aware dav endpoint, which we can use to upload files to the space:
```
curl -k https://localhost:9200/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157\!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e/test.txt -X PUT -d "beep-sboop" -v -u einstein:relativity
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9200 (#0)
* upload completely sent off: 10 out of 10 bytes
< HTTP/1.1 201 Created
< Access-Control-Allow-Origin: *
< Content-Length: 0
< Content-Security-Policy: default-src 'none';
< Content-Type: text/plain
< Date: Tue, 07 Sep 2021 12:45:54 GMT
< Etag: "e2942565a4eb52e8754c2806f215fe93"
< Last-Modified: Tue, 07 Sep 2021 12:45:54 +0000
< Oc-Etag: "e2942565a4eb52e8754c2806f215fe93"
< Oc-Fileid: MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OmU4ZDIwNDA5LTE1OWItNGI2Ny1iODZkLTlkM2U3ZjYyYmM0ZQ==
< Vary: Origin
< X-Content-Type-Options: nosniff
< X-Download-Options: noopen
< X-Frame-Options: SAMEORIGIN
< X-Permitted-Cross-Domain-Policies: none
< X-Robots-Tag: none
< X-Xss-Protection: 1; mode=block
<
* Connection #0 to host localhost left intact
* Closing connection 0
```
This is the state after every transformation:
```
tree -a /var/tmp/ocis/storage/users
/var/tmp/ocis/storage/users
├── blobs
│ └── 83842d56-91de-41d5-8800-b2fb7b2d31cf
├── nodes
│ ├── 02dc1ec5-28b5-41c5-a48a-fabd4fa0562e
│ │ ├── .space -> ../e85d185f-cdaa-4618-a312-e33ea435acfe
│ │ └── test.txt -> ../e8d20409-159b-4b67-b86d-9d3e7f62bc4e
│ ├── 52efe3c2-c95a-47a1-8f3d-924aa473c711
│ ├── e85d185f-cdaa-4618-a312-e33ea435acfe
│ ├── e8d20409-159b-4b67-b86d-9d3e7f62bc4e
│ └── root
│ ├── 4c510ada-c86b-4815-8820-42cdf82c3d51 -> ../52efe3c2-c95a-47a1-8f3d-924aa473c711
│ └── c42debb8-926e-4a46-83b0-39dba56e59a4 -> ../02dc1ec5-28b5-41c5-a48a-fabd4fa0562e
├── spaces
│ ├── personal
│ │ └── 52efe3c2-c95a-47a1-8f3d-924aa473c711 -> ../../nodes/52efe3c2-c95a-47a1-8f3d-924aa473c711
│ ├── project
│ │ └── 02dc1ec5-28b5-41c5-a48a-fabd4fa0562e -> ../../nodes/02dc1ec5-28b5-41c5-a48a-fabd4fa0562e
│ └── share
├── trash
└── uploads
```
Observe the `test.txt` in the `02dc1ec5-28b5-41c5-a48a-fabd4fa0562e` node.
To finalize, verify the new created file is webdav-listable:
```xml
curl -k https://localhost:9200/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157\!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e -X PROPFIND -v -u einstein:relativity | xmllint --format -
<?xml version="1.0" encoding="utf-8"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">
<d:response>
<d:href>/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e/</d:href>
<d:propstat>
<d:prop>
<oc:id>MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OjAyZGMxZWM1LTI4YjUtNDFjNS1hNDhhLWZhYmQ0ZmEwNTYyZQ==</oc:id>
<oc:fileid>MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OjAyZGMxZWM1LTI4YjUtNDFjNS1hNDhhLWZhYmQ0ZmEwNTYyZQ==</oc:fileid>
<d:getetag>"35a2ce5f56592d79d1b7233eff033347"</d:getetag>
<oc:permissions>RDNVCK</oc:permissions>
<d:resourcetype>
<d:collection/>
</d:resourcetype>
<oc:size>0</oc:size>
<d:getlastmodified>Tue, 07 Sep 2021 12:45:54 GMT</d:getlastmodified>
<oc:favorite>0</oc:favorite>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e/.space/</d:href>
<d:propstat>
<d:prop>
<oc:id>MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OmU4NWQxODVmLWNkYWEtNDYxOC1hMzEyLWUzM2VhNDM1YWNmZQ==</oc:id>
<oc:fileid>MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OmU4NWQxODVmLWNkYWEtNDYxOC1hMzEyLWUzM2VhNDM1YWNmZQ==</oc:fileid>
<d:getetag>"2e9a84bffce8b648ba626185800ee8fa"</d:getetag>
<oc:permissions>SRDNVCK</oc:permissions>
<d:resourcetype>
<d:collection/>
</d:resourcetype>
<oc:size>0</oc:size>
<d:getlastmodified>Tue, 07 Sep 2021 12:42:39 GMT</d:getlastmodified>
<oc:favorite>0</oc:favorite>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/dav/spaces/1284d238-aa92-42ce-bdc4-0b0000009157!02dc1ec5-28b5-41c5-a48a-fabd4fa0562e/test.txt</d:href>
<d:propstat>
<d:prop>
<oc:id>MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OmU4ZDIwNDA5LTE1OWItNGI2Ny1iODZkLTlkM2U3ZjYyYmM0ZQ==</oc:id>
<oc:fileid>MTI4NGQyMzgtYWE5Mi00MmNlLWJkYzQtMGIwMDAwMDA5MTU3OmU4ZDIwNDA5LTE1OWItNGI2Ny1iODZkLTlkM2U3ZjYyYmM0ZQ==</oc:fileid>
<d:getetag>"e2942565a4eb52e8754c2806f215fe93"</d:getetag>
<oc:permissions>RDNVW</oc:permissions>
<d:resourcetype/>
<d:getcontentlength>10</d:getcontentlength>
<d:getcontenttype>text/plain</d:getcontenttype>
<d:getlastmodified>Tue, 07 Sep 2021 12:45:54 GMT</d:getlastmodified>
<oc:checksums>
<oc:checksum>SHA1:8f4b4c83c565fc5ec54b78c30c94a6b65e411de5 MD5:6a3a4eca9a6726eef8f7be5b03ea9011 ADLER32:151303ed</oc:checksum>
</oc:checksums>
<oc:favorite>0</oc:favorite>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
```

12
go.mod
View File

@@ -20,11 +20,11 @@ require (
github.com/asim/go-micro/v3 v3.6.0
github.com/blevesearch/bleve/v2 v2.1.0
github.com/coreos/go-oidc/v3 v3.0.0
github.com/cs3org/go-cs3apis v0.0.0-20210812121411-f18cf19614e8
github.com/cs3org/reva v1.12.1-0.20210903075054-73f10ed5ab21
github.com/cs3org/go-cs3apis v0.0.0-20210906133842-03e4a408c1f3
github.com/cs3org/reva v1.12.1-0.20210908153040-a1a5d61a9ac0
github.com/disintegration/imaging v1.6.2
github.com/glauth/glauth v1.1.3-0.20210729125545-b9aecdfcac31
github.com/go-chi/chi/v5 v5.0.3
github.com/go-chi/chi/v5 v5.0.4
github.com/go-chi/render v1.0.1
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-logr/logr v0.4.0
@@ -61,11 +61,11 @@ require (
github.com/yaegashi/msgraph.go v0.1.4
go.opencensus.io v0.23.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.22.0
go.opentelemetry.io/otel v1.0.0-RC2
go.opentelemetry.io/otel v1.0.0-RC3
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC2
go.opentelemetry.io/otel/metric v0.20.0 // indirect
go.opentelemetry.io/otel/sdk v1.0.0-RC2
go.opentelemetry.io/otel/trace v1.0.0-RC2
go.opentelemetry.io/otel/sdk v1.0.0-RC3
go.opentelemetry.io/otel/trace v1.0.0-RC3
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
golang.org/x/net v0.0.0-20210614182718-04defd469f4e

16
go.sum
View File

@@ -178,6 +178,8 @@ github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.40.17 h1:WcE72YOL7ChzAWlgpEv9YMOqAwJDM1yzkv4GxWyS5wk=
github.com/aws/aws-sdk-go v1.40.17/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go v1.40.37 h1:I+Q6cLctkFyMMrKukcDnj+i2kjrQ37LGiOM6xmsxC48=
github.com/aws/aws-sdk-go v1.40.37/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
@@ -313,10 +315,16 @@ github.com/cs3org/go-cs3apis v0.0.0-20210802070913-970eec344e59 h1:cj9HxIbmbGn+H
github.com/cs3org/go-cs3apis v0.0.0-20210802070913-970eec344e59/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20210812121411-f18cf19614e8 h1:bqUkE0l5wD62TKH6HkbSVYwyYzZ0PIeak/hnW7ggUdU=
github.com/cs3org/go-cs3apis v0.0.0-20210812121411-f18cf19614e8/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20210906133842-03e4a408c1f3 h1:NcLk09WK4wx/iIrEI+7ZFbr78APaRKJxF0+zl6kv4is=
github.com/cs3org/go-cs3apis v0.0.0-20210906133842-03e4a408c1f3/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v1.12.0 h1:31Z+9+rLXUHRP3K6U3LK2wWLJUuicFjeFc2iZGg7rWE=
github.com/cs3org/reva v1.12.0/go.mod h1:Fx2PHTX2Y3s/aNG/APpCbmttg5STWnxjD4DpnqdwjQc=
github.com/cs3org/reva v1.12.1-0.20210903075054-73f10ed5ab21 h1:noPCV/0p9EkjpNUQs1K+/U3f+twBefGJSRaPunhI2TA=
github.com/cs3org/reva v1.12.1-0.20210903075054-73f10ed5ab21/go.mod h1:5dEcJZiu8FoxUYR+apy7lkBl5AGiXWwqBzmm/6zCRuE=
github.com/cs3org/reva v1.12.1-0.20210908151045-bd4575a9a056 h1:yChJgTjMJCgpY4tpSjwTgoXMGDYIn6qkMWDXkOsw8zE=
github.com/cs3org/reva v1.12.1-0.20210908151045-bd4575a9a056/go.mod h1:DfORq7oDhBndLw++i8FbHS06RUsFpPhfhJqX7YXpjyc=
github.com/cs3org/reva v1.12.1-0.20210908153040-a1a5d61a9ac0 h1:ewOfYFUaG0gOWCOyD09m764wNZX7o+h5SOm9aH7DiWY=
github.com/cs3org/reva v1.12.1-0.20210908153040-a1a5d61a9ac0/go.mod h1:DfORq7oDhBndLw++i8FbHS06RUsFpPhfhJqX7YXpjyc=
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=
@@ -408,6 +416,8 @@ github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAU
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.3 h1:khYQBdPivkYG1s1TAzDQG1f6eX4kD2TItYVZexL5rS4=
github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.4 h1:5e494iHzsYBiyXQAHHuI4tyJS9M3V84OuX3ufIIGHFo=
github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
@@ -1249,6 +1259,8 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel v1.0.0-RC2 h1:SHhxSjB+omnGZPgGlKe+QMp3MyazcOHdQ8qwo89oKbg=
go.opentelemetry.io/otel v1.0.0-RC2/go.mod h1:w1thVQ7qbAy8MHb0IFj8a5Q2QU0l2ksf8u/CN8m3NOM=
go.opentelemetry.io/otel v1.0.0-RC3 h1:kvwiyEkiUT/JaadXzVLI/R1wDO934A7r3Bs2wEe6wqA=
go.opentelemetry.io/otel v1.0.0-RC3/go.mod h1:Ka5j3ua8tZs4Rkq4Ex3hwgBgOchyPVq5S6P2lz//nKQ=
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC2 h1:RF0nWsIDpDBe+s06lkLxUw9CWQUAhO6hBSxxB7dz45s=
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC2/go.mod h1:sZZqN3Vb0iT+NE6mZ1S7sNyH3t4PFk6ElK5TLGFBZ7E=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
@@ -1257,9 +1269,13 @@ go.opentelemetry.io/otel/oteltest v1.0.0-RC2 h1:xNKqMhlZYkASSyvF4JwObZFMq0jhFN3c
go.opentelemetry.io/otel/oteltest v1.0.0-RC2/go.mod h1:kiQ4tw5tAL4JLTbcOYwK1CWI1HkT5aiLzHovgOVnz/A=
go.opentelemetry.io/otel/sdk v1.0.0-RC2 h1:ROuteeSCBaZNjiT9JcFzZepmInDvLktR28Y6qKo8bCs=
go.opentelemetry.io/otel/sdk v1.0.0-RC2/go.mod h1:fgwHyiDn4e5k40TD9VX243rOxXR+jzsWBZYA2P5jpEw=
go.opentelemetry.io/otel/sdk v1.0.0-RC3 h1:iRMkET+EmJUn5mW0hJzygBraXRmrUwzbOtNvTCh/oKs=
go.opentelemetry.io/otel/sdk v1.0.0-RC3/go.mod h1:78H6hyg2fka0NYT9fqGuFLvly2yCxiBXDJAgLKo/2Us=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/otel/trace v1.0.0-RC2 h1:dunAP0qDULMIT82atj34m5RgvsIK6LcsXf1c/MsYg1w=
go.opentelemetry.io/otel/trace v1.0.0-RC2/go.mod h1:JPQ+z6nNw9mqEGT8o3eoPTdnNI+Aj5JcxEsVGREIAy4=
go.opentelemetry.io/otel/trace v1.0.0-RC3 h1:9F0ayEvlxv8BmNmPbU005WK7hC+7KbOazCPZjNa1yME=
go.opentelemetry.io/otel/trace v1.0.0-RC3/go.mod h1:VUt2TUYd8S2/ZRX09ZDFZQwn2RqfMB5MzO17jBojGxo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=

View File

@@ -1,17 +1,26 @@
package svc
import (
"fmt"
"math"
"net/http"
"net/url"
"path"
"strconv"
"time"
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
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"
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
sproto "github.com/owncloud/ocis/settings/pkg/proto/v0"
settingsSvc "github.com/owncloud/ocis/settings/pkg/service/v0"
msgraph "github.com/owncloud/open-graph-api-go"
)
@@ -128,6 +137,73 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, &listResponse{Value: files})
}
// CreateDrive creates a storage drive (space).
func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
us, ok := ctxpkg.ContextGetUser(r.Context())
if !ok {
errorcode.GeneralException.Render(w, r, http.StatusUnauthorized, "invalid user")
return
}
if err := r.ParseForm(); err != nil {
errorcode.GeneralException.Render(w, r, http.StatusUnauthorized, err.Error())
return
}
s := sproto.NewPermissionService("com.owncloud.api.settings", grpc.DefaultClient)
_, err := s.GetPermissionByID(r.Context(), &sproto.GetPermissionByIDRequest{
PermissionId: settingsSvc.CreateSpacePermissionID,
})
if err != nil {
// if the permission is not existing for the user in context we can assume we don't have it. Return 401.
errorcode.GeneralException.Render(w, r, http.StatusUnauthorized, "insufficient permissions to create a space.")
return
}
client, err := g.GetClient()
if err != nil {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
spaceName := chi.URLParam(r, "drive-name")
if spaceName == "" {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, fmt.Errorf("invalid name").Error())
return
}
quota, _ := strconv.ParseUint(r.Form.Get("quota"), 10, 64)
if quota == 0 {
quota = 65536 // set default quota if no form value was sent.
}
quotaMaxFiles, _ := strconv.ParseUint(r.Form.Get("quotaMaxFiles"), 10, 64)
if quotaMaxFiles == 0 {
quotaMaxFiles = 20 // set default quotaMaxFiles if no form value was sent.
}
csr := provider.CreateStorageSpaceRequest{
Owner: us,
Type: "share",
Name: spaceName,
Quota: &provider.Quota{
QuotaMaxBytes: quota,
QuotaMaxFiles: quotaMaxFiles,
},
}
resp, err := client.CreateStorageSpace(r.Context(), &csr)
if err != nil {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
if resp.GetStatus().GetCode() != v1beta11.Code_CODE_OK {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, fmt.Errorf("").Error())
}
}
func cs3TimestampToTime(t *types.Timestamp) time.Time {
return time.Unix(int64(t.Seconds), int64(t.Nanos))
}

View File

@@ -3,6 +3,9 @@ package svc
import (
"net/http"
"github.com/owncloud/ocis/ocis-pkg/account"
opkgm "github.com/owncloud/ocis/ocis-pkg/middleware"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
@@ -50,6 +53,15 @@ func NewService(opts ...Option) Service {
r.Get("/", svc.GetGroup)
})
})
r.Route("/drives", func(r chi.Router) {
r.Use(opkgm.ExtractAccountUUID(
account.Logger(options.Logger),
account.JWTSecret(options.Config.TokenManager.JWTSecret)),
)
// This route is non-compliant with MS Graph implementation; creating a drive is not supported. There
// is no official MS SDK support for this method.
r.Post("/{drive-name}", svc.CreateDrive)
})
})
})

View File

@@ -300,12 +300,6 @@ Synchronization features like etag propagation, setting mtime and locking files
### Share
File and sync features in a shared scenario
#### [etags don't change for a share receiver](https://github.com/owncloud/product/issues/243)
- [apiWebdavEtagPropagation1/moveFileFolder.feature:244](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation1/moveFileFolder.feature#L244)
- [apiWebdavEtagPropagation1/moveFileFolder.feature:245](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation1/moveFileFolder.feature#L245)
- [apiWebdavEtagPropagation1/moveFileFolder.feature:314](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation1/moveFileFolder.feature#L314)
- [apiWebdavEtagPropagation1/moveFileFolder.feature:315](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavEtagPropagation1/moveFileFolder.feature#L315)
#### [Searching sharee with displayname](https://github.com/owncloud/ocis/issues/547)
- [apiSharees/sharees.feature:32](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharees/sharees.feature#L32)
- [apiSharees/sharees.feature:33](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharees/sharees.feature#L33)
@@ -335,10 +329,8 @@ File and sync features in a shared scenario
- [apiShareManagementToShares/acceptShares.feature:310](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L310)
#### [cannot accept identical pending shares from different user serially](https://github.com/owncloud/ocis/issues/2131)
- [apiShareManagementToShares/acceptShares.feature:82](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L82)
- [apiShareManagementToShares/acceptShares.feature:261](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L261)
- [apiShareCreateSpecialToShares1/createShareUniqueReceivedNames.feature:15](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareCreateSpecialToShares1/createShareUniqueReceivedNames.feature#L15)
- [apiShareManagementToShares/acceptShares.feature:82](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L82)
- [apiShareManagementToShares/acceptShares.feature:504](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L504)
- [apiShareManagementToShares/acceptShares.feature:565](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L565)
- [apiShareCreateSpecialToShares1/createShareReceivedInMultipleWays.feature:153](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareCreateSpecialToShares1/createShareReceivedInMultipleWays.feature#L153)
@@ -348,9 +340,6 @@ File and sync features in a shared scenario
- [apiShareCreateSpecialToShares1/createShareReceivedInMultipleWays.feature:47](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareCreateSpecialToShares1/createShareReceivedInMultipleWays.feature#L47)
- [apiShareCreateSpecialToShares1/createShareReceivedInMultipleWays.feature:48](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareCreateSpecialToShares1/createShareReceivedInMultipleWays.feature#L48)
#### [a declined share still exists in Shares directory](https://github.com/owncloud/ocis/issues/2128)
- [apiShareManagementToShares/acceptShares.feature:207](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/acceptShares.feature#L207)
#### [file_target of a auto-renamed file is not correct directly after sharing](https://github.com/owncloud/core/issues/32322)
- [apiShareManagementBasicToShares/deleteShareFromShares.feature:46](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/deleteShareFromShares.feature#L46)
- [apiShareManagementToShares/mergeShare.feature:89](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/mergeShare.feature#L89)
@@ -362,11 +351,6 @@ File and sync features in a shared scenario
#### [Cannot move a file to a shared folder](https://github.com/owncloud/ocis/issues/2146)
- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:515](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L515)
#### [deleting share response does not contain `data` field](https://github.com/owncloud/ocis/issues/721)
- [apiShareManagementBasicToShares/deleteShareFromShares.feature:43](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/deleteShareFromShares.feature#L43)
- [apiShareManagementBasicToShares/deleteShareFromShares.feature:44](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/deleteShareFromShares.feature#L44)
#### [sharing via API and changing the cases in the username does not work correctly](https://github.com/owncloud/core/issues/35484)
- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:373](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L373)
@@ -662,7 +646,6 @@ _getting and setting quota_
#### [not possible to move file into a received folder](https://github.com/owncloud/ocis/issues/764)
- [apiShareOperationsToShares1/changingFilesShare.feature:24](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares1/changingFilesShare.feature#L24)
- [apiShareOperationsToShares1/changingFilesShare.feature:25](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares1/changingFilesShare.feature#L25)
- [apiShareOperationsToShares1/changingFilesShare.feature:66](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares1/changingFilesShare.feature#L66)
- [apiShareOperationsToShares1/changingFilesShare.feature:82](https://github.com/owncloud/core/blob/master/test/acceptance/features/apiShareOperationsToShares1/changingFilesShare.feature#L82)
- [apiShareOperationsToShares1/changingFilesShare.feature:98](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares1/changingFilesShare.feature#L98)
@@ -1424,10 +1407,6 @@ Scenario Outline: Unauthenticated call
- [apiShareOperationsToShares2/shareAccessByID.feature:155](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/shareAccessByID.feature#L155)
- [apiShareOperationsToShares2/shareAccessByID.feature:156](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/shareAccessByID.feature#L156)
#### [File is still present in the file list after declining a share](https://github.com/owncloud/ocis/issues/2112)
- [apiShareOperationsToShares2/shareAccessByID.feature:123](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/shareAccessByID.feature#L123)
- [apiShareOperationsToShares2/shareAccessByID.feature:124](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/shareAccessByID.feature#L124)
#### [[OC-storage] share-types field empty for shared file folder in webdav response](https://github.com/owncloud/ocis/issues/2144)
- [apiWebdavProperties2/getFileProperties.feature:156](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L156)
- [apiWebdavProperties2/getFileProperties.feature:157](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L157)

View File

@@ -137,9 +137,6 @@ Other free text and markdown formatting can be used elsewhere in the document if
- [webUISharingPublicManagement/publicLinkIndicator.feature:81](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingPublicManagement/publicLinkIndicator.feature#L81)
- [webUISharingPublicManagement/publicLinkIndicator.feature:98](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingPublicManagement/publicLinkIndicator.feature#L98)
### [different button to unshare self from a shared resource in ocis-web and web](https://github.com/owncloud/ocis/issues/2266)
- [webUISharingInternalUsersShareWithPage/shareWithUsers.feature:91](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingInternalUsersShareWithPage/shareWithUsers.feature#L91)
### [Copy private link option not available](https://github.com/owncloud/ocis/issues/1409)
- [webUIFilesCopy/copyPrivateLinks.feature:20](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIFilesCopy/copyPrivateLinks.feature#L20)
- [webUIFilesCopy/copyPrivateLinks.feature:21](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIFilesCopy/copyPrivateLinks.feature#L21)