Implemented some more functions for the Core RESTful API

Former-commit-id: 79af35336c
restapi
Jens Pelzetter 2020-07-24 20:42:49 +02:00
parent aae365f4f3
commit 52663e5b14
5 changed files with 332 additions and 25 deletions

View File

@ -1,3 +1,25 @@
/**
* A list view contains an array of objects and some data about the list.
*/
export interface ListView<T> {
/**
* The list of objects
*/
list: T[],
/**
* The number of elements for the query.
*/
count: number,
/**
* Items per page
*/
limit: number,
/**
* The first item shown
*/
offset: number,
}
/**
* Properties of the type `LocalizedString` are used in several entities
* returned by various of the endpoints the RESTful API of LibreCCM.
@ -7,3 +29,4 @@
export interface LocalizedString {
values: Record<string, string>
}

View File

@ -1,9 +1,15 @@
import {
ApiResponse,
LibreCcmApiClient,
ListView,
} from "@libreccm/ccm-apiclient-commons";
import { Category, buildCategoryFromRecord } from "../entities/categorization";
import {
Category,
Categorization,
buildCategoryFromRecord,
buildCategorizationFromRecord,
} from "../entities/categorization";
import * as Constants from "../constants";
export class CategorizationApiClient {
@ -69,7 +75,7 @@ export class CategorizationApiClient {
}
}
async updateCategoryByDomainAndPath(
async updateCategoryOfDomain(
domain: string,
path: string,
category: Category
@ -91,7 +97,7 @@ export class CategorizationApiClient {
}
}
async updateCategoryById(
async updateCategoryWithId(
categoryId: number,
category: Category
): Promise<void> {
@ -112,7 +118,7 @@ export class CategorizationApiClient {
}
}
async updateCategoryByUuid(
async updateCategoryWithUuid(
uuid: string,
category: Category
): Promise<void> {
@ -133,10 +139,7 @@ export class CategorizationApiClient {
}
}
async deleteCategoryByDomainAndPath(
domain: string,
path: string
): Promise<void> {
async deleteCategoryOfDomain(domain: string, path: string): Promise<void> {
try {
const response: ApiResponse = await this.#apiClient.delete(
`${this.#CATEGORIES_API_PREFIX}/${domain}/${path}`
@ -153,7 +156,7 @@ export class CategorizationApiClient {
}
}
async deleteCategoryById(categoryId: number): Promise<void> {
async deleteCategoryWithId(categoryId: number): Promise<void> {
try {
const response: ApiResponse = await this.#apiClient.delete(
`${this.#CATEGORIES_API_PREFIX}/ID-${categoryId}`
@ -170,12 +173,10 @@ export class CategorizationApiClient {
}
}
async deleteCategoryByUuid(
uuid: string,
): Promise<void> {
async deleteCategoryWithUuid(uuid: string): Promise<void> {
try {
const response: ApiResponse = await this.#apiClient.delete(
`${this.#CATEGORIES_API_PREFIX}/UUID-${uuid}`,
`${this.#CATEGORIES_API_PREFIX}/UUID-${uuid}`
);
if (response.ok) {
@ -188,4 +189,238 @@ export class CategorizationApiClient {
throw `Failed to delete category with UUID ${uuid}: ${err}`;
}
}
async getSubCategoriesByDomainAndPath(
domain: string,
path: string,
limit = 20,
offset = 0
): Promise<ListView<Category>> {
try {
const response: ApiResponse = await this.#apiClient.get(
`${
this.#CATEGORIES_API_PREFIX
}/${domain}/${path}?limit=${limit}&offset=${offset}`
);
if (response.ok) {
const result: Record<string, unknown> = await response.json();
const list: Record<string, unknown>[] = result.list as Record<
string,
unknown
>[];
const categories: Category[] = list.map((record) =>
buildCategoryFromRecord(record)
);
return {
list: categories,
count: result.count as number,
limit: result.limit as number,
offset: result.offset as number,
};
} else {
throw `Failed to get subcategories of category ${path} of
domain ${domain}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to get subcategories of category ${path} of
domain ${domain}: ${err}`;
}
}
async getSubCategoriesById(
categoryId: number,
limit = 20,
offset = 0
): Promise<ListView<Category>> {
try {
const response: ApiResponse = await this.#apiClient.get(
`${
this.#CATEGORIES_API_PREFIX
}/ID-${categoryId}?limit=${limit}&offset=${offset}`
);
if (response.ok) {
const result: Record<string, unknown> = await response.json();
const list: Record<string, unknown>[] = result.list as Record<
string,
unknown
>[];
const categories: Category[] = list.map((record) =>
buildCategoryFromRecord(record)
);
return {
list: categories,
count: result.count as number,
limit: result.limit as number,
offset: result.offset as number,
};
} else {
throw `Failed to get subcategories of category with ID
${categoryId}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to get subcategories of category with
ID ${categoryId}: ${err}`;
}
}
async getSubCategoriesByUuid(
uuid: string,
limit = 20,
offset = 0
): Promise<ListView<Category>> {
try {
const response: ApiResponse = await this.#apiClient.get(
`${
this.#CATEGORIES_API_PREFIX
}/UUID-${uuid}?limit=${limit}&offset=${offset}`
);
if (response.ok) {
const result: Record<string, unknown> = await response.json();
const list: Record<string, unknown>[] = result.list as Record<
string,
unknown
>[];
const categories: Category[] = list.map((record) =>
buildCategoryFromRecord(record)
);
return {
list: categories,
count: result.count as number,
limit: result.limit as number,
offset: result.offset as number,
};
} else {
throw `Failed to get subcategories of category with UUID
${uuid}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to get subcategories of category with
UUID ${uuid}: ${err}`;
}
}
/**
* Add a new subcategory to category
*
* @param domain
* @param path
* @param category
*
* @returns A Promise which resolves to the full path (including domain)
* of the new subcategory.
*/
async addSubCategoryToCategoryOfDomain(
domain: string,
path: string,
category: Category
): Promise<string> {
try {
const response: ApiResponse = await this.#apiClient.post(
`${this.#CATEGORIES_API_PREFIX}/${domain}/${path}`,
JSON.stringify(category)
);
if (response.ok) {
const result: string = await response.text();
return result;
} else {
throw `Failed to add new subcategory to category ${path} of
domain ${domain}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to add new subcategory to category ${path} of
domain ${domain}: ${err}`;
}
}
async addSubCategoryToWithId(
categoryId: number,
category: Category
): Promise<string> {
try {
const response: ApiResponse = await this.#apiClient.post(
`${this.#CATEGORIES_API_PREFIX}/ID-${categoryId}`,
JSON.stringify(category)
);
if (response.ok) {
const result: string = await response.text();
return result;
} else {
throw `Failed to add new subcategory to category with
ID ${categoryId}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to add new subcategory to category with
ID ${categoryId}: ${err}`;
}
}
async addSubCategoryToWithUuid(
uuid: string,
category: Category
): Promise<string> {
try {
const response: ApiResponse = await this.#apiClient.post(
`${this.#CATEGORIES_API_PREFIX}/UUID-${uuid}`,
JSON.stringify(category)
);
if (response.ok) {
const result: string = await response.text();
return result;
} else {
throw `Failed to add new subcategory to category with
UUID ${uuid}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to add new subcategory to category with
UUID ${uuid}: ${err}`;
}
}
async getObjectsInCategoryOfDomain(
domain: string,
path: string,
limit = 20,
offset = 0
): Promise<ListView<Categorization>> {
try {
const response: ApiResponse = await this.#apiClient.get(
`${
this.#CATEGORIES_API_PREFIX
}/$domain/${path}/objects?limit=${limit}&offset=${offset}`
);
if (response.ok) {
const result: Record<string, unknown> = await response.json();
const list: Record<string, unknown>[] = result.list as Record<
string,
unknown
>[];
const objects: Categorization[] = list.map((record) =>
buildCategorizationFromRecord(record)
);
return {
list: objects,
count: result.count as number,
limit: result.limit as number,
offset: result.offset as number
}
} else {
throw `Failed to get objects in category ${path} of
domain ${domain}: ${response.status} ${response.statusText}`;
}
} catch (err) {
throw `Failed to get objects in category ${path} of
domain ${domain}: ${err}`;
}
}
}

View File

@ -2,6 +2,7 @@ import {
LocalizedString,
assertProperties,
} from "@libreccm/ccm-apiclient-commons";
import { CcmObjectId } from "./core";
export interface AssociatedCategory {
name: string;
@ -22,6 +23,16 @@ export interface Category {
categoryOrder: number;
}
export interface Categorization {
categorizationId: number;
uuid: string;
categorizedObject: CcmObjectId;
indexObject: boolean;
categoryOrder: number;
objectOrder: number;
type: string;
}
export function buildCategoryFromRecord(
record: Record<string, unknown>
): Category {
@ -55,3 +66,27 @@ export function buildCategoryFromRecord(
categoryOrder: record.categoryOrder as number,
};
}
export function buildCategorizationFromRecord(
record: Record<string, unknown>
): Categorization {
assertProperties(record, [
"categorizationId",
"uuid",
"categorizedObject",
"indexObject",
"categoryOrder",
"objectOrder",
"type"
]);
return {
categorizationId: record.categorizationId as number,
uuid: record.uuid as string,
categorizedObject: record.categorizedObject as CcmObjectId,
indexObject: record.indexObject as boolean,
categoryOrder: record.categoryOrder as number,
objectOrder: record.objectOrder as number,
type: record.type as string
}
}

View File

@ -0,0 +1,8 @@
/**
* Basic data about an `CcmObject`.
*/
export interface CcmObjectId {
objectId: number,
uuid: string,
displayName: string
}

View File

@ -266,7 +266,7 @@
"schema" : {
"type" : "integer",
"format" : "int32",
"default" : 20
"default" : 0
}
} ],
"responses" : {
@ -333,14 +333,16 @@
"in" : "query",
"schema" : {
"type" : "integer",
"format" : "int32"
"format" : "int32",
"default" : 20
}
}, {
"name" : "offset",
"in" : "query",
"schema" : {
"type" : "integer",
"format" : "int32"
"format" : "int32",
"default" : 0
}
} ],
"responses" : {
@ -379,14 +381,16 @@
"in" : "query",
"schema" : {
"type" : "integer",
"format" : "int32"
"format" : "int32",
"default" : 20
}
}, {
"name" : "offset",
"in" : "query",
"schema" : {
"type" : "integer",
"format" : "int32"
"format" : "int32",
"default" : 0
}
} ],
"responses" : {
@ -454,14 +458,16 @@
"in" : "query",
"schema" : {
"type" : "integer",
"format" : "int32"
"format" : "int32",
"default" : 20
}
}, {
"name" : "offset",
"in" : "query",
"schema" : {
"type" : "integer",
"format" : "int32"
"format" : "int32",
"default" : 0
}
} ],
"responses" : {
@ -601,9 +607,9 @@
}
}
},
"/api/admin/categories/UUID-{categoryId}/objects/objectIdentifier" : {
"/api/admin/categories/UUID-{categoryId}/objects/{objectIdentifier}" : {
"delete" : {
"operationId" : "removeObjectsFromCategory",
"operationId" : "removeObjectFromCategory_2",
"parameters" : [ {
"name" : "categoryId",
"in" : "path",
@ -678,7 +684,7 @@
"schema" : {
"type" : "integer",
"format" : "int32",
"default" : 20
"default" : 0
}
} ],
"responses" : {
@ -720,7 +726,7 @@
"schema" : {
"type" : "integer",
"format" : "int32",
"default" : 20
"default" : 0
}
} ],
"responses" : {