diff --git a/forge/db/models/Project.js b/forge/db/models/Project.js index af1ce44b7..0caff9b3a 100644 --- a/forge/db/models/Project.js +++ b/forge/db/models/Project.js @@ -32,7 +32,8 @@ const BANNED_NAME_LIST = [ 'status', 'billing', 'mqtt', - 'broker' + 'broker', + 'egress' ] /** @type {FFModel} */ diff --git a/forge/db/models/User.js b/forge/db/models/User.js index b56e119b2..287a9e8b5 100644 --- a/forge/db/models/User.js +++ b/forge/db/models/User.js @@ -99,45 +99,16 @@ module.exports = { // determine if this user owns any teams // throw an error if we would orphan any teams const teams = await app.db.models.Team.forUser(user) - const teamBlockers = [] - const ownedTeams = [] for (const team of teams) { const owners = await team.Team.getOwners() const isOwner = owners.find((owner) => owner.id === user.id) + // if this user is the only owner of this team, throw an error if (isOwner && owners.length <= 1) { - const instanceCount = await team.Team.instanceCount() - const deviceCount = await team.Team.deviceCount() - const members = await team.Team.memberCount() - - ownedTeams.push(team) - - // throw error if the team has other members assigned to it - if (members > 1) { - teamBlockers.push(`Team ${team.Team.name} which is being deleted alongside your account still has users in it.`) - } - - // throw error if the team has remaining instances assigned to it - if (instanceCount > 0) { - teamBlockers.push(`Team ${team.Team.name} which is being deleted alongside your account still has instances assigned to it.`) - } - - // throw error if the team has remaining devices assigned to it - if (deviceCount > 0) { - teamBlockers.push(`Team ${team.Team.name} which is being deleted alongside your account still has devices assigned to it.`) - } + throw new Error('Cannot delete the last owner of a team') } } - if (teamBlockers.length) { - throw new Error(teamBlockers[0]) - } - - // delete remaining owned teams - for (const ownedTeam of ownedTeams) { - await ownedTeam.destroy() - } - // Need to do this in beforeDestroy as the Session.UserId field // is set to NULL when user is deleted. // TODO: modify cascade delete relationship between the tables diff --git a/test/unit/forge/routes/api/user_spec.js b/test/unit/forge/routes/api/user_spec.js index 023dcb8d5..fc4c52b85 100644 --- a/test/unit/forge/routes/api/user_spec.js +++ b/test/unit/forge/routes/api/user_spec.js @@ -19,10 +19,6 @@ describe('User API', async function () { TestObjects.BTeam = await app.db.models.Team.create({ name: 'BTeam', TeamTypeId: app.defaultTeamType.id }) TestObjects.Project1 = app.project TestObjects.tokens = {} - TestObjects.application = app.application - TestObjects.stack = app.stack - TestObjects.projectType = app.projectType - TestObjects.template = app.template await setupUsers() } async function setupUsers () { @@ -744,7 +740,7 @@ describe('User API', async function () { const json = response.json() json.should.have.property('error', 'Error: Cannot delete the last platform administrator') }) - it('Last owner of a team cannot delete own account when the team has other members present', async function () { + it('Last owner of a team cannot delete own account', async function () { await login('frank', 'ffPassword') // delete bob so that grace becomes the remaining owner of team B await TestObjects.bob.destroy() @@ -757,66 +753,7 @@ describe('User API', async function () { }) response.statusCode.should.equal(400) const json = response.json() - json.should.have.property('error', 'Error: Team BTeam which is being deleted alongside your account still has users in it.') - }) - it('Last owner of a team cannot delete own account when the team has instances present', async function () { - const amidala = await app.db.models.User.create({ username: 'amidala', name: 'Padme Amidala', email: 'amidala@example.com', email_verified: true, password: 'paPassword', admin: false, sso_enabled: false }) - const nabooTeam = await app.db.models.Team.create({ name: 'nabooTeam', TeamTypeId: app.defaultTeamType.id }) - - await nabooTeam.addUser(amidala, { through: { role: Roles.Owner } }) - - await login('amidala', 'paPassword') - - const nabooTeamApplication = await app.factory.createApplication({ name: 'senate-app' }, nabooTeam) - - // we create an instance so Padme won't be able to delete her account - await app.factory.createInstance( - { name: 'instance' }, - nabooTeamApplication, - TestObjects.stack, - TestObjects.template, - TestObjects.projectType - ) - - // Padme now attempts to delete own account: should fail as she still has instances attached to her team - const response = await app.inject({ - method: 'DELETE', - url: '/api/v1/user', - cookies: { sid: TestObjects.tokens.amidala } - }) - response.statusCode.should.equal(400) - const json = response.json() - json.should.have.property('error', 'Error: Team nabooTeam which is being deleted alongside your account still has instances assigned to it.') - }) - it('Last owner of a team cannot delete own account when the team has devices present', async function () { - const amidala = await app.db.models.User.create({ username: 'amidala', name: 'Padme Amidala', email: 'amidala@example.com', email_verified: true, password: 'paPassword', admin: false, sso_enabled: false }) - const nabooTeam = await app.db.models.Team.create({ name: 'nabooTeam2', TeamTypeId: app.defaultTeamType.id }) - - await nabooTeam.addUser(amidala, { through: { role: Roles.Owner } }) - - await login('amidala', 'paPassword') - - const nabooTeamApplication = await app.factory.createApplication({ name: 'senate-app' }, nabooTeam) - - // we create a device so Padme won't be able to delete her account - await app.factory.createDevice( - { - name: 'some-device' - }, - nabooTeam, - null, - nabooTeamApplication - ) - - // Padme now attempts to delete own account: should fail as owned team has devices attached - const response = await app.inject({ - method: 'DELETE', - url: '/api/v1/user', - cookies: { sid: TestObjects.tokens.amidala } - }) - response.statusCode.should.equal(400) - const json = response.json() - json.should.have.property('error', 'Error: Team nabooTeam2 which is being deleted alongside your account still has devices assigned to it.') + json.should.have.property('error', 'Error: Cannot delete the last owner of a team') }) it('Non admin user who is a team member can delete own account', async function () { await login('grace', 'ggPassword') @@ -836,24 +773,6 @@ describe('User API', async function () { }) response.statusCode.should.equal(200) }) - it('Team owner can delete own account if no other members, instances or devices exist', async function () { - const amidala = await app.db.models.User.create({ username: 'amidala', name: 'Padme Amidala', email: 'amidala@example.com', email_verified: true, password: 'paPassword', admin: false, sso_enabled: false }) - const nabooTeam = await app.db.models.Team.create({ name: 'nabooTeam3', TeamTypeId: app.defaultTeamType.id }) - - await nabooTeam.addUser(amidala, { through: { role: Roles.Owner } }) - - await login('amidala', 'paPassword') - - await app.factory.createApplication({ name: 'senate-app-2' }, nabooTeam) - - // Padme now attempts to delete own account: should succeed even though it has instances attached to the team - const response = await app.inject({ - method: 'DELETE', - url: '/api/v1/user', - cookies: { sid: TestObjects.tokens.amidala } - }) - response.statusCode.should.equal(200) - }) }) describe('User PAT', async function () {