141 lines
3.9 KiB
TypeScript
141 lines
3.9 KiB
TypeScript
/**
|
|
* Secure image storage service using cloud functions
|
|
* No direct Firebase/Firestore access from the frontend
|
|
*/
|
|
|
|
import { secureApi } from './secureApi';
|
|
|
|
export interface StoredImage {
|
|
id: string;
|
|
fileName: string;
|
|
mimeType: string;
|
|
size: number;
|
|
uploadedAt: number;
|
|
data: string; // base64 encoded data
|
|
}
|
|
|
|
/**
|
|
* Upload and store an image via cloud functions
|
|
* @param file - The image file to upload
|
|
* @param collectionName - Collection name for organization (e.g., 'company-logos')
|
|
* @param documentId - Document ID for the image
|
|
* @param orgId - Organization ID for security
|
|
* @param userId - User ID for authentication
|
|
*/
|
|
export const uploadImage = async (
|
|
file: File,
|
|
collectionName: string,
|
|
documentId: string,
|
|
orgId: string,
|
|
userId: string
|
|
): Promise<StoredImage> => {
|
|
if (!file) {
|
|
throw new Error('No file provided');
|
|
}
|
|
|
|
// Validate file type
|
|
if (!file.type.startsWith('image/')) {
|
|
throw new Error('File must be an image');
|
|
}
|
|
|
|
// Validate file size (max 5MB)
|
|
const maxSize = 5 * 1024 * 1024; // 5MB
|
|
if (file.size > maxSize) {
|
|
throw new Error('Image size must be less than 5MB');
|
|
}
|
|
|
|
try {
|
|
// Convert file to base64
|
|
const base64Data = await fileToBase64(file);
|
|
|
|
// Create image object
|
|
const imageData = {
|
|
id: documentId,
|
|
fileName: file.name,
|
|
mimeType: file.type,
|
|
size: file.size,
|
|
uploadedAt: Date.now(),
|
|
data: base64Data
|
|
};
|
|
|
|
// Store via secure API (this would need to be implemented in cloud functions)
|
|
console.log('Image upload via secure API not yet implemented, storing locally');
|
|
|
|
// For now, return the image data (in production, this would go through cloud functions)
|
|
return imageData;
|
|
} catch (error) {
|
|
console.error('Failed to upload image:', error);
|
|
throw new Error('Failed to upload image');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Retrieve an image via cloud functions
|
|
* @param collectionName - Collection name
|
|
* @param documentId - Document ID
|
|
* @param orgId - Organization ID for security
|
|
* @param userId - User ID for authentication
|
|
*/
|
|
export const getImage = async (
|
|
collectionName: string,
|
|
documentId: string,
|
|
orgId: string,
|
|
userId: string
|
|
): Promise<StoredImage | null> => {
|
|
try {
|
|
// This would be implemented as a cloud function
|
|
console.log('Image retrieval via secure API not yet implemented');
|
|
return null;
|
|
} catch (error) {
|
|
console.error('Failed to retrieve image:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Delete an image via cloud functions
|
|
* @param collectionName - Collection name
|
|
* @param documentId - Document ID
|
|
* @param orgId - Organization ID for security
|
|
* @param userId - User ID for authentication
|
|
*/
|
|
export const deleteImage = async (
|
|
collectionName: string,
|
|
documentId: string,
|
|
orgId: string,
|
|
userId: string
|
|
): Promise<boolean> => {
|
|
try {
|
|
// This would be implemented as a cloud function
|
|
console.log('Image deletion via secure API not yet implemented');
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to delete image:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Helper function to convert File to base64
|
|
*/
|
|
const fileToBase64 = (file: File): Promise<string> => {
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.readAsDataURL(file);
|
|
reader.onload = () => {
|
|
if (typeof reader.result === 'string') {
|
|
resolve(reader.result);
|
|
} else {
|
|
reject(new Error('Failed to read file as base64'));
|
|
}
|
|
};
|
|
reader.onerror = (error) => reject(error);
|
|
});
|
|
};
|
|
|
|
// Default export for backward compatibility
|
|
export default {
|
|
uploadImage,
|
|
getImage,
|
|
deleteImage
|
|
}; |