File

src/client-portal/client-portal.controller.ts

Prefix

client-portal

Index

Methods

Methods

Async createToken
createToken(orgId: string, userId: string, dto: CreatePortalTokenDto)
Decorators :
@Post('tokens')
@ApiBearerAuth()
@UseGuards(CombinedAuthGuard, RolesGuard)
@Roles('DISPATCHER', 'OPERATIONS_MANAGER', 'ADMIN', 'SUPER_ADMIN', 'PLANNER', 'CUSTOMER_SERVICE')
@ApiOperation({summary: 'Generate a new portal link + API key for a client'})
Parameters :
Name Type Optional
orgId string No
userId string No
dto CreatePortalTokenDto No
Returns : unknown
Async listTokens
listTokens(clientId: string)
Decorators :
@Get('tokens')
@ApiBearerAuth()
@UseGuards(CombinedAuthGuard, RolesGuard)
@Roles('DISPATCHER', 'OPERATIONS_MANAGER', 'ADMIN', 'SUPER_ADMIN', 'PLANNER', 'CUSTOMER_SERVICE')
@ApiOperation({summary: 'List portal tokens for a client'})
Parameters :
Name Type Optional
clientId string No
Returns : unknown
Async resolve
resolve(token: string)
Decorators :
@Get('resolve/:token')
@Throttle({short: undefined})
@ApiOperation({summary: 'Resolve a portal token → returns client info for the form'})
Parameters :
Name Type Optional
token string No
Returns : unknown
Async revokeToken
revokeToken(id: string)
Decorators :
@Delete('tokens/:id')
@ApiBearerAuth()
@UseGuards(CombinedAuthGuard, RolesGuard)
@Roles('DISPATCHER', 'OPERATIONS_MANAGER', 'ADMIN', 'SUPER_ADMIN')
@ApiOperation({summary: 'Revoke a portal token + API key'})
Parameters :
Name Type Optional
id string No
Returns : unknown
Async submit
submit(token: string, dto: SubmitPortalOrderDto, req: any)
Decorators :
@Post('submit/:token')
@Throttle({short: undefined, medium: undefined})
@ApiOperation({summary: 'Submit an order via portal link (no auth)'})
Parameters :
Name Type Optional
token string No
dto SubmitPortalOrderDto No
req any No
Returns : unknown
Async submitFile
submitFile(token: string, file: Express.Multer.File, req: any)
Decorators :
@Post('submit/:token/file')
@Throttle({short: undefined, medium: undefined})
@UseInterceptors(undefined)
@ApiConsumes('multipart/form-data')
@ApiOperation({summary: 'Upload an Excel/CSV file via portal link — parses all rows into orders'})
Parameters :
Name Type Optional
token string No
file Express.Multer.File No
req any No
Returns : unknown
Async submitViaApiKey
submitViaApiKey(apiKey: string, dto: SubmitPortalOrderDto, req: any)
Decorators :
@Post('api/orders')
@Throttle({short: undefined, medium: undefined})
@ApiOperation({summary: 'Submit an order via API key (X-Client-Key header)'})
Parameters :
Name Type Optional
apiKey string No
dto SubmitPortalOrderDto No
req any No
Returns : unknown
import {
  Controller,
  Get,
  Post,
  Delete,
  Body,
  Param,
  Query,
  Req,
  UseGuards,
  UseInterceptors,
  UploadedFile,
  Headers,
  UnauthorizedException,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { Throttle } from '@nestjs/throttler';
import { ApiTags, ApiBearerAuth, ApiOperation, ApiConsumes } from '@nestjs/swagger';
import { ClientPortalService } from './client-portal.service';
import { CreatePortalTokenDto, SubmitPortalOrderDto } from './dto/create-portal-token.dto';
import { CombinedAuthGuard } from '../auth/guards/combined-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { CurrentUser } from '../auth/decorators/current-user.decorator';

@ApiTags('Client Portal')
@Controller('client-portal')
export class ClientPortalController {
  constructor(private readonly service: ClientPortalService) {}

  // ── DISPATCHER ENDPOINTS (authenticated) ──────────────────────────────

  @Post('tokens')
  @ApiBearerAuth()
  @UseGuards(CombinedAuthGuard, RolesGuard)
  @Roles('DISPATCHER', 'OPERATIONS_MANAGER', 'ADMIN', 'SUPER_ADMIN', 'PLANNER', 'CUSTOMER_SERVICE')
  @ApiOperation({ summary: 'Generate a new portal link + API key for a client' })
  async createToken(
    @CurrentUser('organizationId') orgId: string,
    @CurrentUser('id') userId: string,
    @Body() dto: CreatePortalTokenDto,
  ) {
    return this.service.createToken(orgId, userId, dto);
  }

  @Get('tokens')
  @ApiBearerAuth()
  @UseGuards(CombinedAuthGuard, RolesGuard)
  @Roles('DISPATCHER', 'OPERATIONS_MANAGER', 'ADMIN', 'SUPER_ADMIN', 'PLANNER', 'CUSTOMER_SERVICE')
  @ApiOperation({ summary: 'List portal tokens for a client' })
  async listTokens(@Query('clientId') clientId: string) {
    return this.service.listTokens(clientId);
  }

  @Delete('tokens/:id')
  @ApiBearerAuth()
  @UseGuards(CombinedAuthGuard, RolesGuard)
  @Roles('DISPATCHER', 'OPERATIONS_MANAGER', 'ADMIN', 'SUPER_ADMIN')
  @ApiOperation({ summary: 'Revoke a portal token + API key' })
  async revokeToken(@Param('id') id: string) {
    return this.service.revokeToken(id);
  }

  // ── PUBLIC ENDPOINTS (no auth — token IS the credential) ─────────────

  @Get('resolve/:token')
  @Throttle({ short: { ttl: 60000, limit: 30 } })
  @ApiOperation({ summary: 'Resolve a portal token → returns client info for the form' })
  async resolve(@Param('token') token: string) {
    return this.service.resolveToken(token);
  }

  @Post('submit/:token')
  @Throttle({ short: { ttl: 60000, limit: 10 }, medium: { ttl: 3600000, limit: 100 } })
  @ApiOperation({ summary: 'Submit an order via portal link (no auth)' })
  async submit(
    @Param('token') token: string,
    @Body() dto: SubmitPortalOrderDto,
    @Req() req: any,
  ) {
    const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown';
    const userAgent = req.headers['user-agent'];
    return this.service.submitOrderByToken(token, dto, ip, userAgent);
  }

  @Post('submit/:token/file')
  @Throttle({ short: { ttl: 60000, limit: 5 }, medium: { ttl: 3600000, limit: 30 } })
  @UseInterceptors(
    FileInterceptor('file', {
      limits: { fileSize: 15 * 1024 * 1024 }, // 15 MB
    }),
  )
  @ApiConsumes('multipart/form-data')
  @ApiOperation({
    summary: 'Upload an Excel/CSV file via portal link — parses all rows into orders',
  })
  async submitFile(
    @Param('token') token: string,
    @UploadedFile() file: Express.Multer.File,
    @Req() req: any,
  ) {
    const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown';
    const userAgent = req.headers['user-agent'];
    return this.service.submitFileByToken(token, file, ip, userAgent);
  }

  // ── PUBLIC API-KEY endpoint (for client ERPs) ────────────────────────

  @Post('api/orders')
  @Throttle({ short: { ttl: 60000, limit: 60 }, medium: { ttl: 3600000, limit: 1000 } })
  @ApiOperation({ summary: 'Submit an order via API key (X-Client-Key header)' })
  async submitViaApiKey(
    @Headers('x-client-key') apiKey: string,
    @Body() dto: SubmitPortalOrderDto,
    @Req() req: any,
  ) {
    if (!apiKey) throw new UnauthorizedException('X-Client-Key header required');
    const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown';
    const userAgent = req.headers['user-agent'];
    return this.service.submitOrderByApiKey(apiKey, dto, ip, userAgent);
  }
}

results matching ""

    No results matching ""