summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMeiMei <30769358+mei23@users.noreply.github.com>2019-01-11 08:09:44 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2019-01-11 08:09:44 +0900
commit203fba0216a9123cfe45dba1b3fbe5ecbb36fe03 (patch)
tree7a707150e57aa2274886fe51adb66eb32f5506a5 /src
parent管理者がサインイン履歴を参照できるツール (#3870) (diff)
downloadsharkey-203fba0216a9123cfe45dba1b3fbe5ecbb36fe03.tar.gz
sharkey-203fba0216a9123cfe45dba1b3fbe5ecbb36fe03.tar.bz2
sharkey-203fba0216a9123cfe45dba1b3fbe5ecbb36fe03.zip
管理画面でユーザーを状態でフィルタできるように (#3873)
Diffstat (limited to 'src')
-rw-r--r--src/client/app/admin/views/users.vue39
-rw-r--r--src/server/api/endpoints/admin/show-users.ts123
2 files changed, 160 insertions, 2 deletions
diff --git a/src/client/app/admin/views/users.vue b/src/client/app/admin/views/users.vue
index 21d41efba8..dcacdd5bad 100644
--- a/src/client/app/admin/views/users.vue
+++ b/src/client/app/admin/views/users.vue
@@ -31,6 +31,14 @@
<option value="-updatedAt">{{ $t('users.sort.updatedAtAsc') }}</option>
<option value="+updatedAt">{{ $t('users.sort.updatedAtDesc') }}</option>
</ui-select>
+ <ui-select v-model="state">
+ <span slot="label">{{ $t('users.state.title') }}</span>
+ <option value="all">{{ $t('users.state.all') }}</option>
+ <option value="admin">{{ $t('users.state.admin') }}</option>
+ <option value="moderator">{{ $t('users.state.moderator') }}</option>
+ <option value="verified">{{ $t('users.state.verified') }}</option>
+ <option value="suspended">{{ $t('users.state.suspended') }}</option>
+ </ui-select>
<ui-select v-model="origin">
<span slot="label">{{ $t('users.origin.title') }}</span>
<option value="combined">{{ $t('users.origin.combined') }}</option>
@@ -39,7 +47,7 @@
</ui-select>
</ui-horizon-group>
<sequential-entrance animation="entranceFromTop" delay="25">
- <div class="kofvwchc" v-for="user in users">
+ <div class="kofvwchc" v-for="user in users" :key="user.id">
<div>
<a :href="user | userPage(null, true)">
<mk-avatar class="avatar" :user="user" :disable-link="true"/>
@@ -49,6 +57,10 @@
<header>
<b><mk-user-name :user="user"/></b>
<span class="username">@{{ user | acct }}</span>
+ <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-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
</header>
<div>
<span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span>
@@ -84,6 +96,7 @@ export default Vue.extend({
suspending: false,
unsuspending: false,
sort: '+createdAt',
+ state: 'all',
origin: 'combined',
limit: 10,
offset: 0,
@@ -100,6 +113,12 @@ export default Vue.extend({
this.fetchUsers();
},
+ state() {
+ this.users = [];
+ this.offset = 0;
+ this.fetchUsers();
+ },
+
origin() {
this.users = [];
this.offset = 0;
@@ -236,7 +255,8 @@ export default Vue.extend({
},
fetchUsers() {
- this.$root.api('users', {
+ this.$root.api('admin/show-users', {
+ state: this.state,
origin: this.origin,
sort: this.sort,
offset: this.offset,
@@ -284,4 +304,19 @@ export default Vue.extend({
margin-left 8px
opacity 0.7
+ > .is-admin
+ > .is-moderator
+ flex-shrink 0
+ align-self center
+ margin 0 0 0 .5em
+ padding 1px 6px
+ font-size 80%
+ border-radius 3px
+ background var(--noteHeaderAdminBg)
+ color var(--noteHeaderAdminFg)
+
+ > .is-verified
+ > .is-suspended
+ margin 0 0 0 .5em
+ color #4dabf7
</style>
diff --git a/src/server/api/endpoints/admin/show-users.ts b/src/server/api/endpoints/admin/show-users.ts
new file mode 100644
index 0000000000..20ccfbd7f3
--- /dev/null
+++ b/src/server/api/endpoints/admin/show-users.ts
@@ -0,0 +1,123 @@
+import $ from 'cafy';
+import User, { pack } from '../../../../models/user';
+import define from '../../define';
+
+export const meta = {
+ requireCredential: true,
+ requireModerator: true,
+
+ params: {
+ limit: {
+ validator: $.num.optional.range(1, 100),
+ default: 10
+ },
+
+ offset: {
+ validator: $.num.optional.min(0),
+ default: 0
+ },
+
+ sort: {
+ validator: $.str.optional.or([
+ '+follower',
+ '-follower',
+ '+createdAt',
+ '-createdAt',
+ '+updatedAt',
+ '-updatedAt',
+ ]),
+ },
+
+ state: {
+ validator: $.str.optional.or([
+ 'all',
+ 'admin',
+ 'moderator',
+ 'adminOrModerator',
+ 'verified',
+ 'suspended',
+ ]),
+ default: 'all'
+ },
+
+ origin: {
+ validator: $.str.optional.or([
+ 'combined',
+ 'local',
+ 'remote',
+ ]),
+ default: 'local'
+ }
+ }
+};
+
+export default define(meta, (ps, me) => new Promise(async (res, rej) => {
+ let _sort;
+ if (ps.sort) {
+ if (ps.sort == '+follower') {
+ _sort = {
+ followersCount: -1
+ };
+ } else if (ps.sort == '-follower') {
+ _sort = {
+ followersCount: 1
+ };
+ } else if (ps.sort == '+createdAt') {
+ _sort = {
+ createdAt: -1
+ };
+ } else if (ps.sort == '+updatedAt') {
+ _sort = {
+ updatedAt: -1
+ };
+ } else if (ps.sort == '-createdAt') {
+ _sort = {
+ createdAt: 1
+ };
+ } else if (ps.sort == '-updatedAt') {
+ _sort = {
+ updatedAt: 1
+ };
+ }
+ } else {
+ _sort = {
+ _id: -1
+ };
+ }
+
+ const q = {
+ $and: []
+ } as any;
+
+ // state
+ q.$and.push(
+ ps.state == 'admin' ? { isAdmin: true } :
+ ps.state == 'moderator' ? { isModerator: true } :
+ ps.state == 'adminOrModerator' ? {
+ $or: [{
+ isAdmin: true
+ }, {
+ isModerator: true
+ }]
+ } :
+ ps.state == 'verified' ? { isVerified: true } :
+ ps.state == 'suspended' ? { isSuspended: true } :
+ {}
+ );
+
+ // origin
+ q.$and.push(
+ ps.origin == 'local' ? { host: null } :
+ ps.origin == 'remote' ? { host: { $ne: null } } :
+ {}
+ );
+
+ const users = await User
+ .find(q, {
+ limit: ps.limit,
+ sort: _sort,
+ skip: ps.offset
+ });
+
+ res(await Promise.all(users.map(user => pack(user, me, { detail: true }))));
+}));