chore: synchronize visibility checks (#8687)

* reuse single meId parameter

* unify code style

Use template string to avoid having to use escaped quote marks.

* fix: follower only notes are visible to mentioned users

This synchronizes the visibility rules with the Notes.isVisibleForMe
method from packages/backend/src/models/repositories/note.ts

* add comment
This commit is contained in:
Johann150 2022-06-11 09:14:44 +02:00 committed by GitHub
parent 2a4eddc80f
commit 7db09103e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 9 additions and 6 deletions

View File

@ -136,6 +136,7 @@ async function populateMyReaction(note: Note, meId: User['id'], _hint_?: {
export const NoteRepository = db.getRepository(Note).extend({ export const NoteRepository = db.getRepository(Note).extend({
async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> { async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> {
// This code must always be synchronized with the checks in generateVisibilityQuery.
// visibility が specified かつ自分が指定されていなかったら非表示 // visibility が specified かつ自分が指定されていなかったら非表示
if (note.visibility === 'specified') { if (note.visibility === 'specified') {
if (meId == null) { if (meId == null) {

View File

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