From f7c5f1b8bcebcb5c61c366b27a23fa7026accacd Mon Sep 17 00:00:00 2001 From: afonso Date: Wed, 16 Oct 2024 20:26:08 +0100 Subject: [PATCH] CSCKAN-323 feat: Move ownership check to statement service --- backend/composer/api/views.py | 3 +- frontend/package-lock.json | 2 +- frontend/src/apiclient/backend/api.ts | 233 ++++++++++++++++-- frontend/src/components/Forms/FormBase.tsx | 11 +- .../src/components/Forms/StatementForm.tsx | 12 +- frontend/src/helpers/ownershipAlert.ts | 64 ++--- .../src/services/CustomDropdownService.ts | 22 +- frontend/src/services/StatementService.ts | 142 ++++++++--- openapi/openapi.yaml | 140 ++++++++++- 9 files changed, 516 insertions(+), 113 deletions(-) diff --git a/backend/composer/api/views.py b/backend/composer/api/views.py index 5e56dc36..4f2d887b 100644 --- a/backend/composer/api/views.py +++ b/backend/composer/api/views.py @@ -388,13 +388,14 @@ def partial_update(self, request, *args, **kwargs): return response - @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated]) + @action(detail=True, methods=['patch'], permission_classes=[permissions.IsAuthenticated]) def assign_owner(self, request, pk=None): instance = self.get_object() instance.owner = request.user instance.save() return Response(self.get_serializer(instance).data) + @extend_schema(tags=["public"]) class KnowledgeStatementViewSet( generics.ListAPIView, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d41db89c..78fab1c2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "frontend", - "version": "2.0.1", + "version": "3.0.0", "dependencies": { "@babel/preset-env": "^7.21.5", "@dnd-kit/core": "^6.0.8", diff --git a/frontend/src/apiclient/backend/api.ts b/frontend/src/apiclient/backend/api.ts index afad46f2..01408b3c 100644 --- a/frontend/src/apiclient/backend/api.ts +++ b/frontend/src/apiclient/backend/api.ts @@ -1336,6 +1336,211 @@ export interface PaginatedViaList { */ 'results'?: Array; } +/** + * Connectivity Statement + * @export + * @interface PatchedConnectivityStatement + */ +export interface PatchedConnectivityStatement { + /** + * + * @type {number} + * @memberof PatchedConnectivityStatement + */ + 'id'?: number | null; + /** + * + * @type {number} + * @memberof PatchedConnectivityStatement + */ + 'sentence_id'?: number; + /** + * + * @type {Sentence} + * @memberof PatchedConnectivityStatement + */ + 'sentence'?: Sentence; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'knowledge_statement'?: string; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'tags'?: Array; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'provenances'?: Array; + /** + * + * @type {User} + * @memberof PatchedConnectivityStatement + */ + 'owner'?: User; + /** + * + * @type {number} + * @memberof PatchedConnectivityStatement + */ + 'owner_id'?: number | null; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'state'?: string; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'available_transitions'?: Array; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'origins'?: Array; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'vias'?: Array; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'destinations'?: Array; + /** + * + * @type {number} + * @memberof PatchedConnectivityStatement + */ + 'phenotype_id'?: number | null; + /** + * + * @type {Phenotype} + * @memberof PatchedConnectivityStatement + */ + 'phenotype'?: Phenotype; + /** + * + * @type {ProjectionPhenotype} + * @memberof PatchedConnectivityStatement + */ + 'projection_phenotype'?: ProjectionPhenotype; + /** + * + * @type {number} + * @memberof PatchedConnectivityStatement + */ + 'projection_phenotype_id'?: number | null; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'journey'?: string; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'entities_journey'?: string; + /** + * + * @type {ConnectivityStatementLaterality} + * @memberof PatchedConnectivityStatement + */ + 'laterality'?: ConnectivityStatementLaterality | null; + /** + * + * @type {ConnectivityStatementProjection} + * @memberof PatchedConnectivityStatement + */ + 'projection'?: ConnectivityStatementProjection | null; + /** + * + * @type {ConnectivityStatementCircuitType} + * @memberof PatchedConnectivityStatement + */ + 'circuit_type'?: ConnectivityStatementCircuitType | null; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'species'?: Array; + /** + * + * @type {number} + * @memberof PatchedConnectivityStatement + */ + 'sex_id'?: number | null; + /** + * + * @type {Sex} + * @memberof PatchedConnectivityStatement + */ + 'sex'?: Sex; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'forward_connection'?: Array; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'apinatomy_model'?: string | null; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'additional_information'?: string | null; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'modified_date'?: string; + /** + * + * @type {boolean} + * @memberof PatchedConnectivityStatement + */ + 'has_notes'?: boolean; + /** + * + * @type {string} + * @memberof PatchedConnectivityStatement + */ + 'statement_preview'?: string; + /** + * + * @type {Array} + * @memberof PatchedConnectivityStatement + */ + 'errors'?: Array; + /** + * + * @type {GraphState} + * @memberof PatchedConnectivityStatement + */ + 'graph_rendering_state'?: GraphState | null; +} /** * Connectivity Statement * @export @@ -2628,13 +2833,13 @@ export const ComposerApiAxiosParamCreator = function (configuration?: Configurat /** * ConnectivityStatement * @param {number} id A unique integer value identifying this connectivity statement. - * @param {ConnectivityStatement} [connectivityStatement] + * @param {PatchedConnectivityStatement} [patchedConnectivityStatement] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - composerConnectivityStatementAssignOwnerCreate: async (id: number, connectivityStatement?: ConnectivityStatement, options: AxiosRequestConfig = {}): Promise => { + composerConnectivityStatementAssignOwnerPartialUpdate: async (id: number, patchedConnectivityStatement?: PatchedConnectivityStatement, options: AxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined - assertParamExists('composerConnectivityStatementAssignOwnerCreate', 'id', id) + assertParamExists('composerConnectivityStatementAssignOwnerPartialUpdate', 'id', id) const localVarPath = `/api/composer/connectivity-statement/{id}/assign_owner/` .replace(`{${"id"}}`, encodeURIComponent(String(id))); // use dummy base URL string because the URL constructor only accepts absolute URLs. @@ -2644,7 +2849,7 @@ export const ComposerApiAxiosParamCreator = function (configuration?: Configurat baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'PATCH', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -2664,7 +2869,7 @@ export const ComposerApiAxiosParamCreator = function (configuration?: Configurat setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(connectivityStatement, localVarRequestOptions, configuration) + localVarRequestOptions.data = serializeDataIfNeeded(patchedConnectivityStatement, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -5141,12 +5346,12 @@ export const ComposerApiFp = function(configuration?: Configuration) { /** * ConnectivityStatement * @param {number} id A unique integer value identifying this connectivity statement. - * @param {ConnectivityStatement} [connectivityStatement] + * @param {PatchedConnectivityStatement} [patchedConnectivityStatement] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async composerConnectivityStatementAssignOwnerCreate(id: number, connectivityStatement?: ConnectivityStatement, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.composerConnectivityStatementAssignOwnerCreate(id, connectivityStatement, options); + async composerConnectivityStatementAssignOwnerPartialUpdate(id: number, patchedConnectivityStatement?: PatchedConnectivityStatement, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.composerConnectivityStatementAssignOwnerPartialUpdate(id, patchedConnectivityStatement, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -5772,12 +5977,12 @@ export const ComposerApiFactory = function (configuration?: Configuration, baseP /** * ConnectivityStatement * @param {number} id A unique integer value identifying this connectivity statement. - * @param {ConnectivityStatement} [connectivityStatement] + * @param {PatchedConnectivityStatement} [patchedConnectivityStatement] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - composerConnectivityStatementAssignOwnerCreate(id: number, connectivityStatement?: ConnectivityStatement, options?: any): AxiosPromise { - return localVarFp.composerConnectivityStatementAssignOwnerCreate(id, connectivityStatement, options).then((request) => request(axios, basePath)); + composerConnectivityStatementAssignOwnerPartialUpdate(id: number, patchedConnectivityStatement?: PatchedConnectivityStatement, options?: any): AxiosPromise { + return localVarFp.composerConnectivityStatementAssignOwnerPartialUpdate(id, patchedConnectivityStatement, options).then((request) => request(axios, basePath)); }, /** * ConnectivityStatement @@ -6361,13 +6566,13 @@ export class ComposerApi extends BaseAPI { /** * ConnectivityStatement * @param {number} id A unique integer value identifying this connectivity statement. - * @param {ConnectivityStatement} [connectivityStatement] + * @param {PatchedConnectivityStatement} [patchedConnectivityStatement] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ComposerApi */ - public composerConnectivityStatementAssignOwnerCreate(id: number, connectivityStatement?: ConnectivityStatement, options?: AxiosRequestConfig) { - return ComposerApiFp(this.configuration).composerConnectivityStatementAssignOwnerCreate(id, connectivityStatement, options).then((request) => request(this.axios, this.basePath)); + public composerConnectivityStatementAssignOwnerPartialUpdate(id: number, patchedConnectivityStatement?: PatchedConnectivityStatement, options?: AxiosRequestConfig) { + return ComposerApiFp(this.configuration).composerConnectivityStatementAssignOwnerPartialUpdate(id, patchedConnectivityStatement, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/frontend/src/components/Forms/FormBase.tsx b/frontend/src/components/Forms/FormBase.tsx index fd672c59..af99395b 100644 --- a/frontend/src/components/Forms/FormBase.tsx +++ b/frontend/src/components/Forms/FormBase.tsx @@ -32,7 +32,7 @@ export const FormBase = (props: any) => { showErrorList, submitOnChangeFields = [], submitOnBlurFields = [], - onErrorAction, + onUnauthorizedSave: onSaveCancel, } = props; const [localData, setLocalData] = useState(data); const [isSaving, setIsSaving] = useState(false); @@ -104,9 +104,10 @@ export const FormBase = (props: any) => { const handleSubmit = async (event: IChangeEvent) => { const formData = {...event.formData, ...extraData}; + const saveOptions = onSaveCancel ? { onCancel: onSaveCancel } : {}; setIsSaving(true); service - .save(formData) + .save(formData, saveOptions) .then((newData: any) => { setter && setter(newData); // todo: improve UI feedback @@ -117,11 +118,7 @@ export const FormBase = (props: any) => { setLocalData(formData); }) .catch((error: any) => { - if (onErrorAction) { - onErrorAction(error, formData); // Custom error handling - } else { - log(`Something went wrong ${error}`); // Default error handling - } + log(`Something went wrong ${error}`); // Default error handling }) .finally(() => { setIsSaving(false); diff --git a/frontend/src/components/Forms/StatementForm.tsx b/frontend/src/components/Forms/StatementForm.tsx index e6ba8dff..8430c22f 100644 --- a/frontend/src/components/Forms/StatementForm.tsx +++ b/frontend/src/components/Forms/StatementForm.tsx @@ -700,21 +700,12 @@ const StatementForm = (props: any) => { SelectWidget: CustomSingleSelect, }; - const handleErrorAction = (error: any, newStatementData: ConnectivityStatement) => { - checkOwnership( - statement.id, - (fetchedData, userId) => statementService.save({...newStatementData, owner_id: userId}) - .then(() => refreshStatement()), - () => refreshStatement(), - (owner) => getOwnershipAlertMessage(owner) - ); - }; - return ( { "projection", "projection_phenotype_id", ]} - onErrorAction={(error: any, formData: any) => handleErrorAction(error, formData)} {...props} /> ); diff --git a/frontend/src/helpers/ownershipAlert.ts b/frontend/src/helpers/ownershipAlert.ts index 55485ab9..976cae3f 100644 --- a/frontend/src/helpers/ownershipAlert.ts +++ b/frontend/src/helpers/ownershipAlert.ts @@ -7,41 +7,45 @@ export const checkOwnership = ( onSave: (fetchedData: any, userId: number) => Promise, onCancel: (fetchedData: any, userId: number) => void, alertMessage: (owner: any) => string -) => { +): Promise => { const userId = userProfile.getUser().id; - // Fetch the latest data to check for ownership - statementService.getObject(id.toString()) - .then((fetchedData: any) => { - // Check if the fetched data has an owner and if the current user is not the owner - if (fetchedData.owner && fetchedData.owner.id !== userProfile.getUser().id) { - const userConfirmed = window.confirm(alertMessage(fetchedData.owner)); + return new Promise((resolve, reject) => { + // Fetch the latest data to check for ownership + statementService.getObject(id.toString()) + .then((fetchedData: any) => { + // Check if the fetched data has an owner and if the current user is not the owner + if (fetchedData.owner && fetchedData.owner.id !== userId) { + const userConfirmed = window.confirm(alertMessage(fetchedData.owner)); - if (userConfirmed) { - - // Reassign ownership and save the data - statementService.assignOwner(fetchedData.id, { - ...fetchedData, - owner_id: userId, // Assign ownership to the current user - }) - .then(() => { - // Call the merged save action - return onSave(fetchedData, userId) - }) - .catch((error) => { - console.error("Failed to reassign ownership", error); - onCancel(fetchedData, userId); - }); - } else { - onCancel(fetchedData, userId); + if (userConfirmed) { + // Reassign ownership and save the data + statementService.assignOwner(fetchedData.id, {}) + .then(() => { + // Call the merged save action + return onSave(fetchedData, userId) + .then((result) => resolve(result)) + .catch((error) => reject(error)); + }) + .catch((error) => { + console.error("Failed to reassign ownership", error); + onCancel(fetchedData, userId); + reject(error); + }); + } else { + onCancel(fetchedData, userId); + resolve(); // Resolve since user canceled, but operation is complete + } } - } - }) - .catch((fetchError) => { - console.error("Failed to fetch the data", fetchError); - onCancel(null, userId); - }); + }) + .catch((fetchError) => { + console.error("Failed to fetch the data", fetchError); + onCancel(null, userId); + reject(fetchError); + }); + }); }; + export const getOwnershipAlertMessage = (owner: User) => { return `This statement is currently assigned to ${owner.first_name}. You are in read-only mode. Would you like to assign this statement to yourself and gain edit access?` } \ No newline at end of file diff --git a/frontend/src/services/CustomDropdownService.ts b/frontend/src/services/CustomDropdownService.ts index 8f2e7f60..b58b5e2c 100644 --- a/frontend/src/services/CustomDropdownService.ts +++ b/frontend/src/services/CustomDropdownService.ts @@ -43,24 +43,22 @@ export async function getAnatomicalEntities( } } -export async function updateOrigins(selected: Option[], statementId: number, - setStatement: (statement: any) => void) { +export async function updateOrigins( + selected: Option[], + statementId: number, + setStatement: (statement: any) => void +) { const originIds = selected.map((option) => parseInt(option.id)); const patchedStatement: PatchedConnectivityStatementUpdate = { origins: originIds, }; + try { - await statementService.partialUpdate( - statementId, - patchedStatement, - ); + await statementService.partialUpdate(statementId, patchedStatement, () => { + console.log("User canceled ownership reassignment."); + }); } catch (error) { - checkOwnership( - statementId, - () => statementService.partialUpdate(statementId, patchedStatement), - (fetchedStatement) => setStatement(fetchedStatement), - (owner: User) => getOwnershipAlertMessage(owner) - ); + console.error("Error updating origins:", error); } } diff --git a/frontend/src/services/StatementService.ts b/frontend/src/services/StatementService.ts index c0d66c47..d32ce9f9 100644 --- a/frontend/src/services/StatementService.ts +++ b/frontend/src/services/StatementService.ts @@ -1,77 +1,155 @@ -import { composerApi } from "./apis" +import {composerApi} from "./apis" import { AnatomicalEntity, ConnectivityStatement, ConnectivityStatementUpdate, - PaginatedBaseConnectivityStatementList, + PaginatedBaseConnectivityStatementList, PatchedConnectivityStatement, PatchedConnectivityStatementUpdate } from '../apiclient/backend' -import { AbstractService } from "./AbstractService" -import { QueryParams } from "../redux/statementSlice" +import {AbstractService} from "./AbstractService" +import {QueryParams} from "../redux/statementSlice" +import {checkOwnership} from "../helpers/ownershipAlert"; class ConnectivityStatementService extends AbstractService { - async save(connectivityStatement: ConnectivityStatement) { - - connectivityStatement.forward_connection = connectivityStatement.forward_connection?.map((cs:any) => cs.id) + async save( + connectivityStatement: ConnectivityStatement, + options: { onCancel?: () => void } = {} // Options object with defaults + ) { + const { + onCancel = () => { + } + } = options; + connectivityStatement.forward_connection = connectivityStatement.forward_connection?.map((cs: any) => cs.id); if (connectivityStatement.id) { const updateData: ConnectivityStatementUpdate = { ...connectivityStatement, - origins: connectivityStatement.origins?.map((o: AnatomicalEntity) => o.id) || [] + origins: connectivityStatement.origins?.map((o: AnatomicalEntity) => o.id) || [], }; - return this.update(updateData) + return await this.update(updateData, onCancel); // Pass onCancel to update } - return composerApi.composerConnectivityStatementCreate(connectivityStatement).then((response: any) => response.data) + + // If it's a new connectivity statement, creation doesn't need ownership check + return composerApi.composerConnectivityStatementCreate(connectivityStatement).then((response: any) => response.data); } - async update(connectivityStatement: ConnectivityStatementUpdate) { - const id = connectivityStatement.id || -1 - return composerApi.composerConnectivityStatementUpdate(id, connectivityStatement).then((response: any) => response.data) + + async update( + connectivityStatement: ConnectivityStatementUpdate, + onCancel: () => void = () => { + } + ) { + const id = connectivityStatement.id || -1; + + try { + return await composerApi.composerConnectivityStatementUpdate(id, connectivityStatement).then((response: any) => response.data); + } catch (error) { + return await checkOwnership( + id, + // Retry the update after ownership is reassigned, including new owner ID + async (userId: number) => { + const updatedStatement = { + ...connectivityStatement, + owner_id: userId, + }; + return composerApi.composerConnectivityStatementUpdate(id, updatedStatement).then((response: any) => response.data); + }, + onCancel, + (owner) => + `This statement is currently assigned to ${owner.first_name}. You are in read-only mode. Would you like to assign this statement to yourself and gain edit access?`, + ); + } } - async partialUpdate(id: number, patchedConnectivityStatementUpdate: PatchedConnectivityStatementUpdate) { - return composerApi.composerConnectivityStatementPartialUpdate(id, patchedConnectivityStatementUpdate).then((response: any) => response.data) + async partialUpdate( + id: number, + patchedConnectivityStatementUpdate: PatchedConnectivityStatementUpdate, + onCancel: () => void = () => { + } + ) { + try { + return await composerApi.composerConnectivityStatementPartialUpdate(id, patchedConnectivityStatementUpdate).then((response: any) => response.data); + } catch (error) { + return checkOwnership( + id, + // Retry the partial update after ownership is reassigned, including new owner ID + async (userId: number) => { + const updatedPatchedStatement = { + ...patchedConnectivityStatementUpdate, + owner_id: userId, + }; + return composerApi.composerConnectivityStatementPartialUpdate(id, updatedPatchedStatement).then((response: any) => response.data); + }, + onCancel, + (owner) => + `This statement is currently assigned to ${owner.first_name}. You are in read-only mode. Would you like to assign this statement to yourself and gain edit access?`, + ); + } } + async remove(id: number) { - return composerApi.composerConnectivityStatementDestroy(id).then((response: any) => response.data) + return composerApi.composerConnectivityStatementDestroy(id).then((response: any) => response.data); } + async clone(id: number) { - return composerApi.composerConnectivityStatementCloneStatementRetrieve(id).then((response: any) => response.data) + return composerApi.composerConnectivityStatementCloneStatementRetrieve(id).then((response: any) => response.data); } + async getObject(id: string): Promise { - return composerApi.composerConnectivityStatementRetrieve(Number(id)).then((response: any) => response.data) + return composerApi.composerConnectivityStatementRetrieve(Number(id)).then((response: any) => response.data); } + async doTransition(connectivityStatement: ConnectivityStatement, transition: string) { - const id = connectivityStatement.id || -1 - return composerApi.composerConnectivityStatementDoTransitionCreate(id, transition, connectivityStatement).then((response: any) => response.data) + const id = connectivityStatement.id || -1; + return composerApi.composerConnectivityStatementDoTransitionCreate(id, transition, connectivityStatement).then((response: any) => response.data); } + async addTag(id: number, tagId: number): Promise { - return composerApi.composerConnectivityStatementAddTagCreate(id, tagId).then((response: any) => response.data) + return composerApi.composerConnectivityStatementAddTagCreate(id, tagId).then((response: any) => response.data); } + async addSpecie(id: number, specieId: number): Promise { - return composerApi.composerConnectivityStatementAddSpecieCreate(id, specieId).then((response: any) => response.data) + return composerApi.composerConnectivityStatementAddSpecieCreate(id, specieId).then((response: any) => response.data); } + async removeTag(id: number, tagId: number): Promise { - return composerApi.composerConnectivityStatementDelTagCreate(id, tagId).then((response: any) => response.data) + return composerApi.composerConnectivityStatementDelTagCreate(id, tagId).then((response: any) => response.data); } + async removeSpecie(id: number, specieId: number): Promise { - return composerApi.composerConnectivityStatementDelSpecieCreate(id, specieId).then((response: any) => response.data) + return composerApi.composerConnectivityStatementDelSpecieCreate(id, specieId).then((response: any) => response.data); } + async getList(queryOptions: QueryParams): Promise { - const { origins, limit, ordering, index, knowledgeStatement, stateFilter, tagFilter, sentenceId, excludeSentenceId, excludeIds } = queryOptions - return composerApi.composerConnectivityStatementList(undefined, excludeIds, excludeSentenceId, knowledgeStatement, limit, undefined, index, ordering, origins, sentenceId, stateFilter, tagFilter).then((res: any) => res.data) + const { + origins, + limit, + ordering, + index, + knowledgeStatement, + stateFilter, + tagFilter, + sentenceId, + excludeSentenceId, + excludeIds + } = queryOptions; + return composerApi.composerConnectivityStatementList( + undefined, excludeIds, excludeSentenceId, knowledgeStatement, limit, undefined, index, ordering, origins, sentenceId, stateFilter, tagFilter + ).then((res: any) => res.data); } + async getPhenotypeList() { - return composerApi.composerPhenotypeList(undefined).then((res: any) => res.data) + return composerApi.composerPhenotypeList(undefined).then((res: any) => res.data); } + async getSexList() { - return composerApi.composerSexList(undefined).then((res: any) => res.data) + return composerApi.composerSexList(undefined).then((res: any) => res.data); } - async assignOwner(id: number, connectivityStatement?: ConnectivityStatement): Promise { - return composerApi.composerConnectivityStatementAssignOwnerCreate(id, connectivityStatement).then((response: any) => response.data); + async assignOwner(id: number, patchedConnectivityStatement?: PatchedConnectivityStatement): Promise { + return composerApi.composerConnectivityStatementAssignOwnerPartialUpdate(id, patchedConnectivityStatement).then((response: any) => response.data); } } -const connectivityStatementService = new ConnectivityStatementService() -export default connectivityStatementService +const connectivityStatementService = new ConnectivityStatementService(); +export default connectivityStatementService; diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 1566d54f..25bcbd4e 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -412,8 +412,8 @@ paths: $ref: '#/components/schemas/ConnectivityStatement' description: '' /api/composer/connectivity-statement/{id}/assign_owner/: - post: - operationId: composer_connectivity_statement_assign_owner_create + patch: + operationId: composer_connectivity_statement_assign_owner_partial_update description: ConnectivityStatement parameters: - in: path @@ -428,13 +428,13 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConnectivityStatement' + $ref: '#/components/schemas/PatchedConnectivityStatement' application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/ConnectivityStatement' + $ref: '#/components/schemas/PatchedConnectivityStatement' multipart/form-data: schema: - $ref: '#/components/schemas/ConnectivityStatement' + $ref: '#/components/schemas/PatchedConnectivityStatement' security: - tokenAuth: [] - basicAuth: [] @@ -2756,6 +2756,136 @@ components: type: array items: $ref: '#/components/schemas/Via' + PatchedConnectivityStatement: + type: object + description: Connectivity Statement + properties: + id: + type: integer + readOnly: true + nullable: true + sentence_id: + type: integer + sentence: + allOf: + - $ref: '#/components/schemas/Sentence' + readOnly: true + knowledge_statement: + type: string + tags: + type: array + items: + $ref: '#/components/schemas/Tag' + readOnly: true + provenances: + type: array + items: + $ref: '#/components/schemas/Provenance' + owner: + allOf: + - $ref: '#/components/schemas/User' + readOnly: true + owner_id: + type: integer + nullable: true + state: + type: string + readOnly: true + available_transitions: + type: array + items: + $ref: '#/components/schemas/AvailableTransitions24dEnum' + readOnly: true + origins: + type: array + items: + $ref: '#/components/schemas/AnatomicalEntity' + vias: + type: array + items: + $ref: '#/components/schemas/ViaSerializerDetails' + destinations: + type: array + items: + $ref: '#/components/schemas/DestinationSerializerDetails' + phenotype_id: + type: integer + nullable: true + phenotype: + allOf: + - $ref: '#/components/schemas/Phenotype' + readOnly: true + projection_phenotype: + allOf: + - $ref: '#/components/schemas/ProjectionPhenotype' + readOnly: true + projection_phenotype_id: + type: integer + nullable: true + journey: + type: string + readOnly: true + entities_journey: + type: string + readOnly: true + laterality: + nullable: true + oneOf: + - $ref: '#/components/schemas/LateralityEnum' + - $ref: '#/components/schemas/BlankEnum' + - $ref: '#/components/schemas/NullEnum' + projection: + nullable: true + oneOf: + - $ref: '#/components/schemas/ProjectionEnum' + - $ref: '#/components/schemas/BlankEnum' + - $ref: '#/components/schemas/NullEnum' + circuit_type: + nullable: true + oneOf: + - $ref: '#/components/schemas/CircuitTypeEnum' + - $ref: '#/components/schemas/BlankEnum' + - $ref: '#/components/schemas/NullEnum' + species: + type: array + items: + $ref: '#/components/schemas/Specie' + sex_id: + type: integer + nullable: true + sex: + allOf: + - $ref: '#/components/schemas/Sex' + readOnly: true + forward_connection: + type: array + items: + type: integer + apinatomy_model: + type: string + nullable: true + maxLength: 200 + additional_information: + type: string + nullable: true + modified_date: + type: string + format: date-time + readOnly: true + has_notes: + type: boolean + readOnly: true + statement_preview: + type: string + readOnly: true + errors: + type: array + items: {} + readOnly: true + graph_rendering_state: + allOf: + - $ref: '#/components/schemas/GraphState' + nullable: true PatchedConnectivityStatementUpdate: type: object description: Connectivity Statement