140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
import { S3Client, ListObjectsV2Command, GetObjectCommand, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';
|
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
|
|
// Environment variables for S3 configuration
|
|
const S3_BUCKET_URL = process.env.MINIO_S3_UPLOAD_BUCKET_URL || 'https://dome-api.slm-lab.net/';
|
|
const S3_REGION = process.env.MINIO_AWS_REGION || 'eu-east-1';
|
|
const S3_BUCKET_NAME = process.env.MINIO_AWS_S3_UPLOAD_BUCKET_NAME || 'pages';
|
|
|
|
// Create S3 client with MinIO configuration
|
|
export const s3Client = new S3Client({
|
|
region: S3_REGION,
|
|
endpoint: S3_BUCKET_URL,
|
|
forcePathStyle: true, // Required for MinIO
|
|
});
|
|
|
|
// Helper functions for S3 operations
|
|
|
|
// List objects in a "folder" for a specific user
|
|
export async function listUserObjects(userId: string, folder: string) {
|
|
try {
|
|
const prefix = `user-${userId}/${folder}/`;
|
|
const command = new ListObjectsV2Command({
|
|
Bucket: S3_BUCKET_NAME,
|
|
Prefix: prefix,
|
|
Delimiter: '/'
|
|
});
|
|
|
|
const response = await s3Client.send(command);
|
|
|
|
// Transform S3 objects to match the expected format for the frontend
|
|
// This ensures compatibility with existing NextCloud based components
|
|
return response.Contents?.map(item => ({
|
|
id: item.Key,
|
|
title: item.Key?.split('/').pop()?.replace('.md', '') || '',
|
|
lastModified: item.LastModified?.toISOString(),
|
|
size: item.Size,
|
|
type: 'file',
|
|
mime: item.Key?.endsWith('.md') ? 'text/markdown' : 'application/octet-stream',
|
|
etag: item.ETag
|
|
})) || [];
|
|
} catch (error) {
|
|
console.error('Error listing objects:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Get object content
|
|
export async function getObjectContent(key: string) {
|
|
try {
|
|
const command = new GetObjectCommand({
|
|
Bucket: S3_BUCKET_NAME,
|
|
Key: key
|
|
});
|
|
|
|
const response = await s3Client.send(command);
|
|
|
|
// Convert the stream to string
|
|
return await response.Body?.transformToString();
|
|
} catch (error) {
|
|
console.error('Error getting object content:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Put object (create or update a file)
|
|
export async function putObject(key: string, content: string, contentType?: string) {
|
|
try {
|
|
const command = new PutObjectCommand({
|
|
Bucket: S3_BUCKET_NAME,
|
|
Key: key,
|
|
Body: content,
|
|
ContentType: contentType || (key.endsWith('.md') ? 'text/markdown' : 'text/plain')
|
|
});
|
|
|
|
const response = await s3Client.send(command);
|
|
|
|
return {
|
|
id: key,
|
|
title: key.split('/').pop()?.replace('.md', '') || '',
|
|
lastModified: new Date().toISOString(),
|
|
size: content.length,
|
|
type: 'file',
|
|
mime: contentType || (key.endsWith('.md') ? 'text/markdown' : 'text/plain'),
|
|
etag: response.ETag
|
|
};
|
|
} catch (error) {
|
|
console.error('Error putting object:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Delete object
|
|
export async function deleteObject(key: string) {
|
|
try {
|
|
const command = new DeleteObjectCommand({
|
|
Bucket: S3_BUCKET_NAME,
|
|
Key: key
|
|
});
|
|
|
|
await s3Client.send(command);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error deleting object:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Create folder structure (In S3, folders are just prefix notations)
|
|
export async function createUserFolderStructure(userId: string) {
|
|
try {
|
|
// Define the standard folders to create
|
|
const folders = ['notes', 'diary', 'health', 'contacts'];
|
|
|
|
// For S3, creating a folder means creating an empty object with the folder name as a prefix
|
|
for (const folder of folders) {
|
|
const key = `user-${userId}/${folder}/`;
|
|
await putObject(key, '', 'application/x-directory');
|
|
}
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error creating folder structure:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Generate pre-signed URL for direct browser upload (optional feature)
|
|
export async function generatePresignedUrl(key: string, expiresIn = 3600) {
|
|
try {
|
|
const command = new PutObjectCommand({
|
|
Bucket: S3_BUCKET_NAME,
|
|
Key: key
|
|
});
|
|
|
|
return await getSignedUrl(s3Client, command, { expiresIn });
|
|
} catch (error) {
|
|
console.error('Error generating presigned URL:', error);
|
|
throw error;
|
|
}
|
|
}
|