refactor (backend): port renderEmoji to backend-rs

This commit is contained in:
naskya 2024-07-30 22:39:42 +09:00
parent da307934e4
commit 6344b72321
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
14 changed files with 144 additions and 65 deletions

View file

@ -1,6 +1,7 @@
BEGIN; BEGIN;
DELETE FROM "migrations" WHERE name IN ( DELETE FROM "migrations" WHERE name IN (
'SetEmojiPublicUrl1722346019160',
'SetAccessTokenName1722134626110', 'SetAccessTokenName1722134626110',
'CreateSystemActors1720618854585', 'CreateSystemActors1720618854585',
'AddMastodonSubscriptionType1715181461692', 'AddMastodonSubscriptionType1715181461692',
@ -41,6 +42,9 @@ DELETE FROM "migrations" WHERE name IN (
'RemoveNativeUtilsMigration1705877093218' 'RemoveNativeUtilsMigration1705877093218'
); );
-- set-emoji-public-url
ALTER TABLE "emoji" ALTER COLUMN "publicUrl" SET DEFAULT '';
-- addMastodonSubscriptionType -- addMastodonSubscriptionType
ALTER TABLE "sw_subscription" DROP COLUMN "subscriptionTypes"; ALTER TABLE "sw_subscription" DROP COLUMN "subscriptionTypes";
DROP TYPE "push_subscription_type"; DROP TYPE "push_subscription_type";

View file

@ -25,13 +25,6 @@ export interface AbuseUserReportLike {
comment: string comment: string
} }
export interface Accept {
id: string
type: Activity
actor: string
object: Follow
}
export interface AccessToken { export interface AccessToken {
id: string id: string
createdAt: DateTimeWithTimeZone createdAt: DateTimeWithTimeZone
@ -55,9 +48,6 @@ export interface Acct {
export declare function acctToString(acct: Acct): string export declare function acctToString(acct: Acct): string
export type Activity = 'Accept'|
'Follow';
export interface Ad { export interface Ad {
id: string id: string
createdAt: DateTimeWithTimeZone createdAt: DateTimeWithTimeZone
@ -114,6 +104,33 @@ export type AntennaSrc = 'all'|
'list'| 'list'|
'users'; 'users';
export interface ApAccept {
id: string
type: ApObject
actor: string
object: ApFollow
}
export interface ApEmoji {
id: string
type: ApObject
name: string
updated: string
icon: Icon
}
export interface ApFollow {
id: string
type: ApObject
actor: string
object: string
}
export type ApObject = 'Accept'|
'Emoji'|
'Follow'|
'Image';
export interface App { export interface App {
id: string id: string
createdAt: DateTimeWithTimeZone createdAt: DateTimeWithTimeZone
@ -420,13 +437,6 @@ export declare function fetchMeta(): Promise<Meta>
/** Fetches and returns the NodeInfo (version 2.0) of a remote server. */ /** Fetches and returns the NodeInfo (version 2.0) of a remote server. */
export declare function fetchNodeinfo(host: string): Promise<Nodeinfo> export declare function fetchNodeinfo(host: string): Promise<Nodeinfo>
export interface Follow {
id: string
type: Activity
actor: string
object: string
}
export interface Following { export interface Following {
id: string id: string
createdAt: DateTimeWithTimeZone createdAt: DateTimeWithTimeZone
@ -532,6 +542,12 @@ export interface Hashtag {
attachedRemoteUsersCount: number attachedRemoteUsersCount: number
} }
export interface Icon {
type: ApObject
mediaType: string
url: string
}
export interface IdConfig { export interface IdConfig {
length?: number length?: number
fingerprint?: string fingerprint?: string
@ -1275,11 +1291,13 @@ export type RelayStatus = 'accepted'|
/** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */ /** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */
export declare function removeOldAttestationChallenges(): Promise<void> export declare function removeOldAttestationChallenges(): Promise<void>
export declare function renderAccept(userId: string, followObject: Follow): Accept export declare function renderAccept(userId: string, followObject: Follow): ApAccept
export declare function renderFollow(follower: UserLike, followee: UserLike, requestId?: string | undefined | null): Follow export declare function renderEmoji(emoji: Emoji): ApEmoji
export declare function renderFollowRelay(relayId: string): Promise<Follow> export declare function renderFollow(follower: UserLike, followee: UserLike, requestId?: string | undefined | null): ApFollow
export declare function renderFollowRelay(relayId: string): Promise<ApFollow>
export interface RenoteMuting { export interface RenoteMuting {
id: string id: string

View file

@ -362,8 +362,8 @@ if (!nativeBinding) {
} }
module.exports.acctToString = nativeBinding.acctToString module.exports.acctToString = nativeBinding.acctToString
module.exports.Activity = nativeBinding.Activity
module.exports.AntennaSrc = nativeBinding.AntennaSrc module.exports.AntennaSrc = nativeBinding.AntennaSrc
module.exports.ApObject = nativeBinding.ApObject
module.exports.ChatEvent = nativeBinding.ChatEvent module.exports.ChatEvent = nativeBinding.ChatEvent
module.exports.ChatIndexEvent = nativeBinding.ChatIndexEvent module.exports.ChatIndexEvent = nativeBinding.ChatIndexEvent
module.exports.checkWordMute = nativeBinding.checkWordMute module.exports.checkWordMute = nativeBinding.checkWordMute
@ -439,6 +439,7 @@ module.exports.PushSubscriptionType = nativeBinding.PushSubscriptionType
module.exports.RelayStatus = nativeBinding.RelayStatus module.exports.RelayStatus = nativeBinding.RelayStatus
module.exports.removeOldAttestationChallenges = nativeBinding.removeOldAttestationChallenges module.exports.removeOldAttestationChallenges = nativeBinding.removeOldAttestationChallenges
module.exports.renderAccept = nativeBinding.renderAccept module.exports.renderAccept = nativeBinding.renderAccept
module.exports.renderEmoji = nativeBinding.renderEmoji
module.exports.renderFollow = nativeBinding.renderFollow module.exports.renderFollow = nativeBinding.renderFollow
module.exports.renderFollowRelay = nativeBinding.renderFollowRelay module.exports.renderFollowRelay = nativeBinding.renderFollowRelay
module.exports.safeForSql = nativeBinding.safeForSql module.exports.safeForSql = nativeBinding.safeForSql

View file

@ -3,21 +3,21 @@ use crate::config::CONFIG;
use uuid::Uuid; use uuid::Uuid;
#[macros::export(object)] #[macros::export(object)]
pub struct Accept { pub struct ApAccept {
pub id: String, pub id: String,
pub r#type: Activity, pub r#type: ApObject,
pub actor: String, pub actor: String,
pub object: follow::Follow, pub object: follow::ApFollow,
} }
impl ActivityPubObject for Accept {} impl ActivityPubObject for ApAccept {}
impl Accept { impl ApAccept {
#[allow(dead_code)] // TODO: remove this line #[allow(dead_code)] // TODO: remove this line
fn new(user_id: String, follow_object: follow::Follow) -> Self { fn new(user_id: String, follow_object: follow::ApFollow) -> Self {
Self { Self {
id: format!("{}/{}", CONFIG.url, Uuid::new_v4()), id: format!("{}/{}", CONFIG.url, Uuid::new_v4()),
r#type: Activity::Accept, r#type: ApObject::Accept,
actor: format!("{}/users/{}", CONFIG.url, user_id), actor: format!("{}/users/{}", CONFIG.url, user_id),
object: follow_object, object: follow_object,
} }
@ -25,9 +25,9 @@ impl Accept {
} }
#[cfg(any(test, doctest, feature = "napi"))] #[cfg(any(test, doctest, feature = "napi"))]
type Follow = follow::Follow; type Follow = follow::ApFollow;
#[macros::ts_export] #[macros::ts_export]
pub fn render_accept(user_id: String, follow_object: Follow) -> Accept { pub fn render_accept(user_id: String, follow_object: Follow) -> ApAccept {
Accept::new(user_id, follow_object) ApAccept::new(user_id, follow_object)
} }

View file

@ -0,0 +1,51 @@
use super::*;
use crate::{config::CONFIG, model::entity::emoji};
use chrono::Utc;
#[macros::export(object)]
pub struct ApEmoji {
pub id: String,
pub r#type: ApObject,
pub name: String,
pub updated: String,
pub icon: Icon,
}
#[macros::export(object)]
pub struct Icon {
pub r#type: ApObject,
pub media_type: String,
pub url: String,
}
impl ActivityPubObject for ApEmoji {}
impl ApEmoji {
#[allow(dead_code)] // TODO: remove this line
fn new(emoji: emoji::Model) -> Self {
Self {
id: format!("{}/emojis/{}", CONFIG.url, emoji.name),
r#type: ApObject::Emoji,
name: format!(":{}:", emoji.name),
updated: emoji
.updated_at
.unwrap_or_else(|| Utc::now().into())
.to_rfc3339(),
icon: Icon {
r#type: ApObject::Image,
media_type: emoji.r#type.unwrap_or_else(|| "image/png".to_owned()),
url: emoji.public_url,
},
}
}
}
// for napi export
// https://github.com/napi-rs/napi-rs/issues/2060
#[allow(dead_code)] // TODO: remove this line
type Emoji = emoji::Model;
#[macros::ts_export]
pub fn render_emoji(emoji: Emoji) -> ApEmoji {
ApEmoji::new(emoji)
}

View file

@ -9,14 +9,14 @@ pub struct UserLike {
} }
#[macros::export(object)] #[macros::export(object)]
pub struct Follow { pub struct ApFollow {
pub id: String, pub id: String,
pub r#type: Activity, pub r#type: ApObject,
pub actor: String, pub actor: String,
pub object: String, pub object: String,
} }
impl ActivityPubObject for Follow {} impl ActivityPubObject for ApFollow {}
#[macros::errors] #[macros::errors]
pub enum Error { pub enum Error {
@ -26,7 +26,7 @@ pub enum Error {
MissingFolloweeUri, MissingFolloweeUri,
} }
impl Follow { impl ApFollow {
#[allow(dead_code)] // TODO: remove this line #[allow(dead_code)] // TODO: remove this line
fn new( fn new(
follower: UserLike, follower: UserLike,
@ -37,7 +37,7 @@ impl Follow {
id: request_id.unwrap_or_else(|| { id: request_id.unwrap_or_else(|| {
format!("{}/follows/{}/{}", CONFIG.url, follower.id, followee.id) format!("{}/follows/{}/{}", CONFIG.url, follower.id, followee.id)
}), }),
r#type: Activity::Follow, r#type: ApObject::Follow,
actor: match user::is_local!(follower) { actor: match user::is_local!(follower) {
true => format!("{}/users/{}", CONFIG.url, follower.id), true => format!("{}/users/{}", CONFIG.url, follower.id),
false => follower.uri.ok_or(Error::MissingFollowerUri)?, false => follower.uri.ok_or(Error::MissingFollowerUri)?,
@ -53,7 +53,7 @@ impl Follow {
async fn new_relay(relay_id: String) -> Result<Self, internal_actor::relay::Error> { async fn new_relay(relay_id: String) -> Result<Self, internal_actor::relay::Error> {
Ok(Self { Ok(Self {
id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id), id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id),
r#type: Activity::Follow, r#type: ApObject::Follow,
actor: format!( actor: format!(
"{}/users/{}", "{}/users/{}",
CONFIG.url, CONFIG.url,
@ -69,11 +69,13 @@ pub fn render_follow(
follower: UserLike, follower: UserLike,
followee: UserLike, followee: UserLike,
request_id: Option<String>, request_id: Option<String>,
) -> Result<Follow, Error> { ) -> Result<ApFollow, Error> {
Follow::new(follower, followee, request_id) ApFollow::new(follower, followee, request_id)
} }
#[macros::ts_export] #[macros::ts_export]
pub async fn render_follow_relay(relay_id: String) -> Result<Follow, internal_actor::relay::Error> { pub async fn render_follow_relay(
Follow::new_relay(relay_id).await relay_id: String,
) -> Result<ApFollow, internal_actor::relay::Error> {
ApFollow::new_relay(relay_id).await
} }

View file

@ -1,12 +1,15 @@
pub mod accept; pub mod accept;
pub mod emoji;
pub mod follow; pub mod follow;
pub trait ActivityPubObject {} pub trait ActivityPubObject {}
#[macros::export(string_enum)] #[macros::export(string_enum)]
pub enum Activity { pub enum ApObject {
Accept, Accept,
Emoji,
Follow, Follow,
Image,
} }
const AS_PUBLIC_URL: &str = "https://www.w3.org/ns/activitystreams#Public"; const AS_PUBLIC_URL: &str = "https://www.w3.org/ns/activitystreams#Public";

View file

@ -0,0 +1,18 @@
import type { MigrationInterface, QueryRunner } from "typeorm";
export class SetEmojiPublicUrl1722346019160 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`UPDATE "emoji" SET "publicUrl" = "originalUrl" WHERE "publicUrl" = ''`,
);
await queryRunner.query(
`ALTER TABLE "emoji" ALTER COLUMN "publicUrl" DROP DEFAULT`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "emoji" ALTER COLUMN "publicUrl" SET DEFAULT ''`,
);
}
}

View file

@ -38,7 +38,6 @@ export class Emoji {
@Column("varchar", { @Column("varchar", {
length: 512, length: 512,
default: "",
}) })
public publicUrl: string; public publicUrl: string;

View file

@ -1,17 +0,0 @@
import { config } from "@/config.js";
import type { Emoji } from "@/models/entities/emoji.js";
export default (emoji: 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.type || "image/png",
url: emoji.publicUrl || emoji.originalUrl, // || emoji.originalUrl してるのは後方互換性のため
},
});

View file

@ -3,7 +3,7 @@ import { config } from "@/config.js";
import type { NoteReaction } from "@/models/entities/note-reaction.js"; import type { NoteReaction } from "@/models/entities/note-reaction.js";
import type { Note } from "@/models/entities/note.js"; import type { Note } from "@/models/entities/note.js";
import { Emojis } from "@/models/index.js"; import { Emojis } from "@/models/index.js";
import renderEmoji from "./emoji.js"; import { renderEmoji } from "backend-rs";
export const renderLike = async (noteReaction: NoteReaction, note: Note) => { export const renderLike = async (noteReaction: NoteReaction, note: Note) => {
const reaction = noteReaction.reaction; const reaction = noteReaction.reaction;

View file

@ -6,7 +6,7 @@ import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js";
import type { Emoji } from "@/models/entities/emoji.js"; import type { Emoji } from "@/models/entities/emoji.js";
import type { Poll } from "@/models/entities/poll.js"; import type { Poll } from "@/models/entities/poll.js";
import toHtml from "@/remote/activitypub/misc/get-note-html.js"; import toHtml from "@/remote/activitypub/misc/get-note-html.js";
import renderEmoji from "./emoji.js"; import { renderEmoji } from "backend-rs";
import renderMention from "./mention.js"; import renderMention from "./mention.js";
import renderHashtag from "./hashtag.js"; import renderHashtag from "./hashtag.js";
import renderDocument from "./document.js"; import renderDocument from "./document.js";

View file

@ -4,11 +4,11 @@ import { config } from "@/config.js";
import type { ILocalUser } from "@/models/entities/user.js"; import type { ILocalUser } from "@/models/entities/user.js";
import { DriveFiles, UserProfiles } from "@/models/index.js"; import { DriveFiles, UserProfiles } from "@/models/index.js";
import { getUserKeypair } from "@/misc/keypair-store.js"; import { getUserKeypair } from "@/misc/keypair-store.js";
import { toHtml } from "../../../mfm/to-html.js"; import { toHtml } from "@/mfm/to-html.js";
import renderImage from "./image.js"; import renderImage from "./image.js";
import renderKey from "./key.js"; import renderKey from "./key.js";
import { getEmojis } from "./note.js"; import { getEmojis } from "./note.js";
import renderEmoji from "./emoji.js"; import { renderEmoji } from "backend-rs";
import renderHashtag from "./hashtag.js"; import renderHashtag from "./hashtag.js";
import type { IIdentifier } from "../models/identifier.js"; import type { IIdentifier } from "../models/identifier.js";

View file

@ -7,12 +7,12 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js";
import renderNote from "@/remote/activitypub/renderer/note.js"; import renderNote from "@/remote/activitypub/renderer/note.js";
import renderKey from "@/remote/activitypub/renderer/key.js"; import renderKey from "@/remote/activitypub/renderer/key.js";
import { renderPerson } from "@/remote/activitypub/renderer/person.js"; import { renderPerson } from "@/remote/activitypub/renderer/person.js";
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
import { inbox as processInbox } from "@/queue/index.js"; import { inbox as processInbox } from "@/queue/index.js";
import { import {
fetchMeta, fetchMeta,
getInstanceActor, getInstanceActor,
isSelfHost, isSelfHost,
renderEmoji,
renderFollow, renderFollow,
} from "backend-rs"; } from "backend-rs";
import { import {