import type { User } from "@/models/entities/user.js"; import { Followings } from "@/models/index.js"; import type { SelectQueryBuilder } from "typeorm"; import { Brackets } from "typeorm"; export function generateVisibilityQuery( q: SelectQueryBuilder, me?: { id: User["id"] } | null, ) { // This code must always be synchronized with the checks in Notes.isVisibleForMe. if (me == null) { q.andWhere( new Brackets((qb) => { qb.where(`note.visibility = 'public'`).orWhere( `note.visibility = 'home'`, ); }), ) .andWhere('note.localOnly = FALSE'); } else { const followingQuery = Followings.createQueryBuilder("following") .select("following.followeeId") .where("following.followerId = :meId"); q.andWhere( new Brackets((qb) => { qb // 公開投稿である .where( new Brackets((qb) => { qb.where(`note.visibility = 'public'`).orWhere( `note.visibility = 'home'`, ); }), ) // または 自分自身 .orWhere("note.userId = :meId") // または 自分宛て .orWhere(":meId = ANY(note.visibleUserIds)") .orWhere(":meId = ANY(note.mentions)") .orWhere( new Brackets((qb) => { qb // または フォロワー宛ての投稿であり、 .where(`note.visibility = 'followers'`) .andWhere( new Brackets((qb) => { qb // 自分がフォロワーである .where(`note.userId IN (${followingQuery.getQuery()})`) // または 自分の投稿へのリプライ .orWhere("note.replyUserId = :meId"); }), ); }), ); }), ); q.setParameters({ meId: me.id }); } }