File tree 6 files changed +137
-1
lines changed
6 files changed +137
-1
lines changed Original file line number Diff line number Diff line change
1
+ import { notFound } from 'next/navigation'
2
+ import { NextRequest , NextResponse } from 'next/server'
3
+
4
+ import { GetObjectCommand } from '@aws-sdk/client-s3'
5
+
6
+ import checkUserPermissionOnTask from '@/lib/api/queries/checkUserPermissionOnTask'
7
+ import prisma from '@/lib/prisma'
8
+ import { s3Client } from '@/lib/s3Client'
9
+ import { getServerUser } from '@/lib/session'
10
+ import { forbidden , unauthorized } from '@/utils/apiResponse'
11
+
12
+ export async function GET (
13
+ _ : NextRequest ,
14
+ { params } : { params : { id : string } }
15
+ ) {
16
+ const id = params . id
17
+
18
+ const task = await prisma . task . findUnique ( {
19
+ where : { id } ,
20
+ select : {
21
+ id : true ,
22
+ private : true ,
23
+ statement : true
24
+ }
25
+ } )
26
+
27
+ if ( ! task ) return notFound ( )
28
+
29
+ if ( task . private ) {
30
+ const user = await getServerUser ( )
31
+
32
+ if ( ! user ) {
33
+ return unauthorized ( )
34
+ }
35
+
36
+ if ( ! ( await checkUserPermissionOnTask ( user , task . id ) ) ) {
37
+ return forbidden ( )
38
+ }
39
+ }
40
+
41
+ try {
42
+ const response = await s3Client . send (
43
+ new GetObjectCommand ( {
44
+ Bucket : process . env . BUCKET_NAME ,
45
+ Key : `statements/attachments/${ id } .zip`
46
+ } )
47
+ )
48
+
49
+ return new NextResponse ( response . Body as ReadableStream , {
50
+ headers : {
51
+ 'Content-Type' : 'application/zip' ,
52
+ 'Content-Disposition' : `inline; attachment; filename=${ id } .zip`
53
+ }
54
+ } )
55
+ } catch {
56
+ return new NextResponse ( null , { status : 204 } )
57
+ }
58
+ }
Original file line number Diff line number Diff line change @@ -54,7 +54,9 @@ export async function POST(req: NextRequest) {
54
54
const Key =
55
55
file . type === 'application/pdf'
56
56
? `statements/pdf/${ task . id } .pdf`
57
- : `testcases/${ task . id } /${ file . path } `
57
+ : file . type === 'application/zip'
58
+ ? `statements/attachments/${ task . id } .zip`
59
+ : `testcases/${ task . id } /${ file . path } `
58
60
const url = await getSignedUrl (
59
61
s3Client ,
60
62
new PutObjectCommand ( {
Original file line number Diff line number Diff line change
1
+ 'use client'
2
+
3
+ import useSWR from 'swr'
4
+
5
+ import zipFetcher from '@/lib/zipFetcher'
6
+ import { DownloadIcon } from '@/svg/Illustrations/DownloadIcon'
7
+
8
+ export const Attachment = ( { id } : { id : string } ) => {
9
+ const { data : attachment } = useSWR ( `/api/tasks/${ id } /attachment` , zipFetcher )
10
+
11
+ if ( ! ( attachment instanceof Blob ) ) {
12
+ return null
13
+ }
14
+
15
+ const downloadAttachment = ( ) => {
16
+ const url = URL . createObjectURL ( attachment as Blob )
17
+ const a = document . createElement ( 'a' )
18
+ a . href = url
19
+ a . download = `${ id } .zip`
20
+ document . body . appendChild ( a )
21
+ a . click ( )
22
+ document . body . removeChild ( a )
23
+ URL . revokeObjectURL ( url )
24
+ }
25
+
26
+ return (
27
+ < div className = "my-3 text-gray-500 dark:text-gray-100" >
28
+ < p className = "mb-1" > Attachment</ p >
29
+ < button
30
+ className = "flex w-full items-center justify-between rounded-md border p-3"
31
+ onClick = { downloadAttachment }
32
+ >
33
+ < p className = "w-2/3 truncate" > { id } .zip</ p >
34
+ < DownloadIcon />
35
+ </ button >
36
+ < hr className = "my-4 hidden md:block" />
37
+ </ div >
38
+ )
39
+ }
Original file line number Diff line number Diff line change @@ -14,6 +14,8 @@ import { PieChart } from '@/components/common/PieChart'
14
14
import fetcher from '@/lib/fetcher'
15
15
import { IListSubmission } from '@/types/submissions'
16
16
17
+ import { Attachment } from './Attachment'
18
+
17
19
const NormalTabs = [
18
20
{
19
21
label : 'Statement' ,
@@ -153,6 +155,8 @@ export const SideBar = ({
153
155
154
156
< hr className = "my-4 hidden md:block" />
155
157
158
+ < Attachment id = { task . id } />
159
+
156
160
< div className = "hidden flex-col items-center justify-center md:flex" >
157
161
< a
158
162
target = "_blank"
Original file line number Diff line number Diff line change
1
+ export default async function zipFetcher < JSON = unknown > (
2
+ input : RequestInfo ,
3
+ init ?: RequestInit
4
+ ) : Promise < JSON | Blob > {
5
+ try {
6
+ const res = await fetch ( input , init )
7
+
8
+ if ( res . headers . get ( 'Content-Type' ) ?. includes ( 'application/zip' ) ) {
9
+ return res . blob ( )
10
+ }
11
+ return res . json ( )
12
+ } catch ( e ) {
13
+ return Promise . reject ( e )
14
+ }
15
+ }
Original file line number Diff line number Diff line change
1
+ export const DownloadIcon = ( ) => {
2
+ return (
3
+ < svg
4
+ width = "14"
5
+ height = "14"
6
+ viewBox = "0 0 14 14"
7
+ fill = "none"
8
+ xmlns = "http://www.w3.org/2000/svg"
9
+ >
10
+ < path
11
+ fill-rule = "evenodd"
12
+ clip-rule = "evenodd"
13
+ d = "M2.01465 11.7202C2.01465 11.3612 2.30566 11.0702 2.66465 11.0702H10.4646C10.8236 11.0702 11.1146 11.3612 11.1146 11.7202C11.1146 12.0792 10.8236 12.3702 10.4646 12.3702H2.66465C2.30566 12.3702 2.01465 12.0792 2.01465 11.7202ZM4.15503 6.7106C4.40887 6.45675 4.82043 6.45675 5.07427 6.7106L5.91465 7.55098L5.91465 2.62021C5.91465 2.26123 6.20566 1.97021 6.56465 1.97021C6.92363 1.97021 7.21465 2.26123 7.21465 2.62021L7.21465 7.55098L8.05503 6.7106C8.30887 6.45675 8.72043 6.45675 8.97427 6.7106C9.22811 6.96444 9.22811 7.37599 8.97427 7.62983L7.02427 9.57983C6.90237 9.70173 6.73704 9.77022 6.56465 9.77022C6.39226 9.77022 6.22693 9.70173 6.10503 9.57983L4.15503 7.62983C3.90119 7.37599 3.90119 6.96444 4.15503 6.7106Z"
14
+ fill = "#3B82F6"
15
+ />
16
+ </ svg >
17
+ )
18
+ }
You can’t perform that action at this time.
0 commit comments