···2323 // Check publication and document ownership in one query
2424 let { data: tokenData } = await supabaseServerClient
2525 .from("permission_tokens")
2626- .select(`
2626+ .select(
2727+ `
2728 id,
2829 leaflets_in_publications(publication, publications!inner(identity_did)),
2930 leaflets_to_documents(document, documents!inner(uri))
3030- `)
3131+ `,
3232+ )
3133 .eq("id", permission_token.id)
3234 .single();
3335···3638 const leafletInPubs = tokenData.leaflets_in_publications || [];
3739 if (leafletInPubs.length > 0) {
3840 if (!identity) {
3939- throw new Error("Unauthorized: You must be logged in to delete a leaflet in a publication");
4141+ throw new Error(
4242+ "Unauthorized: You must be logged in to delete a leaflet in a publication",
4343+ );
4044 }
4145 const isOwner = leafletInPubs.some(
4242- (pub: any) => pub.publications.identity_did === identity.atp_did
4646+ (pub: any) => pub.publications.identity_did === identity.atp_did,
4347 );
4448 if (!isOwner) {
4545- throw new Error("Unauthorized: You must own the publication to delete this leaflet");
4949+ throw new Error(
5050+ "Unauthorized: You must own the publication to delete this leaflet",
5151+ );
4652 }
4753 }
48544955 // Check if there's a standalone published document
5050- const leafletDocs = tokenData.leaflets_to_documents || [];
5151- if (leafletDocs.length > 0) {
5252- if (!identity) {
5353- throw new Error("Unauthorized: You must be logged in to delete a published leaflet");
5656+ const leafletDoc = tokenData.leaflets_to_documents;
5757+ if (leafletDoc && leafletDoc.document) {
5858+ if (!identity || !identity.atp_did) {
5959+ throw new Error(
6060+ "Unauthorized: You must be logged in to delete a published leaflet",
6161+ );
5462 }
5555- for (let leafletDoc of leafletDocs) {
5656- const docUri = leafletDoc.documents?.uri;
5757- // Extract the DID from the document URI (format: at://did:plc:xxx/...)
5858- if (docUri && !docUri.includes(identity.atp_did)) {
5959- throw new Error("Unauthorized: You must own the published document to delete this leaflet");
6060- }
6363+ const docUri = leafletDoc.documents?.uri;
6464+ // Extract the DID from the document URI (format: at://did:plc:xxx/...)
6565+ if (docUri && !docUri.includes(identity.atp_did)) {
6666+ throw new Error(
6767+ "Unauthorized: You must own the published document to delete this leaflet",
6868+ );
6169 }
6270 }
6371 }
···7381 .where(eq(permission_tokens.id, permission_token.id));
74827583 if (!token?.permission_token_rights?.write) return;
7676- await tx
7777- .delete(entities)
7878- .where(eq(entities.set, token.permission_token_rights.entity_set));
8484+ const entitySet = token.permission_token_rights.entity_set;
8585+ if (!entitySet) return;
8686+ await tx.delete(entities).where(eq(entities.set, entitySet));
7987 await tx
8088 .delete(permission_tokens)
8189 .where(eq(permission_tokens.id, permission_token.id));
+3
actions/publications/moveLeafletToPublication.ts
···1111) {
1212 let identity = await getIdentityData();
1313 if (!identity || !identity.atp_did) return null;
1414+1515+ // Verify publication ownership
1416 let { data: publication } = await supabaseServerClient
1517 .from("publications")
1618 .select("*")
···1820 .single();
1921 if (publication?.identity_did !== identity.atp_did) return;
20222323+ // Save as a publication draft
2124 await supabaseServerClient.from("leaflets_in_publications").insert({
2225 publication: publication_uri,
2326 leaflet: leaflet_id,
+26
actions/publications/saveLeafletDraft.ts
···11+"use server";
22+33+import { getIdentityData } from "actions/getIdentityData";
44+import { supabaseServerClient } from "supabase/serverClient";
55+66+export async function saveLeafletDraft(
77+ leaflet_id: string,
88+ metadata: { title: string; description: string },
99+ entitiesToDelete: string[],
1010+) {
1111+ let identity = await getIdentityData();
1212+ if (!identity || !identity.atp_did) return null;
1313+1414+ // Save as a looseleaf draft in leaflets_to_documents with null document
1515+ await supabaseServerClient.from("leaflets_to_documents").upsert({
1616+ leaflet: leaflet_id,
1717+ document: null,
1818+ title: metadata.title,
1919+ description: metadata.description,
2020+ });
2121+2222+ await supabaseServerClient
2323+ .from("entities")
2424+ .delete()
2525+ .in("id", entitiesToDelete);
2626+}
+3-3
app/(home-pages)/home/HomeLayout.tsx
···136136 (acc, tok) => {
137137 let title =
138138 tok.permission_tokens.leaflets_in_publications[0]?.title ||
139139- tok.permission_tokens.leaflets_to_documents[0]?.title;
139139+ tok.permission_tokens.leaflets_to_documents?.title;
140140 if (title) acc[tok.permission_tokens.root_entity] = title;
141141 return acc;
142142 },
···233233 value={{
234234 ...leaflet,
235235 leaflets_in_publications: leaflet.leaflets_in_publications || [],
236236- leaflets_to_documents: leaflet.leaflets_to_documents || [],
236236+ leaflets_to_documents: leaflet.leaflets_to_documents || null,
237237 blocked_by_admin: null,
238238 custom_domain_routes: [],
239239 }}
···292292 ({ token: leaflet, archived: archived }) => {
293293 let published =
294294 !!leaflet.leaflets_in_publications?.find((l) => l.doc) ||
295295- !!leaflet.leaflets_to_documents?.find((l) => l.document);
295295+ !!leaflet.leaflets_to_documents?.document;
296296 let drafts = !!leaflet.leaflets_in_publications?.length && !published;
297297 let docs = !leaflet.leaflets_in_publications?.length && !archived;
298298 // If no filters are active, show all
+1-1
app/(home-pages)/home/page.tsx
···3030 (acc, tok) => {
3131 let title =
3232 tok.permission_tokens.leaflets_in_publications[0]?.title ||
3333- tok.permission_tokens.leaflets_to_documents[0]?.title;
3333+ tok.permission_tokens.leaflets_to_documents?.title;
3434 if (title) acc[tok.permission_tokens.root_entity] = title;
3535 return acc;
3636 },