* feat: setup secure presigned uploads and downloads * clean up * update lock * Get presigned url finally working * 557: Migrate backend to hono + ts * chore: update Dockerfile and package.json for backend configuration * add dev command * remove unused packages * Enhance backend API and frontend components for course management - Updated CORS configuration in the backend to allow specific methods and headers. - Refactored lesson download endpoint to use a new route for PDF downloads. - Removed unused certificate download functionality from the lesson router. - Updated frontend components to reflect changes in API endpoints and improve video upload functionality. - Introduced new video upload component and adjusted video handling in lesson materials. - Cleaned up unnecessary imports and optimized component structure for better performance. * PR cleanups * Enhance email configuration by adding SMTP_SENDER environment variable - Updated docker-compose.yaml to include SMTP_SENDER. - Modified Dockerfile to accept SMTP_SENDER as an argument. - Updated environment schema in env.ts to define SMTP_SENDER as optional. - Adjusted mail service to use SMTP_SENDER for the email 'from' field. - Updated documentation to reflect the new SMTP_SENDER variable. * Remove debug log statement from sendEmail function --------- Co-authored-by: Iniubong Obonguko <iniubongobonguko2018@gmail.com>
104 lines
2.7 KiB
TypeScript
104 lines
2.7 KiB
TypeScript
import { GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
|
|
import { ZCourseDownloadPresignedUrl, ZCoursePresignUrlUpload } from '$src/types/course';
|
|
|
|
import { CLOUDFLARE } from '$src/constants';
|
|
import type { GetSignedUrlParameters } from '$src/utils/s3';
|
|
import { Hono } from 'hono';
|
|
import { authMiddleware } from '$src/middlewares/auth';
|
|
import { generateFileKey } from '$src/utils/upload';
|
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
import { s3Client } from '$src/utils/s3';
|
|
|
|
export const presignRouter = new Hono();
|
|
|
|
presignRouter.post('/upload', authMiddleware, async (c) => {
|
|
const body = await c.req.json();
|
|
const result = ZCoursePresignUrlUpload.parse(body);
|
|
|
|
const { fileName, fileType } = result;
|
|
const fileKey = generateFileKey(fileName);
|
|
|
|
try {
|
|
const command = new PutObjectCommand({
|
|
Bucket: CLOUDFLARE.R2.BUCKET,
|
|
Key: fileKey,
|
|
ContentType: fileType
|
|
}) as GetSignedUrlParameters[1];
|
|
|
|
const presignedUrl = await getSignedUrl(s3Client as GetSignedUrlParameters[0], command, {
|
|
expiresIn: CLOUDFLARE.R2.PRESIGN_EXPIRATION_TIME
|
|
});
|
|
|
|
return c.json({
|
|
success: true,
|
|
url: presignedUrl,
|
|
fileKey,
|
|
message: 'Pre-signed URL generated successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Error generating pre-signed URL:', error);
|
|
|
|
if (error instanceof Error && error.name === 'SignatureDoesNotMatch') {
|
|
return c.json(
|
|
{
|
|
success: false,
|
|
type: 'SIGNATURE_ERROR',
|
|
message: 'Invalid signature for the request'
|
|
},
|
|
403
|
|
);
|
|
}
|
|
|
|
return c.json(
|
|
{
|
|
success: false,
|
|
type: 'INTERNAL_ERROR',
|
|
message: 'Error generating pre-signed URL'
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
presignRouter.post('/download', authMiddleware, async (c) => {
|
|
const body = await c.req.json();
|
|
const result = ZCourseDownloadPresignedUrl.parse(body);
|
|
|
|
const { keys } = result;
|
|
|
|
try {
|
|
const signedUrls: Record<string, string> = {};
|
|
|
|
await Promise.all(
|
|
keys.map(async (key) => {
|
|
const command = new GetObjectCommand({
|
|
Bucket: CLOUDFLARE.R2.BUCKET,
|
|
Key: key
|
|
}) as GetSignedUrlParameters[1];
|
|
|
|
const presignedUrl = await getSignedUrl(s3Client as GetSignedUrlParameters[0], command, {
|
|
expiresIn: CLOUDFLARE.R2.DOWNLOAD_EXPIRATION_TIME
|
|
});
|
|
|
|
signedUrls[key] = presignedUrl;
|
|
})
|
|
);
|
|
|
|
return c.json({
|
|
success: true,
|
|
urls: signedUrls,
|
|
message: 'Video URLs retrieved successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Error Retrieving Video:', error);
|
|
return c.json(
|
|
{
|
|
success: false,
|
|
type: 'INTERNAL_ERROR',
|
|
message: 'Error Retrieving Video'
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|