diff --git a/app/api/nextcloud/status/route.ts b/app/api/nextcloud/status/route.ts index 512f8390..f06a0c04 100644 --- a/app/api/nextcloud/status/route.ts +++ b/app/api/nextcloud/status/route.ts @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; -import { authOptions } from '@/lib/auth'; +import { authOptions } from '@/app/api/auth/[...nextauth]/route'; import { DOMParser } from '@xmldom/xmldom'; import { Buffer } from 'buffer'; import { PrismaClient } from '@prisma/client'; @@ -204,60 +204,122 @@ async function getWebDAVCredentials(nextcloudUrl: string, username: string, admi export async function GET() { try { const session = await getServerSession(authOptions); - if (!session?.user?.email) { + if (!session?.user?.email || !session?.user?.id || !session?.accessToken) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const userId = session.user.email.split('@')[0]; - const nextcloudUsername = `cube-${userId}`; const nextcloudUrl = process.env.NEXTCLOUD_URL; - const webDAVUrl = `${nextcloudUrl}/remote.php/dav/files/${nextcloudUsername}/Private/`; + const adminUsername = process.env.NEXTCLOUD_ADMIN_USERNAME; + const adminPassword = process.env.NEXTCLOUD_ADMIN_PASSWORD; - // Check cache first - const cacheKey = nextcloudUsername; - const cachedData = folderCache.get(cacheKey); - if (cachedData) { - const cacheAge = Date.now() - cachedData.timestamp; - if (cacheAge < 5 * 60 * 1000) { // 5 minutes cache - return NextResponse.json({ folders: cachedData.folders }); - } + if (!nextcloudUrl || !adminUsername || !adminPassword) { + console.error('Missing Nextcloud configuration'); + return NextResponse.json({ error: 'Nextcloud configuration is missing' }, { status: 500 }); } - // Fetch folder structure - const response = await fetch(webDAVUrl, { - headers: { - 'Authorization': `Basic ${Buffer.from(`${nextcloudUsername}:${process.env.NEXTCLOUD_ADMIN_PASSWORD}`).toString('base64')}`, - 'Depth': '1' - } - }); - - if (!response.ok) { - throw new Error('Failed to fetch folder structure'); + // Test Nextcloud connectivity + const testResponse = await fetch(`${nextcloudUrl}/status.php`); + if (!testResponse.ok) { + console.error('Nextcloud is not accessible:', await testResponse.text()); + return NextResponse.json({ error: "Nextcloud n'est pas accessible" }, { status: 503 }); } - const xmlData = await response.text(); - const parser = new DOMParser(); - const doc = parser.parseFromString(xmlData, 'text/xml'); - const folders: string[] = []; + try { + // Use the Keycloak ID as the Nextcloud username + const nextcloudUsername = `cube-${session.user.id}`; + console.log('Using Nextcloud username:', nextcloudUsername); - const responses = doc.getElementsByTagName('d:response'); - for (let i = 0; i < responses.length; i++) { - const response = responses[i]; - const displayName = response.getElementsByTagName('d:displayname')[0]?.textContent; - if (displayName && displayName !== 'Private') { - folders.push(displayName); + // Get or create WebDAV credentials + const webdavPassword = await getWebDAVCredentials( + nextcloudUrl, + nextcloudUsername, + adminUsername, + adminPassword, + session.user.id + ); + + if (!webdavPassword) { + throw new Error('Failed to get WebDAV credentials'); } + + // Get user's folders using WebDAV with Basic authentication + const webdavUrl = `${nextcloudUrl}/remote.php/dav/files/${encodeURIComponent(nextcloudUsername)}/Private/`; + console.log('Requesting WebDAV URL:', webdavUrl); + + const foldersResponse = await fetch(webdavUrl, { + method: 'PROPFIND', + headers: { + 'Authorization': `Basic ${Buffer.from(`${nextcloudUsername}:${webdavPassword}`).toString('base64')}`, + 'Depth': '1', + 'Content-Type': 'application/xml', + }, + body: '', + }); + + if (foldersResponse.status === 429) { + // Rate limited, wait and retry + const retryAfter = foldersResponse.headers.get('Retry-After'); + await sleep((retryAfter ? parseInt(retryAfter) : 5) * 1000); + return GET(); // Retry the entire request + } + + if (!foldersResponse.ok) { + const errorText = await foldersResponse.text(); + console.error('Failed to fetch folders. Status:', foldersResponse.status); + console.error('Response:', errorText); + console.error('Response headers:', Object.fromEntries(foldersResponse.headers.entries())); + throw new Error(`Failed to fetch folders: ${errorText}`); + } + + const folderData = await foldersResponse.text(); + console.log('Folder data:', folderData); + + // Parse the XML response to get folder names + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(folderData, 'text/xml'); + const responses = Array.from(xmlDoc.getElementsByTagName('d:response')); + + const folders: string[] = []; + for (const response of responses) { + const resourceType = response.getElementsByTagName('d:resourcetype')[0]; + const isCollection = resourceType?.getElementsByTagName('d:collection').length > 0; + + if (isCollection) { + const href = response.getElementsByTagName('d:href')[0]?.textContent; + if (href) { + // Extract folder name from href + const folderName = decodeURIComponent(href.split('/').filter(Boolean).pop() || ''); + if (folderName && folderName !== 'Private') { + folders.push(folderName); + } + } + } + } + + console.log('Parsed folders:', folders); + + // Update cache + folderCache.set(nextcloudUsername, { + folders, + timestamp: Date.now() + }); + + return NextResponse.json({ + isConnected: true, + folders + }); + } catch (error: any) { + console.error('Error accessing Nextcloud WebDAV:', error); + return NextResponse.json( + { error: "Erreur d'accès aux dossiers Nextcloud", details: error?.message || String(error) }, + { status: 503 } + ); } - - // Update cache - folderCache.set(cacheKey, { - folders, - timestamp: Date.now() - }); - - return NextResponse.json({ folders }); - } catch (error) { - console.error('Error in Nextcloud status:', error); - return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); + } catch (error: any) { + console.error('Error checking Nextcloud status:', error); + return NextResponse.json( + { error: 'Failed to check Nextcloud status', details: error?.message || String(error) }, + { status: 500 } + ); } } \ No newline at end of file