| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- const User = require('./helpers/User')
- const Subscription = require('./helpers/Subscription')
- const request = require('./helpers/request')
- 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, MockGitBridgeApi
- before(function () {
- MockDocstoreApi = MockDocstoreApiClass.instance()
- MockFilestoreApi = MockFilestoreApiClass.instance()
- MockChatApi = MockChatApiClass.instance()
- MockGitBridgeApi = MockGitBridgeApiClass.instance()
- })
- describe('Deleting a user', function () {
- beforeEach(function (done) {
- async.auto(
- {
- user: cb => {
- const user = new User()
- user.ensureUserExists(() => {
- cb(null, user)
- })
- },
- login: [
- 'user',
- (results, cb) => {
- results.user.login(cb)
- },
- ],
- subscription: [
- 'user',
- 'login',
- (results, cb) => {
- const subscription = new Subscription({
- admin_id: results.user._id,
- })
- subscription.ensureExists(err => {
- cb(err, subscription)
- })
- },
- ],
- },
- (err, results) => {
- expect(err).not.to.exist
- this.user = results.user
- this.subscription = results.subscription
- done()
- }
- )
- })
- it('Should remove the user from active users', function (done) {
- 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()
- })
- })
- })
- })
- it('Should create a soft-deleted user', function (done) {
- 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()
- }
- )
- })
- })
- })
- it("Should delete the user's projects", function (done) {
- 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()
- })
- })
- })
- })
- })
- describe('when scrubbing the user', function () {
- beforeEach(function (done) {
- this.user.get((error, user) => {
- if (error) {
- throw error
- }
- this.userId = user._id
- this.user.deleteUser(done)
- })
- })
- it('Should remove the user data from mongo', function (done) {
- 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,
- sendImmediately: true,
- },
- },
- (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()
- }
- )
- }
- )
- }
- )
- })
- })
- })
- describe('Deleting a project', function () {
- beforeEach(function (done) {
- this.user = new User()
- this.projectName = 'wombat'
- this.user.ensureUserExists(() => {
- this.user.login(() => {
- this.user.createProject(this.projectName, (_e, projectId) => {
- this.projectId = projectId
- done()
- })
- })
- })
- })
- it('Should remove the project from active projects', function (done) {
- 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()
- })
- })
- })
- })
- it('Should create a soft-deleted project', function (done) {
- 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()
- }
- )
- })
- })
- })
- })
- describe('when the project has deleted files', function () {
- beforeEach('get rootFolder id', function (done) {
- this.user.getProject(this.projectId, (error, project) => {
- if (error) return done(error)
- this.rootFolder = project.rootFolder[0]._id
- done()
- })
- })
- let allFileIds
- beforeEach('reset allFileIds', function () {
- allFileIds = []
- })
- function createAndDeleteFile(name) {
- let fileId
- beforeEach(`create file ${name}`, function (done) {
- this.user.uploadExampleFileInProject(
- this.projectId,
- this.rootFolder,
- name,
- (error, theFileId) => {
- fileId = theFileId
- allFileIds.push(theFileId)
- done(error)
- }
- )
- })
- beforeEach(`delete file ${name}`, function (done) {
- this.user.deleteItemInProject(this.projectId, 'file', fileId, done)
- })
- }
- for (const name of ['a.png', 'another.png']) {
- createAndDeleteFile(name)
- }
- it('should have two deleteFiles entries', async function () {
- 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)
- })
- describe('When the deleted project is expired', function () {
- beforeEach('soft delete the project', function (done) {
- this.user.deleteProject(this.projectId, done)
- })
- beforeEach('hard delete the project', function (done) {
- 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)
- done()
- }
- )
- })
- it('should cleanup the deleteFiles', async function () {
- const files = await db.deletedFiles
- .find({}, { sort: { _id: 1 } })
- .toArray()
- expect(files).to.deep.equal([])
- })
- })
- })
- describe('When the project has docs', function () {
- beforeEach(function (done) {
- 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()
- }
- )
- MockFilestoreApi.files[this.projectId.toString()] = {
- dummyFile: 'wombat',
- }
- MockChatApi.projects[this.projectId.toString()] = ['message']
- if (Features.hasFeature('git-bridge')) {
- 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) {
- throw error
- }
- done()
- })
- })
- it('Should destroy the docs', function (done) {
- 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,
- sendImmediately: true,
- },
- },
- (error, res) => {
- expect(error).not.to.exist
- expect(res.statusCode).to.equal(200)
- expect(MockDocstoreApi.docs[this.projectId.toString()]).not.to.exist
- done()
- }
- )
- })
- it('Should destroy the files', function (done) {
- expect(MockFilestoreApi.files[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(MockFilestoreApi.files[this.projectId.toString()]).not.to
- .exist
- done()
- }
- )
- })
- 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()
- }
- )
- })
- it('Should remove the project data from mongo', function (done) {
- 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,
- sendImmediately: true,
- },
- },
- (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()
- }
- )
- }
- )
- }
- )
- })
- })
- })
- 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
- })
- })
- })
- }
- })
|