Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1153 enhancement update swagger api docs #1169

Merged
merged 4 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions ci/apiv2/hashtopolis.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,29 @@ def patch_one(self, obj):
payload = self.create_payload(obj, attributes, id=obj.id)
logger.debug("Sending PATCH payload: %s to %s", json.dumps(payload), uri)
r = requests.patch(uri, headers=headers, data=json.dumps(payload))
self.validate_status_code(r, [201], "Patching failed")
self.validate_status_code(r, [200], "Patching failed")

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

def send_patch(self, uri, data):
self.authenticate()
headers = self._headers
headers['Content-Type'] = 'application/json'
logger.debug("Sending PATCH payload: %s to %s", json.dumps(data), uri)
r = requests.patch(uri, headers=headers, data=json.dumps(data))
self.validate_status_code(r, [204], "Patching failed")

def patch_to_many_relationships(self, obj):
for k, v in obj.diff_includes().items():
attributes = []
logger.debug("Going to patch object '%s' property '%s' from '%s' to '%s'", obj, k, v[0], v[1])
for include_id in v[1]:
attributes.append({"type": k, "id": include_id})
data = {"data": attributes}
uri = self._hashtopolis_uri + obj.uri + "/relationships/" + k
self.send_patch(uri, data)

def create(self, obj):
# Check if object to be created is new
assert obj._new_model is True
Expand Down Expand Up @@ -426,6 +444,8 @@ def all(cls):

@classmethod
def patch(cls, obj):
# TODO also patch to one relationships
cls.get_conn().patch_to_many_relationships(obj)
cls.get_conn().patch_one(obj)

@classmethod
Expand All @@ -452,7 +472,6 @@ def get(cls, **filters):
def count(cls, **filters):
return cls.get_conn().count(filter=filters)


@classmethod
def paginate(cls, **pages):
return QuerySet(cls, pages=pages)
Expand Down Expand Up @@ -605,6 +624,10 @@ def diff(self):
if v_current != v_innitial:
diffs.append((key, (v_innitial, v_current)))

return dict(diffs)

def diff_includes(self):
diffs = []
# Find includeables sets which have changed
for include in self.__included:
if include.endswith('_set'):
Expand All @@ -618,7 +641,7 @@ def diff(self):
# Use ID of ojbects as new current/update identifiers
if sorted(v_innitial_ids) != sorted(v_current_ids):
diffs.append((innitial_name, (v_innitial_ids, v_current_ids)))

return dict(diffs)

def has_changed(self):
Expand Down
2 changes: 1 addition & 1 deletion ci/apiv2/test_supertask.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_new_pretasks(self):

# Quirk for expanding object to allow update to take place
work_obj = Supertask.objects.prefetch_related('pretasks').get(pk=model_obj.id)
new_pretasks = [self.create_pretask() for i in range(2)]
new_pretasks = [self.create_pretask(file_id="003") for i in range(2)]
selected_pretasks = [work_obj.pretasks_set[0], new_pretasks[1]]
work_obj.pretasks_set = selected_pretasks
work_obj.save()
Expand Down
1 change: 1 addition & 0 deletions doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
## Enhancements

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

## Bugfixes

Expand Down
6 changes: 5 additions & 1 deletion src/inc/apiv2/common/AbstractBaseAPI.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ protected function getFeatures(): array
$features = [];
foreach($this->getFormFields() as $key => $feature) {
/* Innitate default values */
$features[$key] = $feature + ['null' => False, 'protected' => False, 'private' => False, 'choices' => "unset", 'pk' => False];
$features[$key] = $feature + ['null' => False, 'protected' => False, 'private' => False, 'choices' => "unset", 'pk' => False, 'read_only' => True];
if (!array_key_exists('alias', $feature)) {
$features[$key]['alias'] = $key;
}
Expand All @@ -128,6 +128,10 @@ protected function getFeatures(): array
public function getAliasedFeatures(): array
{
$features = $this->getFeatures();
return $this->mapFeatures($features);
}

final protected function mapFeatures($features) {
$mappedFeatures = [];
foreach ($features as $key => $value) {
$mappedFeatures[$value['alias']] = $value;
Expand Down
34 changes: 25 additions & 9 deletions src/inc/apiv2/common/AbstractModelAPI.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ final protected function getFeatures(): array
);
}

/**
* Seperate get features function to get features without the formfields. This is needed to generate the openAPI documentation
* TODO: This function could probably be used in the patch endpoints aswell, since formfields are not relevant there.
*/
public function getFeaturesWithoutFormfields(): array {
$features = call_user_func($this->getDBAclass() . '::getFeatures');
return $this->mapFeatures($features);
}

/**
* Get features based on DBA model features
*
Expand Down Expand Up @@ -343,7 +352,7 @@ protected function getFilterACL(): array

/**
* Helper function to determine if $resourceRecord is a valid resource record
* returns true if it is a valid resource record and false if it is an invallid resource record
* returns true if it is a valid resource record and false if it is an invalid resource record
*/
final protected function validateResourceRecord(mixed $resourceRecord): bool
{
Expand All @@ -356,7 +365,7 @@ final protected function ResourceRecordArrayToUpdateArray($data, $parentId)
foreach ($data as $item) {
if (!$this->validateResourceRecord($item)) {
$encoded_item = json_encode($item);
throw new HttpErrorException('Invallid resource record given in list! invalid resource record: ' . $encoded_item);
throw new HttpErrorException('Invalid resource record given in list! invalid resource record: ' . $encoded_item);
}
$updates[] = new MassUpdateSet($item["id"], $parentId);
}
Expand All @@ -380,7 +389,7 @@ public static function getManyResources(object $apiClass, Request $request, Resp
$pageAfter = $apiClass->getQueryParameterFamilyMember($request, 'page', 'after') ?? 0;
$pageSize = $apiClass->getQueryParameterFamilyMember($request, 'page', 'size') ?? $defaultPageSize;
if ($pageSize < 0) {
throw new HttpErrorException("Invallid parameter, page[size] must be a positive integer", 400);
throw new HttpErrorException("Invalid parameter, page[size] must be a positive integer", 400);
} elseif ($pageSize > $maxPageSize) {
throw new HttpErrorException(sprintf("You requested a size of %d, but %d is the maximum.", $pageSize, $maxPageSize), 400);
}
Expand Down Expand Up @@ -713,7 +722,7 @@ public function patchOne(Request $request, Response $response, array $args): Res

// Return updated object
$newObject = $this->getFactory()->get($object->getId());
return self::getOneResource($this, $newObject, $request, $response, 201);
return self::getOneResource($this, $newObject, $request, $response, 200);
}


Expand Down Expand Up @@ -1002,8 +1011,18 @@ public function patchToManyRelationshipLink(Request $request, Response $response
if ($jsonBody === null || !array_key_exists('data', $jsonBody) || !is_array($jsonBody['data'])) {
throw new HttpErrorException('No data was sent! Send the json data in the following format: {"data":[{"type": "foo", "id": 1}}]');
}

$data = $jsonBody['data'];
$this->updateToManyRelationship($request, $data, $args);

return $response->withStatus(204)
->withHeader("Content-Type", "application/vnd.api+json");
}

/**
* Overidable function to update the to many relationship
*/
protected function updateToManyRelationship(Request $request, array $data, array $args): void {
$relation = $this->getToManyRelationships()[$args['relation']];
$primaryKey = $this->getPrimaryKeyOther($relation['relationType']);
$relationKey = $relation['relationKey'];
Expand All @@ -1029,7 +1048,7 @@ public function patchToManyRelationshipLink(Request $request, Response $response
foreach ($data as $item) {
if (!$this->validateResourceRecord($item)) {
$encoded_item = json_encode($item);
throw new HttpErrorException('Invallid resource record given in list! invalid resource record: ' . $encoded_item);
throw new HttpErrorException('Invalid resource record given in list! invalid resource record: ' . $encoded_item);
}
$updates[] = new MassUpdateSet($item["id"], $args["id"]);
unset($modelsDict[$item["id"]]);
Expand All @@ -1049,9 +1068,6 @@ public function patchToManyRelationshipLink(Request $request, Response $response
if (!$factory->getDB()->commit()) {
throw new HttpErrorException("Was not able to update to many relationship");
}

return $response->withStatus(204)
->withHeader("Content-Type", "application/vnd.api+json");
}

/**
Expand Down Expand Up @@ -1157,7 +1173,7 @@ protected function updateObject(object $object, array $data, array $processed =
*/
final public function getPatchValidFeatures(): array
{
$aliasedfeatures = $this->getAliasedFeatures();
$aliasedfeatures = $this->getFeaturesWithoutFormfields();
$validFeatures = [];

// Generate listing of validFeatures
Expand Down
Loading
Loading