11import type { FrontMatterCache , TFile } from "obsidian" ;
22import type { default as DiscourseGraphPlugin } from "~/index" ;
33import { getLoggedInClient , getSupabaseContext } from "./supabaseContext" ;
4+ import { addFile } from "@repo/database/lib/files" ;
5+ import mime from "mime-types" ;
46
57export const publishNode = async ( {
68 plugin,
@@ -26,21 +28,80 @@ export const publishNode = async ({
2628 if ( ! myGroup ) throw new Error ( "Cannot get group" ) ;
2729 const existingPublish =
2830 ( frontmatter . publishedToGroups as undefined | string [ ] ) || [ ] ;
29- if ( existingPublish . includes ( myGroup ) ) return ; // already published
30- const publishResponse = await client . from ( "ContentAccess" ) . insert ( {
31- /* eslint-disable @typescript-eslint/naming-convention */
32- account_uid : myGroup ,
33- source_local_id : nodeId ,
34- space_id : spaceId ,
35- /* eslint-enable @typescript-eslint/naming-convention */
36- } ) ;
31+ const idResponse = await client
32+ . from ( "Content" )
33+ . select ( "id,last_modified" )
34+ . eq ( "source_local_id" , nodeId )
35+ . eq ( "space_id" , spaceId )
36+ . eq ( "variant" , "full" )
37+ . maybeSingle ( ) ;
38+ if ( idResponse . error || ! idResponse . data ) {
39+ throw idResponse . error || new Error ( "no data while fetching node" ) ;
40+ }
41+ const contentId = idResponse . data . id ;
42+ const lastModifiedDb = new Date ( idResponse . data . last_modified + "Z" ) ;
43+ if (
44+ existingPublish . includes ( myGroup ) &&
45+ file . stat . mtime <= lastModifiedDb . getTime ( )
46+ )
47+ return ; // already published
48+ const publishResponse = await client . from ( "ContentAccess" ) . upsert (
49+ {
50+ /* eslint-disable @typescript-eslint/naming-convention */
51+ account_uid : myGroup ,
52+ source_local_id : nodeId ,
53+ space_id : spaceId ,
54+ /* eslint-enable @typescript-eslint/naming-convention */
55+ } ,
56+ { ignoreDuplicates : true } ,
57+ ) ;
3758 if ( publishResponse . error && publishResponse . error . code !== "23505" )
3859 // 23505 is duplicate key, which counts as a success.
3960 throw publishResponse . error ;
40- await plugin . app . fileManager . processFrontMatter (
41- file ,
42- ( fm : Record < string , unknown > ) => {
43- fm . publishedToGroups = [ ...existingPublish , myGroup ] ;
44- } ,
45- ) ;
61+
62+ const existingFiles : string [ ] = [ ] ;
63+ const embeds = plugin . app . metadataCache . getFileCache ( file ) ?. embeds ?? [ ] ;
64+ for ( const { link } of embeds ) {
65+ const attachment = plugin . app . metadataCache . getFirstLinkpathDest (
66+ link ,
67+ file . path ,
68+ ) ;
69+ if ( attachment === null ) {
70+ console . warn ( "Could not find file for " + link ) ;
71+ continue ;
72+ }
73+ const mimetype = mime . lookup ( attachment . path ) || "application/octet-stream" ;
74+ if ( mimetype . startsWith ( "text/" ) ) continue ;
75+ existingFiles . push ( attachment . path ) ;
76+ const content = await plugin . app . vault . readBinary ( attachment ) ;
77+ await addFile ( {
78+ client,
79+ spaceId,
80+ contentId,
81+ fname : attachment . path ,
82+ mimetype,
83+ created : new Date ( attachment . stat . ctime ) ,
84+ lastModified : new Date ( attachment . stat . mtime ) ,
85+ content,
86+ } ) ;
87+ }
88+ let cleanupCommand = client
89+ . from ( "FileReference" )
90+ . delete ( )
91+ . eq ( "content_id" , contentId ) ;
92+ if ( existingFiles . length )
93+ cleanupCommand = cleanupCommand . notIn ( "filepath" , [
94+ ...new Set ( existingFiles ) ,
95+ ] ) ;
96+ const cleanupResult = await cleanupCommand ;
97+ // do not fail on cleanup
98+ if ( cleanupResult . error ) console . error ( cleanupResult . error ) ;
99+
100+ if ( ! existingPublish . includes ( myGroup ) )
101+ await plugin . app . fileManager . processFrontMatter (
102+ file ,
103+ ( fm : Record < string , unknown > ) => {
104+ fm . publishedToGroups = [ ...existingPublish , myGroup ] ;
105+ } ,
106+ ) ;
46107} ;
0 commit comments