From bdc04db4b3f42101ff7e5899ece6f1e17751b642 Mon Sep 17 00:00:00 2001 From: pike Date: Mon, 25 Dec 2023 22:28:40 +0100 Subject: [PATCH 1/7] feat: Properly handle changes on prepare --- src/models/Folder.ts | 1 + src/models/Platform.ts | 18 ++++++++++-- src/models/Post.ts | 63 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/models/Folder.ts b/src/models/Folder.ts index d427c47..ecce2e0 100644 --- a/src/models/Folder.ts +++ b/src/models/Folder.ts @@ -113,6 +113,7 @@ export default class Folder { export interface FileInfo { name: string; + original?: string; basename: string; extension: string; group: string; diff --git a/src/models/Platform.ts b/src/models/Platform.ts index a5d211a..6697fe5 100644 --- a/src/models/Platform.ts +++ b/src/models/Platform.ts @@ -122,6 +122,10 @@ export default class Platform { * * Do not throw errors. Instead, catch and log them, * and set the post.valid to false + * + * Presume the post may have already been prepared + * before, and manually adapted later. For example, + * post.skip may have manually been set to true. * @param folder - the folder for which to prepare a post for this platform * @returns the prepared post */ @@ -137,9 +141,19 @@ export default class Platform { } // some default logic. override this - // in your own platform if you need. + // in your own platform if you want; + // but more likely, call super.preparePost + // before adding your own logic. + + // always update the files, they may have changed + // on disk; but also maintain some properties that may have + // been changed manually + + post.purgeFiles(); + const files = await folder.getFiles(); + files.forEach((file) => post.putFile(file)); + post.reorderFiles(); - post.files = await folder.getFiles(); const textFiles = post.getFiles("text"); if (post.hasFile("body.txt")) { diff --git a/src/models/Post.ts b/src/models/Post.ts index 031a80c..da721e9 100644 --- a/src/models/Post.ts +++ b/src/models/Post.ts @@ -26,6 +26,7 @@ export default class Post { body?: string; tags?: string; files?: FileInfo[]; + ignoreFiles?: string[]; link?: string; remoteId?: string; @@ -37,6 +38,7 @@ export default class Post { Object.assign(this, data); this.scheduled = this.scheduled ? new Date(this.scheduled) : undefined; this.published = this.published ? new Date(this.published) : undefined; + this.ignoreFiles = this.ignoreFiles ?? []; } const assetsPath = this.getFilePath(platform.assetsFolder()); if (!fs.existsSync(assetsPath)) { @@ -143,22 +145,73 @@ export default class Post { }); } + /** + * Remove all the files that do not exist (anymore) + */ + purgeFiles() { + this.getFiles().forEach((file) => { + if (file.original && !fs.existsSync(this.getFilePath(file.original))) { + Logger.info( + "Post", + "purgeFiles", + "purging non-existant derivate", + file.name, + ); + this.removeFile(file.name); + } + if (!fs.existsSync(this.getFilePath(file.name))) { + Logger.info( + "Post", + "purgeFiles", + "purging non-existant file", + file.name, + ); + this.removeFile(file.name); + } + }); + } + + /** + * reindex file ordering to remove doubles + */ + reorderFiles() { + this.files + .sort((a, b) => a.order - b.order) + .forEach((file, index) => { + file.order = index; + }); + } + /** * @param name the name of the file - * @returns the files info + * @returns wether the file exists */ hasFile(name: string): boolean { return this.getFile(name) !== undefined; } /** - * @param name the name of the file - * @returns the files info + * @param name - the name of the file + * @returns the files info if any */ getFile(name: string): FileInfo | undefined { return this.files.find((file) => file.name === name); } + /** + * @param file - the fileinfo to add or replace + */ + putFile(file: FileInfo) { + const oldFile = this.files.find( + (oldfile) => oldfile.name === file.name || oldfile.original === file.name, + ); + if (oldFile) { + file.order = oldFile.order; + this.removeFile(oldFile.name); + } + this.files.push(file); + } + /** * @param name the name of the file to remove */ @@ -175,7 +228,9 @@ export default class Post { const index = this.files.findIndex((file) => file.name === search); if (index > -1) { const oldFile = this.getFile(search); - this.files[index] = await this.folder.getFile(replace, oldFile.order); + const newFile = await this.folder.getFile(replace, oldFile.order); + newFile.original = oldFile.name; + this.files[index] = newFile; } return this.files[index]; } From d49cdbd3ee62f70ed4d1ab96d6b2c197939ea7f1 Mon Sep 17 00:00:00 2001 From: pike Date: Mon, 25 Dec 2023 22:33:40 +0100 Subject: [PATCH 2/7] feat: Support for ignoreFiles --- src/models/Platform.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/models/Platform.ts b/src/models/Platform.ts index 6697fe5..445cf85 100644 --- a/src/models/Platform.ts +++ b/src/models/Platform.ts @@ -151,7 +151,11 @@ export default class Platform { post.purgeFiles(); const files = await folder.getFiles(); - files.forEach((file) => post.putFile(file)); + files.forEach((file) => { + if (!post.ignoreFiles.includes(file.name)) { + post.putFile(file); + } + }); post.reorderFiles(); const textFiles = post.getFiles("text"); From bc36b146cbe5c70215174d2ef4e0be553c807483 Mon Sep 17 00:00:00 2001 From: pike Date: Mon, 25 Dec 2023 22:55:05 +0100 Subject: [PATCH 3/7] feat: Adding support for Post.skip --- src/models/Feed.ts | 49 ++++++++++++++++++++++++++++++++++------------ src/models/Post.ts | 3 ++- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/models/Feed.ts b/src/models/Feed.ts index 72278a4..89a021c 100644 --- a/src/models/Feed.ts +++ b/src/models/Feed.ts @@ -316,6 +316,9 @@ export default class Feed { if (!post.valid) { throw Logger.error("Post is not valid"); } + if (post.skip) { + throw Logger.error("Post is marked to be skipped"); + } if (post.status !== PostStatus.UNSCHEDULED) { throw Logger.error("Post is not unscheduled"); } @@ -350,6 +353,9 @@ export default class Feed { if (!post.valid) { throw Logger.error("Post is not valid"); } + if (post.skip) { + throw Logger.error("Post is marked to be skipped"); + } if (post.status !== PostStatus.UNSCHEDULED) { throw Logger.error("Post is not unscheduled"); } @@ -363,7 +369,7 @@ export default class Feed { /** * Publish single post * - * Will publish the post regardless of its status + * Will publish the post regardless of its status or skip * @param path - path to a single folder * @param platformId - the platform for the post * @param dryrun - wether or not to really publish @@ -380,13 +386,13 @@ export default class Feed { const platform = this.getPlatform(platformId); const folder = this.getFolder(path); const post = platform.getPost(folder); - if (post.valid) { - if (!dryrun) post.schedule(now); - Logger.info("Posting", platformId, path); - await platform.publishPost(post, dryrun); - } else { + if (!post.valid) { throw Logger.error("Post is not valid"); } + if (!dryrun) post.schedule(now); + Logger.info("Posting", platformId, path); + await platform.publishPost(post, dryrun); + return post; } @@ -416,12 +422,16 @@ export default class Feed { for (const folder of folders) { const post = platform.getPost(folder); if (post.valid) { - post.schedule(now); - Logger.trace("Posting", platform.id, folder.id); - await platform.publishPost(post, dryrun); - posts.push(post); + if (!post.skip) { + post.schedule(now); + Logger.trace("Posting", post.id); + await platform.publishPost(post, dryrun); + posts.push(post); + } else { + Logger.warn("Skipping post marked skip", post.id); + } } else { - Logger.warn("Skipping invalid post", platform.id, folder.id); + Logger.warn("Skipping invalid post", post.id); } } } @@ -500,7 +510,11 @@ export default class Feed { const nextDate = date ? date : this.getNextPostDate(platform.id); for (const folder of folders) { const post = platform.getPost(folder); - if (post.valid && post?.status === PostStatus.UNSCHEDULED) { + if ( + post.valid && + !post.skip && + post?.status === PostStatus.UNSCHEDULED + ) { post.schedule(nextDate); posts.push(post); break; @@ -538,8 +552,17 @@ export default class Feed { for (const folder of folders) { const post = platform.getPost(folder); if (post?.status === PostStatus.SCHEDULED) { + if (post.skip) { + Logger.warn( + "Not publishing scheduled post marked skip. Unscheduling post.", + post.id, + ); + post.status = PostStatus.UNSCHEDULED; + post.save(); + continue; + } if (post.scheduled <= now) { - console.log("Posting", platform.id, folder.id); + console.log("Posting", post.id); await platform.publishPost(post, dryrun); posts.push(post); break; diff --git a/src/models/Post.ts b/src/models/Post.ts index da721e9..89dea07 100644 --- a/src/models/Post.ts +++ b/src/models/Post.ts @@ -18,6 +18,7 @@ export default class Post { folder: Folder; platform: Platform; valid: boolean = false; + skip: boolean = false; status: PostStatus = PostStatus.UNKNOWN; scheduled?: Date; published?: Date; @@ -163,7 +164,7 @@ export default class Post { Logger.info( "Post", "purgeFiles", - "purging non-existant file", + "purging non-existent file", file.name, ); this.removeFile(file.name); From da9301403aa3d068a80356a811c4957d1e948d3e Mon Sep 17 00:00:00 2001 From: pike Date: Mon, 25 Dec 2023 23:06:14 +0100 Subject: [PATCH 4/7] fix: Some minor code impro --- src/models/Feed.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/models/Feed.ts b/src/models/Feed.ts index 89a021c..9ed1d45 100644 --- a/src/models/Feed.ts +++ b/src/models/Feed.ts @@ -511,9 +511,10 @@ export default class Feed { for (const folder of folders) { const post = platform.getPost(folder); if ( + post && post.valid && !post.skip && - post?.status === PostStatus.UNSCHEDULED + post.status === PostStatus.UNSCHEDULED ) { post.schedule(nextDate); posts.push(post); @@ -551,7 +552,7 @@ export default class Feed { for (const platform of platforms) { for (const folder of folders) { const post = platform.getPost(folder); - if (post?.status === PostStatus.SCHEDULED) { + if (post && post.status === PostStatus.SCHEDULED) { if (post.skip) { Logger.warn( "Not publishing scheduled post marked skip. Unscheduling post.", From 17a6a96906463d9a69a2e44fedf9d113e77dd3b1 Mon Sep 17 00:00:00 2001 From: pike Date: Tue, 26 Dec 2023 13:52:37 +0100 Subject: [PATCH 5/7] feat: Implement post.decompileBody and getCompiledBody .. .. and use that in the platforms --- src/models/Platform.ts | 18 ++++- src/models/Post.ts | 109 ++++++++++++++++++++++++++- src/platforms/Ayrshare/Ayrshare.ts | 4 +- src/platforms/Facebook/Facebook.ts | 6 +- src/platforms/Instagram/Instagram.ts | 6 +- src/platforms/LinkedIn/LinkedIn.ts | 12 +-- src/platforms/Reddit/Reddit.ts | 2 +- src/platforms/Twitter/Twitter.ts | 4 +- src/utilities.ts | 6 ++ 9 files changed, 144 insertions(+), 23 deletions(-) diff --git a/src/models/Platform.ts b/src/models/Platform.ts index 445cf85..5d428a4 100644 --- a/src/models/Platform.ts +++ b/src/models/Platform.ts @@ -171,13 +171,25 @@ export default class Platform { if (post.hasFile("title.txt")) { post.title = fs.readFileSync(post.folder.path + "/title.txt", "utf8"); - } else { - post.title = post.body.split("\n", 1)[0]; + } else if (post.hasFile("subject.txt")) { + post.title = fs.readFileSync(post.folder.path + "/subject.txt", "utf8"); } if (post.hasFile("tags.txt")) { - post.tags = fs.readFileSync(post.folder.path + "/tags.txt", "utf8"); + post.tags = fs + .readFileSync(post.folder.path + "/tags.txt", "utf8") + .split(/\s/); + } + if (post.hasFile("mentions.txt")) { + post.mentions = fs + .readFileSync(post.folder.path + "/mentions.txt", "utf8") + .split(/\s/); } + if (post.hasFile("geo.txt")) { + post.geo = fs.readFileSync(post.folder.path + "/geo.txt", "utf8"); + } + + post.decompileBody(); if (post.title) { post.valid = true; diff --git a/src/models/Post.ts b/src/models/Post.ts index 89dea07..ce6f3dd 100644 --- a/src/models/Post.ts +++ b/src/models/Post.ts @@ -4,6 +4,7 @@ import Folder, { FileInfo } from "./Folder"; import Logger from "../services/Logger"; import Platform from "./Platform"; +import { isSimilarArray } from "../utilities"; /** * Post - a post within a folder @@ -25,7 +26,9 @@ export default class Post { results: PostResult[] = []; title: string = ""; body?: string; - tags?: string; + tags?: string[]; + mentions?: string[]; + geo?: string; files?: FileInfo[]; ignoreFiles?: string[]; link?: string; @@ -93,6 +96,110 @@ export default class Post { this.save(); } + /** + * Check body for title, #tags, @mentions and %geo + * and store those in separate fields instead + */ + decompileBody() { + const lines = this.body.split("\n"); + + // chop title + const title = lines.shift(); + if (!this.title || this.title === title) { + this.title = title; + this.body = lines.join("\n"); + } + + // chop body tail for #tags, @mentions + // and %geo - any geo + + const rxtag = /#\S+/g; + const rxtags = /^\s*((#\S+)\s*)+$/g; + const rxmention = /@\S+/g; + const rxmentions = /^\s*((@\S+)\s*)+$/g; + const rxgeo = /^%geo\s+(.*)/i; + let line = ""; + while (lines.length) { + line = lines.pop(); + + if (!line.trim()) { + this.body = lines.join("\n"); + continue; + } + + if (line.match(rxtags)) { + const tags = line.match(rxtag); + if (!this.tags?.length || isSimilarArray(tags, this.tags)) { + this.tags = tags; + this.body = lines.join("\n"); + } + continue; + } + + if (line.match(rxmentions)) { + const mentions = line.match(rxmention); + if (!this.mentions?.length || isSimilarArray(mentions, this.mentions)) { + this.mentions = mentions; + this.body = lines.join("\n"); + } + continue; + } + + if (line.match(rxgeo)) { + const geo = line.match(rxgeo)[1] ?? ""; + if (!this.geo || this.geo === geo) { + this.geo = geo; + this.body = lines.join("\n"); + } + continue; + } + + break; + } + } + + /** + * Create a body containing the given arguments + * @param parts - any of 'title','body','tags','mentions','geo' + * prepending a ! to every part removes those parts from the default array instead. + * @returns compiled body + */ + getCompiledBody(...parts: string[]): string { + const defaultParts = ["title", "body", "tags", "mentions", "geo"]; + if (!parts.length) { + parts = defaultParts; + } + if (parts.every((part) => part.startsWith("!"))) { + let realParts = defaultParts; + parts.forEach((remove) => { + realParts = realParts.filter((part) => part != remove.substring(1)); + }); + parts = realParts; + } + + let body = ""; + for (const part of parts) { + switch (part) { + case "title": + body += this.title + "\n"; + break; + case "body": + body += this.body + "\n\n"; + break; + case "tags": + body += this.tags.join(" ") + "\n"; + break; + case "mentions": + body += this.mentions.join(" ") + "\n"; + break; + case "geo": + body += this.geo + "\n"; + break; + } + } + return body.trim(); + } + /** * @returns the files grouped by their group property */ diff --git a/src/platforms/Ayrshare/Ayrshare.ts b/src/platforms/Ayrshare/Ayrshare.ts index 085b390..5be1099 100644 --- a/src/platforms/Ayrshare/Ayrshare.ts +++ b/src/platforms/Ayrshare/Ayrshare.ts @@ -188,7 +188,7 @@ export default abstract class Ayrshare extends Platform { const body = JSON.stringify( uploads.length ? { - post: post.body, // required + post: post.getCompiledBody(), // required platforms: [postPlatform], // required mediaUrls: uploads, scheduleDate: scheduleDate, @@ -196,7 +196,7 @@ export default abstract class Ayrshare extends Platform { ...platformOptions, } : { - post: post.body, // required + post: post.getCompiledBody(), // required platforms: [postPlatform], // required scheduleDate: scheduleDate, requiresApproval: this.requiresApproval, diff --git a/src/platforms/Facebook/Facebook.ts b/src/platforms/Facebook/Facebook.ts index d2e04b1..67be349 100644 --- a/src/platforms/Facebook/Facebook.ts +++ b/src/platforms/Facebook/Facebook.ts @@ -121,7 +121,7 @@ export default class Facebook extends Platform { ): Promise<{ id: string }> { if (!dryrun) { return (await this.api.postJson("%PAGE%/feed", { - message: post.body, + message: post.getCompiledBody(), published: Storage.get("settings", "FACEBOOK_PUBLISH_POSTS"), })) as { id: string }; } @@ -149,7 +149,7 @@ export default class Facebook extends Platform { if (!dryrun) { return (await this.api.postJson("%PAGE%/feed", { - message: post.body, + message: post.getCompiledBody(), published: Storage.get("settings", "FACEBOOK_PUBLISH_POSTS"), attached_media: attachments, })) as { id: string }; @@ -173,7 +173,7 @@ export default class Facebook extends Platform { ): Promise<{ id: string }> { const file = post.getFilePath(post.getFiles("video")[0].name); const title = post.title; - const description = post.body; + const description = post.getCompiledBody("!title"); Logger.trace("Reading file", file); const rawData = fs.readFileSync(file); diff --git a/src/platforms/Instagram/Instagram.ts b/src/platforms/Instagram/Instagram.ts index f262828..b79db24 100644 --- a/src/platforms/Instagram/Instagram.ts +++ b/src/platforms/Instagram/Instagram.ts @@ -132,7 +132,7 @@ export default class Instagram extends Platform { dryrun: boolean = false, ): Promise<{ id: string }> { const file = post.getFilePath(post.getFiles("image")[0].name); - const caption = post.body; + const caption = post.getCompiledBody(); const photoId = (await this.uploadImage(file))["id"]; const photoLink = await this.getImageLink(photoId); const container = (await this.api.postJson("%USER%/media", { @@ -172,7 +172,7 @@ export default class Instagram extends Platform { dryrun: boolean = false, ): Promise<{ id: string }> { const file = post.getFilePath(post.getFiles("video")[0].name); - const caption = post.body; + const caption = post.getCompiledBody(); const videoId = (await this.uploadVideo(file))["id"]; const videoLink = await this.getVideoLink(videoId); const container = (await this.api.postJson("%USER%/media", { @@ -247,7 +247,7 @@ export default class Instagram extends Platform { // create carousel const container = (await this.api.postJson("%USER%/media", { media_type: "CAROUSEL", - caption: post.body, + caption: post.getCompiledBody(), children: uploadIds.join(","), })) as { id: string; diff --git a/src/platforms/LinkedIn/LinkedIn.ts b/src/platforms/LinkedIn/LinkedIn.ts index 36f17ad..352f191 100644 --- a/src/platforms/LinkedIn/LinkedIn.ts +++ b/src/platforms/LinkedIn/LinkedIn.ts @@ -156,10 +156,9 @@ export default class LinkedIn extends Platform { */ private async publishTextPost(post: Post, dryrun: boolean = false) { Logger.trace("LinkedIn.publishTextPost"); - const content = post.title + "\n\n" + post.body; const body = { author: this.POST_AUTHOR, - commentary: content, + commentary: post.getCompiledBody(), visibility: this.POST_VISIBILITY, distribution: this.POST_DISTRIBUTION, lifecycleState: "PUBLISHED", @@ -182,7 +181,6 @@ export default class LinkedIn extends Platform { private async publishImagePost(post: Post, dryrun: boolean = false) { Logger.trace("LinkedIn.publishImagePost"); const title = post.title; - const content = post.body; const image = post.getFilePath(post.getFiles("image")[0].name); const leash = await this.getImageLeash(); await this.uploadImage(leash.value.uploadUrl, image); @@ -190,7 +188,7 @@ export default class LinkedIn extends Platform { // https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/videos-api?view=li-lms-2023-10&tabs=http#sample-response-4 const body = { author: this.POST_AUTHOR, - commentary: content, + commentary: post.getCompiledBody("!title"), visibility: this.POST_VISIBILITY, distribution: this.POST_DISTRIBUTION, content: { @@ -219,7 +217,6 @@ export default class LinkedIn extends Platform { private async publishImagesPost(post: Post, dryrun: boolean = false) { Logger.trace("LinkedIn.publishImagesPost"); - const content = post.title + "\n\n" + post.body; const images = post .getFiles("image") .map((image) => post.getFilePath(image.name)); @@ -234,7 +231,7 @@ export default class LinkedIn extends Platform { const body = { author: this.POST_AUTHOR, - commentary: content, + commentary: post.getCompiledBody(), visibility: this.POST_VISIBILITY, distribution: this.POST_DISTRIBUTION, lifecycleState: "PUBLISHED", @@ -268,7 +265,6 @@ export default class LinkedIn extends Platform { Logger.trace("LinkedIn.publishVideoPost"); const title = post.title; - const content = post.body; const video = post.getFilePath(post.getFiles("video")[0].name); const leash = await this.getVideoLeash(video); @@ -277,7 +273,7 @@ export default class LinkedIn extends Platform { // https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/videos-api?view=li-lms-2023-10&tabs=http#sample-response-4 const body = { author: this.POST_AUTHOR, - commentary: content, + commentary: post.getCompiledBody("!title"), visibility: this.POST_VISIBILITY, distribution: this.POST_DISTRIBUTION, content: { diff --git a/src/platforms/Reddit/Reddit.ts b/src/platforms/Reddit/Reddit.ts index 2ec3d87..2a6f3fd 100644 --- a/src/platforms/Reddit/Reddit.ts +++ b/src/platforms/Reddit/Reddit.ts @@ -131,7 +131,7 @@ export default class Reddit extends Platform { private async publishTextPost(post: Post, dryrun = false): Promise { Logger.trace("Reddit.publishTextPost"); const title = post.title; - const body = post.body; + const body = post.getCompiledBody("!title"); if (!dryrun) { return (await this.api.post("submit", { sr: this.SUBREDDIT, diff --git a/src/platforms/Twitter/Twitter.ts b/src/platforms/Twitter/Twitter.ts index d7578e5..e51fc98 100644 --- a/src/platforms/Twitter/Twitter.ts +++ b/src/platforms/Twitter/Twitter.ts @@ -135,7 +135,7 @@ export default class Twitter extends Platform { Storage.get("auth", "TWITTER_ACCESS_TOKEN"), ); const result = await client2.v2.tweet({ - text: post.body, + text: post.getCompiledBody(), }); if (result.errors) { throw Logger.error(result.errors.join()); @@ -189,7 +189,7 @@ export default class Twitter extends Platform { if (!dryrun) { Logger.trace("Tweeting " + post.id + "..."); const result = await client2.v2.tweet({ - text: post.body, + text: post.getCompiledBody(), media: { media_ids: mediaIds }, }); if (result.errors) { diff --git a/src/utilities.ts b/src/utilities.ts index d40571a..f22258e 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -1,5 +1,11 @@ import Logger from "./services/Logger"; +export function isSimilarArray(a, b) { + a = Array.isArray(a) ? a : []; + b = Array.isArray(b) ? b : []; + return a.length === b.length && a.every((el) => b.includes(el)); +} + export class ApiResponseError extends Error { response: Response; // eslint-disable-next-line @typescript-eslint/no-explicit-any From 687f259d50e99e519c4e301d3bf647f45157b7f7 Mon Sep 17 00:00:00 2001 From: pike Date: Tue, 26 Dec 2023 15:23:00 +0100 Subject: [PATCH 6/7] fix: Bugs in Post --- src/models/Post.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/models/Post.ts b/src/models/Post.ts index ce6f3dd..0a648aa 100644 --- a/src/models/Post.ts +++ b/src/models/Post.ts @@ -181,19 +181,19 @@ export default class Post { for (const part of parts) { switch (part) { case "title": - body += this.title + "\n"; + body += this.title ? this.title + "\n" : ""; break; case "body": - body += this.body + "\n\n"; + body += this.body ? this.body + "\n\n" : ""; break; case "tags": - body += this.tags.join(" ") + "\n"; + body += this.tags ? this.tags.join(" ") + "\n" : ""; break; case "mentions": - body += this.mentions.join(" ") + "\n"; + body += this.mentions ? this.mentions.join(" ") + "\n" : ""; break; case "geo": - body += this.geo + "\n"; + body += this.geo? this.geo + "\n" : ""; break; } } From 73a66468c3966bf4ff4c82febf8b921b06f86cb6 Mon Sep 17 00:00:00 2001 From: pike Date: Tue, 26 Dec 2023 15:27:15 +0100 Subject: [PATCH 7/7] fix: Lint --- src/models/Post.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/Post.ts b/src/models/Post.ts index 0a648aa..50142e3 100644 --- a/src/models/Post.ts +++ b/src/models/Post.ts @@ -193,7 +193,7 @@ export default class Post { body += this.mentions ? this.mentions.join(" ") + "\n" : ""; break; case "geo": - body += this.geo? this.geo + "\n" : ""; + body += this.geo ? this.geo + "\n" : ""; break; } }