This commit is contained in:
alma 2025-05-04 14:16:58 +02:00
parent 63d2dbc5b6
commit f657d62373
5 changed files with 114 additions and 37 deletions

View File

@ -32,11 +32,20 @@ export async function GET(request: Request) {
return NextResponse.json({ error: 'Folder parameter is required' }, { status: 400 });
}
// Normalize folder name to lowercase to match S3 convention
// Try both lowercase and original case to maintain compatibility
// MinIO/S3 is case-sensitive, so we need to handle both formats
const normalizedFolder = folderParam.toLowerCase();
// List objects for the user in the specified folder
const files = await listUserObjects(userId, normalizedFolder);
console.log(`Listing files for user ${userId} in folder: ${folderParam} (normalized: ${normalizedFolder})`);
// First try with the exact folder name as provided
let files = await listUserObjects(userId, folderParam);
// If no files found with original case, try with lowercase
if (files.length === 0 && folderParam !== normalizedFolder) {
console.log(`No files found with original case, trying lowercase: ${normalizedFolder}`);
files = await listUserObjects(userId, normalizedFolder);
}
return NextResponse.json(files);
} catch (error) {

View File

@ -10,9 +10,14 @@ export async function POST(request: Request) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
console.log(`Initializing storage for user: ${session.user.id}`);
// Create folder structure for the user
await createUserFolderStructure(session.user.id);
// Update the session to indicate storage is initialized
// This is handled client-side since we can't modify the session directly here
// Return success response
return NextResponse.json({
success: true,

View File

@ -45,6 +45,7 @@ interface Contact {
export default function CarnetPage() {
const { data: session, status } = useSession();
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [layoutMode, setLayoutMode] = useState<string>("item-selection");
const [selectedNote, setSelectedNote] = useState<Note | null>(null);
const [isMobile, setIsMobile] = useState(false);
@ -149,22 +150,6 @@ export default function CarnetPage() {
fetchContacts(selectedFolder);
} else {
// For other folders (Notes, etc.), fetch notes
const fetchNotes = async () => {
try {
setIsLoadingNotes(true);
const response = await fetch(`/api/nextcloud/files?folder=${selectedFolder}`);
if (!response.ok) {
throw new Error('Failed to fetch notes');
}
const data = await response.json();
setNotes(data);
} catch (error) {
console.error('Error fetching notes:', error);
setNotes([]);
} finally {
setIsLoadingNotes(false);
}
};
fetchNotes();
}
}, [selectedFolder, session?.user?.id]);
@ -262,6 +247,74 @@ export default function CarnetPage() {
}
};
// Fetch notes based on the selected folder
const fetchNotes = async () => {
try {
setIsLoading(true);
// Handle folder paths for S3 format - endpoint will try both cases
const response = await fetch(`/api/nextcloud/files?folder=${selectedFolder}`);
if (response.ok) {
const data = await response.json();
console.log(`Fetched ${data.length} notes from ${selectedFolder} folder`);
setNotes(data);
} else {
console.error('Error fetching notes:', await response.text());
setNotes([]);
}
} catch (error) {
console.error('Error fetching notes:', error);
setNotes([]);
} finally {
setIsLoading(false);
}
};
// Handle saving changes to a note
const handleSaveNote = async (note: Note) => {
try {
setIsSaving(true);
// Construct API payload - ensure folder is properly set
const payload = {
id: note.id,
title: note.title,
content: note.content,
folder: selectedFolder.toLowerCase(), // Use lowercase for S3 consistency
mime: "text/markdown"
};
// Use the API endpoint to save the note
const endpoint = note.id ? '/api/nextcloud/files' : '/api/nextcloud/files';
const method = note.id ? 'PUT' : 'POST';
console.log(`Saving note to ${selectedFolder} using ${method}:`, {
id: note.id,
title: note.title,
folder: selectedFolder.toLowerCase()
});
const response = await fetch(endpoint, {
method,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (response.ok) {
// Refresh the list of notes
fetchNotes();
} else {
console.error('Error saving note:', await response.text());
}
} catch (error) {
console.error('Error saving note:', error);
} finally {
setIsSaving(false);
}
};
// Handle panel resizing
const handleNavResize = (e: MouseEvent) => {
if (!isDraggingNav) return;
@ -642,20 +695,11 @@ export default function CarnetPage() {
) : (
<Editor
note={selectedNote}
onSave={handleNoteSave}
onSave={handleSaveNote}
currentFolder={selectedFolder}
onRefresh={() => {
// Refresh the notes list
fetch(`/api/nextcloud/files?folder=${selectedFolder}`)
.then(response => response.json())
.then(updatedNotes => {
if (selectedFolder === 'Contacts') {
setContacts(updatedNotes);
} else {
setNotes(updatedNotes);
}
})
.catch(error => console.error('Error refreshing data:', error));
fetchNotes();
}}
/>
)}

View File

@ -77,23 +77,28 @@ export default function Navigation({ nextcloudFolders, onFolderSelect }: Navigat
const fetchContactFiles = async () => {
try {
setIsLoadingContacts(true);
// Use the consistent folder name case that matches S3 structure
// The endpoint will try both cases, but we should prefer the consistent one
const response = await fetch('/api/nextcloud/files?folder=Contacts');
if (response.ok) {
const files = await response.json();
// Only log the number of files received, not their contents
console.log(`Received ${files.length} files from Nextcloud`);
console.log(`Received ${files.length} files from storage`);
// Filter for VCF files and map to ContactFile interface
const vcfFiles = files
.filter((file: any) => file.basename.endsWith('.vcf'))
.filter((file: any) => file.basename?.endsWith('.vcf') || file.title?.endsWith('.vcf'))
.map((file: any) => ({
id: file.etag,
filename: file.filename,
basename: file.basename,
lastmod: file.lastmod
id: file.etag || file.id,
filename: file.filename || file.id,
basename: file.basename || file.title,
lastmod: file.lastmod || file.lastModified
}));
// Only log the number of VCF files processed
console.log(`Processed ${vcfFiles.length} VCF files`);
setContactFiles(vcfFiles);
} else {
console.error('Error fetching contact files:', await response.text());
setContactFiles([]);
}
} catch (error) {
console.error('Error fetching contact files:', error);

View File

@ -123,15 +123,29 @@ export async function deleteObject(key: string) {
// Create folder structure (In S3, folders are just prefix notations)
export async function createUserFolderStructure(userId: string) {
try {
// Define the standard folders to create
// Define the standard folders to create - use lowercase for consistency with S3 operations
// These are the canonical folder names that match what the frontend expects in the "vues" sidebar
const folders = ['notes', 'diary', 'health', 'contacts'];
// Also create capitalized versions for backward compatibility with UI components
const capitalizedFolders = ['Notes', 'Diary', 'Health', 'Contacts'];
// For S3, creating a folder means creating an empty object with the folder name as a prefix
// First create lowercase versions (primary storage)
for (const folder of folders) {
const key = `user-${userId}/${folder}/`;
console.log(`Creating folder: ${key}`);
await putObject(key, '', 'application/x-directory');
}
// Then create capitalized versions (for backward compatibility)
for (const folder of capitalizedFolders) {
const key = `user-${userId}/${folder}/`;
console.log(`Creating capitalized folder: ${key}`);
await putObject(key, '', 'application/x-directory');
}
console.log(`Successfully created folder structure for user: ${userId}`);
return true;
} catch (error) {
console.error('Error creating folder structure:', error);