pages s3
This commit is contained in:
parent
63d2dbc5b6
commit
f657d62373
@ -32,11 +32,20 @@ export async function GET(request: Request) {
|
|||||||
return NextResponse.json({ error: 'Folder parameter is required' }, { status: 400 });
|
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();
|
const normalizedFolder = folderParam.toLowerCase();
|
||||||
|
|
||||||
// List objects for the user in the specified folder
|
console.log(`Listing files for user ${userId} in folder: ${folderParam} (normalized: ${normalizedFolder})`);
|
||||||
const files = await listUserObjects(userId, 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);
|
return NextResponse.json(files);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -10,9 +10,14 @@ export async function POST(request: Request) {
|
|||||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`Initializing storage for user: ${session.user.id}`);
|
||||||
|
|
||||||
// Create folder structure for the user
|
// Create folder structure for the user
|
||||||
await createUserFolderStructure(session.user.id);
|
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 success response
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@ -45,6 +45,7 @@ interface Contact {
|
|||||||
export default function CarnetPage() {
|
export default function CarnetPage() {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [layoutMode, setLayoutMode] = useState<string>("item-selection");
|
const [layoutMode, setLayoutMode] = useState<string>("item-selection");
|
||||||
const [selectedNote, setSelectedNote] = useState<Note | null>(null);
|
const [selectedNote, setSelectedNote] = useState<Note | null>(null);
|
||||||
const [isMobile, setIsMobile] = useState(false);
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
@ -149,22 +150,6 @@ export default function CarnetPage() {
|
|||||||
fetchContacts(selectedFolder);
|
fetchContacts(selectedFolder);
|
||||||
} else {
|
} else {
|
||||||
// For other folders (Notes, etc.), fetch notes
|
// 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();
|
fetchNotes();
|
||||||
}
|
}
|
||||||
}, [selectedFolder, session?.user?.id]);
|
}, [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
|
// Handle panel resizing
|
||||||
const handleNavResize = (e: MouseEvent) => {
|
const handleNavResize = (e: MouseEvent) => {
|
||||||
if (!isDraggingNav) return;
|
if (!isDraggingNav) return;
|
||||||
@ -642,20 +695,11 @@ export default function CarnetPage() {
|
|||||||
) : (
|
) : (
|
||||||
<Editor
|
<Editor
|
||||||
note={selectedNote}
|
note={selectedNote}
|
||||||
onSave={handleNoteSave}
|
onSave={handleSaveNote}
|
||||||
currentFolder={selectedFolder}
|
currentFolder={selectedFolder}
|
||||||
onRefresh={() => {
|
onRefresh={() => {
|
||||||
// Refresh the notes list
|
// Refresh the notes list
|
||||||
fetch(`/api/nextcloud/files?folder=${selectedFolder}`)
|
fetchNotes();
|
||||||
.then(response => response.json())
|
|
||||||
.then(updatedNotes => {
|
|
||||||
if (selectedFolder === 'Contacts') {
|
|
||||||
setContacts(updatedNotes);
|
|
||||||
} else {
|
|
||||||
setNotes(updatedNotes);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => console.error('Error refreshing data:', error));
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -77,23 +77,28 @@ export default function Navigation({ nextcloudFolders, onFolderSelect }: Navigat
|
|||||||
const fetchContactFiles = async () => {
|
const fetchContactFiles = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoadingContacts(true);
|
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');
|
const response = await fetch('/api/nextcloud/files?folder=Contacts');
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const files = await response.json();
|
const files = await response.json();
|
||||||
// Only log the number of files received, not their contents
|
// 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
|
// Filter for VCF files and map to ContactFile interface
|
||||||
const vcfFiles = files
|
const vcfFiles = files
|
||||||
.filter((file: any) => file.basename.endsWith('.vcf'))
|
.filter((file: any) => file.basename?.endsWith('.vcf') || file.title?.endsWith('.vcf'))
|
||||||
.map((file: any) => ({
|
.map((file: any) => ({
|
||||||
id: file.etag,
|
id: file.etag || file.id,
|
||||||
filename: file.filename,
|
filename: file.filename || file.id,
|
||||||
basename: file.basename,
|
basename: file.basename || file.title,
|
||||||
lastmod: file.lastmod
|
lastmod: file.lastmod || file.lastModified
|
||||||
}));
|
}));
|
||||||
// Only log the number of VCF files processed
|
// Only log the number of VCF files processed
|
||||||
console.log(`Processed ${vcfFiles.length} VCF files`);
|
console.log(`Processed ${vcfFiles.length} VCF files`);
|
||||||
setContactFiles(vcfFiles);
|
setContactFiles(vcfFiles);
|
||||||
|
} else {
|
||||||
|
console.error('Error fetching contact files:', await response.text());
|
||||||
|
setContactFiles([]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching contact files:', error);
|
console.error('Error fetching contact files:', error);
|
||||||
|
|||||||
16
lib/s3.ts
16
lib/s3.ts
@ -123,15 +123,29 @@ export async function deleteObject(key: string) {
|
|||||||
// Create folder structure (In S3, folders are just prefix notations)
|
// Create folder structure (In S3, folders are just prefix notations)
|
||||||
export async function createUserFolderStructure(userId: string) {
|
export async function createUserFolderStructure(userId: string) {
|
||||||
try {
|
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'];
|
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
|
// 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) {
|
for (const folder of folders) {
|
||||||
const key = `user-${userId}/${folder}/`;
|
const key = `user-${userId}/${folder}/`;
|
||||||
|
console.log(`Creating folder: ${key}`);
|
||||||
await putObject(key, '', 'application/x-directory');
|
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;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating folder structure:', error);
|
console.error('Error creating folder structure:', error);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user