🚧 WIP: backend: beginnings of a transactional editing for plugins (#525)
This commit is contained in:
@@ -1025,6 +1025,80 @@ export class DocumentsService {
|
|||||||
CrudException.throwMe(error, new CrudException("Failed to begin editing Drive item", 500));
|
CrudException.throwMe(error, new CrudException("Failed to begin editing Drive item", 500));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End editing session either by providing a URL to a new file to create a version,
|
||||||
|
* or not, to just cancel the session.
|
||||||
|
* @param editing_session_key Editing key of the DriveFile
|
||||||
|
* @param newFileUrl Optional URL to a new version of the file to store
|
||||||
|
* @param options Optional upload information from the request
|
||||||
|
*/
|
||||||
|
endEditing = async (
|
||||||
|
editing_session_key: string,
|
||||||
|
newFileUrl: string | null,
|
||||||
|
context: DriveExecutionContext,
|
||||||
|
) => {
|
||||||
|
if (!context) {
|
||||||
|
this.logger.error("invalid execution context");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!editing_session_key) {
|
||||||
|
this.logger.error("Invalid editing_session_key: " + JSON.stringify(editing_session_key));
|
||||||
|
throw new CrudException("Invalid editing_session_key", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
const driveFile = await this.repository.findOne({ editing_session_key }, {}, context);
|
||||||
|
if (!driveFile) {
|
||||||
|
this.logger.error("Drive item not found by editing session key");
|
||||||
|
throw new CrudException("Item not found by editing session key", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAccess = await checkAccess(driveFile.id, driveFile, "write", this.repository, context);
|
||||||
|
if (!hasAccess) {
|
||||||
|
logger.error("user does not have access drive item " + driveFile.id);
|
||||||
|
CrudException.throwMe(
|
||||||
|
new Error("user does not have access to the drive item"),
|
||||||
|
new CrudException("user does not have access drive item", 401),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFileUrl) {
|
||||||
|
// const response = await axios.request({
|
||||||
|
// url: domain + req.url,
|
||||||
|
// method: req.method as any,
|
||||||
|
// headers: _.omit(req.headers, "host", "content-length") as {
|
||||||
|
// [key: string]: string;
|
||||||
|
// },
|
||||||
|
// data: req.body as any,
|
||||||
|
// responseType: "stream",
|
||||||
|
// maxRedirects: 0,
|
||||||
|
// validateStatus: null,
|
||||||
|
// });
|
||||||
|
//TODO: save file into new version
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.repository.atomicCompareAndSet(
|
||||||
|
driveFile,
|
||||||
|
"editing_session_key",
|
||||||
|
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,
|
||||||
|
)}`,
|
||||||
|
);
|
||||||
|
return { ok: true };
|
||||||
|
} catch (error) {
|
||||||
|
logger.error({ error: `${error}` }, "Failed to cancel editing Drive item");
|
||||||
|
CrudException.throwMe(error, new CrudException("Failed to cancel editing Drive item", 500));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
downloadGetToken = async (
|
downloadGetToken = async (
|
||||||
ids: string[],
|
ids: string[],
|
||||||
versionId: string | null,
|
versionId: string | null,
|
||||||
|
|||||||
@@ -372,6 +372,44 @@ export class DocumentsController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish an editing session by cancelling it.
|
||||||
|
*/
|
||||||
|
cancelEditing = async (
|
||||||
|
request: FastifyRequest<{
|
||||||
|
Params: ItemRequestByEditingSessionKeyParams;
|
||||||
|
Body: { editorApplicationId: string };
|
||||||
|
}>,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const context = getDriveExecutionContext(request);
|
||||||
|
const { editing_session_key } = request.params;
|
||||||
|
|
||||||
|
if (!editing_session_key) throw new CrudException("Missing editing_session_key", 400);
|
||||||
|
|
||||||
|
return await globalResolver.services.documents.documents.endEditing(
|
||||||
|
editing_session_key,
|
||||||
|
null,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error({ error: `${error}` }, "Failed to begin editing Drive item");
|
||||||
|
CrudException.throwMe(error, new CrudException("Failed to begin editing Drive item", 500));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//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
|
||||||
|
*/
|
||||||
|
endEditing = async (
|
||||||
|
request: FastifyRequest<{
|
||||||
|
Params: ItemRequestByEditingSessionKeyParams;
|
||||||
|
Body: { editorApplicationId: string };
|
||||||
|
}>,
|
||||||
|
) => {
|
||||||
|
console.log(request); // make linter happy
|
||||||
|
};
|
||||||
|
|
||||||
downloadGetToken = async (
|
downloadGetToken = async (
|
||||||
request: FastifyRequest<{
|
request: FastifyRequest<{
|
||||||
Params: ItemRequestParams;
|
Params: ItemRequestParams;
|
||||||
|
|||||||
@@ -94,6 +94,20 @@ const routes: FastifyPluginCallback = (fastify: FastifyInstance, _options, next)
|
|||||||
handler: documentsController.getByEditingSessionKey.bind(documentsController),
|
handler: documentsController.getByEditingSessionKey.bind(documentsController),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fastify.route({
|
||||||
|
method: "POST",
|
||||||
|
url: `${serviceUrl}/editing_session/:editing_session_key`,
|
||||||
|
preValidation: [fastify.authenticateOptional],
|
||||||
|
handler: documentsController.endEditing.bind(documentsController),
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `${serviceUrl}/editing_session/:editing_session_key`,
|
||||||
|
preValidation: [fastify.authenticateOptional],
|
||||||
|
handler: documentsController.endEditing.bind(documentsController),
|
||||||
|
});
|
||||||
|
|
||||||
fastify.route({
|
fastify.route({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `${serviceUrl}/download/token`,
|
url: `${serviceUrl}/download/token`,
|
||||||
|
|||||||
@@ -171,7 +171,10 @@ class OnlyOfficeService {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.poller = new PolledThingieValue('Connect to Only Office', () => this.getVersion(), 10 * 1000 * 60);
|
this.poller = new PolledThingieValue('Connect to Only Office', () => this.getVersion(), 10 * 1000 * 60);
|
||||||
}
|
}
|
||||||
/** Get the latest Only Office version */
|
/** Get the latest Only Office version from polling. If the return is `undefined`
|
||||||
|
* it probably means there is a connection issue contacting the OnlyOffice server
|
||||||
|
* from the connector.
|
||||||
|
*/
|
||||||
public getLatestVersion() {
|
public getLatestVersion() {
|
||||||
return this.poller.latest();
|
return this.poller.latest();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user