mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 1881-set-role-in-admin-interface
This commit is contained in:
commit
d3824ae642
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -528,7 +528,7 @@ jobs:
|
|||||||
report_name: Coverage Backend
|
report_name: Coverage Backend
|
||||||
type: lcov
|
type: lcov
|
||||||
result_path: ./backend/coverage/lcov.info
|
result_path: ./backend/coverage/lcov.info
|
||||||
min_coverage: 68
|
min_coverage: 70
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import CreationFormular from './CreationFormular.vue'
|
import CreationFormular from './CreationFormular.vue'
|
||||||
import { createPendingCreation } from '../graphql/createPendingCreation'
|
import { adminCreateContribution } from '../graphql/adminCreateContribution'
|
||||||
import { createPendingCreations } from '../graphql/createPendingCreations'
|
import { adminCreateContributions } from '../graphql/adminCreateContributions'
|
||||||
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
const apolloMutateMock = jest.fn().mockResolvedValue({
|
const apolloMutateMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
createPendingCreation: [0, 0, 0],
|
adminCreateContribution: [0, 0, 0],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const stateCommitMock = jest.fn()
|
const stateCommitMock = jest.fn()
|
||||||
@ -110,7 +110,7 @@ describe('CreationFormular', () => {
|
|||||||
it('sends ... to apollo', () => {
|
it('sends ... to apollo', () => {
|
||||||
expect(apolloMutateMock).toBeCalledWith(
|
expect(apolloMutateMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
mutation: createPendingCreation,
|
mutation: adminCreateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'benjamin@bluemchen.de',
|
email: 'benjamin@bluemchen.de',
|
||||||
creationDate: getCreationDate(2),
|
creationDate: getCreationDate(2),
|
||||||
@ -334,10 +334,10 @@ describe('CreationFormular', () => {
|
|||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
apolloMutateMock.mockResolvedValue({
|
apolloMutateMock.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
createPendingCreations: {
|
adminCreateContributions: {
|
||||||
success: true,
|
success: true,
|
||||||
successfulCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'],
|
successfulContribution: ['bob@baumeister.de', 'bibi@bloxberg.de'],
|
||||||
failedCreation: [],
|
failedContribution: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -355,7 +355,7 @@ describe('CreationFormular', () => {
|
|||||||
it('calls the API', () => {
|
it('calls the API', () => {
|
||||||
expect(apolloMutateMock).toBeCalledWith(
|
expect(apolloMutateMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
mutation: createPendingCreations,
|
mutation: adminCreateContributions,
|
||||||
variables: {
|
variables: {
|
||||||
pendingCreations: [
|
pendingCreations: [
|
||||||
{
|
{
|
||||||
@ -390,10 +390,10 @@ describe('CreationFormular', () => {
|
|||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
apolloMutateMock.mockResolvedValue({
|
apolloMutateMock.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
createPendingCreations: {
|
adminCreateContributions: {
|
||||||
success: true,
|
success: true,
|
||||||
successfulCreation: [],
|
successfulContribution: [],
|
||||||
failedCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'],
|
failedContribution: ['bob@baumeister.de', 'bibi@bloxberg.de'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@ -85,8 +85,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { createPendingCreation } from '../graphql/createPendingCreation'
|
import { adminCreateContribution } from '../graphql/adminCreateContribution'
|
||||||
import { createPendingCreations } from '../graphql/createPendingCreations'
|
import { adminCreateContributions } from '../graphql/adminCreateContributions'
|
||||||
import { creationMonths } from '../mixins/creationMonths'
|
import { creationMonths } from '../mixins/creationMonths'
|
||||||
export default {
|
export default {
|
||||||
name: 'CreationFormular',
|
name: 'CreationFormular',
|
||||||
@ -158,25 +158,25 @@ export default {
|
|||||||
})
|
})
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.mutate({
|
.mutate({
|
||||||
mutation: createPendingCreations,
|
mutation: adminCreateContributions,
|
||||||
variables: {
|
variables: {
|
||||||
pendingCreations: submitObj,
|
pendingCreations: submitObj,
|
||||||
},
|
},
|
||||||
fetchPolicy: 'no-cache',
|
fetchPolicy: 'no-cache',
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
const failedCreations = []
|
const failedContributions = []
|
||||||
this.$store.commit(
|
this.$store.commit(
|
||||||
'openCreationsPlus',
|
'openCreationsPlus',
|
||||||
result.data.createPendingCreations.successfulCreation.length,
|
result.data.adminCreateContributions.successfulContribution.length,
|
||||||
)
|
)
|
||||||
if (result.data.createPendingCreations.failedCreation.length > 0) {
|
if (result.data.adminCreateContributions.failedContribution.length > 0) {
|
||||||
result.data.createPendingCreations.failedCreation.forEach((email) => {
|
result.data.adminCreateContributions.failedContribution.forEach((email) => {
|
||||||
failedCreations.push(email)
|
failedContributions.push(email)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.$emit('remove-all-bookmark')
|
this.$emit('remove-all-bookmark')
|
||||||
this.$emit('toast-failed-creations', failedCreations)
|
this.$emit('toast-failed-creations', failedContributions)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.toastError(error.message)
|
this.toastError(error.message)
|
||||||
@ -190,11 +190,11 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.mutate({
|
.mutate({
|
||||||
mutation: createPendingCreation,
|
mutation: adminCreateContribution,
|
||||||
variables: submitObj,
|
variables: submitObj,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$emit('update-user-data', this.item, result.data.createPendingCreation)
|
this.$emit('update-user-data', this.item, result.data.adminCreateContribution)
|
||||||
this.$store.commit('openCreationsPlus', 1)
|
this.$store.commit('openCreationsPlus', 1)
|
||||||
this.toastSuccess(
|
this.toastSuccess(
|
||||||
this.$t('creation_form.toasted', {
|
this.$t('creation_form.toasted', {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ const localVue = global.localVue
|
|||||||
|
|
||||||
const apolloMutateMock = jest.fn().mockResolvedValue({
|
const apolloMutateMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
updatePendingCreation: {
|
adminUpdateContribution: {
|
||||||
creation: [0, 0, 0],
|
creation: [0, 0, 0],
|
||||||
amount: 500,
|
amount: 500,
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { updatePendingCreation } from '../graphql/updatePendingCreation'
|
import { adminUpdateContribution } from '../graphql/adminUpdateContribution'
|
||||||
import { creationMonths } from '../mixins/creationMonths'
|
import { creationMonths } from '../mixins/creationMonths'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -113,7 +113,7 @@ export default {
|
|||||||
submitCreation() {
|
submitCreation() {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.mutate({
|
.mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: this.item.id,
|
id: this.item.id,
|
||||||
email: this.item.email,
|
email: this.item.email,
|
||||||
@ -123,11 +123,11 @@ export default {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$emit('update-user-data', this.item, result.data.updatePendingCreation.creation)
|
this.$emit('update-user-data', this.item, result.data.adminUpdateContribution.creation)
|
||||||
this.$emit('update-creation-data', {
|
this.$emit('update-creation-data', {
|
||||||
amount: Number(result.data.updatePendingCreation.amount),
|
amount: Number(result.data.adminUpdateContribution.amount),
|
||||||
date: result.data.updatePendingCreation.date,
|
date: result.data.adminUpdateContribution.date,
|
||||||
memo: result.data.updatePendingCreation.memo,
|
memo: result.data.adminUpdateContribution.memo,
|
||||||
row: this.row,
|
row: this.row,
|
||||||
})
|
})
|
||||||
this.toastSuccess(
|
this.toastSuccess(
|
||||||
|
|||||||
12
admin/src/graphql/adminCreateContribution.js
Normal file
12
admin/src/graphql/adminCreateContribution.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const adminCreateContribution = gql`
|
||||||
|
mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
||||||
|
adminCreateContribution(
|
||||||
|
email: $email
|
||||||
|
amount: $amount
|
||||||
|
memo: $memo
|
||||||
|
creationDate: $creationDate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
`
|
||||||
11
admin/src/graphql/adminCreateContributions.js
Normal file
11
admin/src/graphql/adminCreateContributions.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const adminCreateContributions = gql`
|
||||||
|
mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
|
||||||
|
adminCreateContributions(pendingCreations: $pendingCreations) {
|
||||||
|
success
|
||||||
|
successfulContribution
|
||||||
|
failedContribution
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
7
admin/src/graphql/adminDeleteContribution.js
Normal file
7
admin/src/graphql/adminDeleteContribution.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const adminDeleteContribution = gql`
|
||||||
|
mutation ($id: Int!) {
|
||||||
|
adminDeleteContribution(id: $id)
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
export const updatePendingCreation = gql`
|
export const adminUpdateContribution = gql`
|
||||||
mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
||||||
updatePendingCreation(
|
adminUpdateContribution(
|
||||||
id: $id
|
id: $id
|
||||||
email: $email
|
email: $email
|
||||||
amount: $amount
|
amount: $amount
|
||||||
7
admin/src/graphql/confirmContribution.js
Normal file
7
admin/src/graphql/confirmContribution.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const confirmContribution = gql`
|
||||||
|
mutation ($id: Int!) {
|
||||||
|
confirmContribution(id: $id)
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
|
|
||||||
export const confirmPendingCreation = gql`
|
|
||||||
mutation ($id: Int!) {
|
|
||||||
confirmPendingCreation(id: $id)
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
|
|
||||||
export const createPendingCreation = gql`
|
|
||||||
mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
|
||||||
createPendingCreation(email: $email, amount: $amount, memo: $memo, creationDate: $creationDate)
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
|
|
||||||
export const createPendingCreations = gql`
|
|
||||||
mutation ($pendingCreations: [CreatePendingCreationArgs!]!) {
|
|
||||||
createPendingCreations(pendingCreations: $pendingCreations) {
|
|
||||||
success
|
|
||||||
successfulCreation
|
|
||||||
failedCreation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
|
|
||||||
export const deletePendingCreation = gql`
|
|
||||||
mutation ($id: Int!) {
|
|
||||||
deletePendingCreation(id: $id)
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
export const getPendingCreations = gql`
|
export const listUnconfirmedContributions = gql`
|
||||||
query {
|
query {
|
||||||
getPendingCreations {
|
listUnconfirmedContributions {
|
||||||
id
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import CreationConfirm from './CreationConfirm.vue'
|
import CreationConfirm from './CreationConfirm.vue'
|
||||||
import { deletePendingCreation } from '../graphql/deletePendingCreation'
|
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||||
import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
|
import { confirmContribution } from '../graphql/confirmContribution'
|
||||||
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
@ -9,7 +9,7 @@ const localVue = global.localVue
|
|||||||
const storeCommitMock = jest.fn()
|
const storeCommitMock = jest.fn()
|
||||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
getPendingCreations: [
|
listUnconfirmedContributions: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
firstName: 'Bibi',
|
firstName: 'Bibi',
|
||||||
@ -84,9 +84,9 @@ describe('CreationConfirm', () => {
|
|||||||
await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
|
await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls the deletePendingCreation mutation', () => {
|
it('calls the adminDeleteContribution mutation', () => {
|
||||||
expect(apolloMutateMock).toBeCalledWith({
|
expect(apolloMutateMock).toBeCalledWith({
|
||||||
mutation: deletePendingCreation,
|
mutation: adminDeleteContribution,
|
||||||
variables: { id: 1 },
|
variables: { id: 1 },
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -141,9 +141,9 @@ describe('CreationConfirm', () => {
|
|||||||
await wrapper.find('#overlay').findAll('button').at(1).trigger('click')
|
await wrapper.find('#overlay').findAll('button').at(1).trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls the confirmPendingCreation mutation', () => {
|
it('calls the confirmContribution mutation', () => {
|
||||||
expect(apolloMutateMock).toBeCalledWith({
|
expect(apolloMutateMock).toBeCalledWith({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: { id: 2 },
|
variables: { id: 2 },
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -15,9 +15,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import Overlay from '../components/Overlay.vue'
|
import Overlay from '../components/Overlay.vue'
|
||||||
import OpenCreationsTable from '../components/Tables/OpenCreationsTable.vue'
|
import OpenCreationsTable from '../components/Tables/OpenCreationsTable.vue'
|
||||||
import { getPendingCreations } from '../graphql/getPendingCreations'
|
import { listUnconfirmedContributions } from '../graphql/listUnconfirmedContributions'
|
||||||
import { deletePendingCreation } from '../graphql/deletePendingCreation'
|
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||||
import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
|
import { confirmContribution } from '../graphql/confirmContribution'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreationConfirm',
|
name: 'CreationConfirm',
|
||||||
@ -36,7 +36,7 @@ export default {
|
|||||||
removeCreation(item) {
|
removeCreation(item) {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.mutate({
|
.mutate({
|
||||||
mutation: deletePendingCreation,
|
mutation: adminDeleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
},
|
},
|
||||||
@ -52,7 +52,7 @@ export default {
|
|||||||
confirmCreation() {
|
confirmCreation() {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.mutate({
|
.mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: this.item.id,
|
id: this.item.id,
|
||||||
},
|
},
|
||||||
@ -70,13 +70,13 @@ export default {
|
|||||||
getPendingCreations() {
|
getPendingCreations() {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.query({
|
.query({
|
||||||
query: getPendingCreations,
|
query: listUnconfirmedContributions,
|
||||||
fetchPolicy: 'network-only',
|
fetchPolicy: 'network-only',
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$store.commit('resetOpenCreations')
|
this.$store.commit('resetOpenCreations')
|
||||||
this.pendingCreations = result.data.getPendingCreations
|
this.pendingCreations = result.data.listUnconfirmedContributions
|
||||||
this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
|
this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.toastError(error.message)
|
this.toastError(error.message)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ const localVue = global.localVue
|
|||||||
|
|
||||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
getPendingCreations: [
|
listUnconfirmedContributions: [
|
||||||
{
|
{
|
||||||
pending: true,
|
pending: true,
|
||||||
},
|
},
|
||||||
@ -46,7 +46,7 @@ describe('Overview', () => {
|
|||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls getPendingCreations', () => {
|
it('calls listUnconfirmedContributions', () => {
|
||||||
expect(apolloQueryMock).toBeCalled()
|
expect(apolloQueryMock).toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { getPendingCreations } from '../graphql/getPendingCreations'
|
import { listUnconfirmedContributions } from '../graphql/listUnconfirmedContributions'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'overview',
|
name: 'overview',
|
||||||
@ -39,11 +39,11 @@ export default {
|
|||||||
async getPendingCreations() {
|
async getPendingCreations() {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.query({
|
.query({
|
||||||
query: getPendingCreations,
|
query: listUnconfirmedContributions,
|
||||||
fetchPolicy: 'network-only',
|
fetchPolicy: 'network-only',
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
|
this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4082,9 +4082,9 @@ caniuse-api@^3.0.0:
|
|||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001271:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001271:
|
||||||
version "1.0.30001271"
|
version "1.0.30001354"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz#0dda0c9bcae2cf5407cd34cac304186616cc83e8"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001354.tgz"
|
||||||
integrity sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==
|
integrity sha512-mImKeCkyGDAHNywYFA4bqnLAzTUvVkqPvhY4DV47X+Gl2c5Z8c3KNETnXp14GQt11LvxE8AwjzGxJ+rsikiOzg==
|
||||||
|
|
||||||
capture-exit@^2.0.0:
|
capture-exit@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
CONFIG_VERSION=v6.2022-04-21
|
CONFIG_VERSION=v7.2022-06-15
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
PORT=4000
|
PORT=4000
|
||||||
@ -28,6 +28,7 @@ COMMUNITY_NAME=Gradido Entwicklung
|
|||||||
COMMUNITY_URL=http://localhost/
|
COMMUNITY_URL=http://localhost/
|
||||||
COMMUNITY_REGISTER_URL=http://localhost/register
|
COMMUNITY_REGISTER_URL=http://localhost/register
|
||||||
COMMUNITY_REDEEM_URL=http://localhost/redeem/{code}
|
COMMUNITY_REDEEM_URL=http://localhost/redeem/{code}
|
||||||
|
COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code}
|
||||||
COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido.
|
COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido.
|
||||||
|
|
||||||
# Login Server
|
# Login Server
|
||||||
|
|||||||
@ -27,6 +27,7 @@ COMMUNITY_NAME=$COMMUNITY_NAME
|
|||||||
COMMUNITY_URL=$COMMUNITY_URL
|
COMMUNITY_URL=$COMMUNITY_URL
|
||||||
COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL
|
COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL
|
||||||
COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL
|
COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL
|
||||||
|
COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL
|
||||||
COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION
|
COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION
|
||||||
|
|
||||||
# Login Server
|
# Login Server
|
||||||
|
|||||||
@ -30,12 +30,17 @@ export enum RIGHTS {
|
|||||||
SET_USER_ROLE = 'SET_USER_ROLE',
|
SET_USER_ROLE = 'SET_USER_ROLE',
|
||||||
DELETE_USER = 'DELETE_USER',
|
DELETE_USER = 'DELETE_USER',
|
||||||
UNDELETE_USER = 'UNDELETE_USER',
|
UNDELETE_USER = 'UNDELETE_USER',
|
||||||
CREATE_PENDING_CREATION = 'CREATE_PENDING_CREATION',
|
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
|
||||||
UPDATE_PENDING_CREATION = 'UPDATE_PENDING_CREATION',
|
ADMIN_CREATE_CONTRIBUTIONS = 'ADMIN_CREATE_CONTRIBUTIONS',
|
||||||
SEARCH_PENDING_CREATION = 'SEARCH_PENDING_CREATION',
|
ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
|
||||||
DELETE_PENDING_CREATION = 'DELETE_PENDING_CREATION',
|
ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION',
|
||||||
CONFIRM_PENDING_CREATION = 'CONFIRM_PENDING_CREATION',
|
LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
|
||||||
|
CONFIRM_CONTRIBUTION = 'CONFIRM_CONTRIBUTION',
|
||||||
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
||||||
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',
|
||||||
|
LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
|
||||||
|
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
|
||||||
|
UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,14 +10,14 @@ Decimal.set({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const constants = {
|
const constants = {
|
||||||
DB_VERSION: '0038-add_contribution_links_table',
|
DB_VERSION: '0039-contributions_table',
|
||||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||||
LOG4JS_CONFIG: 'log4js-config.json',
|
LOG4JS_CONFIG: 'log4js-config.json',
|
||||||
// default log level on production should be info
|
// default log level on production should be info
|
||||||
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
|
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
|
||||||
CONFIG_VERSION: {
|
CONFIG_VERSION: {
|
||||||
DEFAULT: 'DEFAULT',
|
DEFAULT: 'DEFAULT',
|
||||||
EXPECTED: 'v6.2022-04-21',
|
EXPECTED: 'v7.2022-06-15',
|
||||||
CURRENT: '',
|
CURRENT: '',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -54,6 +54,8 @@ const community = {
|
|||||||
COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
|
COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
|
||||||
COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
|
COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
|
||||||
COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
|
COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
|
||||||
|
COMMUNITY_REDEEM_CONTRIBUTION_URL:
|
||||||
|
process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}',
|
||||||
COMMUNITY_DESCRIPTION:
|
COMMUNITY_DESCRIPTION:
|
||||||
process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
|
process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import Decimal from 'decimal.js-light'
|
|||||||
|
|
||||||
@InputType()
|
@InputType()
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export default class CreatePendingCreationArgs {
|
export default class AdminCreateContributionArgs {
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
email: string
|
email: string
|
||||||
|
|
||||||
@ -2,7 +2,7 @@ import { ArgsType, Field, Int } from 'type-graphql'
|
|||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export default class UpdatePendingCreationArgs {
|
export default class AdminUpdateContributionArgs {
|
||||||
@Field(() => Int)
|
@Field(() => Int)
|
||||||
id: number
|
id: number
|
||||||
|
|
||||||
29
backend/src/graphql/arg/ContributionLinkArgs.ts
Normal file
29
backend/src/graphql/arg/ContributionLinkArgs.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ArgsType, Field, Int } from 'type-graphql'
|
||||||
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export default class ContributionLinkArgs {
|
||||||
|
@Field(() => Decimal)
|
||||||
|
amount: Decimal
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
name: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
memo: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
cycle: string
|
||||||
|
|
||||||
|
@Field(() => String, { nullable: true })
|
||||||
|
validFrom?: string | null
|
||||||
|
|
||||||
|
@Field(() => String, { nullable: true })
|
||||||
|
validTo?: string | null
|
||||||
|
|
||||||
|
@Field(() => Decimal, { nullable: true })
|
||||||
|
maxAmountPerMonth: Decimal | null
|
||||||
|
|
||||||
|
@Field(() => Int)
|
||||||
|
maxPerCycle: number
|
||||||
|
}
|
||||||
28
backend/src/graphql/enum/ContributionCycleType.ts
Normal file
28
backend/src/graphql/enum/ContributionCycleType.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { registerEnumType } from 'type-graphql'
|
||||||
|
|
||||||
|
export enum ContributionCycleType {
|
||||||
|
ONCE = 'once',
|
||||||
|
HOUR = 'hour',
|
||||||
|
TWO_HOURS = 'two_hours',
|
||||||
|
FOUR_HOURS = 'four_hours',
|
||||||
|
EIGHT_HOURS = 'eight_hours',
|
||||||
|
HALF_DAY = 'half_day',
|
||||||
|
DAY = 'day',
|
||||||
|
TWO_DAYS = 'two_days',
|
||||||
|
THREE_DAYS = 'three_days',
|
||||||
|
FOUR_DAYS = 'four_days',
|
||||||
|
FIVE_DAYS = 'five_days',
|
||||||
|
SIX_DAYS = 'six_days',
|
||||||
|
WEEK = 'week',
|
||||||
|
TWO_WEEKS = 'two_weeks',
|
||||||
|
MONTH = 'month',
|
||||||
|
TWO_MONTH = 'two_month',
|
||||||
|
QUARTER = 'quarter',
|
||||||
|
HALF_YEAR = 'half_year',
|
||||||
|
YEAR = 'year',
|
||||||
|
}
|
||||||
|
|
||||||
|
registerEnumType(ContributionCycleType, {
|
||||||
|
name: 'ContributionCycleType', // this one is mandatory
|
||||||
|
description: 'Name of the Type of the ContributionCycle', // this one is optional
|
||||||
|
})
|
||||||
@ -1,19 +1,19 @@
|
|||||||
import { ObjectType, Field } from 'type-graphql'
|
import { ObjectType, Field } from 'type-graphql'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class CreatePendingCreations {
|
export class AdminCreateContributions {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.success = false
|
this.success = false
|
||||||
this.successfulCreation = []
|
this.successfulContribution = []
|
||||||
this.failedCreation = []
|
this.failedContribution = []
|
||||||
}
|
}
|
||||||
|
|
||||||
@Field(() => Boolean)
|
@Field(() => Boolean)
|
||||||
success: boolean
|
success: boolean
|
||||||
|
|
||||||
@Field(() => [String])
|
@Field(() => [String])
|
||||||
successfulCreation: string[]
|
successfulContribution: string[]
|
||||||
|
|
||||||
@Field(() => [String])
|
@Field(() => [String])
|
||||||
failedCreation: string[]
|
failedContribution: string[]
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@ import { ObjectType, Field } from 'type-graphql'
|
|||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class UpdatePendingCreation {
|
export class AdminUpdateContribution {
|
||||||
@Field(() => Date)
|
@Field(() => Date)
|
||||||
date: Date
|
date: Date
|
||||||
|
|
||||||
62
backend/src/graphql/model/ContributionLink.ts
Normal file
62
backend/src/graphql/model/ContributionLink.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { ObjectType, Field, Int } from 'type-graphql'
|
||||||
|
import Decimal from 'decimal.js-light'
|
||||||
|
import { ContributionLink as dbContributionLink } from '@entity/ContributionLink'
|
||||||
|
import CONFIG from '@/config'
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class ContributionLink {
|
||||||
|
constructor(contributionLink: dbContributionLink) {
|
||||||
|
this.id = contributionLink.id
|
||||||
|
this.amount = contributionLink.amount
|
||||||
|
this.name = contributionLink.name
|
||||||
|
this.memo = contributionLink.memo
|
||||||
|
this.createdAt = contributionLink.createdAt
|
||||||
|
this.deletedAt = contributionLink.deletedAt
|
||||||
|
this.validFrom = contributionLink.validFrom
|
||||||
|
this.validTo = contributionLink.validTo
|
||||||
|
this.maxAmountPerMonth = contributionLink.maxAmountPerMonth
|
||||||
|
this.cycle = contributionLink.cycle
|
||||||
|
this.maxPerCycle = contributionLink.maxPerCycle
|
||||||
|
this.code = contributionLink.code
|
||||||
|
this.link = CONFIG.COMMUNITY_REDEEM_CONTRIBUTION_URL.replace(/{code}/g, this.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
id: number
|
||||||
|
|
||||||
|
@Field(() => Decimal)
|
||||||
|
amount: Decimal
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
name: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
memo: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
code: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
link: string
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
createdAt: Date
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
deletedAt: Date | null
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
validFrom: Date | null
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
validTo: Date | null
|
||||||
|
|
||||||
|
@Field(() => Decimal, { nullable: true })
|
||||||
|
maxAmountPerMonth: Decimal | null
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
cycle: string
|
||||||
|
|
||||||
|
@Field(() => Int)
|
||||||
|
maxPerCycle: number
|
||||||
|
}
|
||||||
11
backend/src/graphql/model/ContributionLinkList.ts
Normal file
11
backend/src/graphql/model/ContributionLinkList.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { ObjectType, Field } from 'type-graphql'
|
||||||
|
import { ContributionLink } from '@model/ContributionLink'
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class ContributionLinkList {
|
||||||
|
@Field(() => [ContributionLink])
|
||||||
|
links: ContributionLink[]
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
count: number
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import { ObjectType, Field, Int } from 'type-graphql'
|
|||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class PendingCreation {
|
export class UnconfirmedContribution {
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
firstName: string
|
firstName: string
|
||||||
|
|
||||||
@ -16,25 +16,30 @@ import {
|
|||||||
setUserRole,
|
setUserRole,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
unDeleteUser,
|
unDeleteUser,
|
||||||
createPendingCreation,
|
adminCreateContribution,
|
||||||
createPendingCreations,
|
adminCreateContributions,
|
||||||
updatePendingCreation,
|
adminUpdateContribution,
|
||||||
deletePendingCreation,
|
adminDeleteContribution,
|
||||||
confirmPendingCreation,
|
confirmContribution,
|
||||||
|
createContributionLink,
|
||||||
|
deleteContributionLink,
|
||||||
|
updateContributionLink,
|
||||||
} from '@/seeds/graphql/mutations'
|
} from '@/seeds/graphql/mutations'
|
||||||
import {
|
import {
|
||||||
getPendingCreations,
|
listUnconfirmedContributions,
|
||||||
login,
|
login,
|
||||||
searchUsers,
|
searchUsers,
|
||||||
listTransactionLinksAdmin,
|
listTransactionLinksAdmin,
|
||||||
|
listContributionLinks,
|
||||||
} from '@/seeds/graphql/queries'
|
} from '@/seeds/graphql/queries'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||||
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
|
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
|
||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
import { AdminPendingCreation } from '@entity/AdminPendingCreation'
|
import { Contribution } from '@entity/Contribution'
|
||||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||||
|
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
|
||||||
|
|
||||||
// mock account activation email to avoid console spam
|
// mock account activation email to avoid console spam
|
||||||
jest.mock('@/mailer/sendAccountActivationEmail', () => {
|
jest.mock('@/mailer/sendAccountActivationEmail', () => {
|
||||||
@ -62,7 +67,7 @@ afterAll(async () => {
|
|||||||
|
|
||||||
let admin: User
|
let admin: User
|
||||||
let user: User
|
let user: User
|
||||||
let creation: AdminPendingCreation | void
|
let creation: Contribution | void
|
||||||
|
|
||||||
describe('AdminResolver', () => {
|
describe('AdminResolver', () => {
|
||||||
describe('set user role', () => {
|
describe('set user role', () => {
|
||||||
@ -653,9 +658,9 @@ describe('AdminResolver', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
describe('createPendingCreation', () => {
|
describe('adminCreateContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
|
await expect(mutate({ mutation: adminCreateContribution, variables })).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('401 Unauthorized')],
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
}),
|
}),
|
||||||
@ -663,11 +668,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('createPendingCreations', () => {
|
describe('adminCreateContributions', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: createPendingCreations,
|
mutation: adminCreateContributions,
|
||||||
variables: { pendingCreations: [variables] },
|
variables: { pendingCreations: [variables] },
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
@ -678,11 +683,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('updatePendingCreation', () => {
|
describe('adminUpdateContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
email: 'bibi@bloxberg.de',
|
email: 'bibi@bloxberg.de',
|
||||||
@ -699,11 +704,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('getPendingCreations', () => {
|
describe('listUnconfirmedContributions', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
query: getPendingCreations,
|
query: listUnconfirmedContributions,
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -713,11 +718,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('deletePendingCreation', () => {
|
describe('adminDeleteContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: deletePendingCreation,
|
mutation: adminDeleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
@ -730,11 +735,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirmPendingCreation', () => {
|
describe('confirmContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
@ -763,9 +768,9 @@ describe('AdminResolver', () => {
|
|||||||
resetToken()
|
resetToken()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('createPendingCreation', () => {
|
describe('adminCreateContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
|
await expect(mutate({ mutation: adminCreateContribution, variables })).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('401 Unauthorized')],
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
}),
|
}),
|
||||||
@ -773,11 +778,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('createPendingCreations', () => {
|
describe('adminCreateContributions', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: createPendingCreations,
|
mutation: adminCreateContributions,
|
||||||
variables: { pendingCreations: [variables] },
|
variables: { pendingCreations: [variables] },
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
@ -788,11 +793,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('updatePendingCreation', () => {
|
describe('adminUpdateContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
email: 'bibi@bloxberg.de',
|
email: 'bibi@bloxberg.de',
|
||||||
@ -809,11 +814,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('getPendingCreations', () => {
|
describe('listUnconfirmedContributions', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
query: getPendingCreations,
|
query: listUnconfirmedContributions,
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@ -823,11 +828,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('deletePendingCreation', () => {
|
describe('adminDeleteContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: deletePendingCreation,
|
mutation: adminDeleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
@ -840,11 +845,11 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirmPendingCreation', () => {
|
describe('confirmContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
@ -872,7 +877,7 @@ describe('AdminResolver', () => {
|
|||||||
resetToken()
|
resetToken()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('createPendingCreation', () => {
|
describe('adminCreateContribution', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
creation = await creationFactory(testEnv, {
|
creation = await creationFactory(testEnv, {
|
||||||
@ -885,7 +890,9 @@ describe('AdminResolver', () => {
|
|||||||
|
|
||||||
describe('user to create for does not exist', () => {
|
describe('user to create for does not exist', () => {
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
|
await expect(
|
||||||
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')],
|
errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')],
|
||||||
}),
|
}),
|
||||||
@ -900,9 +907,13 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
|
await expect(
|
||||||
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('This user was deleted. Cannot make a creation.')],
|
errors: [
|
||||||
|
new GraphQLError('This user was deleted. Cannot create a contribution.'),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -915,9 +926,13 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
|
await expect(
|
||||||
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('Creation could not be saved, Email is not activated')],
|
errors: [
|
||||||
|
new GraphQLError('Contribution could not be saved, Email is not activated'),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -932,7 +947,7 @@ describe('AdminResolver', () => {
|
|||||||
describe('date of creation is not a date string', () => {
|
describe('date of creation is not a date string', () => {
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({ mutation: createPendingCreation, variables }),
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [
|
errors: [
|
||||||
@ -952,7 +967,7 @@ describe('AdminResolver', () => {
|
|||||||
1,
|
1,
|
||||||
).toString()
|
).toString()
|
||||||
await expect(
|
await expect(
|
||||||
mutate({ mutation: createPendingCreation, variables }),
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [
|
errors: [
|
||||||
@ -972,7 +987,7 @@ describe('AdminResolver', () => {
|
|||||||
1,
|
1,
|
||||||
).toString()
|
).toString()
|
||||||
await expect(
|
await expect(
|
||||||
mutate({ mutation: createPendingCreation, variables }),
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [
|
errors: [
|
||||||
@ -987,7 +1002,7 @@ describe('AdminResolver', () => {
|
|||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
variables.creationDate = new Date().toString()
|
variables.creationDate = new Date().toString()
|
||||||
await expect(
|
await expect(
|
||||||
mutate({ mutation: createPendingCreation, variables }),
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [
|
errors: [
|
||||||
@ -1004,11 +1019,11 @@ describe('AdminResolver', () => {
|
|||||||
it('returns an array of the open creations for the last three months', async () => {
|
it('returns an array of the open creations for the last three months', async () => {
|
||||||
variables.amount = new Decimal(200)
|
variables.amount = new Decimal(200)
|
||||||
await expect(
|
await expect(
|
||||||
mutate({ mutation: createPendingCreation, variables }),
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
data: {
|
||||||
createPendingCreation: [1000, 1000, 800],
|
adminCreateContribution: [1000, 1000, 800],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -1019,7 +1034,7 @@ describe('AdminResolver', () => {
|
|||||||
it('returns an array of the open creations for the last three months', async () => {
|
it('returns an array of the open creations for the last three months', async () => {
|
||||||
variables.amount = new Decimal(1000)
|
variables.amount = new Decimal(1000)
|
||||||
await expect(
|
await expect(
|
||||||
mutate({ mutation: createPendingCreation, variables }),
|
mutate({ mutation: adminCreateContribution, variables }),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [
|
errors: [
|
||||||
@ -1034,7 +1049,7 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('createPendingCreations', () => {
|
describe('adminCreateContributions', () => {
|
||||||
// at this point we have this data in DB:
|
// at this point we have this data in DB:
|
||||||
// bibi@bloxberg.de: [1000, 1000, 800]
|
// bibi@bloxberg.de: [1000, 1000, 800]
|
||||||
// peter@lustig.de: [1000, 600, 1000]
|
// peter@lustig.de: [1000, 600, 1000]
|
||||||
@ -1059,16 +1074,16 @@ describe('AdminResolver', () => {
|
|||||||
it('returns success, two successful creation and three failed creations', async () => {
|
it('returns success, two successful creation and three failed creations', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: createPendingCreations,
|
mutation: adminCreateContributions,
|
||||||
variables: { pendingCreations: massCreationVariables },
|
variables: { pendingCreations: massCreationVariables },
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
data: {
|
||||||
createPendingCreations: {
|
adminCreateContributions: {
|
||||||
success: true,
|
success: true,
|
||||||
successfulCreation: ['bibi@bloxberg.de', 'peter@lustig.de'],
|
successfulContribution: ['bibi@bloxberg.de', 'peter@lustig.de'],
|
||||||
failedCreation: [
|
failedContribution: [
|
||||||
'stephen@hawking.uk',
|
'stephen@hawking.uk',
|
||||||
'garrick@ollivander.com',
|
'garrick@ollivander.com',
|
||||||
'bob@baumeister.de',
|
'bob@baumeister.de',
|
||||||
@ -1080,7 +1095,7 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('updatePendingCreation', () => {
|
describe('adminUpdateContribution', () => {
|
||||||
// at this I expect to have this data in DB:
|
// at this I expect to have this data in DB:
|
||||||
// bibi@bloxberg.de: [1000, 1000, 300]
|
// bibi@bloxberg.de: [1000, 1000, 300]
|
||||||
// peter@lustig.de: [1000, 600, 500]
|
// peter@lustig.de: [1000, 600, 500]
|
||||||
@ -1091,7 +1106,7 @@ describe('AdminResolver', () => {
|
|||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
email: 'bob@baumeister.de',
|
email: 'bob@baumeister.de',
|
||||||
@ -1112,7 +1127,7 @@ describe('AdminResolver', () => {
|
|||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: 1,
|
id: 1,
|
||||||
email: 'stephen@hawking.uk',
|
email: 'stephen@hawking.uk',
|
||||||
@ -1133,7 +1148,7 @@ describe('AdminResolver', () => {
|
|||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: -1,
|
id: -1,
|
||||||
email: 'bibi@bloxberg.de',
|
email: 'bibi@bloxberg.de',
|
||||||
@ -1144,7 +1159,7 @@ describe('AdminResolver', () => {
|
|||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('No creation found to given id.')],
|
errors: [new GraphQLError('No contribution found to given id.')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1154,7 +1169,7 @@ describe('AdminResolver', () => {
|
|||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
email: 'bibi@bloxberg.de',
|
email: 'bibi@bloxberg.de',
|
||||||
@ -1167,7 +1182,7 @@ describe('AdminResolver', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [
|
errors: [
|
||||||
new GraphQLError(
|
new GraphQLError(
|
||||||
'user of the pending creation and send user does not correspond',
|
'user of the pending contribution and send user does not correspond',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@ -1179,7 +1194,7 @@ describe('AdminResolver', () => {
|
|||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
email: 'peter@lustig.de',
|
email: 'peter@lustig.de',
|
||||||
@ -1204,7 +1219,7 @@ describe('AdminResolver', () => {
|
|||||||
it('returns update creation object', async () => {
|
it('returns update creation object', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
email: 'peter@lustig.de',
|
email: 'peter@lustig.de',
|
||||||
@ -1216,7 +1231,7 @@ describe('AdminResolver', () => {
|
|||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
data: {
|
||||||
updatePendingCreation: {
|
adminUpdateContribution: {
|
||||||
date: expect.any(String),
|
date: expect.any(String),
|
||||||
memo: 'Danke Peter!',
|
memo: 'Danke Peter!',
|
||||||
amount: '300',
|
amount: '300',
|
||||||
@ -1232,7 +1247,7 @@ describe('AdminResolver', () => {
|
|||||||
it('returns update creation object', async () => {
|
it('returns update creation object', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: updatePendingCreation,
|
mutation: adminUpdateContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
email: 'peter@lustig.de',
|
email: 'peter@lustig.de',
|
||||||
@ -1244,7 +1259,7 @@ describe('AdminResolver', () => {
|
|||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
data: {
|
||||||
updatePendingCreation: {
|
adminUpdateContribution: {
|
||||||
date: expect.any(String),
|
date: expect.any(String),
|
||||||
memo: 'Das war leider zu Viel!',
|
memo: 'Das war leider zu Viel!',
|
||||||
amount: '200',
|
amount: '200',
|
||||||
@ -1257,16 +1272,16 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('getPendingCreations', () => {
|
describe('listUnconfirmedContributions', () => {
|
||||||
it('returns four pending creations', async () => {
|
it('returns four pending creations', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
query: getPendingCreations,
|
query: listUnconfirmedContributions,
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
data: {
|
||||||
getPendingCreations: expect.arrayContaining([
|
listUnconfirmedContributions: expect.arrayContaining([
|
||||||
{
|
{
|
||||||
id: expect.any(Number),
|
id: expect.any(Number),
|
||||||
firstName: 'Peter',
|
firstName: 'Peter',
|
||||||
@ -1318,19 +1333,19 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('deletePendingCreation', () => {
|
describe('adminDeleteContribution', () => {
|
||||||
describe('creation id does not exist', () => {
|
describe('creation id does not exist', () => {
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: deletePendingCreation,
|
mutation: adminDeleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: -1,
|
id: -1,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('Creation not found for given id.')],
|
errors: [new GraphQLError('Contribution not found for given id.')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1340,33 +1355,33 @@ describe('AdminResolver', () => {
|
|||||||
it('returns true', async () => {
|
it('returns true', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: deletePendingCreation,
|
mutation: adminDeleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: { deletePendingCreation: true },
|
data: { adminDeleteContribution: true },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirmPendingCreation', () => {
|
describe('confirmContribution', () => {
|
||||||
describe('creation does not exits', () => {
|
describe('creation does not exits', () => {
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: -1,
|
id: -1,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('Creation not found to given id.')],
|
errors: [new GraphQLError('Contribution not found to given id.')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1386,14 +1401,14 @@ describe('AdminResolver', () => {
|
|||||||
it('thows an error', async () => {
|
it('thows an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('Moderator can not confirm own pending creation')],
|
errors: [new GraphQLError('Moderator can not confirm own contribution')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1413,14 +1428,14 @@ describe('AdminResolver', () => {
|
|||||||
it('returns true', async () => {
|
it('returns true', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: creation ? creation.id : -1,
|
id: creation ? creation.id : -1,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: { confirmPendingCreation: true },
|
data: { confirmContribution: true },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1438,8 +1453,8 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('confirm two creations one after the other quickly', () => {
|
describe('confirm two creations one after the other quickly', () => {
|
||||||
let c1: AdminPendingCreation | void
|
let c1: Contribution | void
|
||||||
let c2: AdminPendingCreation | void
|
let c2: Contribution | void
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@ -1460,25 +1475,25 @@ describe('AdminResolver', () => {
|
|||||||
// In the futrue this should not throw anymore
|
// In the futrue this should not throw anymore
|
||||||
it('throws an error for the second confirmation', async () => {
|
it('throws an error for the second confirmation', async () => {
|
||||||
const r1 = mutate({
|
const r1 = mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: c1 ? c1.id : -1,
|
id: c1 ? c1.id : -1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const r2 = mutate({
|
const r2 = mutate({
|
||||||
mutation: confirmPendingCreation,
|
mutation: confirmContribution,
|
||||||
variables: {
|
variables: {
|
||||||
id: c2 ? c2.id : -1,
|
id: c2 ? c2.id : -1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
await expect(r1).resolves.toEqual(
|
await expect(r1).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: { confirmPendingCreation: true },
|
data: { confirmContribution: true },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
await expect(r2).resolves.toEqual(
|
await expect(r2).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('Unable to confirm creation.')],
|
errors: [new GraphQLError('Creation was not successful.')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1749,4 +1764,361 @@ describe('AdminResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Contribution Links', () => {
|
||||||
|
const variables = {
|
||||||
|
amount: new Decimal(200),
|
||||||
|
name: 'Dokumenta 2022',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
|
||||||
|
cycle: 'once',
|
||||||
|
validFrom: new Date(2022, 5, 18).toISOString(),
|
||||||
|
validTo: new Date(2022, 7, 14).toISOString(),
|
||||||
|
maxAmountPerMonth: new Decimal(200),
|
||||||
|
maxPerCycle: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
describe('createContributionLink', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('listContributionLinks', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(query({ query: listContributionLinks })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('updateContributionLink', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: updateContributionLink,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
id: -1,
|
||||||
|
amount: new Decimal(400),
|
||||||
|
name: 'Dokumenta 2023',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('deleteContributionLink', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
|
||||||
|
).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()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('createContributionLink', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('listContributionLinks', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(query({ query: listContributionLinks })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('updateContributionLink', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: updateContributionLink,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
id: -1,
|
||||||
|
amount: new Decimal(400),
|
||||||
|
name: 'Dokumenta 2023',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('deleteContributionLink', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with admin rights', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
user = await userFactory(testEnv, peterLustig)
|
||||||
|
await query({
|
||||||
|
query: login,
|
||||||
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await cleanDB()
|
||||||
|
resetToken()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('createContributionLink', () => {
|
||||||
|
it('returns a contribution link object', async () => {
|
||||||
|
await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
createContributionLink: expect.objectContaining({
|
||||||
|
id: expect.any(Number),
|
||||||
|
amount: '200',
|
||||||
|
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||||
|
link: expect.stringMatching(/^.*?\/CL-[0-9a-f]{24,24}$/),
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
name: 'Dokumenta 2022',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
|
||||||
|
validFrom: expect.any(String),
|
||||||
|
validTo: expect.any(String),
|
||||||
|
maxAmountPerMonth: '200',
|
||||||
|
cycle: 'once',
|
||||||
|
maxPerCycle: 1,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a contribution link stored in db', async () => {
|
||||||
|
const cls = await DbContributionLink.find()
|
||||||
|
expect(cls).toHaveLength(1)
|
||||||
|
expect(cls[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(Number),
|
||||||
|
name: 'Dokumenta 2022',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
|
||||||
|
validFrom: new Date('2022-06-18T00:00:00.000Z'),
|
||||||
|
validTo: new Date('2022-08-14T00:00:00.000Z'),
|
||||||
|
cycle: 'once',
|
||||||
|
maxPerCycle: 1,
|
||||||
|
totalMaxCountOfContribution: null,
|
||||||
|
maxAccountBalance: null,
|
||||||
|
minGapHours: null,
|
||||||
|
createdAt: expect.any(Date),
|
||||||
|
deletedAt: null,
|
||||||
|
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||||
|
linkEnabled: true,
|
||||||
|
// amount: '200',
|
||||||
|
// maxAmountPerMonth: '200',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('listContributionLinks', () => {
|
||||||
|
describe('one link in DB', () => {
|
||||||
|
it('returns the link and count 1', async () => {
|
||||||
|
await expect(query({ query: listContributionLinks })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listContributionLinks: {
|
||||||
|
links: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: '200',
|
||||||
|
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||||
|
link: expect.stringMatching(/^.*?\/CL-[0-9a-f]{24,24}$/),
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
name: 'Dokumenta 2022',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
|
||||||
|
validFrom: expect.any(String),
|
||||||
|
validTo: expect.any(String),
|
||||||
|
maxAmountPerMonth: '200',
|
||||||
|
cycle: 'once',
|
||||||
|
maxPerCycle: 1,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('updateContributionLink', () => {
|
||||||
|
describe('no valid id', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: updateContributionLink,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
id: -1,
|
||||||
|
amount: new Decimal(400),
|
||||||
|
name: 'Dokumenta 2023',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('Contribution Link not found to given id.')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('valid id', () => {
|
||||||
|
let linkId: number
|
||||||
|
beforeAll(async () => {
|
||||||
|
const links = await query({ query: listContributionLinks })
|
||||||
|
linkId = links.data.listContributionLinks.links[0].id
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns updated contribution link object', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: updateContributionLink,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
id: linkId,
|
||||||
|
amount: new Decimal(400),
|
||||||
|
name: 'Dokumenta 2023',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
updateContributionLink: {
|
||||||
|
id: linkId,
|
||||||
|
amount: '400',
|
||||||
|
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||||
|
link: expect.stringMatching(/^.*?\/CL-[0-9a-f]{24,24}$/),
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
name: 'Dokumenta 2023',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
|
||||||
|
validFrom: expect.any(String),
|
||||||
|
validTo: expect.any(String),
|
||||||
|
maxAmountPerMonth: '200',
|
||||||
|
cycle: 'once',
|
||||||
|
maxPerCycle: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updated the DB record', async () => {
|
||||||
|
await expect(DbContributionLink.findOne(linkId)).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: linkId,
|
||||||
|
name: 'Dokumenta 2023',
|
||||||
|
memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
|
||||||
|
// amount: '400',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('deleteContributionLink', () => {
|
||||||
|
describe('no valid id', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('Contribution Link not found to given id.')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('valid id', () => {
|
||||||
|
let linkId: number
|
||||||
|
beforeAll(async () => {
|
||||||
|
const links = await query({ query: listContributionLinks })
|
||||||
|
linkId = links.data.listContributionLinks.links[0].id
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns a date string', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({ mutation: deleteContributionLink, variables: { id: linkId } }),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
deleteContributionLink: expect.any(String),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not list this contribution link anymore', async () => {
|
||||||
|
await expect(query({ query: listContributionLinks })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listContributionLinks: {
|
||||||
|
links: [],
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { Context, getUser } from '@/server/context'
|
import { Context, getUser } from '@/server/context'
|
||||||
|
import { backendLogger as logger } from '@/server/logger'
|
||||||
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx, Int } from 'type-graphql'
|
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx, Int } from 'type-graphql'
|
||||||
import {
|
import {
|
||||||
getCustomRepository,
|
getCustomRepository,
|
||||||
@ -11,21 +12,25 @@ import {
|
|||||||
FindOperator,
|
FindOperator,
|
||||||
} from '@dbTools/typeorm'
|
} from '@dbTools/typeorm'
|
||||||
import { UserAdmin, SearchUsersResult } from '@model/UserAdmin'
|
import { UserAdmin, SearchUsersResult } from '@model/UserAdmin'
|
||||||
import { PendingCreation } from '@model/PendingCreation'
|
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
||||||
import { CreatePendingCreations } from '@model/CreatePendingCreations'
|
import { AdminCreateContributions } from '@model/AdminCreateContributions'
|
||||||
import { UpdatePendingCreation } from '@model/UpdatePendingCreation'
|
import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
|
||||||
|
import { ContributionLink } from '@model/ContributionLink'
|
||||||
|
import { ContributionLinkList } from '@model/ContributionLinkList'
|
||||||
import { RIGHTS } from '@/auth/RIGHTS'
|
import { RIGHTS } from '@/auth/RIGHTS'
|
||||||
import { UserRepository } from '@repository/User'
|
import { UserRepository } from '@repository/User'
|
||||||
import CreatePendingCreationArgs from '@arg/CreatePendingCreationArgs'
|
import AdminCreateContributionArgs from '@arg/AdminCreateContributionArgs'
|
||||||
import UpdatePendingCreationArgs from '@arg/UpdatePendingCreationArgs'
|
import AdminUpdateContributionArgs from '@arg/AdminUpdateContributionArgs'
|
||||||
import SearchUsersArgs from '@arg/SearchUsersArgs'
|
import SearchUsersArgs from '@arg/SearchUsersArgs'
|
||||||
|
import ContributionLinkArgs from '@arg/ContributionLinkArgs'
|
||||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||||
|
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
|
||||||
import { Transaction } from '@model/Transaction'
|
import { Transaction } from '@model/Transaction'
|
||||||
import { TransactionLink, TransactionLinkResult } from '@model/TransactionLink'
|
import { TransactionLink, TransactionLinkResult } from '@model/TransactionLink'
|
||||||
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
|
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
|
||||||
import { TransactionRepository } from '@repository/Transaction'
|
import { TransactionRepository } from '@repository/Transaction'
|
||||||
import { calculateDecay } from '@/util/decay'
|
import { calculateDecay } from '@/util/decay'
|
||||||
import { AdminPendingCreation } from '@entity/AdminPendingCreation'
|
import { Contribution } from '@entity/Contribution'
|
||||||
import { hasElopageBuys } from '@/util/hasElopageBuys'
|
import { hasElopageBuys } from '@/util/hasElopageBuys'
|
||||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||||
import { User as dbUser } from '@entity/User'
|
import { User as dbUser } from '@entity/User'
|
||||||
@ -39,6 +44,7 @@ import { Order } from '@enum/Order'
|
|||||||
import { communityUser } from '@/util/communityUser'
|
import { communityUser } from '@/util/communityUser'
|
||||||
import { checkOptInCode, activationLink, printTimeDuration } from './UserResolver'
|
import { checkOptInCode, activationLink, printTimeDuration } from './UserResolver'
|
||||||
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
|
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
|
||||||
|
import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver'
|
||||||
import CONFIG from '@/config'
|
import CONFIG from '@/config'
|
||||||
|
|
||||||
// const EMAIL_OPT_IN_REGISTER = 1
|
// const EMAIL_OPT_IN_REGISTER = 1
|
||||||
@ -213,72 +219,76 @@ export class AdminResolver {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.CREATE_PENDING_CREATION])
|
@Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTION])
|
||||||
@Mutation(() => [Number])
|
@Mutation(() => [Number])
|
||||||
async createPendingCreation(
|
async adminCreateContribution(
|
||||||
@Args() { email, amount, memo, creationDate }: CreatePendingCreationArgs,
|
@Args() { email, amount, memo, creationDate }: AdminCreateContributionArgs,
|
||||||
@Ctx() context: Context,
|
@Ctx() context: Context,
|
||||||
): Promise<Decimal[]> {
|
): Promise<Decimal[]> {
|
||||||
|
logger.trace('adminCreateContribution...')
|
||||||
const user = await dbUser.findOne({ email }, { withDeleted: true })
|
const user = await dbUser.findOne({ email }, { withDeleted: true })
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error(`Could not find user with email: ${email}`)
|
throw new Error(`Could not find user with email: ${email}`)
|
||||||
}
|
}
|
||||||
if (user.deletedAt) {
|
if (user.deletedAt) {
|
||||||
throw new Error('This user was deleted. Cannot make a creation.')
|
throw new Error('This user was deleted. Cannot create a contribution.')
|
||||||
}
|
}
|
||||||
if (!user.emailChecked) {
|
if (!user.emailChecked) {
|
||||||
throw new Error('Creation could not be saved, Email is not activated')
|
throw new Error('Contribution could not be saved, Email is not activated')
|
||||||
}
|
}
|
||||||
const moderator = getUser(context)
|
const moderator = getUser(context)
|
||||||
|
logger.trace('moderator: ', moderator.id)
|
||||||
const creations = await getUserCreation(user.id)
|
const creations = await getUserCreation(user.id)
|
||||||
|
logger.trace('creations', creations)
|
||||||
const creationDateObj = new Date(creationDate)
|
const creationDateObj = new Date(creationDate)
|
||||||
if (isCreationValid(creations, amount, creationDateObj)) {
|
if (isContributionValid(creations, amount, creationDateObj)) {
|
||||||
const adminPendingCreation = AdminPendingCreation.create()
|
const contribution = Contribution.create()
|
||||||
adminPendingCreation.userId = user.id
|
contribution.userId = user.id
|
||||||
adminPendingCreation.amount = amount
|
contribution.amount = amount
|
||||||
adminPendingCreation.created = new Date()
|
contribution.createdAt = new Date()
|
||||||
adminPendingCreation.date = creationDateObj
|
contribution.contributionDate = creationDateObj
|
||||||
adminPendingCreation.memo = memo
|
contribution.memo = memo
|
||||||
adminPendingCreation.moderator = moderator.id
|
contribution.moderatorId = moderator.id
|
||||||
|
|
||||||
await AdminPendingCreation.save(adminPendingCreation)
|
logger.trace('contribution to save', contribution)
|
||||||
|
await Contribution.save(contribution)
|
||||||
}
|
}
|
||||||
return getUserCreation(user.id)
|
return getUserCreation(user.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.CREATE_PENDING_CREATION])
|
@Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTIONS])
|
||||||
@Mutation(() => CreatePendingCreations)
|
@Mutation(() => AdminCreateContributions)
|
||||||
async createPendingCreations(
|
async adminCreateContributions(
|
||||||
@Arg('pendingCreations', () => [CreatePendingCreationArgs])
|
@Arg('pendingCreations', () => [AdminCreateContributionArgs])
|
||||||
pendingCreations: CreatePendingCreationArgs[],
|
contributions: AdminCreateContributionArgs[],
|
||||||
@Ctx() context: Context,
|
@Ctx() context: Context,
|
||||||
): Promise<CreatePendingCreations> {
|
): Promise<AdminCreateContributions> {
|
||||||
let success = false
|
let success = false
|
||||||
const successfulCreation: string[] = []
|
const successfulContribution: string[] = []
|
||||||
const failedCreation: string[] = []
|
const failedContribution: string[] = []
|
||||||
for (const pendingCreation of pendingCreations) {
|
for (const contribution of contributions) {
|
||||||
await this.createPendingCreation(pendingCreation, context)
|
await this.adminCreateContribution(contribution, context)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
successfulCreation.push(pendingCreation.email)
|
successfulContribution.push(contribution.email)
|
||||||
success = true
|
success = true
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
failedCreation.push(pendingCreation.email)
|
failedContribution.push(contribution.email)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
success,
|
success,
|
||||||
successfulCreation,
|
successfulContribution,
|
||||||
failedCreation,
|
failedContribution,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.UPDATE_PENDING_CREATION])
|
@Authorized([RIGHTS.ADMIN_UPDATE_CONTRIBUTION])
|
||||||
@Mutation(() => UpdatePendingCreation)
|
@Mutation(() => AdminUpdateContribution)
|
||||||
async updatePendingCreation(
|
async adminUpdateContribution(
|
||||||
@Args() { id, email, amount, memo, creationDate }: UpdatePendingCreationArgs,
|
@Args() { id, email, amount, memo, creationDate }: AdminUpdateContributionArgs,
|
||||||
@Ctx() context: Context,
|
@Ctx() context: Context,
|
||||||
): Promise<UpdatePendingCreation> {
|
): Promise<AdminUpdateContribution> {
|
||||||
const user = await dbUser.findOne({ email }, { withDeleted: true })
|
const user = await dbUser.findOne({ email }, { withDeleted: true })
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error(`Could not find user with email: ${email}`)
|
throw new Error(`Could not find user with email: ${email}`)
|
||||||
@ -289,59 +299,65 @@ export class AdminResolver {
|
|||||||
|
|
||||||
const moderator = getUser(context)
|
const moderator = getUser(context)
|
||||||
|
|
||||||
const pendingCreationToUpdate = await AdminPendingCreation.findOne({ id })
|
const contributionToUpdate = await Contribution.findOne({
|
||||||
|
where: { id, confirmedAt: IsNull() },
|
||||||
|
})
|
||||||
|
|
||||||
if (!pendingCreationToUpdate) {
|
if (!contributionToUpdate) {
|
||||||
throw new Error('No creation found to given id.')
|
throw new Error('No contribution found to given id.')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingCreationToUpdate.userId !== user.id) {
|
if (contributionToUpdate.userId !== user.id) {
|
||||||
throw new Error('user of the pending creation and send user does not correspond')
|
throw new Error('user of the pending contribution and send user does not correspond')
|
||||||
}
|
}
|
||||||
|
|
||||||
const creationDateObj = new Date(creationDate)
|
const creationDateObj = new Date(creationDate)
|
||||||
let creations = await getUserCreation(user.id)
|
let creations = await getUserCreation(user.id)
|
||||||
if (pendingCreationToUpdate.date.getMonth() === creationDateObj.getMonth()) {
|
if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) {
|
||||||
creations = updateCreations(creations, pendingCreationToUpdate)
|
creations = updateCreations(creations, contributionToUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// all possible cases not to be true are thrown in this function
|
// all possible cases not to be true are thrown in this function
|
||||||
isCreationValid(creations, amount, creationDateObj)
|
isContributionValid(creations, amount, creationDateObj)
|
||||||
pendingCreationToUpdate.amount = amount
|
contributionToUpdate.amount = amount
|
||||||
pendingCreationToUpdate.memo = memo
|
contributionToUpdate.memo = memo
|
||||||
pendingCreationToUpdate.date = new Date(creationDate)
|
contributionToUpdate.contributionDate = new Date(creationDate)
|
||||||
pendingCreationToUpdate.moderator = moderator.id
|
contributionToUpdate.moderatorId = moderator.id
|
||||||
|
|
||||||
await AdminPendingCreation.save(pendingCreationToUpdate)
|
await Contribution.save(contributionToUpdate)
|
||||||
const result = new UpdatePendingCreation()
|
const result = new AdminUpdateContribution()
|
||||||
result.amount = amount
|
result.amount = amount
|
||||||
result.memo = pendingCreationToUpdate.memo
|
result.memo = contributionToUpdate.memo
|
||||||
result.date = pendingCreationToUpdate.date
|
result.date = contributionToUpdate.contributionDate
|
||||||
|
|
||||||
result.creation = await getUserCreation(user.id)
|
result.creation = await getUserCreation(user.id)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.SEARCH_PENDING_CREATION])
|
@Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS])
|
||||||
@Query(() => [PendingCreation])
|
@Query(() => [UnconfirmedContribution])
|
||||||
async getPendingCreations(): Promise<PendingCreation[]> {
|
async listUnconfirmedContributions(): Promise<UnconfirmedContribution[]> {
|
||||||
const pendingCreations = await AdminPendingCreation.find()
|
const contributions = await Contribution.find({ where: { confirmedAt: IsNull() } })
|
||||||
if (pendingCreations.length === 0) {
|
if (contributions.length === 0) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const userIds = pendingCreations.map((p) => p.userId)
|
const userIds = contributions.map((p) => p.userId)
|
||||||
const userCreations = await getUserCreations(userIds)
|
const userCreations = await getUserCreations(userIds)
|
||||||
const users = await dbUser.find({ where: { id: In(userIds) }, withDeleted: true })
|
const users = await dbUser.find({ where: { id: In(userIds) }, withDeleted: true })
|
||||||
|
|
||||||
return pendingCreations.map((pendingCreation) => {
|
return contributions.map((contribution) => {
|
||||||
const user = users.find((u) => u.id === pendingCreation.userId)
|
const user = users.find((u) => u.id === contribution.userId)
|
||||||
const creation = userCreations.find((c) => c.id === pendingCreation.userId)
|
const creation = userCreations.find((c) => c.id === contribution.userId)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...pendingCreation,
|
id: contribution.id,
|
||||||
amount: pendingCreation.amount,
|
userId: contribution.userId,
|
||||||
|
date: contribution.contributionDate,
|
||||||
|
memo: contribution.memo,
|
||||||
|
amount: contribution.amount,
|
||||||
|
moderator: contribution.moderatorId,
|
||||||
firstName: user ? user.firstName : '',
|
firstName: user ? user.firstName : '',
|
||||||
lastName: user ? user.lastName : '',
|
lastName: user ? user.lastName : '',
|
||||||
email: user ? user.email : '',
|
email: user ? user.email : '',
|
||||||
@ -350,69 +366,93 @@ export class AdminResolver {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.DELETE_PENDING_CREATION])
|
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
|
||||||
@Mutation(() => Boolean)
|
@Mutation(() => Boolean)
|
||||||
async deletePendingCreation(@Arg('id', () => Int) id: number): Promise<boolean> {
|
async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise<boolean> {
|
||||||
const pendingCreation = await AdminPendingCreation.findOne(id)
|
const contribution = await Contribution.findOne(id)
|
||||||
if (!pendingCreation) {
|
if (!contribution) {
|
||||||
throw new Error('Creation not found for given id.')
|
throw new Error('Contribution not found for given id.')
|
||||||
}
|
}
|
||||||
const res = await AdminPendingCreation.delete(pendingCreation)
|
const res = await contribution.softRemove()
|
||||||
return !!res
|
return !!res
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.CONFIRM_PENDING_CREATION])
|
@Authorized([RIGHTS.CONFIRM_CONTRIBUTION])
|
||||||
@Mutation(() => Boolean)
|
@Mutation(() => Boolean)
|
||||||
async confirmPendingCreation(
|
async confirmContribution(
|
||||||
@Arg('id', () => Int) id: number,
|
@Arg('id', () => Int) id: number,
|
||||||
@Ctx() context: Context,
|
@Ctx() context: Context,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const pendingCreation = await AdminPendingCreation.findOne(id)
|
const contribution = await Contribution.findOne(id)
|
||||||
if (!pendingCreation) {
|
if (!contribution) {
|
||||||
throw new Error('Creation not found to given id.')
|
throw new Error('Contribution not found to given id.')
|
||||||
}
|
}
|
||||||
const moderatorUser = getUser(context)
|
const moderatorUser = getUser(context)
|
||||||
if (moderatorUser.id === pendingCreation.userId)
|
if (moderatorUser.id === contribution.userId)
|
||||||
throw new Error('Moderator can not confirm own pending creation')
|
throw new Error('Moderator can not confirm own contribution')
|
||||||
|
|
||||||
const user = await dbUser.findOneOrFail({ id: pendingCreation.userId }, { withDeleted: true })
|
const user = await dbUser.findOneOrFail({ id: contribution.userId }, { withDeleted: true })
|
||||||
if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a creation.')
|
if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a contribution.')
|
||||||
|
|
||||||
const creations = await getUserCreation(pendingCreation.userId, false)
|
const creations = await getUserCreation(contribution.userId, false)
|
||||||
if (!isCreationValid(creations, pendingCreation.amount, pendingCreation.date)) {
|
if (!isContributionValid(creations, contribution.amount, contribution.contributionDate)) {
|
||||||
throw new Error('Creation is not valid!!')
|
throw new Error('Creation is not valid!!')
|
||||||
}
|
}
|
||||||
|
|
||||||
const receivedCallDate = new Date()
|
const receivedCallDate = new Date()
|
||||||
|
|
||||||
const transactionRepository = getCustomRepository(TransactionRepository)
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
const lastTransaction = await transactionRepository.findLastForUser(pendingCreation.userId)
|
await queryRunner.connect()
|
||||||
|
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||||
|
try {
|
||||||
|
const lastTransaction = await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select('transaction')
|
||||||
|
.from(DbTransaction, 'transaction')
|
||||||
|
.where('transaction.userId = :id', { id: contribution.userId })
|
||||||
|
.orderBy('transaction.balanceDate', 'DESC')
|
||||||
|
.getOne()
|
||||||
|
logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined')
|
||||||
|
|
||||||
let newBalance = new Decimal(0)
|
let newBalance = new Decimal(0)
|
||||||
let decay: Decay | null = null
|
let decay: Decay | null = null
|
||||||
if (lastTransaction) {
|
if (lastTransaction) {
|
||||||
decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, receivedCallDate)
|
decay = calculateDecay(
|
||||||
|
lastTransaction.balance,
|
||||||
|
lastTransaction.balanceDate,
|
||||||
|
receivedCallDate,
|
||||||
|
)
|
||||||
newBalance = decay.balance
|
newBalance = decay.balance
|
||||||
}
|
}
|
||||||
newBalance = newBalance.add(pendingCreation.amount.toString())
|
newBalance = newBalance.add(contribution.amount.toString())
|
||||||
|
|
||||||
const transaction = new DbTransaction()
|
const transaction = new DbTransaction()
|
||||||
transaction.typeId = TransactionTypeId.CREATION
|
transaction.typeId = TransactionTypeId.CREATION
|
||||||
transaction.memo = pendingCreation.memo
|
transaction.memo = contribution.memo
|
||||||
transaction.userId = pendingCreation.userId
|
transaction.userId = contribution.userId
|
||||||
transaction.previous = lastTransaction ? lastTransaction.id : null
|
transaction.previous = lastTransaction ? lastTransaction.id : null
|
||||||
transaction.amount = pendingCreation.amount
|
transaction.amount = contribution.amount
|
||||||
transaction.creationDate = pendingCreation.date
|
transaction.creationDate = contribution.contributionDate
|
||||||
transaction.balance = newBalance
|
transaction.balance = newBalance
|
||||||
transaction.balanceDate = receivedCallDate
|
transaction.balanceDate = receivedCallDate
|
||||||
transaction.decay = decay ? decay.decay : new Decimal(0)
|
transaction.decay = decay ? decay.decay : new Decimal(0)
|
||||||
transaction.decayStart = decay ? decay.start : null
|
transaction.decayStart = decay ? decay.start : null
|
||||||
await transaction.save().catch(() => {
|
await queryRunner.manager.insert(DbTransaction, transaction)
|
||||||
throw new Error('Unable to confirm creation.')
|
|
||||||
})
|
|
||||||
|
|
||||||
await AdminPendingCreation.delete(pendingCreation)
|
contribution.confirmedAt = receivedCallDate
|
||||||
|
contribution.confirmedBy = moderatorUser.id
|
||||||
|
contribution.transactionId = transaction.id
|
||||||
|
await queryRunner.manager.update(Contribution, { id: contribution.id }, contribution)
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction()
|
||||||
|
logger.info('creation commited successfuly.')
|
||||||
|
} catch (e) {
|
||||||
|
await queryRunner.rollbackTransaction()
|
||||||
|
logger.error(`Creation was not successful: ${e}`)
|
||||||
|
throw new Error(`Creation was not successful.`)
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,6 +550,99 @@ export class AdminResolver {
|
|||||||
linkList: transactionLinks.map((tl) => new TransactionLink(tl, new User(user))),
|
linkList: transactionLinks.map((tl) => new TransactionLink(tl, new User(user))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorized([RIGHTS.CREATE_CONTRIBUTION_LINK])
|
||||||
|
@Mutation(() => ContributionLink)
|
||||||
|
async createContributionLink(
|
||||||
|
@Args()
|
||||||
|
{
|
||||||
|
amount,
|
||||||
|
name,
|
||||||
|
memo,
|
||||||
|
cycle,
|
||||||
|
validFrom,
|
||||||
|
validTo,
|
||||||
|
maxAmountPerMonth,
|
||||||
|
maxPerCycle,
|
||||||
|
}: ContributionLinkArgs,
|
||||||
|
): Promise<ContributionLink> {
|
||||||
|
const dbContributionLink = new DbContributionLink()
|
||||||
|
dbContributionLink.amount = amount
|
||||||
|
dbContributionLink.name = name
|
||||||
|
dbContributionLink.memo = memo
|
||||||
|
dbContributionLink.createdAt = new Date()
|
||||||
|
dbContributionLink.code = contributionLinkCode(dbContributionLink.createdAt)
|
||||||
|
dbContributionLink.cycle = cycle
|
||||||
|
if (validFrom) dbContributionLink.validFrom = new Date(validFrom)
|
||||||
|
if (validTo) dbContributionLink.validTo = new Date(validTo)
|
||||||
|
dbContributionLink.maxAmountPerMonth = maxAmountPerMonth
|
||||||
|
dbContributionLink.maxPerCycle = maxPerCycle
|
||||||
|
await dbContributionLink.save()
|
||||||
|
return new ContributionLink(dbContributionLink)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorized([RIGHTS.LIST_CONTRIBUTION_LINKS])
|
||||||
|
@Query(() => ContributionLinkList)
|
||||||
|
async listContributionLinks(
|
||||||
|
@Args()
|
||||||
|
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
|
||||||
|
): Promise<ContributionLinkList> {
|
||||||
|
const [links, count] = await DbContributionLink.findAndCount({
|
||||||
|
order: { createdAt: order },
|
||||||
|
skip: (currentPage - 1) * pageSize,
|
||||||
|
take: pageSize,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
links: links.map((link: DbContributionLink) => new ContributionLink(link)),
|
||||||
|
count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorized([RIGHTS.DELETE_CONTRIBUTION_LINK])
|
||||||
|
@Mutation(() => Date, { nullable: true })
|
||||||
|
async deleteContributionLink(@Arg('id', () => Int) id: number): Promise<Date | null> {
|
||||||
|
const contributionLink = await DbContributionLink.findOne(id)
|
||||||
|
if (!contributionLink) {
|
||||||
|
logger.error(`Contribution Link not found to given id: ${id}`)
|
||||||
|
throw new Error('Contribution Link not found to given id.')
|
||||||
|
}
|
||||||
|
await contributionLink.softRemove()
|
||||||
|
const newContributionLink = await DbContributionLink.findOne({ id }, { withDeleted: true })
|
||||||
|
return newContributionLink ? newContributionLink.deletedAt : null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorized([RIGHTS.UPDATE_CONTRIBUTION_LINK])
|
||||||
|
@Mutation(() => ContributionLink)
|
||||||
|
async updateContributionLink(
|
||||||
|
@Args()
|
||||||
|
{
|
||||||
|
amount,
|
||||||
|
name,
|
||||||
|
memo,
|
||||||
|
cycle,
|
||||||
|
validFrom,
|
||||||
|
validTo,
|
||||||
|
maxAmountPerMonth,
|
||||||
|
maxPerCycle,
|
||||||
|
}: ContributionLinkArgs,
|
||||||
|
@Arg('id', () => Int) id: number,
|
||||||
|
): Promise<ContributionLink> {
|
||||||
|
const dbContributionLink = await DbContributionLink.findOne(id)
|
||||||
|
if (!dbContributionLink) {
|
||||||
|
logger.error(`Contribution Link not found to given id: ${id}`)
|
||||||
|
throw new Error('Contribution Link not found to given id.')
|
||||||
|
}
|
||||||
|
dbContributionLink.amount = amount
|
||||||
|
dbContributionLink.name = name
|
||||||
|
dbContributionLink.memo = memo
|
||||||
|
dbContributionLink.cycle = cycle
|
||||||
|
if (validFrom) dbContributionLink.validFrom = new Date(validFrom)
|
||||||
|
if (validTo) dbContributionLink.validTo = new Date(validTo)
|
||||||
|
dbContributionLink.maxAmountPerMonth = maxAmountPerMonth
|
||||||
|
dbContributionLink.maxPerCycle = maxPerCycle
|
||||||
|
await dbContributionLink.save()
|
||||||
|
return new ContributionLink(dbContributionLink)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreationMap {
|
interface CreationMap {
|
||||||
@ -518,24 +651,29 @@ interface CreationMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getUserCreation(id: number, includePending = true): Promise<Decimal[]> {
|
async function getUserCreation(id: number, includePending = true): Promise<Decimal[]> {
|
||||||
|
logger.trace('getUserCreation', id, includePending)
|
||||||
const creations = await getUserCreations([id], includePending)
|
const creations = await getUserCreations([id], includePending)
|
||||||
return creations[0] ? creations[0].creations : FULL_CREATION_AVAILABLE
|
return creations[0] ? creations[0].creations : FULL_CREATION_AVAILABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserCreations(ids: number[], includePending = true): Promise<CreationMap[]> {
|
async function getUserCreations(ids: number[], includePending = true): Promise<CreationMap[]> {
|
||||||
|
logger.trace('getUserCreations:', ids, includePending)
|
||||||
const months = getCreationMonths()
|
const months = getCreationMonths()
|
||||||
|
logger.trace('getUserCreations months', months)
|
||||||
|
|
||||||
const queryRunner = getConnection().createQueryRunner()
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
await queryRunner.connect()
|
await queryRunner.connect()
|
||||||
|
|
||||||
const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day'
|
const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day'
|
||||||
|
logger.trace('getUserCreations dateFilter', dateFilter)
|
||||||
|
|
||||||
const unionString = includePending
|
const unionString = includePending
|
||||||
? `
|
? `
|
||||||
UNION
|
UNION
|
||||||
SELECT date AS date, amount AS amount, userId AS userId FROM admin_pending_creations
|
SELECT contribution_date AS date, amount AS amount, user_id AS userId FROM contributions
|
||||||
WHERE userId IN (${ids.toString()})
|
WHERE user_id IN (${ids.toString()})
|
||||||
AND date >= ${dateFilter}`
|
AND contribution_date >= ${dateFilter}
|
||||||
|
AND confirmed_at IS NULL AND deleted_at IS NULL`
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
const unionQuery = await queryRunner.manager.query(`
|
const unionQuery = await queryRunner.manager.query(`
|
||||||
@ -565,17 +703,18 @@ async function getUserCreations(ids: number[], includePending = true): Promise<C
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCreations(creations: Decimal[], pendingCreation: AdminPendingCreation): Decimal[] {
|
function updateCreations(creations: Decimal[], contribution: Contribution): Decimal[] {
|
||||||
const index = getCreationIndex(pendingCreation.date.getMonth())
|
const index = getCreationIndex(contribution.contributionDate.getMonth())
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
throw new Error('You cannot create GDD for a month older than the last three months.')
|
throw new Error('You cannot create GDD for a month older than the last three months.')
|
||||||
}
|
}
|
||||||
creations[index] = creations[index].plus(pendingCreation.amount.toString())
|
creations[index] = creations[index].plus(contribution.amount.toString())
|
||||||
return creations
|
return creations
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCreationValid(creations: Decimal[], amount: Decimal, creationDate: Date) {
|
function isContributionValid(creations: Decimal[], amount: Decimal, creationDate: Date) {
|
||||||
|
logger.trace('isContributionValid', creations, amount, creationDate)
|
||||||
const index = getCreationIndex(creationDate.getMonth())
|
const index = getCreationIndex(creationDate.getMonth())
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
export interface ContributionLinkInterface {
|
||||||
|
amount: number
|
||||||
|
name: string
|
||||||
|
memo: string
|
||||||
|
validFrom?: Date
|
||||||
|
validTo?: Date
|
||||||
|
}
|
||||||
18
backend/src/seeds/contributionLink/index.ts
Normal file
18
backend/src/seeds/contributionLink/index.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ContributionLinkInterface } from './ContributionLinkInterface'
|
||||||
|
|
||||||
|
export const contributionLinks: ContributionLinkInterface[] = [
|
||||||
|
{
|
||||||
|
name: 'Dokumenta 2017',
|
||||||
|
memo: 'Vielen Dank für deinen Besuch bei der Dokumenta 2017',
|
||||||
|
amount: 200,
|
||||||
|
validFrom: new Date(2017, 3, 8),
|
||||||
|
validTo: new Date(2017, 6, 16),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Dokumenta 2022',
|
||||||
|
memo: 'Vielen Dank für deinen Besuch bei der Dokumenta 2022',
|
||||||
|
amount: 200,
|
||||||
|
validFrom: new Date(2022, 5, 18),
|
||||||
|
validTo: new Date(2022, 8, 25),
|
||||||
|
},
|
||||||
|
]
|
||||||
27
backend/src/seeds/factory/contributionLink.ts
Normal file
27
backend/src/seeds/factory/contributionLink.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||||
|
import { createContributionLink } from '@/seeds/graphql/mutations'
|
||||||
|
import { login } from '@/seeds/graphql/queries'
|
||||||
|
import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface'
|
||||||
|
|
||||||
|
export const contributionLinkFactory = async (
|
||||||
|
client: ApolloServerTestClient,
|
||||||
|
contributionLink: ContributionLinkInterface,
|
||||||
|
): Promise<void> => {
|
||||||
|
const { mutate, query } = client
|
||||||
|
|
||||||
|
// login as admin
|
||||||
|
await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
amount: contributionLink.amount,
|
||||||
|
memo: contributionLink.memo,
|
||||||
|
name: contributionLink.name,
|
||||||
|
cycle: 'ONCE',
|
||||||
|
maxPerCycle: 1,
|
||||||
|
maxAmountPerMonth: 200,
|
||||||
|
validFrom: contributionLink.validFrom ? contributionLink.validFrom.toISOString() : undefined,
|
||||||
|
validTo: contributionLink.validTo ? contributionLink.validTo.toISOString() : undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
await mutate({ mutation: createContributionLink, variables })
|
||||||
|
}
|
||||||
@ -1,13 +1,13 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
import { createPendingCreation, confirmPendingCreation } from '@/seeds/graphql/mutations'
|
import { adminCreateContribution, confirmContribution } from '@/seeds/graphql/mutations'
|
||||||
import { login } from '@/seeds/graphql/queries'
|
import { login } from '@/seeds/graphql/queries'
|
||||||
import { CreationInterface } from '@/seeds/creation/CreationInterface'
|
import { CreationInterface } from '@/seeds/creation/CreationInterface'
|
||||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
import { Transaction } from '@entity/Transaction'
|
import { Transaction } from '@entity/Transaction'
|
||||||
import { AdminPendingCreation } from '@entity/AdminPendingCreation'
|
import { Contribution } from '@entity/Contribution'
|
||||||
// import CONFIG from '@/config/index'
|
// import CONFIG from '@/config/index'
|
||||||
|
|
||||||
export const nMonthsBefore = (date: Date, months = 1): string => {
|
export const nMonthsBefore = (date: Date, months = 1): string => {
|
||||||
@ -17,23 +17,23 @@ export const nMonthsBefore = (date: Date, months = 1): string => {
|
|||||||
export const creationFactory = async (
|
export const creationFactory = async (
|
||||||
client: ApolloServerTestClient,
|
client: ApolloServerTestClient,
|
||||||
creation: CreationInterface,
|
creation: CreationInterface,
|
||||||
): Promise<AdminPendingCreation | void> => {
|
): Promise<Contribution | void> => {
|
||||||
const { mutate, query } = client
|
const { mutate, query } = client
|
||||||
|
|
||||||
await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
|
await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
|
||||||
|
|
||||||
// TODO it would be nice to have this mutation return the id
|
// TODO it would be nice to have this mutation return the id
|
||||||
await mutate({ mutation: createPendingCreation, variables: { ...creation } })
|
await mutate({ mutation: adminCreateContribution, variables: { ...creation } })
|
||||||
|
|
||||||
const user = await User.findOneOrFail({ where: { email: creation.email } })
|
const user = await User.findOneOrFail({ where: { email: creation.email } })
|
||||||
|
|
||||||
const pendingCreation = await AdminPendingCreation.findOneOrFail({
|
const pendingCreation = await Contribution.findOneOrFail({
|
||||||
where: { userId: user.id, amount: creation.amount },
|
where: { userId: user.id, amount: creation.amount },
|
||||||
order: { created: 'DESC' },
|
order: { createdAt: 'DESC' },
|
||||||
})
|
})
|
||||||
|
|
||||||
if (creation.confirmed) {
|
if (creation.confirmed) {
|
||||||
await mutate({ mutation: confirmPendingCreation, variables: { id: pendingCreation.id } })
|
await mutate({ mutation: confirmContribution, variables: { id: pendingCreation.id } })
|
||||||
|
|
||||||
if (creation.moveCreationDate) {
|
if (creation.moveCreationDate) {
|
||||||
const transaction = await Transaction.findOneOrFail({
|
const transaction = await Transaction.findOneOrFail({
|
||||||
|
|||||||
@ -81,15 +81,20 @@ export const createTransactionLink = gql`
|
|||||||
|
|
||||||
// from admin interface
|
// from admin interface
|
||||||
|
|
||||||
export const createPendingCreation = gql`
|
export const adminCreateContribution = gql`
|
||||||
mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
||||||
createPendingCreation(email: $email, amount: $amount, memo: $memo, creationDate: $creationDate)
|
adminCreateContribution(
|
||||||
|
email: $email
|
||||||
|
amount: $amount
|
||||||
|
memo: $memo
|
||||||
|
creationDate: $creationDate
|
||||||
|
)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const confirmPendingCreation = gql`
|
export const confirmContribution = gql`
|
||||||
mutation ($id: Int!) {
|
mutation ($id: Int!) {
|
||||||
confirmPendingCreation(id: $id)
|
confirmContribution(id: $id)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -111,19 +116,19 @@ export const unDeleteUser = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const createPendingCreations = gql`
|
export const adminCreateContributions = gql`
|
||||||
mutation ($pendingCreations: [CreatePendingCreationArgs!]!) {
|
mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
|
||||||
createPendingCreations(pendingCreations: $pendingCreations) {
|
adminCreateContributions(pendingCreations: $pendingCreations) {
|
||||||
success
|
success
|
||||||
successfulCreation
|
successfulContribution
|
||||||
failedCreation
|
failedContribution
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const updatePendingCreation = gql`
|
export const adminUpdateContribution = gql`
|
||||||
mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
|
||||||
updatePendingCreation(
|
adminUpdateContribution(
|
||||||
id: $id
|
id: $id
|
||||||
email: $email
|
email: $email
|
||||||
amount: $amount
|
amount: $amount
|
||||||
@ -138,8 +143,90 @@ export const updatePendingCreation = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const deletePendingCreation = gql`
|
export const adminDeleteContribution = gql`
|
||||||
mutation ($id: Int!) {
|
mutation ($id: Int!) {
|
||||||
deletePendingCreation(id: $id)
|
adminDeleteContribution(id: $id)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const createContributionLink = gql`
|
||||||
|
mutation (
|
||||||
|
$amount: Decimal!
|
||||||
|
$name: String!
|
||||||
|
$memo: String!
|
||||||
|
$cycle: String!
|
||||||
|
$validFrom: String
|
||||||
|
$validTo: String
|
||||||
|
$maxAmountPerMonth: Decimal
|
||||||
|
$maxPerCycle: Int! = 1
|
||||||
|
) {
|
||||||
|
createContributionLink(
|
||||||
|
amount: $amount
|
||||||
|
name: $name
|
||||||
|
memo: $memo
|
||||||
|
cycle: $cycle
|
||||||
|
validFrom: $validFrom
|
||||||
|
validTo: $validTo
|
||||||
|
maxAmountPerMonth: $maxAmountPerMonth
|
||||||
|
maxPerCycle: $maxPerCycle
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
amount
|
||||||
|
name
|
||||||
|
memo
|
||||||
|
code
|
||||||
|
link
|
||||||
|
createdAt
|
||||||
|
validFrom
|
||||||
|
validTo
|
||||||
|
maxAmountPerMonth
|
||||||
|
cycle
|
||||||
|
maxPerCycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const updateContributionLink = gql`
|
||||||
|
mutation (
|
||||||
|
$amount: Decimal!
|
||||||
|
$name: String!
|
||||||
|
$memo: String!
|
||||||
|
$cycle: String!
|
||||||
|
$validFrom: String
|
||||||
|
$validTo: String
|
||||||
|
$maxAmountPerMonth: Decimal
|
||||||
|
$maxPerCycle: Int! = 1
|
||||||
|
$id: Int!
|
||||||
|
) {
|
||||||
|
updateContributionLink(
|
||||||
|
amount: $amount
|
||||||
|
name: $name
|
||||||
|
memo: $memo
|
||||||
|
cycle: $cycle
|
||||||
|
validFrom: $validFrom
|
||||||
|
validTo: $validTo
|
||||||
|
maxAmountPerMonth: $maxAmountPerMonth
|
||||||
|
maxPerCycle: $maxPerCycle
|
||||||
|
id: $id
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
amount
|
||||||
|
name
|
||||||
|
memo
|
||||||
|
code
|
||||||
|
link
|
||||||
|
createdAt
|
||||||
|
validFrom
|
||||||
|
validTo
|
||||||
|
maxAmountPerMonth
|
||||||
|
cycle
|
||||||
|
maxPerCycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const deleteContributionLink = gql`
|
||||||
|
mutation ($id: Int!) {
|
||||||
|
deleteContributionLink(id: $id)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -174,9 +174,9 @@ export const queryTransactionLink = gql`
|
|||||||
|
|
||||||
// from admin interface
|
// from admin interface
|
||||||
|
|
||||||
export const getPendingCreations = gql`
|
export const listUnconfirmedContributions = gql`
|
||||||
query {
|
query {
|
||||||
getPendingCreations {
|
listUnconfirmedContributions {
|
||||||
id
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
@ -218,3 +218,25 @@ export const listTransactionLinksAdmin = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const listContributionLinks = gql`
|
||||||
|
query ($pageSize: Int = 25, $currentPage: Int = 1, $order: Order) {
|
||||||
|
listContributionLinks(pageSize: $pageSize, currentPage: $currentPage, order: $order) {
|
||||||
|
links {
|
||||||
|
id
|
||||||
|
amount
|
||||||
|
name
|
||||||
|
memo
|
||||||
|
code
|
||||||
|
link
|
||||||
|
createdAt
|
||||||
|
validFrom
|
||||||
|
validTo
|
||||||
|
maxAmountPerMonth
|
||||||
|
cycle
|
||||||
|
maxPerCycle
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|||||||
@ -9,9 +9,11 @@ import { name, internet, datatype } from 'faker'
|
|||||||
import { users } from './users/index'
|
import { users } from './users/index'
|
||||||
import { creations } from './creation/index'
|
import { creations } from './creation/index'
|
||||||
import { transactionLinks } from './transactionLink/index'
|
import { transactionLinks } from './transactionLink/index'
|
||||||
|
import { contributionLinks } from './contributionLink/index'
|
||||||
import { userFactory } from './factory/user'
|
import { userFactory } from './factory/user'
|
||||||
import { creationFactory } from './factory/creation'
|
import { creationFactory } from './factory/creation'
|
||||||
import { transactionLinkFactory } from './factory/transactionLink'
|
import { transactionLinkFactory } from './factory/transactionLink'
|
||||||
|
import { contributionLinkFactory } from './factory/contributionLink'
|
||||||
import { entities } from '@entity/index'
|
import { entities } from '@entity/index'
|
||||||
import CONFIG from '@/config'
|
import CONFIG from '@/config'
|
||||||
|
|
||||||
@ -77,6 +79,11 @@ const run = async () => {
|
|||||||
await transactionLinkFactory(seedClient, transactionLinks[i])
|
await transactionLinkFactory(seedClient, transactionLinks[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create Contribution Links
|
||||||
|
for (let i = 0; i < contributionLinks.length; i++) {
|
||||||
|
await contributionLinkFactory(seedClient, contributionLinks[i])
|
||||||
|
}
|
||||||
|
|
||||||
await con.close()
|
await con.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import { readFileSync } from 'fs'
|
|||||||
|
|
||||||
const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8'))
|
const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8'))
|
||||||
|
|
||||||
options.categories.default.level = CONFIG.LOG_LEVEL
|
options.categories.backend.level = CONFIG.LOG_LEVEL
|
||||||
|
options.categories.apollo.level = CONFIG.LOG_LEVEL
|
||||||
|
|
||||||
log4js.configure(options)
|
log4js.configure(options)
|
||||||
|
|
||||||
|
|||||||
@ -37,9 +37,11 @@ ${mutation || query}variables: ${JSON.stringify(filterVariables(variables), null
|
|||||||
return {
|
return {
|
||||||
willSendResponse(requestContext: any) {
|
willSendResponse(requestContext: any) {
|
||||||
if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`)
|
if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`)
|
||||||
if (requestContext.response.data)
|
if (requestContext.response.data) {
|
||||||
logger.info(`Response-Data:
|
logger.info('Response Success!')
|
||||||
|
logger.trace(`Response-Data:
|
||||||
${JSON.stringify(requestContext.response.data, null, 2)}`)
|
${JSON.stringify(requestContext.response.data, null, 2)}`)
|
||||||
|
}
|
||||||
if (requestContext.response.errors)
|
if (requestContext.response.errors)
|
||||||
logger.error(`Response-Errors:
|
logger.error(`Response-Errors:
|
||||||
${JSON.stringify(requestContext.response.errors, null, 2)}`)
|
${JSON.stringify(requestContext.response.errors, null, 2)}`)
|
||||||
|
|||||||
48
database/entity/0039-contributions_table/Contribution.ts
Normal file
48
database/entity/0039-contributions_table/Contribution.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import Decimal from 'decimal.js-light'
|
||||||
|
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn, DeleteDateColumn } from 'typeorm'
|
||||||
|
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
|
||||||
|
|
||||||
|
@Entity('contributions')
|
||||||
|
export class Contribution extends BaseEntity {
|
||||||
|
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||||
|
id: number
|
||||||
|
|
||||||
|
@Column({ unsigned: true, nullable: false, name: 'user_id' })
|
||||||
|
userId: number
|
||||||
|
|
||||||
|
@Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' })
|
||||||
|
createdAt: Date
|
||||||
|
|
||||||
|
@Column({ type: 'datetime', nullable: false, name: 'contribution_date' })
|
||||||
|
contributionDate: Date
|
||||||
|
|
||||||
|
@Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||||
|
memo: string
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
type: 'decimal',
|
||||||
|
precision: 40,
|
||||||
|
scale: 20,
|
||||||
|
nullable: false,
|
||||||
|
transformer: DecimalTransformer,
|
||||||
|
})
|
||||||
|
amount: Decimal
|
||||||
|
|
||||||
|
@Column({ unsigned: true, nullable: true, name: 'moderator_id' })
|
||||||
|
moderatorId: number
|
||||||
|
|
||||||
|
@Column({ unsigned: true, nullable: true, name: 'contribution_link_id' })
|
||||||
|
contributionLinkId: number
|
||||||
|
|
||||||
|
@Column({ unsigned: true, nullable: true, name: 'confirmed_by' })
|
||||||
|
confirmedBy: number
|
||||||
|
|
||||||
|
@Column({ nullable: true, name: 'confirmed_at' })
|
||||||
|
confirmedAt: Date
|
||||||
|
|
||||||
|
@Column({ unsigned: true, nullable: true, name: 'transaction_id' })
|
||||||
|
transactionId: number
|
||||||
|
|
||||||
|
@DeleteDateColumn({ name: 'deleted_at' })
|
||||||
|
deletedAt: Date | null
|
||||||
|
}
|
||||||
1
database/entity/Contribution.ts
Normal file
1
database/entity/Contribution.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { Contribution } from './0039-contributions_table/Contribution'
|
||||||
@ -5,10 +5,10 @@ import { Migration } from './Migration'
|
|||||||
import { Transaction } from './Transaction'
|
import { Transaction } from './Transaction'
|
||||||
import { TransactionLink } from './TransactionLink'
|
import { TransactionLink } from './TransactionLink'
|
||||||
import { User } from './User'
|
import { User } from './User'
|
||||||
import { AdminPendingCreation } from './AdminPendingCreation'
|
import { Contribution } from './Contribution'
|
||||||
|
|
||||||
export const entities = [
|
export const entities = [
|
||||||
AdminPendingCreation,
|
Contribution,
|
||||||
ContributionLink,
|
ContributionLink,
|
||||||
LoginElopageBuys,
|
LoginElopageBuys,
|
||||||
LoginEmailOptIn,
|
LoginEmailOptIn,
|
||||||
|
|||||||
59
database/migrations/0039-contributions_table.ts
Normal file
59
database/migrations/0039-contributions_table.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* MIGRATION to rename ADMIN_PENDING_CREATION table and add columns
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||||
|
await queryFn('RENAME TABLE `admin_pending_creations` TO `contributions`;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `userId` `user_id` int(10);')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `created` `created_at` datetime;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `date` `contribution_date` datetime;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `moderator` `moderator_id` int(10);')
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `contributions` ADD COLUMN `contribution_link_id` int(10) unsigned DEFAULT NULL AFTER `moderator_id`;',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `contributions` ADD COLUMN `confirmed_by` int(10) unsigned DEFAULT NULL AFTER `contribution_link_id`;',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `contributions` ADD COLUMN `confirmed_at` datetime DEFAULT NULL AFTER `confirmed_by`;',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `contributions` ADD COLUMN `transaction_id` int(10) unsigned DEFAULT NULL AFTER `confirmed_at`;',
|
||||||
|
)
|
||||||
|
|
||||||
|
await queryFn(
|
||||||
|
'ALTER TABLE `contributions` ADD COLUMN `deleted_at` datetime DEFAULT NULL AFTER `confirmed_at`;',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||||
|
await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `deleted_at`;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `transaction_id`;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `confirmed_at`;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `confirmed_by`;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `contribution_link_id`;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `moderator_id` `moderator` int(10);')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `created_at` `created` datetime;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `contribution_date` `date` datetime;')
|
||||||
|
|
||||||
|
await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `user_id` `userId` int(10);')
|
||||||
|
|
||||||
|
await queryFn('RENAME TABLE `contributions` TO `admin_pending_creations`;')
|
||||||
|
}
|
||||||
@ -22,10 +22,11 @@ COMMUNITY_NAME="Gradido Development Stage1"
|
|||||||
COMMUNITY_URL=https://stage1.gradido.net/
|
COMMUNITY_URL=https://stage1.gradido.net/
|
||||||
COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register
|
COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register
|
||||||
COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code}
|
COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code}
|
||||||
|
COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code}
|
||||||
COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community"
|
COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community"
|
||||||
|
|
||||||
# backend
|
# backend
|
||||||
BACKEND_CONFIG_VERSION=v6.2022-04-21
|
BACKEND_CONFIG_VERSION=v7.2022-06-15
|
||||||
|
|
||||||
JWT_EXPIRES_IN=30m
|
JWT_EXPIRES_IN=30m
|
||||||
GDT_API_URL=https://gdt.gradido.net
|
GDT_API_URL=https://gdt.gradido.net
|
||||||
|
|||||||
@ -4615,20 +4615,10 @@ caniuse-api@^3.0.0:
|
|||||||
lodash.memoize "^4.1.2"
|
lodash.memoize "^4.1.2"
|
||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001280, caniuse-lite@^1.0.30001286:
|
||||||
version "1.0.30001251"
|
version "1.0.30001354"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001354.tgz"
|
||||||
integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==
|
integrity sha512-mImKeCkyGDAHNywYFA4bqnLAzTUvVkqPvhY4DV47X+Gl2c5Z8c3KNETnXp14GQt11LvxE8AwjzGxJ+rsikiOzg==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001280:
|
|
||||||
version "1.0.30001285"
|
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz#fe1e52229187e11d6670590790d669b9e03315b7"
|
|
||||||
integrity sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q==
|
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001286:
|
|
||||||
version "1.0.30001303"
|
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz#9b168e4f43ccfc372b86f4bc5a551d9b909c95c9"
|
|
||||||
integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ==
|
|
||||||
|
|
||||||
capture-exit@^2.0.0:
|
capture-exit@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user