This commit is contained in:
Jakob Kordež
2023-09-13 16:25:30 +02:00
parent 08a27fb4fc
commit eb29ab1b31
39 changed files with 1081 additions and 191 deletions

View File

@ -1,17 +1,31 @@
import { IsDate, IsOptional, IsString, MinLength } from 'class-validator';
import {
IsBoolean,
IsDateString,
IsOptional,
IsString,
IsUppercase,
Matches,
} from 'class-validator';
export class CreateEventDto {
@IsString()
@MinLength(3)
@IsUppercase()
@Matches(/^[A-Z\d]+\d+[A-Z]+$/, { message: 'Invalid callsign' })
callsign: string;
@IsString()
@IsOptional()
description: string;
@IsDate()
@IsDateString()
@IsOptional()
fromDateTime: Date;
@IsDate()
@IsDateString()
@IsOptional()
toDateTime: Date;
@IsBoolean()
@IsOptional()
isPrivate: boolean;
}

View File

@ -6,6 +6,7 @@ import {
Patch,
Param,
Delete,
BadRequestException,
} from '@nestjs/common';
import { EventsService } from './events.service';
import { CreateEventDto } from './dto/create-event.dto';
@ -14,6 +15,9 @@ import { MongoIdPipe } from 'src/pipes/mongo-id.pipe';
import { Event } from './schemas/event.schema';
import { Roles } from 'src/decorators/roles.decorator';
import { Role } from 'src/enums/role.enum';
import { Public } from 'src/decorators/public.decorator';
import { RequestUser } from 'src/decorators/request-user.decorator';
import { UserTokenData } from 'src/auth/interfaces/user-token-data.interface';
@Controller('events')
export class EventsController {
@ -22,6 +26,11 @@ export class EventsController {
@Roles(Role.Admin)
@Post()
create(@Body() createEventDto: CreateEventDto): Promise<Event> {
const from = createEventDto.fromDateTime;
const to = createEventDto.toDateTime;
if (from && to && from > to)
throw new BadRequestException('fromDateTime must be before toDateTime');
return this.eventsService.create(createEventDto);
}
@ -31,14 +40,21 @@ export class EventsController {
return this.eventsService.findAll();
}
@Get('private')
findPrivate(@RequestUser() user: UserTokenData): Promise<Event[]> {
return this.eventsService.findPrivate(user.id);
}
@Public()
@Get()
findCurrent(): Promise<Event[]> {
return this.eventsService.findCurrent();
}
@Public()
@Get(':id')
findOne(@Param('id', MongoIdPipe) id: string): Promise<Event> {
return this.eventsService.findOne(id);
return this.eventsService.findOne(id, false);
}
@Roles(Role.Admin)
@ -50,6 +66,24 @@ export class EventsController {
return this.eventsService.update(id, updateEventDto);
}
@Roles(Role.Admin)
@Get(':id/grant/:userId')
grantAccess(
@Param('id', MongoIdPipe) id: string,
@Param('userId', MongoIdPipe) userId: string,
): Promise<Event> {
return this.eventsService.grantAccess(id, userId);
}
@Roles(Role.Admin)
@Get(':id/revoke/:userId')
revokeAccess(
@Param('id', MongoIdPipe) id: string,
@Param('userId', MongoIdPipe) userId: string,
): Promise<Event> {
return this.eventsService.revokeAccess(id, userId);
}
@Roles(Role.Admin)
@Delete(':id')
remove(@Param('id', MongoIdPipe) id: string): Promise<Event> {

View File

@ -24,13 +24,42 @@ export class EventsService {
const now = new Date();
return this.eventModel
.find({
$and: [{ fromDateTime: { $lte: now } }, { toDateTime: { $gte: now } }],
$and: [
{
$or: [{ fromDateTime: [null] }, { fromDateTime: { $lte: now } }],
},
{
$or: [{ toDateTime: [null] }, { toDateTime: { $gte: now } }],
},
],
$nor: [{ isDeleted: true }, { isPrivate: true }],
})
.exec();
}
findOne(id: string): Promise<Event> {
return this.eventModel.findById(id).exec();
findPrivate(userId: string): Promise<Event[]> {
const now = new Date();
return this.eventModel
.find({
$and: [
{
$or: [{ fromDateTime: [null] }, { fromDateTime: { $lte: now } }],
},
{
$or: [{ toDateTime: [null] }, { toDateTime: { $gte: now } }],
},
],
$nor: [{ isDeleted: true }],
isPrivate: true,
access: userId,
})
.exec();
}
findOne(id: string, populate: boolean): Promise<Event> {
let q = this.eventModel.findById(id);
if (populate) q = q.populate('access');
return q.exec();
}
update(id: string, updateEventDto: UpdateEventDto): Promise<Event> {
@ -39,6 +68,18 @@ export class EventsService {
.exec();
}
grantAccess(id: string, userId: string): Promise<Event> {
return this.eventModel
.findByIdAndUpdate(id, { $addToSet: { access: userId } }, { new: true })
.exec();
}
revokeAccess(id: string, userId: string): Promise<Event> {
return this.eventModel
.findByIdAndUpdate(id, { $pull: { access: userId } }, { new: true })
.exec();
}
setDeleted(id: string): Promise<Event> {
return this.eventModel
.findByIdAndUpdate(id, { $set: { isDeleted: true } }, { new: true })

View File

@ -19,6 +19,11 @@ export class Event {
@Prop()
toDateTime: Date;
@Prop({
default: false,
})
isPrivate: boolean;
@Prop({
type: [{ type: String, ref: User.name }],
default: [],

View File

@ -3,12 +3,15 @@ import {
IsOptional,
IsPhoneNumber,
IsString,
IsUppercase,
Matches,
MinLength,
} from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(3)
@IsUppercase()
@Matches(/^[A-Z\d]+\d+[A-Z]+$/, { message: 'Invalid callsign' })
username: string;
@IsString()

View File

@ -7,6 +7,8 @@ import {
Param,
Delete,
NotFoundException,
BadRequestException,
ParseArrayPipe,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
@ -24,7 +26,12 @@ export class UsersController {
@Roles(Role.Admin)
@Post()
create(@Body() createUserDto: CreateUserDto): Promise<User> {
async create(@Body() createUserDto: CreateUserDto): Promise<User> {
const exitsting = await this.usersService.findByUsername(
createUserDto.username,
);
if (exitsting) throw new BadRequestException('Username taken');
return this.usersService.create(createUserDto);
}
@ -41,6 +48,7 @@ export class UsersController {
return user;
}
@Roles(Role.Admin)
@Get('search/:username')
findByUsername(@Param('username') username: string): Promise<User> {
const user = this.usersService.findByUsername(username);
@ -48,11 +56,18 @@ export class UsersController {
return user;
}
@Roles(Role.Admin)
@Get(':id')
findOne(@Param('id', MongoIdPipe) id: string): Promise<User> {
return this.usersService.findOne(id);
}
@Roles(Role.Admin)
@Post('many')
findMany(@Body(ParseArrayPipe) ids: string[]): Promise<User[]> {
return this.usersService.findMany(ids);
}
@Roles(Role.Admin)
@Patch(':id')
update(

View File

@ -17,15 +17,21 @@ export class UsersService {
}
findAll(): Promise<User[]> {
return this.userModel.find({ isDeleted: { $in: [false, null] } }).exec();
return this.userModel.find({ $nor: [{ isDeleted: true }] }).exec();
}
findOne(id: string): Promise<User> {
return this.userModel.findById(id).exec();
}
findMany(ids: string[]): Promise<User[]> {
return this.userModel.find({ _id: ids }).exec();
}
findByUsername(username: string): Promise<User> {
return this.userModel.findOne({ username }).exec();
return this.userModel
.findOne({ username, $nor: [{ isDeleted: true }] })
.exec();
}
update(id: string, updateUserDto: UpdateUserDto): Promise<User> {