// apps/box-app-api/src/feature/ads/ad.controller.ts import { Controller, Get, Logger, Query, Post, Body, Param, UseGuards, Req, NotFoundException, UnauthorizedException, } from '@nestjs/common'; import { ApiOperation, ApiResponse, ApiTags, ApiBearerAuth, } from '@nestjs/swagger'; import { Request } from 'express'; import { AdService } from './ad.service'; import { GetAdPlacementQueryDto } from './dto/get-ad-placement.dto'; import { AdDto } from './dto/ad.dto'; import { AdListRequestDto, AdListResponseDto, AdClickDto, AdImpressionDto, AllAdsResponseDto, } from './dto'; import { AdUrlResponseDto } from './dto/ad-url-response.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; // Extend Express Request to include user from JWT interface JwtUser { uid: string; sub: string; jti: string; } interface RequestWithUser extends Request { user: JwtUser; } @ApiTags('广告') @Controller('ads') export class AdController { private readonly logger = new Logger(AdController.name); constructor(private readonly adService: AdService) {} /** * POST /api/v1/ads/list * * List ads by type with pagination. * Request body contains page, size, and adType. * Returns paginated list of ads with metadata. */ @Post('list') @ApiOperation({ summary: '获取所有广告类型及广告列表', description: '获取所有广告类型(从系统参数)以及按广告类型分组的广告列表。支持分页。数据来源:Mongo Ads 模型 + 系统参数。', }) @ApiResponse({ status: 200, description: '成功返回所有广告类型和分组广告列表', type: AllAdsResponseDto, }) async listAdsByType(@Body() req: AdListRequestDto): Promise { const { page, size } = req; this.logger.debug(`listAdsByType: page=${page}, size=${size}`); const response = await this.adService.listAdsByType(page, size); return response; } private getClientIp(req: Request): string { return ( (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() || (req.headers['x-real-ip'] as string) || req.ip || req.socket?.remoteAddress || 'unknown' ); } private getUserAgent(req: Request): string { return (req.headers['user-agent'] as string) || 'unknown'; } }