carnet api nc

This commit is contained in:
alma 2025-04-20 14:50:49 +02:00
parent 1acecd3678
commit d2366a8c74
9 changed files with 3439 additions and 47 deletions

View File

@ -3,6 +3,9 @@ import { getServerSession } from 'next-auth';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
import { DOMParser } from '@xmldom/xmldom';
import { Buffer } from 'buffer';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
@ -10,7 +13,7 @@ async function sleep(ms: number) {
async function parseXMLResponse(response: Response): Promise<any> {
const text = await response.text();
console.log('XML Response:', text); // Debug log
console.log('XML Response:', text);
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(text, 'text/xml');
@ -41,9 +44,49 @@ async function parseXMLResponse(response: Response): Promise<any> {
return result;
}
async function getWebDAVCredentials(nextcloudUrl: string, username: string, adminUsername: string, adminPassword: string) {
async function createFolder(nextcloudUrl: string, username: string, password: string, folderPath: string) {
const response = await fetch(`${nextcloudUrl}/remote.php/dav/files/${encodeURIComponent(username)}/${encodeURIComponent(folderPath)}`, {
method: 'MKCOL',
headers: {
'Authorization': `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
},
});
if (!response.ok && response.status !== 405) { // 405 means folder already exists
throw new Error(`Failed to create folder ${folderPath}: ${response.status} ${response.statusText}`);
}
}
async function getWebDAVCredentials(nextcloudUrl: string, username: string, adminUsername: string, adminPassword: string, userId: string) {
try {
// First, try to get the user's WebDAV password
// Check if credentials exist in database
let credentials = await prisma.webDAVCredentials.findUnique({
where: { userId },
});
if (credentials) {
// Verify existing credentials still work
const verifyResponse = await fetch(`${nextcloudUrl}/remote.php/dav/files/${encodeURIComponent(username)}/`, {
method: 'PROPFIND',
headers: {
'Authorization': `Basic ${Buffer.from(`${username}:${credentials.password}`).toString('base64')}`,
'Depth': '1',
'Content-Type': 'application/xml',
},
body: '<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:"><d:prop><d:resourcetype/></d:prop></d:propfind>',
});
if (verifyResponse.ok) {
return credentials.password;
}
// If verification failed, delete the old credentials
await prisma.webDAVCredentials.delete({
where: { userId },
});
}
// Get user info from Nextcloud
const userInfoResponse = await fetch(`${nextcloudUrl}/ocs/v1.php/cloud/users/${encodeURIComponent(username)}`, {
headers: {
'Authorization': `Basic ${Buffer.from(`${adminUsername}:${adminPassword}`).toString('base64')}`,
@ -52,18 +95,14 @@ async function getWebDAVCredentials(nextcloudUrl: string, username: string, admi
});
if (!userInfoResponse.ok) {
console.error('Failed to get user info:', await userInfoResponse.text());
throw new Error(`Failed to get user info: ${userInfoResponse.status} ${userInfoResponse.statusText}`);
}
const userInfo = await parseXMLResponse(userInfoResponse);
console.log('User Info:', userInfo);
// Generate a new password
const newPassword = Math.random().toString(36).slice(-12);
console.log('Setting new password for user');
// Set the user's password directly
// Set the user's password
const setPasswordResponse = await fetch(`${nextcloudUrl}/ocs/v1.php/cloud/users/${encodeURIComponent(username)}`, {
method: 'PUT',
headers: {
@ -78,25 +117,22 @@ async function getWebDAVCredentials(nextcloudUrl: string, username: string, admi
});
if (!setPasswordResponse.ok) {
console.error('Failed to set password:', await setPasswordResponse.text());
throw new Error(`Failed to set password: ${setPasswordResponse.status} ${setPasswordResponse.statusText}`);
}
// Verify the password was set by trying to authenticate with PROPFIND
const verifyResponse = await fetch(`${nextcloudUrl}/remote.php/dav/files/${encodeURIComponent(username)}/`, {
method: 'PROPFIND',
headers: {
'Authorization': `Basic ${Buffer.from(`${username}:${newPassword}`).toString('base64')}`,
'Depth': '1',
'Content-Type': 'application/xml',
// Store the new credentials
credentials = await prisma.webDAVCredentials.create({
data: {
userId,
username,
password: newPassword,
},
body: '<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:"><d:prop><d:resourcetype/></d:prop></d:propfind>',
});
if (!verifyResponse.ok) {
console.error('Failed to verify password:', await verifyResponse.text());
throw new Error('Password verification failed');
}
// Create required folder structure
await createFolder(nextcloudUrl, username, newPassword, 'Private');
await createFolder(nextcloudUrl, username, newPassword, 'Private/Diary');
await createFolder(nextcloudUrl, username, newPassword, 'Private/Health');
return newPassword;
} catch (error) {
@ -148,7 +184,8 @@ export async function GET() {
nextcloudUrl,
nextcloudUsername,
adminUsername,
adminPassword
adminPassword,
session.user.id
);
if (!webdavPassword) {
@ -156,7 +193,7 @@ export async function GET() {
}
// Get user's folders using WebDAV with Basic authentication
const webdavUrl = `${nextcloudUrl}/remote.php/dav/files/${encodeURIComponent(nextcloudUsername)}/`;
const webdavUrl = `${nextcloudUrl}/remote.php/dav/files/${encodeURIComponent(nextcloudUsername)}/Private/`;
console.log('Requesting WebDAV URL:', webdavUrl);
const foldersResponse = await fetch(webdavUrl, {
@ -202,7 +239,7 @@ export async function GET() {
if (href) {
// Extract folder name from href
const folderName = decodeURIComponent(href.split('/').filter(Boolean).pop() || '');
if (folderName && folderName !== nextcloudUsername) {
if (folderName && folderName !== 'Private') {
folders.push(folderName);
}
}

32
node_modules/.prisma/client/edge.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -149,6 +149,26 @@ exports.Prisma.EventScalarFieldEnum = {
updatedAt: 'updatedAt'
};
exports.Prisma.MailCredentialsScalarFieldEnum = {
id: 'id',
userId: 'userId',
email: 'email',
password: 'password',
host: 'host',
port: 'port',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
exports.Prisma.WebDAVCredentialsScalarFieldEnum = {
id: 'id',
userId: 'userId',
username: 'username',
password: 'password',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
exports.Prisma.SortOrder = {
asc: 'asc',
desc: 'desc'
@ -168,7 +188,9 @@ exports.Prisma.NullsOrder = {
exports.Prisma.ModelName = {
User: 'User',
Calendar: 'Calendar',
Event: 'Event'
Event: 'Event',
MailCredentials: 'MailCredentials',
WebDAVCredentials: 'WebDAVCredentials'
};
/**

3230
node_modules/.prisma/client/index.d.ts generated vendored

File diff suppressed because it is too large Load Diff

32
node_modules/.prisma/client/index.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"name": "prisma-client-067e3ae165f3d7f955e13b8f5c95a2f095181e1bc0dd7f966e97f0ca575218a3",
"name": "prisma-client-c9759cc7a8e2c5f5df4ff9bd3c0aee5a8c3b48f326a42a0aac248c95b4c1be3c",
"main": "index.js",
"types": "index.d.ts",
"browser": "index-browser.js",

View File

@ -12,13 +12,15 @@ datasource db {
}
model User {
id String @id @default(uuid())
email String @unique
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
calendars Calendar[]
events Event[]
id String @id @default(uuid())
email String @unique
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
calendars Calendar[]
events Event[]
mailCredentials MailCredentials?
webdavCredentials WebDAVCredentials?
}
model Calendar {
@ -53,3 +55,29 @@ model Event {
@@index([calendarId])
@@index([userId])
}
model MailCredentials {
id String @id @default(uuid())
userId String @unique
email String
password String
host String
port Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model WebDAVCredentials {
id String @id @default(uuid())
userId String @unique
username String
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}

24
node_modules/.prisma/client/wasm.js generated vendored
View File

@ -149,6 +149,26 @@ exports.Prisma.EventScalarFieldEnum = {
updatedAt: 'updatedAt'
};
exports.Prisma.MailCredentialsScalarFieldEnum = {
id: 'id',
userId: 'userId',
email: 'email',
password: 'password',
host: 'host',
port: 'port',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
exports.Prisma.WebDAVCredentialsScalarFieldEnum = {
id: 'id',
userId: 'userId',
username: 'username',
password: 'password',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
};
exports.Prisma.SortOrder = {
asc: 'asc',
desc: 'desc'
@ -168,7 +188,9 @@ exports.Prisma.NullsOrder = {
exports.Prisma.ModelName = {
User: 'User',
Calendar: 'Calendar',
Event: 'Event'
Event: 'Event',
MailCredentials: 'MailCredentials',
WebDAVCredentials: 'WebDAVCredentials'
};
/**

View File

@ -8,7 +8,7 @@ generator client {
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
url = env("NEWSDB_URL")
}
model User {
@ -20,6 +20,7 @@ model User {
calendars Calendar[]
events Event[]
mailCredentials MailCredentials?
webdavCredentials WebDAVCredentials?
}
model Calendar {
@ -66,5 +67,17 @@ model MailCredentials {
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model WebDAVCredentials {
id String @id @default(uuid())
userId String @unique
username String
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}