mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 1078-GDD-Calculate-Decay-Tool-clear
This commit is contained in:
commit
ff94905ede
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -441,7 +441,7 @@ jobs:
|
||||
report_name: Coverage Admin Interface
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
min_coverage: 50
|
||||
min_coverage: 52
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
|
||||
7
admin/src/graphql/getCountPendingCreations.js
Normal file
7
admin/src/graphql/getCountPendingCreations.js
Normal file
@ -0,0 +1,7 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const countPendingCreations = gql`
|
||||
query {
|
||||
countPendingCreations
|
||||
}
|
||||
`
|
||||
16
admin/src/graphql/getPendingCreations.js
Normal file
16
admin/src/graphql/getPendingCreations.js
Normal file
@ -0,0 +1,16 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const getPendingCreations = gql`
|
||||
query {
|
||||
getPendingCreations {
|
||||
firstName
|
||||
lastName
|
||||
email
|
||||
amount
|
||||
memo
|
||||
date
|
||||
moderator
|
||||
creation
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -4,11 +4,47 @@ import CreationConfirm from './CreationConfirm.vue'
|
||||
const localVue = global.localVue
|
||||
|
||||
const storeCommitMock = jest.fn()
|
||||
const toastedErrorMock = jest.fn()
|
||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
getPendingCreations: [
|
||||
{
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 500,
|
||||
memo: 'Danke für alles',
|
||||
date: new Date(),
|
||||
moderator: 0,
|
||||
},
|
||||
{
|
||||
firstName: 'Räuber',
|
||||
lastName: 'Hotzenplotz',
|
||||
email: 'raeuber@hotzenplotz.de',
|
||||
amount: 1000000,
|
||||
memo: 'Gut Ergatert',
|
||||
date: new Date(),
|
||||
moderator: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const mocks = {
|
||||
$store: {
|
||||
commit: storeCommitMock,
|
||||
},
|
||||
$apollo: {
|
||||
query: apolloQueryMock,
|
||||
},
|
||||
$toasted: {
|
||||
error: toastedErrorMock,
|
||||
},
|
||||
$moment: jest.fn((value) => {
|
||||
return {
|
||||
format: jest.fn((format) => value),
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
describe('CreationConfirm', () => {
|
||||
@ -32,9 +68,22 @@ describe('CreationConfirm', () => {
|
||||
it('commits resetOpenCreations to store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('resetOpenCreations')
|
||||
})
|
||||
it('commits setOpenCreations to store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('setOpenCreations', 2)
|
||||
})
|
||||
})
|
||||
|
||||
it('commits openCreationsPlus to store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('openCreationsPlus', 5)
|
||||
describe('server response is error', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
apolloQueryMock.mockRejectedValue({
|
||||
message: 'Ouch!',
|
||||
})
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('toast an error message', () => {
|
||||
expect(toastedErrorMock).toBeCalledWith('Ouch!')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div class="creation-confirm">
|
||||
<small class="bg-danger text-light p-1">
|
||||
Die anzahl der offene Schöpfungen stimmen nicht! Diese wird bei absenden im $store
|
||||
hochgezählt. Die Liste die hier angezeigt wird ist SIMULIERT!
|
||||
</small>
|
||||
<user-table
|
||||
class="mt-4"
|
||||
type="PageCreationConfirm"
|
||||
@ -15,6 +11,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import UserTable from '../components/UserTable.vue'
|
||||
import { getPendingCreations } from '../graphql/getPendingCreations'
|
||||
|
||||
export default {
|
||||
name: 'CreationConfirm',
|
||||
@ -30,98 +27,25 @@ export default {
|
||||
{ key: 'firstName', label: 'Vorname' },
|
||||
{ key: 'lastName', label: 'Nachname' },
|
||||
{
|
||||
key: 'creation_gdd',
|
||||
key: 'amount',
|
||||
label: 'Schöpfung',
|
||||
formatter: (value) => {
|
||||
return value + ' GDD'
|
||||
},
|
||||
},
|
||||
{ key: 'text', label: 'Text' },
|
||||
{ key: 'memo', label: 'Text' },
|
||||
{
|
||||
key: 'creation_date',
|
||||
key: 'date',
|
||||
label: 'Datum',
|
||||
formatter: (value) => {
|
||||
return value.long
|
||||
return this.$moment(value).format('ll')
|
||||
},
|
||||
},
|
||||
{ key: 'creation_moderator', label: 'Moderator' },
|
||||
{ key: 'moderator', label: 'Moderator' },
|
||||
{ key: 'edit_creation', label: 'ändern' },
|
||||
{ key: 'confirm', label: 'speichern' },
|
||||
],
|
||||
confirmResult: [
|
||||
{
|
||||
id: 1,
|
||||
email: 'dickerson@web.de',
|
||||
firstName: 'Dickerson',
|
||||
lastName: 'Macdonald',
|
||||
creation: '[450,200,700]',
|
||||
creation_gdd: '1000',
|
||||
text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam ',
|
||||
|
||||
creation_date: {
|
||||
short: 'November',
|
||||
long: '22/11/2021',
|
||||
},
|
||||
creation_moderator: 'Manuela Gast',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
email: 'larsen@woob.de',
|
||||
firstName: 'Larsen',
|
||||
lastName: 'Shaw',
|
||||
creation: '[300,200,1000]',
|
||||
creation_gdd: '1000',
|
||||
text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam ',
|
||||
|
||||
creation_date: {
|
||||
short: 'November',
|
||||
long: '03/11/2021',
|
||||
},
|
||||
creation_moderator: 'Manuela Gast',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
email: 'geneva@tete.de',
|
||||
firstName: 'Geneva',
|
||||
lastName: 'Wilson',
|
||||
creation: '[350,200,900]',
|
||||
creation_gdd: '1000',
|
||||
text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam',
|
||||
creation_date: {
|
||||
short: 'September',
|
||||
long: '27/09/2021',
|
||||
},
|
||||
creation_moderator: 'Manuela Gast',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
email: 'viewrter@asdfvb.com',
|
||||
firstName: 'Soledare',
|
||||
lastName: 'Takker',
|
||||
creation: '[100,400,800]',
|
||||
creation_gdd: '500',
|
||||
text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo ',
|
||||
creation_date: {
|
||||
short: 'Oktober',
|
||||
long: '12/10/2021',
|
||||
},
|
||||
creation_moderator: 'Evelyn Roller',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
email: 'dickerson@web.de',
|
||||
firstName: 'Dickerson',
|
||||
lastName: 'Macdonald',
|
||||
creation: '[100,400,800]',
|
||||
creation_gdd: '200',
|
||||
text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At',
|
||||
creation_date: {
|
||||
short: 'September',
|
||||
long: '05/09/2021',
|
||||
},
|
||||
creation_moderator: 'Manuela Gast',
|
||||
},
|
||||
],
|
||||
confirmResult: [],
|
||||
}
|
||||
},
|
||||
|
||||
@ -140,10 +64,23 @@ export default {
|
||||
this.$store.commit('openCreationsMinus', 1)
|
||||
}
|
||||
},
|
||||
getPendingCreations() {
|
||||
this.$apollo
|
||||
.query({
|
||||
query: getPendingCreations,
|
||||
})
|
||||
.then((result) => {
|
||||
this.$store.commit('resetOpenCreations')
|
||||
this.confirmResult = result.data.getPendingCreations.reverse()
|
||||
this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toasted.error(error.message)
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.commit('resetOpenCreations')
|
||||
this.$store.commit('openCreationsPlus', Object.keys(this.confirmResult).length)
|
||||
async created() {
|
||||
await this.getPendingCreations()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -76,7 +76,24 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getPendingCreations } from '../graphql/getPendingCreations'
|
||||
|
||||
export default {
|
||||
name: 'overview',
|
||||
methods: {
|
||||
getPendingCreations() {
|
||||
this.$apollo
|
||||
.query({
|
||||
query: getPendingCreations,
|
||||
})
|
||||
.then((result) => {
|
||||
this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
|
||||
})
|
||||
.catch()
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getPendingCreations()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -18,6 +18,9 @@ export const mutations = {
|
||||
token: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
setOpenCreations: (state, openCreations) => {
|
||||
state.openCreations = openCreations
|
||||
},
|
||||
moderator: (state, moderator) => {
|
||||
state.moderator = moderator
|
||||
},
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import store, { mutations, actions } from './store'
|
||||
import CONFIG from '../config'
|
||||
|
||||
const { token, openCreationsPlus, openCreationsMinus, resetOpenCreations } = mutations
|
||||
jest.mock('../config')
|
||||
|
||||
const { token, openCreationsPlus, openCreationsMinus, resetOpenCreations, setOpenCreations } =
|
||||
mutations
|
||||
const { logout } = actions
|
||||
|
||||
const CONFIG = {
|
||||
DEBUG_DISABLE_AUTH: true,
|
||||
}
|
||||
CONFIG.DEBUG_DISABLE_AUTH = true
|
||||
|
||||
describe('Vuex store', () => {
|
||||
describe('mutations', () => {
|
||||
@ -40,6 +42,14 @@ describe('Vuex store', () => {
|
||||
expect(state.openCreations).toEqual(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('setOpenCreations', () => {
|
||||
it('sets the open creations to given value', () => {
|
||||
const state = { openCreations: 24 }
|
||||
setOpenCreations(state, 12)
|
||||
expect(state.openCreations).toEqual(12)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('actions', () => {
|
||||
|
||||
34
backend/src/graphql/model/PendingCreation.ts
Normal file
34
backend/src/graphql/model/PendingCreation.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class PendingCreation {
|
||||
@Field(() => String)
|
||||
firstName: string
|
||||
|
||||
@Field(() => Int)
|
||||
id?: number
|
||||
|
||||
@Field(() => String)
|
||||
lastName: string
|
||||
|
||||
@Field(() => Number)
|
||||
userId: number
|
||||
|
||||
@Field(() => String)
|
||||
email: string
|
||||
|
||||
@Field(() => Date)
|
||||
date: Date
|
||||
|
||||
@Field(() => String)
|
||||
memo: string
|
||||
|
||||
@Field(() => Number)
|
||||
amount: BigInt
|
||||
|
||||
@Field(() => Number)
|
||||
moderator: number
|
||||
|
||||
@Field(() => [Number])
|
||||
creation: number[]
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { Resolver, Query, Arg, Args, Authorized, Mutation } from 'type-graphql'
|
||||
import { getCustomRepository, Raw } from 'typeorm'
|
||||
import { UserAdmin } from '../model/UserAdmin'
|
||||
import { LoginUserRepository } from '../../typeorm/repository/LoginUser'
|
||||
import { PendingCreation } from '../model/PendingCreation'
|
||||
import { RIGHTS } from '../../auth/RIGHTS'
|
||||
import { TransactionCreationRepository } from '../../typeorm/repository/TransactionCreation'
|
||||
import { PendingCreationRepository } from '../../typeorm/repository/PendingCreation'
|
||||
@ -14,19 +14,19 @@ export class AdminResolver {
|
||||
@Authorized([RIGHTS.SEARCH_USERS])
|
||||
@Query(() => [UserAdmin])
|
||||
async searchUsers(@Arg('searchText') searchText: string): Promise<UserAdmin[]> {
|
||||
const loginUserRepository = getCustomRepository(LoginUserRepository)
|
||||
const loginUsers = await loginUserRepository.findBySearchCriteria(searchText)
|
||||
const users = await Promise.all(
|
||||
loginUsers.map(async (loginUser) => {
|
||||
const user = new UserAdmin()
|
||||
user.firstName = loginUser.firstName
|
||||
user.lastName = loginUser.lastName
|
||||
user.email = loginUser.email
|
||||
user.creation = await getUserCreations(loginUser.id)
|
||||
return user
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const users = await userRepository.findBySearchCriteria(searchText)
|
||||
const adminUsers = await Promise.all(
|
||||
users.map(async (user) => {
|
||||
const adminUser = new UserAdmin()
|
||||
adminUser.firstName = user.firstName
|
||||
adminUser.lastName = user.lastName
|
||||
adminUser.email = user.email
|
||||
adminUser.creation = await getUserCreations(user.id)
|
||||
return adminUser
|
||||
}),
|
||||
)
|
||||
return users
|
||||
return adminUsers
|
||||
}
|
||||
|
||||
@Mutation(() => [Number])
|
||||
@ -52,6 +52,30 @@ export class AdminResolver {
|
||||
}
|
||||
return await getUserCreations(user.id)
|
||||
}
|
||||
|
||||
@Query(() => [PendingCreation])
|
||||
async getPendingCreations(): Promise<PendingCreation[]> {
|
||||
const pendingCreationRepository = getCustomRepository(PendingCreationRepository)
|
||||
const pendingCreations = await pendingCreationRepository.find()
|
||||
|
||||
const pendingCreationsPromise = await Promise.all(
|
||||
pendingCreations.map(async (pendingCreation) => {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findOneOrFail({ id: pendingCreation.userId })
|
||||
|
||||
const newPendingCreation = {
|
||||
...pendingCreation,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
email: user.email,
|
||||
creation: await getUserCreations(user.id),
|
||||
}
|
||||
|
||||
return newPendingCreation
|
||||
}),
|
||||
)
|
||||
return pendingCreationsPromise
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserCreations(id: number): Promise<number[]> {
|
||||
|
||||
@ -30,4 +30,17 @@ export class UserRepository extends Repository<User> {
|
||||
})
|
||||
return usersIndiced
|
||||
}
|
||||
|
||||
async findBySearchCriteria(searchCriteria: string): Promise<User[]> {
|
||||
return await this.createQueryBuilder('user')
|
||||
.where(
|
||||
'user.firstName like :name or user.lastName like :lastName or user.email like :email',
|
||||
{
|
||||
name: `%${searchCriteria}%`,
|
||||
lastName: `%${searchCriteria}%`,
|
||||
email: `%${searchCriteria}%`,
|
||||
},
|
||||
)
|
||||
.getMany()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/*
|
||||
Elopage Webhook
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user