Fixed 267U.pre2
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import config from "../../../config/index.js";
|
||||
import renderFollow from "./follow.js";
|
||||
export default ((follower, followee, requestId)=>{
|
||||
return {
|
||||
type: "Accept",
|
||||
actor: `${config.url}/users/${followee.id}`,
|
||||
object: renderFollow(follower, followee, requestId)
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import config from "../../../config/index.js";
|
||||
// assumes stamp.targetNote is populated
|
||||
export default (async (request, stamp)=>({
|
||||
type: "Accept",
|
||||
to: request.actor,
|
||||
actor: `${config.url}/users/${stamp.targetNote.userId}`,
|
||||
object: {
|
||||
type: "QuoteRequest",
|
||||
id: request.id,
|
||||
actor: request.actor,
|
||||
object: request.object,
|
||||
instrument: request.instrument
|
||||
},
|
||||
result: `${config.url}/stamp/${stamp.id}`
|
||||
}));
|
||||
@@ -0,0 +1,7 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((user, target, object)=>({
|
||||
type: "Add",
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
target,
|
||||
object
|
||||
}));
|
||||
@@ -0,0 +1,39 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((object, note)=>{
|
||||
const attributedTo = `${config.url}/users/${note.userId}`;
|
||||
const mentions = JSON.parse(note.mentionedRemoteUsers).map((x)=>x.uri);
|
||||
let to = [];
|
||||
let cc = [];
|
||||
if (note.visibility === "public") {
|
||||
to = [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
];
|
||||
cc = [
|
||||
`${attributedTo}/followers`
|
||||
];
|
||||
} else if (note.visibility === "home") {
|
||||
to = [
|
||||
`${attributedTo}/followers`
|
||||
];
|
||||
cc = [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
];
|
||||
} else if (note.visibility === "followers") {
|
||||
to = [
|
||||
`${attributedTo}/followers`
|
||||
];
|
||||
} else if (note.visibility === "specified") {
|
||||
to = mentions;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: `${config.url}/notes/${note.id}/activity`,
|
||||
actor: `${config.url}/users/${note.userId}`,
|
||||
type: "Announce",
|
||||
published: note.createdAt.toISOString(),
|
||||
to,
|
||||
cc,
|
||||
object
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import config from "../../../config/index.js";
|
||||
import { Bites } from "../../../models/index.js";
|
||||
export default (async (bite)=>({
|
||||
id: `${config.url}/bites/${bite.id}`,
|
||||
type: "Bite",
|
||||
actor: `${config.url}/users/${bite.userId}`,
|
||||
target: await Bites.targetUri(bite),
|
||||
published: bite.createdAt.toISOString(),
|
||||
to: await Bites.targetUserUri(bite)
|
||||
}));
|
||||
@@ -0,0 +1,16 @@
|
||||
import config from "../../../config/index.js";
|
||||
/**
|
||||
* Renders a block into its ActivityPub representation.
|
||||
*
|
||||
* @param block The block to be rendered. The blockee relation must be loaded.
|
||||
*/ export function renderBlock(block) {
|
||||
if (block.blockee?.uri == null) {
|
||||
throw new Error("renderBlock: missing blockee uri");
|
||||
}
|
||||
return {
|
||||
type: "Block",
|
||||
id: `${config.url}/blocks/${block.id}`,
|
||||
actor: `${config.url}/users/${block.blockerId}`,
|
||||
object: block.blockee.uri
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((object, note)=>{
|
||||
const activity = {
|
||||
id: `${config.url}/notes/${note.id}/activity`,
|
||||
actor: `${config.url}/users/${note.userId}`,
|
||||
type: "Create",
|
||||
published: note.createdAt.toISOString(),
|
||||
object
|
||||
};
|
||||
if (object.to) activity.to = object.to;
|
||||
if (object.cc) activity.cc = object.cc;
|
||||
return activity;
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((object, user)=>({
|
||||
type: "Delete",
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
object,
|
||||
published: new Date().toISOString()
|
||||
}));
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DriveFiles } from "../../../models/index.js";
|
||||
export default ((file)=>({
|
||||
type: "Document",
|
||||
mediaType: file.type,
|
||||
url: DriveFiles.getPublicUrl(file),
|
||||
name: file.comment
|
||||
}));
|
||||
@@ -0,0 +1,12 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((emoji)=>({
|
||||
id: `${config.url}/emojis/${emoji.name}`,
|
||||
type: "Emoji",
|
||||
name: `:${emoji.name}:`,
|
||||
updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString,
|
||||
icon: {
|
||||
type: "Image",
|
||||
mediaType: emoji.glyph ? "image/svg+xml" : emoji.type || "image/png",
|
||||
url: emoji.glyph ? emoji.originalUrl : emoji.publicUrl || emoji.originalUrl
|
||||
}
|
||||
}));
|
||||
@@ -0,0 +1,11 @@
|
||||
import config from "../../../config/index.js";
|
||||
// to anonymise reporters, the reporting actor must be a system user
|
||||
// object has to be a uri or array of uris
|
||||
export const renderFlag = (user, object, content)=>{
|
||||
return {
|
||||
type: "Flag",
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
content,
|
||||
object
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import config from "../../../config/index.js";
|
||||
export function renderFollowRelay(relay, relayActor) {
|
||||
const follow = {
|
||||
id: `${config.url}/activities/follow-relay/${relay.id}`,
|
||||
type: "Follow",
|
||||
actor: `${config.url}/users/${relayActor.id}`,
|
||||
object: "https://www.w3.org/ns/activitystreams#Public"
|
||||
};
|
||||
return follow;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import config from "../../../config/index.js";
|
||||
import { Users } from "../../../models/index.js";
|
||||
/**
|
||||
* Convert (local|remote)(Follower|Followee)ID to URL
|
||||
* @param id Follower|Followee ID
|
||||
*/ export default async function renderFollowUser(id) {
|
||||
const user = await Users.findOneByOrFail({
|
||||
id: id
|
||||
});
|
||||
return Users.isLocalUser(user) ? `${config.url}/users/${user.id}` : user.uri;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import config from "../../../config/index.js";
|
||||
import { Users } from "../../../models/index.js";
|
||||
export default ((follower, followee, requestId)=>{
|
||||
const follow = {
|
||||
id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`,
|
||||
type: "Follow",
|
||||
actor: Users.isLocalUser(follower) ? `${config.url}/users/${follower.id}` : follower.uri,
|
||||
object: Users.isLocalUser(followee) ? `${config.url}/users/${followee.id}` : followee.uri
|
||||
};
|
||||
return follow;
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((tag)=>({
|
||||
type: "Hashtag",
|
||||
href: `${config.url}/tags/${encodeURIComponent(tag)}`,
|
||||
name: `#${tag}`
|
||||
}));
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DriveFiles } from "../../../models/index.js";
|
||||
export default ((file)=>({
|
||||
type: "Image",
|
||||
url: DriveFiles.getPublicUrl(file),
|
||||
sensitive: file.isSensitive,
|
||||
name: file.comment
|
||||
}));
|
||||
@@ -0,0 +1,20 @@
|
||||
import { v4 as uuid } from "uuid";
|
||||
import config from "../../../config/index.js";
|
||||
import { getUserKeypair } from "../../../misc/keypair-store.js";
|
||||
import { LdSignature } from "../misc/ld-signature.js";
|
||||
import { WellKnownContext } from "../misc/contexts.js";
|
||||
export const renderActivity = (x)=>{
|
||||
if (x == null) return null;
|
||||
if (typeof x === "object" && x.id == null) {
|
||||
x.id = `${config.url}/${uuid()}`;
|
||||
}
|
||||
return Object.assign({}, WellKnownContext, x);
|
||||
};
|
||||
export const attachLdSignature = async (activity, user)=>{
|
||||
if (activity == null) return null;
|
||||
const keypair = await getUserKeypair(user.id);
|
||||
const ldSignature = new LdSignature();
|
||||
ldSignature.debug = false;
|
||||
activity = await ldSignature.signRsaSignature2017(activity, keypair.privateKey, `${config.url}/users/${user.id}#main-key`);
|
||||
return activity;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import config from "../../../config/index.js";
|
||||
import { createPublicKey } from "node:crypto";
|
||||
export default ((user, key, postfix)=>({
|
||||
id: `${config.url}/users/${user.id}${postfix || "/publickey"}`,
|
||||
type: "Key",
|
||||
owner: `${config.url}/users/${user.id}`,
|
||||
publicKeyPem: createPublicKey(key.publicKey).export({
|
||||
type: "spki",
|
||||
format: "pem"
|
||||
})
|
||||
}));
|
||||
@@ -0,0 +1,30 @@
|
||||
import { IsNull } from "typeorm";
|
||||
import config from "../../../config/index.js";
|
||||
import { Emojis } from "../../../models/index.js";
|
||||
import renderEmoji from "./emoji.js";
|
||||
import { fetchMeta } from "../../../misc/fetch-meta.js";
|
||||
export const renderLike = async (noteReaction, note)=>{
|
||||
const reaction = noteReaction.reaction;
|
||||
const meta = await fetchMeta();
|
||||
const object = {
|
||||
type: "Like",
|
||||
id: `${config.url}/likes/${noteReaction.id}`,
|
||||
actor: `${config.url}/users/${noteReaction.userId}`,
|
||||
object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`,
|
||||
...!meta.defaultReaction.includes(reaction) ? {
|
||||
content: reaction,
|
||||
_misskey_reaction: reaction
|
||||
} : {}
|
||||
};
|
||||
if (reaction.startsWith(":")) {
|
||||
const name = reaction.replace(/:/g, "");
|
||||
const emoji = await Emojis.findOneBy({
|
||||
name,
|
||||
host: IsNull()
|
||||
});
|
||||
if (emoji) object.tag = [
|
||||
renderEmoji(emoji)
|
||||
];
|
||||
}
|
||||
return object;
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
import config from "../../../config/index.js";
|
||||
import { Users } from "../../../models/index.js";
|
||||
export default ((mention)=>({
|
||||
type: "Mention",
|
||||
href: Users.isRemoteUser(mention) ? mention.uri : `${config.url}/users/${mention.id}`,
|
||||
name: Users.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${mention.username}`
|
||||
}));
|
||||
@@ -0,0 +1,174 @@
|
||||
import { In, IsNull } from "typeorm";
|
||||
import config from "../../../config/index.js";
|
||||
import { DriveFiles, Notes, Users, Emojis, Polls } from "../../../models/index.js";
|
||||
import toHtml from "../misc/get-note-html.js";
|
||||
import renderEmoji from "./emoji.js";
|
||||
import renderMention from "./mention.js";
|
||||
import renderHashtag from "./hashtag.js";
|
||||
import renderDocument from "./document.js";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
export default async function renderNote(note, dive = true, isTalk = false) {
|
||||
const getPromisedFiles = async (ids)=>{
|
||||
if (!ids || ids.length === 0) return [];
|
||||
const items = await DriveFiles.findBy({
|
||||
id: In(ids)
|
||||
});
|
||||
return ids.map((id)=>items.find((item)=>item.id === id)).filter((item)=>item != null);
|
||||
};
|
||||
let inReplyTo;
|
||||
let inReplyToNote;
|
||||
if (note.replyId) {
|
||||
inReplyToNote = await Notes.findOneBy({
|
||||
id: note.replyId
|
||||
});
|
||||
if (inReplyToNote != null) {
|
||||
const inReplyToUser = await Users.findOneBy({
|
||||
id: inReplyToNote.userId
|
||||
});
|
||||
if (inReplyToUser != null) {
|
||||
if (inReplyToNote.uri) {
|
||||
inReplyTo = inReplyToNote.uri;
|
||||
} else {
|
||||
if (dive) {
|
||||
inReplyTo = await renderNote(inReplyToNote, false);
|
||||
} else {
|
||||
inReplyTo = `${config.url}/notes/${inReplyToNote.id}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inReplyTo = null;
|
||||
}
|
||||
let quoteId;
|
||||
let quoteUrl;
|
||||
if (note.renoteId) {
|
||||
const renote = await Notes.findOneBy({
|
||||
id: note.renoteId
|
||||
});
|
||||
if (renote) {
|
||||
if (renote.userHost) {
|
||||
quoteId = renote.uri;
|
||||
quoteUrl = renote.url ?? renote.uri;
|
||||
} else {
|
||||
quoteId = quoteUrl = `${config.url}/notes/${renote.id}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
const attributedTo = `${config.url}/users/${note.userId}`;
|
||||
const mentions = JSON.parse(note.mentionedRemoteUsers).map((x)=>x.uri);
|
||||
let to = [];
|
||||
let cc = [];
|
||||
if (note.visibility === "public") {
|
||||
to = [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
];
|
||||
cc = [
|
||||
`${attributedTo}/followers`
|
||||
].concat(mentions);
|
||||
} else if (note.visibility === "home") {
|
||||
to = [
|
||||
`${attributedTo}/followers`
|
||||
];
|
||||
cc = [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
].concat(mentions);
|
||||
} else if (note.visibility === "followers") {
|
||||
to = [
|
||||
`${attributedTo}/followers`
|
||||
];
|
||||
cc = mentions;
|
||||
} else {
|
||||
to = mentions;
|
||||
}
|
||||
const mentionedUsers = note.mentions.length > 0 ? await Users.findBy({
|
||||
id: In(note.mentions)
|
||||
}) : [];
|
||||
const hashtagTags = (note.tags || []).map((tag)=>renderHashtag(tag));
|
||||
const mentionTags = mentionedUsers.map((u)=>renderMention(u));
|
||||
const files = await getPromisedFiles(note.fileIds);
|
||||
const text = note.text ?? "";
|
||||
let poll = null;
|
||||
if (note.hasPoll) {
|
||||
poll = await Polls.findOneBy({
|
||||
noteId: note.id
|
||||
});
|
||||
}
|
||||
const summary = note.cw === "" ? String.fromCharCode(0x200b) : note.cw;
|
||||
let content = await toHtml(Object.assign({}, note, {
|
||||
text
|
||||
}));
|
||||
if (quoteId) {
|
||||
// wrapping in p.quote-inline lets mastodon automatically strip the link
|
||||
const quoteHREFSan = (quoteUrl || quoteId).replaceAll("&", "&").replaceAll('"', """);
|
||||
const quoteTextSan = sanitizeHtml(quoteUrl || quoteId);
|
||||
content += `<p class="quote-inline">RE: <a href="${quoteHREFSan}">${quoteTextSan}</p>`;
|
||||
}
|
||||
const emojis = await getEmojis(note.emojis);
|
||||
const apemojis = emojis.map((emoji)=>renderEmoji(emoji));
|
||||
const tag = [
|
||||
...hashtagTags,
|
||||
...mentionTags,
|
||||
...apemojis
|
||||
];
|
||||
const asPoll = poll ? {
|
||||
type: "Question",
|
||||
content: await toHtml(Object.assign({}, note, {
|
||||
text: text
|
||||
})),
|
||||
[poll.expiresAt && poll.expiresAt < new Date() ? "closed" : "endTime"]: poll.expiresAt,
|
||||
[poll.multiple ? "anyOf" : "oneOf"]: poll.choices.map((text, i)=>({
|
||||
type: "Note",
|
||||
name: text,
|
||||
replies: {
|
||||
type: "Collection",
|
||||
totalItems: poll.votes[i]
|
||||
}
|
||||
}))
|
||||
} : {};
|
||||
const asTalk = isTalk ? {
|
||||
_misskey_talk: true
|
||||
} : {};
|
||||
return {
|
||||
id: `${config.url}/notes/${note.id}`,
|
||||
type: "Note",
|
||||
attributedTo,
|
||||
summary,
|
||||
content,
|
||||
_misskey_content: text,
|
||||
source: {
|
||||
content: text,
|
||||
mediaType: "text/x.misskeymarkdown"
|
||||
},
|
||||
_misskey_quote: quoteId,
|
||||
quoteUri: quoteId,
|
||||
quoteUrl: quoteId,
|
||||
quote: note.canQuote ? quoteId : undefined,
|
||||
published: note.createdAt.toISOString(),
|
||||
to,
|
||||
cc,
|
||||
inReplyTo,
|
||||
attachment: files.map(renderDocument),
|
||||
sensitive: note.cw != null || files.some((file)=>file.isSensitive),
|
||||
tag,
|
||||
interactionPolicy: note.visibility === "public" || note.visibility === "home" ? {
|
||||
canQuote: {
|
||||
automaticApproval: "https://www.w3.org/ns/activitystreams#Public"
|
||||
}
|
||||
} : undefined,
|
||||
quoteAuthorization: note.quoteAuthorization || undefined,
|
||||
...asPoll,
|
||||
...asTalk
|
||||
};
|
||||
}
|
||||
export async function getEmojis(names) {
|
||||
if (names == null || names.length === 0) return [];
|
||||
const emojis = await Promise.all(names.map((name)=>{
|
||||
const parts = name.split("@");
|
||||
return Emojis.findOneBy({
|
||||
name: parts[0],
|
||||
host: parts.length === 2 ? parts[1] : IsNull()
|
||||
});
|
||||
}));
|
||||
return emojis.filter((emoji)=>emoji != null);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Render OrderedCollectionPage
|
||||
* @param id URL of self
|
||||
* @param totalItems Number of total items
|
||||
* @param orderedItems Items
|
||||
* @param partOf URL of base
|
||||
* @param prev URL of prev page (optional)
|
||||
* @param next URL of next page (optional)
|
||||
*/ export default function(id, totalItems, orderedItems, partOf, prev, next) {
|
||||
const page = {
|
||||
id,
|
||||
partOf,
|
||||
type: "OrderedCollectionPage",
|
||||
totalItems,
|
||||
orderedItems
|
||||
};
|
||||
if (prev) page.prev = prev;
|
||||
if (next) page.next = next;
|
||||
return page;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Render OrderedCollection
|
||||
* @param id URL of self
|
||||
* @param totalItems Total number of items
|
||||
* @param first URL of first page (optional)
|
||||
* @param last URL of last page (optional)
|
||||
* @param orderedItems attached objects (optional)
|
||||
*/ export default function(id, totalItems, first, last, orderedItems) {
|
||||
const page = {
|
||||
id,
|
||||
type: "OrderedCollection",
|
||||
totalItems
|
||||
};
|
||||
if (first) page.first = first;
|
||||
if (last) page.last = last;
|
||||
if (orderedItems) page.orderedItems = orderedItems;
|
||||
return page;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import * as mfm from "mfm-js";
|
||||
import config from "../../../config/index.js";
|
||||
import { DriveFiles, UserProfiles } from "../../../models/index.js";
|
||||
import { getUserKeypair } from "../../../misc/keypair-store.js";
|
||||
import { toHtml } from "../../../mfm/to-html.js";
|
||||
import renderImage from "./image.js";
|
||||
import renderKey from "./key.js";
|
||||
import { getEmojis } from "./note.js";
|
||||
import renderEmoji from "./emoji.js";
|
||||
import renderHashtag from "./hashtag.js";
|
||||
export async function renderPerson(user) {
|
||||
const id = `${config.url}/users/${user.id}`;
|
||||
const isSystem = !!user.username.match(/\./);
|
||||
const [avatar, banner, profile] = await Promise.all([
|
||||
user.avatarId ? DriveFiles.findOneBy({
|
||||
id: user.avatarId
|
||||
}) : Promise.resolve(undefined),
|
||||
user.bannerId ? DriveFiles.findOneBy({
|
||||
id: user.bannerId
|
||||
}) : Promise.resolve(undefined),
|
||||
UserProfiles.findOneByOrFail({
|
||||
userId: user.id
|
||||
})
|
||||
]);
|
||||
const attachment = [];
|
||||
if (profile.fields) {
|
||||
for (const field of profile.fields){
|
||||
const value = await toHtml(mfm.parse(field.value), profile.mentions, profile.userHost);
|
||||
attachment.push({
|
||||
type: "PropertyValue",
|
||||
name: field.name,
|
||||
value: value ?? field.value
|
||||
});
|
||||
}
|
||||
}
|
||||
const emojis = await getEmojis(user.emojis);
|
||||
const apemojis = emojis.map((emoji)=>renderEmoji(emoji));
|
||||
const hashtagTags = (user.tags || []).map((tag)=>renderHashtag(tag));
|
||||
const tag = [
|
||||
...apemojis,
|
||||
...hashtagTags
|
||||
];
|
||||
const keypair = await getUserKeypair(user.id);
|
||||
let canBite;
|
||||
if (user.canBite === "anyone") {
|
||||
canBite = "https://www.w3.org/ns/activitystreams#Public";
|
||||
} else if (user.canBite === "followers") {
|
||||
canBite = user.followersUri ?? `${config.url}/users/${user.id}/followers`;
|
||||
}
|
||||
const person = {
|
||||
type: isSystem ? "Application" : user.isBot ? "Service" : "Person",
|
||||
id,
|
||||
inbox: `${id}/inbox`,
|
||||
outbox: `${id}/outbox`,
|
||||
followers: `${id}/followers`,
|
||||
following: `${id}/following`,
|
||||
featured: `${id}/collections/featured`,
|
||||
sharedInbox: `${config.url}/inbox`,
|
||||
endpoints: {
|
||||
sharedInbox: `${config.url}/inbox`
|
||||
},
|
||||
url: `${config.url}/@${user.username}`,
|
||||
preferredUsername: user.username,
|
||||
name: user.name,
|
||||
summary: profile.description ? await toHtml(mfm.parse(profile.description), profile.mentions, profile.userHost) : null,
|
||||
_misskey_summary: profile.description,
|
||||
icon: avatar ? renderImage(avatar) : null,
|
||||
image: banner ? renderImage(banner) : null,
|
||||
tag,
|
||||
manuallyApprovesFollowers: user.isLocked,
|
||||
discoverable: !!user.isExplorable,
|
||||
publicKey: renderKey(user, keypair, "#main-key"),
|
||||
isCat: user.isCat,
|
||||
attachment: attachment.length ? attachment : undefined,
|
||||
pronouns: profile.pronouns,
|
||||
canBite
|
||||
};
|
||||
if (user.movedToUri) {
|
||||
person.movedTo = user.movedToUri;
|
||||
}
|
||||
if (user.alsoKnownAs) {
|
||||
person.alsoKnownAs = user.alsoKnownAs;
|
||||
}
|
||||
if (profile.birthday) {
|
||||
person["vcard:bday"] = profile.birthday;
|
||||
}
|
||||
if (profile.location) {
|
||||
person["vcard:Address"] = profile.location;
|
||||
}
|
||||
return person;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default async function renderQuestion(user, note, poll) {
|
||||
const question = {
|
||||
type: "Question",
|
||||
id: `${config.url}/questions/${note.id}`,
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
content: note.text || "",
|
||||
[poll.multiple ? "anyOf" : "oneOf"]: poll.choices.map((text, i)=>({
|
||||
name: text,
|
||||
_misskey_votes: poll.votes[i],
|
||||
replies: {
|
||||
type: "Collection",
|
||||
totalItems: poll.votes[i]
|
||||
}
|
||||
}))
|
||||
};
|
||||
return question;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import config from "../../../config/index.js";
|
||||
// assumes stamp.note and stamp.targetNote are populated
|
||||
export default ((stamp)=>({
|
||||
id: `${config.url}/stamp/${stamp.id}`,
|
||||
type: "QuoteAuthorization",
|
||||
attributedTo: `${config.url}/users/${stamp.targetNote.userId}`,
|
||||
interactingObject: stamp.note.userHost === null ? `${config.url}/notes/${stamp.note.id}` : stamp.note.uri,
|
||||
interactionTarget: `${config.url}/notes/${stamp.targetNoteId}`
|
||||
}));
|
||||
@@ -0,0 +1,9 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default function renderQuoteRequest(note, targetNote) {
|
||||
return {
|
||||
type: "QuoteRequest",
|
||||
actor: `${config.url}/users/${note.userId}`,
|
||||
object: targetNote.uri,
|
||||
instrument: `${config.url}/notes/${note.id}`
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import config from "../../../config/index.js";
|
||||
export const renderReadActivity = (user, message)=>({
|
||||
type: "Read",
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
object: message.uri
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((object, user)=>({
|
||||
type: "Reject",
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
object
|
||||
}));
|
||||
@@ -0,0 +1,7 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((user, target, object)=>({
|
||||
type: "Remove",
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
target,
|
||||
object
|
||||
}));
|
||||
@@ -0,0 +1,4 @@
|
||||
export default ((id)=>({
|
||||
id,
|
||||
type: "Tombstone"
|
||||
}));
|
||||
@@ -0,0 +1,14 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((object, user)=>{
|
||||
if (object == null) return null;
|
||||
const id = typeof object.id === "string" && object.id.startsWith(config.url) ? `${object.id}/undo` : undefined;
|
||||
return {
|
||||
type: "Undo",
|
||||
...id ? {
|
||||
id
|
||||
} : {},
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
object,
|
||||
published: new Date().toISOString()
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default ((object, user)=>{
|
||||
const activity = {
|
||||
id: `${config.url}/users/${user.id}#updates/${new Date().getTime()}`,
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
type: "Update",
|
||||
to: [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
object,
|
||||
published: new Date().toISOString()
|
||||
};
|
||||
return activity;
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import config from "../../../config/index.js";
|
||||
export default async function renderVote(user, vote, note, poll, pollOwner) {
|
||||
return {
|
||||
id: `${config.url}/users/${user.id}#votes/${vote.id}/activity`,
|
||||
actor: `${config.url}/users/${user.id}`,
|
||||
type: "Create",
|
||||
to: [
|
||||
pollOwner.uri
|
||||
],
|
||||
published: new Date().toISOString(),
|
||||
object: {
|
||||
id: `${config.url}/users/${user.id}#votes/${vote.id}`,
|
||||
type: "Note",
|
||||
attributedTo: `${config.url}/users/${user.id}`,
|
||||
to: [
|
||||
pollOwner.uri
|
||||
],
|
||||
inReplyTo: note.uri,
|
||||
name: poll.choices[vote.choice]
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user