You've already forked obsidian-visualiser
Update DB schema to include an ID and split overview and content. Progressing on ContentEditor with the ID fixing many issues. Adding modal and sync features.
This commit is contained in:
47
server/api/file/content/[id].get.ts
Normal file
47
server/api/file/content/[id].get.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { projectFilesTable as files, projectContentTable as content } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
try
|
||||
{
|
||||
const id = getRouterParam(e, "id") ?? '';
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const data = db.select({ content: sql<string>`cast(${content.content} as TEXT)`.as('content'), private: files.private, owner: files.owner, }).from(content).leftJoin(files, eq(content.id, files.id)).where(eq(content.id, id)).get();
|
||||
|
||||
if(data && data.content)
|
||||
{
|
||||
const session = await getUserSession(e);
|
||||
|
||||
if(!session || !session.user || session.user.id !== data.owner)
|
||||
{
|
||||
if(data.private)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return data.content.replace(/%%(.+?)%%/g, "");
|
||||
}
|
||||
}
|
||||
|
||||
return data.content;
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
catch(_e)
|
||||
{
|
||||
console.error(_e);
|
||||
setResponseStatus(e, 500);
|
||||
return;
|
||||
}
|
||||
});
|
||||
43
server/api/file/content/[id].post.ts
Normal file
43
server/api/file/content/[id].post.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { hasPermissions } from '#shared/auth.util';
|
||||
import { projectContentTable, projectFilesTable } from '~/db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const { user } = await getUserSession(e);
|
||||
|
||||
if(!user || !hasPermissions(user.permissions, ['admin', 'editor']))
|
||||
{
|
||||
throw createError({ statusCode: 401, statusText: 'Unauthorized' });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const id = getRouterParam(e, "id") ?? '';
|
||||
const body = await readRawBody(e);
|
||||
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const item = db.select({ id: projectFilesTable.id }).from(projectFilesTable).where(eq(projectFilesTable.id, id)).get();
|
||||
|
||||
if(!item)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
db.insert(projectContentTable).values({ id: id, content: body }).onConflictDoUpdate({ set: { content: body }, target: projectContentTable.id }).run();
|
||||
db.update(projectFilesTable).set({ timestamp: new Date() }).where(eq(projectFilesTable.id, id)).run()
|
||||
}
|
||||
catch(_e)
|
||||
{
|
||||
console.error(_e);
|
||||
setResponseStatus(e, 500);
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
import { eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { explorerContentTable } from '~/db/schema';
|
||||
import { Content } from '~/shared/content.util';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
try
|
||||
{
|
||||
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,
|
||||
'type': explorerContentTable.type,
|
||||
'owner': explorerContentTable.owner,
|
||||
'visit': explorerContentTable.visit,
|
||||
}).from(explorerContentTable).where(eq(explorerContentTable.path, sql.placeholder('path'))).prepare().get({ path });
|
||||
|
||||
if(content != undefined && content.content != undefined)
|
||||
{
|
||||
const session = await getUserSession(e);
|
||||
|
||||
if(!session || !session.user || session.user.id !== content.owner)
|
||||
{
|
||||
if(content.private)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
content.content = content.content.replace(/%%(.+)%%/g, "");
|
||||
}
|
||||
}
|
||||
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.fromString(content as any, content.content);
|
||||
}
|
||||
|
||||
console.log(content);
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}
|
||||
catch(_e)
|
||||
{
|
||||
console.error(_e);
|
||||
setResponseStatus(e, 500);
|
||||
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;
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { getTableColumns } from 'drizzle-orm';
|
||||
import { explorerContentTable } from '~/db/schema';
|
||||
import { projectFilesTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const { user } = await getUserSession(e);
|
||||
|
||||
const db = useDatabase();
|
||||
const { content: _, ...columns } = getTableColumns(explorerContentTable);
|
||||
const content = db.select(columns).from(explorerContentTable).all();
|
||||
const content = db.select().from(projectFilesTable).all();
|
||||
|
||||
content.sort((a, b) => {
|
||||
return a.path.split('/').length - b.path.split('/').length;
|
||||
@@ -36,6 +34,5 @@ export default defineEventHandler(async (e) => {
|
||||
return content.filter(e => !!e);
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
return [];
|
||||
});
|
||||
76
server/api/file/overview.post.ts
Normal file
76
server/api/file/overview.post.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { hasPermissions } from "#shared/auth.util";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { projectFilesTable } from "~/db/schema";
|
||||
import { Project } from "~/schemas/project";
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const { user } = await getUserSession(e);
|
||||
|
||||
if(!user || !hasPermissions(user.permissions, ['admin', 'editor']))
|
||||
{
|
||||
throw createError({ statusCode: 401, statusText: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const body = await readValidatedBody(e, Project.safeParse);
|
||||
|
||||
if(!body.success)
|
||||
{
|
||||
throw body.error;
|
||||
}
|
||||
|
||||
const db = useDatabase(), items = body.data, blocked: string[] = [];
|
||||
|
||||
db.transaction((tx) => {
|
||||
const data = tx.select({ id: projectFilesTable.id, timestamp: projectFilesTable.timestamp }).from(projectFilesTable).all();
|
||||
const deletion = tx.delete(projectFilesTable).where(eq(projectFilesTable.id, sql.placeholder('id'))).prepare();
|
||||
|
||||
for(let i = 0; i < items.length; i++)
|
||||
{
|
||||
const item = items[i];
|
||||
|
||||
const index = data.findIndex(e => e.id === item.id);
|
||||
|
||||
if(index !== -1)
|
||||
{
|
||||
if(data[index].timestamp > new Date(item.timestamp))
|
||||
{
|
||||
blocked.push(item.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
data.splice(index, 1);
|
||||
}
|
||||
|
||||
tx.insert(projectFilesTable).values({
|
||||
id: item.id,
|
||||
path: item.path,
|
||||
owner: user.id,
|
||||
title: item.title,
|
||||
type: item.type,
|
||||
navigable: item.navigable,
|
||||
private: item.private,
|
||||
order: item.order,
|
||||
}).onConflictDoUpdate({
|
||||
set: {
|
||||
id: item.id,
|
||||
path: item.path,
|
||||
title: item.title,
|
||||
type: item.type,
|
||||
navigable: item.navigable,
|
||||
private: item.private,
|
||||
order: item.order,
|
||||
timestamp: new Date(),
|
||||
},
|
||||
target: projectFilesTable.id,
|
||||
}).run();
|
||||
}
|
||||
|
||||
for(let i = 0; i < data.length; i++)
|
||||
{
|
||||
deletion.run({ id: data[i].id });
|
||||
}
|
||||
});
|
||||
|
||||
return blocked;
|
||||
});
|
||||
@@ -1,11 +1,11 @@
|
||||
import { eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { explorerContentTable } from '~/db/schema';
|
||||
import { projectFilesTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const path = decodeURIComponent(getRouterParam(e, "path") ?? '');
|
||||
export default defineCachedEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id") ?? '';
|
||||
|
||||
if(!path)
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
@@ -14,13 +14,14 @@ export default defineEventHandler(async (e) => {
|
||||
const db = useDatabase();
|
||||
|
||||
const content = db.select({
|
||||
'path': explorerContentTable.path,
|
||||
'owner': explorerContentTable.owner,
|
||||
'title': explorerContentTable.title,
|
||||
'type': explorerContentTable.type,
|
||||
'navigable': explorerContentTable.navigable,
|
||||
'private': explorerContentTable.private,
|
||||
}).from(explorerContentTable).where(eq(explorerContentTable.path, sql.placeholder('path'))).prepare().get({ path });
|
||||
'id': projectFilesTable.id,
|
||||
'path': projectFilesTable.path,
|
||||
'owner': projectFilesTable.owner,
|
||||
'title': projectFilesTable.title,
|
||||
'type': projectFilesTable.type,
|
||||
'navigable': projectFilesTable.navigable,
|
||||
'private': projectFilesTable.private,
|
||||
}).from(projectFilesTable).where(eq(projectFilesTable.id, sql.placeholder('id'))).prepare().get({ id });
|
||||
|
||||
if(content !== undefined)
|
||||
{
|
||||
@@ -47,4 +48,4 @@ export default defineEventHandler(async (e) => {
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
});
|
||||
}, { getKey: (e) => getRouterParam(e, "id") ?? '', });
|
||||
Reference in New Issue
Block a user