2019-07-18 10:18:56 -04:00
|
|
|
const User = require('./helpers/User')
|
|
|
|
const request = require('./helpers/request')
|
|
|
|
const async = require('async')
|
|
|
|
const { expect } = require('chai')
|
2021-07-07 05:38:56 -04:00
|
|
|
const settings = require('@overleaf/settings')
|
2020-10-07 09:16:54 -04:00
|
|
|
const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb')
|
2023-05-15 09:46:27 -04:00
|
|
|
const Features = require('../../../app/src/infrastructure/Features')
|
2021-02-25 07:22:24 -05:00
|
|
|
const MockDocstoreApiClass = require('./mocks/MockDocstoreApi')
|
|
|
|
const MockFilestoreApiClass = require('./mocks/MockFilestoreApi')
|
2022-03-25 10:00:07 -04:00
|
|
|
const MockChatApiClass = require('./mocks/MockChatApi')
|
2023-05-15 09:46:27 -04:00
|
|
|
const MockGitBridgeApiClass = require('./mocks/MockGitBridgeApi')
|
2021-02-25 07:22:24 -05:00
|
|
|
|
2023-05-15 09:46:27 -04:00
|
|
|
let MockDocstoreApi, MockFilestoreApi, MockChatApi, MockGitBridgeApi
|
2021-02-25 07:22:24 -05:00
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
before(function () {
|
2021-02-25 07:22:24 -05:00
|
|
|
MockDocstoreApi = MockDocstoreApiClass.instance()
|
|
|
|
MockFilestoreApi = MockFilestoreApiClass.instance()
|
2022-03-25 10:00:07 -04:00
|
|
|
MockChatApi = MockChatApiClass.instance()
|
2023-05-15 09:46:27 -04:00
|
|
|
MockGitBridgeApi = MockGitBridgeApiClass.instance()
|
2021-02-25 07:22:24 -05:00
|
|
|
})
|
2019-07-18 10:18:56 -04:00
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('Deleting a user', function () {
|
|
|
|
beforeEach(function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user = new User()
|
|
|
|
async.series(
|
|
|
|
[
|
|
|
|
this.user.ensureUserExists.bind(this.user),
|
2021-04-27 03:52:58 -04:00
|
|
|
this.user.login.bind(this.user),
|
2019-07-18 10:18:56 -04:00
|
|
|
],
|
|
|
|
done
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should remove the user from active users', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.get((error, user) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(user).to.exist
|
|
|
|
this.user.deleteUser(error => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
this.user.get((error, user) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(user).not.to.exist
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should create a soft-deleted user', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.get((error, user) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
this.user.deleteUser(error => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
db.deletedUsers.findOne(
|
|
|
|
{ 'user._id': user._id },
|
|
|
|
(error, deletedUser) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(deletedUser).to.exist
|
|
|
|
// it should set the 'deleterData' correctly
|
|
|
|
expect(deletedUser.deleterData.deleterId.toString()).to.equal(
|
|
|
|
user._id.toString()
|
|
|
|
)
|
|
|
|
expect(deletedUser.deleterData.deletedUserId.toString()).to.equal(
|
|
|
|
user._id.toString()
|
|
|
|
)
|
|
|
|
expect(deletedUser.deleterData.deletedUserReferralId).to.equal(
|
|
|
|
user.referal_id
|
|
|
|
)
|
|
|
|
// it should set the 'user' correctly
|
|
|
|
expect(deletedUser.user._id.toString()).to.equal(
|
|
|
|
user._id.toString()
|
|
|
|
)
|
|
|
|
expect(deletedUser.user.email).to.equal(user.email)
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it("Should delete the user's projects", function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.createProject('wombat', (error, projectId) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
this.user.getProject(projectId, (error, project) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(project).to.exist
|
|
|
|
|
|
|
|
this.user.deleteUser(error => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
this.user.getProject(projectId, (error, project) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(project).not.to.exist
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('when scrubbing the user', function () {
|
|
|
|
beforeEach(function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.get((error, user) => {
|
|
|
|
if (error) {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
this.userId = user._id
|
|
|
|
this.user.deleteUser(done)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should remove the user data from mongo', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
db.deletedUsers.findOne(
|
|
|
|
{ 'deleterData.deletedUserId': this.userId },
|
|
|
|
(error, deletedUser) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(deletedUser).to.exist
|
|
|
|
expect(deletedUser.deleterData.deleterIpAddress).to.exist
|
|
|
|
expect(deletedUser.user).to.exist
|
|
|
|
|
|
|
|
request.post(
|
|
|
|
`/internal/users/${this.userId}/expire`,
|
|
|
|
{
|
|
|
|
auth: {
|
|
|
|
user: settings.apis.web.user,
|
|
|
|
pass: settings.apis.web.pass,
|
2021-04-27 03:52:58 -04:00
|
|
|
sendImmediately: true,
|
|
|
|
},
|
2019-07-18 10:18:56 -04:00
|
|
|
},
|
|
|
|
(error, res) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(res.statusCode).to.equal(204)
|
|
|
|
|
|
|
|
db.deletedUsers.findOne(
|
|
|
|
{ 'deleterData.deletedUserId': this.userId },
|
|
|
|
(error, deletedUser) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(deletedUser).to.exist
|
|
|
|
expect(deletedUser.deleterData.deleterIpAddress).not.to.exist
|
|
|
|
expect(deletedUser.user).not.to.exist
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('Deleting a project', function () {
|
|
|
|
beforeEach(function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user = new User()
|
|
|
|
this.projectName = 'wombat'
|
|
|
|
this.user.ensureUserExists(() => {
|
|
|
|
this.user.login(() => {
|
|
|
|
this.user.createProject(this.projectName, (_e, projectId) => {
|
|
|
|
this.projectId = projectId
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should remove the project from active projects', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.getProject(this.projectId, (error, project) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(project).to.exist
|
|
|
|
|
|
|
|
this.user.deleteProject(this.projectId, error => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
|
|
|
|
this.user.getProject(this.projectId, (error, project) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(project).not.to.exist
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should create a soft-deleted project', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.getProject(this.projectId, (error, project) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
|
|
|
|
this.user.get((error, user) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
|
|
|
|
this.user.deleteProject(this.projectId, error => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
|
|
|
|
db.deletedProjects.findOne(
|
|
|
|
{ 'deleterData.deletedProjectId': project._id },
|
|
|
|
(error, deletedProject) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(deletedProject).to.exist
|
|
|
|
|
|
|
|
// it should set the 'deleterData' correctly
|
|
|
|
expect(deletedProject.deleterData.deleterId.toString()).to.equal(
|
|
|
|
user._id.toString()
|
|
|
|
)
|
|
|
|
expect(
|
|
|
|
deletedProject.deleterData.deletedProjectId.toString()
|
|
|
|
).to.equal(project._id.toString())
|
|
|
|
expect(
|
|
|
|
deletedProject.deleterData.deletedProjectOwnerId.toString()
|
|
|
|
).to.equal(user._id.toString())
|
|
|
|
// it should set the 'user' correctly
|
|
|
|
expect(deletedProject.project._id.toString()).to.equal(
|
|
|
|
project._id.toString()
|
|
|
|
)
|
|
|
|
expect(deletedProject.project.name).to.equal(this.projectName)
|
|
|
|
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('when the project has deleted files', function () {
|
|
|
|
beforeEach('get rootFolder id', function (done) {
|
2021-04-01 06:39:48 -04:00
|
|
|
this.user.getProject(this.projectId, (error, project) => {
|
|
|
|
if (error) return done(error)
|
|
|
|
this.rootFolder = project.rootFolder[0]._id
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
let allFileIds
|
2021-04-14 09:17:21 -04:00
|
|
|
beforeEach('reset allFileIds', function () {
|
2021-04-01 06:39:48 -04:00
|
|
|
allFileIds = []
|
|
|
|
})
|
|
|
|
function createAndDeleteFile(name) {
|
|
|
|
let fileId
|
2021-04-14 09:17:21 -04:00
|
|
|
beforeEach(`create file ${name}`, function (done) {
|
2021-04-01 06:39:48 -04:00
|
|
|
this.user.uploadExampleFileInProject(
|
|
|
|
this.projectId,
|
|
|
|
this.rootFolder,
|
|
|
|
name,
|
|
|
|
(error, theFileId) => {
|
|
|
|
fileId = theFileId
|
|
|
|
allFileIds.push(theFileId)
|
|
|
|
done(error)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
2021-04-14 09:17:21 -04:00
|
|
|
beforeEach(`delete file ${name}`, function (done) {
|
2021-04-01 06:39:48 -04:00
|
|
|
this.user.deleteItemInProject(this.projectId, 'file', fileId, done)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for (const name of ['a.png', 'another.png']) {
|
|
|
|
createAndDeleteFile(name)
|
|
|
|
}
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should have two deleteFiles entries', async function () {
|
2021-04-01 06:39:48 -04:00
|
|
|
const files = await db.deletedFiles
|
|
|
|
.find({}, { sort: { _id: 1 } })
|
|
|
|
.toArray()
|
|
|
|
expect(files).to.have.length(2)
|
|
|
|
expect(files.map(file => file._id.toString())).to.deep.equal(allFileIds)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('When the deleted project is expired', function () {
|
|
|
|
beforeEach('soft delete the project', function (done) {
|
2021-04-01 06:39:48 -04:00
|
|
|
this.user.deleteProject(this.projectId, done)
|
|
|
|
})
|
2021-04-14 09:17:21 -04:00
|
|
|
beforeEach('hard delete the project', function (done) {
|
2021-04-01 06:39:48 -04:00
|
|
|
request.post(
|
|
|
|
`/internal/project/${this.projectId}/expire-deleted-project`,
|
|
|
|
{
|
|
|
|
auth: {
|
|
|
|
user: settings.apis.web.user,
|
|
|
|
pass: settings.apis.web.pass,
|
2021-04-27 03:52:58 -04:00
|
|
|
sendImmediately: true,
|
|
|
|
},
|
2021-04-01 06:39:48 -04:00
|
|
|
},
|
|
|
|
(error, res) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(res.statusCode).to.equal(200)
|
|
|
|
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should cleanup the deleteFiles', async function () {
|
2021-04-01 06:39:48 -04:00
|
|
|
const files = await db.deletedFiles
|
|
|
|
.find({}, { sort: { _id: 1 } })
|
|
|
|
.toArray()
|
|
|
|
expect(files).to.deep.equal([])
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('When the project has docs', function () {
|
|
|
|
beforeEach(function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.getProject(this.projectId, (error, project) => {
|
|
|
|
if (error) {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
this.user.createDocInProject(
|
|
|
|
this.projectId,
|
|
|
|
project.rootFolder[0]._id,
|
|
|
|
'potato',
|
|
|
|
(error, docId) => {
|
|
|
|
if (error) {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
this.docId = docId
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
2021-02-25 07:22:24 -05:00
|
|
|
MockFilestoreApi.files[this.projectId.toString()] = {
|
2021-04-27 03:52:58 -04:00
|
|
|
dummyFile: 'wombat',
|
2020-04-24 05:17:51 -04:00
|
|
|
}
|
2022-03-25 10:00:07 -04:00
|
|
|
MockChatApi.projects[this.projectId.toString()] = ['message']
|
2023-05-15 09:46:27 -04:00
|
|
|
if (Features.hasFeature('git-bridge')) {
|
|
|
|
MockGitBridgeApi.projects[this.projectId.toString()] = {
|
|
|
|
data: 'some-data',
|
|
|
|
}
|
|
|
|
}
|
2019-07-18 10:18:56 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('When the deleted project is expired', function () {
|
|
|
|
beforeEach(function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
this.user.deleteProject(this.projectId, error => {
|
|
|
|
if (error) {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should destroy the docs', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
expect(
|
|
|
|
MockDocstoreApi.docs[this.projectId.toString()][this.docId.toString()]
|
|
|
|
).to.exist
|
|
|
|
|
|
|
|
request.post(
|
|
|
|
`/internal/project/${this.projectId}/expire-deleted-project`,
|
|
|
|
{
|
|
|
|
auth: {
|
|
|
|
user: settings.apis.web.user,
|
|
|
|
pass: settings.apis.web.pass,
|
2021-04-27 03:52:58 -04:00
|
|
|
sendImmediately: true,
|
|
|
|
},
|
2019-07-18 10:18:56 -04:00
|
|
|
},
|
|
|
|
(error, res) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(res.statusCode).to.equal(200)
|
|
|
|
|
|
|
|
expect(MockDocstoreApi.docs[this.projectId.toString()]).not.to.exist
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should destroy the files', function (done) {
|
2021-02-25 07:22:24 -05:00
|
|
|
expect(MockFilestoreApi.files[this.projectId.toString()]).to.exist
|
2020-04-24 05:17:51 -04:00
|
|
|
|
|
|
|
request.post(
|
|
|
|
`/internal/project/${this.projectId}/expire-deleted-project`,
|
|
|
|
{
|
|
|
|
auth: {
|
|
|
|
user: settings.apis.web.user,
|
|
|
|
pass: settings.apis.web.pass,
|
2021-04-27 03:52:58 -04:00
|
|
|
sendImmediately: true,
|
|
|
|
},
|
2020-04-24 05:17:51 -04:00
|
|
|
},
|
|
|
|
(error, res) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(res.statusCode).to.equal(200)
|
|
|
|
|
2021-02-25 07:22:24 -05:00
|
|
|
expect(MockFilestoreApi.files[this.projectId.toString()]).not.to
|
2020-04-24 05:17:51 -04:00
|
|
|
.exist
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-03-25 10:00:07 -04:00
|
|
|
it('Should destroy the chat', function (done) {
|
|
|
|
expect(MockChatApi.projects[this.projectId.toString()]).to.exist
|
|
|
|
|
|
|
|
request.post(
|
|
|
|
`/internal/project/${this.projectId}/expire-deleted-project`,
|
|
|
|
{
|
|
|
|
auth: {
|
|
|
|
user: settings.apis.web.user,
|
|
|
|
pass: settings.apis.web.pass,
|
|
|
|
sendImmediately: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
(error, res) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(res.statusCode).to.equal(200)
|
|
|
|
|
|
|
|
expect(MockChatApi.projects[this.projectId.toString()]).not.to.exist
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('Should remove the project data from mongo', function (done) {
|
2019-07-18 10:18:56 -04:00
|
|
|
db.deletedProjects.findOne(
|
|
|
|
{ 'deleterData.deletedProjectId': ObjectId(this.projectId) },
|
|
|
|
(error, deletedProject) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(deletedProject).to.exist
|
|
|
|
expect(deletedProject.project).to.exist
|
|
|
|
expect(deletedProject.deleterData.deleterIpAddress).to.exist
|
|
|
|
expect(deletedProject.deleterData.deletedAt).to.exist
|
|
|
|
|
|
|
|
request.post(
|
|
|
|
`/internal/project/${this.projectId}/expire-deleted-project`,
|
|
|
|
{
|
|
|
|
auth: {
|
|
|
|
user: settings.apis.web.user,
|
|
|
|
pass: settings.apis.web.pass,
|
2021-04-27 03:52:58 -04:00
|
|
|
sendImmediately: true,
|
|
|
|
},
|
2019-07-18 10:18:56 -04:00
|
|
|
},
|
|
|
|
(error, res) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(res.statusCode).to.equal(200)
|
|
|
|
|
|
|
|
db.deletedProjects.findOne(
|
|
|
|
{ 'deleterData.deletedProjectId': ObjectId(this.projectId) },
|
|
|
|
(error, deletedProject) => {
|
|
|
|
expect(error).not.to.exist
|
|
|
|
expect(deletedProject).to.exist
|
|
|
|
expect(deletedProject.project).not.to.exist
|
|
|
|
expect(deletedProject.deleterData.deleterIpAddress).not.to
|
|
|
|
.exist
|
|
|
|
expect(deletedProject.deleterData.deletedAt).to.exist
|
|
|
|
done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2023-05-15 09:46:27 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2019-07-18 10:18:56 -04:00
|
|
|
})
|