2023-09-27 07:06:56 +00:00
|
|
|
import { ACCOUNT, ACTIVITY_INBOX_PATH, ACTIVITY_OUTBOX_PATH, ACTOR, CONTENT_PATH, DATA_PATH, POSTS_PATH, PUBLIC_KEY, STATIC_PATH } from "./env";
|
2023-09-16 00:28:06 +00:00
|
|
|
import path from "path"
|
|
|
|
|
import { readdir } from "fs/promises"
|
2023-09-20 06:43:48 +00:00
|
|
|
import { unlinkSync } from "node:fs"
|
2023-09-21 07:04:27 +00:00
|
|
|
import { fetchObject } from "./request";
|
|
|
|
|
import { idsFromValue } from "./activitypub";
|
2023-09-16 00:28:06 +00:00
|
|
|
const matter = require('gray-matter')
|
2023-09-27 04:13:10 +00:00
|
|
|
const Eleventy = require("@11ty/eleventy")
|
2023-09-16 00:28:06 +00:00
|
|
|
|
2023-09-27 04:13:10 +00:00
|
|
|
// rebuild the 11ty static pages
|
|
|
|
|
export async function rebuild() {
|
|
|
|
|
console.info(`Building 11ty from ${CONTENT_PATH}, to ${STATIC_PATH}`)
|
|
|
|
|
await new Eleventy(CONTENT_PATH, STATIC_PATH, { configPath: '.eleventy.js' }).write()
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-20 06:43:48 +00:00
|
|
|
export async function createInboxActivity(activity:any, object_id:any) {
|
|
|
|
|
const activityFile = Bun.file(path.join(ACTIVITY_INBOX_PATH, `${object_id}.activity.json`))
|
|
|
|
|
await Bun.write(activityFile, JSON.stringify(activity))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createOutboxActivity(activity:any, object_id:any) {
|
|
|
|
|
const activityFile = Bun.file(path.join(ACTIVITY_OUTBOX_PATH, `${object_id}.activity.json`))
|
|
|
|
|
await Bun.write(activityFile, JSON.stringify(activity))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getInboxActivity(id:string) {
|
|
|
|
|
const file = Bun.file(path.join(ACTIVITY_INBOX_PATH, `${id}.activity.json`))
|
|
|
|
|
return await file.json()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getOutboxActivity(id:string) {
|
|
|
|
|
const file = Bun.file(path.join(ACTIVITY_OUTBOX_PATH, `${id}.activity.json`))
|
|
|
|
|
return await file.json()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function listInboxActivities() {
|
|
|
|
|
return await Promise.all(
|
|
|
|
|
(await readdir(ACTIVITY_INBOX_PATH)).filter(v => v.endsWith('.activity.json'))
|
|
|
|
|
.map(async filename => await Bun.file(path.join(ACTIVITY_INBOX_PATH, filename)).json())
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function listOutboxActivities() {
|
|
|
|
|
return await Promise.all(
|
|
|
|
|
(await readdir(ACTIVITY_OUTBOX_PATH)).filter(v => v.endsWith('.activity.json'))
|
|
|
|
|
.map(async filename => await Bun.file(path.join(ACTIVITY_OUTBOX_PATH, filename)).json())
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createPost(post_object:any, object_id:string) {
|
|
|
|
|
const file = Bun.file(path.join(POSTS_PATH, `${object_id}.md`))
|
2023-09-21 07:04:27 +00:00
|
|
|
let {type, object, inReplyTo} = post_object
|
|
|
|
|
if(inReplyTo && typeof inReplyTo === 'string') inReplyTo = await fetchObject(ACTOR, inReplyTo)
|
|
|
|
|
|
2023-09-20 06:43:48 +00:00
|
|
|
if(object){
|
|
|
|
|
let { content, published, id, attributedTo } = object
|
|
|
|
|
if(content as string) content = '> ' + content.replace('\n', '\n> ') + '\n'
|
|
|
|
|
else content = ""
|
|
|
|
|
|
|
|
|
|
content += post_object.content || ""
|
|
|
|
|
//TODO: add appropriate content for different types (e.g. like, etc)
|
2023-09-21 07:04:27 +00:00
|
|
|
const data:any = { id, published, attributedTo, type }
|
|
|
|
|
if(inReplyTo) data.inReplyTo = idsFromValue(inReplyTo).at(0)
|
|
|
|
|
await Bun.write(file, matter.stringify(content, data))
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const { content, published, id, attributedTo } = post_object
|
2023-09-21 07:04:27 +00:00
|
|
|
|
|
|
|
|
let reply_content = ""
|
|
|
|
|
if(!object && inReplyTo) {
|
|
|
|
|
reply_content = inReplyTo.content
|
|
|
|
|
if(reply_content as string) reply_content = '> ' + reply_content.replace('\n', '\n> ') + '\n'
|
|
|
|
|
else reply_content = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const data:any = { id, published, attributedTo, type }
|
|
|
|
|
if(inReplyTo) data.inReplyTo = idsFromValue(inReplyTo).at(0)
|
|
|
|
|
await Bun.write(file, matter.stringify((reply_content || "") + (content || ""), data))
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-16 00:28:06 +00:00
|
|
|
export async function getPost(id:string) {
|
|
|
|
|
const file = Bun.file(path.join(POSTS_PATH, `${id}.md`))
|
|
|
|
|
const { data, content } = matter(await file.text())
|
|
|
|
|
return {
|
|
|
|
|
...data,
|
2023-09-21 07:04:27 +00:00
|
|
|
content: content.trim(),
|
|
|
|
|
local_id: id
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 07:04:27 +00:00
|
|
|
export async function getPostByURL(url_id:string) {
|
2023-09-27 04:13:10 +00:00
|
|
|
if(!url_id || !url_id.startsWith(ACTOR + '/posts/')) return null
|
2023-09-21 07:04:27 +00:00
|
|
|
const match = url_id.match(/\/([0-9a-f]+)\/?$/)
|
|
|
|
|
const local_id = match ? match[1] : url_id
|
|
|
|
|
return await getPost(local_id)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 06:43:48 +00:00
|
|
|
export async function deletePost(id:string) {
|
|
|
|
|
unlinkSync(path.join(POSTS_PATH, id + '.md'))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-16 00:28:06 +00:00
|
|
|
export async function listPosts() {
|
|
|
|
|
return await Promise.all((await readdir(POSTS_PATH)).filter(v => v.endsWith('.md')).map(async filename => await getPost(filename.slice(0, -3))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createFollowing(handle:string, id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `following.json`))
|
|
|
|
|
const following_list = await file.json() as Array<any>
|
|
|
|
|
if(!following_list.find(v => v.id === id || v.handle === handle)) following_list.push({id, handle, createdAt: new Date().toISOString()})
|
|
|
|
|
await Bun.write(file, JSON.stringify(following_list))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function deleteFollowing(handle:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `following.json`))
|
|
|
|
|
const following_list = await file.json() as Array<any>
|
|
|
|
|
await Bun.write(file, JSON.stringify(following_list.filter(v => v.handle !== handle)))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getFollowing(handle:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `following.json`))
|
|
|
|
|
const following_list = await file.json() as Array<any>
|
|
|
|
|
return following_list.find(v => v.handle === handle)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 06:43:48 +00:00
|
|
|
export async function listFollowing(onlyAccepted = true) {
|
2023-09-16 00:28:06 +00:00
|
|
|
const file = Bun.file(path.join(DATA_PATH, `following.json`))
|
2023-09-20 06:43:48 +00:00
|
|
|
return ((await file.json()) as Array<any>).filter(f => !onlyAccepted || f.accepted)
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function acceptFollowing(handle:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `following.json`))
|
|
|
|
|
const following_list = await file.json() as Array<any>
|
|
|
|
|
const following = following_list.find(v => v.handle === handle)
|
|
|
|
|
if(following) following.accepted = new Date().toISOString()
|
|
|
|
|
await Bun.write(file, JSON.stringify(following_list))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createFollower(actor:string, id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `followers.json`))
|
|
|
|
|
const followers_list = await file.json() as Array<any>
|
|
|
|
|
if(!followers_list.find(v => v.id === id || v.actor === actor)) followers_list.push({id, actor, createdAt: new Date().toISOString()})
|
|
|
|
|
await Bun.write(file, JSON.stringify(followers_list))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function deleteFollower(actor:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `followers.json`))
|
|
|
|
|
const followers_list = await file.json() as Array<any>
|
|
|
|
|
await Bun.write(file, JSON.stringify(followers_list.filter(v => v.actor !== actor)))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getFollower(actor:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `followers.json`))
|
|
|
|
|
const followers_list = await file.json() as Array<any>
|
|
|
|
|
return followers_list.find(v => v.actor === actor)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function listFollowers() {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `followers.json`))
|
|
|
|
|
return await file.json() as Array<any>
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createLiked(object_id:string, id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `liked.json`))
|
|
|
|
|
const liked_list = await file.json() as Array<any>
|
|
|
|
|
if(!liked_list.find(v => v.object_id === object_id)) liked_list.push({id, object_id, createdAt: new Date().toISOString()})
|
|
|
|
|
await Bun.write(file, JSON.stringify(liked_list))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function deleteLiked(object_id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `liked.json`))
|
|
|
|
|
const liked_list = await file.json() as Array<any>
|
|
|
|
|
await Bun.write(file, JSON.stringify(liked_list.filter(v => v.object_id !== object_id)))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-20 06:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function listLiked() {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `liked.json`))
|
|
|
|
|
return await file.json() as Array<any>
|
2023-09-21 07:04:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createDisliked(object_id:string, id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `disliked.json`))
|
|
|
|
|
const disliked_list = await file.json() as Array<any>
|
|
|
|
|
if(!disliked_list.find(v => v.object_id === object_id)) disliked_list.push({id, object_id, createdAt: new Date().toISOString()})
|
|
|
|
|
await Bun.write(file, JSON.stringify(disliked_list))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-21 07:04:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function deleteDisliked(object_id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `disliked.json`))
|
|
|
|
|
const disliked_list = await file.json() as Array<any>
|
|
|
|
|
await Bun.write(file, JSON.stringify(disliked_list.filter(v => v.object_id !== object_id)))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-21 07:04:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function listDisliked() {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `disliked.json`))
|
|
|
|
|
return await file.json() as Array<any>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createShared(object_id:string, id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `shared.json`))
|
|
|
|
|
const shared_list = await file.json() as Array<any>
|
|
|
|
|
if(!shared_list.find(v => v.object_id === object_id)) shared_list.push({id, object_id, createdAt: new Date().toISOString()})
|
|
|
|
|
await Bun.write(file, JSON.stringify(shared_list))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-21 07:04:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function deleteShared(object_id:string) {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `shared.json`))
|
|
|
|
|
const shared_list = await file.json() as Array<any>
|
|
|
|
|
await Bun.write(file, JSON.stringify(shared_list.filter(v => v.object_id !== object_id)))
|
2023-09-27 04:13:10 +00:00
|
|
|
rebuild()
|
2023-09-21 07:04:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function listShared() {
|
|
|
|
|
const file = Bun.file(path.join(DATA_PATH, `shared.json`))
|
|
|
|
|
return await file.json() as Array<any>
|
2023-09-16 00:28:06 +00:00
|
|
|
}
|