feat: Implement lesson creation with file uploads (video, attachments) and quiz data, integrating MinIO for storage.
This commit is contained in:
parent
4851182f4a
commit
04e2da43c4
6 changed files with 715 additions and 4 deletions
111
Backend/src/config/minio.ts
Normal file
111
Backend/src/config/minio.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import { Client } from 'minio';
|
||||
import { config } from './index';
|
||||
import { logger } from './logger';
|
||||
|
||||
/**
|
||||
* MinIO Client Configuration
|
||||
* Used for uploading videos and attachments to S3-compatible storage
|
||||
*/
|
||||
export const minioClient = new Client({
|
||||
endPoint: new URL(config.s3.endpoint).hostname,
|
||||
port: parseInt(new URL(config.s3.endpoint).port) || (config.s3.useSSL ? 443 : 9000),
|
||||
useSSL: config.s3.useSSL,
|
||||
accessKey: config.s3.accessKey,
|
||||
secretKey: config.s3.secretKey,
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensure bucket exists, create if not
|
||||
*/
|
||||
export async function ensureBucketExists(): Promise<void> {
|
||||
try {
|
||||
const exists = await minioClient.bucketExists(config.s3.bucket);
|
||||
if (!exists) {
|
||||
await minioClient.makeBucket(config.s3.bucket, 'us-east-1');
|
||||
logger.info(`Bucket '${config.s3.bucket}' created successfully`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error ensuring bucket exists: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique file path for storage
|
||||
*/
|
||||
export function generateFilePath(
|
||||
courseId: number,
|
||||
lessonId: number,
|
||||
fileType: 'video' | 'attachment',
|
||||
originalFilename: string
|
||||
): string {
|
||||
const timestamp = Date.now();
|
||||
const uniqueId = Math.random().toString(36).substring(2, 15);
|
||||
const extension = originalFilename.split('.').pop() || '';
|
||||
const safeFilename = `${timestamp}-${uniqueId}.${extension}`;
|
||||
|
||||
if (fileType === 'video') {
|
||||
return `courses/${courseId}/lessons/${lessonId}/video/${safeFilename}`;
|
||||
}
|
||||
return `courses/${courseId}/lessons/${lessonId}/attachments/${safeFilename}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a file to MinIO
|
||||
*/
|
||||
export async function uploadFile(
|
||||
filePath: string,
|
||||
fileBuffer: Buffer,
|
||||
mimeType: string
|
||||
): Promise<string> {
|
||||
try {
|
||||
await ensureBucketExists();
|
||||
|
||||
await minioClient.putObject(
|
||||
config.s3.bucket,
|
||||
filePath,
|
||||
fileBuffer,
|
||||
fileBuffer.length,
|
||||
{ 'Content-Type': mimeType }
|
||||
);
|
||||
|
||||
logger.info(`File uploaded successfully: ${filePath}`);
|
||||
return filePath;
|
||||
} catch (error) {
|
||||
logger.error(`Error uploading file: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file from MinIO
|
||||
*/
|
||||
export async function deleteFile(filePath: string): Promise<void> {
|
||||
try {
|
||||
await minioClient.removeObject(config.s3.bucket, filePath);
|
||||
logger.info(`File deleted successfully: ${filePath}`);
|
||||
} catch (error) {
|
||||
logger.error(`Error deleting file: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a presigned URL for file access
|
||||
*/
|
||||
export async function getPresignedUrl(
|
||||
filePath: string,
|
||||
expirySeconds: number = 3600
|
||||
): Promise<string> {
|
||||
try {
|
||||
const url = await minioClient.presignedGetObject(
|
||||
config.s3.bucket,
|
||||
filePath,
|
||||
expirySeconds
|
||||
);
|
||||
return url;
|
||||
} catch (error) {
|
||||
logger.error(`Error generating presigned URL: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue