From a28c515ef63a6f9c188cf0a7f544db1afa8e1331 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 7 Nov 2021 18:04:32 +0900 Subject: feat: make possible to configure following/followers visibility (#7959) * feat: make possible to configure following/followers visibility * add test * ap * add ap test * set Cache-Control * hide following/followers count --- src/server/api/endpoints/i/update.ts | 5 +++++ src/server/api/endpoints/users/followers.ts | 30 +++++++++++++++++++++++++++-- src/server/api/endpoints/users/following.ts | 30 +++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 4 deletions(-) (limited to 'src/server/api') diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index 3b8b1579ea..d0f201ab60 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -72,6 +72,10 @@ export const meta = { validator: $.optional.bool, }, + ffVisibility: { + validator: $.optional.str, + }, + carefulBot: { validator: $.optional.bool, }, @@ -174,6 +178,7 @@ export default define(meta, async (ps, _user, token) => { if (ps.lang !== undefined) profileUpdates.lang = ps.lang; if (ps.location !== undefined) profileUpdates.location = ps.location; if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday; + if (ps.ffVisibility !== undefined) profileUpdates.ffVisibility = ps.ffVisibility; if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId; if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId; if (ps.mutedWords !== undefined) { diff --git a/src/server/api/endpoints/users/followers.ts b/src/server/api/endpoints/users/followers.ts index e54b6078ee..6d042a2861 100644 --- a/src/server/api/endpoints/users/followers.ts +++ b/src/server/api/endpoints/users/followers.ts @@ -2,7 +2,7 @@ import $ from 'cafy'; import { ID } from '@/misc/cafy-id'; import define from '../../define'; import { ApiError } from '../../error'; -import { Users, Followings } from '@/models/index'; +import { Users, Followings, UserProfiles } from '@/models/index'; import { makePaginationQuery } from '../../common/make-pagination-query'; import { toPunyNullable } from '@/misc/convert-host'; @@ -53,7 +53,13 @@ export const meta = { message: 'No such user.', code: 'NO_SUCH_USER', id: '27fa5435-88ab-43de-9360-387de88727cd' - } + }, + + forbidden: { + message: 'Forbidden.', + code: 'FORBIDDEN', + id: '3c6a84db-d619-26af-ca14-06232a21df8a' + }, } }; @@ -66,6 +72,26 @@ export default define(meta, async (ps, me) => { throw new ApiError(meta.errors.noSuchUser); } + const profile = await UserProfiles.findOneOrFail(user.id); + + if (profile.ffVisibility === 'private') { + if (me == null || (me.id !== user.id)) { + throw new ApiError(meta.errors.forbidden); + } + } else if (profile.ffVisibility === 'followers') { + if (me == null) { + throw new ApiError(meta.errors.forbidden); + } else if (me.id !== user.id) { + const following = await Followings.findOne({ + followeeId: user.id, + followerId: me.id, + }); + if (following == null) { + throw new ApiError(meta.errors.forbidden); + } + } + } + const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) .andWhere(`following.followeeId = :userId`, { userId: user.id }) .innerJoinAndSelect('following.follower', 'follower'); diff --git a/src/server/api/endpoints/users/following.ts b/src/server/api/endpoints/users/following.ts index f2ef7f47e1..1033117ef8 100644 --- a/src/server/api/endpoints/users/following.ts +++ b/src/server/api/endpoints/users/following.ts @@ -2,7 +2,7 @@ import $ from 'cafy'; import { ID } from '@/misc/cafy-id'; import define from '../../define'; import { ApiError } from '../../error'; -import { Users, Followings } from '@/models/index'; +import { Users, Followings, UserProfiles } from '@/models/index'; import { makePaginationQuery } from '../../common/make-pagination-query'; import { toPunyNullable } from '@/misc/convert-host'; @@ -53,7 +53,13 @@ export const meta = { message: 'No such user.', code: 'NO_SUCH_USER', id: '63e4aba4-4156-4e53-be25-c9559e42d71b' - } + }, + + forbidden: { + message: 'Forbidden.', + code: 'FORBIDDEN', + id: 'f6cdb0df-c19f-ec5c-7dbb-0ba84a1f92ba' + }, } }; @@ -66,6 +72,26 @@ export default define(meta, async (ps, me) => { throw new ApiError(meta.errors.noSuchUser); } + const profile = await UserProfiles.findOneOrFail(user.id); + + if (profile.ffVisibility === 'private') { + if (me == null || (me.id !== user.id)) { + throw new ApiError(meta.errors.forbidden); + } + } else if (profile.ffVisibility === 'followers') { + if (me == null) { + throw new ApiError(meta.errors.forbidden); + } else if (me.id !== user.id) { + const following = await Followings.findOne({ + followeeId: user.id, + followerId: me.id, + }); + if (following == null) { + throw new ApiError(meta.errors.forbidden); + } + } + } + const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) .andWhere(`following.followerId = :userId`, { userId: user.id }) .innerJoinAndSelect('following.followee', 'followee'); -- cgit v1.2.3-freya