Add issue attachments
- IssueAttachment link table (issue <-> file) + migration - GET/POST /issues/:issueId/attachments, DELETE .../attachments/:fileId - Only own uploaded files can be attached; attach is idempotent - Registers issues as a file owner: attached files stay visible to issue participants and are not collected by GC - IssueDetail.attachments GraphQL field via @ResolveField, issue module untouched Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f32c6e348d
commit
423afa658d
28 files changed
+828
-16
No files matched your search
+24
@@ -0,0 +1,24 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { IssueAttachment } from '../../domain/entities/issue-attachment.entity.js';
|
||||
import { IssueAttachmentDto } from '../dto/issue-attachment.dto.js';
|
||||
import { GetFilesUseCase } from '../../../file/application/use-cases/get-files/get-files.use-case.js';
|
||||
import { GetFilesQuery } from '../../../file/application/use-cases/get-files/get-files.query.js';
|
||||
|
||||
/** Раскрывает вложения в метаданные файлов из file-модуля */
|
||||
@Injectable()
|
||||
export class IssueAttachmentExpanderService {
|
||||
constructor(private readonly getFilesUseCase: GetFilesUseCase) {}
|
||||
|
||||
async expandAll(attachments: IssueAttachment[]): Promise<IssueAttachmentDto[]> {
|
||||
if (attachments.length === 0) return [];
|
||||
|
||||
const files = await this.getFilesUseCase.execute(new GetFilesQuery(attachments.map((a) => a.fileId)));
|
||||
const filesById = new Map(files.map((file) => [file.id, file]));
|
||||
|
||||
// Файл могли удалить между запросами — такое вложение просто не показываем
|
||||
return attachments.flatMap((attachment) => {
|
||||
const file = filesById.get(attachment.fileId);
|
||||
return file ? [{ issueId: attachment.issueId, file, attachedAt: attachment.createdAt }] : [];
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user