feat(chat,board): file/image attachments on chat, board threads and comments
チャット・掲示板(スレッド/コメント)へファイル/画像添付を追加。 - lib/db/migrations/002_attachments.sql: attachments テーブル + file_assets.source 列 - repositories/AttachmentRepository + services/AttachmentService: 添付紐付け(プロジェクト/アップロード者チェック) - FileStorageService.uploadForAttachment: 通知/SSE/アクティビティを行わない添付専用アップロード(source='attachment') - ChatService/BoardService: fileIds 受理・添付紐付け・履歴/詳細表示・削除クリーンアップ(トランザクション) - API: POST /attachments + chat/board の fileIds 受理 - UI: AttachmentList(画像サムネイル+Lightbox/ダウンロード) + AttachmentPicker(複数アップロード・送信中は送信不可) をチャット/スレッド/コメントに統合 - 添付ファイルは既存の /api/files/[fileId]/download(権限チェック済)で配信
This commit is contained in:
@ -157,4 +157,49 @@ describe('FileStorageService', () => {
|
||||
service.delete(authorId, file.id); // authorId is admin
|
||||
expect(() => service.getFileInfo(memberId, file.id)).toThrow();
|
||||
});
|
||||
|
||||
it('uploadForAttachment is silent: no notification/SSE/activity, source=attachment', () => {
|
||||
const file = service.uploadForAttachment(authorId, projectId, {
|
||||
originalName: 'pic.png',
|
||||
mimeType: 'image/png',
|
||||
data: Buffer.from('img'),
|
||||
});
|
||||
expect(file.source).toBe('attachment');
|
||||
expect(fs.existsSync(file.path)).toBe(true);
|
||||
// メンバーへの file_shared 通知は飛ばない
|
||||
expect(new NotificationRepository(db).countUnreadByUser(memberId)).toBe(0);
|
||||
// file_uploaded アクティビティは記録されない
|
||||
expect(
|
||||
new ActivityLogRepository(db)
|
||||
.findByProject(projectId)
|
||||
.items.some((l) => l.action === 'file_uploaded')
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('uploadForAttachment result is excluded from the library list', () => {
|
||||
service.uploadForAttachment(authorId, projectId, {
|
||||
originalName: 'pic.png',
|
||||
mimeType: 'image/png',
|
||||
data: Buffer.from('img'),
|
||||
});
|
||||
const list = service.listFiles(authorId, projectId);
|
||||
expect(list.total).toBe(0);
|
||||
});
|
||||
|
||||
it('uploadForAttachment still enforces MIME and membership', () => {
|
||||
expect(() =>
|
||||
service.uploadForAttachment(authorId, projectId, {
|
||||
originalName: 'evil.exe',
|
||||
mimeType: 'application/x-msdownload',
|
||||
data: Buffer.from('x'),
|
||||
})
|
||||
).toThrow(ValidationError);
|
||||
expect(() =>
|
||||
service.uploadForAttachment(outsiderId, projectId, {
|
||||
originalName: 'x.png',
|
||||
mimeType: 'image/png',
|
||||
data: Buffer.from('x'),
|
||||
})
|
||||
).toThrow(ForbiddenError);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user