refactor: cache suspended users

This commit is contained in:
Namekuji 2023-09-20 01:57:02 -04:00
parent 19d7dc8b84
commit 8e0b0c7cb9
No known key found for this signature in database
GPG key ID: 1D62332C07FBA532
21 changed files with 234 additions and 225 deletions

View file

@ -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),
);
}

View file

@ -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;
}
}

View file

@ -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];
}

View file

@ -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,
});

View file

@ -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,
});

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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) {

View file

@ -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(

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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));
}

View file

@ -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);

View file

@ -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);

View file

@ -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;
};

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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);

View file

@ -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));
}