64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
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<ClassificationTagEntity>,
|
|
) {}
|
|
|
|
@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<string, ClassificationTagEntity[]>();
|
|
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;
|
|
}
|
|
}
|