mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into combine_transaction_tables2
This commit is contained in:
commit
4ada6ea182
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -422,7 +422,7 @@ jobs:
|
||||
report_name: Coverage Admin Interface
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
min_coverage: 94
|
||||
min_coverage: 95
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
|
||||
BIN
admin/public/img/elopage_favicon.png
Normal file
BIN
admin/public/img/elopage_favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
262
admin/src/components/DeletedUserFormular.spec.js
Normal file
262
admin/src/components/DeletedUserFormular.spec.js
Normal file
@ -0,0 +1,262 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import DeletedUserFormular from './DeletedUserFormular.vue'
|
||||
import { deleteUser } from '../graphql/deleteUser'
|
||||
import { unDeleteUser } from '../graphql/unDeleteUser'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const date = new Date()
|
||||
|
||||
const apolloMutateMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
deleteUser: date,
|
||||
},
|
||||
})
|
||||
|
||||
const toastedErrorMock = jest.fn()
|
||||
const toastedSuccessMock = jest.fn()
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$apollo: {
|
||||
mutate: apolloMutateMock,
|
||||
},
|
||||
$store: {
|
||||
state: {
|
||||
moderator: {
|
||||
id: 0,
|
||||
name: 'test moderator',
|
||||
},
|
||||
},
|
||||
},
|
||||
$toasted: {
|
||||
error: toastedErrorMock,
|
||||
success: toastedSuccessMock,
|
||||
},
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
item: {},
|
||||
}
|
||||
|
||||
describe('DeletedUserFormular', () => {
|
||||
let wrapper
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(DeletedUserFormular, { localVue, mocks, propsData })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('has a DIV element with the class.delete-user-formular', () => {
|
||||
expect(wrapper.find('.deleted-user-formular').exists()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe('delete self', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.setProps({
|
||||
item: {
|
||||
userId: 0,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('shows a text that you cannot delete yourself', () => {
|
||||
expect(wrapper.text()).toBe('removeNotSelf')
|
||||
})
|
||||
})
|
||||
|
||||
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('toasts a success message', () => {
|
||||
expect(toastedSuccessMock).toBeCalledWith('user_deleted')
|
||||
})
|
||||
|
||||
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(toastedErrorMock).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', () => {
|
||||
expect(wrapper.find('button').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
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('toasts a success message', () => {
|
||||
expect(toastedSuccessMock).toBeCalledWith('user_recovered')
|
||||
})
|
||||
|
||||
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(toastedErrorMock).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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
86
admin/src/components/DeletedUserFormular.vue
Normal file
86
admin/src/components/DeletedUserFormular.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="deleted-user-formular">
|
||||
<div v-if="item.userId === $store.state.moderator.id" class="mt-5 mb-5">
|
||||
{{ $t('removeNotSelf') }}
|
||||
</div>
|
||||
<div v-else class="mt-5">
|
||||
<b-form-checkbox switch size="lg" v-model="checked">
|
||||
<div>{{ item.deletedAt ? $t('undelete_user') : $t('delete_user') }}</div>
|
||||
</b-form-checkbox>
|
||||
|
||||
<div class="mt-3 mb-5">
|
||||
<b-button v-if="checked && item.deletedAt === null" variant="danger" @click="deleteUser">
|
||||
{{ $t('delete_user') }}
|
||||
</b-button>
|
||||
<b-button v-if="checked && item.deletedAt !== null" variant="success" @click="unDeleteUser">
|
||||
{{ $t('undelete_user') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { deleteUser } from '../graphql/deleteUser'
|
||||
import { unDeleteUser } from '../graphql/unDeleteUser'
|
||||
|
||||
export default {
|
||||
name: 'DeletedUser',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checked: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteUser() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: deleteUser,
|
||||
variables: {
|
||||
userId: this.item.userId,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
this.$toasted.success(this.$t('user_deleted'))
|
||||
this.$emit('updateDeletedAt', {
|
||||
userId: this.item.userId,
|
||||
deletedAt: result.data.deleteUser,
|
||||
})
|
||||
this.checked = false
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toasted.error(error.message)
|
||||
})
|
||||
},
|
||||
unDeleteUser() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: unDeleteUser,
|
||||
variables: {
|
||||
userId: this.item.userId,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
this.$toasted.success(this.$t('user_recovered'))
|
||||
this.$emit('updateDeletedAt', {
|
||||
userId: this.item.userId,
|
||||
deletedAt: result.data.unDeleteUser,
|
||||
})
|
||||
this.checked = false
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toasted.error(error.message)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.input-group-text {
|
||||
background-color: rgb(255, 252, 205);
|
||||
}
|
||||
</style>
|
||||
@ -1,10 +1,7 @@
|
||||
<template>
|
||||
<b-card class="shadow-lg pl-3 pr-3 mb-5 bg-white rounded">
|
||||
<b-row class="mb-2">
|
||||
<b-col></b-col>
|
||||
</b-row>
|
||||
<slot :name="slotName" />
|
||||
<b-button size="sm" @click="$emit('row-toogle-details', row, index)">
|
||||
<b-button size="sm" @click="$emit('row-toggle-details', row, index)">
|
||||
<b-icon
|
||||
:icon="type === 'PageCreationConfirm' ? 'x' : 'eye-slash-fill'"
|
||||
aria-label="Help"
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
</b-button>
|
||||
</template>
|
||||
<template #cell(edit_creation)="row">
|
||||
<b-button variant="info" size="md" @click="rowToogleDetails(row, 0)" class="mr-2">
|
||||
<b-button variant="info" size="md" @click="rowToggleDetails(row, 0)" class="mr-2">
|
||||
<b-icon :icon="row.detailsShowing ? 'x' : 'pencil-square'" aria-label="Help"></b-icon>
|
||||
</b-button>
|
||||
</template>
|
||||
@ -27,7 +27,7 @@
|
||||
type="show-creation"
|
||||
slotName="show-creation"
|
||||
:index="0"
|
||||
@row-toogle-details="rowToogleDetails"
|
||||
@row-toggle-details="rowToggleDetails"
|
||||
>
|
||||
<template #show-creation>
|
||||
<div>
|
||||
|
||||
129
admin/src/components/Tables/SearchUserTable.spec.js
Normal file
129
admin/src/components/Tables/SearchUserTable.spec.js
Normal file
@ -0,0 +1,129 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import SearchUserTable from './SearchUserTable.vue'
|
||||
|
||||
const date = new Date()
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const apolloMutateMock = jest.fn().mockResolvedValue({})
|
||||
const apolloQueryMock = jest.fn().mockResolvedValue({})
|
||||
|
||||
const propsData = {
|
||||
items: [
|
||||
{
|
||||
userId: 1,
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
email: 'bibi@bloxberg.de',
|
||||
creation: [200, 400, 600],
|
||||
emailChecked: true,
|
||||
},
|
||||
{
|
||||
userId: 2,
|
||||
firstName: 'Benjamin',
|
||||
lastName: 'Blümchen',
|
||||
email: 'benjamin@bluemchen.de',
|
||||
creation: [1000, 1000, 1000],
|
||||
emailChecked: true,
|
||||
},
|
||||
{
|
||||
userId: 3,
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
creation: [0, 0, 0],
|
||||
emailChecked: true,
|
||||
},
|
||||
{
|
||||
userId: 4,
|
||||
firstName: 'New',
|
||||
lastName: 'User',
|
||||
email: 'new@user.ch',
|
||||
creation: [1000, 1000, 1000],
|
||||
emailChecked: false,
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{ key: 'email', label: 'e_mail' },
|
||||
{ key: 'firstName', label: 'firstname' },
|
||||
{ key: 'lastName', label: 'lastname' },
|
||||
{
|
||||
key: 'creation',
|
||||
label: 'creationLabel',
|
||||
formatter: (value, key, item) => {
|
||||
return value.join(' | ')
|
||||
},
|
||||
},
|
||||
{ key: 'status', label: 'status' },
|
||||
],
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$d: jest.fn((d) => d),
|
||||
$apollo: {
|
||||
mutate: apolloMutateMock,
|
||||
query: apolloQueryMock,
|
||||
},
|
||||
$store: {
|
||||
state: {
|
||||
moderator: {
|
||||
id: 0,
|
||||
name: 'test moderator',
|
||||
},
|
||||
},
|
||||
},
|
||||
$toasted: {
|
||||
error: jest.fn(),
|
||||
success: jest.fn(),
|
||||
},
|
||||
}
|
||||
|
||||
describe('SearchUserTable', () => {
|
||||
let wrapper
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(SearchUserTable, { localVue, mocks, propsData })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('has a table with four rows', () => {
|
||||
expect(wrapper.findAll('tbody > tr')).toHaveLength(4)
|
||||
})
|
||||
|
||||
describe('show row details', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.findAll('tbody > tr').at(1).trigger('click')
|
||||
})
|
||||
|
||||
describe('deleted at', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('div.deleted-user-formular').vm.$emit('updateDeletedAt', {
|
||||
userId: 1,
|
||||
deletedAt: date,
|
||||
})
|
||||
})
|
||||
|
||||
it('emits updateDeletedAt', () => {
|
||||
expect(wrapper.emitted('updateDeletedAt')).toEqual([[1, date]])
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateUserData', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper
|
||||
.find('div.component-creation-formular')
|
||||
.vm.$emit('update-user-data', propsData.items[1], [250, 500, 750])
|
||||
})
|
||||
|
||||
it('updates the item', () => {
|
||||
expect(wrapper.vm.items[1].creation).toEqual([250, 500, 750])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,100 +1,97 @@
|
||||
<template>
|
||||
<div class="search-user-table">
|
||||
<b-table-lite :items="items" :fields="fields" caption-top striped hover stacked="md">
|
||||
<b-table
|
||||
tbody-tr-class="pointer"
|
||||
:items="myItems"
|
||||
:fields="fields"
|
||||
caption-top
|
||||
striped
|
||||
hover
|
||||
stacked="md"
|
||||
select-mode="single"
|
||||
selectableonRowSelected
|
||||
@row-clicked="onRowClicked"
|
||||
>
|
||||
<template #cell(creation)="data">
|
||||
<div v-html="data.value"></div>
|
||||
</template>
|
||||
<template #cell(show_details)="row">
|
||||
<b-button
|
||||
variant="info"
|
||||
size="md"
|
||||
v-if="row.item.emailChecked"
|
||||
@click="rowToogleDetails(row, 0)"
|
||||
class="mr-2"
|
||||
>
|
||||
<b-icon :icon="row.detailsShowing ? 'eye-slash-fill' : 'eye-fill'"></b-icon>
|
||||
</b-button>
|
||||
</template>
|
||||
<template #cell(confirm_mail)="row">
|
||||
<b-button
|
||||
:variant="row.item.emailChecked ? 'success' : 'danger'"
|
||||
size="md"
|
||||
@click="rowToogleDetails(row, 1)"
|
||||
class="mr-2"
|
||||
>
|
||||
|
||||
<template #cell(status)="row">
|
||||
<div class="text-right">
|
||||
<b-avatar v-if="row.item.deletedAt" class="mr-3" variant="light">
|
||||
<b-iconstack font-scale="2">
|
||||
<b-icon stacked icon="person" variant="info" scale="0.75"></b-icon>
|
||||
<b-icon stacked icon="slash-circle" variant="danger"></b-icon>
|
||||
</b-iconstack>
|
||||
</b-avatar>
|
||||
<span v-if="!row.item.deletedAt">
|
||||
<b-avatar
|
||||
v-if="!row.item.emailChecked"
|
||||
icon="envelope"
|
||||
class="align-center mr-3"
|
||||
variant="danger"
|
||||
></b-avatar>
|
||||
|
||||
<b-avatar
|
||||
v-if="!row.item.hasElopage"
|
||||
variant="danger"
|
||||
class="mr-3"
|
||||
src="img/elopage_favicon.png"
|
||||
></b-avatar>
|
||||
</span>
|
||||
<b-icon
|
||||
:icon="row.item.emailChecked ? 'envelope-open' : 'envelope'"
|
||||
aria-label="Help"
|
||||
variant="dark"
|
||||
:icon="row.detailsShowing ? 'caret-up-fill' : 'caret-down'"
|
||||
:title="row.item.enabled ? $t('enabled') : $t('deleted')"
|
||||
></b-icon>
|
||||
</b-button>
|
||||
</template>
|
||||
<template #cell(has_elopage)="row">
|
||||
<b-icon
|
||||
:variant="row.item.hasElopage ? 'success' : 'danger'"
|
||||
:icon="row.item.hasElopage ? 'check-circle' : 'x-circle'"
|
||||
></b-icon>
|
||||
</template>
|
||||
<template #cell(transactions_list)="row">
|
||||
<b-button variant="warning" size="md" @click="rowToogleDetails(row, 2)" class="mr-2">
|
||||
<b-icon icon="list"></b-icon>
|
||||
</b-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #row-details="row">
|
||||
<row-details
|
||||
:row="row"
|
||||
type="singleCreation"
|
||||
:slotName="slotName"
|
||||
:index="slotIndex"
|
||||
@row-toogle-details="rowToogleDetails"
|
||||
>
|
||||
<template #show-creation>
|
||||
<div>
|
||||
<creation-formular
|
||||
type="singleCreation"
|
||||
pagetype="singleCreation"
|
||||
:creation="row.item.creation"
|
||||
:item="row.item"
|
||||
:creationUserData="creationUserData"
|
||||
@update-user-data="updateUserData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #show-register-mail>
|
||||
<confirm-register-mail-formular
|
||||
:checked="row.item.emailChecked"
|
||||
:email="row.item.email"
|
||||
:dateLastSend="
|
||||
row.item.emailConfirmationSend
|
||||
? $d(new Date(row.item.emailConfirmationSend), 'long')
|
||||
: ''
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #show-transaction-list>
|
||||
<creation-transaction-list-formular :userId="row.item.userId" />
|
||||
</template>
|
||||
</row-details>
|
||||
<b-card ref="rowDetails" class="shadow-lg pl-3 pr-3 mb-5 bg-white rounded">
|
||||
<creation-formular
|
||||
v-if="!row.item.deletedAt"
|
||||
type="singleCreation"
|
||||
pagetype="singleCreation"
|
||||
:creation="row.item.creation"
|
||||
:item="row.item"
|
||||
:creationUserData="creationUserData"
|
||||
@update-user-data="updateUserData"
|
||||
/>
|
||||
<div v-else>{{ $t('userIsDeleted') }}</div>
|
||||
<confirm-register-mail-formular
|
||||
v-if="!row.item.deletedAt"
|
||||
:checked="row.item.emailChecked"
|
||||
:email="row.item.email"
|
||||
:dateLastSend="
|
||||
row.item.emailConfirmationSend
|
||||
? $d(new Date(row.item.emailConfirmationSend), 'long')
|
||||
: ''
|
||||
"
|
||||
/>
|
||||
<creation-transaction-list-formular
|
||||
v-if="!row.item.deletedAt"
|
||||
:userId="row.item.userId"
|
||||
/>
|
||||
<deleted-user-formular :item="row.item" @updateDeletedAt="updateDeletedAt" />
|
||||
</b-card>
|
||||
</template>
|
||||
</b-table-lite>
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import CreationFormular from '../CreationFormular.vue'
|
||||
import ConfirmRegisterMailFormular from '../ConfirmRegisterMailFormular.vue'
|
||||
import RowDetails from '../RowDetails.vue'
|
||||
import CreationTransactionListFormular from '../CreationTransactionListFormular.vue'
|
||||
import { toggleRowDetails } from '../../mixins/toggleRowDetails'
|
||||
|
||||
const slotNames = ['show-creation', 'show-register-mail', 'show-transaction-list']
|
||||
import DeletedUserFormular from '../DeletedUserFormular.vue'
|
||||
|
||||
export default {
|
||||
name: 'SearchUserTable',
|
||||
mixins: [toggleRowDetails],
|
||||
components: {
|
||||
CreationFormular,
|
||||
ConfirmRegisterMailFormular,
|
||||
CreationTransactionListFormular,
|
||||
RowDetails,
|
||||
DeletedUserFormular,
|
||||
},
|
||||
props: {
|
||||
items: {
|
||||
@ -115,10 +112,29 @@ export default {
|
||||
updateUserData(rowItem, newCreation) {
|
||||
rowItem.creation = newCreation
|
||||
},
|
||||
updateDeletedAt({ userId, deletedAt }) {
|
||||
this.$emit('updateDeletedAt', userId, deletedAt)
|
||||
},
|
||||
async onRowClicked(item) {
|
||||
const status = this.myItems.find((obj) => obj === item)._showDetails
|
||||
this.myItems.forEach((obj) => {
|
||||
if (obj === item) {
|
||||
obj._showDetails = !status
|
||||
} else {
|
||||
obj._showDetails = false
|
||||
}
|
||||
})
|
||||
await this.$nextTick()
|
||||
if (!status && this.$refs.rowDetails) {
|
||||
this.$refs.rowDetails.focus()
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
slotName() {
|
||||
return slotNames[this.slotIndex]
|
||||
myItems() {
|
||||
return this.items.map((item) => {
|
||||
return { ...item, _showDetails: false }
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
7
admin/src/graphql/deleteUser.js
Normal file
7
admin/src/graphql/deleteUser.js
Normal file
@ -0,0 +1,7 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const deleteUser = gql`
|
||||
mutation ($userId: Float!) {
|
||||
deleteUser(userId: $userId)
|
||||
}
|
||||
`
|
||||
@ -1,12 +1,19 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const searchUsers = gql`
|
||||
query ($searchText: String!, $currentPage: Int, $pageSize: Int, $notActivated: Boolean) {
|
||||
query (
|
||||
$searchText: String!
|
||||
$currentPage: Int
|
||||
$pageSize: Int
|
||||
$notActivated: Boolean
|
||||
$isDeleted: Boolean
|
||||
) {
|
||||
searchUsers(
|
||||
searchText: $searchText
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
notActivated: $notActivated
|
||||
isDeleted: $isDeleted
|
||||
) {
|
||||
userCount
|
||||
userList {
|
||||
@ -18,6 +25,7 @@ export const searchUsers = gql`
|
||||
emailChecked
|
||||
hasElopage
|
||||
emailConfirmationSend
|
||||
deletedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
admin/src/graphql/unDeleteUser.js
Normal file
7
admin/src/graphql/unDeleteUser.js
Normal file
@ -0,0 +1,7 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const unDeleteUser = gql`
|
||||
mutation ($userId: Float!) {
|
||||
unDeleteUser(userId: $userId)
|
||||
}
|
||||
`
|
||||
@ -23,12 +23,15 @@
|
||||
"creation_for_month": "Schöpfung für Monat",
|
||||
"date": "Datum",
|
||||
"delete": "Löschen",
|
||||
"deleted": "gelöscht",
|
||||
"deleted_user": "Alle gelöschten Nutzer",
|
||||
"delete_user": "Nutzer löschen",
|
||||
"details": "Details",
|
||||
"edit": "Bearbeiten",
|
||||
"e_mail": "E-Mail",
|
||||
"firstname": "Vorname",
|
||||
"gradido_admin_footer": "Gradido Akademie Adminkonsole",
|
||||
"hide_details": "Details verbergen von",
|
||||
"hide_details": "Details verbergen",
|
||||
"lastname": "Nachname",
|
||||
"moderator": "Moderator",
|
||||
"multiple_creation_text": "Bitte wähle ein oder mehrere Mitglieder aus für die du Schöpfen möchtest.",
|
||||
@ -61,8 +64,10 @@
|
||||
}
|
||||
},
|
||||
"remove": "Entfernen",
|
||||
"removeNotSelf": "Als Admin / Moderator kannst du dich nicht selber löschen.",
|
||||
"remove_all": "alle Nutzer entfernen",
|
||||
"save": "Speichern",
|
||||
"status": "Status",
|
||||
"text": "Text",
|
||||
"transaction": "Transaktion",
|
||||
"transactionlist": {
|
||||
@ -73,6 +78,7 @@
|
||||
"memo": "Nachricht",
|
||||
"title": "Alle geschöpften Transaktionen für den Nutzer"
|
||||
},
|
||||
"undelete_user": "Nutzer wiederherstellen",
|
||||
"unregistered_emails": "Nur unregistrierte Nutzer",
|
||||
"unregister_mail": {
|
||||
"button": "Registrierungs-Email bestätigen, jetzt senden",
|
||||
@ -83,5 +89,8 @@
|
||||
"text_false": " Die letzte Email wurde am {date} Uhr an das Mitglied ({email}) gesendet.",
|
||||
"text_true": " Die Email wurde bestätigt."
|
||||
},
|
||||
"userIsDeleted": "Der Nutzer ist gelöscht. Es können keine GDD mehr geschöpft werden.",
|
||||
"user_deleted": "Nutzer ist gelöscht.",
|
||||
"user_recovered.": "Nutzer ist wiederhergestellt.",
|
||||
"user_search": "Nutzer-Suche"
|
||||
}
|
||||
|
||||
@ -23,12 +23,15 @@
|
||||
"creation_for_month": "Creation for month",
|
||||
"date": "Date",
|
||||
"delete": "Delete",
|
||||
"deleted": "deleted",
|
||||
"deleted_user": "All deleted user",
|
||||
"delete_user": "Delete user",
|
||||
"details": "Details",
|
||||
"edit": "Edit",
|
||||
"e_mail": "E-mail",
|
||||
"firstname": "Firstname",
|
||||
"gradido_admin_footer": "Gradido Academy Admin Console",
|
||||
"hide_details": "Hide details from",
|
||||
"hide_details": "Hide details",
|
||||
"lastname": "Lastname",
|
||||
"moderator": "Moderator",
|
||||
"multiple_creation_text": "Please select one or more members for which you would like to perform creations.",
|
||||
@ -61,8 +64,10 @@
|
||||
}
|
||||
},
|
||||
"remove": "Remove",
|
||||
"removeNotSelf": "As admin / moderator you cannot delete yourself.",
|
||||
"remove_all": "Remove all users",
|
||||
"save": "Speichern",
|
||||
"status": "Status",
|
||||
"text": "Text",
|
||||
"transaction": "Transaction",
|
||||
"transactionlist": {
|
||||
@ -73,6 +78,7 @@
|
||||
"memo": "Message",
|
||||
"title": "All creation-transactions for the user"
|
||||
},
|
||||
"undelete_user": "Undelete User",
|
||||
"unregistered_emails": "Only unregistered users",
|
||||
"unregister_mail": {
|
||||
"button": "Confirm registration email, send now",
|
||||
@ -83,5 +89,8 @@
|
||||
"text_false": "The last email was sent to the member ({email}) on {date}.",
|
||||
"text_true": "The email was confirmed."
|
||||
},
|
||||
"userIsDeleted": "The user is deleted. No more GDD can be created.",
|
||||
"user_deleted": "User is deleted.",
|
||||
"user_recovered.": "User is recovered.",
|
||||
"user_search": "User search"
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export const toggleRowDetails = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rowToogleDetails(row, index) {
|
||||
rowToggleDetails(row, index) {
|
||||
if (this.openRow) {
|
||||
if (this.openRow.index === row.index) {
|
||||
if (index === this.slotIndex) {
|
||||
|
||||
@ -35,7 +35,7 @@ describe('toggleRowDetails', () => {
|
||||
|
||||
describe('no open row', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.vm.rowToogleDetails(row, 2)
|
||||
wrapper.vm.rowToggleDetails(row, 2)
|
||||
})
|
||||
|
||||
it('calls toggleDetails', () => {
|
||||
@ -70,7 +70,7 @@ describe('toggleRowDetails', () => {
|
||||
describe('row index is open row index', () => {
|
||||
describe('index is slot index', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.vm.rowToogleDetails(row, 0)
|
||||
wrapper.vm.rowToggleDetails(row, 0)
|
||||
})
|
||||
|
||||
it('calls toggleDetails', () => {
|
||||
@ -84,7 +84,7 @@ describe('toggleRowDetails', () => {
|
||||
|
||||
describe('index is not slot index', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.vm.rowToogleDetails(row, 2)
|
||||
wrapper.vm.rowToggleDetails(row, 2)
|
||||
})
|
||||
|
||||
it('does not call toggleDetails', () => {
|
||||
@ -99,7 +99,7 @@ describe('toggleRowDetails', () => {
|
||||
|
||||
describe('row index is not open row index', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.vm.rowToogleDetails(
|
||||
wrapper.vm.rowToggleDetails(
|
||||
{
|
||||
toggleDetails: secondToggleDetailsMock,
|
||||
index: 2,
|
||||
|
||||
@ -83,6 +83,7 @@ describe('UserSearch', () => {
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
notActivated: false,
|
||||
isDeleted: false,
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -90,7 +91,7 @@ describe('UserSearch', () => {
|
||||
|
||||
describe('unconfirmed emails', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('button.btn-block').trigger('click')
|
||||
await wrapper.find('button.unconfirmedRegisterMails').trigger('click')
|
||||
})
|
||||
|
||||
it('calls API with filter', () => {
|
||||
@ -101,6 +102,27 @@ describe('UserSearch', () => {
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
notActivated: true,
|
||||
isDeleted: false,
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleted Users', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('button.deletedUserSearch').trigger('click')
|
||||
})
|
||||
|
||||
it('calls API with filter', () => {
|
||||
expect(apolloQueryMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
searchText: '',
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
notActivated: false,
|
||||
isDeleted: true,
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -120,6 +142,7 @@ describe('UserSearch', () => {
|
||||
currentPage: 2,
|
||||
pageSize: 25,
|
||||
notActivated: false,
|
||||
isDeleted: false,
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -139,6 +162,7 @@ describe('UserSearch', () => {
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
notActivated: false,
|
||||
isDeleted: false,
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -155,6 +179,7 @@ describe('UserSearch', () => {
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
notActivated: false,
|
||||
isDeleted: false,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
<template>
|
||||
<div class="user-search">
|
||||
<div style="text-align: right">
|
||||
<b-button block variant="danger" @click="unconfirmedRegisterMails">
|
||||
<b-icon icon="envelope" variant="light"></b-icon>
|
||||
<b-button class="unconfirmedRegisterMails" variant="light" @click="unconfirmedRegisterMails">
|
||||
<b-icon icon="envelope" variant="danger"></b-icon>
|
||||
{{ filterCheckedEmails ? $t('all_emails') : $t('unregistered_emails') }}
|
||||
</b-button>
|
||||
<b-button class="deletedUserSearch" variant="light" @click="deletedUserSearch">
|
||||
<b-icon icon="x-circle" variant="danger"></b-icon>
|
||||
{{ filterDeletedUser ? $t('all_emails') : $t('deleted_user') }}
|
||||
</b-button>
|
||||
</div>
|
||||
<label>{{ $t('user_search') }}</label>
|
||||
<div>
|
||||
@ -22,7 +26,12 @@
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</div>
|
||||
<search-user-table type="PageUserSearch" :items="searchResult" :fields="fields" />
|
||||
<search-user-table
|
||||
type="PageUserSearch"
|
||||
:items="searchResult"
|
||||
:fields="fields"
|
||||
@updateDeletedAt="updateDeletedAt"
|
||||
/>
|
||||
<b-pagination
|
||||
pills
|
||||
size="lg"
|
||||
@ -52,6 +61,7 @@ export default {
|
||||
massCreation: [],
|
||||
criteria: '',
|
||||
filterCheckedEmails: false,
|
||||
filterDeletedUser: false,
|
||||
rows: 0,
|
||||
currentPage: 1,
|
||||
perPage: 25,
|
||||
@ -63,6 +73,10 @@ export default {
|
||||
this.filterCheckedEmails = !this.filterCheckedEmails
|
||||
this.getUsers()
|
||||
},
|
||||
deletedUserSearch() {
|
||||
this.filterDeletedUser = !this.filterDeletedUser
|
||||
this.getUsers()
|
||||
},
|
||||
getUsers() {
|
||||
this.$apollo
|
||||
.query({
|
||||
@ -72,6 +86,7 @@ export default {
|
||||
currentPage: this.currentPage,
|
||||
pageSize: this.perPage,
|
||||
notActivated: this.filterCheckedEmails,
|
||||
isDeleted: this.filterDeletedUser,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
@ -82,6 +97,9 @@ export default {
|
||||
this.$toasted.error(error.message)
|
||||
})
|
||||
},
|
||||
updateDeletedAt(userId, deletedAt) {
|
||||
this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
currentPage() {
|
||||
@ -104,10 +122,11 @@ export default {
|
||||
return value.join(' | ')
|
||||
},
|
||||
},
|
||||
{ key: 'show_details', label: this.$t('details') },
|
||||
{ key: 'confirm_mail', label: this.$t('confirmed') },
|
||||
{ key: 'has_elopage', label: 'elopage' },
|
||||
{ key: 'transactions_list', label: this.$t('transaction') },
|
||||
// { key: 'show_details', label: this.$t('details') },
|
||||
// { key: 'confirm_mail', label: this.$t('confirmed') },
|
||||
// { key: 'has_elopage', label: 'elopage' },
|
||||
// { key: 'transactions_list', label: this.$t('transaction') },
|
||||
{ key: 'status', label: this.$t('status') },
|
||||
]
|
||||
},
|
||||
},
|
||||
|
||||
@ -26,4 +26,6 @@ export enum RIGHTS {
|
||||
DELETE_PENDING_CREATION = 'DELETE_PENDING_CREATION',
|
||||
CONFIRM_PENDING_CREATION = 'CONFIRM_PENDING_CREATION',
|
||||
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
||||
DELETE_USER = 'DELETE_USER',
|
||||
UNDELETE_USER = 'UNDELETE_USER',
|
||||
}
|
||||
|
||||
@ -13,4 +13,7 @@ export default class SearchUsersArgs {
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
notActivated?: boolean
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
isDeleted?: boolean
|
||||
}
|
||||
|
||||
@ -1,7 +1,20 @@
|
||||
import { User } from '@entity/User'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class UserAdmin {
|
||||
constructor(user: User, creation: number[], hasElopage: boolean, emailConfirmationSend: string) {
|
||||
this.userId = user.id
|
||||
this.email = user.email
|
||||
this.firstName = user.firstName
|
||||
this.lastName = user.lastName
|
||||
this.creation = creation
|
||||
this.emailChecked = user.emailChecked
|
||||
this.hasElopage = hasElopage
|
||||
this.deletedAt = user.deletedAt
|
||||
this.emailConfirmationSend = emailConfirmationSend
|
||||
}
|
||||
|
||||
@Field(() => Number)
|
||||
userId: number
|
||||
|
||||
@ -23,6 +36,9 @@ export class UserAdmin {
|
||||
@Field(() => Boolean)
|
||||
hasElopage: boolean
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
deletedAt?: Date | null
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
emailConfirmationSend?: string
|
||||
}
|
||||
|
||||
@ -2,7 +2,14 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx } from 'type-graphql'
|
||||
import { getCustomRepository, ObjectLiteral, getConnection, In } from '@dbTools/typeorm'
|
||||
import {
|
||||
getCustomRepository,
|
||||
IsNull,
|
||||
Not,
|
||||
ObjectLiteral,
|
||||
getConnection,
|
||||
In,
|
||||
} from '@dbTools/typeorm'
|
||||
import { UserAdmin, SearchUsersResult } from '../model/UserAdmin'
|
||||
import { PendingCreation } from '../model/PendingCreation'
|
||||
import { CreatePendingCreations } from '../model/CreatePendingCreations'
|
||||
@ -31,7 +38,14 @@ export class AdminResolver {
|
||||
@Authorized([RIGHTS.SEARCH_USERS])
|
||||
@Query(() => SearchUsersResult)
|
||||
async searchUsers(
|
||||
@Args() { searchText, currentPage = 1, pageSize = 25, notActivated = false }: SearchUsersArgs,
|
||||
@Args()
|
||||
{
|
||||
searchText,
|
||||
currentPage = 1,
|
||||
pageSize = 25,
|
||||
notActivated = false,
|
||||
isDeleted = false,
|
||||
}: SearchUsersArgs,
|
||||
): Promise<SearchUsersResult> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
|
||||
@ -40,7 +54,11 @@ export class AdminResolver {
|
||||
filterCriteria.push({ emailChecked: false })
|
||||
}
|
||||
|
||||
const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked']
|
||||
if (isDeleted) {
|
||||
filterCriteria.push({ deletedAt: Not(IsNull()) })
|
||||
}
|
||||
|
||||
const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked', 'deletedAt']
|
||||
const [users, count] = await userRepository.findBySearchCriteriaPagedFiltered(
|
||||
userFields.map((fieldName) => {
|
||||
return 'user.' + fieldName
|
||||
@ -51,19 +69,18 @@ export class AdminResolver {
|
||||
pageSize,
|
||||
)
|
||||
|
||||
if (users.length === 0) {
|
||||
return {
|
||||
userCount: 0,
|
||||
userList: [],
|
||||
}
|
||||
}
|
||||
|
||||
const creations = await getUserCreations(users.map((u) => u.id))
|
||||
|
||||
const adminUsers = await Promise.all(
|
||||
users.map(async (user) => {
|
||||
const adminUser = new UserAdmin()
|
||||
adminUser.userId = user.id
|
||||
adminUser.firstName = user.firstName
|
||||
adminUser.lastName = user.lastName
|
||||
adminUser.email = user.email
|
||||
const userCreations = creations.find((c) => c.id === user.id)
|
||||
adminUser.creation = userCreations ? userCreations.creations : [1000, 1000, 1000]
|
||||
adminUser.emailChecked = user.emailChecked
|
||||
adminUser.hasElopage = await hasElopageBuys(user.email)
|
||||
let emailConfirmationSend = ''
|
||||
if (!user.emailChecked) {
|
||||
const emailOptIn = await LoginEmailOptIn.findOne(
|
||||
{
|
||||
@ -79,12 +96,19 @@ export class AdminResolver {
|
||||
)
|
||||
if (emailOptIn) {
|
||||
if (emailOptIn.updatedAt) {
|
||||
adminUser.emailConfirmationSend = emailOptIn.updatedAt.toISOString()
|
||||
emailConfirmationSend = emailOptIn.updatedAt.toISOString()
|
||||
} else {
|
||||
adminUser.emailConfirmationSend = emailOptIn.createdAt.toISOString()
|
||||
emailConfirmationSend = emailOptIn.createdAt.toISOString()
|
||||
}
|
||||
}
|
||||
}
|
||||
const userCreations = creations.find((c) => c.id === user.id)
|
||||
const adminUser = new UserAdmin(
|
||||
user,
|
||||
userCreations ? userCreations.creations : [1000, 1000, 1000],
|
||||
await hasElopageBuys(user.email),
|
||||
emailConfirmationSend,
|
||||
)
|
||||
return adminUser
|
||||
}),
|
||||
)
|
||||
@ -94,6 +118,39 @@ export class AdminResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.DELETE_USER])
|
||||
@Mutation(() => Date, { nullable: true })
|
||||
async deleteUser(@Arg('userId') userId: number, @Ctx() context: any): Promise<Date | null> {
|
||||
const user = await User.findOne({ id: userId })
|
||||
// user exists ?
|
||||
if (!user) {
|
||||
throw new Error(`Could not find user with userId: ${userId}`)
|
||||
}
|
||||
// moderator user disabled own account?
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const moderatorUser = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
if (moderatorUser.id === userId) {
|
||||
throw new Error('Moderator can not delete his own account!')
|
||||
}
|
||||
// soft-delete user
|
||||
await user.softRemove()
|
||||
const newUser = await User.findOne({ id: userId }, { withDeleted: true })
|
||||
return newUser ? newUser.deletedAt : null
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.UNDELETE_USER])
|
||||
@Mutation(() => Date, { nullable: true })
|
||||
async unDeleteUser(@Arg('userId') userId: number): Promise<Date | null> {
|
||||
const user = await User.findOne({ id: userId }, { withDeleted: true })
|
||||
// user exists ?
|
||||
if (!user) {
|
||||
throw new Error(`Could not find user with userId: ${userId}`)
|
||||
}
|
||||
// recover user account
|
||||
await user.recover()
|
||||
return null
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.CREATE_PENDING_CREATION])
|
||||
@Mutation(() => [Number])
|
||||
async createPendingCreation(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/* eslint-disable new-cap */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { Resolver, Query, Args, Authorized, Ctx, Mutation } from 'type-graphql'
|
||||
import { getCustomRepository, getConnection, QueryRunner } from '@dbTools/typeorm'
|
||||
|
||||
@ -252,7 +252,7 @@ export class UserResolver {
|
||||
throw new Error('No user with this credentials')
|
||||
})
|
||||
if (dbUser.deletedAt) {
|
||||
throw new Error('This user was permanently disabled. Contact support for questions.')
|
||||
throw new Error('This user was permanently deleted. Contact support for questions.')
|
||||
}
|
||||
if (!dbUser.emailChecked) {
|
||||
throw new Error('User email not validated')
|
||||
|
||||
@ -24,7 +24,7 @@ export class UserRepository extends Repository<User> {
|
||||
currentPage: number,
|
||||
pageSize: number,
|
||||
): Promise<[User[], number]> {
|
||||
return await this.createQueryBuilder('user')
|
||||
const query = await this.createQueryBuilder('user')
|
||||
.select(select)
|
||||
.withDeleted()
|
||||
.where(
|
||||
@ -39,7 +39,10 @@ export class UserRepository extends Repository<User> {
|
||||
)
|
||||
}),
|
||||
)
|
||||
.andWhere(filterCriteria)
|
||||
filterCriteria.forEach((filter) => {
|
||||
query.andWhere(filter)
|
||||
})
|
||||
return query
|
||||
.take(pageSize)
|
||||
.skip((currentPage - 1) * pageSize)
|
||||
.getManyAndCount()
|
||||
|
||||
@ -215,6 +215,7 @@
|
||||
"gdt-text": "GradidoTransform Transaktionen",
|
||||
"more": "mehr",
|
||||
"nullTransactions": "Du hast noch keine Transaktionen auf deinem Konto.",
|
||||
"receiverDeleted": "Das Empfängerkonto wurde gelöscht",
|
||||
"receiverNotFound": "Empfänger nicht gefunden",
|
||||
"show_all": "Alle <strong>{count}</strong> Transaktionen ansehen"
|
||||
},
|
||||
|
||||
@ -215,6 +215,7 @@
|
||||
"gdt-text": "GradidoTransform Transactions",
|
||||
"more": "more",
|
||||
"nullTransactions": "You don't have any transactions on your account yet.",
|
||||
"receiverDeleted": "The recipient account was deleted",
|
||||
"receiverNotFound": "Recipient not found",
|
||||
"show_all": "View all <strong>{count}</strong> transactions."
|
||||
},
|
||||
|
||||
@ -13,6 +13,12 @@
|
||||
<div class="test-receiver-not-found" v-if="errorResult === 'recipient not known'">
|
||||
{{ $t('transaction.receiverNotFound') }}
|
||||
</div>
|
||||
<div
|
||||
class="test-receiver-not-found"
|
||||
v-if="errorResult === 'GraphQL error: The recipient account was deleted'"
|
||||
>
|
||||
{{ $t('transaction.receiverDeleted') }}
|
||||
</div>
|
||||
<div v-else>({{ errorResult }})</div>
|
||||
</div>
|
||||
<p class="text-center mt-3">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user