♻️ oo-connector: single request endediting, refactor URLs, bit of logging (#525)
This commit is contained in:
@@ -83,8 +83,9 @@ class ApiService implements IApiService {
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to post to Twake Drive: ', { error });
|
||||
logger.error('Failed to post to Twake Drive: ', { error: error.stack });
|
||||
this.refreshToken();
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DriveFileType, IDriveService } from '@/interfaces/drive.interface';
|
||||
import apiService from './api.service';
|
||||
import logger from '../lib/logger';
|
||||
import * as Utils from '../utils';
|
||||
import { Stream } from 'stream';
|
||||
import FormData from 'form-data';
|
||||
import { INSTANCE_ID } from '@/config';
|
||||
@@ -8,6 +9,12 @@ import { INSTANCE_ID } from '@/config';
|
||||
/** Thrown when Twake Drive returns a 404 for a key */
|
||||
export class UnknownKeyInDriveError extends Error {}
|
||||
|
||||
const makeTwakeDriveApiUrl = (paths: string[], params?: Utils.QueryParams) => Utils.joinURL(['/internal/services/documents/v1', ...paths], params);
|
||||
const makeNonEditingSessionItemUrl = (company_id: string, drive_file_id: string, paths: string[] = [], params?: Utils.QueryParams) =>
|
||||
makeTwakeDriveApiUrl(['companies', company_id, 'item', drive_file_id, ...paths], params);
|
||||
const makeEditingSessionItemUrl = (editing_session: string, params?: Utils.QueryParams) =>
|
||||
makeTwakeDriveApiUrl(['editing_session', editing_session], params);
|
||||
|
||||
/**
|
||||
* Client for Twake Drive's APIs dealing with `DriveItem`s, using {@see apiService}
|
||||
* to handle authorization
|
||||
@@ -17,7 +24,7 @@ class DriveService implements IDriveService {
|
||||
try {
|
||||
const { company_id, drive_file_id } = params;
|
||||
const resource = await apiService.get<DriveFileType>({
|
||||
url: `/internal/services/documents/v1/companies/${company_id}/item/${drive_file_id}`,
|
||||
url: makeNonEditingSessionItemUrl(company_id, drive_file_id),
|
||||
token: params.user_token,
|
||||
});
|
||||
|
||||
@@ -37,7 +44,7 @@ class DriveService implements IDriveService {
|
||||
try {
|
||||
const { company_id, drive_file_id, file_id } = params;
|
||||
return await apiService.post<{}, DriveFileType['item']['last_version_cache']>({
|
||||
url: `/internal/services/documents/v1/companies/${company_id}/item/${drive_file_id}/version`,
|
||||
url: makeNonEditingSessionItemUrl(company_id, drive_file_id, ['version']),
|
||||
payload: {
|
||||
drive_item_id: drive_file_id,
|
||||
provider: 'internal',
|
||||
@@ -56,7 +63,7 @@ class DriveService implements IDriveService {
|
||||
public async beginEditingSession(company_id: string, drive_file_id: string, user_token?: string) {
|
||||
try {
|
||||
const resource = await apiService.post<{}, { editingSessionKey: string }>({
|
||||
url: `/internal/services/documents/v1/companies/${company_id}/item/${drive_file_id}/editing_session`,
|
||||
url: makeNonEditingSessionItemUrl(company_id, drive_file_id, ['editing_session']),
|
||||
token: user_token,
|
||||
payload: {
|
||||
editorApplicationId: 'tdrive_onlyoffice',
|
||||
@@ -77,7 +84,7 @@ class DriveService implements IDriveService {
|
||||
public async cancelEditing(editing_session_key: string) {
|
||||
try {
|
||||
await apiService.delete<{}>({
|
||||
url: `/internal/services/documents/v1/editing_session/${encodeURIComponent(editing_session_key)}`,
|
||||
url: makeEditingSessionItemUrl(editing_session_key),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to begin editing session: ', error.stack);
|
||||
@@ -99,21 +106,6 @@ class DriveService implements IDriveService {
|
||||
if (!url) {
|
||||
throw Error('no url found');
|
||||
}
|
||||
//TODO: It would be better to avoid two requests for this operation
|
||||
const originalFile = await this.getByEditingSessionKey({ editing_session_key });
|
||||
|
||||
if (!originalFile) {
|
||||
// TODO: Make a single request and don't require the filename at all
|
||||
// then in POST /editing_session/... if the key is not found, just
|
||||
// put it in a users or company "lost and found" folder.
|
||||
// and accept without error. Because really, if backend doesn't know
|
||||
// the key anymore, there's not much we can do, and we should get OO
|
||||
// to clean up and stop trying to upload it.
|
||||
// but for today:
|
||||
logger.error("Forgotten OO document that Twake Drive doesn't know the key of.", { editing_session_key, url });
|
||||
throw new UnknownKeyInDriveError(`Unknown key ${JSON.stringify(editing_session_key)}`);
|
||||
// TODO: Distinguish this case from a long disconnected browser tab waking up
|
||||
}
|
||||
|
||||
const newFile = await apiService.get<Stream>({
|
||||
url,
|
||||
@@ -122,47 +114,30 @@ class DriveService implements IDriveService {
|
||||
|
||||
const form = new FormData();
|
||||
|
||||
const filename = encodeURIComponent(originalFile.last_version_cache.file_metadata.name);
|
||||
form.append('file', newFile);
|
||||
|
||||
form.append('file', newFile, {
|
||||
filename,
|
||||
});
|
||||
|
||||
logger.info('Saving file version to Twake Drive: ', filename);
|
||||
|
||||
const queryString = keepEditing ? '?keepEditing=true' : '';
|
||||
logger.info(`Saving file version to Twake Drive`, { editing_session_key, url });
|
||||
|
||||
await apiService.post({
|
||||
url: `/internal/services/documents/v1/editing_session/${encodeURIComponent(editing_session_key)}` + queryString,
|
||||
url: makeEditingSessionItemUrl(editing_session_key, {
|
||||
keepEditing: keepEditing ? 'true' : null,
|
||||
}),
|
||||
payload: form,
|
||||
token: user_token,
|
||||
headers: form.getHeaders(),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to end editing session: ', error.stack);
|
||||
throw error;
|
||||
//TODO make monitoring for such kind of errors
|
||||
if (error.response?.status === 404) {
|
||||
logger.error('Forgotten OO document that Twake Drive doesnt know the key of.', { editing_session_key, url });
|
||||
throw new UnknownKeyInDriveError(`Unknown key ${JSON.stringify(editing_session_key)}`);
|
||||
//TODO: Distinguish this case from a long disconnected browser tab waking up
|
||||
//TODO make monitoring for such kind of errors
|
||||
} else {
|
||||
logger.error('Failed to end editing session: ', error.stack);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the document information by the editing session key. Just simple call to the drive API
|
||||
* /item/editing_session/${editing_session_key}
|
||||
* @param params
|
||||
* @returns null if the key was not found, or the api response body
|
||||
*/
|
||||
public getByEditingSessionKey = async (params: { editing_session_key: string; user_token?: string }): Promise<DriveFileType['item']> => {
|
||||
try {
|
||||
const { editing_session_key } = params;
|
||||
return await apiService.get<DriveFileType['item']>({
|
||||
url: `/internal/services/documents/v1/editing_session/${encodeURIComponent(editing_session_key)}`,
|
||||
token: params.user_token,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.response?.status === 404) return null;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new DriveService();
|
||||
|
||||
Reference in New Issue
Block a user