import { Controller, Get, Query } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { In, Repository } from 'typeorm'; import { CatalogService } from '../catalog/catalog.service'; import { ClassificationTagEntity } from '../entities/classification-tag.entity'; @Controller('discover') export class DiscoveryController { constructor( private readonly catalog: CatalogService, @InjectRepository(ClassificationTagEntity) private readonly tags: Repository, ) {} @Get('changes') async changes(@Query('days') days?: string, @Query('limit') limit?: string) { const daysCount = this.clampDays(days ? Number(days) : 7); const take = limit ? Math.min(Number(limit) || 20, 200) : 20; const since = this.startOfDayOffset(daysCount - 1); let changes = await this.catalog.listChangesSince(since); changes = changes.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); changes = changes.slice(0, take); const itemIds = Array.from(new Set(changes.map((c) => c.itemId).filter(Boolean))); const tags = itemIds.length ? await this.tags.find({ where: { itemId: In(itemIds) } }) : []; const tagsByItem = new Map(); for (const tag of tags) { const list = tagsByItem.get(tag.itemId) || []; list.push(tag); tagsByItem.set(tag.itemId, list); } return changes.map((change) => ({ ...change, tags: this.groupTags(tagsByItem.get(change.itemId) || []), })); } private groupTags(tags: ClassificationTagEntity[]) { return { topics: tags.filter((t) => t.type === 'topic').map((t) => t.value), territories: tags.filter((t) => t.type === 'territory').map((t) => t.value), formats: tags.filter((t) => t.type === 'format').map((t) => t.value), publishers: tags.filter((t) => t.type === 'publisher').map((t) => t.value), }; } private clampDays(value: number) { if (!value || Number.isNaN(value)) return 7; return Math.min(Math.max(value, 1), 90); } private startOfDayOffset(offsetDays: number) { const date = new Date(); date.setHours(0, 0, 0, 0); date.setDate(date.getDate() - offsetDays); return date; } }