Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 1x 1x 1x 1x 1x 23x 23x 2x 21x 21x 20x 20x 8x 12x 2x 10x 10x 10x 10x 10x 9x 2x 2x | const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3')
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner')
const { randomUUID } = require('crypto')
const s3Client = new S3Client({ region: 'eu-central-1' })
exports.handler = async (event) => {
try {
// Only allow POST requests
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'POST, OPTIONS'
},
body: JSON.stringify({ error: 'Method not allowed' })
}
}
// Handle CORS preflight
Iif (event.httpMethod === 'OPTIONS') {
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Allow-Methods': 'POST, OPTIONS'
}
}
}
const body = JSON.parse(event.body || '{}')
const { fileName, fileType, tenantId, entityId, itemId, fieldName } = body
// Validate required parameters
if (!fileName || !fileType || !tenantId || !entityId || !itemId || !fieldName) {
return {
statusCode: 400,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
},
body: JSON.stringify({
error:
'Missing required parameters: fileName, fileType, tenantId, entityId, itemId, fieldName'
})
}
}
// Validate file type (only images)
if (!fileType.startsWith('image/')) {
return {
statusCode: 400,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
},
body: JSON.stringify({ error: 'Only image files are allowed' })
}
}
// Generate unique filename
const fileExtension = fileName.split('.').pop()
const uniqueFileName = `${randomUUID()}.${fileExtension}`
// Create S3 key with organized folder structure
const key = `${tenantId}/${entityId}/${itemId}/${fieldName}/${uniqueFileName}`
// Create the PutObject command
const command = new PutObjectCommand({
Bucket: process.env.ATTACHMENTS_BUCKET_NAME,
Key: key,
ContentType: fileType,
// Optional: Add metadata
Metadata: {
tenantId,
entityId,
itemId,
fieldName,
originalFileName: fileName
}
})
// Generate presigned URL (expires in 15 minutes)
const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 900 })
// Return the presigned URL and the S3 key
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
},
body: JSON.stringify({
uploadUrl: signedUrl,
key: key,
bucket: process.env.ATTACHMENTS_BUCKET_NAME
})
}
} catch (error) {
console.error('Error generating presigned URL:', error)
return {
statusCode: 500,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
},
body: JSON.stringify({ error: 'Internal server error' })
}
}
}
|