From d5b5710d018dea1f3ba5e84fd4869af18c99c756 Mon Sep 17 00:00:00 2001 From: Domagoj Kriskovic Date: Mon, 21 Jul 2025 11:53:48 +0200 Subject: [PATCH] Add docModified hook in ds-mobile-app module (#27196) * Add docModified hook in ds-mobile-app module * use Object.entries when iterating over promises * avoid project lookup * update tests GitOrigin-RevId: 88676746f56558a97ce31010b57f5eeb254fefef --- .../Features/Documents/DocumentController.mjs | 4 ++++ .../web/app/src/infrastructure/Modules.js | 3 +-- .../src/Documents/DocumentController.test.mjs | 21 +++++++++++++++++++ services/web/types/web-module.ts | 5 ++++- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/services/web/app/src/Features/Documents/DocumentController.mjs b/services/web/app/src/Features/Documents/DocumentController.mjs index 6998c0b36a..9a16811894 100644 --- a/services/web/app/src/Features/Documents/DocumentController.mjs +++ b/services/web/app/src/Features/Documents/DocumentController.mjs @@ -7,6 +7,7 @@ import logger from '@overleaf/logger' import _ from 'lodash' import { plainTextResponse } from '../../infrastructure/Response.js' import { expressify } from '@overleaf/promise-utils' +import Modules from '../../infrastructure/Modules.js' async function getDocument(req, res) { const { Project_id: projectId, doc_id: docId } = req.params @@ -92,6 +93,9 @@ async function setDocument(req, res) { { docId, projectId }, 'finished receiving set document request from api (docupdater)' ) + + await Modules.promises.hooks.fire('docModified', projectId, docId) + res.json(result) } diff --git a/services/web/app/src/infrastructure/Modules.js b/services/web/app/src/infrastructure/Modules.js index 20975a3642..aea3aeb087 100644 --- a/services/web/app/src/infrastructure/Modules.js +++ b/services/web/app/src/infrastructure/Modules.js @@ -150,8 +150,7 @@ async function linkedFileAgentsIncludes() { async function attachHooks() { for (const module of await modules()) { const { promises, ...hooks } = module.hooks || {} - for (const hook in promises || {}) { - const method = promises[hook] + for (const [hook, method] of Object.entries(promises || {})) { attachHook(hook, method) } for (const hook in hooks || {}) { diff --git a/services/web/test/unit/src/Documents/DocumentController.test.mjs b/services/web/test/unit/src/Documents/DocumentController.test.mjs index e3fe3bdec2..b683cc5d14 100644 --- a/services/web/test/unit/src/Documents/DocumentController.test.mjs +++ b/services/web/test/unit/src/Documents/DocumentController.test.mjs @@ -87,6 +87,14 @@ describe('DocumentController', function () { }, } + ctx.Modules = { + promises: { + hooks: { + fire: sinon.stub().resolves(), + }, + }, + } + vi.doMock('../../../../app/src/Features/Project/ProjectGetter', () => ({ default: ctx.ProjectGetter, })) @@ -113,6 +121,10 @@ describe('DocumentController', function () { default: ctx.ChatApiHandler, })) + vi.doMock('../../../../app/src/infrastructure/Modules.js', () => ({ + default: ctx.Modules, + })) + ctx.DocumentController = (await import(MODULE_PATH)).default }) @@ -208,6 +220,15 @@ describe('DocumentController', function () { it('should return a successful response', function (ctx) { ctx.res.success.should.equal(true) }) + + it('should call the docModified hook', function (ctx) { + sinon.assert.calledWith( + ctx.Modules.promises.hooks.fire, + 'docModified', + ctx.project._id, + ctx.doc._id + ) + }) }) describe("when the document doesn't exist", function () { diff --git a/services/web/types/web-module.ts b/services/web/types/web-module.ts index 298f430df2..f6b59cdf6f 100644 --- a/services/web/types/web-module.ts +++ b/services/web/types/web-module.ts @@ -53,7 +53,10 @@ export type WebModule = { apply: (webRouter: any, privateApiRouter: any, publicApiRouter: any) => void } hooks?: { - [name: string]: (args: any[]) => void + promises?: { + [name: string]: (...args: any[]) => Promise + } + [name: string]: ((...args: any[]) => void) | any } middleware?: { [name: string]: RequestHandler