Merge pull request #22321 from overleaf/msm-force-flag-delete-user

[web] Fix user deletion in CE/SP when email does not exist

GitOrigin-RevId: 051f822318d63c8a9f50d5e9aeca095f3b37efb4
This commit is contained in:
Miguel Serrano
2025-01-10 09:57:32 +01:00
committed by Copybot
parent ac8c381597
commit e6ceb314cb
3 changed files with 53 additions and 14 deletions

View File

@@ -56,7 +56,7 @@ async function deleteUser(userId, options) {
)
await _createDeletedUser(user, options)
await ProjectDeleter.promises.deleteUsersProjects(user._id)
await _sendDeleteEmail(user)
await _sendDeleteEmail(user, options.force)
await deleteMongoUser(user._id)
} catch (error) {
logger.warn({ error, userId }, 'something went wrong deleting the user')
@@ -119,13 +119,24 @@ async function ensureCanDeleteUser(user) {
}
}
async function _sendDeleteEmail(user) {
async function _sendDeleteEmail(user, force) {
const emailOptions = {
to: user.email,
action: 'account deleted',
actionDescribed: 'your Overleaf account was deleted',
}
await EmailHandler.promises.sendEmail('securityAlert', emailOptions)
try {
await EmailHandler.promises.sendEmail('securityAlert', emailOptions)
} catch (error) {
if (force) {
logger.error(
{ error },
'error sending account deletion email notification'
)
} else {
throw error
}
}
}
async function _createDeletedUser(user, options) {

View File

@@ -24,6 +24,7 @@ async function main() {
}
const options = {
ipAddress: '0.0.0.0',
force: true,
}
UserDeleter.deleteUser(user._id, options, function (err) {
if (err) {

View File

@@ -299,18 +299,45 @@ describe('UserDeleter', function () {
this.DeletedUserMock.verify()
})
it('should email the user', async function () {
await this.UserDeleter.promises.deleteUser(this.userId, {
ipAddress: this.ipAddress,
describe('email notifications', function () {
it('should email the user', async function () {
await this.UserDeleter.promises.deleteUser(this.userId, {
ipAddress: this.ipAddress,
})
const emailOptions = {
to: 'bob@bob.com',
action: 'account deleted',
actionDescribed: 'your Overleaf account was deleted',
}
expect(
this.EmailHandler.promises.sendEmail
).to.have.been.calledWith('securityAlert', emailOptions)
})
it('should fail when the email service fails', async function () {
this.EmailHandler.promises.sendEmail = sinon
.stub()
.rejects(new Error('email failed'))
await expect(
this.UserDeleter.promises.deleteUser(this.userId, {
ipAddress: this.ipAddress,
})
).to.be.rejectedWith('email failed')
})
describe('with "force: true" option', function () {
it('should succeed when the email service fails', async function () {
this.EmailHandler.promises.sendEmail = sinon
.stub()
.rejects(new Error('email failed'))
await expect(
this.UserDeleter.promises.deleteUser(this.userId, {
ipAddress: this.ipAddress,
force: true,
})
).to.be.fulfilled
})
})
const emailOptions = {
to: 'bob@bob.com',
action: 'account deleted',
actionDescribed: 'your Overleaf account was deleted',
}
expect(
this.EmailHandler.promises.sendEmail
).to.have.been.calledWith('securityAlert', emailOptions)
})
it('should add an audit log entry', async function () {