summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/app/admin/views/users.user.vue5
-rw-r--r--src/client/app/admin/views/users.vue46
-rw-r--r--src/models/user.ts5
-rw-r--r--src/server/api/endpoints/admin/silence-user.ts49
-rw-r--r--src/server/api/endpoints/admin/unsilence-user.ts45
-rw-r--r--src/services/note/create.ts5
6 files changed, 152 insertions, 3 deletions
diff --git a/src/client/app/admin/views/users.user.vue b/src/client/app/admin/views/users.user.vue
index afece18e82..096e017e6a 100644
--- a/src/client/app/admin/views/users.user.vue
+++ b/src/client/app/admin/views/users.user.vue
@@ -12,6 +12,7 @@
<span class="is-admin" v-if="user.isAdmin">admin</span>
<span class="is-moderator" v-if="user.isModerator">moderator</span>
<span class="is-verified" v-if="user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
+ <span class="is-silenced" v-if="user.isSilenced" :title="$t('@.silenced-user')"><fa :icon="faMicrophoneSlash"/></span>
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
</header>
<div>
@@ -27,6 +28,7 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
+import { faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
@@ -34,7 +36,7 @@ export default Vue.extend({
props: ['user'],
data() {
return {
- faSnowflake
+ faSnowflake, faMicrophoneSlash
};
},
});
@@ -76,6 +78,7 @@ export default Vue.extend({
color var(--noteHeaderAdminFg)
> .is-verified
+ > .is-silenced
> .is-suspended
margin 0 0 0 .5em
color #4dabf7
diff --git a/src/client/app/admin/views/users.vue b/src/client/app/admin/views/users.vue
index 09d074eee2..f2306c26f2 100644
--- a/src/client/app/admin/views/users.vue
+++ b/src/client/app/admin/views/users.vue
@@ -17,6 +17,10 @@
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
</ui-horizon-group>
<ui-horizon-group>
+ <ui-button @click="silenceUser"><fa :icon="faMicrophoneSlash"/> {{ $t('make-silence') }}</ui-button>
+ <ui-button @click="unsilenceUser">{{ $t('unmake-silence') }}</ui-button>
+ </ui-horizon-group>
+ <ui-horizon-group>
<ui-button @click="suspendUser" :disabled="suspending"><fa :icon="faSnowflake"/> {{ $t('suspend') }}</ui-button>
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
</ui-horizon-group>
@@ -66,7 +70,7 @@
import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse";
-import { faCertificate, faUsers, faTerminal, faSearch, faKey, faSync } from '@fortawesome/free-solid-svg-icons';
+import { faCertificate, faUsers, faTerminal, faSearch, faKey, faSync, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
import XUser from './users.user.vue';
@@ -90,7 +94,7 @@ export default Vue.extend({
offset: 0,
users: [],
existMore: false,
- faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey, faSync
+ faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey, faSync, faMicrophoneSlash
};
},
@@ -216,6 +220,44 @@ export default Vue.extend({
this.refreshUser();
},
+ async silenceUser() {
+ const process = async () => {
+ await this.$root.api('admin/silence-user', { userId: this.user._id });
+ this.$root.dialog({
+ type: 'success',
+ splash: true
+ });
+ };
+
+ await process().catch(e => {
+ this.$root.dialog({
+ type: 'error',
+ text: e.toString()
+ });
+ });
+
+ this.refreshUser();
+ },
+
+ async unsilenceUser() {
+ const process = async () => {
+ await this.$root.api('admin/unsilence-user', { userId: this.user._id });
+ this.$root.dialog({
+ type: 'success',
+ splash: true
+ });
+ };
+
+ await process().catch(e => {
+ this.$root.dialog({
+ type: 'error',
+ text: e.toString()
+ });
+ });
+
+ this.refreshUser();
+ },
+
async suspendUser() {
if (!await this.getConfirmed(this.$t('suspend-confirm'))) return;
diff --git a/src/models/user.ts b/src/models/user.ts
index 6987bd3da8..df0e3c22a2 100644
--- a/src/models/user.ts
+++ b/src/models/user.ts
@@ -55,6 +55,11 @@ type IUserBase = {
isSuspended: boolean;
/**
+ * サイレンスされているか否か
+ */
+ isSilenced: boolean;
+
+ /**
* 鍵アカウントか否か
*/
isLocked: boolean;
diff --git a/src/server/api/endpoints/admin/silence-user.ts b/src/server/api/endpoints/admin/silence-user.ts
new file mode 100644
index 0000000000..7b1090a895
--- /dev/null
+++ b/src/server/api/endpoints/admin/silence-user.ts
@@ -0,0 +1,49 @@
+import $ from 'cafy';
+import ID, { transform } from '../../../../misc/cafy-id';
+import define from '../../define';
+import User from '../../../../models/user';
+
+export const meta = {
+ desc: {
+ 'ja-JP': '指定したユーザーをサイレンスにします。',
+ 'en-US': 'Make silence a user.'
+ },
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ userId: {
+ validator: $.type(ID),
+ transform: transform,
+ desc: {
+ 'ja-JP': '対象のユーザーID',
+ 'en-US': 'The user ID which you want to make silence'
+ }
+ },
+ }
+};
+
+export default define(meta, (ps) => new Promise(async (res, rej) => {
+ const user = await User.findOne({
+ _id: ps.userId
+ });
+
+ if (user == null) {
+ return rej('user not found');
+ }
+
+ if (user.isAdmin) {
+ return rej('cannot silence admin');
+ }
+
+ await User.findOneAndUpdate({
+ _id: user._id
+ }, {
+ $set: {
+ isSilenced: true
+ }
+ });
+
+ res();
+}));
diff --git a/src/server/api/endpoints/admin/unsilence-user.ts b/src/server/api/endpoints/admin/unsilence-user.ts
new file mode 100644
index 0000000000..a01bfbb6d2
--- /dev/null
+++ b/src/server/api/endpoints/admin/unsilence-user.ts
@@ -0,0 +1,45 @@
+import $ from 'cafy';
+import ID, { transform } from '../../../../misc/cafy-id';
+import define from '../../define';
+import User from '../../../../models/user';
+
+export const meta = {
+ desc: {
+ 'ja-JP': '指定したユーザーのサイレンスを解除します。',
+ 'en-US': 'Unsilence a user.'
+ },
+
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ userId: {
+ validator: $.type(ID),
+ transform: transform,
+ desc: {
+ 'ja-JP': '対象のユーザーID',
+ 'en-US': 'The user ID which you want to unsilence'
+ }
+ },
+ }
+};
+
+export default define(meta, (ps) => new Promise(async (res, rej) => {
+ const user = await User.findOne({
+ _id: ps.userId
+ });
+
+ if (user == null) {
+ return rej('user not found');
+ }
+
+ await User.findOneAndUpdate({
+ _id: user._id
+ }, {
+ $set: {
+ isSilenced: false
+ }
+ });
+
+ res();
+}));
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 344672bd63..4e8e707961 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -116,6 +116,11 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
if (data.viaMobile == null) data.viaMobile = false;
if (data.localOnly == null) data.localOnly = false;
+ // サイレンス
+ if (user.isSilenced && data.visibility == 'public') {
+ data.visibility = 'home';
+ }
+
if (data.visibleUsers) {
data.visibleUsers = erase(null, data.visibleUsers);
}