Skip to content

Commit ba5c1a0

Browse files
authored
1153 enhancement update swagger api docs (#1169)
* FEAT updated openAPI schema to latest API updates * Fixed bug where openAPI scheme would show formfields in API responses * Fixed bug in creating description for endpoints * FEAT: added overidable patch to many relationship function to change logic where needed in model endpoints ex. supertasks route
1 parent 73ac675 commit ba5c1a0

File tree

7 files changed

+361
-67
lines changed

7 files changed

+361
-67
lines changed

ci/apiv2/hashtopolis.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,29 @@ def patch_one(self, obj):
252252
payload = self.create_payload(obj, attributes, id=obj.id)
253253
logger.debug("Sending PATCH payload: %s to %s", json.dumps(payload), uri)
254254
r = requests.patch(uri, headers=headers, data=json.dumps(payload))
255-
self.validate_status_code(r, [201], "Patching failed")
255+
self.validate_status_code(r, [200], "Patching failed")
256256

257257
# TODO: Validate if return objects matches digital twin
258258
obj.set_initial(self.resp_to_json(r)['data'].copy())
259259

260+
def send_patch(self, uri, data):
261+
self.authenticate()
262+
headers = self._headers
263+
headers['Content-Type'] = 'application/json'
264+
logger.debug("Sending PATCH payload: %s to %s", json.dumps(data), uri)
265+
r = requests.patch(uri, headers=headers, data=json.dumps(data))
266+
self.validate_status_code(r, [204], "Patching failed")
267+
268+
def patch_to_many_relationships(self, obj):
269+
for k, v in obj.diff_includes().items():
270+
attributes = []
271+
logger.debug("Going to patch object '%s' property '%s' from '%s' to '%s'", obj, k, v[0], v[1])
272+
for include_id in v[1]:
273+
attributes.append({"type": k, "id": include_id})
274+
data = {"data": attributes}
275+
uri = self._hashtopolis_uri + obj.uri + "/relationships/" + k
276+
self.send_patch(uri, data)
277+
260278
def create(self, obj):
261279
# Check if object to be created is new
262280
assert obj._new_model is True
@@ -426,6 +444,8 @@ def all(cls):
426444

427445
@classmethod
428446
def patch(cls, obj):
447+
# TODO also patch to one relationships
448+
cls.get_conn().patch_to_many_relationships(obj)
429449
cls.get_conn().patch_one(obj)
430450

431451
@classmethod
@@ -452,7 +472,6 @@ def get(cls, **filters):
452472
def count(cls, **filters):
453473
return cls.get_conn().count(filter=filters)
454474

455-
456475
@classmethod
457476
def paginate(cls, **pages):
458477
return QuerySet(cls, pages=pages)
@@ -605,6 +624,10 @@ def diff(self):
605624
if v_current != v_innitial:
606625
diffs.append((key, (v_innitial, v_current)))
607626

627+
return dict(diffs)
628+
629+
def diff_includes(self):
630+
diffs = []
608631
# Find includeables sets which have changed
609632
for include in self.__included:
610633
if include.endswith('_set'):
@@ -618,7 +641,7 @@ def diff(self):
618641
# Use ID of ojbects as new current/update identifiers
619642
if sorted(v_innitial_ids) != sorted(v_current_ids):
620643
diffs.append((innitial_name, (v_innitial_ids, v_current_ids)))
621-
644+
622645
return dict(diffs)
623646

624647
def has_changed(self):

ci/apiv2/test_supertask.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_new_pretasks(self):
3131

3232
# Quirk for expanding object to allow update to take place
3333
work_obj = Supertask.objects.prefetch_related('pretasks').get(pk=model_obj.id)
34-
new_pretasks = [self.create_pretask() for i in range(2)]
34+
new_pretasks = [self.create_pretask(file_id="003") for i in range(2)]
3535
selected_pretasks = [work_obj.pretasks_set[0], new_pretasks[1]]
3636
work_obj.pretasks_set = selected_pretasks
3737
work_obj.save()

doc/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
## Enhancements
55

66
- Use utf8mb4 as default encoding in order to support the full unicode range
7+
- Updated OpenAPI docs to latest API updates
78

89
## Bugfixes
910

src/inc/apiv2/common/AbstractBaseAPI.class.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ protected function getFeatures(): array
112112
$features = [];
113113
foreach($this->getFormFields() as $key => $feature) {
114114
/* Innitate default values */
115-
$features[$key] = $feature + ['null' => False, 'protected' => False, 'private' => False, 'choices' => "unset", 'pk' => False];
115+
$features[$key] = $feature + ['null' => False, 'protected' => False, 'private' => False, 'choices' => "unset", 'pk' => False, 'read_only' => True];
116116
if (!array_key_exists('alias', $feature)) {
117117
$features[$key]['alias'] = $key;
118118
}
@@ -128,6 +128,10 @@ protected function getFeatures(): array
128128
public function getAliasedFeatures(): array
129129
{
130130
$features = $this->getFeatures();
131+
return $this->mapFeatures($features);
132+
}
133+
134+
final protected function mapFeatures($features) {
131135
$mappedFeatures = [];
132136
foreach ($features as $key => $value) {
133137
$mappedFeatures[$value['alias']] = $value;

src/inc/apiv2/common/AbstractModelAPI.class.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@ final protected function getFeatures(): array
110110
);
111111
}
112112

113+
/**
114+
* Seperate get features function to get features without the formfields. This is needed to generate the openAPI documentation
115+
* TODO: This function could probably be used in the patch endpoints aswell, since formfields are not relevant there.
116+
*/
117+
public function getFeaturesWithoutFormfields(): array {
118+
$features = call_user_func($this->getDBAclass() . '::getFeatures');
119+
return $this->mapFeatures($features);
120+
}
121+
113122
/**
114123
* Get features based on DBA model features
115124
*
@@ -343,7 +352,7 @@ protected function getFilterACL(): array
343352

344353
/**
345354
* Helper function to determine if $resourceRecord is a valid resource record
346-
* returns true if it is a valid resource record and false if it is an invallid resource record
355+
* returns true if it is a valid resource record and false if it is an invalid resource record
347356
*/
348357
final protected function validateResourceRecord(mixed $resourceRecord): bool
349358
{
@@ -356,7 +365,7 @@ final protected function ResourceRecordArrayToUpdateArray($data, $parentId)
356365
foreach ($data as $item) {
357366
if (!$this->validateResourceRecord($item)) {
358367
$encoded_item = json_encode($item);
359-
throw new HttpErrorException('Invallid resource record given in list! invalid resource record: ' . $encoded_item);
368+
throw new HttpErrorException('Invalid resource record given in list! invalid resource record: ' . $encoded_item);
360369
}
361370
$updates[] = new MassUpdateSet($item["id"], $parentId);
362371
}
@@ -380,7 +389,7 @@ public static function getManyResources(object $apiClass, Request $request, Resp
380389
$pageAfter = $apiClass->getQueryParameterFamilyMember($request, 'page', 'after') ?? 0;
381390
$pageSize = $apiClass->getQueryParameterFamilyMember($request, 'page', 'size') ?? $defaultPageSize;
382391
if ($pageSize < 0) {
383-
throw new HttpErrorException("Invallid parameter, page[size] must be a positive integer", 400);
392+
throw new HttpErrorException("Invalid parameter, page[size] must be a positive integer", 400);
384393
} elseif ($pageSize > $maxPageSize) {
385394
throw new HttpErrorException(sprintf("You requested a size of %d, but %d is the maximum.", $pageSize, $maxPageSize), 400);
386395
}
@@ -714,7 +723,7 @@ public function patchOne(Request $request, Response $response, array $args): Res
714723
715724
// Return updated object
716725
$newObject = $this->getFactory()->get($object->getId());
717-
return self::getOneResource($this, $newObject, $request, $response, 201);
726+
return self::getOneResource($this, $newObject, $request, $response, 200);
718727
}
719728

720729

@@ -1003,8 +1012,18 @@ public function patchToManyRelationshipLink(Request $request, Response $response
10031012
if ($jsonBody === null || !array_key_exists('data', $jsonBody) || !is_array($jsonBody['data'])) {
10041013
throw new HttpErrorException('No data was sent! Send the json data in the following format: {"data":[{"type": "foo", "id": 1}}]');
10051014
}
1015+
10061016
$data = $jsonBody['data'];
1017+
$this->updateToManyRelationship($request, $data, $args);
10071018

1019+
return $response->withStatus(204)
1020+
->withHeader("Content-Type", "application/vnd.api+json");
1021+
}
1022+
1023+
/**
1024+
* Overidable function to update the to many relationship
1025+
*/
1026+
protected function updateToManyRelationship(Request $request, array $data, array $args): void {
10081027
$relation = $this->getToManyRelationships()[$args['relation']];
10091028
$primaryKey = $this->getPrimaryKeyOther($relation['relationType']);
10101029
$relationKey = $relation['relationKey'];
@@ -1030,7 +1049,7 @@ public function patchToManyRelationshipLink(Request $request, Response $response
10301049
foreach ($data as $item) {
10311050
if (!$this->validateResourceRecord($item)) {
10321051
$encoded_item = json_encode($item);
1033-
throw new HttpErrorException('Invallid resource record given in list! invalid resource record: ' . $encoded_item);
1052+
throw new HttpErrorException('Invalid resource record given in list! invalid resource record: ' . $encoded_item);
10341053
}
10351054
$updates[] = new MassUpdateSet($item["id"], $args["id"]);
10361055
unset($modelsDict[$item["id"]]);
@@ -1050,9 +1069,6 @@ public function patchToManyRelationshipLink(Request $request, Response $response
10501069
if (!$factory->getDB()->commit()) {
10511070
throw new HttpErrorException("Was not able to update to many relationship");
10521071
}
1053-
1054-
return $response->withStatus(204)
1055-
->withHeader("Content-Type", "application/vnd.api+json");
10561072
}
10571073

10581074
/**
@@ -1158,7 +1174,7 @@ protected function updateObject(object $object, array $data, array $processed =
11581174
*/
11591175
final public function getPatchValidFeatures(): array
11601176
{
1161-
$aliasedfeatures = $this->getAliasedFeatures();
1177+
$aliasedfeatures = $this->getFeaturesWithoutFormfields();
11621178
$validFeatures = [];
11631179

11641180
// Generate listing of validFeatures

0 commit comments

Comments
 (0)