diff --git a/backend/src/graphql/arg/TransactionSendArgs.ts b/backend/src/graphql/arg/TransactionSendArgs.ts index 026a87eef..48827be8d 100644 --- a/backend/src/graphql/arg/TransactionSendArgs.ts +++ b/backend/src/graphql/arg/TransactionSendArgs.ts @@ -7,9 +7,13 @@ import { IsPositiveDecimal } from '@/graphql/validator/Decimal' @ArgsType() export class TransactionSendArgs { + @Field(() => String, { nullable: true }) + @IsString() + recipientCommunityIdentifier?: string | null | undefined + @Field(() => String) @IsString() - identifier: string + recipientIdentifier: string @Field(() => Decimal) @IsPositiveDecimal() diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 4b4101e66..0ded14405 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -12,7 +12,7 @@ import { ApolloServerTestClient } from 'apollo-server-testing' import { cleanDB, testEnvironment } from '@test/helpers' -import { getCommunities, getCommunitySelections } from '@/seeds/graphql/queries' +import { getCommunities, communities } from '@/seeds/graphql/queries' // to do: We need a setup for the tests that closes the connection let query: ApolloServerTestClient['query'], con: Connection @@ -234,7 +234,7 @@ describe('CommunityResolver', () => { }) }) - describe('getCommunitySelections', () => { + describe('communities', () => { let homeCom1: DbCommunity let foreignCom1: DbCommunity let foreignCom2: DbCommunity @@ -248,9 +248,9 @@ describe('CommunityResolver', () => { it('returns no community entry', async () => { // const result: Community[] = await query({ query: getCommunities }) // expect(result.length).toEqual(0) - await expect(query({ query: getCommunitySelections })).resolves.toMatchObject({ + await expect(query({ query: communities })).resolves.toMatchObject({ data: { - getCommunitySelections: [], + communities: [], }, }) }) @@ -275,9 +275,9 @@ describe('CommunityResolver', () => { }) it('returns 1 home-community entry', async () => { - await expect(query({ query: getCommunitySelections })).resolves.toMatchObject({ + await expect(query({ query: communities })).resolves.toMatchObject({ data: { - getCommunitySelections: [ + communities: [ { id: expect.any(Number), foreign: homeCom1.foreign, @@ -337,9 +337,9 @@ describe('CommunityResolver', () => { }) it('returns 3 community entries', async () => { - await expect(query({ query: getCommunitySelections })).resolves.toMatchObject({ + await expect(query({ query: communities })).resolves.toMatchObject({ data: { - getCommunitySelections: [ + communities: [ { id: expect.any(Number), foreign: homeCom1.foreign, diff --git a/backend/src/graphql/resolver/CommunityResolver.ts b/backend/src/graphql/resolver/CommunityResolver.ts index 4c6c8e785..09553bf24 100644 --- a/backend/src/graphql/resolver/CommunityResolver.ts +++ b/backend/src/graphql/resolver/CommunityResolver.ts @@ -26,7 +26,7 @@ export class CommunityResolver { @Authorized([RIGHTS.COMMUNITIES]) @Query(() => [Community]) - async getCommunitySelections(): Promise { + async communities(): Promise { const dbCommunities: DbCommunity[] = await DbCommunity.find({ order: { name: 'ASC', diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 5650015c3..bd7d0f2a8 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -91,7 +91,7 @@ describe('send coins', () => { await mutate({ mutation: sendCoins, variables: { - identifier: 'wrong@email.com', + recipientIdentifier: 'wrong@email.com', amount: 100, memo: 'test test', }, @@ -119,7 +119,7 @@ describe('send coins', () => { await mutate({ mutation: sendCoins, variables: { - identifier: 'stephen@hawking.uk', + recipientIdentifier: 'stephen@hawking.uk', amount: 100, memo: 'test test', }, @@ -148,7 +148,7 @@ describe('send coins', () => { await mutate({ mutation: sendCoins, variables: { - identifier: 'garrick@ollivander.com', + recipientIdentifier: 'garrick@ollivander.com', amount: 100, memo: 'test test', }, @@ -184,7 +184,7 @@ describe('send coins', () => { await mutate({ mutation: sendCoins, variables: { - identifier: 'bob@baumeister.de', + recipientIdentifier: 'bob@baumeister.de', amount: 100, memo: 'test test', }, @@ -207,7 +207,7 @@ describe('send coins', () => { const { errors: errorObjects } = await mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 100, memo: 'Test', }, @@ -238,7 +238,7 @@ describe('send coins', () => { const { errors: errorObjects } = await mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 100, memo: 'test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test t', }, @@ -270,7 +270,7 @@ describe('send coins', () => { await mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 100, memo: 'testing', }, @@ -319,7 +319,7 @@ describe('send coins', () => { const { errors: errorObjects } = await mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: -50, memo: 'testing negative', }, @@ -350,7 +350,7 @@ describe('send coins', () => { await mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 50, memo: 'unrepeatable memo', }, @@ -456,7 +456,7 @@ describe('send coins', () => { mutate({ mutation: sendCoins, variables: { - identifier: peter?.gradidoID, + recipientIdentifier: peter?.gradidoID, amount: 10, memo: 'send via gradido ID', }, @@ -496,7 +496,7 @@ describe('send coins', () => { mutate({ mutation: sendCoins, variables: { - identifier: 'bob', + recipientIdentifier: 'bob', amount: 6.66, memo: 'send via alias', }, @@ -564,7 +564,7 @@ describe('send coins', () => { mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 10, memo: 'first transaction', }, @@ -580,7 +580,7 @@ describe('send coins', () => { mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 20, memo: 'second transaction', }, @@ -596,7 +596,7 @@ describe('send coins', () => { mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 30, memo: 'third transaction', }, @@ -612,7 +612,7 @@ describe('send coins', () => { mutate({ mutation: sendCoins, variables: { - identifier: 'peter@lustig.de', + recipientIdentifier: 'peter@lustig.de', amount: 40, memo: 'fourth transaction', }, diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 9ec8ff7b3..32b453ae1 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -308,15 +308,18 @@ export class TransactionResolver { @Authorized([RIGHTS.SEND_COINS]) @Mutation(() => Boolean) async sendCoins( - @Args() { identifier, amount, memo }: TransactionSendArgs, + @Args() + { /* recipientCommunityIdentifier, */ recipientIdentifier, amount, memo }: TransactionSendArgs, @Ctx() context: Context, ): Promise { - logger.info(`sendCoins(identifier=${identifier}, amount=${amount}, memo=${memo})`) + logger.info( + `sendCoins(recipientIdentifier=${recipientIdentifier}, amount=${amount}, memo=${memo})`, + ) const senderUser = getUser(context) // validate recipient user - const recipientUser = await findUserByIdentifier(identifier) + const recipientUser = await findUserByIdentifier(recipientIdentifier) if (!recipientUser) { throw new LogError('The recipient user was not found', recipientUser) } diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 366b94d72..37331d832 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -156,7 +156,11 @@ describe('semaphore', () => { }) const bibisTransaction = mutate({ mutation: sendCoins, - variables: { identifier: 'bob@baumeister.de', amount: '50', memo: 'Das ist für dich, Bob' }, + variables: { + recipientIdentifier: 'bob@baumeister.de', + amount: '50', + memo: 'Das ist für dich, Bob', + }, }) await mutate({ mutation: login, @@ -172,7 +176,11 @@ describe('semaphore', () => { }) const bobsTransaction = mutate({ mutation: sendCoins, - variables: { identifier: 'bibi@bloxberg.de', amount: '50', memo: 'Das ist für dich, Bibi' }, + variables: { + recipientIdentifier: 'bibi@bloxberg.de', + amount: '50', + memo: 'Das ist für dich, Bibi', + }, }) await mutate({ mutation: login, diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 87231531f..965b52bec 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -79,8 +79,8 @@ export const sendActivationEmail = gql` ` export const sendCoins = gql` - mutation ($identifier: String!, $amount: Decimal!, $memo: String!) { - sendCoins(identifier: $identifier, amount: $amount, memo: $memo) + mutation ($recipientIdentifier: String!, $amount: Decimal!, $memo: String!) { + sendCoins(recipientIdentifier: $recipientIdentifier, amount: $amount, memo: $memo) } ` diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 949ed86d7..b7ef87aa8 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -118,25 +118,17 @@ export const listGDTEntriesQuery = gql` } ` -export const communityInfo = gql` - query { - getCommunityInfo { - name - description - registerUrl - url - } - } -` - export const communities = gql` query { communities { id + foreign name - url description - registerUrl + url + creationDate + uuid + authenticatedAt } } ` @@ -157,21 +149,6 @@ export const getCommunities = gql` } ` -export const getCommunitySelections = gql` - query { - getCommunitySelections { - id - foreign - name - description - url - creationDate - uuid - authenticatedAt - } - } -` - export const queryTransactionLink = gql` query ($code: String!) { queryTransactionLink(code: $code) { diff --git a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts index f3bcfe36c..a114c20c5 100644 --- a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts @@ -49,8 +49,13 @@ When('the user submits the transaction by confirming', () => { cy.wrap(interception.request.body).should( 'have.property', 'query', - `mutation ($identifier: String!, $amount: Decimal!, $memo: String!) { - sendCoins(identifier: $identifier, amount: $amount, memo: $memo) + `mutation ($recipientCommunityIdentifier: String!, $recipientIdentifier: String!, $amount: Decimal!, $memo: String!) { + sendCoins( + recipientCommunityIdentifier: $recipientCommunityIdentifier + recipientIdentifier: $recipientIdentifier + amount: $amount + memo: $memo + ) } `, ) diff --git a/frontend/src/components/CommunitySwitch.vue b/frontend/src/components/CommunitySwitch.vue new file mode 100644 index 000000000..dd4b159aa --- /dev/null +++ b/frontend/src/components/CommunitySwitch.vue @@ -0,0 +1,58 @@ + + diff --git a/frontend/src/components/GddSend/TransactionConfirmationSend.vue b/frontend/src/components/GddSend/TransactionConfirmationSend.vue index 95a06ea3c..caa40d128 100644 --- a/frontend/src/components/GddSend/TransactionConfirmationSend.vue +++ b/frontend/src/components/GddSend/TransactionConfirmationSend.vue @@ -6,7 +6,7 @@ {{ $t('form.recipientCommunity') }} - {{ communityName }} + {{ targetCommunity.name }} {{ $t('form.recipient') }} @@ -76,11 +76,16 @@ export default { amount: { type: Number, required: true }, memo: { type: String, required: true }, userName: { type: String, default: '' }, + targetCommunity: { + type: Object, + default: function () { + return { uuid: '', name: COMMUNITY_NAME } + }, + }, }, data() { return { disabled: false, - communityName: COMMUNITY_NAME, } }, } diff --git a/frontend/src/components/GddSend/TransactionForm.spec.js b/frontend/src/components/GddSend/TransactionForm.spec.js index e4cee20be..bc9dfa93f 100644 --- a/frontend/src/components/GddSend/TransactionForm.spec.js +++ b/frontend/src/components/GddSend/TransactionForm.spec.js @@ -4,7 +4,7 @@ import flushPromises from 'flush-promises' import { SEND_TYPES } from '@/pages/Send' import { createMockClient } from 'mock-apollo-client' import VueApollo from 'vue-apollo' -import { user as userQuery } from '@/graphql/queries' +import { user as userQuery, selectCommunities as selectCommunitiesQuery } from '@/graphql/queries' const mockClient = createMockClient() const apolloProvider = new VueApollo({ @@ -61,6 +61,28 @@ describe('TransactionForm', () => { }), ) + mockClient.setRequestHandler( + selectCommunitiesQuery, + jest.fn().mockResolvedValue({ + data: { + communities: [ + { + uuid: '8f4c146a-79b5-413f-89ed-53f624ec49b2', + name: 'Gradido Entwicklung', + description: 'Gradido-Community einer lokalen Entwicklungsumgebung.', + foreign: false, + }, + { + uuid: 'ashasas', + name: 'Hunde-Community', + description: 'Hier geht es um Hunde', + foreign: true, + }, + ], + }, + }), + ) + describe('mount', () => { beforeEach(() => { wrapper = Wrapper() @@ -352,6 +374,12 @@ Die ganze Welt bezwingen.“`) memo: 'Long enough', selected: 'send', userName: '', + targetCommunity: { + description: 'Gradido-Community einer lokalen Entwicklungsumgebung.', + foreign: false, + name: 'Gradido Entwicklung', + uuid: '8f4c146a-79b5-413f-89ed-53f624ec49b2', + }, }, ], ]) diff --git a/frontend/src/components/GddSend/TransactionForm.vue b/frontend/src/components/GddSend/TransactionForm.vue index d5b67d547..7304137ee 100644 --- a/frontend/src/components/GddSend/TransactionForm.vue +++ b/frontend/src/components/GddSend/TransactionForm.vue @@ -54,7 +54,12 @@ {{ $t('form.recipientCommunity') }} - {{ communityName }} + + + @@ -137,6 +142,7 @@ import { SEND_TYPES } from '@/pages/Send' import InputIdentifier from '@/components/Inputs/InputIdentifier' import InputAmount from '@/components/Inputs/InputAmount' import InputTextarea from '@/components/Inputs/InputTextarea' +import CommunitySwitch from '@/components/CommunitySwitch.vue' import { user as userQuery } from '@/graphql/queries' import { isEmpty } from 'lodash' import { COMMUNITY_NAME } from '@/config' @@ -147,6 +153,7 @@ export default { InputIdentifier, InputAmount, InputTextarea, + CommunitySwitch, }, props: { balance: { type: Number, default: 0 }, @@ -154,6 +161,12 @@ export default { amount: { type: Number, default: 0 }, memo: { type: String, default: '' }, selected: { type: String, default: 'send' }, + targetCommunity: { + type: Object, + default: function () { + return { uuid: '', name: COMMUNITY_NAME } + }, + }, }, data() { return { @@ -161,10 +174,10 @@ export default { identifier: this.identifier, amount: this.amount ? String(this.amount) : '', memo: this.memo, + targetCommunity: this.targetCommunity, }, radioSelected: this.selected, userName: '', - communityName: COMMUNITY_NAME, } }, methods: { @@ -179,6 +192,7 @@ export default { amount: Number(this.form.amount.replace(',', '.')), memo: this.form.memo, userName: this.userName, + targetCommunity: this.form.targetCommunity, }) }, onReset(event) { @@ -186,6 +200,7 @@ export default { this.form.identifier = '' this.form.amount = '' this.form.memo = '' + this.form.targetCommunity = { uuid: '', name: COMMUNITY_NAME } this.$refs.formValidator.validate() if (this.$route.query && !isEmpty(this.$route.query)) this.$router.replace({ query: undefined }) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index 2f6b53ac9..b4f96179f 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -71,8 +71,18 @@ export const createUser = gql` ` export const sendCoins = gql` - mutation($identifier: String!, $amount: Decimal!, $memo: String!) { - sendCoins(identifier: $identifier, amount: $amount, memo: $memo) + mutation( + $recipientCommunityIdentifier: String! + $recipientIdentifier: String! + $amount: Decimal! + $memo: String! + ) { + sendCoins( + recipientCommunityIdentifier: $recipientCommunityIdentifier + recipientIdentifier: $recipientIdentifier + amount: $amount + memo: $memo + ) } ` diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index c7e1e9067..6ef5d56d6 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -72,14 +72,13 @@ export const listGDTEntriesQuery = gql` } ` -export const communities = gql` +export const selectCommunities = gql` query { communities { - id + uuid name - url description - registerUrl + foreign } } ` diff --git a/frontend/src/pages/Send.spec.js b/frontend/src/pages/Send.spec.js index 1001d0c58..9427e32f8 100644 --- a/frontend/src/pages/Send.spec.js +++ b/frontend/src/pages/Send.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils' -import Send, { SEND_TYPES } from './Send' +import Send from './Send' import { toastErrorSpy, toastSuccessSpy } from '@test/testSetup' import { TRANSACTION_STEPS } from '@/components/GddSend' import { sendCoins, createTransactionLink } from '@/graphql/mutations.js' @@ -118,11 +118,10 @@ describe('Send', () => { expect.objectContaining({ mutation: sendCoins, variables: { - identifier: 'user@example.org', + recipientIdentifier: 'user@example.org', amount: 23.45, memo: 'Make the best of it!', - selected: SEND_TYPES.send, - userName: '', + recipientCommunityIdentifier: '', }, }), ) @@ -217,11 +216,10 @@ describe('Send', () => { expect.objectContaining({ mutation: sendCoins, variables: { - identifier: 'gradido-ID', + recipientIdentifier: 'gradido-ID', amount: 34.56, memo: 'Make the best of it!', - selected: SEND_TYPES.send, - userName: '', + recipientCommunityIdentifier: '', }, }), ) diff --git a/frontend/src/pages/Send.vue b/frontend/src/pages/Send.vue index 30ffc06ed..607c7e36c 100644 --- a/frontend/src/pages/Send.vue +++ b/frontend/src/pages/Send.vue @@ -122,7 +122,13 @@ export default { this.$apollo .mutate({ mutation: sendCoins, - variables: this.transactionData, + variables: { + // from target community we need only the uuid + recipientCommunityIdentifier: this.transactionData.targetCommunity.uuid, + recipientIdentifier: this.transactionData.identifier, + amount: this.transactionData.amount, + memo: this.transactionData.memo, + }, }) .then(() => { this.error = false