Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Syndesi committed Oct 7, 2023
1 parent 16ff691 commit 779c2d6
Show file tree
Hide file tree
Showing 42 changed files with 696 additions and 258 deletions.
1 change: 1 addition & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ imports:
- {resource: ../src/EventSystem/NormalizedValueToRawValue/config.yaml}
- {resource: ../src/EventSystem/RawValueToNormalizedValue/config.yaml}
- {resource: ../src/EventSystem/ElementPropertyChange/config.yaml}
- {resource: ../src/EventSystem/ElementPropertyReset/config.yaml}
- {resource: ../src/EventSystem/ElementPropertyReturn/config.yaml}

services:
Expand Down
2 changes: 1 addition & 1 deletion docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
- [<span class="method-get">GET</span>` /<uuid>/parents -` Get Parents](/api-endpoints/element/get-parents)
- [<span class="method-get">GET</span>` /<uuid>/children -` Get Children](/api-endpoints/element/get-children)
- [<span class="method-get">GET</span>` /<uuid>/related -` Get Related](/api-endpoints/element/get-related)
- [<span class="method-post">POST</span>` / -` Create Root Element](/api-endpoints/element/post-index)
- [<span class="method-post">POST</span>` / -` Create Root Level Element](/api-endpoints/element/post-index)
- [<span class="method-post">POST</span>` /<uuid> -` Create Element](/api-endpoints/element/post-element)
- [<span class="method-put">PUT</span>` /<uuid> -` Replace Element](/api-endpoints/element/put-element)
- [<span class="method-patch">PATCH</span>` /<uuid> -` Update Element](/api-endpoints/element/patch-element)
Expand Down
187 changes: 186 additions & 1 deletion docs/api-endpoints/element/post-index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,188 @@
# <span class="method-post">POST</span>` / -` Create Root Element
# <span class="method-post">POST</span>` / -` Create Root Level Element


<!-- panels:start -->
<!-- div:left-panel -->

Creates a new data element. If the data element is a node, it is directly owned by the current user.

## Request Body

The posted request must be a valid JSON document.

The request must contain the following attributes:

- `type`: The type of element to be created. Internally used types might have restrictions.
- `id`: The elements UUID, optional. If not set, the API will generate one for you.
- `start`: The start node's UUID, only required for relations.
- `end`: The end node's UUID, only required for relations.
- `data`: Data related to the element in the form of an JSON object. Restrictions might apply to internally used
properties. If no properties should be used, send an empty object, e.g. `"data": {}`;

```json
{
"type": "Demo",
"data": {
"hello": "world :D"
}
}
```

## Request Example

```bash
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"type": "Demo", "data": {"hello": "world :D"}}' \
https://api.localhost/
```

<!-- tabs:start -->

### **🟢 Success 204**

<div class="code-title auto-refresh">Response Headers</div>

[Response Body](./post-index/204-response-header.txt ':include :type=code')

Success response does not have a response body. The UUID of the created element is written in the `Location`-header.

### **🔴 Error 400**

<div class="code-title auto-refresh">Response Headers</div>

[Response Body](./post-index/400-response-header.txt ':include :type=code')

<div class="code-title auto-refresh">Response Body</div>

[Response Body](./post-index/400-response-body.json ':include :type=code problem+json')

### **🔴 Error 401**

<div class="code-title auto-refresh">Response Headers</div>

[Response Body](./post-index/401-response-header.txt ':include :type=code')

<div class="code-title auto-refresh">Response Body</div>

[Response Body](./post-index/401-response-body.json ':include :type=code problem+json')

### **🔴 Error 403**

<div class="code-title auto-refresh">Response Headers</div>

[Response Body](./post-index/403-response-header.txt ':include :type=code')

<div class="code-title auto-refresh">Response Body</div>

[Response Body](./post-index/403-response-body.json ':include :type=code problem+json')

### **🔴 Error 429**

<div class="code-title">Response Headers</div>

[Response Body](./post-index/429-response-header.txt ':include :type=code')

<div class="code-title">Response Body</div>

[Response Body](./post-index/429-response-body.json ':include :type=code problem+json')

<!-- tabs:end -->

<!-- div:right-panel -->

## Internal Workflow

Once the server receives such a request, it checks several things internally:

<div id="graph-container-1" class="graph-container" style="height:1400px"></div>

<!-- panels:end -->

<script>
G6.registerEdge('polyline-edge', {
draw(cfg, group) {
const { startPoint, endPoint } = cfg;
const hgap = Math.abs(endPoint.x - startPoint.x);

const path = [
['M', startPoint.x, startPoint.y],
[
'C',
startPoint.x + hgap / 4,
startPoint.y,
endPoint.x - hgap / 2,
endPoint.y,
endPoint.x,
endPoint.y,
],
];
const shape = group.addShape('path', {
attrs: {
stroke: '#AAB7C4',
path,
},
name: 'path-shape',
});
const midPoint = {
x: (startPoint.x + endPoint.x) / 2,
y: (startPoint.y + endPoint.y) / 2,
};
const label = group.addShape('text', {
attrs: {
text: cfg.label + '###########',
x: midPoint.x,
y: midPoint.y,
textAlign: 'center',
textBaseline: 'middle',
fill: '#000',
fontSize: 14,
},
name: 'label-shape',
});
return shape;
},
});
renderWorkflow(document.getElementById('graph-container-1'), {
nodes: [
{ id: 'init', ...workflowStart, label: 'server receives POST-request' },
{ id: 'checkType', ...workflowDecision, label: 'is type given?' },
{ id: 'checkTypeContent', ...workflowDecision, label: "is type equal to\n\"ActionChangePassword\"?" },
{ id: 'checkCurrentPassword', ...workflowDecision, label: "is currentPassword given?" },
{ id: 'checkNewPassword', ...workflowDecision, label: 'is newPassword given?' },
{ id: 'checkUniqueIdentifier', ...workflowDecision, label: 'is unique identifier given?' },
{ id: 'checkNewPasswordDifferentToCurrentPassword', ...workflowDecision, label: "is new password different\nto old password?" },
{ id: 'checkUser', ...workflowDecision, label: 'does user exist?' },
{ id: 'checkAnonymousUser', ...workflowDecision, label: 'is anonymous user?' },
{ id: 'checkCurrentPasswordMatch', ...workflowDecision, label: 'does current password match?' },
{ id: 'changePassword', ...workflowStep, label: "change password" },
{ id: 'error400', ...workflowEndError, label: "return 400" },
{ id: 'error401', ...workflowEndError, label: "return 401" },
{ id: 'error403', ...workflowEndError, label: 'return 403' },
{ id: 'success204', ...workflowEndSuccess , label: "return 204"},
],
edges: [
{ source: 'init', target: 'checkType', label: '' },
{ source: 'checkType', target: 'checkTypeContent', label: 'yes' },
{ source: 'checkType', target: 'error400', label: 'no' },
{ source: 'checkTypeContent', target: 'checkCurrentPassword', label: 'yes' },
{ source: 'checkTypeContent', target: 'error400', label: 'no' },
{ source: 'checkCurrentPassword', target: 'checkNewPassword', label: 'yes' },
{ source: 'checkCurrentPassword', target: 'error400', label: 'no' },
{ source: 'checkNewPassword', target: 'checkUniqueIdentifier', label: 'yes' },
{ source: 'checkNewPassword', target: 'error400', label: 'no' },
{ source: 'checkUniqueIdentifier', target: 'checkNewPasswordDifferentToCurrentPassword', label: 'yes' },
{ source: 'checkUniqueIdentifier', target: 'error400', label: 'no' },
{ source: 'checkNewPasswordDifferentToCurrentPassword', target: 'checkUser', label: 'yes' },
{ source: 'checkNewPasswordDifferentToCurrentPassword', target: 'error400', label: 'no' },
{ source: 'checkUser', target: 'checkAnonymousUser', label: 'yes' },
{ source: 'checkUser', target: 'error401', label: 'no' },
{ source: 'checkAnonymousUser', target: 'checkCurrentPasswordMatch', label: 'no' },
{ source: 'checkAnonymousUser', target: 'error403', label: 'yes' },
{ source: 'checkCurrentPasswordMatch', target: 'changePassword', label: 'yes' },
{ source: 'checkCurrentPasswordMatch', target: 'error401', label: 'no' },
{ source: 'changePassword', target: 'success204', label: '' },
],
}, 'TB');
</script>
8 changes: 8 additions & 0 deletions docs/api-endpoints/element/post-index/204-response-header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method
Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Access-Control-Allow-Origin: *
Allow: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Cache-Control: no-cache, private
Date: Fri, 29 Sep 2023 10:05:24 GMT
Server: Unit
X-Powered-By: Ember-Nexus-API
6 changes: 6 additions & 0 deletions docs/api-endpoints/element/post-index/400-response-body.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "http://ember-nexus-api/error/400/bad-content",
"title": "Bad content",
"status": 400,
"detail": "Endpoint expects property 'type' to be ActionChangePassword, got 'NotActionChangePassword'."
}
10 changes: 10 additions & 0 deletions docs/api-endpoints/element/post-index/400-response-header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method
Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Access-Control-Allow-Origin: *
Allow: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Cache-Control: no-cache, private
Content-Type: application/problem+json; charset=utf-8
Date: Fri, 29 Sep 2023 10:11:29 GMT
Server: Unit
Transfer-Encoding: chunked
X-Powered-By: Ember-Nexus-API
6 changes: 6 additions & 0 deletions docs/api-endpoints/element/post-index/401-response-body.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "http://ember-nexus-api/error/401/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Authorization for the request failed due to possible problems with the token (incorrect or expired), password (incorrect or changed), the user's unique identifier, or the user's status (e.g., missing, blocked, or deleted)."
}
10 changes: 10 additions & 0 deletions docs/api-endpoints/element/post-index/401-response-header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method
Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Access-Control-Allow-Origin: *
Allow: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Cache-Control: no-cache, private
Content-Type: application/problem+json; charset=utf-8
Date: Fri, 29 Sep 2023 10:14:53 GMT
Server: Unit
Transfer-Encoding: chunked
X-Powered-By: Ember-Nexus-API
6 changes: 6 additions & 0 deletions docs/api-endpoints/element/post-index/403-response-body.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "http://ember-nexus-api/error/403/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "Requested endpoint, element or action is forbidden."
}
10 changes: 10 additions & 0 deletions docs/api-endpoints/element/post-index/403-response-header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method
Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Access-Control-Allow-Origin: *
Allow: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Cache-Control: no-cache, private
Content-Type: application/problem+json; charset=utf-8
Date: Fri, 29 Sep 2023 17:33:00 GMT
Server: Unit
Transfer-Encoding: chunked
X-Powered-By: Ember-Nexus-API
6 changes: 6 additions & 0 deletions docs/api-endpoints/element/post-index/429-response-body.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "401-unauthorized",
"title": "Request does not contain valid token, or anonymous user is disabled.",
"status": 401,
"detail": ""
}
9 changes: 9 additions & 0 deletions docs/api-endpoints/element/post-index/429-response-header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, PATCH, DELETE
Allow: GET, POST, OPTIONS, PUT, PATCH, DELETE
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache, private
Date: Fri, 15 Sep 2023 08:03:41 GMT
Server: Unit
Transfer-Encoding: chunked
6 changes: 0 additions & 6 deletions src/Controller/Element/DeleteElementController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace App\Controller\Element;

use App\Factory\Exception\Client401UnauthorizedExceptionFactory;
use App\Factory\Exception\Client404NotFoundExceptionFactory;
use App\Helper\Regex;
use App\Response\NoContentResponse;
Expand All @@ -21,7 +20,6 @@ public function __construct(
private ElementManager $elementManager,
private AuthProvider $authProvider,
private AccessChecker $accessChecker,
private Client401UnauthorizedExceptionFactory $client401UnauthorizedExceptionFactory,
private Client404NotFoundExceptionFactory $client404NotFoundExceptionFactory
) {
}
Expand All @@ -39,10 +37,6 @@ public function deleteElement(string $uuid): Response
$elementUuid = UuidV4::fromString($uuid);
$userUuid = $this->authProvider->getUserUuid();

if (!$userUuid) {
throw $this->client401UnauthorizedExceptionFactory->createFromTemplate();
}

if (!$this->accessChecker->hasAccessToElement($userUuid, $elementUuid, AccessType::DELETE)) {
throw $this->client404NotFoundExceptionFactory->createFromTemplate();
}
Expand Down
6 changes: 0 additions & 6 deletions src/Controller/Element/GetChildrenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace App\Controller\Element;

use App\Factory\Exception\Client401UnauthorizedExceptionFactory;
use App\Factory\Exception\Client404NotFoundExceptionFactory;
use App\Helper\Regex;
use App\Security\AccessChecker;
Expand All @@ -24,7 +23,6 @@ public function __construct(
private CollectionService $collectionService,
private AuthProvider $authProvider,
private AccessChecker $accessChecker,
private Client401UnauthorizedExceptionFactory $client401UnauthorizedExceptionFactory,
private Client404NotFoundExceptionFactory $client404NotFoundExceptionFactory
) {
}
Expand All @@ -42,10 +40,6 @@ public function getChildren(string $uuid): Response
$parentUuid = UuidV4::fromString($uuid);
$userUuid = $this->authProvider->getUserUuid();

if (!$userUuid) {
throw $this->client401UnauthorizedExceptionFactory->createFromTemplate();
}

$type = $this->accessChecker->getElementType($parentUuid);
if (ElementType::RELATION === $type) {
// relations can not be parent nodes
Expand Down
6 changes: 0 additions & 6 deletions src/Controller/Element/GetElementController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace App\Controller\Element;

use App\Factory\Exception\Client401UnauthorizedExceptionFactory;
use App\Factory\Exception\Client404NotFoundExceptionFactory;
use App\Helper\Regex;
use App\Security\AccessChecker;
Expand All @@ -20,7 +19,6 @@ public function __construct(
private ElementResponseService $elementResponseService,
private AuthProvider $authProvider,
private AccessChecker $accessChecker,
private Client401UnauthorizedExceptionFactory $client401UnauthorizedExceptionFactory,
private Client404NotFoundExceptionFactory $client404NotFoundExceptionFactory
) {
}
Expand All @@ -38,10 +36,6 @@ public function getElement(string $uuid): Response
$elementUuid = UuidV4::fromString($uuid);
$userUuid = $this->authProvider->getUserUuid();

if (!$userUuid) {
throw $this->client401UnauthorizedExceptionFactory->createFromTemplate();
}

if (!$this->accessChecker->hasAccessToElement($userUuid, $elementUuid, AccessType::READ)) {
throw $this->client404NotFoundExceptionFactory->createFromTemplate();
}
Expand Down
Loading

0 comments on commit 779c2d6

Please sign in to comment.