mirror of
https://github.com/suitenumerique/drive.git
synced 2026-08-30 03:39:46 +02:00
External services consuming the resource server API may need items they create to carry specific attributes, typically quota_excluded so their uploads do not consume the user quota. The new EXTERNAL_API_AUD_ITEM_ATTRIBUTES setting maps a token audience to the attributes applied at creation. The lookup is a hook on the item viewset overridden only in the resource server viewset, so both the root create and children creation paths are covered while the regular API remains unaffected.
177 lines
6.2 KiB
Markdown
177 lines
6.2 KiB
Markdown
# Use Drive as a Resource Server
|
|
|
|
Drive implements resource server, so it means it can be used from an external app to perform some operation using the dedicated API.
|
|
|
|
> **Note:** This feature might be subject to future evolutions. The API endpoints, configuration options, and behavior may change in future versions.
|
|
|
|
## Prerequisites
|
|
|
|
In order to activate the resource server on Drive you need to setup the following environement variables
|
|
|
|
```
|
|
OIDC_RESOURCE_SERVER_ENABLED=True
|
|
OIDC_OP_URL=
|
|
OIDC_OP_INTROSPECTION_ENDPOINT=
|
|
OIDC_RS_CLIENT_ID=
|
|
OIDC_RS_CLIENT_SECRET=
|
|
OIDC_RS_AUDIENCE_CLAIM=
|
|
OIDC_RS_ALLOWED_AUDIENCES=
|
|
```
|
|
|
|
It implements the resource server using `django-lasuite`, see the [documentation](https://github.com/suitenumerique/django-lasuite/blob/main/documentation/how-to-use-oidc-resource-server-backend.md)
|
|
|
|
## Customise allowed routes
|
|
|
|
Configure the `EXTERNAL_API` setting to control which routes and actions are available in the external API. Set it via the `EXTERNAL_API` environment variable (as JSON) or in Django settings.
|
|
|
|
Default configuration:
|
|
|
|
```python
|
|
EXTERNAL_API = {
|
|
"items": {
|
|
"enabled": True,
|
|
"actions": ["list", "retrieve", "children", "upload_ended"],
|
|
},
|
|
"item_access": {
|
|
"enabled": False,
|
|
"actions": [],
|
|
},
|
|
"item_invitation": {
|
|
"enabled": False,
|
|
"actions": [],
|
|
},
|
|
"users": {
|
|
"enabled": True,
|
|
"actions": ["get_me"],
|
|
}
|
|
}
|
|
```
|
|
|
|
**Endpoints:**
|
|
|
|
- `items`: Controls `/external_api/v1.0/items/`. Available actions: `list`, `retrieve`, `create`, `update`, `partial_update`, `destroy`, `children`, `upload_ended`, `move`, `restore`, `trashbin`, `hard_delete`, `tree`, `breadcrumb`, `link_configuration`, `favorite`, `media_auth`, `wopi`
|
|
- `item_access`: Controls `/external_api/v1.0/items/{id}/accesses/`. Available actions: `list`, `retrieve`, `create`, `update`, `partial_update`, `destroy`
|
|
- `item_invitation`: Controls `/external_api/v1.0/items/{id}/invitations/`. Available actions: `list`, `retrieve`, `create`, `update`, `partial_update`, `destroy`
|
|
|
|
Each endpoint has `enabled` (boolean) and `actions` (list of allowed actions). Only actions explicitly listed are accessible.
|
|
|
|
## Customise created item attributes per audience
|
|
|
|
Configure the `EXTERNAL_API_AUD_ITEM_ATTRIBUTES` setting to apply extra attributes to items
|
|
created through the external API, depending on the token audience of the request (the claim
|
|
configured by `OIDC_RS_AUDIENCE_CLAIM`). Set it via the `EXTERNAL_API_AUD_ITEM_ATTRIBUTES`
|
|
environment variable (as JSON) or in Django settings.
|
|
|
|
```python
|
|
EXTERNAL_API_AUD_ITEM_ATTRIBUTES = {
|
|
"some_audience": {
|
|
"quota_excluded": True,
|
|
},
|
|
}
|
|
```
|
|
|
|
With this configuration, every item created by a request authenticated with the
|
|
`some_audience` audience is excluded from its creator's storage quota computation.
|
|
Audiences without an entry keep the default item attributes.
|
|
|
|
## Request Drive
|
|
|
|
In order to request drive from an external resource provider, you need to implement the basic setup of `django-lasuite` [Using the OIDC Authentication Backend to request a resource server](https://github.com/suitenumerique/django-lasuite/blob/main/documentation/how-to-use-oidc-call-to-resource-server.md)
|
|
|
|
Then you can requests some routes that are available at `/external_api/v1.0/*`, here are some examples of what you can do.
|
|
|
|
#### Upload a file
|
|
|
|
Here is an example of a view that create a file on the main workspace in Drive.
|
|
|
|
```python
|
|
@method_decorator(refresh_oidc_access_token)
|
|
def upload_file(self, request):
|
|
"""
|
|
Create a new file in the main workspace.
|
|
"""
|
|
|
|
# Get the access token from the session
|
|
access_token = request.session.get('oidc_access_token')
|
|
|
|
# Get the main workspace
|
|
response = requests.get(
|
|
f"{settings.DRIVE_API}/items/",
|
|
headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
items = data['results']
|
|
main_workspace = None
|
|
for item in items:
|
|
if item['main_workspace']:
|
|
main_workspace = item
|
|
break
|
|
|
|
if not main_workspace:
|
|
return drf.response.Response(status=404, data={"error": "No main workspace found"})
|
|
|
|
# Create a new file in the main workspace
|
|
response = requests.post(
|
|
f"{settings.DRIVE_API}/items/{main_workspace['id']}/children/",
|
|
json={
|
|
"type": "file",
|
|
"filename": "test.txt",
|
|
},
|
|
headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
|
|
)
|
|
response.raise_for_status()
|
|
item = response.json()
|
|
policy = item['policy']
|
|
|
|
# Upload file content using the presigned URL
|
|
import os
|
|
sample_file_path = os.path.join(os.path.dirname(__file__), "sample.txt")
|
|
with open(sample_file_path, "rb") as f:
|
|
upload_response = requests.put(
|
|
policy,
|
|
data=f.read(),
|
|
headers={
|
|
"Content-Type": "text/plain",
|
|
"x-amz-acl": "private"
|
|
}
|
|
)
|
|
upload_response.raise_for_status()
|
|
|
|
# Tell the Drive API that the upload is ended
|
|
response = requests.post(
|
|
f"{settings.DRIVE_API}/items/{item['id']}/upload-ended/",
|
|
json={},
|
|
headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
|
|
)
|
|
response.raise_for_status()
|
|
|
|
return drf.response.Response(data)
|
|
```
|
|
|
|
#### Create a new folder
|
|
|
|
Using the same logic as the previous example, you can create a folder in the main workspace.
|
|
|
|
```python
|
|
response = requests.post(
|
|
f"{settings.DRIVE_API}/items/{main_workspace['id']}/children/",
|
|
json={
|
|
"type": "folder",
|
|
"title": "My folder",
|
|
},
|
|
headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
|
|
)
|
|
```
|
|
|
|
#### Get user information
|
|
|
|
The same way, you can use the /me endpoint to get user information.
|
|
|
|
```python
|
|
response = requests.get(
|
|
"{settings.DRIVE_API}/users/me/",
|
|
headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
|
|
)
|
|
```
|