Skip to content

Commit

Permalink
Merge pull request #100 from david-loe/david-loe/issue94
Browse files Browse the repository at this point in the history
Add Project Supervisors
  • Loading branch information
david-loe authored Sep 28, 2024
2 parents c8d4007 + 12d56c1 commit 105f800
Show file tree
Hide file tree
Showing 22 changed files with 425 additions and 77 deletions.
48 changes: 36 additions & 12 deletions backend/controller/expenseReportController.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Request as ExRequest } from 'express'
import { Condition } from 'mongoose'
import multer from 'multer'
import { Body, Delete, Get, Middlewares, Post, Produces, Queries, Query, Request, Route, Security, Tags } from 'tsoa'
import { Expense, ExpenseReportState, ExpenseReport as IExpenseReport, Locale, _id } from '../../common/types.js'
import { documentFileHandler, writeToDisk } from '../helper.js'
import { checkIfUserIsProjectSupervisor, documentFileHandler, writeToDisk } from '../helper.js'
import i18n from '../i18n.js'
import { sendNotificationMail } from '../mail/mail.js'
import ExpenseReport, { ExpenseReportDoc } from '../models/expenseReport.js'
Expand Down Expand Up @@ -168,20 +169,31 @@ export class ExpenseReportController extends Controller {
@Security('cookieAuth', ['examine/expenseReport'])
export class ExpenseReportExamineController extends Controller {
@Get()
public async getExpenseReport(@Queries() query: GetterQuery<IExpenseReport>) {
public async getExpenseReport(@Queries() query: GetterQuery<IExpenseReport>, @Request() request: ExRequest) {
const filter: Condition<IExpenseReport> = {
$and: [{ historic: false }, { $or: [{ state: 'underExamination' }, { state: 'refunded' }] }]
}
if (request.user!.projects.supervised.length > 0) {
filter.$and.push({ project: { $in: request.user!.projects.supervised } })
}
const sortFn = (a: IExpenseReport, b: IExpenseReport) => (b.updatedAt as Date).valueOf() - (a.updatedAt as Date).valueOf()
return await this.getter(ExpenseReport, {
query,
filter: { $and: [{ historic: false }, { $or: [{ state: 'underExamination' }, { state: 'refunded' }] }] },
filter,
projection: { history: 0, historic: 0, expenses: 0 },
allowedAdditionalFields: ['expenses'],
sortFn
})
}

@Delete()
public async deleteExpenseReport(@Query() _id: _id) {
return await this.deleter(ExpenseReport, { _id: _id })
public async deleteExpenseReport(@Query() _id: _id, @Request() request: ExRequest) {
return await this.deleter(ExpenseReport, {
_id: _id,
async checkOldObject(oldObject: IExpenseReport) {
return checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
}
})
}

@Post('expense')
Expand All @@ -192,8 +204,12 @@ export class ExpenseReportExamineController extends Controller {
parentId,
arrayElementKey: 'expenses',
allowNew: true,
async checkOldObject(oldObject) {
if (!oldObject.historic && oldObject.state === 'underExamination') {
async checkOldObject(oldObject: IExpenseReport) {
if (
!oldObject.historic &&
oldObject.state === 'underExamination' &&
checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
) {
await documentFileHandler(['cost', 'receipts'], { owner: oldObject.owner._id })(request)
return true
} else {
Expand All @@ -205,13 +221,17 @@ export class ExpenseReportExamineController extends Controller {
}

@Delete('expense')
public async deleteExpenese(@Query() _id: _id, @Query() parentId: _id) {
public async deleteExpenese(@Query() _id: _id, @Query() parentId: _id, @Request() request: ExRequest) {
return await this.deleterForArrayElement(ExpenseReport, {
_id,
parentId,
arrayElementKey: 'expenses',
async checkOldObject(oldObject) {
if (!oldObject.historic && oldObject.state === 'underExamination') {
if (
!oldObject.historic &&
oldObject.state === 'underExamination' &&
checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
) {
return true
} else {
return false
Expand Down Expand Up @@ -241,7 +261,7 @@ export class ExpenseReportExamineController extends Controller {
cb: (e: IExpenseReport) => sendNotificationMail(e, extendedBody._id ? 'backToInWork' : undefined),
allowNew: true,
async checkOldObject(oldObject: ExpenseReportDoc) {
if (oldObject.state === 'underExamination') {
if (oldObject.state === 'underExamination' && checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)) {
await oldObject.saveToHistory()
await oldObject.save()
return true
Expand Down Expand Up @@ -271,7 +291,7 @@ export class ExpenseReportExamineController extends Controller {
cb,
allowNew: false,
async checkOldObject(oldObject: ExpenseReportDoc) {
if (oldObject.state === 'underExamination') {
if (oldObject.state === 'underExamination' && checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)) {
await oldObject.saveToHistory()
await oldObject.save()
return true
Expand All @@ -285,7 +305,11 @@ export class ExpenseReportExamineController extends Controller {
@Get('report')
@Produces('application/pdf')
public async getReport(@Query() _id: _id, @Request() request: ExRequest) {
const expenseReport = await ExpenseReport.findOne({ _id, historic: false, state: 'refunded' }).lean()
const filter: Condition<IExpenseReport> = { _id, historic: false, state: 'refunded' }
if (request.user!.projects.supervised.length > 0) {
filter.project = { $in: request.user!.projects.supervised }
}
const expenseReport = await ExpenseReport.findOne(filter).lean()
if (expenseReport) {
const report = await generateExpenseReportReport(expenseReport, request.user!.settings.language)
request.res?.setHeader('Content-disposition', 'attachment; filename=' + expenseReport.name + '.pdf')
Expand Down
75 changes: 57 additions & 18 deletions backend/controller/healthCareCostController.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Request as ExRequest } from 'express'
import { Condition } from 'mongoose'
import multer from 'multer'
import { Body, Delete, Get, Middlewares, Post, Produces, Queries, Query, Request, Route, Security, Tags } from 'tsoa'
import {
Expand All @@ -9,7 +10,7 @@ import {
Locale,
_id
} from '../../common/types.js'
import { documentFileHandler, writeToDisk } from '../helper.js'
import { checkIfUserIsProjectSupervisor, documentFileHandler, writeToDisk } from '../helper.js'
import i18n from '../i18n.js'
import { sendNotificationMail } from '../mail/mail.js'
import HealthCareCost, { HealthCareCostDoc } from '../models/healthCareCost.js'
Expand Down Expand Up @@ -175,20 +176,31 @@ export class HealthCareCostController extends Controller {
@Security('cookieAuth', ['examine/healthCareCost'])
export class HealthCareCostExamineController extends Controller {
@Get()
public async getHealthCareCost(@Queries() query: GetterQuery<IHealthCareCost>) {
public async getHealthCareCost(@Queries() query: GetterQuery<IHealthCareCost>, @Request() request: ExRequest) {
const filter: Condition<IHealthCareCost> = {
$and: [{ historic: false }, { $or: [{ state: 'underExamination' }, { state: 'underExaminationByInsurance' }] }]
}
if (request.user!.projects.supervised.length > 0) {
filter.$and.push({ project: { $in: request.user!.projects.supervised } })
}
const sortFn = (a: IHealthCareCost, b: IHealthCareCost) => (b.updatedAt as Date).valueOf() - (a.updatedAt as Date).valueOf()
return await this.getter(HealthCareCost, {
query,
filter: { $and: [{ historic: false }, { $or: [{ state: 'underExamination' }, { state: 'underExaminationByInsurance' }] }] },
filter,
projection: { history: 0, historic: 0, expenses: 0 },
allowedAdditionalFields: ['expenses'],
sortFn
})
}

@Delete()
public async deleteHealthCareCost(@Query() _id: _id) {
return await this.deleter(HealthCareCost, { _id: _id })
public async deleteHealthCareCost(@Query() _id: _id, @Request() request: ExRequest) {
return await this.deleter(HealthCareCost, {
_id: _id,
async checkOldObject(oldObject: IHealthCareCost) {
return checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
}
})
}

@Post('expense')
Expand All @@ -200,7 +212,11 @@ export class HealthCareCostExamineController extends Controller {
arrayElementKey: 'expenses',
allowNew: true,
async checkOldObject(oldObject) {
if (!oldObject.historic && oldObject.state === 'underExamination') {
if (
!oldObject.historic &&
oldObject.state === 'underExamination' &&
checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
) {
await documentFileHandler(['cost', 'receipts'], { owner: oldObject.owner._id })(request)
return true
} else {
Expand All @@ -212,13 +228,17 @@ export class HealthCareCostExamineController extends Controller {
}

@Delete('expense')
public async deleteExpenese(@Query() _id: _id, @Query() parentId: _id) {
public async deleteExpenese(@Query() _id: _id, @Query() parentId: _id, @Request() request: ExRequest) {
return await this.deleterForArrayElement(HealthCareCost, {
_id,
parentId,
arrayElementKey: 'expenses',
async checkOldObject(oldObject) {
if (!oldObject.historic && oldObject.state === 'underExamination') {
if (
!oldObject.historic &&
oldObject.state === 'underExamination' &&
checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
) {
return true
} else {
return false
Expand Down Expand Up @@ -249,7 +269,7 @@ export class HealthCareCostExamineController extends Controller {
cb,
allowNew: false,
async checkOldObject(oldObject: HealthCareCostDoc) {
if (oldObject.state === 'underExamination') {
if (oldObject.state === 'underExamination' && checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)) {
await oldObject.saveToHistory()
await oldObject.save()
return true
Expand Down Expand Up @@ -289,7 +309,7 @@ export class HealthCareCostExamineController extends Controller {
cb: (e: IHealthCareCost) => sendNotificationMail(e, extendedBody._id ? 'backToInWork' : undefined),
allowNew: true,
async checkOldObject(oldObject: HealthCareCostDoc) {
if (oldObject.state === 'underExamination') {
if (oldObject.state === 'underExamination' && checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)) {
await oldObject.saveToHistory()
await oldObject.save()
return true
Expand All @@ -303,7 +323,11 @@ export class HealthCareCostExamineController extends Controller {
@Get('report')
@Produces('application/pdf')
public async getReport(@Query() _id: _id, @Request() request: ExRequest) {
const healthCareCost = await HealthCareCost.findOne({ _id, historic: false, state: 'underExaminationByInsurance' }).lean()
const filter: Condition<IHealthCareCost> = { _id, historic: false, state: 'underExaminationByInsurance' }
if (request.user!.projects.supervised.length > 0) {
filter.project = { $in: request.user!.projects.supervised }
}
const healthCareCost = await HealthCareCost.findOne(filter).lean()
if (healthCareCost) {
const report = await generateHealthCareCostReport(healthCareCost, request.user!.settings.language)
request.res?.setHeader('Content-disposition', 'attachment; filename=' + healthCareCost.name + '.pdf')
Expand All @@ -326,11 +350,17 @@ export class HealthCareCostExamineController extends Controller {
@Security('cookieAuth', ['confirm/healthCareCost'])
export class HealthCareCostConfirmController extends Controller {
@Get()
public async getHealthCareCost(@Queries() query: GetterQuery<IHealthCareCost>) {
public async getHealthCareCost(@Queries() query: GetterQuery<IHealthCareCost>, @Request() request: ExRequest) {
const filter: Condition<IHealthCareCost> = {
$and: [{ historic: false }, { $or: [{ state: 'underExaminationByInsurance' }, { state: 'refunded' }] }]
}
if (request.user!.projects.supervised.length > 0) {
filter.$and.push({ project: { $in: request.user!.projects.supervised } })
}
const sortFn = (a: IHealthCareCost, b: IHealthCareCost) => (b.updatedAt as Date).valueOf() - (a.updatedAt as Date).valueOf()
return await this.getter(HealthCareCost, {
query,
filter: { $and: [{ historic: false }, { $or: [{ state: 'underExaminationByInsurance' }, { state: 'refunded' }] }] },
filter,
projection: { history: 0, historic: 0, expenses: 0 },
allowedAdditionalFields: ['expenses'],
sortFn
Expand Down Expand Up @@ -360,7 +390,7 @@ export class HealthCareCostConfirmController extends Controller {
cb,
allowNew: false,
async checkOldObject(oldObject: HealthCareCostDoc) {
if (oldObject.state === 'underExaminationByInsurance') {
if (oldObject.state === 'underExaminationByInsurance' && checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)) {
await documentFileHandler(['refundSum', 'receipts'], { owner: oldObject.owner._id })(request)
await oldObject.saveToHistory()
await oldObject.save()
Expand All @@ -372,16 +402,25 @@ export class HealthCareCostConfirmController extends Controller {
})
}
@Delete()
public async deleteHealthCareCost(@Query() _id: _id) {
return await this.deleter(HealthCareCost, { _id: _id })
public async deleteHealthCareCost(@Query() _id: _id, @Request() request: ExRequest) {
return await this.deleter(HealthCareCost, {
_id: _id,
async checkOldObject(oldObject: IHealthCareCost) {
return checkIfUserIsProjectSupervisor(request.user!, oldObject.project._id)
}
})
}

@Get('report')
@Produces('application/pdf')
public async getReport(@Query() _id: _id, @Request() request: ExRequest) {
const healthCareCost = await HealthCareCost.findOne({
const filter: Condition<IHealthCareCost> = {
$and: [{ _id, historic: false }, { $or: [{ state: 'refunded' }, { state: 'underExaminationByInsurance' }] }]
}).lean()
}
if (request.user!.projects.supervised.length > 0) {
filter.$and.push({ project: { $in: request.user!.projects.supervised } })
}
const healthCareCost = await HealthCareCost.findOne(filter).lean()
if (healthCareCost) {
const report = await generateHealthCareCostReport(healthCareCost, request.user!.settings.language)
request.res?.setHeader('Content-disposition', 'attachment; filename=' + healthCareCost.name + '.pdf')
Expand Down
22 changes: 18 additions & 4 deletions backend/controller/projectController.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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 { Project as IProject, ProjectSimple, ProjectWithUsers, _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 User from '../models/user.js'
import { Controller, GetterQuery, SetterBody } from './controller.js'
import { AuthorizationError } from './error.js'

Expand All @@ -22,7 +23,8 @@ export class ProjectController extends Controller {
request.user?.access['examine/travel'] ||
request.user?.access['examine/expenseReport'] ||
request.user?.access['examine/healthCareCost'] ||
request.user?.access['confirm/healthCareCost']
request.user?.access['confirm/healthCareCost'] ||
request.user?.access['admin']
) {
return await this.getter(Project, { query, projection: { identifier: 1, organisation: 1 } })
} else {
Expand All @@ -40,8 +42,20 @@ export class ProjectAdminController extends Controller {
return await this.getter(Project, { query })
}
@Post()
public async postProject(@Body() requestBody: SetterBody<IProject>) {
return await this.setter(Project, { requestBody: requestBody, allowNew: true })
public async postProject(@Body() requestBody: SetterBody<ProjectWithUsers>) {
async function cb(project: IProject) {
if (requestBody.assignees) {
for (const userId of requestBody.assignees) {
await (await User.findOne({ _id: userId }))?.addProjects({ assigned: [project._id] })
}
}
if (requestBody.supervisors) {
for (const userId of requestBody.supervisors) {
await (await User.findOne({ _id: userId }))?.addProjects({ supervised: [project._id] })
}
}
}
return await this.setter(Project, { requestBody: requestBody, allowNew: true, cb })
}
@Post('bulk')
public async postManyProjects(@Body() requestBody: SetterBody<IProject>[]) {
Expand Down
Loading

0 comments on commit 105f800

Please sign in to comment.