diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index df61d656..30e0081b 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -35,7 +35,7 @@ declare module "next-auth" { role: string[]; nextcloudInitialized?: boolean; }; - accessToken: string; + accessToken?: string; } interface JWT { diff --git a/app/api/nextcloud/files/content/route.ts b/app/api/nextcloud/files/content/route.ts index e4301dce..2455155b 100644 --- a/app/api/nextcloud/files/content/route.ts +++ b/app/api/nextcloud/files/content/route.ts @@ -1,45 +1,9 @@ import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; -import { PrismaClient } from '@prisma/client'; import { authOptions } from '@/app/api/auth/[...nextauth]/route'; +import { prisma } from '@/lib/prisma'; import { createClient } from 'webdav'; -// Use a single PrismaClient instance -declare global { - var prisma: PrismaClient | undefined; -} - -const prisma = global.prisma || new PrismaClient(); -if (process.env.NODE_ENV !== 'production') global.prisma = prisma; - -// Helper function to create WebDAV client -const createWebDAVClient = async (userId: string) => { - const credentials = await prisma.webDAVCredentials.findUnique({ - where: { userId }, - }); - - if (!credentials) { - throw new Error('No WebDAV credentials found'); - } - - const baseURL = process.env.NEXTCLOUD_URL; - if (!baseURL) { - throw new Error('NEXTCLOUD_URL environment variable is not set'); - } - - const normalizedBaseURL = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL; - const webdavURL = `${normalizedBaseURL}/remote.php/dav`; - - return { - client: createClient(webdavURL, { - username: credentials.username, - password: credentials.password, - authType: 'password', - }), - username: credentials.username - }; -}; - export async function GET(request: Request) { try { const { searchParams } = new URL(request.url); @@ -54,9 +18,6 @@ export async function GET(request: Request) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const nextcloudUrl = process.env.NEXTCLOUD_URL; - const username = `cube-${session.user.id}`; - // Get credentials without logging const credentials = await prisma.webDAVCredentials.findUnique({ where: { userId: session.user.id } @@ -66,29 +27,29 @@ export async function GET(request: Request) { return NextResponse.json({ error: 'Nextcloud credentials not found' }, { status: 404 }); } - // Make request without logging sensitive information - const response = await fetch(`${nextcloudUrl}/remote.php/dav${path}`, { - method: 'GET', - headers: { - 'Authorization': `Basic ${Buffer.from(`${username}:${credentials.password}`).toString('base64')}`, - }, + // Create WebDAV client + const client = createClient(process.env.NEXTCLOUD_URL!, { + username: credentials.username, + password: credentials.password, }); - if (!response.ok) { - return NextResponse.json({ error: 'Failed to fetch file content' }, { status: response.status }); - } + try { + const content = await client.getFileContents(path, { format: 'text' }); + + // For VCF files, don't log the content + if (path.endsWith('.vcf')) { + return NextResponse.json({ content }); + } - const content = await response.text(); - - // For VCF files, don't log the content - if (path.endsWith('.vcf')) { return NextResponse.json({ content }); + } catch (error) { + // Log error without sensitive information + console.error('Error fetching file content:', error instanceof Error ? error.message : 'Unknown error'); + return NextResponse.json({ error: 'Failed to fetch file content' }, { status: 500 }); } - - return NextResponse.json({ content }); } catch (error) { // Log error without sensitive information - console.error('Error fetching file content:', error instanceof Error ? error.message : 'Unknown error'); + console.error('Error in GET request:', error instanceof Error ? error.message : 'Unknown error'); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } \ No newline at end of file diff --git a/app/api/nextcloud/files/route.ts b/app/api/nextcloud/files/route.ts index b6f89ccd..8dbd7e92 100644 --- a/app/api/nextcloud/files/route.ts +++ b/app/api/nextcloud/files/route.ts @@ -3,18 +3,19 @@ import { getServerSession } from 'next-auth'; import { PrismaClient } from '@prisma/client'; import { authOptions } from '@/app/api/auth/[...nextauth]/route'; import { createClient } from 'webdav'; +import { prisma } from '@/lib/prisma'; // Use a single PrismaClient instance declare global { var prisma: PrismaClient | undefined; } -const prisma = global.prisma || new PrismaClient(); -if (process.env.NODE_ENV !== 'production') global.prisma = prisma; +const prismaClient = global.prisma || new PrismaClient(); +if (process.env.NODE_ENV !== 'production') global.prisma = prismaClient; // Helper function to create WebDAV client const createWebDAVClient = async (userId: string) => { - const credentials = await prisma.webDAVCredentials.findUnique({ + const credentials = await prismaClient.webDAVCredentials.findUnique({ where: { userId }, }); @@ -54,9 +55,6 @@ export async function GET(request: Request) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const nextcloudUrl = process.env.NEXTCLOUD_URL; - const username = `cube-${session.user.id}`; - // Get credentials without logging const credentials = await prisma.webDAVCredentials.findUnique({ where: { userId: session.user.id } @@ -66,61 +64,40 @@ export async function GET(request: Request) { return NextResponse.json({ error: 'Nextcloud credentials not found' }, { status: 404 }); } - const path = `/files/${username}/Private/${folder}`; - - // Make request without logging sensitive information - const response = await fetch(`${nextcloudUrl}/remote.php/dav${path}`, { - method: 'PROPFIND', - headers: { - 'Authorization': `Basic ${Buffer.from(`${username}:${credentials.password}`).toString('base64')}`, - 'Depth': '1', - 'Content-Type': 'application/xml', - }, - body: '', + // Create WebDAV client + const client = createClient(process.env.NEXTCLOUD_URL!, { + username: credentials.username, + password: credentials.password, }); - if (!response.ok) { - return NextResponse.json({ error: 'Failed to fetch files' }, { status: response.status }); - } + try { + const path = `/files/${credentials.username}/Private/${folder}`; + const files = await client.getDirectoryContents(path); - const text = await response.text(); - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(text, 'text/xml'); - - const files: any[] = []; - const responses = xmlDoc.getElementsByTagName('d:response'); - - for (let i = 0; i < responses.length; i++) { - const response = responses[i]; - const href = response.getElementsByTagName('d:href')[0]?.textContent; - const propstat = response.getElementsByTagName('d:propstat')[0]; - - if (href && propstat) { - const prop = propstat.getElementsByTagName('d:prop')[0]; - if (prop) { - const type = prop.getElementsByTagName('d:resourcetype')[0]; - const lastmod = prop.getElementsByTagName('d:getlastmodified')[0]?.textContent; - const size = prop.getElementsByTagName('d:getcontentlength')[0]?.textContent; - const mime = prop.getElementsByTagName('d:getcontenttype')[0]?.textContent; - const etag = prop.getElementsByTagName('d:getetag')[0]?.textContent; - - if (type && !type.getElementsByTagName('d:collection').length) { - const filename = href.split('/').pop() || ''; - files.push({ - filename: href, - basename: filename, - lastmod, - size, - type: 'file', - etag, - mime - }); - } - } + // For Contacts folder, return all files + if (folder === 'Contacts') { + return NextResponse.json(files); } - } - return NextResponse.json(files); + // For other folders, filter markdown files + const markdownFiles = files + .filter((file: any) => file.basename.endsWith('.md')) + .map((file: any) => ({ + id: file.filename, + title: file.basename.replace('.md', ''), + lastModified: new Date(file.lastmod).toISOString(), + size: file.size, + type: 'file', + mime: file.mime, + etag: file.etag + })); + + return NextResponse.json(markdownFiles); + } catch (error) { + // Log error without sensitive information + console.error('Error listing directory contents:', error instanceof Error ? error.message : 'Unknown error'); + return NextResponse.json({ error: 'Failed to list directory contents' }, { status: 500 }); + } } catch (error) { // Log error without sensitive information console.error('Error fetching files:', error instanceof Error ? error.message : 'Unknown error');