✨Added editing session key to the connector services
This commit is contained in:
committed by
Eric Doughty-Papassideris
parent
7941ba2e1f
commit
d94ec46e1d
@@ -74,9 +74,9 @@ class IndexController {
|
|||||||
throw new Error('You do not have access to this file');
|
throw new Error('You do not have access to this file');
|
||||||
}
|
}
|
||||||
|
|
||||||
let editingSessionId = null;
|
let editingSessionKey = null;
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
editingSessionId = driveService.beginEditing(drive_file_id);
|
editingSessionKey = await driveService.beginEditingSession(company_id, drive_file_id);
|
||||||
//TODO catch error and display to the user when we can't stopped editing
|
//TODO catch error and display to the user when we can't stopped editing
|
||||||
|
|
||||||
//TODO Log error with format to be able to set up grafana alert fir such king of errors
|
//TODO Log error with format to be able to set up grafana alert fir such king of errors
|
||||||
@@ -87,7 +87,7 @@ class IndexController {
|
|||||||
user_id: user.id, //To verify that link is opened by the same user
|
user_id: user.id, //To verify that link is opened by the same user
|
||||||
company_id,
|
company_id,
|
||||||
drive_file_id,
|
drive_file_id,
|
||||||
editing_session_id: editingSessionId,
|
editing_session_key: editingSessionKey,
|
||||||
file_id: file.id,
|
file_id: file.id,
|
||||||
file_name: file.filename || file?.metadata?.name || '',
|
file_name: file.filename || file?.metadata?.name || '',
|
||||||
preview: !!preview,
|
preview: !!preview,
|
||||||
@@ -103,7 +103,7 @@ class IndexController {
|
|||||||
Utils.joinURL([SERVER_ORIGIN ?? '', SERVER_PREFIX, 'editor'], {
|
Utils.joinURL([SERVER_ORIGIN ?? '', SERVER_PREFIX, 'editor'], {
|
||||||
token,
|
token,
|
||||||
file_id,
|
file_id,
|
||||||
editing_session_id: editingSessionId,
|
editing_session_key: editingSessionKey,
|
||||||
company_id,
|
company_id,
|
||||||
preview,
|
preview,
|
||||||
office_token: officeToken,
|
office_token: officeToken,
|
||||||
@@ -123,11 +123,14 @@ class IndexController {
|
|||||||
const { user } = req;
|
const { user } = req;
|
||||||
|
|
||||||
const officeTokenPayload = jwt.verify(office_token, CREDENTIALS_SECRET) as OfficeToken;
|
const officeTokenPayload = jwt.verify(office_token, CREDENTIALS_SECRET) as OfficeToken;
|
||||||
const { preview, user_id, company_id, file_name, file_id, drive_file_id } = officeTokenPayload;
|
const { preview, user_id, company_id, file_name, file_id, drive_file_id, editing_session_key } = officeTokenPayload;
|
||||||
|
|
||||||
if (user_id !== user.id) {
|
if (user_id !== user.id) {
|
||||||
throw new Error('You do not have access to this link');
|
throw new Error('You do not have access to this link');
|
||||||
}
|
}
|
||||||
|
if (!preview && !editing_session_key) {
|
||||||
|
throw new Error('Cant start editing without "editing session key"');
|
||||||
|
}
|
||||||
|
|
||||||
const initResponse = await editorService.init(company_id, file_name, file_id, user, preview, drive_file_id || file_id);
|
const initResponse = await editorService.init(company_id, file_name, file_id, user, preview, drive_file_id || file_id);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class OnlyOfficeController {
|
|||||||
const { token } = req.query;
|
const { token } = req.query;
|
||||||
|
|
||||||
const officeTokenPayload = jwt.verify(token, CREDENTIALS_SECRET) as OfficeToken;
|
const officeTokenPayload = jwt.verify(token, CREDENTIALS_SECRET) as OfficeToken;
|
||||||
const { company_id, drive_file_id, file_id, in_page_token } = officeTokenPayload;
|
const { company_id, drive_file_id, file_id, in_page_token, editing_session_key } = officeTokenPayload;
|
||||||
let fileId = file_id;
|
let fileId = file_id;
|
||||||
|
|
||||||
// check token is an in_page_token
|
// check token is an in_page_token
|
||||||
@@ -36,9 +36,9 @@ class OnlyOfficeController {
|
|||||||
|
|
||||||
if (drive_file_id) {
|
if (drive_file_id) {
|
||||||
//Get the drive file
|
//Get the drive file
|
||||||
const driveFile = await driveService.get({
|
const driveFile = await driveService.getByEditingSessionKey({
|
||||||
company_id,
|
company_id,
|
||||||
drive_file_id,
|
editing_session_key,
|
||||||
});
|
});
|
||||||
if (driveFile) {
|
if (driveFile) {
|
||||||
fileId = driveFile?.item?.last_version_cache?.file_metadata?.external_id;
|
fileId = driveFile?.item?.last_version_cache?.file_metadata?.external_id;
|
||||||
@@ -77,7 +77,7 @@ class OnlyOfficeController {
|
|||||||
logger.info('OO callback', req.body);
|
logger.info('OO callback', req.body);
|
||||||
|
|
||||||
const officeTokenPayload = jwt.verify(token, CREDENTIALS_SECRET) as OfficeToken;
|
const officeTokenPayload = jwt.verify(token, CREDENTIALS_SECRET) as OfficeToken;
|
||||||
const { preview, company_id, file_id, /* user_id, */ drive_file_id, in_page_token } = officeTokenPayload;
|
const { preview, company_id, file_id, /* user_id, */ drive_file_id, in_page_token, editing_session_key } = officeTokenPayload;
|
||||||
|
|
||||||
// check token is an in_page_token and allow save
|
// check token is an in_page_token and allow save
|
||||||
if (!in_page_token) throw new Error('Invalid token, must be a in_page_token');
|
if (!in_page_token) throw new Error('Invalid token, must be a in_page_token');
|
||||||
@@ -93,6 +93,14 @@ class OnlyOfficeController {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OnlyOffice.Callback.Status.READY_FOR_SAVING:
|
case OnlyOffice.Callback.Status.READY_FOR_SAVING:
|
||||||
|
const driveFile = await driveService.getByEditingSessionKey({
|
||||||
|
company_id,
|
||||||
|
editing_session_key,
|
||||||
|
});
|
||||||
|
if (!driveFile) {
|
||||||
|
throw new Error('Error getting drive files ');
|
||||||
|
}
|
||||||
|
|
||||||
const newVersionFile = await fileService.save({
|
const newVersionFile = await fileService.save({
|
||||||
company_id,
|
company_id,
|
||||||
file_id,
|
file_id,
|
||||||
@@ -106,6 +114,7 @@ class OnlyOfficeController {
|
|||||||
file_id: newVersionFile?.resource?.id,
|
file_id: newVersionFile?.resource?.id,
|
||||||
});
|
});
|
||||||
logger.info('New version created', version);
|
logger.info('New version created', version);
|
||||||
|
|
||||||
return respondToOO();
|
return respondToOO();
|
||||||
|
|
||||||
case OnlyOffice.Callback.Status.CLOSED_WITHOUT_CHANGES:
|
case OnlyOffice.Callback.Status.CLOSED_WITHOUT_CHANGES:
|
||||||
|
|||||||
@@ -19,4 +19,7 @@ export type DriveRequestParams = {
|
|||||||
export interface IDriveService {
|
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>;
|
||||||
|
endEditing: (company_id: string, editing_session_key: string) => Promise<void>;
|
||||||
|
getByEditingSessionKey: (params: { company_id: string; editing_session_key: string; user_token?: string }) => Promise<DriveFileType>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface OfficeToken {
|
|||||||
file_id: string;
|
file_id: string;
|
||||||
file_name: string;
|
file_name: string;
|
||||||
preview: boolean;
|
preview: boolean;
|
||||||
|
editing_session_key: string;
|
||||||
drive_file_id?: string;
|
drive_file_id?: string;
|
||||||
in_page_token?: boolean;
|
in_page_token?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class OnlyOfficeRoute implements Routes {
|
|||||||
|
|
||||||
private initRoutes = () => {
|
private initRoutes = () => {
|
||||||
this.router.get(`${this.path}:mode/read`, requirementsMiddleware, this.onlyOfficeController.read);
|
this.router.get(`${this.path}:mode/read`, requirementsMiddleware, this.onlyOfficeController.read);
|
||||||
this.router.post(`${this.path}:mode/save`, requirementsMiddleware, this.onlyOfficeController.ooCallback);
|
this.router.post(`${this.path}:mode/callback`, requirementsMiddleware, this.onlyOfficeController.ooCallback);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,26 @@ class ApiService implements IApiService {
|
|||||||
return await axiosWithToken.get(url, config);
|
return await axiosWithToken.get(url, config);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public delete = async <T>(params: IApiServiceRequestParams<T>): Promise<T> => {
|
||||||
|
const { url, token, responseType, headers } = params;
|
||||||
|
|
||||||
|
const axiosWithToken = await this.requireAxios();
|
||||||
|
|
||||||
|
const config: AxiosRequestConfig = {};
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
config['headers'] = {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
...headers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseType) {
|
||||||
|
config['responseType'] = responseType;
|
||||||
|
}
|
||||||
|
return await axiosWithToken.delete(url, config);
|
||||||
|
};
|
||||||
|
|
||||||
public post = async <T, R>(params: IApiServiceRequestParams<T>): Promise<R> => {
|
public post = async <T, R>(params: IApiServiceRequestParams<T>): Promise<R> => {
|
||||||
const { url, payload, headers } = params;
|
const { url, payload, headers } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -49,13 +49,58 @@ class DriveService implements IDriveService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public beginEditing(drive_file_id: string): string {
|
public async beginEditingSession(company_id: string, drive_file_id: string) {
|
||||||
return '';
|
try {
|
||||||
|
const resource = await apiService.post<{}, { editingSessionKey: string }>({
|
||||||
|
url: `/internal/services/documents/v1/companies/${company_id}/item/${drive_file_id}/editing_session`,
|
||||||
|
payload: {
|
||||||
|
editorApplicationId: 'mock_application_id',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (resource?.editingSessionKey) {
|
||||||
|
return resource.editingSessionKey;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Failed to obtain editing session key, response: ${JSON.stringify(resource)}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to begin editing session: ', error.stack);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public endEditing(editing_session_id: string) {
|
public async endEditing(company_id: string, editing_session_key: string) {
|
||||||
return '';
|
try {
|
||||||
|
await apiService.delete<{}>({
|
||||||
|
url: `/internal/services/documents/v1/companies/${company_id}/item/editing_session/${editing_session_key}`,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to begin editing session: ', error.stack);
|
||||||
|
throw error;
|
||||||
|
//TODO make monitoring for such kind of errors
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the document information by the editing session key. Just simple call to the drive API
|
||||||
|
* /item/editing_session/${editing_session_key}
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
public getByEditingSessionKey = async (params: {
|
||||||
|
company_id: string;
|
||||||
|
editing_session_key: string;
|
||||||
|
user_token?: string;
|
||||||
|
}): Promise<DriveFileType> => {
|
||||||
|
try {
|
||||||
|
const { company_id, editing_session_key } = params;
|
||||||
|
return await apiService.get<DriveFileType>({
|
||||||
|
url: `/internal/services/documents/v1/companies/${company_id}/item/editing_session/${editing_session_key}`,
|
||||||
|
token: params.user_token,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to fetch file metadata by editing session key: ', error.stack);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new DriveService();
|
export default new DriveService();
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
token: "<%= it.file_id %>",
|
token: "<%= it.file_id %>",
|
||||||
type: screen.width < 600 ? 'mobile' : 'desktop',
|
type: screen.width < 600 ? 'mobile' : 'desktop',
|
||||||
editorConfig: {
|
editorConfig: {
|
||||||
callbackUrl: `${window.baseURL}save?file_id=<%= it.file_id %>&company_id=<%= it.company_id %>&token=<%= it.token %>`,
|
callbackUrl: `${window.baseURL}callback?file_id=<%= it.file_id %>&company_id=<%= it.company_id %>&token=<%= it.token %>`,
|
||||||
lang: window.user.language,
|
lang: window.user.language,
|
||||||
user: {
|
user: {
|
||||||
id: window.user.id,
|
id: window.user.id,
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
},
|
},
|
||||||
customization: {
|
customization: {
|
||||||
chat: false,
|
chat: false,
|
||||||
compactToolbar: true,
|
compactToolbar: false,
|
||||||
about: false,
|
about: false,
|
||||||
feedback: false,
|
feedback: false,
|
||||||
goback: {
|
goback: {
|
||||||
|
|||||||
Reference in New Issue
Block a user