mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 1880-no-throw-when-register-with-existing-email
This commit is contained in:
commit
4c420ecbf4
254
admin/src/components/ChangeUserRoleFormular.spec.js
Normal file
254
admin/src/components/ChangeUserRoleFormular.spec.js
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import ChangeUserRoleFormular from './ChangeUserRoleFormular.vue'
|
||||||
|
import { setUserRole } from '../graphql/setUserRole'
|
||||||
|
import { toastSuccessSpy, toastErrorSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
const apolloMutateMock = jest.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
setUserRole: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$t: jest.fn((t) => t),
|
||||||
|
$apollo: {
|
||||||
|
mutate: apolloMutateMock,
|
||||||
|
},
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
moderator: {
|
||||||
|
id: 0,
|
||||||
|
name: 'test moderator',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let propsData
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
describe('ChangeUserRoleFormular', () => {
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(ChangeUserRoleFormular, { localVue, mocks, propsData })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('DOM has', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData = {
|
||||||
|
item: {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a DIV element with the class.delete-user-formular', () => {
|
||||||
|
expect(wrapper.find('.change-user-role-formular').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('change own role', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData = {
|
||||||
|
item: {
|
||||||
|
userId: 0,
|
||||||
|
isAdmin: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the text that you cannot change own role', () => {
|
||||||
|
expect(wrapper.text()).toContain('userRole.notChangeYourSelf')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has role select disabled', () => {
|
||||||
|
expect(wrapper.find('select[disabled="disabled"]').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('change others role', () => {
|
||||||
|
let rolesToSelect
|
||||||
|
|
||||||
|
describe('general', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData = {
|
||||||
|
item: {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
rolesToSelect = wrapper.find('select.role-select').findAll('option')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has no text that you cannot change own role', () => {
|
||||||
|
expect(wrapper.text()).not.toContain('userRole.notChangeYourSelf')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the select label', () => {
|
||||||
|
expect(wrapper.text()).toContain('userRole.selectLabel')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a select', () => {
|
||||||
|
expect(wrapper.find('select.role-select').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has role select enabled', () => {
|
||||||
|
expect(wrapper.find('select.role-select[disabled="disabled"]').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('on API error', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||||
|
rolesToSelect.at(1).setSelected()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts an error message', () => {
|
||||||
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('user is usual user', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
apolloMutateMock.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
setUserRole: new Date(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
propsData = {
|
||||||
|
item: {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
rolesToSelect = wrapper.find('select.role-select').findAll('option')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has selected option set to "usual user"', () => {
|
||||||
|
expect(wrapper.find('select.role-select').element.value).toBe('user')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('change select to', () => {
|
||||||
|
describe('same role', () => {
|
||||||
|
it('does not call the API', () => {
|
||||||
|
rolesToSelect.at(0).setSelected()
|
||||||
|
expect(apolloMutateMock).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('new role', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
rolesToSelect.at(1).setSelected()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls the API', () => {
|
||||||
|
expect(apolloMutateMock).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
mutation: setUserRole,
|
||||||
|
variables: {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits "updateIsAdmin"', () => {
|
||||||
|
expect(wrapper.emitted('updateIsAdmin')).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.arrayContaining([
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: expect.any(Date),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts success message', () => {
|
||||||
|
expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('user is admin', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
apolloMutateMock.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
setUserRole: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
propsData = {
|
||||||
|
item: {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: new Date(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
rolesToSelect = wrapper.find('select.role-select').findAll('option')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has selected option set to "admin"', () => {
|
||||||
|
expect(wrapper.find('select.role-select').element.value).toBe('admin')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('change select to', () => {
|
||||||
|
describe('same role', () => {
|
||||||
|
it('does not call the API', () => {
|
||||||
|
rolesToSelect.at(1).setSelected()
|
||||||
|
expect(apolloMutateMock).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('new role', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
rolesToSelect.at(0).setSelected()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls the API', () => {
|
||||||
|
expect(apolloMutateMock).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
mutation: setUserRole,
|
||||||
|
variables: {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits "updateIsAdmin"', () => {
|
||||||
|
expect(wrapper.emitted('updateIsAdmin')).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.arrayContaining([
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: null,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts success message', () => {
|
||||||
|
expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
89
admin/src/components/ChangeUserRoleFormular.vue
Normal file
89
admin/src/components/ChangeUserRoleFormular.vue
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<div class="change-user-role-formular">
|
||||||
|
<div class="shadow p-3 mb-5 bg-white rounded">
|
||||||
|
<div v-if="item.userId === $store.state.moderator.id" class="m-3 mb-4">
|
||||||
|
{{ $t('userRole.notChangeYourSelf') }}
|
||||||
|
</div>
|
||||||
|
<div class="m-3">
|
||||||
|
<label for="role" class="mr-3">{{ $t('userRole.selectLabel') }}</label>
|
||||||
|
<b-form-select
|
||||||
|
class="role-select"
|
||||||
|
v-model="roleSelected"
|
||||||
|
:options="roles"
|
||||||
|
:disabled="item.userId === $store.state.moderator.id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { setUserRole } from '../graphql/setUserRole'
|
||||||
|
|
||||||
|
const rolesValues = {
|
||||||
|
admin: 'admin',
|
||||||
|
user: 'user',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ChangeUserRoleFormular',
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
roleSelected: this.item.isAdmin ? rolesValues.admin : rolesValues.user,
|
||||||
|
roles: [
|
||||||
|
{ value: rolesValues.user, text: this.$t('userRole.selectRoles.user') },
|
||||||
|
{ value: rolesValues.admin, text: this.$t('userRole.selectRoles.admin') },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
roleSelected(newRole, oldRole) {
|
||||||
|
if (newRole !== oldRole) {
|
||||||
|
this.setUserRole(newRole, oldRole)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setUserRole(newRole, oldRole) {
|
||||||
|
this.$apollo
|
||||||
|
.mutate({
|
||||||
|
mutation: setUserRole,
|
||||||
|
variables: {
|
||||||
|
userId: this.item.userId,
|
||||||
|
isAdmin: newRole === rolesValues.admin,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
this.$emit('updateIsAdmin', {
|
||||||
|
userId: this.item.userId,
|
||||||
|
isAdmin: result.data.setUserRole,
|
||||||
|
})
|
||||||
|
this.toastSuccess(
|
||||||
|
this.$t('userRole.successfullyChangedTo', {
|
||||||
|
role:
|
||||||
|
result.data.setUserRole !== null
|
||||||
|
? this.$t('userRole.selectRoles.admin')
|
||||||
|
: this.$t('userRole.selectRoles.user'),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.roleSelected = oldRole
|
||||||
|
this.toastError(error.message)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.role-select {
|
||||||
|
width: 300pt;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -47,200 +47,200 @@ describe('DeletedUserFormular', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('has a DIV element with the class.delete-user-formular', () => {
|
it('has a DIV element with the class.delete-user-formular', () => {
|
||||||
expect(wrapper.find('.deleted-user-formular').exists()).toBeTruthy()
|
expect(wrapper.find('.deleted-user-formular').exists()).toBe(true)
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('delete self', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.setProps({
|
|
||||||
item: {
|
|
||||||
userId: 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows a text that you cannot delete yourself', () => {
|
describe('delete self', () => {
|
||||||
expect(wrapper.text()).toBe('removeNotSelf')
|
beforeEach(() => {
|
||||||
})
|
wrapper.setProps({
|
||||||
})
|
item: {
|
||||||
|
userId: 0,
|
||||||
describe('delete other user', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.setProps({
|
|
||||||
item: {
|
|
||||||
userId: 1,
|
|
||||||
deletedAt: null,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a checkbox', () => {
|
|
||||||
expect(wrapper.find('input[type="checkbox"]').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('shows the text "delete_user"', () => {
|
|
||||||
expect(wrapper.text()).toBe('delete_user')
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click on checkbox', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await wrapper.find('input[type="checkbox"]').setChecked()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a confirmation button', () => {
|
|
||||||
expect(wrapper.find('button').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has the button text "delete_user"', () => {
|
|
||||||
expect(wrapper.find('button').text()).toBe('delete_user')
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('confirm delete with success', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await wrapper.find('button').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls the API', () => {
|
|
||||||
expect(apolloMutateMock).toBeCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
mutation: deleteUser,
|
|
||||||
variables: {
|
|
||||||
userId: 1,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('emits update deleted At', () => {
|
|
||||||
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.arrayContaining([
|
|
||||||
{
|
|
||||||
userId: 1,
|
|
||||||
deletedAt: date,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('unchecks the checkbox', () => {
|
|
||||||
expect(wrapper.find('input').attributes('checked')).toBe(undefined)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('confirm delete with error', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
|
||||||
await wrapper.find('button').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
|
||||||
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click on checkbox again', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await wrapper.find('input[type="checkbox"]').setChecked(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has no confirmation button anymore', () => {
|
|
||||||
expect(wrapper.find('button').exists()).toBeFalsy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('recover user', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.setProps({
|
|
||||||
item: {
|
|
||||||
userId: 1,
|
|
||||||
deletedAt: date,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a checkbox', () => {
|
|
||||||
expect(wrapper.find('input[type="checkbox"]').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('shows the text "undelete_user"', () => {
|
|
||||||
expect(wrapper.text()).toBe('undelete_user')
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click on checkbox', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
apolloMutateMock.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
unDeleteUser: null,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
await wrapper.find('input[type="checkbox"]').setChecked()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has a confirmation button', () => {
|
it('shows a text that you cannot delete yourself', () => {
|
||||||
expect(wrapper.find('button').exists()).toBeTruthy()
|
expect(wrapper.text()).toBe('removeNotSelf')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('delete other user', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper.setProps({
|
||||||
|
item: {
|
||||||
|
userId: 1,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has the button text "undelete_user"', () => {
|
it('has a checkbox', () => {
|
||||||
expect(wrapper.find('button').text()).toBe('undelete_user')
|
expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirm recover with success', () => {
|
it('shows the text "delete_user"', () => {
|
||||||
|
expect(wrapper.text()).toBe('delete_user')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click on checkbox', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await wrapper.find('button').trigger('click')
|
await wrapper.find('input[type="checkbox"]').setChecked()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls the API', () => {
|
it('has a confirmation button', () => {
|
||||||
expect(apolloMutateMock).toBeCalledWith(
|
expect(wrapper.find('button').exists()).toBe(true)
|
||||||
expect.objectContaining({
|
|
||||||
mutation: unDeleteUser,
|
|
||||||
variables: {
|
|
||||||
userId: 1,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('emits update deleted At', () => {
|
it('has the button text "delete_user"', () => {
|
||||||
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
expect(wrapper.find('button').text()).toBe('delete_user')
|
||||||
expect.arrayContaining([
|
})
|
||||||
expect.arrayContaining([
|
|
||||||
{
|
describe('confirm delete with success', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper.find('button').trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls the API', () => {
|
||||||
|
expect(apolloMutateMock).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
mutation: deleteUser,
|
||||||
|
variables: {
|
||||||
userId: 1,
|
userId: 1,
|
||||||
deletedAt: null,
|
|
||||||
},
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits update deleted At', () => {
|
||||||
|
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.arrayContaining([
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
deletedAt: date,
|
||||||
|
},
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
)
|
||||||
)
|
})
|
||||||
|
|
||||||
|
it('unchecks the checkbox', () => {
|
||||||
|
expect(wrapper.find('input').attributes('checked')).toBe(undefined)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('unchecks the checkbox', () => {
|
describe('confirm delete with error', () => {
|
||||||
expect(wrapper.find('input').attributes('checked')).toBe(undefined)
|
beforeEach(async () => {
|
||||||
|
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||||
|
await wrapper.find('button').trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts an error message', () => {
|
||||||
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click on checkbox again', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper.find('input[type="checkbox"]').setChecked(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has no confirmation button anymore', () => {
|
||||||
|
expect(wrapper.find('button').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('recover user', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper.setProps({
|
||||||
|
item: {
|
||||||
|
userId: 1,
|
||||||
|
deletedAt: date,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirm recover with error', () => {
|
it('has a checkbox', () => {
|
||||||
beforeEach(async () => {
|
expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true)
|
||||||
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
|
||||||
await wrapper.find('button').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
|
||||||
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('click on checkbox again', () => {
|
it('shows the text "undelete_user"', () => {
|
||||||
|
expect(wrapper.text()).toBe('undelete_user')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click on checkbox', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await wrapper.find('input[type="checkbox"]').setChecked(false)
|
apolloMutateMock.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
unDeleteUser: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await wrapper.find('input[type="checkbox"]').setChecked()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has no confirmation button anymore', () => {
|
it('has a confirmation button', () => {
|
||||||
expect(wrapper.find('button').exists()).toBeFalsy()
|
expect(wrapper.find('button').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the button text "undelete_user"', () => {
|
||||||
|
expect(wrapper.find('button').text()).toBe('undelete_user')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('confirm recover with success', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper.find('button').trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls the API', () => {
|
||||||
|
expect(apolloMutateMock).toBeCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
mutation: unDeleteUser,
|
||||||
|
variables: {
|
||||||
|
userId: 1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits update deleted At', () => {
|
||||||
|
expect(wrapper.emitted('updateDeletedAt')).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.arrayContaining([
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('unchecks the checkbox', () => {
|
||||||
|
expect(wrapper.find('input').attributes('checked')).toBe(undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('confirm recover with error', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||||
|
await wrapper.find('button').trigger('click')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts an error message', () => {
|
||||||
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click on checkbox again', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper.find('input[type="checkbox"]').setChecked(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has no confirmation button anymore', () => {
|
||||||
|
expect(wrapper.find('button').exists()).toBe(false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -28,6 +28,7 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import SearchUserTable from './SearchUserTable.vue'
|
import SearchUserTable from './SearchUserTable.vue'
|
||||||
|
|
||||||
const date = new Date()
|
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
const apolloMutateMock = jest.fn().mockResolvedValue({})
|
const apolloMutateMock = jest.fn().mockResolvedValue({})
|
||||||
@ -96,16 +94,29 @@ describe('SearchUserTable', () => {
|
|||||||
await wrapper.findAll('tbody > tr').at(1).trigger('click')
|
await wrapper.findAll('tbody > tr').at(1).trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('isAdmin', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper.find('div.change-user-role-formular').vm.$emit('updateIsAdmin', {
|
||||||
|
userId: 1,
|
||||||
|
isAdmin: new Date(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits updateIsAdmin', () => {
|
||||||
|
expect(wrapper.emitted('updateIsAdmin')).toEqual([[1, expect.any(Date)]])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('deleted at', () => {
|
describe('deleted at', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await wrapper.find('div.deleted-user-formular').vm.$emit('updateDeletedAt', {
|
await wrapper.find('div.deleted-user-formular').vm.$emit('updateDeletedAt', {
|
||||||
userId: 1,
|
userId: 1,
|
||||||
deletedAt: date,
|
deletedAt: new Date(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('emits updateDeletedAt', () => {
|
it('emits updateDeletedAt', () => {
|
||||||
expect(wrapper.emitted('updateDeletedAt')).toEqual([[1, date]])
|
expect(wrapper.emitted('updateDeletedAt')).toEqual([[1, expect.any(Date)]])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<template #cell(status)="row">
|
<template #cell(status)="row">
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<b-avatar v-if="row.item.deletedAt" class="mr-3" variant="light">
|
<b-avatar v-if="row.item.deletedAt" class="mr-3 test-deleted-icon" variant="light">
|
||||||
<b-iconstack font-scale="2">
|
<b-iconstack font-scale="2">
|
||||||
<b-icon stacked icon="person" variant="info" scale="0.75"></b-icon>
|
<b-icon stacked icon="person" variant="info" scale="0.75"></b-icon>
|
||||||
<b-icon stacked icon="slash-circle" variant="danger"></b-icon>
|
<b-icon stacked icon="slash-circle" variant="danger"></b-icon>
|
||||||
@ -79,6 +79,9 @@
|
|||||||
<b-tab :title="$t('transactionlink.name')" :disabled="row.item.deletedAt !== null">
|
<b-tab :title="$t('transactionlink.name')" :disabled="row.item.deletedAt !== null">
|
||||||
<transaction-link-list v-if="!row.item.deletedAt" :userId="row.item.userId" />
|
<transaction-link-list v-if="!row.item.deletedAt" :userId="row.item.userId" />
|
||||||
</b-tab>
|
</b-tab>
|
||||||
|
<b-tab :title="$t('userRole.tabTitle')">
|
||||||
|
<change-user-role-formular :item="row.item" @updateIsAdmin="updateIsAdmin" />
|
||||||
|
</b-tab>
|
||||||
<b-tab :title="$t('delete_user')">
|
<b-tab :title="$t('delete_user')">
|
||||||
<deleted-user-formular :item="row.item" @updateDeletedAt="updateDeletedAt" />
|
<deleted-user-formular :item="row.item" @updateDeletedAt="updateDeletedAt" />
|
||||||
</b-tab>
|
</b-tab>
|
||||||
@ -93,6 +96,7 @@ import CreationFormular from '../CreationFormular.vue'
|
|||||||
import ConfirmRegisterMailFormular from '../ConfirmRegisterMailFormular.vue'
|
import ConfirmRegisterMailFormular from '../ConfirmRegisterMailFormular.vue'
|
||||||
import CreationTransactionList from '../CreationTransactionList.vue'
|
import CreationTransactionList from '../CreationTransactionList.vue'
|
||||||
import TransactionLinkList from '../TransactionLinkList.vue'
|
import TransactionLinkList from '../TransactionLinkList.vue'
|
||||||
|
import ChangeUserRoleFormular from '../ChangeUserRoleFormular.vue'
|
||||||
import DeletedUserFormular from '../DeletedUserFormular.vue'
|
import DeletedUserFormular from '../DeletedUserFormular.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -102,6 +106,7 @@ export default {
|
|||||||
ConfirmRegisterMailFormular,
|
ConfirmRegisterMailFormular,
|
||||||
CreationTransactionList,
|
CreationTransactionList,
|
||||||
TransactionLinkList,
|
TransactionLinkList,
|
||||||
|
ChangeUserRoleFormular,
|
||||||
DeletedUserFormular,
|
DeletedUserFormular,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -123,6 +128,9 @@ export default {
|
|||||||
updateUserData(rowItem, newCreation) {
|
updateUserData(rowItem, newCreation) {
|
||||||
rowItem.creation = newCreation
|
rowItem.creation = newCreation
|
||||||
},
|
},
|
||||||
|
updateIsAdmin({ userId, isAdmin }) {
|
||||||
|
this.$emit('updateIsAdmin', userId, isAdmin)
|
||||||
|
},
|
||||||
updateDeletedAt({ userId, deletedAt }) {
|
updateDeletedAt({ userId, deletedAt }) {
|
||||||
this.$emit('updateDeletedAt', userId, deletedAt)
|
this.$emit('updateDeletedAt', userId, deletedAt)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export const searchUsers = gql`
|
|||||||
hasElopage
|
hasElopage
|
||||||
emailConfirmationSend
|
emailConfirmationSend
|
||||||
deletedAt
|
deletedAt
|
||||||
|
isAdmin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
admin/src/graphql/setUserRole.js
Normal file
7
admin/src/graphql/setUserRole.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const setUserRole = gql`
|
||||||
|
mutation ($userId: Int!, $isAdmin: Boolean!) {
|
||||||
|
setUserRole(userId: $userId, isAdmin: $isAdmin)
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -101,7 +101,7 @@
|
|||||||
},
|
},
|
||||||
"redeemed": "eingelöst",
|
"redeemed": "eingelöst",
|
||||||
"remove": "Entfernen",
|
"remove": "Entfernen",
|
||||||
"removeNotSelf": "Als Admin / Moderator kannst du dich nicht selber löschen.",
|
"removeNotSelf": "Als Admin/Moderator kannst du dich nicht selber löschen.",
|
||||||
"remove_all": "alle Nutzer entfernen",
|
"remove_all": "alle Nutzer entfernen",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
@ -131,6 +131,16 @@
|
|||||||
"text_false": " Die letzte Email wurde am {date} Uhr an das Mitglied ({email}) gesendet.",
|
"text_false": " Die letzte Email wurde am {date} Uhr an das Mitglied ({email}) gesendet.",
|
||||||
"text_true": " Die Email wurde bestätigt."
|
"text_true": " Die Email wurde bestätigt."
|
||||||
},
|
},
|
||||||
|
"userRole": {
|
||||||
|
"notChangeYourSelf": "Als Admin/Moderator kannst du nicht selber deine Rolle ändern.",
|
||||||
|
"selectLabel": "Rolle:",
|
||||||
|
"selectRoles": {
|
||||||
|
"admin": "Administrator",
|
||||||
|
"user": "einfacher Nutzer"
|
||||||
|
},
|
||||||
|
"successfullyChangedTo": "Nutzer ist jetzt „{role}“.",
|
||||||
|
"tabTitle": "Nutzer-Rolle"
|
||||||
|
},
|
||||||
"user_deleted": "Nutzer ist gelöscht.",
|
"user_deleted": "Nutzer ist gelöscht.",
|
||||||
"user_recovered": "Nutzer ist wiederhergestellt.",
|
"user_recovered": "Nutzer ist wiederhergestellt.",
|
||||||
"user_search": "Nutzer-Suche"
|
"user_search": "Nutzer-Suche"
|
||||||
|
|||||||
@ -101,7 +101,7 @@
|
|||||||
},
|
},
|
||||||
"redeemed": "redeemed",
|
"redeemed": "redeemed",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"removeNotSelf": "As admin / moderator you cannot delete yourself.",
|
"removeNotSelf": "As an admin/moderator, you cannot delete yourself.",
|
||||||
"remove_all": "Remove all users",
|
"remove_all": "Remove all users",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
@ -131,6 +131,16 @@
|
|||||||
"text_false": "The last email was sent to the member ({email}) on {date}.",
|
"text_false": "The last email was sent to the member ({email}) on {date}.",
|
||||||
"text_true": "The email was confirmed."
|
"text_true": "The email was confirmed."
|
||||||
},
|
},
|
||||||
|
"userRole": {
|
||||||
|
"notChangeYourSelf": "As an admin/moderator, you cannot change your own role.",
|
||||||
|
"selectLabel": "Role:",
|
||||||
|
"selectRoles": {
|
||||||
|
"admin": "administrator",
|
||||||
|
"user": "usual user"
|
||||||
|
},
|
||||||
|
"successfullyChangedTo": "User is now \"{role}\".",
|
||||||
|
"tabTitle": "User Role"
|
||||||
|
},
|
||||||
"user_deleted": "User is deleted.",
|
"user_deleted": "User is deleted.",
|
||||||
"user_recovered": "User is recovered.",
|
"user_recovered": "User is recovered.",
|
||||||
"user_search": "User search"
|
"user_search": "User search"
|
||||||
|
|||||||
@ -199,14 +199,43 @@ describe('UserSearch', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('change user role', () => {
|
||||||
|
const userId = 4
|
||||||
|
|
||||||
|
describe('to admin', () => {
|
||||||
|
it('updates user role to admin', async () => {
|
||||||
|
await wrapper
|
||||||
|
.findComponent({ name: 'SearchUserTable' })
|
||||||
|
.vm.$emit('updateIsAdmin', userId, new Date())
|
||||||
|
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).isAdmin).toEqual(
|
||||||
|
expect.any(Date),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('to usual user', () => {
|
||||||
|
it('updates user role to usual user', async () => {
|
||||||
|
await wrapper
|
||||||
|
.findComponent({ name: 'SearchUserTable' })
|
||||||
|
.vm.$emit('updateIsAdmin', userId, null)
|
||||||
|
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).isAdmin).toEqual(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('delete user', () => {
|
describe('delete user', () => {
|
||||||
const now = new Date()
|
const userId = 4
|
||||||
beforeEach(async () => {
|
beforeEach(() => {
|
||||||
wrapper.findComponent({ name: 'SearchUserTable' }).vm.$emit('updateDeletedAt', 4, now)
|
wrapper
|
||||||
|
.findComponent({ name: 'SearchUserTable' })
|
||||||
|
.vm.$emit('updateDeletedAt', userId, new Date())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('marks the user as deleted', () => {
|
it('marks the user as deleted', () => {
|
||||||
expect(wrapper.vm.searchResult.find((obj) => obj.userId === 4).deletedAt).toEqual(now)
|
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).deletedAt).toEqual(
|
||||||
|
expect.any(Date),
|
||||||
|
)
|
||||||
|
expect(wrapper.find('.test-deleted-icon').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts a success message', () => {
|
it('toasts a success message', () => {
|
||||||
|
|||||||
@ -42,6 +42,7 @@
|
|||||||
type="PageUserSearch"
|
type="PageUserSearch"
|
||||||
:items="searchResult"
|
:items="searchResult"
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
|
@updateIsAdmin="updateIsAdmin"
|
||||||
@updateDeletedAt="updateDeletedAt"
|
@updateDeletedAt="updateDeletedAt"
|
||||||
/>
|
/>
|
||||||
<b-pagination
|
<b-pagination
|
||||||
@ -111,6 +112,9 @@ export default {
|
|||||||
this.toastError(error.message)
|
this.toastError(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
updateIsAdmin(userId, isAdmin) {
|
||||||
|
this.searchResult.find((obj) => obj.userId === userId).isAdmin = isAdmin
|
||||||
|
},
|
||||||
updateDeletedAt(userId, deletedAt) {
|
updateDeletedAt(userId, deletedAt) {
|
||||||
this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
|
this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
|
||||||
this.toastSuccess(deletedAt ? this.$t('user_deleted') : this.$t('user_recovered'))
|
this.toastSuccess(deletedAt ? this.$t('user_deleted') : this.$t('user_recovered'))
|
||||||
|
|||||||
@ -27,6 +27,9 @@ export enum RIGHTS {
|
|||||||
GDT_BALANCE = 'GDT_BALANCE',
|
GDT_BALANCE = 'GDT_BALANCE',
|
||||||
// Admin
|
// Admin
|
||||||
SEARCH_USERS = 'SEARCH_USERS',
|
SEARCH_USERS = 'SEARCH_USERS',
|
||||||
|
SET_USER_ROLE = 'SET_USER_ROLE',
|
||||||
|
DELETE_USER = 'DELETE_USER',
|
||||||
|
UNDELETE_USER = 'UNDELETE_USER',
|
||||||
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
|
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
|
||||||
ADMIN_CREATE_CONTRIBUTIONS = 'ADMIN_CREATE_CONTRIBUTIONS',
|
ADMIN_CREATE_CONTRIBUTIONS = 'ADMIN_CREATE_CONTRIBUTIONS',
|
||||||
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
|
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
|
||||||
@ -34,8 +37,6 @@ export enum RIGHTS {
|
|||||||
LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
|
LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
|
||||||
CONFIRM_CONTRIBUTION = 'CONFIRM_CONTRIBUTION',
|
CONFIRM_CONTRIBUTION = 'CONFIRM_CONTRIBUTION',
|
||||||
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
||||||
DELETE_USER = 'DELETE_USER',
|
|
||||||
UNDELETE_USER = 'UNDELETE_USER',
|
|
||||||
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
|
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
|
||||||
LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
|
LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
|
||||||
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
|
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export class UserAdmin {
|
|||||||
this.hasElopage = hasElopage
|
this.hasElopage = hasElopage
|
||||||
this.deletedAt = user.deletedAt
|
this.deletedAt = user.deletedAt
|
||||||
this.emailConfirmationSend = emailConfirmationSend
|
this.emailConfirmationSend = emailConfirmationSend
|
||||||
|
this.isAdmin = user.isAdmin
|
||||||
}
|
}
|
||||||
|
|
||||||
@Field(() => Number)
|
@Field(() => Number)
|
||||||
@ -42,6 +43,9 @@ export class UserAdmin {
|
|||||||
|
|
||||||
@Field(() => String, { nullable: true })
|
@Field(() => String, { nullable: true })
|
||||||
emailConfirmationSend?: string
|
emailConfirmationSend?: string
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
isAdmin: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { peterLustig } from '@/seeds/users/peter-lustig'
|
|||||||
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
||||||
import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
|
import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
|
||||||
import {
|
import {
|
||||||
|
setUserRole,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
unDeleteUser,
|
unDeleteUser,
|
||||||
adminCreateContribution,
|
adminCreateContribution,
|
||||||
@ -69,6 +70,161 @@ let user: User
|
|||||||
let creation: Contribution | void
|
let creation: Contribution | void
|
||||||
|
|
||||||
describe('AdminResolver', () => {
|
describe('AdminResolver', () => {
|
||||||
|
describe('set user role', () => {
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: 1, isAdmin: true } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authenticated', () => {
|
||||||
|
describe('without admin rights', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
user = await userFactory(testEnv, bibiBloxberg)
|
||||||
|
await query({
|
||||||
|
query: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await cleanDB()
|
||||||
|
resetToken()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: user.id + 1, isAdmin: true } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with admin rights', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
admin = await userFactory(testEnv, peterLustig)
|
||||||
|
await query({
|
||||||
|
query: login,
|
||||||
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await cleanDB()
|
||||||
|
resetToken()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('user to get a new role does not exist', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: admin.id + 1, isAdmin: true } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError(`Could not find user with userId: ${admin.id + 1}`)],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('change role with success', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
user = await userFactory(testEnv, bibiBloxberg)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('user gets new role', () => {
|
||||||
|
describe('to admin', () => {
|
||||||
|
it('returns date string', async () => {
|
||||||
|
const result = await mutate({
|
||||||
|
mutation: setUserRole,
|
||||||
|
variables: { userId: user.id, isAdmin: true },
|
||||||
|
})
|
||||||
|
expect(result).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
setUserRole: expect.any(String),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
expect(new Date(result.data.setUserRole)).toEqual(expect.any(Date))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('to usual user', () => {
|
||||||
|
it('returns null', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: user.id, isAdmin: false } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
setUserRole: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('change role with error', () => {
|
||||||
|
describe('is own role', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: admin.id, isAdmin: false } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('Administrator can not change his own role!')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('user has already role to be set', () => {
|
||||||
|
describe('to admin', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: setUserRole,
|
||||||
|
variables: { userId: user.id, isAdmin: true },
|
||||||
|
})
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: user.id, isAdmin: true } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('User is already admin!')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('to usual user', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: setUserRole,
|
||||||
|
variables: { userId: user.id, isAdmin: false },
|
||||||
|
})
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: setUserRole, variables: { userId: user.id, isAdmin: false } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('User is already a usual user!')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('delete user', () => {
|
describe('delete user', () => {
|
||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
|
|||||||
@ -73,7 +73,15 @@ export class AdminResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked', 'deletedAt']
|
const userFields = [
|
||||||
|
'id',
|
||||||
|
'firstName',
|
||||||
|
'lastName',
|
||||||
|
'email',
|
||||||
|
'emailChecked',
|
||||||
|
'deletedAt',
|
||||||
|
'isAdmin',
|
||||||
|
]
|
||||||
const [users, count] = await userRepository.findBySearchCriteriaPagedFiltered(
|
const [users, count] = await userRepository.findBySearchCriteriaPagedFiltered(
|
||||||
userFields.map((fieldName) => {
|
userFields.map((fieldName) => {
|
||||||
return 'user.' + fieldName
|
return 'user.' + fieldName
|
||||||
@ -133,6 +141,48 @@ export class AdminResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorized([RIGHTS.SET_USER_ROLE])
|
||||||
|
@Mutation(() => Date, { nullable: true })
|
||||||
|
async setUserRole(
|
||||||
|
@Arg('userId', () => Int)
|
||||||
|
userId: number,
|
||||||
|
@Arg('isAdmin', () => Boolean)
|
||||||
|
isAdmin: boolean,
|
||||||
|
@Ctx()
|
||||||
|
context: Context,
|
||||||
|
): Promise<Date | null> {
|
||||||
|
const user = await dbUser.findOne({ id: userId })
|
||||||
|
// user exists ?
|
||||||
|
if (!user) {
|
||||||
|
throw new Error(`Could not find user with userId: ${userId}`)
|
||||||
|
}
|
||||||
|
// administrator user changes own role?
|
||||||
|
const moderatorUser = getUser(context)
|
||||||
|
if (moderatorUser.id === userId) {
|
||||||
|
throw new Error('Administrator can not change his own role!')
|
||||||
|
}
|
||||||
|
// change isAdmin
|
||||||
|
switch (user.isAdmin) {
|
||||||
|
case null:
|
||||||
|
if (isAdmin === true) {
|
||||||
|
user.isAdmin = new Date()
|
||||||
|
} else {
|
||||||
|
throw new Error('User is already a usual user!')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (isAdmin === false) {
|
||||||
|
user.isAdmin = null
|
||||||
|
} else {
|
||||||
|
throw new Error('User is already admin!')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await user.save()
|
||||||
|
const newUser = await dbUser.findOne({ id: userId })
|
||||||
|
return newUser ? newUser.isAdmin : null
|
||||||
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.DELETE_USER])
|
@Authorized([RIGHTS.DELETE_USER])
|
||||||
@Mutation(() => Date, { nullable: true })
|
@Mutation(() => Date, { nullable: true })
|
||||||
async deleteUser(
|
async deleteUser(
|
||||||
|
|||||||
@ -98,6 +98,12 @@ export const confirmContribution = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const setUserRole = gql`
|
||||||
|
mutation ($userId: Int!, $isAdmin: Boolean!) {
|
||||||
|
setUserRole(userId: $userId, isAdmin: $isAdmin)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export const deleteUser = gql`
|
export const deleteUser = gql`
|
||||||
mutation ($userId: Int!) {
|
mutation ($userId: Int!) {
|
||||||
deleteUser(userId: $userId)
|
deleteUser(userId: $userId)
|
||||||
|
|||||||
@ -110,6 +110,7 @@ export const searchUsers = gql`
|
|||||||
hasElopage
|
hasElopage
|
||||||
emailConfirmationSend
|
emailConfirmationSend
|
||||||
deletedAt
|
deletedAt
|
||||||
|
isAdmin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user