Skip to content

Commit

Permalink
introduce reference checks
Browse files Browse the repository at this point in the history
  • Loading branch information
david-loe committed Sep 24, 2024
1 parent 6df9ae9 commit dd61b94
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 4 deletions.
17 changes: 16 additions & 1 deletion backend/controller/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FilterQuery, HydratedDocument, Model, ProjectionType, Types } from 'mon
import { Controller as TsoaController } from 'tsoa'
import { Base64 } from '../../common/scripts.js'
import { GETResponse, Meta, User, _id } from '../../common/types.js'
import { NotAllowedError, NotFoundError } from './error.js'
import { ConflictError, NotAllowedError, NotFoundError } from './error.js'
import { IdDocument } from './types.js'

export interface GetterQuery<ModelType> {
Expand Down Expand Up @@ -144,6 +144,7 @@ export interface DeleterQuery {
}

export interface DeleterOptions<ModelType, ModelMethods = any> extends DeleterQuery {
referenceChecks?: { paths: string[]; model: Model<any>; conditions?: { [key: string]: any } }[]
cb?: (data: DeleteResult) => any
checkOldObject?: (oldObject: HydratedDocument<ModelType> & ModelMethods) => Promise<boolean>
}
Expand Down Expand Up @@ -299,6 +300,20 @@ export class Controller extends TsoaController {
if (options.checkOldObject && !(await options.checkOldObject(doc))) {
throw new NotAllowedError(`Not allowed to delete this ${model.modelName}`)
}
if (options.referenceChecks) {
for (const referenceCheck of options.referenceChecks) {
const filter = { $or: [] as { [key: string]: any }[] }
for (const path of referenceCheck.paths) {
const conditions: { [key: string]: any } = structuredClone(referenceCheck.conditions) || {}
conditions[path] = options._id
filter.$or.push(conditions)
}
const count = await referenceCheck.model.countDocuments(filter)
if (count > 0) {
throw new ConflictError(`${count} ${referenceCheck.model.modelName}${count > 1 ? 's' : ''} linked.`)
}
}
}
const result = await doc.deleteOne()
if (options.cb) {
options.cb(result)
Expand Down
5 changes: 5 additions & 0 deletions backend/controller/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export class NotFoundError extends ClientError {
name = 'alerts.notFound'
}

export class ConflictError extends ClientError {
status = 409
name = 'alerts.conflict'
}

export class NotImplementedError extends ClientError {
status = 501
name = 'alerts.notImplemented'
Expand Down
3 changes: 2 additions & 1 deletion backend/controller/organisationController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Body, Consumes, Delete, Get, Middlewares, Post, Queries, Query, Request
import { Organisation as IOrganisation, _id } from '../../common/types.js'
import { documentFileHandler } from '../helper.js'
import Organisation from '../models/organisation.js'
import Project from '../models/project.js'
import { Controller, GetterQuery, SetterBody } from './controller.js'

const fileHandler = multer({ limits: { fileSize: 16000000 } })
Expand Down Expand Up @@ -42,6 +43,6 @@ export class OrganisationAdminController extends Controller {

@Delete()
public async deleteOrganisation(@Query() _id: _id) {
return await this.deleter(Organisation, { _id: _id })
return await this.deleter(Organisation, { _id: _id, referenceChecks: [{ model: Project, paths: ['organisation'] }] })
}
}
12 changes: 11 additions & 1 deletion backend/controller/projectController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { Request as ExRequest } from 'express'
import { Body, Delete, Get, Post, Queries, Query, Request, Route, Security, Tags } from 'tsoa'
import { Project as IProject, ProjectSimple, _id } from '../../common/types.js'
import { getSettings } from '../helper.js'
import ExpenseReport from '../models/expenseReport.js'
import HealthCareCost from '../models/healthCareCost.js'
import Project from '../models/project.js'
import Travel from '../models/travel.js'
import { Controller, GetterQuery, SetterBody } from './controller.js'
import { AuthorizationError } from './error.js'

Expand Down Expand Up @@ -46,6 +49,13 @@ export class ProjectAdminController extends Controller {
}
@Delete()
public async deleteProject(@Query() _id: _id) {
return await this.deleter(Project, { _id: _id })
return await this.deleter(Project, {
_id: _id,
referenceChecks: [
{ model: ExpenseReport, paths: ['project'] },
{ model: Travel, paths: ['project'] },
{ model: HealthCareCost, paths: ['project'] }
]
})
}
}
12 changes: 11 additions & 1 deletion backend/controller/userController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { User as IUser, _id } from '../../common/types.js'
import { documentFileHandler } from '../helper.js'
import i18n from '../i18n.js'
import { sendMail } from '../mail/mail.js'
import ExpenseReport from '../models/expenseReport.js'
import HealthCareCost from '../models/healthCareCost.js'
import Token from '../models/token.js'
import Travel from '../models/travel.js'
import User from '../models/user.js'
import { Controller, GetterQuery, SetterBody } from './controller.js'
import { NotAllowedError, NotFoundError } from './error.js'
Expand Down Expand Up @@ -131,7 +134,14 @@ export class UserAdminController extends Controller {

@Delete()
public async deleteUser(@Query() _id: _id) {
return await this.deleter(User, { _id })
return await this.deleter(User, {
_id,
referenceChecks: [
{ model: Travel, paths: ['owner', 'editor', 'comments.author'], conditions: { historic: false } },
{ model: ExpenseReport, paths: ['owner', 'editor', 'comments.author'], conditions: { historic: false } },
{ model: HealthCareCost, paths: ['owner', 'editor', 'comments.author'], conditions: { historic: false } }
]
})
}

@Post('merge')
Expand Down
1 change: 1 addition & 0 deletions common/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"alerts": {
"areYouSureDelete": "Bist du dir sicher, dass du das löschen willst?",
"areYouSureMerge": "Bist du dir sicher, dass du diese Benutzer zusammenführen willst? Das kann nicht rückgängig gemacht werden.",
"conflict": "Konflikt!",
"countryChangeBetweenStages": "Länderwechsel zwischen aufeinanderfolgenden Etappen",
"db": {
"createdSettings": "Einstellungen wurden vom Standard erstellt",
Expand Down
1 change: 1 addition & 0 deletions common/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"alerts": {
"areYouSureDelete": "Are you sure that you want to delete this?",
"areYouSureMerge": "Are you sure you want to merge these users? This cannot be undone.",
"conflict": "Conflict!",
"countryChangeBetweenStages": "Country change between consecutive stages",
"db": {
"createdSettings": "Created Settings from Default",
Expand Down

0 comments on commit dd61b94

Please sign in to comment.