diff --git a/locales/en-US.yml b/locales/en-US.yml index ad9876e22..adb540ae6 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -586,7 +586,8 @@ deleteAllFilesConfirm: "Are you sure that you want to delete all files?" removeAllFollowing: "Unfollow all followed users" removeAllFollowingDescription: "Executing this unfollows all accounts from {host}. Please run this if the instance e.g. no longer exists." userSuspended: "This user has been suspended." -userSilenced: "This user is being silenced." +userLimited: "This user has been limited." +userSilenced: "This user has been silenced." yourAccountSuspendedTitle: "This account is suspended" yourAccountSuspendedDescription: "This account has been suspended due to breaking the server's terms of services or similar. Contact the administrator if you would like to know a more detailed reason. Please do not create a new account." tokenRevoked: "Invalid token" diff --git a/locales/index.d.ts b/locales/index.d.ts index be8b5e802..b494c844d 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2388,6 +2388,10 @@ export interface Locale extends ILocale { * このユーザーは凍結されています。 */ "userSuspended": string; + /** + * このユーザーは制限されています。 + */ + "userLimited": string; /** * このユーザーはサイレンスされています。 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b4fd8616a..c62f0bfb9 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -593,6 +593,7 @@ deleteAllFilesConfirm: "すべてのファイルを削除しますか?" removeAllFollowing: "フォローを全解除" removeAllFollowingDescription: "{host}からのフォローをすべて解除します。そのサーバーがもう存在しなくなった場合などに実行してください。" userSuspended: "このユーザーは凍結されています。" +userLimited: "このユーザーは制限されています。" userSilenced: "このユーザーはサイレンスされています。" yourAccountSuspendedTitle: "アカウントが凍結されています" yourAccountSuspendedDescription: "このアカウントは、サーバーの利用規約に違反したなどの理由により、凍結されています。詳細については管理者までお問い合わせください。新しいアカウントを作らないでください。" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index c3802bf0a..0de32907f 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -592,6 +592,7 @@ deleteAllFilesConfirm: "모든 파일을 삭제하시겠습니까?" removeAllFollowing: "모든 팔로잉 해제" removeAllFollowingDescription: "{host} 서버의 모든 팔로잉을 해제합니다. 해당 서버가 더 이상 존재하지 않는 경우 등에 실행해 주세요." userSuspended: "이 계정은 정지된 상태입니다." +userLimited: "이 계정은 제한된 상태입니다." userSilenced: "이 계정은 사일런스된 상태입니다." yourAccountSuspendedTitle: "계정이 정지되었습니다" yourAccountSuspendedDescription: "이 계정은 서버의 이용 약관을 위반하거나, 기타 다른 이유로 인해 정지되었습니다. 자세한 사항은 관리자에게 문의해 주십시오. 계정을 새로 생성하지 마십시오." diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 3373b9e8b..75029333d 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -343,9 +343,9 @@ export class UserEntityService implements OnModuleInit { (profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : null; - const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null; - const isAdmin = isMe && opts.detail ? this.roleService.isAdministrator(user) : null; const policies = opts.detail ? await this.roleService.getUserPolicies(user.id) : null; + const isModerator = (isMe || iAmModerator) && opts.detail ? this.roleService.isModerator(user) : null; + const isAdmin = (isMe || iAmModerator) && opts.detail ? this.roleService.isAdministrator(user) : null; const unreadAnnouncements = isMe && opts.detail ? await this.announcementService.getUnreadAnnouncements(user) : null; const notificationsInfo = isMe && opts.detail ? await this.getNotificationsInfo(user.id) : null; @@ -426,16 +426,20 @@ export class UserEntityService implements OnModuleInit { userId: user.id, }).then(result => result >= 1) : false, - roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({ - id: role.id, - name: role.name, - color: role.color, - iconUrl: role.iconUrl, - description: role.description, - isModerator: role.isModerator, - isAdministrator: role.isAdministrator, - displayOrder: role.displayOrder, - }))), + roles: this.roleService.getUserRoles(user.id).then(roles => roles + .filter(role => role.isPublic || iAmModerator) + .sort((a, b) => b.displayOrder - a.displayOrder) + .map(role => ({ + id: role.id, + name: role.name, + color: role.color, + iconUrl: role.iconUrl, + description: role.description, + isModerator: role.isModerator, + isAdministrator: role.isAdministrator, + displayOrder: role.displayOrder, + })) + ), memo: meId == null ? null : await this.userMemosRepository.findOneBy({ userId: meId, targetUserId: user.id, @@ -443,7 +447,7 @@ export class UserEntityService implements OnModuleInit { moderationNote: iAmModerator ? (profile!.moderationNote ?? '') : undefined, } : {}), - ...(opts.detail && isMe ? { + ...(opts.detail && (isMe || iAmModerator) ? { avatarId: user.avatarId, bannerId: user.bannerId, isModerator: isModerator, @@ -468,7 +472,7 @@ export class UserEntityService implements OnModuleInit { where: { userId: user.id, isMentioned: true }, take: 1, }).then(count => count > 0), - hasUnreadAnnouncement: unreadAnnouncements!.length > 0, + hasUnreadAnnouncement: (unreadAnnouncements?.length ?? 0) > 0, unreadAnnouncements, hasUnreadAntenna: this.getHasUnreadAntenna(user.id), hasUnreadChannel: false, // 後方互換性のため diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index e8687b148..abc203f12 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -7,9 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - +
{{ i18n.ts.userSuspended }}
+
{{ i18n.ts.userLimited }}
+
{{ i18n.ts.userSilenced }}
@@ -312,6 +312,10 @@ onUnmounted(() => { > .punished { font-size: 0.8em; padding: 16px; + background: var(--infoWarnBg); + color: var(--infoWarnFg); + border-radius: var(--radius); + overflow: clip; } > .profile { diff --git a/packages/frontend/src/pages/user/raw.vue b/packages/frontend/src/pages/user/raw.vue index 0c0bfc29c..85aab5ddb 100644 --- a/packages/frontend/src/pages/user/raw.vue +++ b/packages/frontend/src/pages/user/raw.vue @@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only @{{ acct(user) }} Suspended + Limited Silenced Moderator @@ -53,6 +54,7 @@ const props = defineProps<{ const moderator = computed(() => props.user.isModerator ?? false); const silenced = computed(() => props.user.isSilenced ?? false); +const limited = computed(() => props.user.isLimited ?? false); const suspended = computed(() => props.user.isSuspended ?? false); @@ -103,6 +105,7 @@ const suspended = computed(() => props.user.isSuspended ?? false); } > .suspended, + > .limited, > .silenced, > .moderator { display: inline-block; @@ -117,6 +120,11 @@ const suspended = computed(() => props.user.isSuspended ?? false); border-color: var(--error); } + > .limited { + color: var(--error); + border-color: var(--error); + } + > .silenced { color: var(--warn); border-color: var(--warn);