管理画面でユーザーを状態でフィルタできるように (#3873)

This commit is contained in:
MeiMei 2019-01-11 08:09:44 +09:00 committed by syuilo
parent b0778dde7a
commit e5782a7c30
3 changed files with 168 additions and 2 deletions

View file

@ -1255,6 +1255,14 @@ admin/views/users.vue:
createdAtDesc: "登録日時が新しい順" createdAtDesc: "登録日時が新しい順"
updatedAtAsc: "更新日時が古い順" updatedAtAsc: "更新日時が古い順"
updatedAtDesc: "更新日時が新しい順" updatedAtDesc: "更新日時が新しい順"
state:
title: "状態"
all: "すべて"
admin: "管理者"
moderator: "モデレーター"
adminOrModerator: "管理者+モデレーター"
verified: "公式アカウント"
suspended: "凍結済み"
origin: origin:
title: "オリジン" title: "オリジン"
combined: "ローカル+リモート" combined: "ローカル+リモート"

View file

@ -31,6 +31,14 @@
<option value="-updatedAt">{{ $t('users.sort.updatedAtAsc') }}</option> <option value="-updatedAt">{{ $t('users.sort.updatedAtAsc') }}</option>
<option value="+updatedAt">{{ $t('users.sort.updatedAtDesc') }}</option> <option value="+updatedAt">{{ $t('users.sort.updatedAtDesc') }}</option>
</ui-select> </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"> <ui-select v-model="origin">
<span slot="label">{{ $t('users.origin.title') }}</span> <span slot="label">{{ $t('users.origin.title') }}</span>
<option value="combined">{{ $t('users.origin.combined') }}</option> <option value="combined">{{ $t('users.origin.combined') }}</option>
@ -39,7 +47,7 @@
</ui-select> </ui-select>
</ui-horizon-group> </ui-horizon-group>
<sequential-entrance animation="entranceFromTop" delay="25"> <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> <div>
<a :href="user | userPage(null, true)"> <a :href="user | userPage(null, true)">
<mk-avatar class="avatar" :user="user" :disable-link="true"/> <mk-avatar class="avatar" :user="user" :disable-link="true"/>
@ -49,6 +57,10 @@
<header> <header>
<b><mk-user-name :user="user"/></b> <b><mk-user-name :user="user"/></b>
<span class="username">@{{ user | acct }}</span> <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> </header>
<div> <div>
<span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span> <span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span>
@ -84,6 +96,7 @@ export default Vue.extend({
suspending: false, suspending: false,
unsuspending: false, unsuspending: false,
sort: '+createdAt', sort: '+createdAt',
state: 'all',
origin: 'combined', origin: 'combined',
limit: 10, limit: 10,
offset: 0, offset: 0,
@ -100,6 +113,12 @@ export default Vue.extend({
this.fetchUsers(); this.fetchUsers();
}, },
state() {
this.users = [];
this.offset = 0;
this.fetchUsers();
},
origin() { origin() {
this.users = []; this.users = [];
this.offset = 0; this.offset = 0;
@ -236,7 +255,8 @@ export default Vue.extend({
}, },
fetchUsers() { fetchUsers() {
this.$root.api('users', { this.$root.api('admin/show-users', {
state: this.state,
origin: this.origin, origin: this.origin,
sort: this.sort, sort: this.sort,
offset: this.offset, offset: this.offset,
@ -284,4 +304,19 @@ export default Vue.extend({
margin-left 8px margin-left 8px
opacity 0.7 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> </style>

View file

@ -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 }))));
}));