Commit 7ff1bbe8 authored by Martin Mechtel's avatar Martin Mechtel
Browse files

Merge branch 'main-data' into 'main'

Dev of main data is complete

See merge request !1
parents f3be6095 e52a8a88
......@@ -5,6 +5,8 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/personaldb/dist" />
<excludeFolder url="file://$MODULE_DIR$/personaldb/tmp" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
......
......@@ -12,7 +12,7 @@ export class IsAdminGuard implements CanActivate {
) {
const req = context.switchToHttp().getRequest();
const userId = req.user.id;
const isAdmin = await this.authService.isAdminUser(userId);
const isAdmin = await this.authService.isAppAdminUser(userId);
if (!isAdmin) {
throw new UnauthorizedException();
}
......
......@@ -37,12 +37,8 @@ export class AppController {
type: AuthDataDto,
})
@ApiTags('auth')
async findCanDos(@UserId() userId: number, @UserName() userName: string): Promise<AuthDataDto> {
return <AuthDataDto>{
userId: userId,
userName: userName,
isAppAdmin: await this.authService.isAdminUser(userId)
}
async findCanDos(@UserId() userId: number): Promise<AuthDataDto> {
return await this.authService.getCanDos(userId)
}
@Patch('password')
......
import { Injectable } from '@nestjs/common';
import {JwtService} from "@nestjs/jwt";
import {UsersService} from "../../database/services/users.service";
import {AuthDataDto} from "../../../../../../libs/dto/src";
@Injectable()
export class AuthService {
......@@ -18,9 +19,23 @@ export class AuthService {
return this.jwtService.sign(payload);
}
async isAdminUser(userId: number): Promise<boolean> {
const isAdmin = await this.usersService.getUserIsAppAdmin(userId);
return isAdmin ? isAdmin : false;
async isAppAdminUser(userId: number): Promise<boolean> {
const canDos = await this.usersService.getCanDos(userId);
return canDos ? canDos.isAppAdmin : false;
}
async isPersonalAdminUser(userId: number): Promise<boolean> {
const canDos = await this.usersService.getCanDos(userId);
return canDos ? canDos.isPersonalAdmin : false;
}
async isCmsAdminUser(userId: number): Promise<boolean> {
const canDos = await this.usersService.getCanDos(userId);
return canDos ? canDos.isCmsAdmin : false;
}
async getCanDos(userId: number): Promise<AuthDataDto> {
return await this.usersService.getCanDos(userId);
}
async getMyName(id: number): Promise<string> {
......
......@@ -6,12 +6,15 @@ import Config from "./entities/config.entity";
import {ConfigService} from "./services/config.service";
import Staff from "./entities/staff-member.entity";
import {StaffService} from "./services/staff.service";
import Principal from "./entities/principal.entity";
import {PrincipalService} from "./services/principal.service";
@Module({
imports: [
User,
Config,
Staff,
Principal,
TypeOrmModule.forRootAsync({
useFactory: () => ({
"type": "postgres",
......@@ -20,25 +23,28 @@ import {StaffService} from "./services/staff.service";
"username": process.env.POSTGRES_USER,
"password": process.env.POSTGRES_PASSWORD,
"database": process.env.POSTGRES_DB,
"entities": [User, Config, Staff],
"entities": [User, Config, Staff, Principal],
"synchronize": false
})
}
),
TypeOrmModule.forFeature([User, Config, Staff])
TypeOrmModule.forFeature([User, Config, Staff, Principal])
],
providers: [
UsersService,
StaffService,
ConfigService
ConfigService,
PrincipalService
],
exports: [
User,
Config,
Staff,
Principal,
UsersService,
StaffService,
ConfigService
ConfigService,
PrincipalService
]
})
export class DatabaseModule {}
import {Entity, PrimaryColumn} from 'typeorm';
@Entity()
class Principal {
@PrimaryColumn()
public id: number;
@PrimaryColumn({
name: 'sub_id'
})
public subId: number;
}
export default Principal;
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import {StaffMemberMetadataDto} from "../../../../../../libs/dto/src";
import {StaffMemberVacationDataDto} from "@lib/dto";
@Entity()
class Staff {
......@@ -14,16 +14,30 @@ class Staff {
})
public firstName: string;
@Column()
public address: string | null;
@Column({
name: 'idm_id'
})
public idmId: string;
@Column({
name: 'cn'
name: 'idm_registered'
})
public canonicalName: string | null;
public idmRegistered: string;
@Column()
public address: string | null;
@Column()
public title: string | null;
@Column()
public salutation: string | null;
public sex: string | null;
@Column({
type: 'date',
name: 'date_of_birth'
})
dateOfBirth: string | null;
@Column({
name: 'contract_type'
......@@ -43,17 +57,23 @@ class Staff {
contractEnd: string | null;
@Column({
name: 'contract_week_days'
})
contractWeekDays: string | null;
@Column({
name: 'vacation_data',
type: 'jsonb',
array: false,
default: () => "'{}'",
nullable: false,
})
public metadata: StaffMemberMetadataDto;
public vacationData: StaffMemberVacationDataDto;
@Column({
name: 'payroll_number'
name: 'payroll_id'
})
public payrollNumber: string | null;
public payrollId: string | null;
}
export default Staff;
import { Test, TestingModule } from '@nestjs/testing';
import { PrincipalService } from './principal.service';
describe('PrincipalService', () => {
let service: PrincipalService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PrincipalService],
}).compile();
service = module.get<PrincipalService>(PrincipalService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { Injectable } from '@nestjs/common';
import {InjectRepository} from "@nestjs/typeorm";
import {Repository} from "typeorm";
import Principal from "../entities/principal.entity";
import {PrincipalRelationDto} from "@lib/dto";
@Injectable()
export class PrincipalService {
constructor(
@InjectRepository(Principal)
private principalRepository: Repository<Principal>,
) {}
async findAllPrincipals(subId: number): Promise<PrincipalRelationDto[]> {
const principalData = await this.principalRepository.createQueryBuilder('principal')
.where(`principal.sub_id = ${subId}`)
.innerJoinAndSelect('staff', 'staff', 'principal.id = staff.id')
.select(['staff.id as id', 'staff.name as name', 'staff.first_name as first_name'])
.execute();
const returnPrincipals: PrincipalRelationDto[] = [];
principalData.forEach(principal => {
returnPrincipals.push(<PrincipalRelationDto>{
id: principal.id,
name: principal.name,
firstName: principal.first_name
})
});
return returnPrincipals;
}
async findAllSubs(id: number): Promise<PrincipalRelationDto[]> {
const principalData = await this.principalRepository.createQueryBuilder('principal')
.where(`principal.id = ${id}`)
.innerJoinAndSelect('staff', 'staff', 'principal.sub_id = staff.id')
.select(['staff.id as id', 'staff.name as name', 'staff.first_name as first_name'])
.execute();
const returnPrincipals: PrincipalRelationDto[] = [];
principalData.forEach(principal => {
returnPrincipals.push(<PrincipalRelationDto>{
id: principal.id,
name: principal.name,
firstName: principal.first_name
})
});
return returnPrincipals;
}
async create(id: number, subId: number): Promise<void> {
const principalToCreate = await this.principalRepository.findOne({
where: {id: id, subId: subId}
});
if (!principalToCreate) {
await this.principalRepository.createQueryBuilder()
.insert()
.values([
{ id: id, subId: subId }
])
.execute();
}
}
async remove(id: number, subId: number): Promise<void> {
await this.principalRepository.createQueryBuilder()
.where('subId = :subId', {subId})
.andWhere('id = :id', {id})
.delete()
.execute();
}
}
import { Injectable } from '@nestjs/common';
import {Injectable, NotFoundException} from '@nestjs/common';
import {InjectRepository} from "@nestjs/typeorm";
import {Repository} from "typeorm";
import Staff from "../entities/staff-member.entity";
import {StaffMemberInListDto, UserInListDto} from "../../../../../../libs/dto/src";
import {StaffMemberCreateDto, StaffMemberInListDto, StaffMemberMainDto} from "@lib/dto";
import {PrincipalService} from "./principal.service";
@Injectable()
export class StaffService {
constructor(
@InjectRepository(Staff)
private staffRepository: Repository<Staff>,
private principalService: PrincipalService,
) {}
async findAll(): Promise<StaffMemberInListDto[]> {
const staffMembers: Staff[] = await this.staffRepository.find({order: {name: 'ASC'}});
const staffMembers: Staff[] = await this.staffRepository.find({
order: {
name: 'ASC',
firstName: 'ASC'
}
});
const returnStaff: StaffMemberInListDto[] = [];
staffMembers.forEach(staffMember => {
returnStaff.push(<StaffMemberInListDto>{
id: staffMember.id,
name: staffMember.name,
firstName: staffMember.firstName,
canonicalName: staffMember.canonicalName,
contractStart: staffMember.contractStart,
contractEnd: staffMember.contractEnd,
contractType: staffMember.contractType
idmId: staffMember.idmId
})
});
return returnStaff;
}
async findOneMain(id: number): Promise<StaffMemberMainDto> {
const staffMember = await this.staffRepository.findOne(id);
if (staffMember) {
return <StaffMemberMainDto>{
id: staffMember.id,
name: staffMember.name,
firstName: staffMember.firstName,
sex: staffMember.sex,
title: staffMember.title,
contractStart: staffMember.contractStart,
contractEnd: staffMember.contractEnd,
contractType: staffMember.contractType,
contractWeekDays: staffMember.contractWeekDays,
payrollId: staffMember.payrollId,
idmId: staffMember.idmId,
idmRegistered: staffMember.idmRegistered,
address: staffMember.address,
dateOfBirth: staffMember.dateOfBirth,
principals: await this.principalService.findAllPrincipals(staffMember.id),
subs: await this.principalService.findAllSubs(staffMember.id)
}
} else {
throw new NotFoundException();
}
}
async patchMain(newStaffMemberMainData: StaffMemberMainDto): Promise<void> {
const staffMember = await this.staffRepository.findOne(newStaffMemberMainData.id);
if (staffMember) {
if (newStaffMemberMainData.hasOwnProperty('name')) staffMember.name = newStaffMemberMainData.name;
if (newStaffMemberMainData.hasOwnProperty('firstName')) staffMember.firstName = newStaffMemberMainData.firstName;
if (newStaffMemberMainData.hasOwnProperty('title')) staffMember.title = newStaffMemberMainData.title;
if (newStaffMemberMainData.hasOwnProperty('address')) staffMember.address = newStaffMemberMainData.address;
if (newStaffMemberMainData.hasOwnProperty('sex')) staffMember.sex = newStaffMemberMainData.sex;
if (newStaffMemberMainData.hasOwnProperty('contractType')) staffMember.contractType = newStaffMemberMainData.contractType;
if (newStaffMemberMainData.hasOwnProperty('contractStart')) staffMember.contractStart = newStaffMemberMainData.contractStart ? newStaffMemberMainData.contractStart : null;
if (newStaffMemberMainData.hasOwnProperty('contractEnd')) staffMember.contractEnd = newStaffMemberMainData.contractEnd ? newStaffMemberMainData.contractEnd : null;
if (newStaffMemberMainData.hasOwnProperty('contractWeekDays')) staffMember.contractWeekDays = newStaffMemberMainData.contractWeekDays;
if (newStaffMemberMainData.hasOwnProperty('dateOfBirth')) staffMember.dateOfBirth = newStaffMemberMainData.dateOfBirth ? newStaffMemberMainData.dateOfBirth : null;
if (newStaffMemberMainData.hasOwnProperty('payrollId')) staffMember.payrollId = newStaffMemberMainData.payrollId;
await this.staffRepository.save(staffMember);
}
}
async create(newStaffMemberData: StaffMemberCreateDto): Promise<number> {
const newStaffMember = await this.staffRepository.create(newStaffMemberData);
await this.staffRepository.save(newStaffMember);
return newStaffMember.id;
}
}
......@@ -4,7 +4,7 @@ import {InjectRepository} from "@nestjs/typeorm";
import User from "../entities/user.entity";
import * as bcrypt from 'bcrypt';
import {passwordHash} from "../../auth/auth.constants";
import {CreateUserDto, UserFullDto, UserInListDto} from "../../../../../../libs/dto/src";
import {AuthDataDto, CreateUserDto, UserFullDto, UserInListDto} from "../../../../../../libs/dto/src";
@Injectable()
export class UsersService {
......@@ -61,7 +61,7 @@ export class UsersService {
return null
}
async getUserIsAppAdmin(userId: number): Promise<boolean | null> {
async getCanDos(userId: number): Promise<AuthDataDto | null> {
const user = await getConnection()
.getRepository(User)
.createQueryBuilder("user")
......@@ -69,7 +69,13 @@ export class UsersService {
{id: userId})
.getOne();
if (user) {
return user.isAppAdmin
return <AuthDataDto>{
userId: userId,
userName: user.name,
isAppAdmin: user.isAppAdmin,
isPersonalAdmin: user.isPersonalAdmin,
isCmsAdmin: user.isCmsAdmin
}
}
return null
}
......
import {Controller, Get, UseGuards} from '@nestjs/common';
import {Body, Controller, Delete, Get, Param, Patch, Post, UseGuards} from '@nestjs/common';
import {JwtAuthGuard} from "../auth/jwt-auth.guard";
import {IsAdminGuard} from "../app-admin/is-admin.guard";
import {ApiBearerAuth, ApiCreatedResponse, ApiTags} from "@nestjs/swagger";
import {StaffMemberInListDto, UserInListDto} from "../../../../../libs/dto/src";
import {PrincipalRelationDto, StaffMemberCreateDto, StaffMemberInListDto, StaffMemberMainDto} from "@lib/dto";
import {StaffService} from "../database/services/staff.service";
import {PrincipalService} from "../database/services/principal.service";
@Controller('staff')
export class StaffController {
constructor(
private staffService: StaffService
private staffService: StaffService,
private principalService: PrincipalService
) {}
@Get()
......@@ -22,4 +23,72 @@ export class StaffController {
return this.staffService.findAll();
}
@Get(':id/main')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiCreatedResponse({
type: StaffMemberMainDto,
})
@ApiTags('staff')
async findOneMain(@Param('id') id: number): Promise<StaffMemberMainDto> {
return this.staffService.findOneMain(id);
}
@Patch(':id/main')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiTags('staff')
async patchMain(@Body() staffMemberFullDto: StaffMemberMainDto) {
return this.staffService.patchMain(staffMemberFullDto)
}
@Post()
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiCreatedResponse({
description: 'Sends back the id of the new staff member in database',
type: Number,
})
@ApiTags('staff')
async create(@Body() staffMemberCreateDto: StaffMemberCreateDto) {
return this.staffService.create(staffMemberCreateDto)
}
@Get(':id/principals')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiCreatedResponse({
type: [PrincipalRelationDto],
})
@ApiTags('staff')
async findOnesPrincipals(@Param('id') id: number): Promise<PrincipalRelationDto[]> {
return this.principalService.findAllPrincipals(id);
}
@Get(':id/subs')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiCreatedResponse({
type: [PrincipalRelationDto],
})
@ApiTags('staff')
async findOnesSubs(@Param('id') id: number): Promise<PrincipalRelationDto[]> {
return this.principalService.findAllSubs(id);
}
@Post(':subId/principals/:id')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiTags('staff')
async createPrincipal(@Param('subId') subId: number, @Param('id') id: number) {
return this.principalService.create(id, subId);
}
@Delete(':subId/principals/:id')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiTags('staff')
async remove(@Param('subId') subId: number, @Param('id') id: number): Promise<void> {
return this.principalService.remove(id, subId);
}
}
......@@ -15,7 +15,6 @@ import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MAT_DATE_LOCALE, MatNativeDateModule } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatBadgeModule } from '@angular/material/badge';
import { FlexLayoutModule } from '@angular/flex-layout';
......@@ -31,7 +30,7 @@ import { AppConfigComponent } from './settings/app-config.component';
import {HTTP_INTERCEPTORS} from "@angular/common/http";
import {AuthInterceptor} from "./auth.interceptor";
import {EditUserComponent} from "./users/edituser.component";
import {IqbComponentsModule} from "../../../../../libs/iqb-components/src";
import {IqbComponentsModule} from "@lib/iqb-components";
@NgModule({
imports: [
......@@ -54,7 +53,6 @@ import {IqbComponentsModule} from "../../../../../libs/iqb-components/src";
MatInputModule,
MatToolbarModule,
MatSnackBarModule,
MatNativeDateModule,
MatDatepickerModule,
MatBadgeModule,
FlexLayoutModule,
......@@ -73,17 +71,14 @@ import {IqbComponentsModule} from "../../../../../libs/iqb-components/src";
],
providers: [
BackendService,
[
{ provide: MAT_DATE_LOCALE, useValue: 'de-DE' },
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
],
entryComponents: [
EditUserComponent
]
})
export class AdminModule { }
export class AppAdminModule { }
......@@ -2,7 +2,7 @@ import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {Observable, of, throwError} from 'rxjs';
import {catchError, map} from 'rxjs/operators';
import {ConfigFullDto, CreateUserDto, UserFullDto, UserInListDto} from "../../../../../libs/dto/src";
import {ConfigFullDto, CreateUserDto, UserFullDto, UserInListDto} from "@lib/dto";
@Injectable({
providedIn: 'root'
......
export { AdminComponent } from './admin.component';
export { AdminModule } from './admin.module';
export { AppAdminModule } from './app-admin.module';
......@@ -4,7 +4,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs';
import {BackendService} from "../backend.service";