-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: set up add finding attachments action
- Loading branch information
1 parent
4a8e83f
commit f6699ae
Showing
4 changed files
with
109 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {handleUpload, type HandleUploadBody} from '@vercel/blob/client' | ||
import {NextResponse} from 'next/server' | ||
|
||
import {requireServerSession} from '@/server/utils/auth' | ||
|
||
export const POST = async (request: Request): Promise<NextResponse> => { | ||
const body = (await request.json()) as HandleUploadBody | ||
|
||
try { | ||
const jsonResponse = await handleUpload({ | ||
body, | ||
request, | ||
onBeforeGenerateToken: async (_, clientPayload) => { | ||
await requireServerSession() | ||
|
||
return { | ||
maximumSizeInBytes: 4 * 1024 * 1024, // 4 MB | ||
tokenPayload: clientPayload, | ||
} | ||
}, | ||
onUploadCompleted: async () => { | ||
// ⚠️ This will not work on `localhost` websites, | ||
// Use ngrok or similar to get the full upload | ||
}, | ||
}) | ||
|
||
return NextResponse.json(jsonResponse) | ||
} catch (error) { | ||
return NextResponse.json( | ||
{error: (error as Error).message}, | ||
{status: 400}, // The webhook will retry 5 times waiting for a 200 | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,50 @@ | ||
import {MutateOptions, useMutation} from '@tanstack/react-query' | ||
import {upload} from '@vercel/blob/client' | ||
|
||
import { | ||
AddFindingRequest, | ||
AddFinding, | ||
AddFindingResponse, | ||
addFinding, | ||
} from '@/server/actions/finding/addFinding' | ||
import {withApiErrorHandler} from '@/lib/utils/common/error' | ||
|
||
type AddFindingRequest = { | ||
finding: AddFinding | ||
attachments?: File[] | ||
} | ||
|
||
const addFindingWithAttachments = async ({ | ||
finding, | ||
attachments, | ||
}: AddFindingRequest) => { | ||
if (!attachments) { | ||
return addFinding({finding, attachments: []}) | ||
} | ||
|
||
const blobs = attachments.map((attachment) => | ||
upload(attachment.name, attachment, { | ||
access: 'public', | ||
handleUploadUrl: '/api/upload/finding', | ||
}), | ||
) | ||
|
||
const uploadedBlobs = await Promise.all(blobs) | ||
|
||
return addFinding({ | ||
finding, | ||
attachments: uploadedBlobs.map((blob) => ({ | ||
attachmentUrl: blob.url, | ||
mimeType: blob.contentType, | ||
})), | ||
}) | ||
} | ||
|
||
export const useAddFinding = ( | ||
options?: MutateOptions<AddFindingResponse, Error, AddFindingRequest>, | ||
) => { | ||
return useMutation({ | ||
...options, | ||
mutationFn: withApiErrorHandler(addFinding), | ||
mutationFn: withApiErrorHandler(addFindingWithAttachments), | ||
// TODO: invalidate relevant GET queries | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
'use server' | ||
|
||
import {z} from 'zod' | ||
|
||
import {db, schema} from '@/server/db' | ||
import {insertFindingAttachmentSchema} from '@/server/db/schema/findingAttachment' | ||
import {requireServerSession} from '@/server/utils/auth' | ||
import {getApiZodError} from '@/lib/utils/common/error' | ||
|
||
export type AddFindingAttachmentRequest = z.infer< | ||
typeof insertFindingAttachmentSchema | ||
> | ||
|
||
export const addFindingAttachment = async ( | ||
request: AddFindingAttachmentRequest, | ||
) => { | ||
const session = await requireServerSession() | ||
|
||
const result = insertFindingAttachmentSchema.safeParse(request) | ||
|
||
if (!result.success) { | ||
return getApiZodError(result.error) | ||
} | ||
|
||
const {findingId} = result.data | ||
|
||
const finding = await db.query.findings.findFirst({ | ||
where: (findings, {eq}) => eq(findings.id, findingId), | ||
}) | ||
|
||
if (!finding) { | ||
throw new Error('Finding not found.') | ||
} | ||
|
||
if (finding.authorId === session.user.id) { | ||
throw new Error('Only finding author can add attachments.') | ||
} | ||
|
||
return db.insert(schema.findingAttachments).values(result.data).returning() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters