Skip to content

Commit

Permalink
Merge branch 'main' into 4534-bom-api-use-project-model-versions
Browse files Browse the repository at this point in the history
  • Loading branch information
Steve-Mcl committed Sep 23, 2024
2 parents b85947f + 45c992a commit 594e0c7
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 115 deletions.
3 changes: 2 additions & 1 deletion forge/db/models/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const BANNED_NAME_LIST = [
'status',
'billing',
'mqtt',
'broker'
'broker',
'egress'
]

/** @type {FFModel} */
Expand Down
33 changes: 2 additions & 31 deletions forge/db/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
85 changes: 2 additions & 83 deletions test/unit/forge/routes/api/user_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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()
Expand All @@ -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')
Expand All @@ -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 () {
Expand Down

0 comments on commit 594e0c7

Please sign in to comment.