Spaces:
Runtime error
Runtime error
| import { Controller, Get, Query, BadRequestException } from '@nestjs/common'; | |
| import { ApiTags, ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger'; | |
| import { RequireRole, CurrentApiKey } from '../auth/decorators/auth.decorators'; | |
| import { ApiKey, ApiKeyRole } from '../auth/entities/api-key.entity'; | |
| import { SearchService } from './search.service'; | |
| import { SearchQueryDto } from './dto/search-query.dto'; | |
| import type { SearchResults } from './search.types'; | |
| ('search') | |
| ('search') | |
| export class SearchController { | |
| constructor(private readonly searchService: SearchService) {} | |
| () | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Search messages across sessions (active search provider)' }) | |
| ({ status: 200, description: 'Search results from the active provider' }) | |
| ({ status: 400, description: 'Empty or whitespace-only "q"' }) | |
| ({ status: 501, description: 'No search provider configured' }) | |
| ({ name: 'q', required: true, description: 'Search term (required, non-empty)' }) | |
| ({ name: 'sessionId', required: false, description: 'Restrict to a single session' }) | |
| ({ name: 'chatId', required: false, description: 'Restrict to a single chat id' }) | |
| ({ name: 'direction', required: false, description: 'incoming | outgoing' }) | |
| ({ name: 'type', required: false, description: 'Message type filter' }) | |
| ({ name: 'from', required: false, description: 'Sender filter' }) | |
| ({ name: 'dateFrom', required: false, description: 'Epoch-ms lower bound (inclusive)' }) | |
| ({ name: 'dateTo', required: false, description: 'Epoch-ms upper bound (inclusive)' }) | |
| ({ name: 'limit', required: false, type: Number, description: 'Max hits to return' }) | |
| ({ name: 'offset', required: false, type: Number, description: 'Pagination offset' }) | |
| async search(() dto: SearchQueryDto, () apiKey?: ApiKey): Promise<SearchResults> { | |
| if (!dto.q || !dto.q.trim()) { | |
| throw new BadRequestException('Query parameter "q" is required and must be non-empty.'); | |
| } | |
| // callerSessionIds comes ONLY from the authenticated key's allowedSessions — never from the | |
| // query/body — so a scoped key cannot broaden its reach. A null/empty allowlist (e.g. ADMIN) | |
| // resolves to undefined → searches all sessions, mirroring GET /webhooks. The DTO carries no | |
| // `sessionIds` field (the global ValidationPipe's forbidNonWhitelisted would reject it anyway), | |
| // and SearchService makes scope authoritative by overwriting sessionIds at the provider boundary. | |
| return this.searchService.search(dto, apiKey?.allowedSessions ?? undefined); | |
| } | |
| } | |