diff --git a/services/web/app/src/Features/Project/ProjectDeleter.js b/services/web/app/src/Features/Project/ProjectDeleter.js index af22c1a0f3..9a01faf0d5 100644 --- a/services/web/app/src/Features/Project/ProjectDeleter.js +++ b/services/web/app/src/Features/Project/ProjectDeleter.js @@ -1,5 +1,6 @@ const _ = require('lodash') const { db, ObjectId } = require('../../infrastructure/mongodb') +const Modules = require('../../infrastructure/Modules') const { callbackify } = require('util') const { Project } = require('../../models/Project') const { DeletedProject } = require('../../models/DeletedProject') @@ -387,6 +388,7 @@ async function expireDeletedProject(projectId) { ChatApiHandler.promises.destroyProject(deletedProject.project._id), hardDeleteDeletedFiles(deletedProject.project._id), ProjectAuditLogEntry.deleteMany({ projectId }), + Modules.promises.hooks.fire('projectExpired', deletedProject.project._id), ]) await DeletedProject.updateOne( diff --git a/services/web/test/acceptance/config/settings.test.defaults.js b/services/web/test/acceptance/config/settings.test.defaults.js index 52587290bc..d871d52b23 100644 --- a/services/web/test/acceptance/config/settings.test.defaults.js +++ b/services/web/test/acceptance/config/settings.test.defaults.js @@ -90,6 +90,9 @@ module.exports = { webpack: { url: 'http://localhost:23808', }, + gitBridge: { + url: 'http://localhost:28000', + }, }, // for registration via SL, set enableLegacyRegistration to true diff --git a/services/web/test/acceptance/src/DeletionTests.js b/services/web/test/acceptance/src/DeletionTests.js index 6e09a706c4..9b4013f05c 100644 --- a/services/web/test/acceptance/src/DeletionTests.js +++ b/services/web/test/acceptance/src/DeletionTests.js @@ -4,16 +4,19 @@ const async = require('async') const { expect } = require('chai') const settings = require('@overleaf/settings') const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb') +const Features = require('../../../app/src/infrastructure/Features') const MockDocstoreApiClass = require('./mocks/MockDocstoreApi') const MockFilestoreApiClass = require('./mocks/MockFilestoreApi') const MockChatApiClass = require('./mocks/MockChatApi') +const MockGitBridgeApiClass = require('./mocks/MockGitBridgeApi') -let MockDocstoreApi, MockFilestoreApi, MockChatApi +let MockDocstoreApi, MockFilestoreApi, MockChatApi, MockGitBridgeApi before(function () { MockDocstoreApi = MockDocstoreApiClass.instance() MockFilestoreApi = MockFilestoreApiClass.instance() MockChatApi = MockChatApiClass.instance() + MockGitBridgeApi = MockGitBridgeApiClass.instance() }) describe('Deleting a user', function () { @@ -313,6 +316,11 @@ describe('Deleting a project', function () { dummyFile: 'wombat', } MockChatApi.projects[this.projectId.toString()] = ['message'] + if (Features.hasFeature('git-bridge')) { + MockGitBridgeApi.projects[this.projectId.toString()] = { + data: 'some-data', + } + } }) }) @@ -437,4 +445,46 @@ describe('Deleting a project', function () { }) }) }) + + if (Features.hasFeature('git-bridge')) { + describe('When the project has git-bridge data', function () { + beforeEach(function () { + MockGitBridgeApi.projects[this.projectId.toString()] = { + data: 'some-data', + } + }) + + describe('When the deleted project is expired', function () { + beforeEach(function (done) { + this.user.deleteProject(this.projectId, error => { + if (error) { + return done(error) + } + request.post( + `/internal/project/${this.projectId}/expire-deleted-project`, + { + auth: { + user: settings.apis.web.user, + pass: settings.apis.web.pass, + sendImmediately: true, + }, + }, + (error, res) => { + if (error) { + return done(error) + } + expect(res.statusCode).to.equal(200) + done() + } + ) + }) + }) + + it('should delete the git-bridge data', function () { + expect(MockGitBridgeApi.projects[this.projectId.toString()]).not.to + .exist + }) + }) + }) + } }) diff --git a/services/web/test/acceptance/src/Init.js b/services/web/test/acceptance/src/Init.js index 7d6a70b93a..b872881565 100644 --- a/services/web/test/acceptance/src/Init.js +++ b/services/web/test/acceptance/src/Init.js @@ -7,6 +7,7 @@ const MockClsiApi = require('./mocks/MockClsiApi') const MockDocstoreApi = require('./mocks/MockDocstoreApi') const MockDocUpdaterApi = require('./mocks/MockDocUpdaterApi') const MockFilestoreApi = require('./mocks/MockFilestoreApi') +const MockGitBridgeApi = require('./mocks/MockGitBridgeApi') const MockNotificationsApi = require('./mocks/MockNotificationsApi') const MockProjectHistoryApi = require('./mocks/MockProjectHistoryApi') const MockSpellingApi = require('./mocks/MockSpellingApi') @@ -35,3 +36,7 @@ if (Features.hasFeature('saas')) { MockV1Api.initialize(25000, mockOpts) MockThirdPartyDataStoreApi.initialize(23002, mockOpts) } + +if (Features.hasFeature('git-bridge')) { + MockGitBridgeApi.initialize(28000, mockOpts) +} diff --git a/services/web/test/acceptance/src/mocks/MockGitBridgeApi.js b/services/web/test/acceptance/src/mocks/MockGitBridgeApi.js new file mode 100644 index 0000000000..e9815ef220 --- /dev/null +++ b/services/web/test/acceptance/src/mocks/MockGitBridgeApi.js @@ -0,0 +1,21 @@ +const AbstractMockApi = require('./AbstractMockApi') + +class MockGitBridgeApi extends AbstractMockApi { + reset() { + this.projects = {} + } + + applyRoutes() { + this.app.delete('/api/projects/:projectId', (req, res) => { + this.deleteProject(req, res) + }) + } + + deleteProject(req, res) { + const projectId = req.params.projectId + delete this.projects[projectId] + res.sendStatus(204) + } +} + +module.exports = MockGitBridgeApi