server: add user decorator, add ping module

This commit is contained in:
Roland Schneider
2025-12-12 08:20:32 +01:00
parent 453d02612c
commit 57edf5b4a8
9 changed files with 90 additions and 3 deletions

View File

@@ -9,6 +9,11 @@ Content-Type: application/json
> {% client.global.set("auth_token", response.body.accessToken); %}
### GET request with parameter
GET {{apiBaseUrl}}/ping/auth
Accept: application/json
Authorization: Bearer {{auth_token}}
### GET request with parameter
GET {{apiBaseUrl}}/users
Accept: application/json

View File

@@ -24,6 +24,7 @@ import { EventExceptionsModule } from './event-exception/event-exceptions.module
import { CalendarModule } from './calendar/calendar.module';
import { Booking } from './entity/booking.entity';
import { BookingsModule } from './booking/bookings.module';
import { PingModule } from './ping/ping.module';
const moduleTypeOrm = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
@@ -69,6 +70,7 @@ const moduleTypeOrm = TypeOrmModule.forRootAsync({
EventExceptionsModule,
CalendarModule,
BookingsModule,
PingModule,
],
controllers: [AppController],
providers: [AppService],

View File

@@ -0,0 +1,23 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import express from 'express';
import { AppUser, UserPayload } from '../types';
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request: express.Request = ctx.switchToHttp().getRequest();
const user: UserPayload = request.user as UserPayload;
let result: AppUser;
if (user) {
result = {
anonymous: false,
user: user,
};
} else {
result = {
anonymous: true,
user: undefined,
};
}
return result;
},
);

View File

@@ -22,6 +22,8 @@ import { Role } from '../auth/role.enum';
import { CalendarCreateBookingDto } from './dto/create-booking.dto';
import { CancelBookingDto } from './dto/cancel-booking.dto';
import { ApiBody } from '@nestjs/swagger';
import { User } from '../auth/user.decorator';
import * as types from '../types';
@Controller('calendar')
@UseGuards(JwtAuthGuard, RolesGuard)
@@ -77,9 +79,11 @@ export class CalendarController {
@Post('events/:id/bookings')
@ApiBody({ type: CalendarCreateBookingDto })
createBooking(
@User() user: types.AppUser,
@Param('id', ParseIntPipe) eventId: number,
@Body(new ValidationPipe()) createBookingDto: CalendarCreateBookingDto,
) {
console.info('user user', user);
return this.calendarService.createBooking(eventId, createBookingDto);
}

View File

@@ -16,6 +16,7 @@ export class CalendarCreateBookingDto {
@ApiProperty()
occurrenceStartTime: Date;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty()

View File

@@ -15,9 +15,24 @@ async function bootstrap() {
.setDescription('The DV Booking API description')
.setVersion('1.0')
.addTag('dvbooking')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
name: 'JWT',
description: 'Enter JWT token',
in: 'header',
},
'bearer',
)
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
SwaggerModule.setup('api', app, document, {
swaggerOptions: {
security: [{ bearer: [] }],
},
});
app.useGlobalPipes(
new ValidationPipe({

View File

@@ -0,0 +1,20 @@
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../auth/roles.guard';
import { User } from '../auth/user.decorator';
import * as types from '../types';
@Controller('ping')
export class PingController {
@Get()
ping() {
return 'pong';
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Get('auth')
pingAuth(@User() user: types.AppUser) {
console.info('user', user);
return 'pong';
}
}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { PingController } from './ping.controller';
@Module({
controllers: [PingController],
})
export class PingModule {}

View File

@@ -1,5 +1,4 @@
export interface LoginRequest{
export interface LoginRequest {
username: string;
password: string;
}
@@ -8,3 +7,14 @@ export interface LoginResponse {
accessToken: string;
refreshToken: string;
}
export interface AppUser {
anonymous: boolean;
user: UserPayload | undefined;
}
export interface UserPayload {
userId: number;
username: string;
roles: string[];
}