One operation to change permission

This commit is contained in:
Pig Fang 2019-03-18 13:24:03 +08:00
parent 0e58460d21
commit f64e6494c6
8 changed files with 137 additions and 365 deletions

View File

@ -333,10 +333,8 @@ class AdminController extends Controller
return json(trans('admin.users.operations.non-existent'), 1);
}
if ($user->uid !== $currentUser->uid) {
if ($user->permission >= $currentUser->permission) {
return json(trans('admin.users.operations.no-permission'), 1);
}
if ($user->uid !== $currentUser->uid && $user->permission >= $currentUser->permission) {
return json(trans('admin.users.operations.no-permission'), 1);
}
if ($action == 'email') {
@ -382,25 +380,15 @@ class AdminController extends Controller
$user->setScore($request->input('score'));
return json(trans('admin.users.operations.score.success'), 0);
} elseif ($action == 'ban') {
$permission = $user->getPermission() == User::BANNED ? User::NORMAL : User::BANNED;
$user->setPermission($permission);
} elseif ($action == 'permission') {
$user->permission = $this->validate($request, [
'permission' => 'required|in:-1,0,1'
])['permission'];
$user->save();
return json([
'errno' => 0,
'msg' => trans('admin.users.operations.ban.'.($permission == User::BANNED ? 'ban' : 'unban').'.success'),
'permission' => $user->getPermission(),
]);
} elseif ($action == 'admin') {
$permission = $user->getPermission() == User::ADMIN ? User::NORMAL : User::ADMIN;
$user->setPermission($permission);
return json([
'errno' => 0,
'msg' => trans('admin.users.operations.admin.'.($permission == User::ADMIN ? 'set' : 'unset').'.success'),
'permission' => $user->getPermission(),
'errno' => 0,
'msg' => trans('admin.users.operations.permission'),
]);
} elseif ($action == 'delete') {
$user->delete();

View File

@ -41,7 +41,15 @@
>{{ props.formattedRow[props.column.field] }}</a>
</span>
<span v-else-if="props.column.field === 'permission'">
{{ props.row | humanizePermission }}
<span>{{ props.row | humanizePermission }}</span>
<a
v-if="props.row.permission < 1 || (props.row.operations === 2 && props.row.permission < 2)"
:title="$t('admin.changePermission')"
data-test="permission"
@click="changePermission(props.row)"
>
<i class="fas fa-edit btn-edit" />
</a>
</span>
<span v-else-if="props.column.field === 'verified'">
<span v-if="props.row.verified" v-t="'admin.verified'" />
@ -59,36 +67,11 @@
</a>
</span>
<div v-else-if="props.column.field === 'operations'">
<div class="btn-group">
<button
class="btn btn-default dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
{{ $t('general.more') }} <span class="caret" />
</button>
<ul class="dropdown-menu operations-menu" :class="{ 'row-at-bottom': users.length - props.index < 3 }">
<li><a v-t="'admin.changePassword'" href="#" @click="changePassword(props.row)" /></li>
<template v-if="props.row.permission < 2">
<li class="divider" />
<li v-if="props.row.operations >= 2 && props.row.permission > -1">
<a
v-t="props.row.permission === 0 ? 'admin.setAdmin' : 'admin.unsetAdmin'"
href="#"
@click="toggleAdmin(props.row)"
/>
</li>
<li v-if="props.row.permission < 1">
<a
v-t="props.row.permission === 0 ? 'admin.ban' : 'admin.unban'"
href="#"
@click="toggleBan(props.row)"
/>
</li>
</template>
</ul>
</div>
<button
v-t="'admin.changePassword'"
class="btn btn-default"
@click="changePassword(props.row)"
/>
<button
v-t="'admin.deleteUser'"
:disabled="props.row.permission >= 2 || (props.row.operations === 1 && props.row.permission >= 1)"
@ -152,7 +135,7 @@ export default {
field: 'players_count', label: this.$t('admin.playersCount'), type: 'number',
},
{
field: 'permission', label: this.$t('admin.status'), globalSearchDisabled: true,
field: 'permission', label: this.$t('admin.permission'), globalSearchDisabled: true,
},
{
field: 'verified', label: this.$t('admin.verification'), type: 'boolean', globalSearchDisabled: true,
@ -311,25 +294,32 @@ export default {
toastr.warning(msg)
}
},
async toggleAdmin(user) {
const { errno, msg } = await this.$http.post(
'/admin/users?action=admin',
{ uid: user.uid }
)
if (errno === 0) {
user.permission = ~user.permission + 2
toastr.success(msg)
} else {
toastr.warning(msg)
async changePermission(user) {
const operator = user.operations
const options = {
'-1': this.$t('admin.banned'),
0: this.$t('admin.normal'),
}
},
async toggleBan(user) {
const { errno, msg } = await this.$http.post(
'/admin/users?action=ban',
{ uid: user.uid }
)
if (operator === 2) {
options[1] = this.$t('admin.admin')
}
const { dismiss, value } = await swal({
text: this.$t('admin.newPermission'),
input: 'radio',
inputOptions: options,
showCancelButton: true,
})
if (dismiss) {
return
}
const { errno, msg } = await this.$http.post('/admin/users?action=permission', {
uid: user.uid,
permission: value,
})
if (errno === 0) {
user.permission = ~user.permission
user.permission = +value
toastr.success(msg)
} else {
toastr.warning(msg)

View File

@ -93,7 +93,7 @@ test('generate players page link', async () => {
expect(wrapper.find('[data-toggle="tooltip"]').attributes('href')).toBe('/admin/players?uid=1')
})
test('admin option should not be displayed for super admins', async () => {
test('permission option should not be displayed for super admins', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{ uid: 1, permission: 2 },
@ -101,25 +101,10 @@ test('admin option should not be displayed for super admins', async () => {
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.setAdmin')
expect(text).not.toContain('admin.unsetAdmin')
expect(wrapper.find('[data-test=permission]').exists()).toBeFalse()
})
test('banning option should not be displayed for super admins', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{ uid: 1, permission: 2 },
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.ban')
expect(text).not.toContain('admin.unban')
})
test('admin option should be displayed for admin as super admin', async () => {
test('permission option should be displayed for admin as super admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
@ -129,27 +114,10 @@ test('admin option should be displayed for admin as super admin', async () => {
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).toContain('admin.unsetAdmin')
expect(text).not.toContain('admin.setAdmin')
expect(wrapper.find('[data-test=permission]').exists()).toBeTrue()
})
test('banning option should not be displayed for admin as super admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: 1, operations: 2,
},
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.ban')
expect(text).not.toContain('admin.unban')
})
test('admin option should be displayed for normal users as super admin', async () => {
test('permission option should be displayed for normal users as super admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
@ -159,27 +127,10 @@ test('admin option should be displayed for normal users as super admin', async (
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).toContain('admin.setAdmin')
expect(text).not.toContain('admin.unsetAdmin')
expect(wrapper.find('[data-test=permission]').exists()).toBeTrue()
})
test('banning option should be displayed for normal users as super admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: 0, operations: 2,
},
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).toContain('admin.ban')
expect(text).not.toContain('admin.unban')
})
test('admin option should not be displayed for banned users as super admin', async () => {
test('permission option should be displayed for banned users as super admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
@ -189,26 +140,10 @@ test('admin option should not be displayed for banned users as super admin', asy
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.setAdmin')
expect(text).not.toContain('admin.unsetAdmin')
expect(wrapper.find('[data-test=permission]').exists()).toBeTrue()
})
test('banning option should be displayed for banned users as super admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: -1, operations: 2,
},
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).toContain('admin.unban')
})
test('admin option should not be displayed for other admins as admin', async () => {
test('permission option should not be displayed for other admins as admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
@ -218,27 +153,10 @@ test('admin option should not be displayed for other admins as admin', async ()
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.setAdmin')
expect(text).not.toContain('admin.unsetAdmin')
expect(wrapper.find('[data-test=permission]').exists()).toBeFalse()
})
test('banning option should not be displayed for other admins as admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: 1, operations: 1,
},
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.ban')
expect(text).not.toContain('admin.unban')
})
test('admin option should not be displayed for normal users as admin', async () => {
test('permission option should be displayed for normal users as admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
@ -248,27 +166,10 @@ test('admin option should not be displayed for normal users as admin', async ()
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.setAdmin')
expect(text).not.toContain('admin.unsetAdmin')
expect(wrapper.find('[data-test=permission]').exists()).toBeTrue()
})
test('banning option should be displayed for normal users as admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: 0, operations: 1,
},
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).toContain('admin.ban')
expect(text).not.toContain('admin.unban')
})
test('admin option should not be displayed for banned users as admin', async () => {
test('permission option should be displayed for banned users as admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
@ -278,23 +179,7 @@ test('admin option should not be displayed for banned users as admin', async ()
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).not.toContain('admin.setAdmin')
expect(text).not.toContain('admin.unsetAdmin')
})
test('banning option should be displayed for banned users as admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: -1, operations: 1,
},
],
})
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const text = wrapper.find('.vgt-table').text()
expect(text).toContain('admin.unban')
expect(wrapper.find('[data-test=permission]').exists()).toBeTrue()
})
test('deletion button should not be displayed for super admins', async () => {
@ -501,7 +386,7 @@ test('change password', async () => {
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const button = wrapper.find('.operations-menu > li:nth-child(1) > a')
const button = wrapper.find('.btn-default')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
@ -553,70 +438,61 @@ test('change score', async () => {
expect(wrapper.text()).toContain('45')
})
test('toggle admin', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: 0, operations: 2,
},
],
})
test('change permission', async () => {
Vue.prototype.$http.get
.mockResolvedValueOnce({
data: [
{
uid: 1, permission: 0, operations: 2,
},
],
})
.mockResolvedValueOnce({
data: [
{
uid: 1, permission: 0, operations: 1,
},
],
})
Vue.prototype.$http.post
.mockResolvedValueOnce({ errno: 1, msg: '1' })
.mockResolvedValue({ errno: 0, msg: '0' })
swal
.mockResolvedValueOnce({ dismiss: 1 })
.mockResolvedValueOnce({ value: 1 })
.mockResolvedValueOnce({ value: -1 })
const wrapper = mount(Users)
let wrapper = mount(Users)
await wrapper.vm.$nextTick()
const button = wrapper.find('.operations-menu > li:nth-child(3) > a')
let button = wrapper.find('[data-test=permission]')
button.trigger('click')
expect(swal.mock.calls[0][0].inputOptions).toStrictEqual({
'-1': 'admin.banned',
0: 'admin.normal',
1: 'admin.admin',
})
expect(Vue.prototype.$http.post).not.toBeCalled()
button.trigger('click')
await wrapper.vm.$nextTick()
expect(Vue.prototype.$http.post).toBeCalledWith(
'/admin/users?action=admin',
{ uid: 1 }
'/admin/users?action=permission',
{ uid: 1, permission: 1 }
)
expect(wrapper.text()).toContain('admin.normal')
button.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('admin.admin')
wrapper = mount(Users)
await wrapper.vm.$nextTick()
button = wrapper.find('[data-test=permission]')
button.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('admin.normal')
})
test('toggle ban', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: [
{
uid: 1, permission: 0, operations: 2,
},
],
expect(swal.mock.calls[2][0].inputOptions).toStrictEqual({
'-1': 'admin.banned',
0: 'admin.normal',
})
Vue.prototype.$http.post
.mockResolvedValueOnce({ errno: 1, msg: '1' })
.mockResolvedValue({ errno: 0, msg: '0' })
const wrapper = mount(Users)
await wrapper.vm.$nextTick()
const button = wrapper.find('.operations-menu > li:nth-child(4) > a')
button.trigger('click')
await wrapper.vm.$nextTick()
expect(Vue.prototype.$http.post).toBeCalledWith(
'/admin/users?action=ban',
{ uid: 1 }
)
expect(wrapper.text()).toContain('admin.ban')
button.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('admin.banned')
button.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('admin.ban')
})
test('delete user', async () => {

View File

@ -8,49 +8,22 @@ index:
user-registration: User Registration
users:
players-count:
title: Players Count
status:
title: Status
normal: Normal
banned: Banned
admin: Admin
super-admin: Super Admin
operations:
title: Operations
non-existent: No such user.
no-permission: You have no permission to operate this user.
invalid: Invalid action.
email:
change: Edit Email
existed: :email is existed.
success: Email changed successfully.
verification:
success: Account verification status toggled successfully.
nickname:
change: Edit Nickname
success: Nickname changed successfully.
password:
change: Edit Password
success: Password changed successfully.
score:
success: Score changed successfully.
admin:
set:
text: Set as Admin
success: The account has been set as admin.
unset:
text: Remove Admin
success: The account's admin privilege has been removed.
ban:
ban:
text: Ban
success: The account has been banned.
unban:
text: Unban
success: The account was not banned anymore.
cant-super-admin: You can't ban a super admin.
cant-admin: Only super admins are able to ban admins.
permission: Permission updated.
delete:
delete: Delete User
success: The account has been deleted successfully.

View File

@ -218,24 +218,22 @@ admin:
operationsTitle: Operations
status: Status
playersCount: Players Count
ban: Ban
unban: Unban
setAdmin: Set as admin
unsetAdmin: Remove admin
deleteUser: Delete
cannotDeleteAdmin: You can't delete admins.
cannotDeleteSuperAdmin: You can't delete super admin in this way
changeEmail: Edit Email
newUserEmail: 'Please enter the new email:'
verification: Email Verification
toggleVerification: Toggle Verification Status
changeNickName: Edit Nickname
changePassword: Edit Password
changeScore: Edit Score
newUserEmail: 'Please enter the new email:'
newUserNickname: 'Please enter the new nickname:'
changePassword: Edit Password
newUserPassword: 'Please enter the new password:'
deleteUserNotice: Are you sure to delete this user? It' permanent.
changeScore: Edit Score
newScore: 'Please enter the new score:'
changePermission: Change permission
newPermission: 'Please select new permission:'
deleteUserNotice: Are you sure to delete this user? It' permanent.
inspectHisOwner: Click to inspect the owner of this player
inspectHisPlayers: Click to inspect the players he owns
banned: Banned

View File

@ -8,49 +8,22 @@ index:
user-registration: 用户注册
users:
players-count:
title: 拥有角色数
status:
title: 状态
normal: 普通用户
banned: 封禁
admin: 管理员
super-admin: 超级管理员
operations:
title: 更多操作
non-existent: 用户不存在
no-permission: 你无权操作此用户
invalid: 无效的 action
email:
change: 修改邮箱
existed: 邮箱 :email 已被占用
success: 邮箱修改成功
verification:
success: 用户的邮箱验证状态已修改
nickname:
change: 修改昵称
success: 昵称已成功设置为 :new
password:
change: 更改密码
success: 密码修改成功
score:
success: 积分修改成功
admin:
set:
text: 设为管理员
success: 账号已被设置为管理员
unset:
text: 解除管理员
success: 账号已被解除管理员
ban:
ban:
text: 封禁
success: 账号已被封禁
unban:
text: 解封
success: 账号已被解封
cant-super-admin: 无法封禁超级管理员
cant-admin: 非超级管理员无法封禁普通管理员
permission: 权限已更改
delete:
delete: 删除用户
success: 账号已被成功删除

View File

@ -214,26 +214,24 @@ user:
admin:
operationsTitle: 更多操作
status: 状态
permission: 权限
playersCount: 角色数量
ban: 封禁
unban: 解封
setAdmin: 设为管理员
unsetAdmin: 解除管理员
deleteUser: 删除
cannotDeleteAdmin: 你不能删除管理员账号哦
cannotDeleteSuperAdmin: 超级管理员账号不能被这样删除的啦
changeEmail: 修改邮箱
newUserEmail: 请输入新邮箱:
verification: 邮箱验证
toggleVerification: 修改邮箱验证状态
changeNickName: 修改昵称
changePassword: 更改密码
changeScore: 更改积分
newUserEmail: 请输入新邮箱:
newUserNickname: 请输入新昵称:
changePassword: 更改密码
newUserPassword: 请输入新密码:
deleteUserNotice: 真的要删除此用户吗?此操作不可恢复
changeScore: 更改积分
newScore: 请输入积分值:
changePermission: 更改权限
newPermission: 请选择新的权限:
deleteUserNotice: 真的要删除此用户吗?此操作不可恢复
inspectHisOwner: 点击查看该角色的所有者
inspectHisPlayers: 点击查看该用户的角色
banned: 封禁

View File

@ -418,54 +418,30 @@ class AdminControllerTest extends BrowserKitTestCase
'score' => 123,
]);
// Ban a user
$this->postJson('/admin/users', ['uid' => $user->uid, 'action' => 'ban'])
->seeJson([
'errno' => 0,
'msg' => trans('admin.users.operations.ban.ban.success'),
'permission' => User::BANNED,
]);
// Invalid permission value
$this->postJson('/admin/users', [
'uid' => $user->uid,
'action' => 'permission',
'permission' => -2
])->seeJson([
'errno' => 1,
'msg' => trans('validation.in', ['attribute' => 'permission']),
]);
$user = User::find($user->uid);
$this->assertEquals(User::NORMAL, $user->getPermission());
// Update permission successfully
$this->postJson('/admin/users', [
'uid' => $user->uid,
'action' => 'permission',
'permission' => -1
])->seeJson([
'errno' => 0,
'msg' => trans('admin.users.operations.permission'),
]);
$user = User::find($user->uid);
$this->assertEquals(User::BANNED, $user->getPermission());
// Unban a user
$this->postJson('/admin/users', ['uid' => $user->uid, 'action' => 'ban'])
->seeJson([
'errno' => 0,
'msg' => trans('admin.users.operations.ban.unban.success'),
'permission' => User::NORMAL,
]);
$user = User::find($user->uid);
$this->assertEquals(User::NORMAL, $user->getPermission());
// Set a user to be an admin
$this->postJson('/admin/users', ['uid' => $user->uid, 'action' => 'admin'])
->seeJson([
'errno' => 0,
'msg' => trans('admin.users.operations.admin.set.success'),
'permission' => User::ADMIN,
]);
$user = User::find($user->uid);
$this->assertEquals(User::ADMIN, $user->getPermission());
// An admin cannot set another admin to be a normal user
$this->postJson('/admin/users', ['uid' => $user->uid])
->seeJson([
'errno' => 1,
'msg' => trans('admin.users.operations.no-permission'),
]);
// Set an admin to be a normal user
$this->actAs('superAdmin')
->postJson('/admin/users', ['uid' => $user->uid, 'action' => 'admin'])
->seeJson([
'errno' => 0,
'msg' => trans('admin.users.operations.admin.unset.success'),
'permission' => User::NORMAL,
]);
$user = User::find($user->uid);
$this->assertEquals(User::NORMAL, $user->getPermission());
// Delete a user
$this->postJson('/admin/users', ['uid' => $user->uid, 'action' => 'delete'])
->seeJson([