import { WebDAV } from 'webdav'; import { getSession } from 'next-auth/react'; export class NextCloudService { private webdav: WebDAV; private basePath: string = '/Personal/Carnet'; private subFolders: string[] = ['Journal', 'Santé', 'Notes']; constructor(token: string) { const nextcloudUrl = process.env.NEXTCLOUD_URL; console.log('NextCloud Configuration:', { baseUrl: nextcloudUrl, tokenLength: token?.length || 0, hasToken: !!token }); if (!nextcloudUrl) { throw new Error('NEXTCLOUD_URL environment variable is not set'); } const webdavUrl = `${nextcloudUrl}/remote.php/dav/files`; console.log('WebDAV endpoint:', webdavUrl); this.webdav = new WebDAV( webdavUrl, { headers: { Authorization: `Bearer ${token}`, }, } ); } private async testConnection() { try { console.log('Testing WebDAV connection...'); // Try to list root directory const rootContents = await this.webdav.getDirectoryContents('/'); console.log('WebDAV connection successful, root directory contents:', rootContents); return true; } catch (error) { console.error('WebDAV connection test failed:', { error: error instanceof Error ? error.message : error, response: error.response?.data, status: error.response?.status, headers: error.response?.headers }); return false; } } async initializeUserFolders(username: string) { console.log('=== Starting folder initialization ==='); console.log(`User: ${username}`); // Test connection first const connectionOk = await this.testConnection(); if (!connectionOk) { throw new Error('Failed to connect to NextCloud WebDAV service'); } const userBasePath = `${username}${this.basePath}`; console.log('Target base path:', userBasePath); // Create base Carnet folder try { console.log('Checking base folder existence...'); const baseExists = await this.webdav.exists(userBasePath); console.log('Base folder check result:', baseExists); if (!baseExists) { console.log('Creating base folder structure...'); try { await this.webdav.createDirectory(userBasePath, { recursive: true }); console.log('Base folder created successfully'); } catch (createError) { console.error('Failed to create base folder:', { error: createError instanceof Error ? createError.message : createError, response: createError.response?.data, status: createError.response?.status }); throw createError; } } } catch (error) { console.error('Error in base folder operation:', { path: userBasePath, error: error instanceof Error ? error.message : error, response: error.response?.data, status: error.response?.status, headers: error.response?.headers }); throw new Error(`Failed to initialize base folder: ${error.message || 'Unknown error'}`); } // Create subfolders for (const folder of this.subFolders) { const folderPath = `${userBasePath}/${folder}`; console.log(`\nProcessing subfolder: ${folder}`); console.log('Target path:', folderPath); try { console.log(`Checking if ${folder} exists...`); const exists = await this.webdav.exists(folderPath); console.log(`${folder} existence check result:`, exists); if (!exists) { console.log(`Creating ${folder} folder...`); try { await this.webdav.createDirectory(folderPath, { recursive: true }); console.log(`${folder} folder created successfully`); } catch (createError) { console.error(`Failed to create ${folder} folder:`, { error: createError instanceof Error ? createError.message : createError, response: createError.response?.data, status: createError.response?.status }); throw createError; } } } catch (error) { console.error(`Error processing ${folder} folder:`, { path: folderPath, error: error instanceof Error ? error.message : error, response: error.response?.data, status: error.response?.status, headers: error.response?.headers }); throw new Error(`Failed to initialize ${folder} folder: ${error.message || 'Unknown error'}`); } } console.log('\n=== Folder initialization completed ==='); // Verify final structure try { console.log('\nVerifying folder structure...'); const contents = await this.webdav.getDirectoryContents(userBasePath, { deep: true }); console.log('Final folder structure:', contents); } catch (error) { console.error('Error verifying folder structure:', { error: error instanceof Error ? error.message : error, response: error.response?.data, status: error.response?.status }); } } async saveNote(username: string, content: string, category: string = 'Notes', date: Date = new Date()) { console.log('Saving note:', { username, category, date }); if (!this.subFolders.includes(category)) { console.error('Invalid category provided:', category); throw new Error(`Invalid category: ${category}`); } const fileName = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}.md`; const filePath = `${username}${this.basePath}/${category}/${fileName}`; console.log('File path for save:', filePath); try { await this.initializeUserFolders(username); console.log('Saving file content to:', filePath); await this.webdav.putFileContents(filePath, content, { overwrite: true }); console.log('File saved successfully'); return { fileName, category }; } catch (error) { console.error('Error saving note:', { path: filePath, error: error instanceof Error ? error.message : error, fullError: error }); throw error; } } async getNote(username: string, category: string, date: Date) { console.log('Getting note:', { username, category, date }); if (!this.subFolders.includes(category)) { console.error('Invalid category provided:', category); throw new Error(`Invalid category: ${category}`); } const fileName = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}.md`; const filePath = `${username}${this.basePath}/${category}/${fileName}`; console.log('File path for get:', filePath); try { console.log('Fetching file content from:', filePath); const content = await this.webdav.getFileContents(filePath, { format: 'text' }); console.log('File content fetched successfully'); return content; } catch (error) { if (error.response?.status === 404) { console.log('Note not found:', filePath); return null; } console.error('Error getting note:', { path: filePath, error: error instanceof Error ? error.message : error, fullError: error }); throw error; } } async listNotes(username: string, category?: string) { console.log('Listing notes:', { username, category }); try { await this.initializeUserFolders(username); const userPath = `${username}${this.basePath}`; const results = []; if (category) { if (!this.subFolders.includes(category)) { console.error('Invalid category provided:', category); throw new Error(`Invalid category: ${category}`); } const folderPath = `${userPath}/${category}`; console.log('Listing files in category folder:', folderPath); const files = await this.webdav.getDirectoryContents(folderPath); console.log(`Found ${files.length} files in ${category}`); results.push(...this.processFiles(files, category)); } else { for (const folder of this.subFolders) { const folderPath = `${userPath}/${folder}`; try { console.log('Listing files in folder:', folderPath); const files = await this.webdav.getDirectoryContents(folderPath); console.log(`Found ${files.length} files in ${folder}`); results.push(...this.processFiles(files, folder)); } catch (error) { if (error.response?.status !== 404) { console.error(`Error listing files in ${folder}:`, { path: folderPath, error: error instanceof Error ? error.message : error, fullError: error }); throw error; } console.log(`No files found in ${folder}`); } } } console.log(`Total notes found: ${results.length}`); return results; } catch (error) { if (error.response?.status === 404) { console.log('No notes found'); return []; } console.error('Error listing notes:', { username, category, error: error instanceof Error ? error.message : error, fullError: error }); throw error; } } private processFiles(files: any[], category: string) { const processed = files .filter(file => file.basename.endsWith('.md')) .map(file => ({ date: this.fileNameToDate(file.basename), name: file.basename, path: file.filename, category })); console.log(`Processed ${processed.length} files in ${category}`); return processed; } private fileNameToDate(fileName: string): Date { const [year, month, day] = fileName.split('.')[0].split('-').map(Number); return new Date(year, month - 1, day); } } }