refactor (backend): port acct to backend-rs
This commit is contained in:
parent
beb16ab9cf
commit
452e0b921c
16 changed files with 106 additions and 46 deletions
|
@ -310,8 +310,10 @@ if (!nativeBinding) {
|
|||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { nyaify, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr, IdConvertType, convertId } = nativeBinding
|
||||
const { stringToAcct, acctToString, nyaify, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr, IdConvertType, convertId } = nativeBinding
|
||||
|
||||
module.exports.stringToAcct = stringToAcct
|
||||
module.exports.acctToString = acctToString
|
||||
module.exports.nyaify = nyaify
|
||||
module.exports.AntennaSrcEnum = AntennaSrcEnum
|
||||
module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum
|
||||
|
|
73
packages/backend-rs/src/misc/acct.rs
Normal file
73
packages/backend-rs/src/misc/acct.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "napi", crate::export(object, use_nullable = true))]
|
||||
pub struct Acct {
|
||||
pub username: String,
|
||||
pub host: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", crate::export)]
|
||||
pub fn string_to_acct(acct: &str) -> Acct {
|
||||
let split: Vec<&str> = if let Some(stripped) = acct.strip_prefix('@') {
|
||||
stripped
|
||||
} else {
|
||||
&acct
|
||||
}
|
||||
.split('@')
|
||||
.collect();
|
||||
|
||||
Acct {
|
||||
username: split[0].to_string(),
|
||||
host: if split.len() == 1 {
|
||||
None
|
||||
} else {
|
||||
Some(split[1].to_string())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", crate::export)]
|
||||
pub fn acct_to_string(acct: &Acct) -> String {
|
||||
match &acct.host {
|
||||
Some(host) => format!("{}@{}", acct.username, host),
|
||||
None => acct.username.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{acct_to_string, string_to_acct, Acct};
|
||||
|
||||
#[test]
|
||||
fn test_acct_to_string() {
|
||||
let remote_acct = Acct {
|
||||
username: "firefish".to_string(),
|
||||
host: Some("example.com".to_string()),
|
||||
};
|
||||
let local_acct = Acct {
|
||||
username: "MisakaMikoto".to_string(),
|
||||
host: None,
|
||||
};
|
||||
|
||||
assert_eq!(acct_to_string(&remote_acct), "firefish@example.com");
|
||||
assert_ne!(acct_to_string(&remote_acct), "mastodon@example.com");
|
||||
assert_eq!(acct_to_string(&local_acct), "MisakaMikoto");
|
||||
assert_ne!(acct_to_string(&local_acct), "ShiraiKuroko");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_to_acct() {
|
||||
let remote_acct = Acct {
|
||||
username: "firefish".to_string(),
|
||||
host: Some("example.com".to_string()),
|
||||
};
|
||||
let local_acct = Acct {
|
||||
username: "MisakaMikoto".to_string(),
|
||||
host: None,
|
||||
};
|
||||
|
||||
assert_eq!(string_to_acct("@firefish@example.com"), remote_acct);
|
||||
assert_eq!(string_to_acct("firefish@example.com"), remote_acct);
|
||||
assert_eq!(string_to_acct("@MisakaMikoto"), local_acct);
|
||||
assert_eq!(string_to_acct("MisakaMikoto"), local_acct);
|
||||
}
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
pub mod acct;
|
||||
pub mod nyaify;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
export type Acct = {
|
||||
username: string;
|
||||
host: string | null;
|
||||
};
|
||||
|
||||
export function parse(acct: string): Acct {
|
||||
if (acct.startsWith("@")) acct = acct.slice(1);
|
||||
const split = acct.split("@", 2);
|
||||
return { username: split[0], host: split[1] || null };
|
||||
}
|
||||
|
||||
export function toString(acct: Acct): string {
|
||||
return acct.host == null ? acct.username : `${acct.username}@${acct.host}`;
|
||||
}
|
|
@ -4,7 +4,7 @@ import type { User } from "@/models/entities/user.js";
|
|||
import type { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { Blockings, Followings, UserProfiles } from "@/models/index.js";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
|
@ -30,7 +30,7 @@ export async function checkHitAntenna(
|
|||
|
||||
if (antenna.src === "users") {
|
||||
const accts = antenna.users.map((x) => {
|
||||
const { username, host } = Acct.parse(x);
|
||||
const { username, host } = stringToAcct(x);
|
||||
return getFullApAccount(username, host).toLowerCase();
|
||||
});
|
||||
if (
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
|
@ -42,7 +42,7 @@ export async function importBlocking(
|
|||
|
||||
try {
|
||||
const acct = line.split(",")[0].trim();
|
||||
const { username, host } = Acct.parse(acct);
|
||||
const { username, host } = stringToAcct(acct);
|
||||
|
||||
let target = isSelfHost(host!)
|
||||
? await Users.findOneBy({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IsNull } from "typeorm";
|
||||
import follow from "@/services/following/create.js";
|
||||
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
|
@ -40,7 +40,7 @@ export async function importFollowing(
|
|||
if (file.type.endsWith("json")) {
|
||||
for (const acct of JSON.parse(csv)) {
|
||||
try {
|
||||
const { username, host } = Acct.parse(acct);
|
||||
const { username, host } = stringToAcct(acct);
|
||||
|
||||
let target = isSelfHost(host!)
|
||||
? await Users.findOneBy({
|
||||
|
@ -78,7 +78,7 @@ export async function importFollowing(
|
|||
|
||||
try {
|
||||
const acct = line.split(",")[0].trim();
|
||||
const { username, host } = Acct.parse(acct);
|
||||
const { username, host } = stringToAcct(acct);
|
||||
|
||||
let target = isSelfHost(host!)
|
||||
? await Users.findOneBy({
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { Users, DriveFiles, Mutings } from "@/models/index.js";
|
||||
import type { DbUserImportJobData } from "@/queue/types.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { genId } from "backend-rs";
|
||||
import { genId, stringToAcct } from "backend-rs";
|
||||
import { IsNull } from "typeorm";
|
||||
import { inspect } from "node:util";
|
||||
|
||||
|
@ -43,7 +42,7 @@ export async function importMuting(
|
|||
|
||||
try {
|
||||
const acct = line.split(",")[0].trim();
|
||||
const { username, host } = Acct.parse(acct);
|
||||
const { username, host } = stringToAcct(acct);
|
||||
|
||||
let target = isSelfHost(host!)
|
||||
? await Users.findOneBy({
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { pushUserToUserList } from "@/services/user-list/push.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
|
@ -12,7 +11,7 @@ import {
|
|||
UserLists,
|
||||
UserListJoinings,
|
||||
} from "@/models/index.js";
|
||||
import { genId } from "backend-rs";
|
||||
import { genId, stringToAcct } from "backend-rs";
|
||||
import type { DbUserImportJobData } from "@/queue/types.js";
|
||||
import { IsNull } from "typeorm";
|
||||
import { inspect } from "node:util";
|
||||
|
@ -48,7 +47,7 @@ export async function importUserLists(
|
|||
|
||||
try {
|
||||
const listName = line.split(",")[0].trim();
|
||||
const { username, host } = Acct.parse(line.split(",")[1].trim());
|
||||
const { username, host } = stringToAcct(line.split(",")[1].trim());
|
||||
|
||||
let list = await UserLists.findOneBy({
|
||||
userId: user.id,
|
||||
|
|
|
@ -8,7 +8,7 @@ import { DAY } from "@/const.js";
|
|||
import { apiLogger } from "@/server/api/logger.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { parse } from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { inspect } from "node:util";
|
||||
|
||||
export const meta = {
|
||||
|
@ -72,7 +72,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
|
||||
for (const line of ps.alsoKnownAs) {
|
||||
if (!line) throw new ApiError(meta.errors.noSuchUser);
|
||||
const { username, host } = parse(line);
|
||||
const { username, host } = stringToAcct(line);
|
||||
|
||||
const aka = await resolveUser(username, host).catch((e) => {
|
||||
apiLogger.warn(`failed to resolve remote user:\n${inspect(e)}`);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { getUser } from "@/server/api/common/getters.js";
|
|||
import { Followings, Users } from "@/models/index.js";
|
||||
import config from "@/config/index.js";
|
||||
import { publishMainStream } from "@/services/stream.js";
|
||||
import { parse } from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { inspect } from "node:util";
|
||||
|
||||
export const meta = {
|
||||
|
@ -90,7 +90,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
if (!ps.moveToAccount) throw new ApiError(meta.errors.noSuchMoveTarget);
|
||||
if (user.movedToUri) throw new ApiError(meta.errors.alreadyMoved);
|
||||
|
||||
const { username, host } = parse(ps.moveToAccount);
|
||||
const { username, host } = stringToAcct(ps.moveToAccount);
|
||||
if (!host) throw new ApiError(meta.errors.notRemote);
|
||||
|
||||
const moveTo: User = await resolveUser(username, host).catch((e) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IsNull } from "typeorm";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
|
@ -35,7 +35,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
|
||||
const users = await Promise.all(
|
||||
meta.pinnedUsers
|
||||
.map((acct) => Acct.parse(acct))
|
||||
.map((acct) => stringToAcct(acct))
|
||||
.map((acct) =>
|
||||
Users.findOneBy({
|
||||
usernameLower: acct.username.toLowerCase(),
|
||||
|
|
|
@ -19,7 +19,7 @@ import { Users } from "@/models/index.js";
|
|||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { genIdenticon } from "@/misc/gen-identicon.js";
|
||||
import { createTemp } from "@/misc/create-temp.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { envOption } from "@/env.js";
|
||||
import megalodon, { MegalodonInterface } from "megalodon";
|
||||
import activityPub from "./activitypub.js";
|
||||
|
@ -108,7 +108,7 @@ router.use(nodeinfo.routes());
|
|||
router.use(wellKnown.routes());
|
||||
|
||||
router.get("/avatar/@:acct", async (ctx) => {
|
||||
const { username, host } = Acct.parse(ctx.params.acct);
|
||||
const { username, host } = stringToAcct(ctx.params.acct);
|
||||
const user = await Users.findOne({
|
||||
where: {
|
||||
usernameLower: username.toLowerCase(),
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
Emojis,
|
||||
GalleryPosts,
|
||||
} from "@/models/index.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import { getNoteSummary } from "@/misc/get-note-summary.js";
|
||||
import { queues } from "@/queue/queues.js";
|
||||
import { genOpenapiSpec } from "../api/openapi/gen-spec.js";
|
||||
|
@ -330,7 +330,7 @@ const getFeed = async (
|
|||
if (meta.privateMode) {
|
||||
return;
|
||||
}
|
||||
const { username, host } = Acct.parse(acct);
|
||||
const { username, host } = stringToAcct(acct);
|
||||
const user = await Users.findOneBy({
|
||||
usernameLower: username.toLowerCase(),
|
||||
host: host ?? IsNull(),
|
||||
|
@ -461,7 +461,7 @@ const jsonFeed: Router.Middleware = async (ctx) => {
|
|||
const userPage: Router.Middleware = async (ctx, next) => {
|
||||
const userParam = ctx.params.user;
|
||||
const subParam = ctx.params.sub;
|
||||
const { username, host } = Acct.parse(userParam);
|
||||
const { username, host } = stringToAcct(userParam);
|
||||
|
||||
const user = await Users.findOneBy({
|
||||
usernameLower: username.toLowerCase(),
|
||||
|
@ -580,7 +580,7 @@ router.get("/posts/:note", async (ctx, next) => {
|
|||
|
||||
// Page
|
||||
router.get("/@:user/pages/:page", async (ctx, next) => {
|
||||
const { username, host } = Acct.parse(ctx.params.user);
|
||||
const { username, host } = stringToAcct(ctx.params.user);
|
||||
const user = await Users.findOneBy({
|
||||
usernameLower: username.toLowerCase(),
|
||||
host: host ?? IsNull(),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Router from "@koa/router";
|
||||
|
||||
import config from "@/config/index.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { type Acct, stringToAcct } from "backend-rs";
|
||||
import { links } from "./nodeinfo.js";
|
||||
import { escapeAttribute, escapeValue } from "@/prelude/xml.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
|
@ -110,7 +110,7 @@ router.get(webFingerPath, async (ctx) => {
|
|||
resource.startsWith(`${config.url.toLowerCase()}/users/`)
|
||||
? fromId(resource.split("/").pop()!)
|
||||
: fromAcct(
|
||||
Acct.parse(
|
||||
stringToAcct(
|
||||
resource.startsWith(`${config.url.toLowerCase()}/@`)
|
||||
? resource.split("/").pop()!
|
||||
: resource.startsWith("acct:")
|
||||
|
@ -119,7 +119,7 @@ router.get(webFingerPath, async (ctx) => {
|
|||
),
|
||||
);
|
||||
|
||||
const fromAcct = (acct: Acct.Acct): FindOptionsWhere<User> | number =>
|
||||
const fromAcct = (acct: Acct): FindOptionsWhere<User> | number =>
|
||||
!acct.host || acct.host === config.host.toLowerCase()
|
||||
? {
|
||||
usernameLower: acct.username,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import type { User } from "@/models/entities/user.js";
|
||||
// import { sendEmail } from "./send-email.js";
|
||||
// import { I18n } from "@/misc/i18n.js";
|
||||
// import * as Acct from "@/misc/acct.js";
|
||||
// import { acctToString } from "backend-rs";
|
||||
// TODO
|
||||
//const locales = await import('../../../../locales/index.js');
|
||||
|
||||
|
@ -15,7 +15,7 @@ async function follow(userId: User["id"], follower: User) {
|
|||
const locale = locales['en-US'];
|
||||
const i18n = new I18n(locale);
|
||||
// TODO: render user information html
|
||||
sendEmail(userProfile.email, i18n.t('_email._follow.title'), `${follower.name} (@${Acct.toString(follower)})`, `${follower.name} (@${Acct.toString(follower)})`);
|
||||
sendEmail(userProfile.email, i18n.t('_email._follow.title'), `${follower.name} (@${acctToString(follower)})`, `${follower.name} (@${acctToString(follower)})`);
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ async function receiveFollowRequest(userId: User["id"], follower: User) {
|
|||
const locale = locales['en-US'];
|
||||
const i18n = new I18n(locale);
|
||||
// TODO: render user information html
|
||||
sendEmail(userProfile.email, i18n.t('_email._receiveFollowRequest.title'), `${follower.name} (@${Acct.toString(follower)})`, `${follower.name} (@${Acct.toString(follower)})`);
|
||||
sendEmail(userProfile.email, i18n.t('_email._receiveFollowRequest.title'), `${follower.name} (@${acctToString(follower)})`, `${follower.name} (@${acctToString(follower)})`);
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue