♻️ backend,oo: split endEditing into add version and actual end, via "updateEditing" (#525)

This commit is contained in:
Eric Doughty-Papassideris
2024-09-17 17:37:20 +02:00
parent c9db0bf3d7
commit 816fb58e89
5 changed files with 56 additions and 27 deletions
@@ -977,6 +977,8 @@ export class DocumentsService {
return null; return null;
} }
//TODO: This needs to try in a loop depending on oo-connector response
// when there is already a key
let newKey: string; let newKey: string;
try { try {
newKey = EditingSessionKeyFormat.generate( newKey = EditingSessionKeyFormat.generate(
@@ -986,6 +988,7 @@ export class DocumentsService {
context.user.id, context.user.id,
); );
} catch (e) { } catch (e) {
logger.error(`Error generating new editing_session_key: ${e}`, { error: e });
CrudException.throwMe(e, new CrudException("Error generating new editing_session_key", 500)); CrudException.throwMe(e, new CrudException("Error generating new editing_session_key", 500));
} }
@@ -1026,12 +1029,15 @@ export class DocumentsService {
* @param editing_session_key Editing key of the DriveFile * @param editing_session_key Editing key of the DriveFile
* @param file Multipart files from the incoming http request * @param file Multipart files from the incoming http request
* @param options Optional upload information from the request * @param options Optional upload information from the request
* @param keepEditing If `true`, the file will be saved as a new version,
* and the DriveFile will keep its editing_session_key. If `true`, a file is required.
* @param context * @param context
*/ */
endEditing = async ( updateEditing = async (
editing_session_key: string, editing_session_key: string,
file: MultipartFile, file: MultipartFile,
options: UploadOptions, options: UploadOptions,
keepEditing: boolean,
context: CompanyExecutionContext, context: CompanyExecutionContext,
) => { ) => {
if (!context) { if (!context) {
@@ -1043,6 +1049,7 @@ export class DocumentsService {
throw new CrudException("Invalid editing_session_key", 400); throw new CrudException("Invalid editing_session_key", 400);
} }
//TODO If the app is the "user" calling, set user to that from the parsed key
try { try {
const parsedKey = EditingSessionKeyFormat.parse(editing_session_key); const parsedKey = EditingSessionKeyFormat.parse(editing_session_key);
context = { context = {
@@ -1087,26 +1094,31 @@ export class DocumentsService {
}, },
context, context,
); );
} else if (keepEditing) {
this.logger.error("Inconsistent endEditing call");
throw new CrudException("Inconsistent endEditing call", 500);
} }
try { if (!keepEditing) {
const result = await this.repository.atomicCompareAndSet( try {
driveFile, const result = await this.repository.atomicCompareAndSet(
"editing_session_key", driveFile,
editing_session_key, "editing_session_key",
null, editing_session_key,
); null,
if (!result.didSet)
throw new Error(
`Couldn't set editing_session_key ${JSON.stringify(
editing_session_key,
)} on DriveFile ${JSON.stringify(driveFile.id)} because it is ${JSON.stringify(
result.currentValue,
)}`,
); );
} catch (error) { if (!result.didSet)
logger.error({ error: `${error}` }, "Failed to cancel editing Drive item"); throw new Error(
CrudException.throwMe(error, new CrudException("Failed to cancel editing Drive item", 500)); `Couldn't set editing_session_key ${JSON.stringify(
editing_session_key,
)} on DriveFile ${JSON.stringify(driveFile.id)} because it is ${JSON.stringify(
result.currentValue,
)}`,
);
} catch (error) {
logger.error({ error: `${error}` }, "Failed to cancel editing Drive item");
CrudException.throwMe(error, new CrudException("Failed to cancel editing Drive item", 500));
}
} }
}; };
@@ -381,10 +381,11 @@ export class DocumentsController {
if (!editing_session_key) throw new CrudException("Missing editing_session_key", 400); if (!editing_session_key) throw new CrudException("Missing editing_session_key", 400);
return await globalResolver.services.documents.documents.endEditing( return await globalResolver.services.documents.documents.updateEditing(
editing_session_key, editing_session_key,
null, null,
null, null,
false,
context, context,
); );
} catch (error) { } catch (error) {
@@ -394,12 +395,13 @@ export class DocumentsController {
}; };
//TODO: will need a save under session key, but without ending the edit (for force saves) //TODO: will need a save under session key, but without ending the edit (for force saves)
/** /**
* Finish an editing session for a given `editing_session_key` by uploading the new version of the File * Finish an editing session for a given `editing_session_key` by uploading the new version of the File.
* Unless the `keepEditing` query param is `true`, then just save and stay in editing mode.
*/ */
endEditing = async ( updateEditing = async (
request: FastifyRequest<{ request: FastifyRequest<{
Params: ItemRequestByEditingSessionKeyParams; Params: ItemRequestByEditingSessionKeyParams;
Querystring: Record<string, string>; Querystring: { keepEditing?: string };
Body: { Body: {
item: Partial<DriveFile>; item: Partial<DriveFile>;
version: Partial<FileVersion>; version: Partial<FileVersion>;
@@ -423,17 +425,19 @@ export class DocumentsController {
waitForThumbnail: !!q.thumbnail_sync, waitForThumbnail: !!q.thumbnail_sync,
ignoreThumbnails: false, ignoreThumbnails: false,
}; };
return await globalResolver.services.documents.documents.endEditing( return await globalResolver.services.documents.documents.updateEditing(
editing_session_key, editing_session_key,
file, file,
options, options,
request.query.keepEditing == "true",
context, context,
); );
} else { } else {
return await globalResolver.services.documents.documents.endEditing( return await globalResolver.services.documents.documents.updateEditing(
editing_session_key, editing_session_key,
null, null,
null, null,
true,
context, context,
); );
} }
@@ -99,7 +99,7 @@ const routes: FastifyPluginCallback = (fastify: FastifyInstance, _options, next)
method: "POST", method: "POST",
url: editingSessionBase, url: editingSessionBase,
preValidation: [fastify.authenticateOptional], preValidation: [fastify.authenticateOptional],
handler: documentsController.endEditing.bind(documentsController), handler: documentsController.updateEditing.bind(documentsController),
}); });
fastify.route({ fastify.route({
@@ -21,6 +21,7 @@ export interface IDriveService {
get: (params: DriveRequestParams) => Promise<DriveFileType>; get: (params: DriveRequestParams) => Promise<DriveFileType>;
createVersion: (params: { company_id: string; drive_file_id: string; file_id: string }) => Promise<DriveFileType['item']['last_version_cache']>; createVersion: (params: { company_id: string; drive_file_id: string; file_id: string }) => Promise<DriveFileType['item']['last_version_cache']>;
beginEditingSession: (company_id: string, drive_file_id: string) => Promise<string>; beginEditingSession: (company_id: string, drive_file_id: string) => Promise<string>;
addEditingSessionVersion: (editing_session_key: string, url: string) => Promise<void>;
endEditing: (editing_session_key: string, url: string) => Promise<void>; endEditing: (editing_session_key: string, url: string) => Promise<void>;
getByEditingSessionKey: (params: { company_id: string; editing_session_key: string; user_token?: string }) => Promise<DriveFileType['item']>; getByEditingSessionKey: (params: { company_id: string; editing_session_key: string; user_token?: string }) => Promise<DriveFileType['item']>;
} }
@@ -54,6 +54,7 @@ class DriveService implements IDriveService {
try { try {
const resource = await apiService.post<{}, { editingSessionKey: string }>({ const resource = await apiService.post<{}, { editingSessionKey: string }>({
url: `/internal/services/documents/v1/companies/${company_id}/item/${drive_file_id}/editing_session`, url: `/internal/services/documents/v1/companies/${company_id}/item/${drive_file_id}/editing_session`,
token: user_token,
payload: { payload: {
editorApplicationId: 'tdrive_onlyoffice', editorApplicationId: 'tdrive_onlyoffice',
appInstanceId: INSTANCE_ID ?? '', appInstanceId: INSTANCE_ID ?? '',
@@ -82,7 +83,15 @@ class DriveService implements IDriveService {
} }
} }
public async endEditing(editing_session_key: string, url: string) { public async addEditingSessionVersion(editing_session_key: string, url: string, user_token?: string) {
return this.updateEditing(editing_session_key, url, true, user_token);
}
public async endEditing(editing_session_key: string, url: string, user_token?: string) {
return this.updateEditing(editing_session_key, url, false, user_token);
}
private async updateEditing(editing_session_key: string, url: string, keepEditing: boolean, user_token?: string) {
try { try {
if (!url) { if (!url) {
throw Error('no url found'); throw Error('no url found');
@@ -109,9 +118,12 @@ class DriveService implements IDriveService {
logger.info('Saving file version to Twake Drive: ', filename); logger.info('Saving file version to Twake Drive: ', filename);
const queryString = keepEditing ? '?keepEditing=true' : '';
await apiService.post({ await apiService.post({
url: `/internal/services/documents/v1/editing_session/${encodeURIComponent(editing_session_key)}`, url: `/internal/services/documents/v1/editing_session/${encodeURIComponent(editing_session_key)}` + queryString,
payload: form, payload: form,
token: user_token,
headers: form.getHeaders(), headers: form.getHeaders(),
}); });
} catch (error) { } catch (error) {