Merge branch 'develop' into feat/scylladb
This commit is contained in:
commit
466c4e5636
11 changed files with 70 additions and 26 deletions
|
@ -184,6 +184,9 @@ reservedUsernames: [
|
||||||
# deliverJobMaxAttempts: 12
|
# deliverJobMaxAttempts: 12
|
||||||
# inboxJobMaxAttempts: 8
|
# inboxJobMaxAttempts: 8
|
||||||
|
|
||||||
|
# Local address used for outgoing requests
|
||||||
|
#outgoingAddress: 127.0.0.1
|
||||||
|
|
||||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||||
#outgoingAddressFamily: ipv4
|
#outgoingAddressFamily: ipv4
|
||||||
|
|
||||||
|
|
|
@ -76,5 +76,5 @@ COPY --from=build /firefish/packages/backend/native-utils/built /firefish/packag
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
VOLUME "/firefish/files"
|
VOLUME "/firefish/files"
|
||||||
ENTRYPOINT [ "/sbin/tini", "--" ]
|
ENTRYPOINT [ "/usr/bin/tini", "--" ]
|
||||||
CMD [ "pnpm", "run", "migrateandstart" ]
|
CMD [ "pnpm", "run", "migrateandstart" ]
|
||||||
|
|
|
@ -2099,7 +2099,7 @@ customKaTeXMacro: Individuelle KaTeX Makros
|
||||||
enableCustomKaTeXMacro: Individuelle KaTeX-Makros aktivieren
|
enableCustomKaTeXMacro: Individuelle KaTeX-Makros aktivieren
|
||||||
replayTutorial: Wiederhole die Benutzeranleitung
|
replayTutorial: Wiederhole die Benutzeranleitung
|
||||||
apps: Apps
|
apps: Apps
|
||||||
caption: Automatische Untertitelung
|
caption: Automatische Beschreibung
|
||||||
pwa: PWA installieren
|
pwa: PWA installieren
|
||||||
cw: Inhaltswarnung
|
cw: Inhaltswarnung
|
||||||
older: älter
|
older: älter
|
||||||
|
@ -2204,3 +2204,7 @@ deletePasskeysConfirm: Alle Passkeys und Security-Keys werden unwiderruflich von
|
||||||
inputNotMatch: Eingabe stimmt nicht überein
|
inputNotMatch: Eingabe stimmt nicht überein
|
||||||
addRe: Ein "re:" am Anfang des Kommentars hinzufügen, um einem Beitrag mit einer Inhaltswarnung
|
addRe: Ein "re:" am Anfang des Kommentars hinzufügen, um einem Beitrag mit einer Inhaltswarnung
|
||||||
zu antworten
|
zu antworten
|
||||||
|
confirm: Bestätigen
|
||||||
|
importZip: ZIP Importieren
|
||||||
|
emojiPackCreator: Emoji-Pack Ersteller
|
||||||
|
exportZip: ZIP Exportieren
|
||||||
|
|
|
@ -303,7 +303,7 @@ emptyDrive: "ドライブは空です"
|
||||||
emptyFolder: "フォルダーは空です"
|
emptyFolder: "フォルダーは空です"
|
||||||
unableToDelete: "削除できません"
|
unableToDelete: "削除できません"
|
||||||
inputNewFileName: "新しいファイル名を入力してください"
|
inputNewFileName: "新しいファイル名を入力してください"
|
||||||
inputNewDescription: "新しいキャプションを入力"
|
inputNewDescription: "新しい説明を入力"
|
||||||
inputNewFolderName: "新しいフォルダ名を入力してください"
|
inputNewFolderName: "新しいフォルダ名を入力してください"
|
||||||
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
|
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。"
|
||||||
hasChildFilesOrFolders: "このフォルダは空でないため、削除できません。"
|
hasChildFilesOrFolders: "このフォルダは空でないため、削除できません。"
|
||||||
|
@ -577,8 +577,8 @@ disablePlayer: "プレイヤーを閉じる"
|
||||||
expandTweet: "ツイートを展開する"
|
expandTweet: "ツイートを展開する"
|
||||||
themeEditor: "テーマエディター"
|
themeEditor: "テーマエディター"
|
||||||
description: "説明"
|
description: "説明"
|
||||||
describeFile: "キャプションを追加"
|
describeFile: "説明を追加"
|
||||||
enterFileDescription: "キャプションを入力"
|
enterFileDescription: "説明を入力"
|
||||||
author: "作者"
|
author: "作者"
|
||||||
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
||||||
manage: "管理"
|
manage: "管理"
|
||||||
|
@ -949,7 +949,7 @@ customSplashIconsDescription: "ユーザがページをロード/リロードす
|
||||||
showUpdates: "Firefishの更新時にポップアップを表示する"
|
showUpdates: "Firefishの更新時にポップアップを表示する"
|
||||||
recommendedInstances: "おすすめサーバー"
|
recommendedInstances: "おすすめサーバー"
|
||||||
recommendedInstancesDescription: "おすすめタイムラインに表示するサーバーを改行区切りで入力してください。"
|
recommendedInstancesDescription: "おすすめタイムラインに表示するサーバーを改行区切りで入力してください。"
|
||||||
caption: "自動でキャプションをつける"
|
caption: "自動で説明をつける"
|
||||||
splash: "スプラッシュスクリーン"
|
splash: "スプラッシュスクリーン"
|
||||||
updateAvailable: "アップデートがありますよ!"
|
updateAvailable: "アップデートがありますよ!"
|
||||||
swipeOnDesktop: "デスクトップでモバイルスタイルのスワイプを可能にする"
|
swipeOnDesktop: "デスクトップでモバイルスタイルのスワイプを可能にする"
|
||||||
|
|
|
@ -85,6 +85,7 @@ export type Source = {
|
||||||
fingerprint?: string;
|
fingerprint?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
outgoingAddress?: string;
|
||||||
outgoingAddressFamily?: "ipv4" | "ipv6" | "dual";
|
outgoingAddressFamily?: "ipv4" | "ipv6" | "dual";
|
||||||
|
|
||||||
deliverJobConcurrency?: number;
|
deliverJobConcurrency?: number;
|
||||||
|
|
|
@ -99,6 +99,7 @@ const _http = new http.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup,
|
lookup: cache.lookup,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
} as http.AgentOptions);
|
} as http.AgentOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,6 +109,7 @@ const _https = new https.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup,
|
lookup: cache.lookup,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
} as https.AgentOptions);
|
} as https.AgentOptions);
|
||||||
|
|
||||||
const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
|
const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
|
||||||
|
@ -123,6 +125,7 @@ export const httpAgent = config.proxy
|
||||||
maxFreeSockets: 256,
|
maxFreeSockets: 256,
|
||||||
scheduling: "lifo",
|
scheduling: "lifo",
|
||||||
proxy: config.proxy,
|
proxy: config.proxy,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
})
|
})
|
||||||
: _http;
|
: _http;
|
||||||
|
|
||||||
|
@ -137,6 +140,7 @@ export const httpsAgent = config.proxy
|
||||||
maxFreeSockets: 256,
|
maxFreeSockets: 256,
|
||||||
scheduling: "lifo",
|
scheduling: "lifo",
|
||||||
proxy: config.proxy,
|
proxy: config.proxy,
|
||||||
|
localAddress: config.outgoingAddress,
|
||||||
})
|
})
|
||||||
: _https;
|
: _https;
|
||||||
|
|
||||||
|
|
|
@ -122,19 +122,31 @@ export default class DeliverManager {
|
||||||
)
|
)
|
||||||
.forEach((recipe) => inboxes.add(recipe.to.inbox!));
|
.forEach((recipe) => inboxes.add(recipe.to.inbox!));
|
||||||
|
|
||||||
|
// Validate Inboxes first
|
||||||
|
const validInboxes = [];
|
||||||
|
for (const inbox of inboxes) {
|
||||||
|
try {
|
||||||
|
validInboxes.push({
|
||||||
|
inbox,
|
||||||
|
host: new URL(inbox).host,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
console.error(`Invalid Inbox ${inbox}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const instancesToSkip = await skippedInstances(
|
const instancesToSkip = await skippedInstances(
|
||||||
// get (unique) list of hosts
|
// get (unique) list of hosts
|
||||||
Array.from(
|
Array.from(new Set(validInboxes.map((valid) => valid.host))),
|
||||||
new Set(Array.from(inboxes).map((inbox) => new URL(inbox).host)),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// deliver
|
// deliver
|
||||||
for (const inbox of inboxes) {
|
for (const valid of validInboxes) {
|
||||||
// skip instances as indicated
|
// skip instances as indicated
|
||||||
if (instancesToSkip.includes(new URL(inbox).host)) continue;
|
if (instancesToSkip.includes(valid.host)) continue;
|
||||||
|
|
||||||
deliver(this.actor, this.activity, inbox);
|
deliver(this.actor, this.activity, valid.inbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as sanitizeHtml from "sanitize-html";
|
import sanitizeHtml from "sanitize-html";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
import { Users, UserProfiles } from "@/models/index.js";
|
import { Users, UserProfiles } from "@/models/index.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import * as sanitizeHtml from "sanitize-html";
|
import * as mfm from "mfm-js";
|
||||||
|
import sanitizeHtml from "sanitize-html";
|
||||||
import { publishAdminStream } from "@/services/stream.js";
|
import { publishAdminStream } from "@/services/stream.js";
|
||||||
import { AbuseUserReports, Users } from "@/models/index.js";
|
import { AbuseUserReports, UserProfiles, Users } from "@/models/index.js";
|
||||||
import { genId } from "@/misc/gen-id.js";
|
import { genId } from "@/misc/gen-id.js";
|
||||||
import { sendEmail } from "@/services/send-email.js";
|
import { sendEmail } from "@/services/send-email.js";
|
||||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { getUser } from "../../common/getters.js";
|
import { getUser } from "../../common/getters.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
|
import { toHtml } from "@/mfm/to-html.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["users"],
|
tags: ["users"],
|
||||||
|
@ -84,6 +86,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const meta = await fetchMeta();
|
||||||
for (const moderator of moderators) {
|
for (const moderator of moderators) {
|
||||||
publishAdminStream(moderator.id, "newAbuseUserReport", {
|
publishAdminStream(moderator.id, "newAbuseUserReport", {
|
||||||
id: report.id,
|
id: report.id,
|
||||||
|
@ -91,16 +94,16 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
reporterId: report.reporterId,
|
reporterId: report.reporterId,
|
||||||
comment: report.comment,
|
comment: report.comment,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const profile = await UserProfiles.findOneBy({ userId: moderator.id });
|
||||||
if (meta.email) {
|
if (profile?.email) {
|
||||||
sendEmail(
|
sendEmail(
|
||||||
meta.email,
|
profile.email,
|
||||||
"New abuse report",
|
"New abuse report",
|
||||||
sanitizeHtml(ps.comment),
|
sanitizeHtml(toHtml(mfm.parse(ps.comment))!),
|
||||||
sanitizeHtml(ps.comment),
|
sanitizeHtml(toHtml(mfm.parse(ps.comment))!),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,3 +74,13 @@ export function convertStatus(status: Entity.Status) {
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertConversation(conversation: Entity.Conversation) {
|
||||||
|
conversation.id = convertId(conversation.id, IdType.MastodonId);
|
||||||
|
conversation.accounts = conversation.accounts.map(convertAccount);
|
||||||
|
if (conversation.last_status) {
|
||||||
|
conversation.last_status = convertStatus(conversation.last_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return conversation;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import Router from "@koa/router";
|
import Router from "@koa/router";
|
||||||
import { getClient } from "../ApiMastodonCompatibleService.js";
|
import { getClient } from "../ApiMastodonCompatibleService.js";
|
||||||
import { ParsedUrlQuery } from "querystring";
|
import { ParsedUrlQuery } from "querystring";
|
||||||
import { convertAccount, convertList, convertStatus } from "../converters.js";
|
import {
|
||||||
|
convertAccount,
|
||||||
|
convertConversation,
|
||||||
|
convertList,
|
||||||
|
convertStatus,
|
||||||
|
} from "../converters.js";
|
||||||
import { convertId, IdType } from "../../index.js";
|
import { convertId, IdType } from "../../index.js";
|
||||||
|
|
||||||
export function limitToInt(q: ParsedUrlQuery) {
|
export function limitToInt(q: ParsedUrlQuery) {
|
||||||
|
@ -136,7 +141,9 @@ export function apiTimelineMastodon(router: Router): void {
|
||||||
const data = await client.getConversationTimeline(
|
const data = await client.getConversationTimeline(
|
||||||
convertTimelinesArgsId(limitToInt(ctx.query)),
|
convertTimelinesArgsId(limitToInt(ctx.query)),
|
||||||
);
|
);
|
||||||
ctx.body = data.data;
|
ctx.body = data.data.map((conversation) =>
|
||||||
|
convertConversation(conversation),
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
console.error(e.response.data);
|
console.error(e.response.data);
|
||||||
|
|
Loading…
Reference in a new issue