shadowfacts.net/lib/activitypub/articles.ts

79 lines
2.6 KiB
TypeScript

import express, { Router, Request, Response } from "express";
import { Page, PostMetadata } from "../metadata";
import { ArticleObject } from "./activity";
import Article from "../entity/Article";
import { getConnection } from "typeorm";
import uuidv4 from "uuid/v4";
const domain = process.env.DOMAIN;
export async function setup(posts: Page[]) {
const repository = getConnection().getRepository(Article);
const allPosts = await repository.find();
for (const post of posts) {
const postMeta = <PostMetadata>post.metadata;
if (allPosts.some((p) => p.id === postMeta.permalink)) {
continue;
}
const articleObject = {
"@context": [
"https://www.w3.org/ns/activitystreams",
],
"type": "Article",
"id": `https://${domain}${post.metadata.permalink}`,
"published": (<Date>postMeta.date).toISOString(),
"inReplyTo": null,
"conversation": `https://${domain}/ap/conversation/${uuidv4()}`,
"url": `https://${domain}${postMeta.permalink}`,
"attributedTo": `https://${domain}/ap/actor`,
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
`https://${domain}/ap/actor/followers`
],
"name": postMeta.title,
"content": post.text
};
const article = new Article();
article.id = postMeta.permalink;
article.articleObject = articleObject;
article.conversation = articleObject.conversation;
article.hasFederated = false;
await getConnection().manager.save(article);
}
}
export async function toFederate(): Promise<[string, ArticleObject][]> {
return new Promise(async (resolve, reject) => {
const articles: Article[] = await getConnection().createQueryBuilder().select("article").from(Article, "article").where("article.hasFederated = :hasFederated", { hasFederated: false }).getMany();
let result: [string, ArticleObject][] = [];
articles.forEach(it => {
result.push([it.id, it.articleObject]);
});
resolve(result);
});
}
export function route(router: Router) {
router.use("/:year/:slug/", async (req, res, next) => {
const best = req.accepts(["text/html", "application/activity+json"]);
if (best === "text/html") {
next();
} else if (best === "application/activity+json") {
const id = `/${req.params.year}/${req.params.slug}/`;
const repository = getConnection().getRepository(Article);
try {
const article = await repository.findOne(id);
res.type("application/activity+json").json(article.articleObject).end();
} catch (err) {
res.status(500).end(err);
}
} else {
res.status(415).end("No acceptable content-type given. text/html or application/activity+json are supported");
}
});
}