refactor: cache suspended users
This commit is contained in:
parent
19d7dc8b84
commit
8e0b0c7cb9
21 changed files with 234 additions and 225 deletions
|
@ -404,7 +404,7 @@ export async function execPaginationQuery(
|
|||
userIds?: string[];
|
||||
},
|
||||
filter?: {
|
||||
note?: (_: ScyllaNote[]) => Promise<ScyllaNote[]>;
|
||||
note?: (_: ScyllaNote[]) => ScyllaNote[];
|
||||
reaction?: (_: ScyllaNoteReaction[]) => Promise<ScyllaNoteReaction[]>;
|
||||
notification?: (_: ScyllaNotification[]) => Promise<ScyllaNotification[]>;
|
||||
},
|
||||
|
@ -492,7 +492,7 @@ export async function execPaginationQuery(
|
|||
} else {
|
||||
const notes = result.rows.map(parseScyllaNote);
|
||||
(found as ScyllaNote[]).push(
|
||||
...(filter?.note ? await filter.note(notes) : notes),
|
||||
...(filter?.note ? filter.note(notes) : notes),
|
||||
);
|
||||
untilDate = notes[notes.length - 1].createdAt;
|
||||
}
|
||||
|
@ -517,11 +517,11 @@ export async function execPaginationQuery(
|
|||
return found as ScyllaNote[];
|
||||
}
|
||||
|
||||
export async function filterVisibility(
|
||||
export function filterVisibility(
|
||||
notes: ScyllaNote[],
|
||||
user: { id: User["id"] } | null,
|
||||
followingIds?: User["id"][],
|
||||
): Promise<ScyllaNote[]> {
|
||||
followingIds: User["id"][],
|
||||
): ScyllaNote[] {
|
||||
let filtered = notes;
|
||||
|
||||
if (!user) {
|
||||
|
@ -529,15 +529,6 @@ export async function filterVisibility(
|
|||
["public", "home"].includes(note.visibility),
|
||||
);
|
||||
} else {
|
||||
let ids: User["id"][];
|
||||
if (followingIds) {
|
||||
ids = followingIds;
|
||||
} else {
|
||||
ids = await LocalFollowingsCache.init(user.id).then((cache) =>
|
||||
cache.getAll(),
|
||||
);
|
||||
}
|
||||
|
||||
filtered = filtered.filter(
|
||||
(note) =>
|
||||
["public", "home"].includes(note.visibility) ||
|
||||
|
@ -545,18 +536,18 @@ export async function filterVisibility(
|
|||
note.visibleUserIds.includes(user.id) ||
|
||||
note.mentions.includes(user.id) ||
|
||||
(note.visibility === "followers" &&
|
||||
(ids.includes(note.userId) || note.replyUserId === user.id)),
|
||||
(followingIds.includes(note.userId) || note.replyUserId === user.id)),
|
||||
);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
export async function filterChannel(
|
||||
export function filterChannel(
|
||||
notes: ScyllaNote[],
|
||||
user: { id: User["id"] } | null,
|
||||
followingIds?: Channel["id"][],
|
||||
): Promise<ScyllaNote[]> {
|
||||
followingIds: Channel["id"][],
|
||||
): ScyllaNote[] {
|
||||
let filtered = notes;
|
||||
|
||||
if (!user) {
|
||||
|
@ -564,16 +555,8 @@ export async function filterChannel(
|
|||
} else {
|
||||
const channelNotes = filtered.filter((note) => !!note.channelId);
|
||||
if (channelNotes.length > 0) {
|
||||
let followings: Channel["id"][];
|
||||
if (followingIds) {
|
||||
followings = followingIds;
|
||||
} else {
|
||||
followings = await ChannelFollowingsCache.init(user.id).then((cache) =>
|
||||
cache.getAll(),
|
||||
);
|
||||
}
|
||||
filtered = filtered.filter(
|
||||
(note) => !note.channelId || followings.includes(note.channelId),
|
||||
(note) => !note.channelId || followingIds.includes(note.channelId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -581,11 +564,11 @@ export async function filterChannel(
|
|||
return filtered;
|
||||
}
|
||||
|
||||
export async function filterReply(
|
||||
export function filterReply(
|
||||
notes: ScyllaNote[],
|
||||
withReplies: boolean,
|
||||
user: { id: User["id"] } | null,
|
||||
): Promise<ScyllaNote[]> {
|
||||
): ScyllaNote[] {
|
||||
let filtered = notes;
|
||||
|
||||
if (!user) {
|
||||
|
@ -605,113 +588,60 @@ export async function filterReply(
|
|||
return filtered;
|
||||
}
|
||||
|
||||
export async function filterMutedUser(
|
||||
export function filterMutedUser(
|
||||
notes: ScyllaNote[],
|
||||
user: { id: User["id"] },
|
||||
mutedIds?: User["id"][],
|
||||
mutedInstances?: UserProfile["mutedInstances"],
|
||||
mutedIds: User["id"][],
|
||||
mutedInstances: UserProfile["mutedInstances"],
|
||||
exclude?: User,
|
||||
): Promise<ScyllaNote[]> {
|
||||
let ids: User["id"][];
|
||||
let instances: UserProfile["mutedInstances"];
|
||||
|
||||
if (mutedIds) {
|
||||
ids = mutedIds;
|
||||
} else {
|
||||
ids = await UserMutingsCache.init(user.id).then((cache) => cache.getAll());
|
||||
}
|
||||
|
||||
if (mutedInstances) {
|
||||
instances = mutedInstances;
|
||||
} else {
|
||||
instances = await InstanceMutingsCache.init(user.id).then((cache) =>
|
||||
cache.getAll(),
|
||||
);
|
||||
}
|
||||
): ScyllaNote[] {
|
||||
let userIds: User["id"][] = mutedIds;
|
||||
|
||||
if (exclude) {
|
||||
ids = ids.filter((id) => id !== exclude.id);
|
||||
userIds = mutedIds.filter((id) => id !== exclude.id);
|
||||
}
|
||||
|
||||
return notes.filter(
|
||||
(note) =>
|
||||
!ids.includes(note.userId) &&
|
||||
!(note.replyUserId && ids.includes(note.replyUserId)) &&
|
||||
!(note.renoteUserId && ids.includes(note.renoteUserId)) &&
|
||||
!(note.userHost && instances.includes(note.userHost)) &&
|
||||
!(note.replyUserHost && instances.includes(note.replyUserHost)) &&
|
||||
!(note.renoteUserHost && instances.includes(note.renoteUserHost)),
|
||||
!userIds.includes(note.userId) &&
|
||||
!(note.replyUserId && userIds.includes(note.replyUserId)) &&
|
||||
!(note.renoteUserId && userIds.includes(note.renoteUserId)) &&
|
||||
!(note.userHost && mutedInstances.includes(note.userHost)) &&
|
||||
!(note.replyUserHost && mutedInstances.includes(note.replyUserHost)) &&
|
||||
!(note.renoteUserHost && mutedInstances.includes(note.renoteUserHost)),
|
||||
);
|
||||
}
|
||||
|
||||
export async function filterMutedNote(
|
||||
export function filterMutedNote(
|
||||
notes: ScyllaNote[],
|
||||
user: { id: User["id"] },
|
||||
mutedWords?: string[][],
|
||||
): Promise<ScyllaNote[]> {
|
||||
let words = mutedWords;
|
||||
|
||||
if (!words) {
|
||||
words = await userWordMuteCache.fetchMaybe(user.id, () =>
|
||||
UserProfiles.findOne({
|
||||
select: ["mutedWords"],
|
||||
where: { userId: user.id },
|
||||
}).then((profile) => profile?.mutedWords),
|
||||
);
|
||||
}
|
||||
|
||||
if (words && words.length > 0) {
|
||||
mutedWords: string[][],
|
||||
): ScyllaNote[] {
|
||||
if (mutedWords.length > 0) {
|
||||
return notes.filter(
|
||||
(note) => !getWordHardMute(note, user, words as string[][]),
|
||||
(note) => !getWordHardMute(note, user, mutedWords),
|
||||
);
|
||||
}
|
||||
|
||||
return notes;
|
||||
}
|
||||
|
||||
export async function filterBlockUser(
|
||||
export function filterBlockUser(
|
||||
notes: ScyllaNote[],
|
||||
user: { id: User["id"] },
|
||||
blockIds?: User["id"][],
|
||||
): Promise<ScyllaNote[]> {
|
||||
let ids: User["id"][];
|
||||
|
||||
if (blockIds) {
|
||||
ids = blockIds;
|
||||
} else {
|
||||
const blocked = await UserBlockedCache.init(user.id).then((cache) =>
|
||||
cache.getAll(),
|
||||
);
|
||||
const blocking = await UserBlockingCache.init(user.id).then((cache) =>
|
||||
cache.getAll(),
|
||||
);
|
||||
ids = [...blocked, ...blocking];
|
||||
}
|
||||
|
||||
blockIds: User["id"][],
|
||||
): ScyllaNote[] {
|
||||
return notes.filter(
|
||||
(note) =>
|
||||
!ids.includes(note.userId) &&
|
||||
!(note.replyUserId && ids.includes(note.replyUserId)) &&
|
||||
!(note.renoteUserId && ids.includes(note.renoteUserId)),
|
||||
!blockIds.includes(note.userId) &&
|
||||
!(note.replyUserId && blockIds.includes(note.replyUserId)) &&
|
||||
!(note.renoteUserId && blockIds.includes(note.renoteUserId)),
|
||||
);
|
||||
}
|
||||
|
||||
export async function filterMutedRenotes(
|
||||
export function filterMutedRenotes(
|
||||
notes: ScyllaNote[],
|
||||
user: { id: User["id"] },
|
||||
muteeIds?: User["id"][],
|
||||
): Promise<ScyllaNote[]> {
|
||||
let ids: User["id"][];
|
||||
|
||||
if (muteeIds) {
|
||||
ids = muteeIds;
|
||||
} else {
|
||||
ids = await RenoteMutingsCache.init(user.id).then((cache) =>
|
||||
cache.getAll(),
|
||||
);
|
||||
}
|
||||
|
||||
muteeIds: User["id"][],
|
||||
): ScyllaNote[] {
|
||||
return notes.filter(
|
||||
(note) => note.text || !note.renoteId || !ids.includes(note.userId),
|
||||
(note) => note.text || !note.renoteId || !muteeIds.includes(note.userId),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
Mutings,
|
||||
RenoteMutings,
|
||||
UserProfiles,
|
||||
Users,
|
||||
} from "@/models/index.js";
|
||||
import { IsNull } from "typeorm";
|
||||
import config from "@/config/index.js";
|
||||
|
@ -479,3 +480,21 @@ export class RenoteMutingsCache extends SetCache {
|
|||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
export class SuspendedUsersCache extends SetCache {
|
||||
private constructor() {
|
||||
const fetcher = () => Users.find({
|
||||
select: ["id"],
|
||||
where: { isSuspended: true }
|
||||
}).then((users) => users.map(({ id }) => id));
|
||||
|
||||
super("suspendedUsers", "system", fetcher);
|
||||
}
|
||||
|
||||
public static async init(): Promise<SuspendedUsersCache> {
|
||||
const cache = new SuspendedUsersCache();
|
||||
await cache.fetch();
|
||||
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
scyllaClient,
|
||||
} from "@/db/scylla.js";
|
||||
import { userByIdCache } from "@/services/user-cache.js";
|
||||
import { LocalFollowingsCache } from "@/misc/cache.js";
|
||||
|
||||
/**
|
||||
* Get note for API processing, taking into account visibility.
|
||||
|
@ -28,7 +29,13 @@ export async function getNote(
|
|||
);
|
||||
if (result.rowLength > 0) {
|
||||
const candidate = parseScyllaNote(result.first());
|
||||
const filtered = await filterVisibility([candidate], me, followingIds);
|
||||
let ids: string[] = [];
|
||||
if (followingIds) {
|
||||
ids = followingIds
|
||||
} else if (me) {
|
||||
ids = await LocalFollowingsCache.init(me.id).then((cache) => cache.getAll());
|
||||
}
|
||||
const filtered = filterVisibility([candidate], me, ids);
|
||||
if (filtered.length > 0) {
|
||||
note = filtered[0];
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
|||
import { doPostSuspend } from "@/services/suspend-user.js";
|
||||
import { publishUserEvent } from "@/services/stream.js";
|
||||
import { scyllaClient } from "@/db/scylla.js";
|
||||
import { SuspendedUsersCache } from "@/misc/cache.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
@ -37,6 +38,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
throw new Error("cannot suspend moderator");
|
||||
}
|
||||
|
||||
await SuspendedUsersCache.init().then((cache) => cache.add(user.id));
|
||||
await Users.update(user.id, {
|
||||
isSuspended: true,
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { SuspendedUsersCache } from "@/misc/cache.js";
|
||||
import define from "../../define.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { insertModerationLog } from "@/services/insert-moderation-log.js";
|
||||
|
@ -25,6 +26,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
throw new Error("user not found");
|
||||
}
|
||||
|
||||
await SuspendedUsersCache.init().then((cache) => cache.delete(user.id));
|
||||
await Users.update(user.id, {
|
||||
isSuspended: false,
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -93,6 +94,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
blockerIds,
|
||||
blockingIds,
|
||||
renoteMutedIds,
|
||||
suspendedUsers,
|
||||
] = await Promise.all([
|
||||
LocalFollowingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
|
@ -108,6 +110,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockedCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
RenoteMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
SuspendedUsersCache.init().then((cache) => cache.getAll()),
|
||||
]);
|
||||
|
||||
const userIds: string[] = [];
|
||||
|
@ -139,21 +142,21 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.map((xs) => xs.filter((x) => x !== ""))
|
||||
.filter((xs) => xs.length > 0);
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
let filtered = await filterVisibility(notes, user, followingUserIds);
|
||||
filtered = await filterReply(filtered, antenna.withReplies, user);
|
||||
filtered = await filterMutedUser(
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterVisibility(notes, user, followingUserIds);
|
||||
filtered = filterReply(filtered, antenna.withReplies, user);
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUsers,
|
||||
]);
|
||||
filtered = await filterMutedRenotes(filtered, user, renoteMutedIds);
|
||||
filtered = filterMutedRenotes(filtered, renoteMutedIds);
|
||||
if (antenna.withFile) {
|
||||
filtered = filtered.filter((n) => n.files.length > 0);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
scyllaClient,
|
||||
} from "@/db/scylla.js";
|
||||
import {
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -87,15 +88,17 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUsers = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
if (!user) return notes;
|
||||
let filtered = await filterMutedUser(notes, user, mutedUserIds, []);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterBlockUser(notes, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUsers
|
||||
]);
|
||||
if (!user) return filtered;
|
||||
filtered = filterMutedUser(notes, mutedUserIds, []);
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
return filtered;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
import {
|
||||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -91,6 +92,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
}
|
||||
|
||||
const noteIds = await ClipNotes.find({
|
||||
select: ["noteId"],
|
||||
where: whereOpt,
|
||||
order: { noteId: "DESC" },
|
||||
take: Math.min(ps.limit * 2, config.scylla?.queryLimit ?? 100),
|
||||
|
@ -108,6 +110,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
blockingIds,
|
||||
]: string[][] = [];
|
||||
let mutedWords: string[][];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
if (user) {
|
||||
[
|
||||
followingUserIds,
|
||||
|
@ -132,22 +136,22 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
let filtered = notes;
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterBlockUser(notes, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
if (user) {
|
||||
filtered = await filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
}
|
||||
return filtered;
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
import {
|
||||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -98,12 +99,14 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
mutedInstances,
|
||||
blockerIds,
|
||||
blockingIds,
|
||||
suspendedUsers,
|
||||
] = await Promise.all([
|
||||
LocalFollowingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
InstanceMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserBlockedCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
SuspendedUsersCache.init().then((cache) => cache.getAll()),
|
||||
]);
|
||||
const validUserIds = [user.id, ...followingUserIds];
|
||||
|
||||
|
@ -130,7 +133,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
n.notifierId &&
|
||||
(mutedUserIds.includes(n.notifierId) ||
|
||||
blockingIds.includes(n.notifierId) ||
|
||||
blockerIds.includes(n.notifierId))
|
||||
blockerIds.includes(n.notifierId) ||
|
||||
suspendedUsers.includes(n.notifierId))
|
||||
),
|
||||
);
|
||||
if (ps.directOnly) {
|
||||
|
|
|
@ -42,7 +42,7 @@ export const paramDef = {
|
|||
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
if (scyllaClient) {
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = notes.filter((note) => !note.localOnly);
|
||||
if (ps.reply === undefined) {
|
||||
filtered = filtered.filter(
|
||||
|
|
|
@ -19,6 +19,7 @@ import type { Note } from "@/models/entities/note.js";
|
|||
import {
|
||||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -67,6 +68,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
blockingIds,
|
||||
]: string[][] = [];
|
||||
let mutedWords: string[][] = [];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
if (user) {
|
||||
[
|
||||
followingUserIds,
|
||||
|
@ -91,6 +94,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const root = await getNote(ps.noteId, user, followingUserIds).catch(
|
||||
() => null,
|
||||
|
@ -99,20 +103,20 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
return await Notes.packMany([]);
|
||||
}
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
let filtered = await filterVisibility(notes, user, followingUserIds);
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterVisibility(notes, user, followingUserIds);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
if (user) {
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
}
|
||||
return filtered;
|
||||
};
|
||||
|
@ -123,7 +127,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
[root.id],
|
||||
{ prepare: true },
|
||||
);
|
||||
const foundNotes = await filter(
|
||||
const foundNotes = filter(
|
||||
renoteResult.rows.map(parseScyllaNote).filter((note) => !!note.text),
|
||||
);
|
||||
|
||||
|
@ -140,7 +144,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
[note.id],
|
||||
{ prepare: true },
|
||||
);
|
||||
const replies = await filter(replyResult.rows.map(parseScyllaNote));
|
||||
const replies = filter(replyResult.rows.map(parseScyllaNote));
|
||||
if (replies.length > 0) {
|
||||
foundNotes.push(...replies);
|
||||
queue.push(...replies);
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from "@/db/scylla.js";
|
||||
import {
|
||||
InstanceMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -63,6 +64,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
let [mutedUserIds, mutedInstances, blockerIds, blockingIds]: string[][] =
|
||||
[];
|
||||
let mutedWords: string[][] = [];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const foundNotes: ScyllaNote[] = [];
|
||||
let searchedDays = 0;
|
||||
|
@ -101,18 +105,19 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
break;
|
||||
}
|
||||
|
||||
notes = filterBlockUser(notes, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
|
||||
if (user) {
|
||||
notes = await filterMutedUser(
|
||||
notes = filterMutedUser(
|
||||
notes,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
notes = await filterMutedNote(notes, user, mutedWords);
|
||||
notes = await filterBlockUser(notes, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
notes = filterMutedNote(notes, user, mutedWords);
|
||||
}
|
||||
|
||||
foundNotes.push(...notes);
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
import {
|
||||
InstanceMutingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -103,6 +104,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
renoteMutedIds,
|
||||
]: string[][] = [];
|
||||
let mutedWords: string[][];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
const suspendedUsers = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
if (user) {
|
||||
[
|
||||
mutedUserIds,
|
||||
|
@ -128,24 +132,24 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
]);
|
||||
}
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = notes.filter(
|
||||
(n) => n.visibility === "public" && !n.channelId,
|
||||
);
|
||||
filtered = await filterReply(filtered, ps.withReplies, user);
|
||||
filtered = filterReply(filtered, ps.withReplies, user);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUsers,
|
||||
]);
|
||||
if (user) {
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
filtered = await filterMutedRenotes(filtered, user, renoteMutedIds);
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = filterMutedRenotes(filtered, renoteMutedIds);
|
||||
}
|
||||
if (ps.withFiles) {
|
||||
filtered = filtered.filter((n) => n.files.length > 0);
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -111,6 +112,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
blockerIds,
|
||||
blockingIds,
|
||||
renoteMutedIds,
|
||||
suspendedUserIds,
|
||||
] = await Promise.all([
|
||||
ChannelFollowingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
LocalFollowingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
|
@ -127,6 +129,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockedCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
RenoteMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
SuspendedUsersCache.init().then((cache) => cache.getAll()),
|
||||
]);
|
||||
const homeUserIds = [user.id, ...followingUserIds];
|
||||
const optFilter = (n: ScyllaNote) =>
|
||||
|
@ -137,22 +140,22 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
const localFilter = (notes: ScyllaNote[]) =>
|
||||
notes.filter((n) => !homeUserIds.includes(n.userId));
|
||||
|
||||
const commonFilter = async (notes: ScyllaNote[]) => {
|
||||
let filtered = await filterChannel(notes, user, followingChannelIds);
|
||||
filtered = await filterReply(filtered, ps.withReplies, user);
|
||||
filtered = await filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = await filterMutedUser(
|
||||
const commonFilter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterChannel(notes, user, followingChannelIds);
|
||||
filtered = filterReply(filtered, ps.withReplies, user);
|
||||
filtered = filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
filtered = await filterMutedRenotes(filtered, user, renoteMutedIds);
|
||||
filtered = filterMutedRenotes(filtered, renoteMutedIds);
|
||||
if (!ps.includeMyRenotes) {
|
||||
filtered = filtered.filter((n) => n.userId !== user.id || optFilter(n));
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -120,6 +121,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
renoteMutedIds,
|
||||
]: string[][] = [];
|
||||
let mutedWords: string[][];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
if (user) {
|
||||
[
|
||||
followingChannelIds,
|
||||
|
@ -148,24 +151,25 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
RenoteMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
let filtered = await filterChannel(notes, user, followingChannelIds);
|
||||
filtered = await filterReply(filtered, ps.withReplies, user);
|
||||
filtered = await filterVisibility(filtered, user, followingUserIds);
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterChannel(notes, user, followingChannelIds);
|
||||
filtered = filterReply(filtered, ps.withReplies, user);
|
||||
filtered = filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
if (user) {
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
filtered = await filterMutedRenotes(filtered, user, renoteMutedIds);
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = filterMutedRenotes(filtered, renoteMutedIds);
|
||||
}
|
||||
if (ps.withFiles) {
|
||||
filtered = filtered.filter((n) => n.files.length > 0);
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -116,6 +117,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
renoteMutedIds,
|
||||
]: string[][] = [];
|
||||
let mutedWords: string[][];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
if (user) {
|
||||
[
|
||||
followingUserIds,
|
||||
|
@ -142,8 +145,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
RenoteMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = notes.filter(
|
||||
(n) =>
|
||||
n.visibility === "public" &&
|
||||
|
@ -151,21 +155,21 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
m.recommendedInstances.includes(n.userHost) &&
|
||||
!n.channelId,
|
||||
);
|
||||
filtered = await filterReply(filtered, ps.withReplies, user);
|
||||
filtered = await filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterReply(filtered, ps.withReplies, user);
|
||||
filtered = filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
if (user) {
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
filtered = await filterMutedRenotes(filtered, user, renoteMutedIds);
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = filterMutedRenotes(filtered, renoteMutedIds);
|
||||
}
|
||||
if (ps.withFiles) {
|
||||
filtered = filtered.filter((n) => n.files.length > 0);
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
import {
|
||||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -78,6 +79,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
if (scyllaClient) {
|
||||
let [mutedUserIds, mutedInstances, blockerIds, blockingIds]: string[][] =
|
||||
[];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
if (user) {
|
||||
[mutedUserIds, mutedInstances, blockerIds, blockingIds] =
|
||||
await Promise.all([
|
||||
|
@ -87,24 +90,25 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = notes;
|
||||
if (ps.userId) {
|
||||
filtered = filtered.filter((n) => n.userId === ps.userId);
|
||||
}
|
||||
filtered = await filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
if (user) {
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
}
|
||||
return filtered;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -102,6 +103,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
blockerIds,
|
||||
blockingIds,
|
||||
renoteMutedIds,
|
||||
suspendedUserIds,
|
||||
] = await Promise.all([
|
||||
ChannelFollowingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
followingsCache.getAll(),
|
||||
|
@ -118,28 +120,29 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
UserBlockedCache.init(user.id).then((cache) => cache.getAll()),
|
||||
UserBlockingCache.init(user.id).then((cache) => cache.getAll()),
|
||||
RenoteMutingsCache.init(user.id).then((cache) => cache.getAll()),
|
||||
SuspendedUsersCache.init().then((cache) => cache.getAll()),
|
||||
]);
|
||||
const validUserIds = [user.id, ...followingUserIds];
|
||||
const optFilter = (n: ScyllaNote) =>
|
||||
!n.renoteId || !!n.text || n.files.length > 0 || n.hasPoll;
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = notes.filter((n) => validUserIds.includes(n.userId));
|
||||
filtered = await filterChannel(filtered, user, followingChannelIds);
|
||||
filtered = await filterReply(filtered, ps.withReplies, user);
|
||||
filtered = await filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterChannel(filtered, user, followingChannelIds);
|
||||
filtered = filterReply(filtered, ps.withReplies, user);
|
||||
filtered = filterVisibility(filtered, user, followingUserIds);
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
user,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, user, [
|
||||
filtered = filterMutedNote(filtered, user, mutedWords);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
filtered = await filterMutedRenotes(filtered, user, renoteMutedIds);
|
||||
filtered = filterMutedRenotes(filtered, renoteMutedIds);
|
||||
if (!ps.includeMyRenotes) {
|
||||
filtered = filtered.filter((n) => n.userId !== user.id || optFilter(n));
|
||||
}
|
||||
|
|
|
@ -91,8 +91,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
);
|
||||
const optFilter = (n: ScyllaNote) =>
|
||||
!n.renoteId || !!n.text || n.files.length > 0 || n.hasPoll;
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
let filtered = await filterVisibility(notes, user, followingUserIds);
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = filterVisibility(notes, user, followingUserIds);
|
||||
if (!ps.includeMyRenotes) {
|
||||
filtered = filtered.filter((n) => n.userId !== user.id || optFilter(n));
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
InstanceMutingsCache,
|
||||
LocalFollowingsCache,
|
||||
RenoteMutingsCache,
|
||||
SuspendedUsersCache,
|
||||
UserBlockedCache,
|
||||
UserBlockingCache,
|
||||
UserMutingsCache,
|
||||
|
@ -94,6 +95,8 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
blockingIds,
|
||||
]: string[][] = [];
|
||||
let mutedWords: string[][];
|
||||
blockerIds = [];
|
||||
blockingIds = [];
|
||||
if (me) {
|
||||
[
|
||||
followingUserIds,
|
||||
|
@ -118,6 +121,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
UserBlockingCache.init(me.id).then((cache) => cache.getAll()),
|
||||
]);
|
||||
}
|
||||
const suspendedUserIds = await SuspendedUsersCache.init().then((cache) => cache.getAll());
|
||||
|
||||
if (
|
||||
me &&
|
||||
|
@ -128,21 +132,21 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
return Notes.packMany([]);
|
||||
}
|
||||
|
||||
const filter = async (notes: ScyllaNote[]) => {
|
||||
const filter = (notes: ScyllaNote[]) => {
|
||||
let filtered = notes.filter((n) => n.userId === ps.userId);
|
||||
filtered = await filterVisibility(filtered, me, followingUserIds);
|
||||
filtered = filterVisibility(filtered, me, followingUserIds);
|
||||
filtered = filterBlockUser(filtered, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
...suspendedUserIds,
|
||||
]);
|
||||
if (me) {
|
||||
filtered = await filterMutedUser(
|
||||
filtered = filterMutedUser(
|
||||
filtered,
|
||||
me,
|
||||
mutedUserIds,
|
||||
mutedInstances,
|
||||
);
|
||||
filtered = await filterMutedNote(filtered, me, mutedWords);
|
||||
filtered = await filterBlockUser(filtered, me, [
|
||||
...blockerIds,
|
||||
...blockingIds,
|
||||
]);
|
||||
filtered = filterMutedNote(filtered, me, mutedWords);
|
||||
}
|
||||
if (ps.withFiles) {
|
||||
filtered = filtered.filter((n) => n.files.length > 0);
|
||||
|
|
|
@ -79,11 +79,11 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
const notes = await client
|
||||
.execute(prepared.note.select.byIds, [noteIds], { prepare: true })
|
||||
.then((result) => result.rows.map(parseScyllaNote));
|
||||
const filteredNoteIds = await filterVisibility(
|
||||
const filteredNoteIds = filterVisibility(
|
||||
notes,
|
||||
me,
|
||||
followingUserIds,
|
||||
).then((notes) => notes.map(({ id }) => id));
|
||||
).map(({ id }) => id);
|
||||
noteIds = noteIds.filter((id) => filteredNoteIds.includes(id));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue