forked from naskya/firefish
fix: refactor antennas and fix bugs
This commit is contained in:
parent
958c6678f9
commit
1694b82154
9 changed files with 41 additions and 106 deletions
|
@ -1,29 +1,20 @@
|
||||||
import type { Antenna } from "@/models/entities/antenna.js";
|
import type { Antenna } from "@/models/entities/antenna.js";
|
||||||
import type { Note } from "@/models/entities/note.js";
|
import type { Note } from "@/models/entities/note.js";
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import {
|
import { Blockings, UserProfiles } from "@/models/index.js";
|
||||||
UserListJoinings,
|
|
||||||
UserGroupJoinings,
|
|
||||||
Blockings,
|
|
||||||
} from "@/models/index.js";
|
|
||||||
import { getFullApAccount } from "./convert-host.js";
|
import { getFullApAccount } from "./convert-host.js";
|
||||||
import * as Acct from "@/misc/acct.js";
|
import * as Acct from "@/misc/acct.js";
|
||||||
import type { Packed } from "./schema.js";
|
import type { Packed } from "./schema.js";
|
||||||
import { Cache } from "./cache.js";
|
import { Cache } from "./cache.js";
|
||||||
|
import { getWordHardMute } from "./check-word-mute.js";
|
||||||
|
|
||||||
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
||||||
|
|
||||||
// NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
|
|
||||||
|
|
||||||
/**
|
|
||||||
* noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい
|
|
||||||
*/
|
|
||||||
export async function checkHitAntenna(
|
export async function checkHitAntenna(
|
||||||
antenna: Antenna,
|
antenna: Antenna,
|
||||||
note: Note | Packed<"Note">,
|
note: Note | Packed<"Note">,
|
||||||
noteUser: { id: User["id"]; username: string; host: string | null },
|
noteUser: { id: User["id"]; username: string; host: string | null },
|
||||||
noteUserFollowers?: User["id"][],
|
antennaUserFollowing: User["id"][],
|
||||||
antennaUserFollowing?: User["id"][],
|
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (note.visibility === "specified") return false;
|
if (note.visibility === "specified") return false;
|
||||||
|
|
||||||
|
@ -35,41 +26,25 @@ export async function checkHitAntenna(
|
||||||
);
|
);
|
||||||
if (blockings.some((blocking) => blocking === antenna.userId)) return false;
|
if (blockings.some((blocking) => blocking === antenna.userId)) return false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
await getWordHardMute(
|
||||||
|
note,
|
||||||
|
antenna.userId,
|
||||||
|
(
|
||||||
|
await UserProfiles.findOneBy({ userId: antenna.userId })
|
||||||
|
)?.mutedWords,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (note.visibility === "followers" || note.visibility === "home") {
|
if (note.visibility === "followers" || note.visibility === "home") {
|
||||||
if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId))
|
|
||||||
return false;
|
|
||||||
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
|
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!antenna.withReplies && note.replyId != null) return false;
|
if (!antenna.withReplies && note.replyId != null) return false;
|
||||||
|
|
||||||
if (antenna.src === "home") {
|
if (antenna.src === "users") {
|
||||||
if (noteUserFollowers && !noteUserFollowers.includes(antenna.userId))
|
|
||||||
return false;
|
|
||||||
if (antennaUserFollowing && !antennaUserFollowing.includes(note.userId))
|
|
||||||
return false;
|
|
||||||
} else if (antenna.src === "list") {
|
|
||||||
const listUsers = (
|
|
||||||
await UserListJoinings.findBy({
|
|
||||||
userListId: antenna.userListId!,
|
|
||||||
})
|
|
||||||
).map((x) => x.userId);
|
|
||||||
|
|
||||||
if (!listUsers.includes(note.userId)) return false;
|
|
||||||
} else if (antenna.src === "group") {
|
|
||||||
const joining = await UserGroupJoinings.findOneByOrFail({
|
|
||||||
id: antenna.userGroupJoiningId!,
|
|
||||||
});
|
|
||||||
|
|
||||||
const groupUsers = (
|
|
||||||
await UserGroupJoinings.findBy({
|
|
||||||
userGroupId: joining.userGroupId,
|
|
||||||
})
|
|
||||||
).map((x) => x.userId);
|
|
||||||
|
|
||||||
if (!groupUsers.includes(note.userId)) return false;
|
|
||||||
} else if (antenna.src === "users") {
|
|
||||||
const accts = antenna.users.map((x) => {
|
const accts = antenna.users.map((x) => {
|
||||||
const { username, host } = Acct.parse(x);
|
const { username, host } = Acct.parse(x);
|
||||||
return getFullApAccount(username, host).toLowerCase();
|
return getFullApAccount(username, host).toLowerCase();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import RE2 from "re2";
|
import RE2 from "re2";
|
||||||
import type { Note } from "@/models/entities/note.js";
|
import type { Note } from "@/models/entities/note.js";
|
||||||
import type { User } from "@/models/entities/user.js";
|
|
||||||
|
|
||||||
type NoteLike = {
|
type NoteLike = {
|
||||||
userId: Note["userId"];
|
userId: Note["userId"];
|
||||||
|
@ -9,10 +8,6 @@ type NoteLike = {
|
||||||
cw?: Note["cw"];
|
cw?: Note["cw"];
|
||||||
};
|
};
|
||||||
|
|
||||||
type UserLike = {
|
|
||||||
id: User["id"];
|
|
||||||
};
|
|
||||||
|
|
||||||
function checkWordMute(
|
function checkWordMute(
|
||||||
note: NoteLike,
|
note: NoteLike,
|
||||||
mutedWords: Array<string | string[]>,
|
mutedWords: Array<string | string[]>,
|
||||||
|
@ -61,11 +56,11 @@ function checkWordMute(
|
||||||
|
|
||||||
export async function getWordHardMute(
|
export async function getWordHardMute(
|
||||||
note: NoteLike,
|
note: NoteLike,
|
||||||
me: UserLike | null | undefined,
|
meId: string | null | undefined,
|
||||||
mutedWords: Array<string | string[]>,
|
mutedWords?: Array<string | string[]>,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
// 自分自身
|
// 自分自身
|
||||||
if (me && note.userId === me.id) {
|
if (note.userId === meId || mutedWords == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,9 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
|
this.user &&
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,9 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
|
this.user &&
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,9 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
|
this.user &&
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,9 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
|
this.user &&
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,9 @@ export default class extends Channel {
|
||||||
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
// レコードが追加されるNoteでも追加されるより先にここのストリーミングの処理に到達することが起こる。
|
||||||
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
// そのためレコードが存在するかのチェックでは不十分なので、改めてgetWordHardMuteを呼んでいる
|
||||||
if (
|
if (
|
||||||
|
this.user &&
|
||||||
this.userProfile &&
|
this.userProfile &&
|
||||||
(await getWordHardMute(note, this.user, this.userProfile.mutedWords))
|
(await getWordHardMute(note, this.user.id, this.userProfile.mutedWords))
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { extractHashtags } from "@/misc/extract-hashtags.js";
|
||||||
import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
|
import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
|
||||||
import { Note } from "@/models/entities/note.js";
|
import { Note } from "@/models/entities/note.js";
|
||||||
import {
|
import {
|
||||||
|
Followings,
|
||||||
Mutings,
|
Mutings,
|
||||||
Users,
|
Users,
|
||||||
NoteWatchings,
|
NoteWatchings,
|
||||||
|
@ -370,7 +371,7 @@ export default async (
|
||||||
)
|
)
|
||||||
.then((us) => {
|
.then((us) => {
|
||||||
for (const u of us) {
|
for (const u of us) {
|
||||||
getWordHardMute(data, { id: u.userId }, u.mutedWords).then(
|
getWordHardMute(data, u.userId, u.mutedWords).then(
|
||||||
(shouldMute) => {
|
(shouldMute) => {
|
||||||
if (shouldMute) {
|
if (shouldMute) {
|
||||||
MutedNotes.insert({
|
MutedNotes.insert({
|
||||||
|
@ -387,7 +388,17 @@ export default async (
|
||||||
|
|
||||||
// Antenna
|
// Antenna
|
||||||
for (const antenna of await getAntennas()) {
|
for (const antenna of await getAntennas()) {
|
||||||
checkHitAntenna(antenna, note, user).then((hit) => {
|
checkHitAntenna(
|
||||||
|
antenna,
|
||||||
|
note,
|
||||||
|
user,
|
||||||
|
(
|
||||||
|
await Followings.find({
|
||||||
|
where: { followerId: user.id },
|
||||||
|
select: ["followeeId"],
|
||||||
|
})
|
||||||
|
).map((x) => x.followeeId),
|
||||||
|
).then((hit) => {
|
||||||
if (hit) {
|
if (hit) {
|
||||||
addNoteToAntenna(antenna, note, user);
|
addNoteToAntenna(antenna, note, user);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@ import {
|
||||||
} from "@/models/index.js";
|
} from "@/models/index.js";
|
||||||
import { Not, IsNull, In } from "typeorm";
|
import { Not, IsNull, In } from "typeorm";
|
||||||
import type { Channel } from "@/models/entities/channel.js";
|
import type { Channel } from "@/models/entities/channel.js";
|
||||||
import { checkHitAntenna } from "@/misc/check-hit-antenna.js";
|
|
||||||
import { getAntennas } from "@/misc/antenna-cache.js";
|
|
||||||
import { readNotificationByQuery } from "@/server/api/common/read-notification.js";
|
import { readNotificationByQuery } from "@/server/api/common/read-notification.js";
|
||||||
import type { Packed } from "@/misc/schema.js";
|
import type { Packed } from "@/misc/schema.js";
|
||||||
|
|
||||||
|
@ -50,11 +48,9 @@ export default async function (
|
||||||
).map((x) => x.followeeId),
|
).map((x) => x.followeeId),
|
||||||
);
|
);
|
||||||
|
|
||||||
// const myAntennas = (await getAntennas()).filter((a) => a.userId === userId);
|
|
||||||
const readMentions: (Note | Packed<"Note">)[] = [];
|
const readMentions: (Note | Packed<"Note">)[] = [];
|
||||||
const readSpecifiedNotes: (Note | Packed<"Note">)[] = [];
|
const readSpecifiedNotes: (Note | Packed<"Note">)[] = [];
|
||||||
const readChannelNotes: (Note | Packed<"Note">)[] = [];
|
const readChannelNotes: (Note | Packed<"Note">)[] = [];
|
||||||
// const readAntennaNotes: (Note | Packed<"Note">)[] = [];
|
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
if (note.mentions?.includes(userId)) {
|
if (note.mentions?.includes(userId)) {
|
||||||
|
@ -66,23 +62,6 @@ export default async function (
|
||||||
if (note.channelId && followingChannels.has(note.channelId)) {
|
if (note.channelId && followingChannels.has(note.channelId)) {
|
||||||
readChannelNotes.push(note);
|
readChannelNotes.push(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (note.user != null) {
|
|
||||||
// // たぶんnullになることは無いはずだけど一応
|
|
||||||
// for (const antenna of myAntennas) {
|
|
||||||
// if (
|
|
||||||
// await checkHitAntenna(
|
|
||||||
// antenna,
|
|
||||||
// note,
|
|
||||||
// note.user,
|
|
||||||
// undefined,
|
|
||||||
// Array.from(following),
|
|
||||||
// )
|
|
||||||
// ) {
|
|
||||||
// readAntennaNotes.push(note);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -139,34 +118,4 @@ export default async function (
|
||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (readAntennaNotes.length > 0) {
|
|
||||||
// await AntennaNotes.update(
|
|
||||||
// {
|
|
||||||
// antennaId: In(myAntennas.map((a) => a.id)),
|
|
||||||
// noteId: In(readAntennaNotes.map((n) => n.id)),
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// read: true,
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // TODO: まとめてクエリしたい
|
|
||||||
// for (const antenna of myAntennas) {
|
|
||||||
// const count = await AntennaNotes.countBy({
|
|
||||||
// antennaId: antenna.id,
|
|
||||||
// read: false,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (count === 0) {
|
|
||||||
// publishMainStream(userId, "readAntenna", antenna);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Users.getHasUnreadAntenna(userId).then((unread) => {
|
|
||||||
// if (!unread) {
|
|
||||||
// publishMainStream(userId, "readAllAntennas");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue