You've already forked obsidian-visualiser
Rework file access and link archiving
This commit is contained in:
@@ -1,47 +0,0 @@
|
||||
import { and, eq, like, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { explorerContentTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const query = getQuery(e);
|
||||
const where = [];
|
||||
|
||||
if(query && query.path !== undefined)
|
||||
{
|
||||
where.push(eq(explorerContentTable.path, sql.placeholder('path')));
|
||||
}
|
||||
if(query && query.title !== undefined)
|
||||
{
|
||||
where.push(eq(explorerContentTable.title, sql.placeholder('title')));
|
||||
}
|
||||
if(query && query.type !== undefined)
|
||||
{
|
||||
where.push(eq(explorerContentTable.type, sql.placeholder('type')));
|
||||
}
|
||||
if (query && query.search !== undefined)
|
||||
{
|
||||
where.push(like(explorerContentTable.path, sql.placeholder('search')));
|
||||
}
|
||||
|
||||
if(where.length > 0)
|
||||
{
|
||||
const db = useDatabase();
|
||||
|
||||
const content = db.select({
|
||||
'path': explorerContentTable.path,
|
||||
'owner': explorerContentTable.owner,
|
||||
'title': explorerContentTable.title,
|
||||
'type': explorerContentTable.type,
|
||||
'content': sql<string>`cast(${explorerContentTable.content} as TEXT)`.as('content'),
|
||||
'navigable': explorerContentTable.navigable,
|
||||
'private': explorerContentTable.private,
|
||||
}).from(explorerContentTable).where(and(...where)).prepare().all(query);
|
||||
|
||||
if(content.length > 0)
|
||||
{
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { explorerContentTable } from '~/db/schema';
|
||||
import { schema } from '~/schemas/file';
|
||||
import { parsePath } from '~/shared/general.utils';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const body = await readValidatedBody(e, schema.safeParse);
|
||||
@@ -10,9 +11,10 @@ export default defineEventHandler(async (e) => {
|
||||
throw body.error;
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(body.data.content, 'utf-8');
|
||||
|
||||
const db = useDatabase();
|
||||
|
||||
const buffer = Buffer.from(convertToStorableLinks(body.data.content, db.select({ path: explorerContentTable.path }).from(explorerContentTable).all().map(e => e.path)), 'utf-8');
|
||||
|
||||
const content = db.insert(explorerContentTable).values({ ...body.data, content: buffer }).onConflictDoUpdate({ target: explorerContentTable.path, set: { ...body.data, content: buffer, timestamp: new Date() } });
|
||||
|
||||
if(content !== undefined)
|
||||
@@ -22,4 +24,14 @@ export default defineEventHandler(async (e) => {
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
});
|
||||
});
|
||||
|
||||
export function convertToStorableLinks(content: string, path: string[]): string
|
||||
{
|
||||
return content.replaceAll(/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/g, (e: string, a1?: string, a2?: string , a3?: string) => {
|
||||
const parsed = parsePath(a1 ?? '%%%%----%%%%----%%%%');
|
||||
const replacer = path.find(e => e.endsWith(parsed));
|
||||
const value = `[[${replacer ?? ''}${a2 ?? ''}${(!a3 && replacer !== parsed ? '|' + a1 : a3) ?? ''}]]`;
|
||||
return value;
|
||||
});
|
||||
}
|
||||
62
server/api/file/content/[path].get.ts
Normal file
62
server/api/file/content/[path].get.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { explorerContentTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const path = decodeURIComponent(getRouterParam(e, "path") ?? '');
|
||||
const query = getQuery(e);
|
||||
|
||||
if(!path)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const content = db.select({
|
||||
'content': sql<string>`cast(${explorerContentTable.content} as TEXT)`.as('content'),
|
||||
'private': explorerContentTable.private,
|
||||
'owner': explorerContentTable.owner,
|
||||
'visit': explorerContentTable.visit,
|
||||
}).from(explorerContentTable).where(eq(explorerContentTable.path, sql.placeholder('path'))).prepare().get({ path });
|
||||
|
||||
if(content !== undefined)
|
||||
{
|
||||
const session = await getUserSession(e);
|
||||
|
||||
if(content.private && (!session || !session.user))
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
if(session && session.user && content.private && session.user.id !== content.owner)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
if(query.type === 'view')
|
||||
{
|
||||
db.update(explorerContentTable).set({ visit: content.visit + 1 }).where(eq(explorerContentTable.path, path)).run();
|
||||
}
|
||||
if(query.type === 'editing')
|
||||
{
|
||||
content.content = convertFromStorableLinks(content.content);
|
||||
}
|
||||
|
||||
return { content: content.content };
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
});
|
||||
|
||||
export function convertFromStorableLinks(content: string): string
|
||||
{
|
||||
/*return content.replaceAll(/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/g, (e: string, a1?: string, a2?: string , a3?: string) => {
|
||||
const parsed = parsePath(a1 ?? '%%%%----%%%%----%%%%');
|
||||
const replacer = path.find(e => e.endsWith(parsed)) ?? parsed;
|
||||
const value = `[[${replacer}${a2 ?? ''}${(!a3 && replacer !== parsed ? '|' + a1 : a3) ?? ''}]]`;
|
||||
return value;
|
||||
});*/
|
||||
return content;
|
||||
}
|
||||
@@ -18,7 +18,6 @@ export default defineEventHandler(async (e) => {
|
||||
'owner': explorerContentTable.owner,
|
||||
'title': explorerContentTable.title,
|
||||
'type': explorerContentTable.type,
|
||||
'content': sql<string>`cast(${explorerContentTable.content} as TEXT)`.as('content'),
|
||||
'navigable': explorerContentTable.navigable,
|
||||
'private': explorerContentTable.private,
|
||||
'order': explorerContentTable.order,
|
||||
@@ -27,8 +26,19 @@ export default defineEventHandler(async (e) => {
|
||||
|
||||
if(content !== undefined)
|
||||
{
|
||||
db.update(explorerContentTable).set({ visit: content.visit + 1 }).where(eq(explorerContentTable.path, content.path)).run();
|
||||
const session = await getUserSession(e);
|
||||
|
||||
if(content.private && (!session || !session.user))
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
if(session && session.user && content.private && session.user.id !== content.owner)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { extname, basename } from 'node:path';
|
||||
import type { FileType } from '~/types/api';
|
||||
import type { CanvasColor, CanvasContent } from "~/types/canvas";
|
||||
import { explorerContentTable } from "~/db/schema";
|
||||
import { convertToStorableLinks } from "../api/file.post";
|
||||
|
||||
const typeMapping: Record<string, FileType> = {
|
||||
".md": "markdown",
|
||||
@@ -27,7 +28,7 @@ export default defineTask({
|
||||
}
|
||||
}) as { tree: any[] } & Record<string, any>;
|
||||
|
||||
const files: typeof explorerContentTable.$inferInsert = await Promise.all(tree.tree.filter((e: any) => !e.path.startsWith(".")).map(async (e, i) => {
|
||||
const files: typeof explorerContentTable.$inferInsert[] = await Promise.all(tree.tree.filter((e: any) => !e.path.startsWith(".")).map(async (e, i) => {
|
||||
if(e.type === 'tree')
|
||||
{
|
||||
const title = basename(e.path);
|
||||
@@ -63,11 +64,17 @@ export default defineTask({
|
||||
}
|
||||
}));
|
||||
|
||||
const pathList = files.map(e => e.path);
|
||||
files.forEach(e => {
|
||||
if(e.type !== 'folder' && e.content)
|
||||
{
|
||||
e.content = Buffer.from(convertToStorableLinks(e.content.toString('utf-8'), files.map(e => e.path)), 'utf-8');
|
||||
}
|
||||
})
|
||||
|
||||
const db = useDatabase();
|
||||
db.delete(explorerContentTable).run();
|
||||
db.insert(explorerContentTable).values(files).run();
|
||||
|
||||
useStorage('cache').clear();
|
||||
|
||||
return { result: true };
|
||||
}
|
||||
@@ -85,6 +92,9 @@ function reshapeContent(content: string, type: FileType): string | null
|
||||
switch(type)
|
||||
{
|
||||
case "markdown":
|
||||
return content.replaceAll(/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/g, (e: string, a1?: string, a2?: string , a3?: string) => {
|
||||
return `[[${a1?.split('/').map(f => { const check = /(\d+)\. ?(.+)/gsmi.exec(f); return check && check[2] ? check[2] : f }).join('/') ?? ''}${a2 ?? ''}${a3 ?? ''}]]`;
|
||||
});
|
||||
case "file":
|
||||
return content;
|
||||
case "canvas":
|
||||
|
||||
Reference in New Issue
Block a user