2024-01-10 14:19:57 -05:00
|
|
|
'use strict';
|
|
|
|
|
|
2024-01-24 20:10:22 -05:00
|
|
|
const nconf = require('nconf');
|
2024-01-24 22:59:09 -05:00
|
|
|
const mime = require('mime');
|
2024-02-02 17:19:59 -05:00
|
|
|
const path = require('path');
|
2024-05-23 15:29:32 -04:00
|
|
|
const sanitize = require('sanitize-html');
|
2024-01-24 20:10:22 -05:00
|
|
|
|
2024-02-28 14:07:27 -05:00
|
|
|
const meta = require('../meta');
|
2024-01-10 14:19:57 -05:00
|
|
|
const user = require('../user');
|
2024-02-02 17:19:59 -05:00
|
|
|
const categories = require('../categories');
|
2024-01-25 15:35:45 -05:00
|
|
|
const posts = require('../posts');
|
2024-01-26 21:39:20 -05:00
|
|
|
const topics = require('../topics');
|
2024-03-05 09:56:15 -05:00
|
|
|
const plugins = require('../plugins');
|
2024-03-07 13:16:13 -05:00
|
|
|
const slugify = require('../slugify');
|
2024-02-02 17:19:59 -05:00
|
|
|
const utils = require('../utils');
|
2024-01-10 14:19:57 -05:00
|
|
|
|
|
|
|
|
const activitypub = module.parent.exports;
|
|
|
|
|
const Mocks = module.exports;
|
|
|
|
|
|
2024-05-23 15:29:32 -04:00
|
|
|
/**
|
|
|
|
|
* A more restrictive html sanitization run on top of standard sanitization from core.
|
|
|
|
|
* Done so the output HTML is stripped of all non-essential items; mainly classes from plugins..
|
|
|
|
|
*/
|
|
|
|
|
const sanitizeConfig = {
|
2024-06-19 11:23:26 -04:00
|
|
|
allowedTags: sanitize.defaults.allowedTags.concat(['img']),
|
2024-05-23 15:29:32 -04:00
|
|
|
allowedClasses: {
|
|
|
|
|
'*': [],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2024-01-26 15:10:35 -05:00
|
|
|
Mocks.profile = async (actors) => {
|
|
|
|
|
// Should only ever be called by activitypub.actors.assert
|
2024-06-07 11:55:21 -04:00
|
|
|
const profiles = await Promise.all(actors.map(async (actor) => {
|
2024-01-10 14:19:57 -05:00
|
|
|
if (!actor) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uid = actor.id;
|
2024-03-07 13:16:13 -05:00
|
|
|
let {
|
2024-04-03 13:49:27 -04:00
|
|
|
url, preferredUsername, published, icon, image,
|
2024-05-06 14:46:26 -04:00
|
|
|
name, summary, followers, followerCount, followingCount,
|
2024-06-21 16:46:33 -04:00
|
|
|
inbox, endpoints,
|
2024-01-26 15:10:35 -05:00
|
|
|
} = actor;
|
2024-03-07 13:16:13 -05:00
|
|
|
preferredUsername = preferredUsername || slugify(name);
|
2024-06-04 12:30:47 -04:00
|
|
|
|
2024-06-06 20:59:02 -04:00
|
|
|
const { hostname } = new URL(actor.id);
|
2024-01-10 14:19:57 -05:00
|
|
|
|
|
|
|
|
let picture;
|
|
|
|
|
if (icon) {
|
|
|
|
|
picture = typeof icon === 'string' ? icon : icon.url;
|
|
|
|
|
}
|
|
|
|
|
const iconBackgrounds = await user.getIconBackgrounds();
|
|
|
|
|
let bgColor = Array.prototype.reduce.call(preferredUsername, (cur, next) => cur + next.charCodeAt(), 0);
|
|
|
|
|
bgColor = iconBackgrounds[bgColor % iconBackgrounds.length];
|
|
|
|
|
|
|
|
|
|
const payload = {
|
|
|
|
|
uid,
|
|
|
|
|
username: `${preferredUsername}@${hostname}`,
|
|
|
|
|
userslug: `${preferredUsername}@${hostname}`,
|
|
|
|
|
displayname: name,
|
|
|
|
|
fullname: name,
|
|
|
|
|
joindate: new Date(published).getTime(),
|
|
|
|
|
picture,
|
2024-01-10 20:51:23 -05:00
|
|
|
status: 'offline',
|
2024-01-10 14:19:57 -05:00
|
|
|
'icon:text': (preferredUsername[0] || '').toUpperCase(),
|
|
|
|
|
'icon:bgColor': bgColor,
|
|
|
|
|
uploadedpicture: undefined,
|
|
|
|
|
'cover:url': !image || typeof image === 'string' ? image : image.url,
|
|
|
|
|
'cover:position': '50% 50%',
|
|
|
|
|
aboutme: summary,
|
2024-01-26 15:10:35 -05:00
|
|
|
followerCount,
|
|
|
|
|
followingCount,
|
2024-01-10 14:19:57 -05:00
|
|
|
|
2024-04-03 13:49:27 -04:00
|
|
|
url,
|
2024-01-26 15:10:35 -05:00
|
|
|
inbox,
|
2024-01-26 21:39:20 -05:00
|
|
|
sharedInbox: endpoints ? endpoints.sharedInbox : null,
|
2024-05-06 14:46:26 -04:00
|
|
|
followersUrl: followers,
|
2024-01-10 14:19:57 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return payload;
|
2024-06-07 11:55:21 -04:00
|
|
|
}));
|
2024-01-10 14:19:57 -05:00
|
|
|
|
2024-01-26 15:10:35 -05:00
|
|
|
return profiles;
|
2024-01-10 14:19:57 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Mocks.post = async (objects) => {
|
|
|
|
|
let single = false;
|
|
|
|
|
if (!Array.isArray(objects)) {
|
|
|
|
|
single = true;
|
|
|
|
|
objects = [objects];
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-14 12:22:06 -04:00
|
|
|
const actorIds = new Set(objects.map(object => object.attributedTo).filter(Boolean));
|
|
|
|
|
await activitypub.actors.assert(Array.from(actorIds));
|
|
|
|
|
|
2024-01-12 11:29:08 -05:00
|
|
|
const posts = await Promise.all(objects.map(async (object) => {
|
2024-04-14 02:42:30 +02:00
|
|
|
if (!activitypub._constants.acceptedPostTypes.includes(object.type)) {
|
2024-01-10 14:19:57 -05:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-14 00:17:45 -04:00
|
|
|
let {
|
2024-01-10 14:19:57 -05:00
|
|
|
id: pid,
|
2024-04-11 13:25:37 -04:00
|
|
|
url,
|
2024-01-10 14:19:57 -05:00
|
|
|
attributedTo: uid,
|
|
|
|
|
inReplyTo: toPid,
|
2024-02-29 11:19:56 -05:00
|
|
|
published, updated, name, content, sourceContent,
|
2024-06-13 17:05:37 -04:00
|
|
|
to, cc, audience, attachment, tag,
|
2024-02-29 11:19:56 -05:00
|
|
|
// conversation, // mastodon-specific, ignored.
|
2024-01-10 14:19:57 -05:00
|
|
|
} = object;
|
|
|
|
|
|
2024-03-14 00:17:45 -04:00
|
|
|
const resolved = await activitypub.helpers.resolveLocalId(toPid);
|
|
|
|
|
if (resolved.type === 'post') {
|
|
|
|
|
toPid = resolved.id;
|
|
|
|
|
}
|
2024-01-10 20:51:23 -05:00
|
|
|
const timestamp = new Date(published).getTime();
|
2024-01-10 14:19:57 -05:00
|
|
|
let edited = new Date(updated);
|
2024-01-10 20:51:23 -05:00
|
|
|
edited = Number.isNaN(edited.valueOf()) ? undefined : edited;
|
2024-01-10 14:19:57 -05:00
|
|
|
|
2024-05-30 12:04:37 -04:00
|
|
|
content = sanitize(content, sanitizeConfig);
|
2024-06-12 20:31:36 -04:00
|
|
|
content = await activitypub.helpers.remoteAnchorToLocalProfile(content);
|
2024-05-30 12:04:37 -04:00
|
|
|
|
2024-01-10 14:19:57 -05:00
|
|
|
const payload = {
|
|
|
|
|
uid,
|
|
|
|
|
pid,
|
2024-01-18 16:20:37 -05:00
|
|
|
// tid, --> purposely omitted
|
|
|
|
|
name,
|
2024-01-10 20:51:23 -05:00
|
|
|
content,
|
|
|
|
|
sourceContent,
|
|
|
|
|
timestamp,
|
2024-01-10 14:19:57 -05:00
|
|
|
toPid,
|
|
|
|
|
|
|
|
|
|
edited,
|
|
|
|
|
editor: edited ? uid : undefined,
|
2024-06-13 17:05:37 -04:00
|
|
|
_activitypub: { to, cc, audience, attachment, tag, url },
|
2024-01-10 14:19:57 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return payload;
|
2024-01-12 11:29:08 -05:00
|
|
|
}));
|
2024-01-10 14:19:57 -05:00
|
|
|
|
|
|
|
|
return single ? posts.pop() : posts;
|
|
|
|
|
};
|
2024-01-24 20:10:22 -05:00
|
|
|
|
2024-02-02 17:19:59 -05:00
|
|
|
Mocks.actors = {};
|
|
|
|
|
|
|
|
|
|
Mocks.actors.user = async (uid) => {
|
2024-04-10 12:17:03 -04:00
|
|
|
let { username, userslug, displayname, fullname, aboutme, picture, 'cover:url': cover } = await user.getUserData(uid);
|
2024-02-05 16:57:17 -05:00
|
|
|
const publicKey = await activitypub.getPublicKey('uid', uid);
|
2024-01-24 20:10:22 -05:00
|
|
|
|
2024-01-24 22:59:09 -05:00
|
|
|
if (picture) {
|
|
|
|
|
const imagePath = await user.getLocalAvatarPath(uid);
|
|
|
|
|
picture = {
|
|
|
|
|
type: 'Image',
|
|
|
|
|
mediaType: mime.getType(imagePath),
|
|
|
|
|
url: `${nconf.get('url')}${picture}`,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cover) {
|
|
|
|
|
const imagePath = await user.getLocalCoverPath(uid);
|
|
|
|
|
cover = {
|
|
|
|
|
type: 'Image',
|
|
|
|
|
mediaType: mime.getType(imagePath),
|
|
|
|
|
url: `${nconf.get('url')}${cover}`,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-24 20:10:22 -05:00
|
|
|
return {
|
2024-06-17 16:27:59 -04:00
|
|
|
'@context': [
|
|
|
|
|
'https://www.w3.org/ns/activitystreams',
|
|
|
|
|
'https://w3id.org/security/v1',
|
|
|
|
|
],
|
2024-01-25 14:23:59 -05:00
|
|
|
id: `${nconf.get('url')}/uid/${uid}`,
|
2024-01-24 20:10:22 -05:00
|
|
|
url: `${nconf.get('url')}/user/${userslug}`,
|
2024-01-29 16:59:13 -05:00
|
|
|
followers: `${nconf.get('url')}/uid/${uid}/followers`,
|
|
|
|
|
following: `${nconf.get('url')}/uid/${uid}/following`,
|
|
|
|
|
inbox: `${nconf.get('url')}/uid/${uid}/inbox`,
|
|
|
|
|
outbox: `${nconf.get('url')}/uid/${uid}/outbox`,
|
2024-01-24 20:10:22 -05:00
|
|
|
|
|
|
|
|
type: 'Person',
|
2024-04-10 12:17:03 -04:00
|
|
|
name: username !== displayname ? fullname : username, // displayname is escaped, fullname is not
|
2024-04-12 14:26:37 -04:00
|
|
|
preferredUsername: userslug,
|
2024-01-24 20:10:22 -05:00
|
|
|
summary: aboutme,
|
2024-01-24 22:59:09 -05:00
|
|
|
icon: picture,
|
|
|
|
|
image: cover,
|
2024-01-24 20:10:22 -05:00
|
|
|
|
|
|
|
|
publicKey: {
|
2024-01-29 16:59:13 -05:00
|
|
|
id: `${nconf.get('url')}/uid/${uid}#key`,
|
|
|
|
|
owner: `${nconf.get('url')}/uid/${uid}`,
|
2024-01-24 20:10:22 -05:00
|
|
|
publicKeyPem: publicKey,
|
|
|
|
|
},
|
2024-06-25 11:29:20 -04:00
|
|
|
|
|
|
|
|
endpoints: {
|
|
|
|
|
sharedInbox: `${nconf.get('url')}/inbox`,
|
|
|
|
|
},
|
2024-01-24 20:10:22 -05:00
|
|
|
};
|
|
|
|
|
};
|
2024-01-25 15:35:45 -05:00
|
|
|
|
2024-02-02 17:19:59 -05:00
|
|
|
Mocks.actors.category = async (cid) => {
|
2024-03-22 13:06:09 -04:00
|
|
|
let {
|
|
|
|
|
name, handle: preferredUsername, slug,
|
|
|
|
|
description: summary, backgroundImage,
|
|
|
|
|
} = await categories.getCategoryData(cid);
|
2024-02-06 10:40:46 -05:00
|
|
|
const publicKey = await activitypub.getPublicKey('cid', cid);
|
2024-02-02 17:19:59 -05:00
|
|
|
|
2024-02-28 14:07:27 -05:00
|
|
|
backgroundImage = backgroundImage || meta.config['brand:logo'] || `${nconf.get('relative_path')}/assets/logo.png`;
|
|
|
|
|
const filename = path.basename(utils.decodeHTMLEntities(backgroundImage));
|
|
|
|
|
backgroundImage = {
|
|
|
|
|
type: 'Image',
|
|
|
|
|
mediaType: mime.getType(filename),
|
|
|
|
|
url: `${nconf.get('url')}${utils.decodeHTMLEntities(backgroundImage)}`,
|
|
|
|
|
};
|
2024-02-02 17:19:59 -05:00
|
|
|
|
|
|
|
|
return {
|
2024-06-17 16:27:59 -04:00
|
|
|
'@context': [
|
|
|
|
|
'https://www.w3.org/ns/activitystreams',
|
|
|
|
|
'https://w3id.org/security/v1',
|
|
|
|
|
],
|
2024-02-02 17:19:59 -05:00
|
|
|
id: `${nconf.get('url')}/category/${cid}`,
|
|
|
|
|
url: `${nconf.get('url')}/category/${slug}`,
|
|
|
|
|
// followers: ,
|
|
|
|
|
// following: ,
|
|
|
|
|
inbox: `${nconf.get('url')}/category/${cid}/inbox`,
|
|
|
|
|
outbox: `${nconf.get('url')}/category/${cid}/outbox`,
|
|
|
|
|
|
|
|
|
|
type: 'Group',
|
|
|
|
|
name,
|
2024-03-22 13:06:09 -04:00
|
|
|
preferredUsername,
|
2024-02-02 17:19:59 -05:00
|
|
|
summary,
|
|
|
|
|
icon: backgroundImage,
|
2024-02-06 10:40:46 -05:00
|
|
|
|
|
|
|
|
publicKey: {
|
|
|
|
|
id: `${nconf.get('url')}/category/${cid}#key`,
|
|
|
|
|
owner: `${nconf.get('url')}/category/${cid}`,
|
|
|
|
|
publicKeyPem: publicKey,
|
|
|
|
|
},
|
2024-06-25 11:29:20 -04:00
|
|
|
|
|
|
|
|
endpoints: {
|
|
|
|
|
sharedInbox: `${nconf.get('url')}/inbox`,
|
|
|
|
|
},
|
2024-02-02 17:19:59 -05:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2024-01-25 15:35:45 -05:00
|
|
|
Mocks.note = async (post) => {
|
|
|
|
|
const id = `${nconf.get('url')}/post/${post.pid}`;
|
2024-05-07 12:15:51 -04:00
|
|
|
|
|
|
|
|
// Return a tombstone for a deleted post
|
|
|
|
|
if (post.deleted === true) {
|
|
|
|
|
return Mocks.tombstone({
|
|
|
|
|
id,
|
|
|
|
|
formerType: 'Note',
|
|
|
|
|
attributedTo: `${nconf.get('url')}/uid/${post.user.uid}`,
|
|
|
|
|
context: `${nconf.get('url')}/topic/${post.topic.tid}`,
|
|
|
|
|
audience: `${nconf.get('url')}/category/${post.category.cid}`,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-25 16:33:31 -05:00
|
|
|
const published = new Date(parseInt(post.timestamp, 10)).toISOString();
|
2024-01-25 15:35:45 -05:00
|
|
|
|
2024-02-26 15:39:09 -05:00
|
|
|
// todo: post visibility
|
2024-03-11 11:40:24 -04:00
|
|
|
const to = new Set([activitypub._constants.publicAddress]);
|
|
|
|
|
const cc = new Set([`${nconf.get('url')}/uid/${post.user.uid}/followers`]);
|
2024-01-25 15:35:45 -05:00
|
|
|
|
|
|
|
|
let inReplyTo = null;
|
2024-02-29 11:35:07 -05:00
|
|
|
let tag = null;
|
2024-05-10 15:30:45 -04:00
|
|
|
let followersUrl;
|
2024-05-23 12:36:03 -04:00
|
|
|
|
|
|
|
|
let name = null;
|
|
|
|
|
({ titleRaw: name } = await topics.getTopicFields(post.tid, ['title']));
|
|
|
|
|
|
2024-01-26 21:39:20 -05:00
|
|
|
if (post.toPid) { // direct reply
|
2024-02-09 11:18:23 -05:00
|
|
|
inReplyTo = utils.isNumber(post.toPid) ? `${nconf.get('url')}/post/${post.toPid}` : post.toPid;
|
2024-05-23 12:36:03 -04:00
|
|
|
name = `Re: ${name}`;
|
|
|
|
|
|
2024-01-25 15:35:45 -05:00
|
|
|
const parentId = await posts.getPostField(post.toPid, 'uid');
|
2024-05-10 15:30:45 -04:00
|
|
|
followersUrl = await user.getUserField(parentId, ['followersUrl']);
|
2024-03-11 11:40:24 -04:00
|
|
|
to.add(utils.isNumber(parentId) ? `${nconf.get('url')}/uid/${parentId}` : parentId);
|
2024-01-26 21:39:20 -05:00
|
|
|
} else if (!post.isMainPost) { // reply to OP
|
2024-02-09 11:18:23 -05:00
|
|
|
inReplyTo = utils.isNumber(post.topic.mainPid) ? `${nconf.get('url')}/post/${post.topic.mainPid}` : post.topic.mainPid;
|
2024-05-23 12:36:03 -04:00
|
|
|
name = `Re: ${name}`;
|
|
|
|
|
|
2024-03-11 11:40:24 -04:00
|
|
|
to.add(utils.isNumber(post.topic.uid) ? `${nconf.get('url')}/uid/${post.topic.uid}` : post.topic.uid);
|
2024-05-10 15:30:45 -04:00
|
|
|
followersUrl = await user.getUserField(post.topic.uid, ['followersUrl']);
|
2024-01-26 21:39:20 -05:00
|
|
|
} else { // new topic
|
2024-02-29 11:35:07 -05:00
|
|
|
tag = post.topic.tags.map(tag => ({
|
|
|
|
|
type: 'Hashtag',
|
|
|
|
|
href: `${nconf.get('url')}/tags/${tag.valueEncoded}`,
|
|
|
|
|
name: `#${tag.value}`,
|
|
|
|
|
}));
|
2024-01-25 15:35:45 -05:00
|
|
|
}
|
|
|
|
|
|
2024-05-10 15:30:45 -04:00
|
|
|
if (followersUrl) {
|
|
|
|
|
cc.add(followersUrl);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-20 22:25:09 -04:00
|
|
|
const content = await posts.getPostField(post.pid, 'content');
|
|
|
|
|
post.content = content; // re-send raw content
|
2024-05-17 15:22:08 -04:00
|
|
|
const { postData: parsed } = await plugins.hooks.fire('filter:parse.post', {
|
2024-06-19 11:23:26 -04:00
|
|
|
postData: post,
|
2024-05-17 15:22:08 -04:00
|
|
|
type: 'activitypub.note',
|
|
|
|
|
});
|
2024-05-23 15:29:32 -04:00
|
|
|
post.content = sanitize(parsed.content, sanitizeConfig);
|
2024-04-12 15:30:59 -04:00
|
|
|
post.content = posts.relativeToAbsolute(post.content, posts.urlRegex);
|
|
|
|
|
post.content = posts.relativeToAbsolute(post.content, posts.imgRegex);
|
|
|
|
|
|
2024-03-12 13:27:29 -04:00
|
|
|
let source = null;
|
|
|
|
|
const [markdownEnabled, mentionsEnabled] = await Promise.all([
|
|
|
|
|
plugins.isActive('nodebb-plugin-markdown'),
|
|
|
|
|
plugins.isActive('nodebb-plugin-mentions'),
|
|
|
|
|
]);
|
|
|
|
|
if (markdownEnabled) {
|
|
|
|
|
const raw = await posts.getPostField(post.pid, 'content');
|
|
|
|
|
source = {
|
|
|
|
|
content: raw,
|
|
|
|
|
mediaType: 'text/markdown',
|
|
|
|
|
};
|
|
|
|
|
}
|
2024-03-05 09:56:15 -05:00
|
|
|
if (mentionsEnabled) {
|
|
|
|
|
const mentions = require.main.require('nodebb-plugin-mentions');
|
|
|
|
|
const matches = await mentions.getMatches(post.content);
|
|
|
|
|
|
|
|
|
|
if (matches.size) {
|
|
|
|
|
tag = tag || [];
|
2024-03-05 14:24:13 -05:00
|
|
|
tag.push(...Array.from(matches).map(({ id: href, slug: name }) => {
|
|
|
|
|
if (utils.isNumber(href)) { // local ref
|
2024-03-07 16:47:09 -05:00
|
|
|
name = name.toLowerCase(); // local slugs are always lowercase
|
2024-03-05 14:24:13 -05:00
|
|
|
href = `${nconf.get('url')}/user/${name.slice(1)}`;
|
|
|
|
|
name = `${name}@${nconf.get('url_parsed').hostname}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
type: 'Mention',
|
|
|
|
|
href,
|
|
|
|
|
name,
|
|
|
|
|
};
|
2024-03-05 09:56:15 -05:00
|
|
|
}));
|
2024-03-08 14:06:23 -05:00
|
|
|
|
2024-03-11 11:40:24 -04:00
|
|
|
Array.from(matches)
|
|
|
|
|
.reduce((ids, { id }) => {
|
|
|
|
|
if (!utils.isNumber(id) && !to.has(id) && !cc.has(id)) {
|
|
|
|
|
ids.push(id);
|
|
|
|
|
}
|
2024-03-08 14:06:23 -05:00
|
|
|
|
2024-03-11 11:40:24 -04:00
|
|
|
return ids;
|
|
|
|
|
}, [])
|
|
|
|
|
.forEach(id => cc.add(id));
|
2024-03-05 09:56:15 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-10 22:01:44 -04:00
|
|
|
let attachment = await posts.attachments.get(post.pid) || [];
|
2024-04-12 14:08:28 -04:00
|
|
|
const uploads = await posts.uploads.listWithSizes(post.pid);
|
|
|
|
|
uploads.forEach(({ name, width, height }) => {
|
|
|
|
|
const mediaType = mime.getType(name);
|
2024-04-12 14:10:33 -04:00
|
|
|
const url = `${nconf.get('url') + nconf.get('upload_url')}/${name}`;
|
2024-04-12 14:08:28 -04:00
|
|
|
attachment.push({ mediaType, url, width, height });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
attachment = attachment.map(({ mediaType, url, width, height }) => {
|
2024-04-12 12:56:18 -04:00
|
|
|
let type;
|
|
|
|
|
|
|
|
|
|
switch (true) {
|
|
|
|
|
case mediaType.startsWith('image'): {
|
|
|
|
|
type = 'Image';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
type = 'Link';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-12 14:08:28 -04:00
|
|
|
const payload = { type, mediaType, url };
|
|
|
|
|
|
|
|
|
|
if (width || height) {
|
|
|
|
|
payload.width = width;
|
|
|
|
|
payload.height = height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return payload;
|
2024-04-12 12:56:18 -04:00
|
|
|
});
|
2024-04-10 22:01:44 -04:00
|
|
|
|
2024-01-25 15:35:45 -05:00
|
|
|
const object = {
|
2024-01-29 16:33:41 -05:00
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
2024-01-25 15:35:45 -05:00
|
|
|
id,
|
|
|
|
|
type: 'Note',
|
2024-03-11 11:40:24 -04:00
|
|
|
to: Array.from(to),
|
|
|
|
|
cc: Array.from(cc),
|
2024-01-25 15:35:45 -05:00
|
|
|
inReplyTo,
|
|
|
|
|
published,
|
|
|
|
|
url: id,
|
|
|
|
|
attributedTo: `${nconf.get('url')}/uid/${post.user.uid}`,
|
2024-05-03 14:11:17 -04:00
|
|
|
context: `${nconf.get('url')}/topic/${post.topic.tid}`,
|
|
|
|
|
audience: `${nconf.get('url')}/category/${post.category.cid}`,
|
2024-01-25 15:35:45 -05:00
|
|
|
sensitive: false, // todo
|
2024-01-25 16:26:39 -05:00
|
|
|
summary: null,
|
2024-01-26 21:39:20 -05:00
|
|
|
name,
|
2024-01-25 15:35:45 -05:00
|
|
|
content: post.content,
|
2024-03-12 13:27:29 -04:00
|
|
|
source,
|
2024-02-29 11:35:07 -05:00
|
|
|
tag,
|
2024-04-10 22:01:44 -04:00
|
|
|
attachment,
|
2024-01-25 15:35:45 -05:00
|
|
|
// replies: {} todo...
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
};
|
2024-05-07 12:15:51 -04:00
|
|
|
|
|
|
|
|
Mocks.tombstone = async properties => ({
|
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
|
type: 'Tombstone',
|
|
|
|
|
...properties,
|
|
|
|
|
});
|