mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
use findUserByIdentifier for emails, use it in send coins
This commit is contained in:
parent
4c15669c4b
commit
761ff80b97
@ -4,7 +4,7 @@ import Decimal from 'decimal.js-light'
|
|||||||
@ArgsType()
|
@ArgsType()
|
||||||
export default class TransactionSendArgs {
|
export default class TransactionSendArgs {
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
email: string
|
identifier: string
|
||||||
|
|
||||||
@Field(() => Decimal)
|
@Field(() => Decimal)
|
||||||
amount: Decimal
|
amount: Decimal
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import { User } from '@entity/User'
|
|||||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||||
import { logger } from '@test/testSetup'
|
import { logger } from '@test/testSetup'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { findUserByEmail } from './UserResolver'
|
|
||||||
|
|
||||||
let mutate: any, query: any, con: any
|
let mutate: any, query: any, con: any
|
||||||
let testEnv: any
|
let testEnv: any
|
||||||
@ -81,7 +80,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'wrong@email.com',
|
identifier: 'wrong@email.com',
|
||||||
amount: 100,
|
amount: 100,
|
||||||
memo: 'test',
|
memo: 'test',
|
||||||
},
|
},
|
||||||
@ -109,22 +108,20 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'stephen@hawking.uk',
|
identifier: 'stephen@hawking.uk',
|
||||||
amount: 100,
|
amount: 100,
|
||||||
memo: 'test',
|
memo: 'test',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).toEqual(
|
).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('The recipient account was deleted')],
|
errors: [new GraphQLError('No user to given contact')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('logs the error thrown', async () => {
|
it('logs the error thrown', () => {
|
||||||
// find peter to check the log
|
expect(logger.error).toBeCalledWith('No user to given contact', 'stephen@hawking.uk')
|
||||||
const user = await findUserByEmail('stephen@hawking.uk')
|
|
||||||
expect(logger.error).toBeCalledWith('The recipient account was deleted', user)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -140,22 +137,23 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'garrick@ollivander.com',
|
identifier: 'garrick@ollivander.com',
|
||||||
amount: 100,
|
amount: 100,
|
||||||
memo: 'test',
|
memo: 'test',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).toEqual(
|
).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('The recipient account is not activated')],
|
errors: [new GraphQLError('No user with this credentials')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('logs the error thrown', async () => {
|
it('logs the error thrown', () => {
|
||||||
// find peter to check the log
|
expect(logger.error).toBeCalledWith(
|
||||||
const user = await findUserByEmail('garrick@ollivander.com')
|
'No user with this credentials',
|
||||||
expect(logger.error).toBeCalledWith('The recipient account is not activated', user)
|
'garrick@ollivander.com',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -175,7 +173,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'bob@baumeister.de',
|
identifier: 'bob@baumeister.de',
|
||||||
amount: 100,
|
amount: 100,
|
||||||
memo: 'test',
|
memo: 'test',
|
||||||
},
|
},
|
||||||
@ -199,7 +197,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 100,
|
amount: 100,
|
||||||
memo: 'test',
|
memo: 'test',
|
||||||
},
|
},
|
||||||
@ -223,7 +221,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 100,
|
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',
|
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',
|
||||||
},
|
},
|
||||||
@ -247,7 +245,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 100,
|
amount: 100,
|
||||||
memo: 'testing',
|
memo: 'testing',
|
||||||
},
|
},
|
||||||
@ -297,7 +295,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: -50,
|
amount: -50,
|
||||||
memo: 'testing negative',
|
memo: 'testing negative',
|
||||||
},
|
},
|
||||||
@ -320,7 +318,7 @@ describe('send coins', () => {
|
|||||||
await mutate({
|
await mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 50,
|
amount: 50,
|
||||||
memo: 'unrepeatable memo',
|
memo: 'unrepeatable memo',
|
||||||
},
|
},
|
||||||
@ -375,7 +373,7 @@ describe('send coins', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 10,
|
amount: 10,
|
||||||
memo: 'first transaction',
|
memo: 'first transaction',
|
||||||
},
|
},
|
||||||
@ -391,7 +389,7 @@ describe('send coins', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 20,
|
amount: 20,
|
||||||
memo: 'second transaction',
|
memo: 'second transaction',
|
||||||
},
|
},
|
||||||
@ -407,7 +405,7 @@ describe('send coins', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 30,
|
amount: 30,
|
||||||
memo: 'third transaction',
|
memo: 'third transaction',
|
||||||
},
|
},
|
||||||
@ -423,7 +421,7 @@ describe('send coins', () => {
|
|||||||
mutate({
|
mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: {
|
variables: {
|
||||||
email: 'peter@lustig.de',
|
identifier: 'peter@lustig.de',
|
||||||
amount: 40,
|
amount: 40,
|
||||||
memo: 'fourth transaction',
|
memo: 'fourth transaction',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -34,7 +34,7 @@ import { EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Event
|
|||||||
|
|
||||||
import { BalanceResolver } from './BalanceResolver'
|
import { BalanceResolver } from './BalanceResolver'
|
||||||
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
|
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
|
||||||
import { findUserByEmail } from './UserResolver'
|
import { findUserByIdentifier } from './util/findUserByIdentifier'
|
||||||
|
|
||||||
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
|
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
|
||||||
import LogError from '@/server/LogError'
|
import LogError from '@/server/LogError'
|
||||||
@ -307,10 +307,9 @@ export class TransactionResolver {
|
|||||||
@Authorized([RIGHTS.SEND_COINS])
|
@Authorized([RIGHTS.SEND_COINS])
|
||||||
@Mutation(() => Boolean)
|
@Mutation(() => Boolean)
|
||||||
async sendCoins(
|
async sendCoins(
|
||||||
@Args() { email, amount, memo }: TransactionSendArgs,
|
@Args() { identifier, amount, memo }: TransactionSendArgs,
|
||||||
@Ctx() context: Context,
|
@Ctx() context: Context,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
logger.info(`sendCoins(email=${email}, amount=${amount}, memo=${memo})`)
|
|
||||||
if (amount.lte(0)) {
|
if (amount.lte(0)) {
|
||||||
throw new LogError('Amount to send must be positive', amount)
|
throw new LogError('Amount to send must be positive', amount)
|
||||||
}
|
}
|
||||||
@ -319,13 +318,9 @@ export class TransactionResolver {
|
|||||||
const senderUser = getUser(context)
|
const senderUser = getUser(context)
|
||||||
|
|
||||||
// validate recipient user
|
// validate recipient user
|
||||||
const recipientUser = await findUserByEmail(email)
|
const recipientUser = await findUserByIdentifier(identifier)
|
||||||
if (recipientUser.deletedAt) {
|
if (!recipientUser) {
|
||||||
throw new LogError('The recipient account was deleted', recipientUser)
|
throw new LogError('The recipient user was not found', recipientUser)
|
||||||
}
|
|
||||||
const emailContact = recipientUser.emailContact
|
|
||||||
if (!emailContact.emailChecked) {
|
|
||||||
throw new LogError('The recipient account is not activated', recipientUser)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await executeTransaction(amount, memo, senderUser, recipientUser)
|
await executeTransaction(amount, memo, senderUser, recipientUser)
|
||||||
|
|||||||
@ -2228,8 +2228,8 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('identifier is no gradido ID', () => {
|
describe('identifier is no gradido ID and no email', () => {
|
||||||
it('throws and logs "No valid gradido ID" error', async () => {
|
it('throws and logs "Unknown identifier type" error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
query: userQuery,
|
query: userQuery,
|
||||||
@ -2239,10 +2239,10 @@ describe('UserResolver', () => {
|
|||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
errors: [new GraphQLError('No valid gradido ID')],
|
errors: [new GraphQLError('Unknown identifier type')],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
expect(logger.error).toBeCalledWith('No valid gradido ID', 'identifier')
|
expect(logger.error).toBeCalledWith('Unknown identifier type', 'identifier')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -2267,7 +2267,30 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('identifier is found', () => {
|
describe('identifier is found via email', () => {
|
||||||
|
it('returns user', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: userQuery,
|
||||||
|
variables: {
|
||||||
|
identifier: 'bibi@bloxberg.de',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
firstName: 'Bibi',
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('identifier is found via gradidoID', () => {
|
||||||
it('returns user', async () => {
|
it('returns user', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
|
|||||||
@ -68,6 +68,7 @@ import { encryptPassword, verifyPassword } from '@/password/PasswordEncryptor'
|
|||||||
import { PasswordEncryptionType } from '../enum/PasswordEncryptionType'
|
import { PasswordEncryptionType } from '../enum/PasswordEncryptionType'
|
||||||
import LogError from '@/server/LogError'
|
import LogError from '@/server/LogError'
|
||||||
import { EventProtocolType } from '@/event/EventProtocolType'
|
import { EventProtocolType } from '@/event/EventProtocolType'
|
||||||
|
import { findUserByIdentifier } from './util/findUserByIdentifier'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const sodium = require('sodium-native')
|
const sodium = require('sodium-native')
|
||||||
@ -815,16 +816,8 @@ export class UserResolver {
|
|||||||
@Authorized([RIGHTS.USER])
|
@Authorized([RIGHTS.USER])
|
||||||
@Query(() => User, { nullable: true })
|
@Query(() => User, { nullable: true })
|
||||||
async user(@Arg('identifier') identifier: string): Promise<User | null> {
|
async user(@Arg('identifier') identifier: string): Promise<User | null> {
|
||||||
const isGradidoID =
|
const user = await findUserByIdentifier(identifier)
|
||||||
/^[0-9a-f]{8,8}-[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]{12,12}$/.exec(identifier)
|
return user ? new User(user) : null
|
||||||
if (!isGradidoID) {
|
|
||||||
throw new LogError('No valid gradido ID', identifier)
|
|
||||||
}
|
|
||||||
const user = await DbUser.findOne({ where: { gradidoID: identifier } })
|
|
||||||
if (!user) {
|
|
||||||
throw new LogError('No user found to given identifier', identifier)
|
|
||||||
}
|
|
||||||
return new User(user)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -152,7 +152,7 @@ describe('semaphore', () => {
|
|||||||
})
|
})
|
||||||
const bibisTransaction = mutate({
|
const bibisTransaction = mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: { email: 'bob@baumeister.de', amount: '50', memo: 'Das ist für dich, Bob' },
|
variables: { identifier: 'bob@baumeister.de', amount: '50', memo: 'Das ist für dich, Bob' },
|
||||||
})
|
})
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: login,
|
mutation: login,
|
||||||
@ -168,7 +168,7 @@ describe('semaphore', () => {
|
|||||||
})
|
})
|
||||||
const bobsTransaction = mutate({
|
const bobsTransaction = mutate({
|
||||||
mutation: sendCoins,
|
mutation: sendCoins,
|
||||||
variables: { email: 'bibi@bloxberg.de', amount: '50', memo: 'Das ist für dich, Bibi' },
|
variables: { identifier: 'bibi@bloxberg.de', amount: '50', memo: 'Das ist für dich, Bibi' },
|
||||||
})
|
})
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: login,
|
mutation: login,
|
||||||
|
|||||||
36
backend/src/graphql/resolver/util/findUserByIdentifier.ts
Normal file
36
backend/src/graphql/resolver/util/findUserByIdentifier.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { User as DbUser } from '@entity/User'
|
||||||
|
import { UserContact as DbUserContact } from '@entity/UserContact'
|
||||||
|
import LogError from '@/server/LogError'
|
||||||
|
|
||||||
|
export const findUserByIdentifier = async (identifier: string): Promise<DbUser | null> => {
|
||||||
|
let user: DbUser | undefined
|
||||||
|
if (
|
||||||
|
/^[0-9a-f]{8,8}-[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]{12,12}$/.exec(identifier)
|
||||||
|
) {
|
||||||
|
user = await DbUser.findOne({ where: { gradidoID: identifier } })
|
||||||
|
if (!user) {
|
||||||
|
throw new LogError('No user found to given identifier', identifier)
|
||||||
|
}
|
||||||
|
} else if (/^.{2,}@.{2,}\..{2,}$/.exec(identifier)) {
|
||||||
|
const userContact = await DbUserContact.findOne(
|
||||||
|
{
|
||||||
|
email: identifier,
|
||||||
|
emailChecked: true,
|
||||||
|
},
|
||||||
|
{ relations: ['user'] },
|
||||||
|
)
|
||||||
|
if (!userContact) {
|
||||||
|
throw new LogError('No user with this credentials', identifier)
|
||||||
|
}
|
||||||
|
if (!userContact.user) {
|
||||||
|
throw new LogError('No user to given contact', identifier)
|
||||||
|
}
|
||||||
|
user = userContact.user
|
||||||
|
user.emailContact = userContact
|
||||||
|
} else {
|
||||||
|
// last is alias when implemented
|
||||||
|
throw new LogError('Unknown identifier type', identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
@ -75,8 +75,8 @@ export const sendActivationEmail = gql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export const sendCoins = gql`
|
export const sendCoins = gql`
|
||||||
mutation ($email: String!, $amount: Decimal!, $memo: String!) {
|
mutation ($identifier: String!, $amount: Decimal!, $memo: String!) {
|
||||||
sendCoins(email: $email, amount: $amount, memo: $memo)
|
sendCoins(identifier: $identifier, amount: $amount, memo: $memo)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user