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
@@ -0,0 +1,18 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "issue_attachment" (
|
||||
"issueId" INTEGER NOT NULL,
|
||||
"fileId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "issue_attachment_pkey" PRIMARY KEY ("issueId","fileId")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "issue_attachment_fileId_idx" ON "issue_attachment"("fileId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "issue_attachment" ADD CONSTRAINT "issue_attachment_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "issue"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "issue_attachment" ADD CONSTRAINT "issue_attachment_fileId_fkey" FOREIGN KEY ("fileId") REFERENCES "file"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
+33
-16
@@ -81,22 +81,23 @@ model Verification {
|
||||
}
|
||||
|
||||
model Issue {
|
||||
id Int @id @default(autoincrement())
|
||||
key String
|
||||
title String
|
||||
content String?
|
||||
status String
|
||||
priority Int @default(0)
|
||||
assigneeId String?
|
||||
assignee User? @relation(name: "assigneeIssues", fields: [assigneeId], references: [id], onDelete: SetNull)
|
||||
reporterId String?
|
||||
reporter User? @relation(name: "reporterIssues", fields: [reporterId], references: [id], onDelete: SetNull)
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
dueDate DateTime? @db.Timestamptz(3)
|
||||
comments Comment[]
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(3)
|
||||
id Int @id @default(autoincrement())
|
||||
key String
|
||||
title String
|
||||
content String?
|
||||
status String
|
||||
priority Int @default(0)
|
||||
assigneeId String?
|
||||
assignee User? @relation(name: "assigneeIssues", fields: [assigneeId], references: [id], onDelete: SetNull)
|
||||
reporterId String?
|
||||
reporter User? @relation(name: "reporterIssues", fields: [reporterId], references: [id], onDelete: SetNull)
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
dueDate DateTime? @db.Timestamptz(3)
|
||||
comments Comment[]
|
||||
attachments IssueAttachment[]
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(3)
|
||||
|
||||
@@index([status])
|
||||
@@index([assigneeId])
|
||||
@@ -225,8 +226,24 @@ model File {
|
||||
uploader User? @relation(fields: [uploaderId], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
|
||||
issueAttachments IssueAttachment[]
|
||||
|
||||
@@unique([storageKey])
|
||||
@@index([uploaderId])
|
||||
@@index([createdAt])
|
||||
@@map("file")
|
||||
}
|
||||
|
||||
/// Вложение задачи — связь задачи с файлом. Удаление задачи или файла
|
||||
/// удаляет связь каскадом; сам файл, оставшийся без связей, удалит GC.
|
||||
model IssueAttachment {
|
||||
issueId Int
|
||||
issue Issue @relation(fields: [issueId], references: [id], onDelete: Cascade)
|
||||
fileId String
|
||||
file File @relation(fields: [fileId], references: [id], onDelete: Cascade)
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
|
||||
@@id([issueId, fileId])
|
||||
@@index([fileId])
|
||||
@@map("issue_attachment")
|
||||
}
|
||||
Reference in new issue
Block a user