summaryrefslogtreecommitdiff
path: root/packages/backend
diff options
context:
space:
mode:
authorzawa-ch <lunatic.zawa.ch@gmail.com>2023-12-18 20:59:20 +0900
committerGitHub <noreply@github.com>2023-12-18 20:59:20 +0900
commit4e2d8029678951ca3b8b9b40e62901b0c67618ed (patch)
tree3a2cc7ef92f461493945023969601bf7c9e63044 /packages/backend
parentFix: Renoteの判定が間違っているのを修正 (#12706) (diff)
downloadsharkey-4e2d8029678951ca3b8b9b40e62901b0c67618ed.tar.gz
sharkey-4e2d8029678951ca3b8b9b40e62901b0c67618ed.tar.bz2
sharkey-4e2d8029678951ca3b8b9b40e62901b0c67618ed.zip
enhance: “つながりの公開範囲”がフォロー・フォロワー個別設定できるように (#12702)
* Enhance: “つながりの公開範囲”がフォロー・フォロワー個別設定できるように (#12072) * refactor: crowdin 編集部分のコミットを打ち消し https://github.com/misskey-dev/misskey/pull/12702#issuecomment-1859417158 * refactor: オブジェクトの名前修正 https://github.com/misskey-dev/misskey/pull/12702#issuecomment-1859417158 * fix: 設定項目の説明を削除 名称が具体的になって必要なくなったため https://github.com/misskey-dev/misskey/pull/12702#discussion_r1429932463
Diffstat (limited to 'packages/backend')
-rw-r--r--packages/backend/migration/1702718871541-ffVisibility.js35
-rw-r--r--packages/backend/src/core/entities/UserEntityService.ts11
-rw-r--r--packages/backend/src/models/UserProfile.ts12
-rw-r--r--packages/backend/src/models/json-schema/user.ts7
-rw-r--r--packages/backend/src/server/ActivityPubServerService.ts8
-rw-r--r--packages/backend/src/server/api/endpoints/i/update.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/users/followers.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/users/following.ts4
-rw-r--r--packages/backend/src/server/web/FeedService.ts2
-rw-r--r--packages/backend/src/types.ts3
-rw-r--r--packages/backend/test/e2e/ff-visibility.ts543
-rw-r--r--packages/backend/test/e2e/users.ts15
12 files changed, 603 insertions, 47 deletions
diff --git a/packages/backend/migration/1702718871541-ffVisibility.js b/packages/backend/migration/1702718871541-ffVisibility.js
new file mode 100644
index 0000000000..24b1873134
--- /dev/null
+++ b/packages/backend/migration/1702718871541-ffVisibility.js
@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class ffVisibility1702718871541 {
+ constructor() {
+ this.name = 'ffVisibility1702718871541';
+ }
+ async up(queryRunner) {
+ await queryRunner.query(`CREATE TYPE "public"."user_profile_followingvisibility_enum" AS ENUM('public', 'followers', 'private')`);
+ await queryRunner.query(`CREATE CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followingvisibility_enum") WITH INOUT AS ASSIGNMENT`);
+ await queryRunner.query(`CREATE TYPE "public"."user_profile_followersVisibility_enum" AS ENUM('public', 'followers', 'private')`);
+ await queryRunner.query(`CREATE CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followersVisibility_enum") WITH INOUT AS ASSIGNMENT`);
+ await queryRunner.query(`ALTER TABLE "user_profile" ADD "followingVisibility" "public"."user_profile_followingvisibility_enum" NOT NULL DEFAULT 'public'`);
+ await queryRunner.query(`ALTER TABLE "user_profile" ADD "followersVisibility" "public"."user_profile_followersVisibility_enum" NOT NULL DEFAULT 'public'`);
+ await queryRunner.query(`UPDATE "user_profile" SET "followingVisibility" = "ffVisibility"`);
+ await queryRunner.query(`UPDATE "user_profile" SET "followersVisibility" = "ffVisibility"`);
+ await queryRunner.query(`DROP CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followersVisibility_enum")`);
+ await queryRunner.query(`DROP CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followingvisibility_enum")`);
+ await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "ffVisibility"`);
+ await queryRunner.query(`DROP TYPE "public"."user_profile_ffvisibility_enum"`);
+ }
+ async down(queryRunner) {
+ await queryRunner.query(`CREATE TYPE "public"."user_profile_ffvisibility_enum" AS ENUM('public', 'followers', 'private')`);
+ await queryRunner.query(`ALTER TABLE "user_profile" ADD "ffVisibility" "public"."user_profile_ffvisibility_enum" NOT NULL DEFAULT 'public'`);
+ await queryRunner.query(`CREATE CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum") WITH INOUT AS ASSIGNMENT`);
+ await queryRunner.query(`UPDATE "user_profile" SET ffVisibility = "user_profile"."followingVisibility"`);
+ await queryRunner.query(`DROP CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum")`);
+ await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followersVisibility"`);
+ await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followingVisibility"`);
+ await queryRunner.query(`DROP TYPE "public"."user_profile_followersVisibility_enum"`);
+ await queryRunner.query(`DROP TYPE "public"."user_profile_followingvisibility_enum"`);
+ }
+}
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index fb7aa0c244..ef815a388a 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -332,13 +332,13 @@ export class UserEntityService implements OnModuleInit {
const profile = opts.detail ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null;
const followingCount = profile == null ? null :
- (profile.ffVisibility === 'public') || isMe ? user.followingCount :
- (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount :
+ (profile.followingVisibility === 'public') || isMe ? user.followingCount :
+ (profile.followingVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount :
null;
const followersCount = profile == null ? null :
- (profile.ffVisibility === 'public') || isMe ? user.followersCount :
- (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
+ (profile.followersVisibility === 'public') || isMe ? user.followersCount :
+ (profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
null;
const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null;
@@ -417,7 +417,8 @@ export class UserEntityService implements OnModuleInit {
pinnedPageId: profile!.pinnedPageId,
pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null,
publicReactions: profile!.publicReactions,
- ffVisibility: profile!.ffVisibility,
+ followersVisibility: profile!.followersVisibility,
+ followingVisibility: profile!.followingVisibility,
twoFactorEnabled: profile!.twoFactorEnabled,
usePasswordLessLogin: profile!.usePasswordLessLogin,
securityKeys: profile!.twoFactorEnabled
diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts
index 6659a01412..328dbeaa1c 100644
--- a/packages/backend/src/models/UserProfile.ts
+++ b/packages/backend/src/models/UserProfile.ts
@@ -4,7 +4,7 @@
*/
import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
-import { obsoleteNotificationTypes, ffVisibility, notificationTypes } from '@/types.js';
+import { obsoleteNotificationTypes, followingVisibilities, followersVisibilities, notificationTypes } from '@/types.js';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiPage } from './Page.js';
@@ -94,10 +94,16 @@ export class MiUserProfile {
public publicReactions: boolean;
@Column('enum', {
- enum: ffVisibility,
+ enum: followingVisibilities,
default: 'public',
})
- public ffVisibility: typeof ffVisibility[number];
+ public followingVisibility: typeof followingVisibilities[number];
+
+ @Column('enum', {
+ enum: followersVisibilities,
+ default: 'public',
+ })
+ public followersVisibility: typeof followersVisibilities[number];
@Column('varchar', {
length: 128, nullable: true,
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index 7a3ca58269..1b86b1bf10 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -311,7 +311,12 @@ export const packedUserDetailedNotMeOnlySchema = {
type: 'boolean',
nullable: false, optional: false,
},
- ffVisibility: {
+ followingVisibility: {
+ type: 'string',
+ nullable: false, optional: false,
+ enum: ['public', 'followers', 'private'],
+ },
+ followersVisibility: {
type: 'string',
nullable: false, optional: false,
enum: ['public', 'followers', 'private'],
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index 2bc7e1136a..68e426b5bc 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -195,11 +195,11 @@ export class ActivityPubServerService {
//#region Check ff visibility
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.ffVisibility === 'private') {
+ if (profile.followersVisibility === 'private') {
reply.code(403);
reply.header('Cache-Control', 'public, max-age=30');
return;
- } else if (profile.ffVisibility === 'followers') {
+ } else if (profile.followersVisibility === 'followers') {
reply.code(403);
reply.header('Cache-Control', 'public, max-age=30');
return;
@@ -287,11 +287,11 @@ export class ActivityPubServerService {
//#region Check ff visibility
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.ffVisibility === 'private') {
+ if (profile.followingVisibility === 'private') {
reply.code(403);
reply.header('Cache-Control', 'public, max-age=30');
return;
- } else if (profile.ffVisibility === 'followers') {
+ } else if (profile.followingVisibility === 'followers') {
reply.code(403);
reply.header('Cache-Control', 'public, max-age=30');
return;
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index a56f50115b..eed3082258 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -176,7 +176,8 @@ export const paramDef = {
receiveAnnouncementEmail: { type: 'boolean' },
alwaysMarkNsfw: { type: 'boolean' },
autoSensitive: { type: 'boolean' },
- ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] },
+ followingVisibility: { type: 'string', enum: ['public', 'followers', 'private'] },
+ followersVisibility: { type: 'string', enum: ['public', 'followers', 'private'] },
pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true },
mutedWords: muteWords,
hardMutedWords: muteWords,
@@ -241,7 +242,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
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.followingVisibility !== undefined) profileUpdates.followingVisibility = ps.followingVisibility;
+ if (ps.followersVisibility !== undefined) profileUpdates.followersVisibility = ps.followersVisibility;
function checkMuteWordCount(mutedWords: (string[] | string)[], limit: number) {
// TODO: ちゃんと数える
diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts
index b22fd2ff7a..5706e46b96 100644
--- a/packages/backend/src/server/api/endpoints/users/followers.ts
+++ b/packages/backend/src/server/api/endpoints/users/followers.ts
@@ -93,11 +93,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.ffVisibility === 'private') {
+ if (profile.followersVisibility === 'private') {
if (me == null || (me.id !== user.id)) {
throw new ApiError(meta.errors.forbidden);
}
- } else if (profile.ffVisibility === 'followers') {
+ } else if (profile.followersVisibility === 'followers') {
if (me == null) {
throw new ApiError(meta.errors.forbidden);
} else if (me.id !== user.id) {
diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts
index ead7ba8c40..794fb04f10 100644
--- a/packages/backend/src/server/api/endpoints/users/following.ts
+++ b/packages/backend/src/server/api/endpoints/users/following.ts
@@ -101,11 +101,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.ffVisibility === 'private') {
+ if (profile.followingVisibility === 'private') {
if (me == null || (me.id !== user.id)) {
throw new ApiError(meta.errors.forbidden);
}
- } else if (profile.ffVisibility === 'followers') {
+ } else if (profile.followingVisibility === 'followers') {
if (me == null) {
throw new ApiError(meta.errors.forbidden);
} else if (me.id !== user.id) {
diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts
index dd4304e6ef..dfda85aac9 100644
--- a/packages/backend/src/server/web/FeedService.ts
+++ b/packages/backend/src/server/web/FeedService.ts
@@ -60,7 +60,7 @@ export class FeedService {
title: `${author.name} (@${user.username}@${this.config.host})`,
updated: notes.length !== 0 ? this.idService.parse(notes[0].id).date : undefined,
generator: 'Misskey',
- description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`,
+ description: `${user.notesCount} Notes, ${profile.followingVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.followersVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`,
link: author.link,
image: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
feedLinks: {
diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts
index 1fb3d6a6ce..e085407de0 100644
--- a/packages/backend/src/types.ts
+++ b/packages/backend/src/types.ts
@@ -25,7 +25,8 @@ export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as
export const mutedNoteReasons = ['word', 'manual', 'spam', 'other'] as const;
-export const ffVisibility = ['public', 'followers', 'private'] as const;
+export const followingVisibilities = ['public', 'followers', 'private'] as const;
+export const followersVisibilities = ['public', 'followers', 'private'] as const;
export const moderationLogTypes = [
'updateServerSettings',
diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts
index 7841e057bf..1fbd45c741 100644
--- a/packages/backend/test/e2e/ff-visibility.ts
+++ b/packages/backend/test/e2e/ff-visibility.ts
@@ -26,9 +26,10 @@ describe('FF visibility', () => {
await app.close();
});
- test('ffVisibility が public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
+ test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
await api('/i/update', {
- ffVisibility: 'public',
+ followingVisibility: 'public',
+ followersVisibility: 'public',
}, alice);
const followingRes = await api('/users/following', {
@@ -44,9 +45,88 @@ describe('FF visibility', () => {
assert.strictEqual(Array.isArray(followersRes.body), true);
});
- test('ffVisibility が followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
+ test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ });
+
+ test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ });
+
+ test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
await api('/i/update', {
- ffVisibility: 'followers',
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
}, alice);
const followingRes = await api('/users/following', {
@@ -62,9 +142,88 @@ describe('FF visibility', () => {
assert.strictEqual(Array.isArray(followersRes.body), true);
});
- test('ffVisibility が followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
+ test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ });
+
+ test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ });
+
+ test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
await api('/i/update', {
- ffVisibility: 'followers',
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
}, alice);
const followingRes = await api('/users/following', {
@@ -78,9 +237,82 @@ describe('FF visibility', () => {
assert.strictEqual(followersRes.status, 400);
});
- test('ffVisibility が followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
+ test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 400);
+ }
+ });
+
+ test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 400);
+ }
+ });
+
+ test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
await api('/i/update', {
- ffVisibility: 'followers',
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
}, alice);
await api('/following/create', {
@@ -100,9 +332,106 @@ describe('FF visibility', () => {
assert.strictEqual(Array.isArray(followersRes.body), true);
});
- test('ffVisibility が private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
+ test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'public',
+ }, alice);
+ await api('/following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
+ }, alice);
+ await api('/following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'private',
+ }, alice);
+ await api('/following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ });
+
+ test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'followers',
+ }, alice);
+ await api('/following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'followers',
+ }, alice);
+ await api('/following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'followers',
+ }, alice);
+ await api('/following/create', {
+ userId: alice.id,
+ }, bob);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ });
+
+ test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
await api('/i/update', {
- ffVisibility: 'private',
+ followingVisibility: 'private',
+ followersVisibility: 'private',
}, alice);
const followingRes = await api('/users/following', {
@@ -118,9 +447,88 @@ describe('FF visibility', () => {
assert.strictEqual(Array.isArray(followersRes.body), true);
});
- test('ffVisibility が private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
+ test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followingRes.status, 200);
+ assert.strictEqual(Array.isArray(followingRes.body), true);
+ }
+ });
+
+ test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, alice);
+ assert.strictEqual(followersRes.status, 200);
+ assert.strictEqual(Array.isArray(followersRes.body), true);
+ }
+ });
+
+ test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
await api('/i/update', {
- ffVisibility: 'private',
+ followingVisibility: 'private',
+ followersVisibility: 'private',
}, alice);
const followingRes = await api('/users/following', {
@@ -134,36 +542,129 @@ describe('FF visibility', () => {
assert.strictEqual(followersRes.status, 400);
});
+ test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'public',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followingRes = await api('/users/following', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followingRes.status, 400);
+ }
+ });
+
+ test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => {
+ {
+ await api('/i/update', {
+ followingVisibility: 'public',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'followers',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 400);
+ }
+ {
+ await api('/i/update', {
+ followingVisibility: 'private',
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await api('/users/followers', {
+ userId: alice.id,
+ }, bob);
+ assert.strictEqual(followersRes.status, 400);
+ }
+ });
+
describe('AP', () => {
- test('ffVisibility が public 以外ならばAPからは取得できない', async () => {
+ test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => {
{
await api('/i/update', {
- ffVisibility: 'public',
+ followingVisibility: 'public',
}, alice);
const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json');
- const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
assert.strictEqual(followingRes.status, 200);
- assert.strictEqual(followersRes.status, 200);
}
{
await api('/i/update', {
- ffVisibility: 'followers',
+ followingVisibility: 'followers',
}, alice);
const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json');
- const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
assert.strictEqual(followingRes.status, 403);
- assert.strictEqual(followersRes.status, 403);
}
{
await api('/i/update', {
- ffVisibility: 'private',
+ followingVisibility: 'private',
}, alice);
const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json');
- const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
assert.strictEqual(followingRes.status, 403);
+ }
+ });
+
+ test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => {
+ {
+ await api('/i/update', {
+ followersVisibility: 'public',
+ }, alice);
+
+ const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
+ assert.strictEqual(followersRes.status, 200);
+ }
+ {
+ await api('/i/update', {
+ followersVisibility: 'followers',
+ }, alice);
+
+ const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
+ assert.strictEqual(followersRes.status, 403);
+ }
+ {
+ await api('/i/update', {
+ followersVisibility: 'private',
+ }, alice);
+
+ const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
assert.strictEqual(followersRes.status, 403);
}
});
diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts
index 2ce8fbc129..9c4cbac368 100644
--- a/packages/backend/test/e2e/users.ts
+++ b/packages/backend/test/e2e/users.ts
@@ -112,7 +112,8 @@ describe('ユーザー', () => {
pinnedPageId: user.pinnedPageId,
pinnedPage: user.pinnedPage,
publicReactions: user.publicReactions,
- ffVisibility: user.ffVisibility,
+ followingVisibility: user.followingVisibility,
+ followersVisibility: user.followersVisibility,
twoFactorEnabled: user.twoFactorEnabled,
usePasswordLessLogin: user.usePasswordLessLogin,
securityKeys: user.securityKeys,
@@ -386,7 +387,8 @@ describe('ユーザー', () => {
assert.strictEqual(response.pinnedPageId, null);
assert.strictEqual(response.pinnedPage, null);
assert.strictEqual(response.publicReactions, true);
- assert.strictEqual(response.ffVisibility, 'public');
+ assert.strictEqual(response.followingVisibility, 'public');
+ assert.strictEqual(response.followersVisibility, 'public');
assert.strictEqual(response.twoFactorEnabled, false);
assert.strictEqual(response.usePasswordLessLogin, false);
assert.strictEqual(response.securityKeys, false);
@@ -495,9 +497,12 @@ describe('ユーザー', () => {
{ parameters: (): object => ({ alwaysMarkNsfw: false }) },
{ parameters: (): object => ({ autoSensitive: true }) },
{ parameters: (): object => ({ autoSensitive: false }) },
- { parameters: (): object => ({ ffVisibility: 'private' }) },
- { parameters: (): object => ({ ffVisibility: 'followers' }) },
- { parameters: (): object => ({ ffVisibility: 'public' }) },
+ { parameters: (): object => ({ followingVisibility: 'private' }) },
+ { parameters: (): object => ({ followingVisibility: 'followers' }) },
+ { parameters: (): object => ({ followingVisibility: 'public' }) },
+ { parameters: (): object => ({ followersVisibility: 'private' }) },
+ { parameters: (): object => ({ followersVisibility: 'followers' }) },
+ { parameters: (): object => ({ followersVisibility: 'public' }) },
{ parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
{ parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) },
{ parameters: (): object => ({ mutedWords: [] }) },