285 lines
9.8 KiB
TypeScript
285 lines
9.8 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|