mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge branch 'master' into federation-fix-database-public-key-length
This commit is contained in:
commit
4a9568a99d
37
admin/src/components/UserQuery.vue
Normal file
37
admin/src/components/UserQuery.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-input-group>
|
||||
<b-form-input
|
||||
type="text"
|
||||
class="test-input-criteria"
|
||||
v-model="currentValue"
|
||||
:placeholder="$t('user_search')"
|
||||
></b-form-input>
|
||||
<b-input-group-append class="test-click-clear-criteria" @click="currentValue = ''">
|
||||
<b-input-group-text class="pointer">
|
||||
<b-icon icon="x" />
|
||||
</b-input-group-text>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'UserQuery',
|
||||
props: {
|
||||
value: { type: String, default: '' },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentValue: this.value,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
currentValue() {
|
||||
if (this.value !== this.currentValue) {
|
||||
this.$emit('input', this.currentValue)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -7,6 +7,7 @@ export const adminListContributions = gql`
|
||||
$order: Order = DESC
|
||||
$statusFilter: [ContributionStatus!]
|
||||
$userId: Int
|
||||
$query: String
|
||||
) {
|
||||
adminListContributions(
|
||||
currentPage: $currentPage
|
||||
@ -14,6 +15,7 @@ export const adminListContributions = gql`
|
||||
order: $order
|
||||
statusFilter: $statusFilter
|
||||
userId: $userId
|
||||
query: $query
|
||||
) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
|
||||
@ -341,6 +341,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['CONFIRMED'],
|
||||
})
|
||||
})
|
||||
@ -356,6 +357,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['IN_PROGRESS', 'PENDING'],
|
||||
})
|
||||
})
|
||||
@ -372,6 +374,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['DENIED'],
|
||||
})
|
||||
})
|
||||
@ -388,6 +391,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['DELETED'],
|
||||
})
|
||||
})
|
||||
@ -404,6 +408,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['IN_PROGRESS', 'PENDING', 'CONFIRMED', 'DENIED', 'DELETED'],
|
||||
})
|
||||
})
|
||||
@ -424,6 +429,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 2,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['IN_PROGRESS', 'PENDING', 'CONFIRMED', 'DENIED', 'DELETED'],
|
||||
})
|
||||
})
|
||||
@ -439,6 +445,7 @@ describe('CreationConfirm', () => {
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['IN_PROGRESS', 'PENDING'],
|
||||
})
|
||||
})
|
||||
@ -449,6 +456,40 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('user query', () => {
|
||||
describe('with user query', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.findComponent({ name: 'UserQuery' }).vm.$emit('input', 'query')
|
||||
})
|
||||
|
||||
it('calls the API with query', () => {
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: 'query',
|
||||
statusFilter: ['IN_PROGRESS', 'PENDING'],
|
||||
})
|
||||
})
|
||||
|
||||
describe('reset query', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.findComponent({ name: 'UserQuery' }).vm.$emit('input', '')
|
||||
})
|
||||
|
||||
it('calls the API with empty query', () => {
|
||||
expect(adminListContributionsMock).toBeCalledWith({
|
||||
currentPage: 1,
|
||||
order: 'DESC',
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
statusFilter: ['IN_PROGRESS', 'PENDING'],
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('update status', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.findComponent({ name: 'OpenCreationsTable' }).vm.$emit('update-status', 2)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<!-- eslint-disable @intlify/vue-i18n/no-dynamic-keys -->
|
||||
<template>
|
||||
<div class="creation-confirm">
|
||||
<user-query class="mb-4 mt-2" v-model="query" />
|
||||
<div>
|
||||
<b-tabs v-model="tabIndex" content-class="mt-3" fill>
|
||||
<b-tab active :title-link-attributes="{ 'data-test': 'open' }">
|
||||
@ -85,6 +86,7 @@
|
||||
<script>
|
||||
import Overlay from '../components/Overlay'
|
||||
import OpenCreationsTable from '../components/Tables/OpenCreationsTable'
|
||||
import UserQuery from '../components/UserQuery'
|
||||
import { adminListContributions } from '../graphql/adminListContributions'
|
||||
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||
import { confirmContribution } from '../graphql/confirmContribution'
|
||||
@ -103,6 +105,7 @@ export default {
|
||||
components: {
|
||||
OpenCreationsTable,
|
||||
Overlay,
|
||||
UserQuery,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -114,6 +117,7 @@ export default {
|
||||
rows: 0,
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
query: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -409,6 +413,7 @@ export default {
|
||||
currentPage: this.currentPage,
|
||||
pageSize: this.pageSize,
|
||||
statusFilter: this.statusFilter,
|
||||
query: this.query,
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
|
||||
@ -186,7 +186,7 @@ describe('UserSearch', () => {
|
||||
describe('reset the search field', () => {
|
||||
it('calls the API with empty criteria', async () => {
|
||||
jest.clearAllMocks()
|
||||
await wrapper.find('.test-click-clear-criteria').trigger('click')
|
||||
await wrapper.findComponent({ name: 'UserQuery' }).vm.$emit('input', '')
|
||||
expect(apolloQueryMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
|
||||
@ -23,21 +23,7 @@
|
||||
</b-button>
|
||||
</div>
|
||||
<label>{{ $t('user_search') }}</label>
|
||||
<div>
|
||||
<b-input-group>
|
||||
<b-form-input
|
||||
type="text"
|
||||
class="test-input-criteria"
|
||||
v-model="criteria"
|
||||
:placeholder="$t('user_search')"
|
||||
></b-form-input>
|
||||
<b-input-group-append class="test-click-clear-criteria" @click="criteria = ''">
|
||||
<b-input-group-text class="pointer">
|
||||
<b-icon icon="x" />
|
||||
</b-input-group-text>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</div>
|
||||
<user-query class="mb-4 mt-2" v-model="criteria" />
|
||||
<search-user-table
|
||||
type="PageUserSearch"
|
||||
:items="searchResult"
|
||||
@ -61,12 +47,14 @@
|
||||
import SearchUserTable from '../components/Tables/SearchUserTable'
|
||||
import { searchUsers } from '../graphql/searchUsers'
|
||||
import { creationMonths } from '../mixins/creationMonths'
|
||||
import UserQuery from '../components/UserQuery'
|
||||
|
||||
export default {
|
||||
name: 'UserSearch',
|
||||
mixins: [creationMonths],
|
||||
components: {
|
||||
SearchUserTable,
|
||||
UserQuery,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@ -2890,6 +2890,97 @@ describe('ContributionResolver', () => {
|
||||
]),
|
||||
})
|
||||
})
|
||||
|
||||
describe('with user query', () => {
|
||||
it('returns only contributions of the queried user', async () => {
|
||||
const {
|
||||
data: { adminListContributions: contributionListObject },
|
||||
} = await query({
|
||||
query: adminListContributions,
|
||||
variables: {
|
||||
query: 'Peter',
|
||||
},
|
||||
})
|
||||
expect(contributionListObject.contributionList).toHaveLength(3)
|
||||
expect(contributionListObject).toMatchObject({
|
||||
contributionCount: 3,
|
||||
contributionList: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
amount: expect.decimalEqual(400),
|
||||
firstName: 'Peter',
|
||||
id: expect.any(Number),
|
||||
lastName: 'Lustig',
|
||||
memo: 'Herzlich Willkommen bei Gradido!',
|
||||
messagesCount: 0,
|
||||
status: 'PENDING',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
amount: expect.decimalEqual(100),
|
||||
firstName: 'Peter',
|
||||
id: expect.any(Number),
|
||||
lastName: 'Lustig',
|
||||
memo: 'Test env contribution',
|
||||
messagesCount: 0,
|
||||
status: 'PENDING',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
amount: expect.decimalEqual(200),
|
||||
firstName: 'Peter',
|
||||
id: expect.any(Number),
|
||||
lastName: 'Lustig',
|
||||
memo: 'Das war leider zu Viel!',
|
||||
messagesCount: 0,
|
||||
status: 'DELETED',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
|
||||
// test for case sensitivity and email
|
||||
it('returns only contributions of the queried user email', async () => {
|
||||
const {
|
||||
data: { adminListContributions: contributionListObject },
|
||||
} = await query({
|
||||
query: adminListContributions,
|
||||
variables: {
|
||||
query: 'RAEUBER', // only found in lowercase in the email
|
||||
},
|
||||
})
|
||||
expect(contributionListObject.contributionList).toHaveLength(3)
|
||||
expect(contributionListObject).toMatchObject({
|
||||
contributionCount: 3,
|
||||
contributionList: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
amount: expect.decimalEqual(166),
|
||||
firstName: 'Räuber',
|
||||
id: expect.any(Number),
|
||||
lastName: 'Hotzenplotz',
|
||||
memo: 'Whatever contribution',
|
||||
messagesCount: 0,
|
||||
status: 'DENIED',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
amount: expect.decimalEqual(166),
|
||||
firstName: 'Räuber',
|
||||
id: expect.any(Number),
|
||||
lastName: 'Hotzenplotz',
|
||||
memo: 'Whatever contribution',
|
||||
messagesCount: 0,
|
||||
status: 'DELETED',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
amount: expect.decimalEqual(166),
|
||||
firstName: 'Räuber',
|
||||
id: expect.any(Number),
|
||||
lastName: 'Hotzenplotz',
|
||||
memo: 'Whatever contribution',
|
||||
messagesCount: 0,
|
||||
status: 'CONFIRMED',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -138,7 +138,7 @@ export class ContributionResolver {
|
||||
currentPage,
|
||||
pageSize,
|
||||
withDeleted: true,
|
||||
relations: ['messages'],
|
||||
relations: { messages: true },
|
||||
userId: user.id,
|
||||
statusFilter,
|
||||
})
|
||||
@ -160,7 +160,7 @@ export class ContributionResolver {
|
||||
order,
|
||||
currentPage,
|
||||
pageSize,
|
||||
relations: ['user'],
|
||||
relations: { user: true },
|
||||
statusFilter,
|
||||
})
|
||||
|
||||
@ -372,6 +372,8 @@ export class ContributionResolver {
|
||||
statusFilter?: ContributionStatus[] | null,
|
||||
@Arg('userId', () => Int, { nullable: true })
|
||||
userId?: number | null,
|
||||
@Arg('query', () => String, { nullable: true })
|
||||
query?: string | null,
|
||||
): Promise<ContributionListResult> {
|
||||
const [dbContributions, count] = await findContributions({
|
||||
order,
|
||||
@ -379,8 +381,14 @@ export class ContributionResolver {
|
||||
pageSize,
|
||||
withDeleted: true,
|
||||
userId,
|
||||
relations: ['user', 'messages'],
|
||||
relations: {
|
||||
user: {
|
||||
emailContact: true,
|
||||
},
|
||||
messages: true,
|
||||
},
|
||||
statusFilter,
|
||||
query,
|
||||
})
|
||||
|
||||
return new ContributionListResult(
|
||||
|
||||
@ -1,38 +1,73 @@
|
||||
import { In } from '@dbTools/typeorm'
|
||||
import { In, Like } from '@dbTools/typeorm'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
interface Relations {
|
||||
[key: string]: boolean | Relations
|
||||
}
|
||||
|
||||
interface FindContributionsOptions {
|
||||
order: Order
|
||||
currentPage: number
|
||||
pageSize: number
|
||||
withDeleted?: boolean
|
||||
relations?: string[]
|
||||
relations?: Relations | undefined
|
||||
userId?: number | null
|
||||
statusFilter?: ContributionStatus[] | null
|
||||
query?: string | null
|
||||
}
|
||||
|
||||
export const findContributions = async (
|
||||
options: FindContributionsOptions,
|
||||
): Promise<[DbContribution[], number]> => {
|
||||
const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter } = {
|
||||
const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter, query } = {
|
||||
withDeleted: false,
|
||||
relations: [],
|
||||
relations: undefined,
|
||||
query: '',
|
||||
...options,
|
||||
}
|
||||
|
||||
const requiredWhere = {
|
||||
...(statusFilter?.length && { contributionStatus: In(statusFilter) }),
|
||||
...(userId && { userId }),
|
||||
}
|
||||
|
||||
const where =
|
||||
query && relations?.user
|
||||
? [
|
||||
{
|
||||
...requiredWhere,
|
||||
user: {
|
||||
firstName: Like(`%${query}%`),
|
||||
},
|
||||
},
|
||||
{
|
||||
...requiredWhere,
|
||||
user: {
|
||||
lastName: Like(`%${query}%`),
|
||||
},
|
||||
},
|
||||
{
|
||||
...requiredWhere,
|
||||
user: {
|
||||
emailContact: {
|
||||
email: Like(`%${query}%`),
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
: requiredWhere
|
||||
|
||||
return DbContribution.findAndCount({
|
||||
where: {
|
||||
...(statusFilter?.length && { contributionStatus: In(statusFilter) }),
|
||||
...(userId && { userId }),
|
||||
},
|
||||
relations,
|
||||
where,
|
||||
withDeleted,
|
||||
order: {
|
||||
createdAt: order,
|
||||
id: order,
|
||||
},
|
||||
relations,
|
||||
skip: (currentPage - 1) * pageSize,
|
||||
take: pageSize,
|
||||
})
|
||||
|
||||
@ -235,6 +235,7 @@ export const adminListContributions = gql`
|
||||
$order: Order = DESC
|
||||
$statusFilter: [ContributionStatus!]
|
||||
$userId: Int
|
||||
$query: String
|
||||
) {
|
||||
adminListContributions(
|
||||
currentPage: $currentPage
|
||||
@ -242,6 +243,7 @@ export const adminListContributions = gql`
|
||||
order: $order
|
||||
statusFilter: $statusFilter
|
||||
userId: $userId
|
||||
query: $query
|
||||
) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user