Skip to content

Commit f0b8a47

Browse files
authored
Merge pull request #5 from johnf/entity-refactor
entity refactor
2 parents 66e1814 + 1e4cce6 commit f0b8a47

File tree

4 files changed

+508
-287
lines changed

4 files changed

+508
-287
lines changed

biome.jsonc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://biomejs.dev/schemas/2.2.2/schema.json",
2+
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
33
"vcs": {
44
"enabled": true,
55
"clientKind": "git",
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
---
2+
sidebar_position: 4
3+
title: Authorization
4+
---
5+
6+
# Authorization
7+
8+
The RO-Crate API uses an `access` property on each entity which signals to the
9+
consumer that level of access the current user has to metadata and content.
10+
This is designed to allow consumers of the API like Oni UI to communicate what
11+
is accessible and redirect to enrollment URLs when access is restricted.
12+
13+
## Access Property Structure
14+
15+
Each entity in the API includes an `access` object with the following
16+
structure:
17+
18+
```json
19+
{
20+
"access": {
21+
"metadata": true,
22+
"content": false,
23+
"metadataAuthorizationUrl": "https://example.com/apply?item=123",
24+
"contentAuthorizationUrl": "https://example.com/apply?item=123"
25+
}
26+
}
27+
```
28+
29+
### Required Fields
30+
31+
- **`metadata`** (boolean): Whether the current user has access to view the
32+
entity's metadata
33+
- **`content`** (boolean): Whether the current user has access to download or
34+
view the entity's content files
35+
36+
### Optional Fields
37+
38+
- **`metadataAuthorizationUrl`** (string): URL where users can request access
39+
to metadata when `metadata` is `false`
40+
- **`contentAuthorizationUrl`** (string): URL where users can request access to
41+
content when `content` is `false`
42+
43+
## Authorization Rules
44+
45+
### Validation Requirements
46+
47+
When implementing the API, the following validation rules MUST be enforced:
48+
49+
- If `metadata` is `false`, then `metadataAuthorizationUrl` MUST be provided
50+
- If `content` is `false`, then `contentAuthorizationUrl` MUST be provided
51+
- Entities that violate these rules should not be surfaced in API responses
52+
53+
### Implementation Flexibility
54+
55+
The authorization system provides maximum flexibility to implementors:
56+
57+
- **Enrollment URL format**: Completely open to implementor design
58+
- **Authorization flow**: The process after visiting an enrollment URL is up to
59+
the implementor
60+
- **Access determination**: How the API determines user access is
61+
implementation-specific
62+
63+
## Access Scenarios and Examples
64+
65+
### 1. Full Access
66+
67+
Both metadata and content are accessible to the current user:
68+
69+
```json
70+
{
71+
"id": "https://catalog.example.com/repository/PUBLIC/001",
72+
"name": "Public Research Data",
73+
"access": {
74+
"metadata": true,
75+
"content": true
76+
}
77+
}
78+
```
79+
80+
### 2. Metadata Only Access
81+
82+
User can view metadata but must request access for content:
83+
84+
```json
85+
{
86+
"id": "https://catalog.example.com/repository/RESTRICTED/001",
87+
"name": "Sensitive Audio Recordings",
88+
"access": {
89+
"metadata": true,
90+
"content": false,
91+
"contentAuthorizationUrl": "https://ethics.example.com/apply?collection=RESTRICTED-001"
92+
}
93+
}
94+
```
95+
96+
### 3. No Access
97+
98+
User must request access for both metadata and content:
99+
100+
```json
101+
{
102+
"id": "https://catalog.example.com/repository/PRIVATE/001",
103+
"name": "Confidential Collection",
104+
"access": {
105+
"metadata": false,
106+
"content": false,
107+
"metadataAuthorizationUrl": "https://portal.example.com/metadata-access?id=PRIVATE-001",
108+
"contentAuthorizationUrl": "https://portal.example.com/content-access?id=PRIVATE-001"
109+
}
110+
}
111+
112+
```
113+
114+
### 4. Content Only Access
115+
116+
User can access content but not detailed metadata (rare scenario):
117+
118+
```json
119+
{
120+
"id": "https://catalog.example.com/repository/CLASSIFIED/001",
121+
"name": "Research Materials",
122+
"access": {
123+
"metadata": false,
124+
"content": true,
125+
"metadataAuthorizationUrl": "https://clearance.example.com/request?item=CLASSIFIED-001"
126+
}
127+
}
128+
```
129+
130+
### 5. Invalid Configurations
131+
132+
These examples show invalid configurations that should result in errors:
133+
134+
```json
135+
// ERROR: content is false but no contentAuthorizationUrl provided
136+
{
137+
"access": {
138+
"metadata": true,
139+
"content": false
140+
// Missing contentAuthorizationUrl
141+
}
142+
}
143+
144+
// ERROR: metadata is false but no metadataAuthorizationUrl provided
145+
{
146+
"access": {
147+
"metadata": false, // Missing metadataAuthorizationUrl
148+
"content": true
149+
}
150+
}
151+
```
152+
153+
## Client Implementation Guidelines
154+
155+
### Checking Access
156+
157+
Before attempting to access entity metadata or content, clients should check
158+
the access property:
159+
160+
```javascript
161+
function canAccessMetadata(entity) {
162+
return entity.access.metadata === true;
163+
}
164+
165+
function canAccessContent(entity) {
166+
return entity.access.content === true;
167+
}
168+
169+
function getEnrollmentUrl(entity, type) {
170+
if (type === 'metadata' && !entity.access.metadata) {
171+
return entity.access.metadataAuthorizationUrl;
172+
}
173+
174+
if (type === 'content' && !entity.access.content) {
175+
return entity.access.contentAuthorizationUrl;
176+
}
177+
return null;
178+
}
179+
```
180+
181+
### Handling Restricted Access
182+
183+
When access is denied, present the enrollment URL to users:
184+
185+
```javascript
186+
if (!canAccessContent(entity)) {
187+
const enrollmentUrl = getEnrollmentUrl(entity, 'content');
188+
// Display message: "Access restricted. Apply for access at: {enrollmentUrl}"
189+
}
190+
```
191+
192+
## Use Cases
193+
194+
### Public Archives
195+
196+
Most content publicly accessible with some restricted materials:
197+
198+
- `metadata: true, content: true` - Open research data
199+
- `metadata: true, content: false` - Culturally sensitive materials requiring
200+
approval
201+
202+
### Institutional Repositories
203+
204+
Metadata discoverable but content restricted to authenticated users:
205+
206+
- `metadata: true, content: false` - Internal research requiring institutional login
207+
208+
### Sensitive Collections
209+
210+
Both metadata and content require special authorization:
211+
212+
- `metadata: false, content: false` - Classified or highly sensitive materials
213+
214+
## Implementation Notes
215+
216+
- Authorization URLs can point to any system: web forms, OAuth providers,
217+
institutional portals, etc.
218+
- The API does not prescribe the enrollment process - this is entirely up to
219+
the implementor
220+
- Access permissions may be user-specific, time-based, or dependent on other
221+
factors
222+
- Consider caching authorization decisions to improve performance
223+
- Ensure authorization URLs are accessible and provide clear instructions to
224+
users

docs/getting-started/extensions.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
sidebar_position: 5
3+
title: Extensions
4+
mdx.format: md
5+
---
6+
7+
# API Extensions
8+
9+
This guide explains how implementations can extend the RO-Crate API
10+
specification with additional properties.
11+
12+
## Core vs Extension Properties
13+
14+
The RO-Crate API specification defines mandatory fields that all
15+
implementations must provide. However, implementations are free to add optional
16+
extension properties directly at the root level of entity responses to meet
17+
their specific requirements.
18+
19+
**Important**: Extension properties are implementation-specific and not
20+
required by the core API. Clients should be prepared to handle additional
21+
properties beyond those defined in the specification.
22+
23+
## How Extensions Work
24+
25+
Extension properties are added at the root level of entity objects, alongside
26+
the mandatory fields defined in the API specification. For example:
27+
28+
```json
29+
{
30+
"id": "https://catalog.paradisec.org.au/repository/LRB/001",
31+
"name": "Recordings of West Alor languages",
32+
"description": "A compilation of recordings featuring various West Alor languages",
33+
"entityType": "http://pcdm.org/models#Collection",
34+
"memberOf": "https://catalog.paradisec.org.au/repository/LRB",
35+
"rootCollection": "https://catalog.paradisec.org.au/repository/LRB",
36+
"metadataLicenseId": "https://license.example.com/metadata",
37+
"contentLicenseId": "https://license.example.com/content",
38+
"access": {
39+
"metadata": true,
40+
"content": false
41+
},
42+
43+
// Extension properties below
44+
"counts": {
45+
"collections": 5,
46+
"objects": 42,
47+
"subCollections": 3,
48+
"files": 150
49+
},
50+
"language": ["English", "Italian"],
51+
"communicationMode": ["SpokenLanguage", "Song"],
52+
"mediaType": ["audio/wav", "text/plain"],
53+
"accessControl": "Public"
54+
}
55+
```
56+
57+
## Example: Oni-UI Extensions
58+
59+
The [oni-ui](https://github.com/Language-Research-Technology/oni-ui) implementation
60+
requires the following additional properties to be present in API responses:
61+
62+
### Statistical Counts
63+
64+
- **`counts`** (object): Statistical information about the entity's subtree:
65+
- **`collections`** (integer): The total number of collections in the subtree
66+
- **`objects`** (integer): The total number of objects in the subtree
67+
- **`subCollections`** (integer): The number of nested sub-collections within
68+
this entity
69+
- **`files`** (integer): The number of individual files attached to or within
70+
this entity's structure
71+
72+
### Content Classification
73+
74+
- **`language`** (array of strings): All languages contained in the sub-tree of
75+
entities. Useful for archives that store diverse linguistic data.
76+
- Example: `["English", "Italian", "Mandarin"]`
77+
78+
- **`communicationMode`** (array of strings): The modes of communication found
79+
in this sub-tree's data, such as speech, song, or sign.
80+
- Example: `["SpokenLanguage", "Song", "SignLanguage"]`
81+
82+
- **`mediaType`** (array of strings): Media types (MIME types) of files within
83+
the sub-tree.
84+
- Example: `["audio/wav", "text/plain", "video/mp4"]`
85+
86+
### Access Control
87+
88+
- **`accessControl`** (string): The level of access control required to view or
89+
download this entity.
90+
- Example: `"Public"`, `"Restricted"`, `"Private"`
91+
92+
## Implementation Guidelines
93+
94+
When adding extension properties to your API implementation:
95+
96+
1. **Document your extensions**: Clearly document any additional properties
97+
your implementation provides
98+
2. **Use descriptive names**: Choose property names that clearly indicate their
99+
purpose
100+
3. **Consider namespacing**: For complex implementations, consider using
101+
prefixed property names to avoid conflicts
102+
4. **Maintain consistency**: Use consistent data types and naming conventions
103+
across your extensions
104+
5. **Version appropriately**: Consider how extension changes might affect
105+
client compatibility
106+
107+
## Other Implementations
108+
109+
Different RO-Crate API implementations may define their own extension
110+
properties based on their specific use cases and requirements. Always consult
111+
the documentation for the specific implementation you're working with to
112+
understand what additional properties might be available.
113+
114+
When building clients that work across multiple implementations, design them to
115+
gracefully handle unknown extension properties.

0 commit comments

Comments
 (0)