Files
ollama-plus/nextcloud/helpers.ts
T
2025-10-11 11:29:11 -04:00

127 lines
3.1 KiB
TypeScript

import { Request } from "express";
import { WebDAVClient } from "webdav";
import { DIRS } from "./server";
import fetch from 'node-fetch'
import { XMLParser } from 'fast-xml-parser';
export async function statOne(fpath: string, client: WebDAVClient) {
const parent = fpath.replace(/\/[^/]+$/, '') || '/',
base = fpath.split('/').filter(Boolean).pop(),
list = await client.getDirectoryContents(parent, { deep: false }).catch(err => {
console.error(`error for "${parent}":`);
console.error(err);
if (err.response?.status === 404) {
throw `Path "${fpath}" not found`;
}
throw err;
}),
entry = Array.isArray(list) ? list.find((e: any) => e.basename === base) : undefined;
if (!entry) throw `Path "${fpath}" not found`;
return { etag: entry.etag as string, size: Number(entry.size), mime: entry.mime as string | undefined };
}
export const toRegExp = (spec: string): RegExp | null => {
// slash-delimited form: /pattern/flags
const m = spec.match(/^\/(.+)\/([a-z]*)$/i);
try {
if (m) {
const [, source, flags] = m;
return new RegExp(source, flags);
}
// raw pattern form: "pattern"
return new RegExp(spec);
} catch {
return null;
}
}
export function checkIfHasPerms(req: Request | string) {
try {
if (typeof req === 'string') {
if (req.includes('..')) return false;
return !DIRS || DIRS.find(r => req.match(r));
}
else if (!req.body) {
return false;
}
const { fpath, obj_type, deep, usecache } = req.body,
o = { fpath, obj_type, deep, usecache };
if (!fpath) return false;
if (!DIRS) return o;
if (fpath.includes('..')) return false;
return DIRS.find(r => fpath.match(r)) ? o : false;
}
catch (err) {
console.error(err);
return false;
}
}
function buildCountPropfindXml() {
return `<?xml version="1.0" encoding="UTF-8"?>
<d:propfind xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:nc="http://nextcloud.org/ns">
<d:prop>
<nc:contained-file-count/>
<nc:contained-folder-count/>
<oc:contained-file-count/>
<oc:contained-folder-count/>
</d:prop>
</d:propfind>`;
}
const authHeaders = (() => {
const u = process.env.NEXTCLOUD_APP_ID!,
p = process.env.NEXTCLOUD_APP_PASS!,
token = Buffer.from(`${u}:${p}`).toString("base64");
return `Basic ${token}`;
})();
export async function getDirectoryFileCount(dirPath: string, client: WebDAVClient) {
const url = client.getFileDownloadLink(dirPath),
xml = buildCountPropfindXml();
const resp = await fetch(url, {
method: "PROPFIND",
headers: {
"Content-Type": "text/xml",
"Depth": "0",
"Authorization": authHeaders
},
body: xml
});
if (!resp.ok) {
throw resp;
}
// parse XML
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: "@_",
allowBooleanAttributes: true,
numberParseOptions: {
hex: false,
leadingZeros: false
}
}),
text = await resp.text(),
doc = parser.parse(text),
objs = doc['d:multistatus']['d:response']['d:propstat'],
obj = objs.find((o: any) => o['d:status'].includes("200"))['d:prop'];
return {
file_count: obj['nc:contained-file-count'],
folder: obj['nc:contained-folder-count']
};
}