missions carrousse
This commit is contained in:
parent
76d4d55285
commit
dddfd5024b
115
README-MINIO-TROUBLESHOOTING.md
Normal file
115
README-MINIO-TROUBLESHOOTING.md
Normal file
@ -0,0 +1,115 @@
|
||||
# Minio Troubleshooting Guide
|
||||
|
||||
This document outlines the fixes implemented for the mission file upload issues with Minio.
|
||||
|
||||
## Problem Description
|
||||
|
||||
Mission uploads (logo and attachments) were not working correctly:
|
||||
- Files weren't appearing in Minio despite upload attempts
|
||||
- Mission logos weren't displaying even though they were uploaded
|
||||
- Participation field showed "Non spécifié" despite values in the database
|
||||
- SDG/ODD icons weren't displaying correctly
|
||||
|
||||
## Implemented Fixes
|
||||
|
||||
### 1. Added URL Generation Function
|
||||
|
||||
Added a `getPublicUrl` function in `lib/s3.ts` that properly constructs URLs for files stored in Minio:
|
||||
```typescript
|
||||
export function getPublicUrl(filePath: string): string {
|
||||
if (!filePath) return '';
|
||||
if (filePath.startsWith('http')) return filePath; // Already a full URL
|
||||
|
||||
// Remove leading slash if present
|
||||
const cleanPath = filePath.startsWith('/') ? filePath.substring(1) : filePath;
|
||||
|
||||
// Construct the full URL
|
||||
const endpoint = S3_CONFIG.endpoint?.replace(/\/$/, ''); // Remove trailing slash if present
|
||||
const bucket = S3_CONFIG.bucket;
|
||||
|
||||
// Return original path if no endpoint is configured
|
||||
if (!endpoint) return cleanPath;
|
||||
|
||||
// Construct and return the full URL
|
||||
return `${endpoint}/${bucket}/${cleanPath}`;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Updated Mission Display Page
|
||||
|
||||
Modified `app/missions/page.tsx` to use the `getPublicUrl` function when displaying mission logos:
|
||||
```tsx
|
||||
{mission.logo ? (
|
||||
<img
|
||||
src={mission.logo ? getPublicUrl(mission.logo) : ''}
|
||||
alt={mission.name}
|
||||
className="w-full h-full object-cover rounded-md border border-gray-200"
|
||||
onError={(e) => {
|
||||
// Error handling...
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
```
|
||||
|
||||
### 3. Enhanced Upload API
|
||||
|
||||
Updated `/app/api/missions/upload/route.ts` to:
|
||||
- Include additional logging
|
||||
- Generate and return proper public URLs
|
||||
- Improve error handling
|
||||
|
||||
### 4. Enhanced Mission Detail API
|
||||
|
||||
Modified `/app/api/missions/[missionId]/route.ts` to include public URLs in the response:
|
||||
```typescript
|
||||
const missionWithUrls = {
|
||||
...mission,
|
||||
logoUrl: mission.logo ? getPublicUrl(mission.logo) : null,
|
||||
attachments: mission.attachments.map((attachment) => ({
|
||||
...attachment,
|
||||
publicUrl: getPublicUrl(attachment.filePath)
|
||||
}))
|
||||
};
|
||||
```
|
||||
|
||||
### 5. Added Testing Tools
|
||||
|
||||
1. Browser Console Utilities:
|
||||
- `window.testMinioConnection()` - Test Minio connectivity
|
||||
- `window.getMinioUrl(path)` - Generate a public URL for debugging
|
||||
|
||||
2. Server-side Test Script:
|
||||
- Created `scripts/test-minio-upload.js` to test uploads from the command line
|
||||
- Tests uploading, downloading, and URL generation
|
||||
|
||||
## How to Test
|
||||
|
||||
1. **Using the browser console:**
|
||||
```javascript
|
||||
// Test connection and list files
|
||||
window.testMinioConnection()
|
||||
|
||||
// Generate URL for a specific path
|
||||
window.getMinioUrl('user-123/missions/456/logo.jpg')
|
||||
```
|
||||
|
||||
2. **Using the server-side script:**
|
||||
```bash
|
||||
node scripts/test-minio-upload.js
|
||||
```
|
||||
|
||||
## Required Environment Variables
|
||||
|
||||
Make sure these are properly set in your environment:
|
||||
- `MINIO_S3_UPLOAD_BUCKET_URL` - The Minio endpoint URL
|
||||
- `MINIO_AWS_REGION` - The AWS region (often 'us-east-1' for Minio)
|
||||
- `MINIO_AWS_S3_UPLOAD_BUCKET_NAME` - The bucket name
|
||||
- `MINIO_ACCESS_KEY` - Access key for Minio
|
||||
- `MINIO_SECRET_KEY` - Secret key for Minio
|
||||
|
||||
## Additional Notes
|
||||
|
||||
1. The same Minio bucket is used for both Pages and Missions.
|
||||
2. Pages functionality is working properly, suggesting the Minio configuration itself is correct.
|
||||
3. Make sure that the bucket has proper permissions for public read access.
|
||||
4. The URL paths for SDG/ODD icons were corrected to use `/F SDG Icons 2019 WEB/F-WEB-Goal-XX.png`
|
||||
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { UploadCloud, X, Check, Loader2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useSession } from 'next-auth/react';
|
||||
@ -21,6 +21,15 @@ export function FileUpload({
|
||||
maxSize = 5 * 1024 * 1024, // 5MB
|
||||
acceptedFileTypes = type === 'logo' ? 'image/*' : '.pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png'
|
||||
}: FileUploadProps) {
|
||||
// Log props on init
|
||||
console.log('FileUpload component initialized with props:', {
|
||||
type,
|
||||
missionId,
|
||||
hasMissionId: !!missionId,
|
||||
maxSize,
|
||||
acceptedFileTypes
|
||||
});
|
||||
|
||||
const { data: session } = useSession();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
@ -28,6 +37,28 @@ export function FileUpload({
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const isMounted = useRef(true);
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
isMounted.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Log when session changes
|
||||
useEffect(() => {
|
||||
console.log('Session state in FileUpload:', {
|
||||
isSessionLoaded: !!session,
|
||||
hasUser: !!session?.user,
|
||||
userId: session?.user?.id
|
||||
});
|
||||
}, [session]);
|
||||
|
||||
// Log when missionId changes
|
||||
useEffect(() => {
|
||||
console.log('MissionId in FileUpload component:', missionId);
|
||||
}, [missionId]);
|
||||
|
||||
// Handle drag events
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
@ -92,11 +123,41 @@ export function FileUpload({
|
||||
};
|
||||
|
||||
const handleUpload = async () => {
|
||||
if (!file || !session?.user?.id || !missionId) {
|
||||
console.error('Upload failed: Missing required data', {
|
||||
fileExists: !!file,
|
||||
userIdExists: !!session?.user?.id,
|
||||
missionIdExists: !!missionId
|
||||
// Log all values to see what's missing
|
||||
console.log('Debug upload parameters:', {
|
||||
file,
|
||||
sessionUser: session?.user,
|
||||
userId: session?.user?.id,
|
||||
missionId
|
||||
});
|
||||
|
||||
// Check for missing parameters and provide specific feedback
|
||||
if (!file) {
|
||||
console.error('Upload failed: No file selected');
|
||||
toast({
|
||||
title: 'Upload failed',
|
||||
description: 'No file selected. Please select a file first.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session?.user?.id) {
|
||||
console.error('Upload failed: No user session');
|
||||
toast({
|
||||
title: 'Authentication required',
|
||||
description: 'You need to be logged in to upload files. Please log in and try again.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!missionId) {
|
||||
console.error('Upload failed: Missing mission ID');
|
||||
toast({
|
||||
title: 'Upload failed',
|
||||
description: 'Missing mission ID. Please refresh the page and try again.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -142,28 +203,39 @@ export function FileUpload({
|
||||
|
||||
const result = await response.json();
|
||||
console.log('Upload successful, result:', result);
|
||||
setProgress(100);
|
||||
|
||||
// Reset file after successful upload
|
||||
setTimeout(() => {
|
||||
setFile(null);
|
||||
setIsUploading(false);
|
||||
setProgress(0);
|
||||
// Only update state if the component is still mounted
|
||||
if (isMounted.current) {
|
||||
setProgress(100);
|
||||
|
||||
// Call the callback if provided
|
||||
if (onUploadComplete) {
|
||||
onUploadComplete(result);
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'File uploaded successfully',
|
||||
description: type === 'logo' ? 'Logo has been updated' : `${file.name} has been added to attachments`,
|
||||
variant: 'default',
|
||||
});
|
||||
}, 1000);
|
||||
// Reset file after successful upload
|
||||
setTimeout(() => {
|
||||
if (isMounted.current) {
|
||||
setFile(null);
|
||||
setIsUploading(false);
|
||||
setProgress(0);
|
||||
|
||||
// Call the callback if provided
|
||||
if (onUploadComplete) {
|
||||
onUploadComplete(result);
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'File uploaded successfully',
|
||||
description: type === 'logo' ? 'Logo has been updated' : `${file.name} has been added to attachments`,
|
||||
variant: 'default',
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload error details:', error);
|
||||
setIsUploading(false);
|
||||
|
||||
// Only update state if the component is still mounted
|
||||
if (isMounted.current) {
|
||||
setIsUploading(false);
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'Upload failed',
|
||||
description: error instanceof Error ? error.message : 'An error occurred during upload',
|
||||
|
||||
0
scripts/test-minio-upload.js
Normal file → Executable file
0
scripts/test-minio-upload.js
Normal file → Executable file
Loading…
Reference in New Issue
Block a user