refactor: move mockProfile and mockPost to separate mocks.js

This commit is contained in:
Julian Lam
2024-01-10 14:19:57 -05:00
parent f1e5e5a0ad
commit 06e1583461
5 changed files with 134 additions and 144 deletions

View File

@@ -14,7 +14,7 @@ const ActivityPub = module.exports;
ActivityPub.helpers = require('./helpers'); ActivityPub.helpers = require('./helpers');
ActivityPub.inbox = require('./inbox'); ActivityPub.inbox = require('./inbox');
ActivityPub.notes = require('./notes'); ActivityPub.mocks = require('./mocks');
ActivityPub.getActor = async (uid, input) => { ActivityPub.getActor = async (uid, input) => {
// Can be a webfinger id, uri, or object, handle as appropriate // Can be a webfinger id, uri, or object, handle as appropriate
@@ -56,66 +56,6 @@ ActivityPub.getActor = async (uid, input) => {
} }
}; };
// todo: move to mocks.js
ActivityPub.mockProfile = async (actors, callerUid = 0) => {
// Accepts an array containing actor objects (the output of getActor()), or uris
let single = false;
if (!Array.isArray(actors)) {
single = true;
actors = [actors];
}
const profiles = (await Promise.all(actors.map(async (actor) => {
// convert uri to actor object
if (typeof actor === 'string' && ActivityPub.helpers.isUri(actor)) {
actor = await ActivityPub.getActor(callerUid, actor);
}
if (!actor) {
return null;
}
const uid = actor.id;
const { preferredUsername, published, icon, image, name, summary, hostname, followerCount, followingCount } = actor;
const isFollowing = await db.isSortedSetMember(`followingRemote:${callerUid}`, uid);
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,
'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,
aboutmeParsed: summary,
isFollowing,
counts: {
following: followingCount,
followers: followerCount,
},
};
return payload;
}))).filter(Boolean);
return single ? profiles.pop() : profiles;
};
ActivityPub.resolveInboxes = async (uid, ids) => await Promise.all(ids.map(async (id) => { ActivityPub.resolveInboxes = async (uid, ids) => await Promise.all(ids.map(async (id) => {
const actor = await ActivityPub.getActor(uid, id); const actor = await ActivityPub.getActor(uid, id);
return actor.inbox; return actor.inbox;

128
src/activitypub/mocks.js Normal file
View File

@@ -0,0 +1,128 @@
'use strict';
const winston = require('winston');
const db = require('../database');
const user = require('../user');
const activitypub = module.parent.exports;
const Mocks = module.exports;
Mocks.profile = async (actors, callerUid = 0) => {
// Accepts an array containing actor objects (the output of getActor()), or uris
let single = false;
if (!Array.isArray(actors)) {
single = true;
actors = [actors];
}
const profiles = (await Promise.all(actors.map(async (actor) => {
// convert uri to actor object
if (typeof actor === 'string' && activitypub.helpers.isUri(actor)) {
actor = await activitypub.getActor(callerUid, actor);
}
if (!actor) {
return null;
}
const uid = actor.id;
const { preferredUsername, published, icon, image, name, summary, hostname, followerCount, followingCount } = actor;
const isFollowing = await db.isSortedSetMember(`followingRemote:${callerUid}`, uid);
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,
'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,
aboutmeParsed: summary,
isFollowing,
counts: {
following: followingCount,
followers: followerCount,
},
};
return payload;
}))).filter(Boolean);
return single ? profiles.pop() : profiles;
};
Mocks.post = async (objects) => {
const postCache = require('../posts/cache');
let single = false;
if (!Array.isArray(objects)) {
single = true;
objects = [objects];
}
const posts = (await Promise.all(objects.map(async (object) => {
if (object.type !== 'Note') {
return null;
}
const {
id: pid,
published,
updated,
attributedTo: uid,
// conversation,
content,
sourceContent,
inReplyTo: toPid,
} = object;
const timestamp = new Date(published);
let edited = new Date(updated);
edited = Number.isNaN(edited.valueOf()) ? 0 : edited;
// If no source content, then `content` is pre-parsed and should be HTML, so cache it
if (!sourceContent) {
winston.verbose(`[activitypub/mockPost] pid ${pid} already has pre-parsed HTML content, adding to post cache...`);
postCache.set(pid, content);
}
const payload = {
uid,
pid,
timestamp: timestamp.getTime(),
timestampISO: timestamp.toISOString(),
content: sourceContent || content,
toPid,
edited,
editor: edited ? uid : undefined,
editedISO: edited ? edited.toISOString() : '',
deleted: 0,
deleterUid: 0,
replies: 0, // todo
bookmarks: 0,
votes: 0, // todo
};
return payload;
}))).filter(Boolean);
return single ? posts.pop() : posts;
};

View File

@@ -1,78 +0,0 @@
'use strict';
const winston = require('winston');
const db = require('../database');
const activitypub = module.parent.exports;
const Notes = module.exports;
Notes.get = async (uid, id) => {
try {
const object = await activitypub.get(uid, id);
return await Notes.mockPost(object);
} catch (e) {
return null;
}
};
// todo: move to mocks.js
Notes.mockPost = async (objects) => {
const postCache = require('../posts/cache');
let single = false;
if (!Array.isArray(objects)) {
single = true;
objects = [objects];
}
const posts = (await Promise.all(objects.map(async (object) => {
if (object.type !== 'Note') {
return null;
}
const {
id: pid,
published,
updated,
attributedTo: uid,
// conversation,
content,
sourceContent,
inReplyTo: toPid,
} = object;
const timestamp = new Date(published);
let edited = new Date(updated);
edited = Number.isNaN(edited.valueOf()) ? 0 : edited;
// If no source content, then `content` is pre-parsed and should be HTML, so cache it
if (!sourceContent) {
winston.verbose(`[activitypub/mockPost] pid ${pid} already has pre-parsed HTML content, adding to post cache...`);
postCache.set(pid, content);
}
const payload = {
uid,
pid,
timestamp: timestamp.getTime(),
timestampISO: timestamp.toISOString(),
content: sourceContent || content,
toPid,
edited,
editor: edited ? uid : undefined,
editedISO: edited ? edited.toISOString() : '',
deleted: 0,
deleterUid: 0,
replies: 0, // todo
bookmarks: 0,
votes: 0, // todo
};
return payload;
}))).filter(Boolean);
return single ? posts.pop() : posts;
};

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const { getActor, mockProfile, get } = require('../../activitypub'); const { getActor, mocks, get } = require('../../activitypub');
const helpers = require('../helpers'); const helpers = require('../helpers');
const pagination = require('../../pagination'); const pagination = require('../../pagination');
@@ -13,7 +13,7 @@ controller.get = async function (req, res, next) {
return next(); return next();
} }
const payload = await mockProfile(actor, req.uid); const payload = await mocks.profile(actor, req.uid);
res.render('account/profile', payload); res.render('account/profile', payload);
}; };
@@ -26,13 +26,13 @@ controller.getFollow = async function (tpl, name, req, res) {
const page = parseInt(req.query.page, 10) || 1; const page = parseInt(req.query.page, 10) || 1;
const payload = { const payload = {
...await mockProfile(actor, req.uid), ...await mocks.profile(actor, req.uid),
}; };
payload.title = `[[pages:${tpl}, ${username}]]`; payload.title = `[[pages:${tpl}, ${username}]]`;
const collection = await get(req.uid, `${actor[name]}?page=${page}`); const collection = await get(req.uid, `${actor[name]}?page=${page}`);
const resultsPerPage = collection.orderedItems.length; const resultsPerPage = collection.orderedItems.length;
payload.users = await mockProfile(collection.orderedItems, req.uid); payload.users = await mocks.profile(collection.orderedItems, req.uid);
const count = name === 'following' ? followingCount : followerCount; const count = name === 'following' ? followingCount : followerCount;
const pageCount = Math.ceil(count / resultsPerPage); const pageCount = Math.ceil(count / resultsPerPage);

View File

@@ -80,7 +80,7 @@ module.exports = function (User) {
const users = [ const users = [
...await db.getObjectsFields(uniqueUids.map(uid => `user:${uid}`), fields), ...await db.getObjectsFields(uniqueUids.map(uid => `user:${uid}`), fields),
...await activitypub.mockProfile(remoteIds, 0, fields), ...await activitypub.mocks.profile(remoteIds, 0, fields),
]; ];
const result = await plugins.hooks.fire('filter:user.getFields', { const result = await plugins.hooks.fire('filter:user.getFields', {
uids: uniqueUids, uids: uniqueUids,