diff --git a/src/lib/pages/server.ts b/src/lib/pages/server.ts index 36fd86e..91d8ba4 100644 --- a/src/lib/pages/server.ts +++ b/src/lib/pages/server.ts @@ -43,7 +43,8 @@ async function get(link: ExactLink): Promise { async function getLoroSnapshot(link: ExactLink): Promise { const ent = await leafClient.get_components(link, LoroCommonMark); - return ent?.get(LoroCommonMark)?.value; + const v = ent?.get(LoroCommonMark)?.value; + return v ? new Uint8Array(v) : undefined; } async function save( diff --git a/src/routes/(app)/[username]/[slug]/+page.server.ts b/src/routes/(app)/[username]/[slug]/+page.server.ts index 61f66a3..f8c000f 100644 --- a/src/routes/(app)/[username]/[slug]/+page.server.ts +++ b/src/routes/(app)/[username]/[slug]/+page.server.ts @@ -26,6 +26,9 @@ export const load: PageServerLoad = async ({ params }): Promise<{ page: Page }> export const actions = { default: async ({ request, params, url, fetch }) => { + const { sessionInfo } = await getSession(fetch, request); + if (!sessionInfo) return redirect(302, `/login?to=${url}`); + const fullUsername = usernames.fullDomain(params.username); const subspace = await usernames.getSubspace(fullUsername); if (!subspace) return error(404, `User not found: ${fullUsername}`); @@ -35,9 +38,6 @@ export const actions = { const oldEnt = await leafClient.get_components(oldPageLink, WeirdWikiPage); const isWikiPage = !!oldEnt?.get(WeirdWikiPage); - const { sessionInfo } = await getSession(fetch, request); - if (!sessionInfo) return redirect(302, `/login?to=${url}`); - const editorIsOwner = sessionInfo.user_id == (await usernames.getRauthyId(fullUsername)); // If this isn't a wiki page, we need to make sure that only the author can edit the page. diff --git a/src/routes/(app)/[username]/[slug]/+page.svelte b/src/routes/(app)/[username]/[slug]/+page.svelte index 1590351..17310ce 100644 --- a/src/routes/(app)/[username]/[slug]/+page.svelte +++ b/src/routes/(app)/[username]/[slug]/+page.svelte @@ -17,6 +17,7 @@ import type { Page, PageSaveReq } from '$lib/pages/types'; import { LoroDoc } from 'loro-crdt'; import base64 from 'base64-js'; + import { checkResponse } from '$lib/utils/http'; const { data, form }: { data: PageData; form: ActionData } = $props(); @@ -24,6 +25,7 @@ editing: false, page: data.page }); + let previousLoroSnapshot = $state(undefined) as Uint8Array | undefined; const slugifiedSlug = $derived( slugify(editingState.page.slug || editingState.page.name || 'untitled', { @@ -32,8 +34,11 @@ }) ); - function startEdit() { + async function startEdit() { if (data.profileMatchesUserSession || data.page.wiki) { + const resp = await fetch(`/${$page.params.username}/${$page.params.slug}/loroSnapshot`); + await checkResponse(resp); + previousLoroSnapshot = new Uint8Array(await resp.arrayBuffer()); editingState.page = data.page; editingState.editing = true; } @@ -55,11 +60,11 @@ let formDataInput: HTMLInputElement = $state(undefined) as unknown as HTMLInputElement; async function handleSubmit() { const doc = new LoroDoc(); + doc.setRecordTimestamp(true); + if (previousLoroSnapshot) doc.import(previousLoroSnapshot); const content = doc.getText('content'); - content.delete(0, 10e30); + content.delete(0, content.length); content.insert(0, editingState.page.markdown); - console.log('markdown', editingState.page.markdown); - console.log('doc', content.toString()); const out: PageSaveReq = { name: editingState.page.name, slug: slugifiedSlug, diff --git a/src/routes/(app)/[username]/[slug]/loroSnapshot/+server.ts b/src/routes/(app)/[username]/[slug]/loroSnapshot/+server.ts index 2863e60..a48a8d2 100644 --- a/src/routes/(app)/[username]/[slug]/loroSnapshot/+server.ts +++ b/src/routes/(app)/[username]/[slug]/loroSnapshot/+server.ts @@ -1,15 +1,21 @@ import { subspace_link } from '$lib/leaf'; import { pages } from '$lib/pages/server'; +import { getSession } from '$lib/rauthy/server'; import { usernames } from '$lib/usernames'; import { error, type RequestHandler } from '@sveltejs/kit'; -export const GET: RequestHandler = async ({ request, fetch, params, url }) => { - const fullUsername = usernames.fullDomain(params.username!); +export const GET: RequestHandler = async ({ params, request, fetch }) => { + const { sessionInfo } = await getSession(fetch, request); + if (!sessionInfo) return error(403, `Not logged in`); + + const fullUsername = await usernames.getByRauthyId(sessionInfo.user_id); + if (!fullUsername) return error(404, `User not found`); const subspace = await usernames.getSubspace(fullUsername); if (!subspace) return error(404, `User not found: ${fullUsername}`); const pageLink = subspace_link(subspace, params.slug!); const snapshot = await pages.getLoroSnapshot(pageLink); + if (!snapshot) return error(404, `Snapshot not found`); - return new Response(); + return new Response(snapshot); }; diff --git a/src/routes/(app)/[username]/[slug]/revisions/+page.svelte b/src/routes/(app)/[username]/[slug]/revisions/+page.svelte new file mode 100644 index 0000000..aeadbf0 --- /dev/null +++ b/src/routes/(app)/[username]/[slug]/revisions/+page.svelte @@ -0,0 +1,103 @@ + + +
+
+

+ Revisions for {$page.params.slug} +

+ + {#if loroDoc} + + +
+
+ {@html renderMarkdownSanitized(markdown)} +
+
+ {:else} +
+ +
+ {/if} +
+
diff --git a/src/routes/(app)/[username]/new/+page.svelte b/src/routes/(app)/[username]/new/+page.svelte index 5d83747..ae7a796 100644 --- a/src/routes/(app)/[username]/new/+page.svelte +++ b/src/routes/(app)/[username]/new/+page.svelte @@ -38,6 +38,7 @@ let formDataInput: HTMLInputElement; function handleSubmit(_e: SubmitEvent) { const doc = new LoroDoc(); + doc.setRecordTimestamp(true); const content = doc.getText('content'); content.delete(0, 10e30); content.insert(0, page.markdown);