mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge pull request #3277 from gradido/frontend_send_routing
feat(frontend): use params instead of query for send/identifier route
This commit is contained in:
commit
1c9691a612
@ -27,7 +27,7 @@ DLT_CONNECTOR_URL=http://localhost:6010
|
||||
|
||||
# Community
|
||||
COMMUNITY_NAME=Gradido Entwicklung
|
||||
COMMUNITY_URL=http://localhost/
|
||||
COMMUNITY_URL=http://localhost
|
||||
COMMUNITY_REGISTER_PATH=/register
|
||||
COMMUNITY_REDEEM_PATH=/redeem/{code}
|
||||
COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code}
|
||||
|
||||
@ -12,7 +12,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0080-fill_linked_user_gradidoId_of_contributions',
|
||||
DB_VERSION: '0081-user_join_community',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
@ -3,11 +3,11 @@ import { ArgsType, Field } from 'type-graphql'
|
||||
|
||||
@ArgsType()
|
||||
export class UserArgs {
|
||||
@Field({ nullable: false })
|
||||
@Field()
|
||||
@IsString()
|
||||
identifier: string
|
||||
|
||||
@Field({ nullable: true })
|
||||
@Field()
|
||||
@IsString()
|
||||
communityIdentifier?: string
|
||||
communityIdentifier: string
|
||||
}
|
||||
|
||||
@ -10,6 +10,9 @@ export class User {
|
||||
this.id = user.id
|
||||
this.foreign = user.foreign
|
||||
this.communityUuid = user.communityUuid
|
||||
if (user.community) {
|
||||
this.communityName = user.community.name
|
||||
}
|
||||
this.gradidoID = user.gradidoID
|
||||
this.alias = user.alias
|
||||
if (user.emailContact) {
|
||||
|
||||
@ -142,7 +142,11 @@ describe('send coins', () => {
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('No user with this credentials', 'wrong@email.com')
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No user with this credentials',
|
||||
'wrong@email.com',
|
||||
homeCom.communityUuid,
|
||||
)
|
||||
})
|
||||
|
||||
describe('deleted recipient', () => {
|
||||
@ -165,13 +169,17 @@ describe('send coins', () => {
|
||||
}),
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('No user to given contact')],
|
||||
errors: [new GraphQLError('No user with this credentials')],
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error thrown', () => {
|
||||
expect(logger.error).toBeCalledWith('No user to given contact', 'stephen@hawking.uk')
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No user with this credentials',
|
||||
'stephen@hawking.uk',
|
||||
homeCom.communityUuid,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -204,6 +212,7 @@ describe('send coins', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No user with this credentials',
|
||||
'garrick@ollivander.com',
|
||||
homeCom.communityUuid,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -432,7 +432,7 @@ export class TransactionResolver {
|
||||
const senderUser = getUser(context)
|
||||
|
||||
if (!recipientCommunityIdentifier || (await isHomeCommunity(recipientCommunityIdentifier))) {
|
||||
// processing sendCoins within sender and recepient are both in home community
|
||||
// processing sendCoins within sender and recipient are both in home community
|
||||
const recipientUser = await findUserByIdentifier(
|
||||
recipientIdentifier,
|
||||
recipientCommunityIdentifier,
|
||||
|
||||
@ -2552,6 +2552,7 @@ describe('UserResolver', () => {
|
||||
query: userQuery,
|
||||
variables: {
|
||||
identifier: 'identifier',
|
||||
communityIdentifier: 'community identifier',
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
@ -2637,13 +2638,11 @@ describe('UserResolver', () => {
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [
|
||||
new GraphQLError('Found user to given contact, but belongs to other community'),
|
||||
],
|
||||
errors: [new GraphQLError('No user with this credentials')],
|
||||
}),
|
||||
)
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'Found user to given contact, but belongs to other community',
|
||||
'No user with this credentials',
|
||||
'bibi@bloxberg.de',
|
||||
foreignCom1.communityUuid,
|
||||
)
|
||||
|
||||
@ -65,7 +65,7 @@ import random from 'random-bigint'
|
||||
import { randombytes_random } from 'sodium-native'
|
||||
|
||||
import { FULL_CREATION_AVAILABLE } from './const/const'
|
||||
import { getCommunityName, getHomeCommunity } from './util/communities'
|
||||
import { getHomeCommunity } from './util/communities'
|
||||
import { getUserCreations } from './util/creations'
|
||||
import { findUserByIdentifier } from './util/findUserByIdentifier'
|
||||
import { findUsers } from './util/findUsers'
|
||||
@ -821,11 +821,6 @@ export class UserResolver {
|
||||
): Promise<User> {
|
||||
const foundDbUser = await findUserByIdentifier(identifier, communityIdentifier)
|
||||
const modelUser = new User(foundDbUser)
|
||||
if (!foundDbUser.communityUuid) {
|
||||
modelUser.communityName = (await Promise.resolve(getHomeCommunity())).name
|
||||
} else {
|
||||
modelUser.communityName = await getCommunityName(foundDbUser.communityUuid)
|
||||
}
|
||||
return modelUser
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { Community as DbCommunity } from '@entity/Community'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers'
|
||||
|
||||
@ -54,7 +55,7 @@ describe('semaphore', () => {
|
||||
beforeAll(async () => {
|
||||
const now = new Date()
|
||||
homeCom = DbCommunity.create()
|
||||
homeCom.communityUuid = 'homeCom-UUID'
|
||||
homeCom.communityUuid = uuidv4()
|
||||
homeCom.creationDate = new Date('2000-01-01')
|
||||
homeCom.description = 'homeCom description'
|
||||
homeCom.foreign = false
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { FindOptionsWhere } from '@dbTools/typeorm'
|
||||
import { Community } from '@entity/Community'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { UserContact as DbUserContact } from '@entity/UserContact'
|
||||
import { validate, version } from 'uuid'
|
||||
@ -6,15 +8,26 @@ import { LogError } from '@/server/LogError'
|
||||
|
||||
import { VALID_ALIAS_REGEX } from './validateAlias'
|
||||
|
||||
/**
|
||||
*
|
||||
* @param identifier could be gradidoID, alias or email of user
|
||||
* @param communityIdentifier could be uuid or name of community
|
||||
* @returns
|
||||
*/
|
||||
export const findUserByIdentifier = async (
|
||||
identifier: string,
|
||||
communityIdentifier?: string,
|
||||
communityIdentifier: string,
|
||||
): Promise<DbUser> => {
|
||||
let user: DbUser | null
|
||||
const communityWhere: FindOptionsWhere<Community> =
|
||||
validate(communityIdentifier) && version(communityIdentifier) === 4
|
||||
? { communityUuid: communityIdentifier }
|
||||
: { name: communityIdentifier }
|
||||
|
||||
if (validate(identifier) && version(identifier) === 4) {
|
||||
user = await DbUser.findOne({
|
||||
where: { gradidoID: identifier, communityUuid: communityIdentifier },
|
||||
relations: ['emailContact'],
|
||||
where: { gradidoID: identifier, community: communityWhere },
|
||||
relations: ['emailContact', 'community'],
|
||||
})
|
||||
if (!user) {
|
||||
throw new LogError('No user found to given identifier(s)', identifier, communityIdentifier)
|
||||
@ -24,28 +37,21 @@ export const findUserByIdentifier = async (
|
||||
where: {
|
||||
email: identifier,
|
||||
emailChecked: true,
|
||||
user: {
|
||||
community: communityWhere,
|
||||
},
|
||||
},
|
||||
relations: ['user'],
|
||||
relations: { user: { community: true } },
|
||||
})
|
||||
if (!userContact) {
|
||||
throw new LogError('No user with this credentials', identifier)
|
||||
}
|
||||
if (!userContact.user) {
|
||||
throw new LogError('No user to given contact', identifier)
|
||||
}
|
||||
if (userContact.user.communityUuid !== communityIdentifier) {
|
||||
throw new LogError(
|
||||
'Found user to given contact, but belongs to other community',
|
||||
identifier,
|
||||
communityIdentifier,
|
||||
)
|
||||
throw new LogError('No user with this credentials', identifier, communityIdentifier)
|
||||
}
|
||||
user = userContact.user
|
||||
user.emailContact = userContact
|
||||
} else if (VALID_ALIAS_REGEX.exec(identifier)) {
|
||||
user = await DbUser.findOne({
|
||||
where: { alias: identifier, communityUuid: communityIdentifier },
|
||||
relations: ['emailContact'],
|
||||
where: { alias: identifier, community: communityWhere },
|
||||
relations: ['emailContact', 'community'],
|
||||
})
|
||||
if (!user) {
|
||||
throw new LogError('No user found to given identifier(s)', identifier, communityIdentifier)
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
import { Connection } from '@dbTools/typeorm'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
|
||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||
|
||||
import { writeHomeCommunityEntry } from '@/seeds/community'
|
||||
import { userFactory } from '@/seeds/factory/user'
|
||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||
import { bobBaumeister } from '@/seeds/users/bob-baumeister'
|
||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
|
||||
import { findUserByIdentifier } from './findUserByIdentifier'
|
||||
|
||||
let con: Connection
|
||||
let testEnv: {
|
||||
mutate: ApolloServerTestClient['mutate']
|
||||
query: ApolloServerTestClient['query']
|
||||
con: Connection
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment()
|
||||
con = testEnv.con
|
||||
await cleanDB()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDB()
|
||||
await con.close()
|
||||
})
|
||||
|
||||
describe('graphql/resolver/util/findUserByIdentifier', () => {
|
||||
let homeCom: DbCommunity
|
||||
let communityUuid: string
|
||||
let communityName: string
|
||||
let userBibi: DbUser
|
||||
|
||||
beforeAll(async () => {
|
||||
homeCom = await writeHomeCommunityEntry()
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
communityUuid = homeCom.communityUuid!
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
communityName = homeCom.communityUuid!
|
||||
|
||||
userBibi = await userFactory(testEnv, bibiBloxberg)
|
||||
await userFactory(testEnv, peterLustig)
|
||||
await userFactory(testEnv, bobBaumeister)
|
||||
})
|
||||
|
||||
describe('communityIdentifier is community uuid', () => {
|
||||
it('userIdentifier is gradido id', async () => {
|
||||
const user = await findUserByIdentifier(userBibi.gradidoID, communityUuid)
|
||||
user.userRoles = []
|
||||
expect(user).toMatchObject(userBibi)
|
||||
})
|
||||
|
||||
it('userIdentifier is alias', async () => {
|
||||
const user = await findUserByIdentifier(userBibi.alias, communityUuid)
|
||||
user.userRoles = []
|
||||
expect(user).toMatchObject(userBibi)
|
||||
})
|
||||
|
||||
it('userIdentifier is email', async () => {
|
||||
const user = await findUserByIdentifier(userBibi.emailContact.email, communityUuid)
|
||||
user.userRoles = []
|
||||
expect(user).toMatchObject(userBibi)
|
||||
})
|
||||
})
|
||||
|
||||
describe('communityIdentifier is community name', () => {
|
||||
it('userIdentifier is gradido id', async () => {
|
||||
const user = await findUserByIdentifier(userBibi.gradidoID, communityName)
|
||||
user.userRoles = []
|
||||
expect(user).toMatchObject(userBibi)
|
||||
})
|
||||
|
||||
it('userIdentifier is alias', async () => {
|
||||
const user = await findUserByIdentifier(userBibi.alias, communityName)
|
||||
user.userRoles = []
|
||||
expect(user).toMatchObject(userBibi)
|
||||
})
|
||||
|
||||
it('userIdentifier is email', async () => {
|
||||
const user = await findUserByIdentifier(userBibi.emailContact.email, communityName)
|
||||
user.userRoles = []
|
||||
expect(user).toMatchObject(userBibi)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -370,7 +370,7 @@ export const adminListContributionMessages = gql`
|
||||
`
|
||||
|
||||
export const user = gql`
|
||||
query ($identifier: String!, $communityIdentifier: String) {
|
||||
query ($identifier: String!, $communityIdentifier: String!) {
|
||||
user(identifier: $identifier, communityIdentifier: $communityIdentifier) {
|
||||
firstName
|
||||
lastName
|
||||
|
||||
@ -4,6 +4,7 @@ export const bibiBloxberg: UserInterface = {
|
||||
email: 'bibi@bloxberg.de',
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
alias: 'BBB',
|
||||
// description: 'Hex Hex',
|
||||
emailChecked: true,
|
||||
language: 'de',
|
||||
|
||||
@ -50,6 +50,7 @@ const communityDbUser: dbUser = {
|
||||
},
|
||||
foreign: false,
|
||||
communityUuid: '55555555-4444-4333-2222-11111111',
|
||||
community: null,
|
||||
}
|
||||
const communityUser = new User(communityDbUser)
|
||||
|
||||
|
||||
70
database/entity/0081-user_join_community/Community.ts
Normal file
70
database/entity/0081-user_join_community/Community.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
} from 'typeorm'
|
||||
import { User } from '../User'
|
||||
|
||||
@Entity('communities')
|
||||
export class Community extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ name: 'foreign', type: 'bool', nullable: false, default: true })
|
||||
foreign: boolean
|
||||
|
||||
@Column({ name: 'url', length: 255, nullable: false })
|
||||
url: string
|
||||
|
||||
@Column({ name: 'public_key', type: 'binary', length: 32, nullable: false })
|
||||
publicKey: Buffer
|
||||
|
||||
@Column({ name: 'private_key', type: 'binary', length: 64, nullable: true })
|
||||
privateKey: Buffer | null
|
||||
|
||||
@Column({
|
||||
name: 'community_uuid',
|
||||
type: 'char',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
communityUuid: string | null
|
||||
|
||||
@Column({ name: 'authenticated_at', type: 'datetime', nullable: true })
|
||||
authenticatedAt: Date | null
|
||||
|
||||
@Column({ name: 'name', type: 'varchar', length: 40, nullable: true })
|
||||
name: string | null
|
||||
|
||||
@Column({ name: 'description', type: 'varchar', length: 255, nullable: true })
|
||||
description: string | null
|
||||
|
||||
@CreateDateColumn({ name: 'creation_date', type: 'datetime', nullable: true })
|
||||
creationDate: Date | null
|
||||
|
||||
@CreateDateColumn({
|
||||
name: 'created_at',
|
||||
type: 'datetime',
|
||||
default: () => 'CURRENT_TIMESTAMP(3)',
|
||||
nullable: false,
|
||||
})
|
||||
createdAt: Date
|
||||
|
||||
@UpdateDateColumn({
|
||||
name: 'updated_at',
|
||||
type: 'datetime',
|
||||
onUpdate: 'CURRENT_TIMESTAMP(3)',
|
||||
nullable: true,
|
||||
})
|
||||
updatedAt: Date | null
|
||||
|
||||
@OneToMany(() => User, (user) => user.community)
|
||||
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
|
||||
users: User[]
|
||||
}
|
||||
138
database/entity/0081-user_join_community/User.ts
Normal file
138
database/entity/0081-user_join_community/User.ts
Normal file
@ -0,0 +1,138 @@
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
OneToOne,
|
||||
ManyToOne,
|
||||
} from 'typeorm'
|
||||
import { Contribution } from '../Contribution'
|
||||
import { ContributionMessage } from '../ContributionMessage'
|
||||
import { UserContact } from '../UserContact'
|
||||
import { UserRole } from '../UserRole'
|
||||
import { Community } from '../Community'
|
||||
|
||||
@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
foreign: boolean
|
||||
|
||||
@Column({
|
||||
name: 'gradido_id',
|
||||
length: 36,
|
||||
nullable: false,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
gradidoID: string
|
||||
|
||||
@Column({
|
||||
name: 'community_uuid',
|
||||
type: 'char',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
communityUuid: string
|
||||
|
||||
@ManyToOne(() => Community, (community) => community.users)
|
||||
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
|
||||
community: Community | null
|
||||
|
||||
@Column({
|
||||
name: 'alias',
|
||||
length: 20,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
alias: string
|
||||
|
||||
@OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user)
|
||||
@JoinColumn({ name: 'email_id' })
|
||||
emailContact: UserContact
|
||||
|
||||
@Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null })
|
||||
emailId: number | null
|
||||
|
||||
@Column({
|
||||
name: 'first_name',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
firstName: string
|
||||
|
||||
@Column({
|
||||
name: 'last_name',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
lastName: string
|
||||
|
||||
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
|
||||
createdAt: Date
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
|
||||
deletedAt: Date | null
|
||||
|
||||
@Column({ type: 'bigint', default: 0, unsigned: true })
|
||||
password: BigInt
|
||||
|
||||
@Column({
|
||||
name: 'password_encryption_type',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: false,
|
||||
default: 0,
|
||||
})
|
||||
passwordEncryptionType: number
|
||||
|
||||
@Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false })
|
||||
language: string
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
hideAmountGDD: boolean
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
hideAmountGDT: boolean
|
||||
|
||||
@OneToMany(() => UserRole, (userRole) => userRole.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
userRoles: UserRole[]
|
||||
|
||||
@Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null })
|
||||
referrerId?: number | null
|
||||
|
||||
@Column({
|
||||
name: 'contribution_link_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
contributionLinkId?: number | null
|
||||
|
||||
@Column({ name: 'publisher_id', default: 0 })
|
||||
publisherId: number
|
||||
|
||||
@OneToMany(() => Contribution, (contribution) => contribution.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
contributions?: Contribution[]
|
||||
|
||||
@OneToMany(() => ContributionMessage, (message) => message.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
messages?: ContributionMessage[]
|
||||
|
||||
@OneToMany(() => UserContact, (userContact: UserContact) => userContact.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
userContacts?: UserContact[]
|
||||
}
|
||||
@ -1 +1 @@
|
||||
export { Community } from './0068-community_tables_public_key_length/Community'
|
||||
export { Community } from './0081-user_join_community/Community'
|
||||
|
||||
@ -1 +1 @@
|
||||
export { User } from './0073-introduce_foreign_user_in_users_table/User'
|
||||
export { User } from './0081-user_join_community/User'
|
||||
|
||||
11
database/migrations/0081-user_join_community.ts
Normal file
11
database/migrations/0081-user_join_community.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'ALTER TABLE users MODIFY community_uuid VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;',
|
||||
)
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'ALTER TABLE users MODIFY community_uuid VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;',
|
||||
)
|
||||
}
|
||||
@ -4,7 +4,7 @@ import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0080-fill_linked_user_gradidoId_of_contributions',
|
||||
DB_VERSION: '0081-user_join_community',
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
LOG_LEVEL: process.env.LOG_LEVEL ?? 'info',
|
||||
|
||||
@ -10,7 +10,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0080-fill_linked_user_gradidoId_of_contributions',
|
||||
DB_VERSION: '0081-user_join_community',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
@ -4,7 +4,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.{js,vue}', '!**/node_modules/**', '!**/?(*.)+(spec|test).js?(x)'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 95,
|
||||
lines: 94,
|
||||
},
|
||||
},
|
||||
moduleFileExtensions: [
|
||||
|
||||
@ -1,16 +1,23 @@
|
||||
<template>
|
||||
<div class="community-switch">
|
||||
<b-dropdown no-flip :text="value.name">
|
||||
<b-dropdown-item
|
||||
v-for="community in communities"
|
||||
@click.prevent="updateCommunity(community)"
|
||||
:key="community.id"
|
||||
:title="community.description"
|
||||
:active="value.uuid === community.uuid"
|
||||
>
|
||||
{{ community.name }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<div v-if="!validCommunityIdentifier">
|
||||
<b-dropdown no-flip :text="value.name">
|
||||
<b-dropdown-item
|
||||
v-for="community in communities"
|
||||
@click.prevent="updateCommunity(community)"
|
||||
:key="community.id"
|
||||
:title="community.description"
|
||||
:active="value.uuid === community.uuid"
|
||||
>
|
||||
{{ community.name }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
<div v-else class="mb-4 mt-2">
|
||||
<b-row>
|
||||
<b-col class="font-weight-bold" :title="value.description">{{ value.name }}</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -26,6 +33,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
communities: [],
|
||||
validCommunityIdentifier: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -33,6 +41,27 @@ export default {
|
||||
this.$emit('input', community)
|
||||
},
|
||||
setDefaultCommunity() {
|
||||
// when we already get an identifier via url we choose this if the community exist
|
||||
if (this.communityIdentifier && this.communities.length >= 1) {
|
||||
const foundCommunity = this.communities.find((community) => {
|
||||
if (
|
||||
community.uuid === this.communityIdentifier ||
|
||||
community.name === this.communityIdentifier
|
||||
) {
|
||||
this.validCommunityIdentifier = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if (foundCommunity) {
|
||||
this.updateCommunity(foundCommunity)
|
||||
return
|
||||
}
|
||||
this.toastError('invalid community identifier in url')
|
||||
}
|
||||
if (this.validCommunityIdentifier && !this.communityIdentifier) {
|
||||
this.validCommunityIdentifier = false
|
||||
}
|
||||
// set default community, the only one which isn't foreign
|
||||
// we assume it is only one entry with foreign = false
|
||||
if (this.value.uuid === '' && this.communities.length) {
|
||||
@ -48,12 +77,17 @@ export default {
|
||||
query: selectCommunities,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setDefaultCommunity()
|
||||
computed: {
|
||||
communityIdentifier() {
|
||||
return this.$route.params && this.$route.params.communityIdentifier
|
||||
},
|
||||
},
|
||||
updated() {
|
||||
this.setDefaultCommunity()
|
||||
},
|
||||
mounted() {
|
||||
this.setDefaultCommunity()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
@ -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 { userAndCommunity, selectCommunities as selectCommunitiesQuery } from '@/graphql/queries'
|
||||
import { user, selectCommunities as selectCommunitiesQuery } from '@/graphql/queries'
|
||||
|
||||
const mockClient = createMockClient()
|
||||
const apolloProvider = new VueApollo({
|
||||
@ -32,6 +32,9 @@ describe('TransactionForm', () => {
|
||||
params: {},
|
||||
query: {},
|
||||
},
|
||||
$router: {
|
||||
replace: jest.fn(),
|
||||
},
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
@ -47,23 +50,21 @@ describe('TransactionForm', () => {
|
||||
})
|
||||
}
|
||||
|
||||
const userAndCommunityMock = jest.fn()
|
||||
const userMock = jest.fn()
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
userAndCommunity,
|
||||
userAndCommunityMock
|
||||
.mockRejectedValueOnce({ message: 'Query user name fails!' })
|
||||
.mockResolvedValue({
|
||||
data: {
|
||||
user: {
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
},
|
||||
community: {
|
||||
name: 'Gradido Entwicklung',
|
||||
},
|
||||
user,
|
||||
userMock.mockRejectedValueOnce({ message: 'Query user name fails!' }).mockResolvedValue({
|
||||
data: {
|
||||
user: {
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
},
|
||||
}),
|
||||
community: {
|
||||
name: 'Gradido Entwicklung',
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
@ -410,7 +411,8 @@ Die ganze Welt bezwingen.“`)
|
||||
describe('with gradido ID', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
mocks.$route.query.gradidoID = 'gradido-ID'
|
||||
mocks.$route.params.userIdentifier = 'gradido-ID'
|
||||
mocks.$route.params.communityIdentifier = 'community-ID'
|
||||
wrapper = Wrapper()
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
@ -421,8 +423,9 @@ Die ganze Welt bezwingen.“`)
|
||||
})
|
||||
|
||||
it('queries the username', () => {
|
||||
expect(userAndCommunityMock).toBeCalledWith({
|
||||
expect(userMock).toBeCalledWith({
|
||||
identifier: 'gradido-ID',
|
||||
communityIdentifier: 'community-ID',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -55,22 +55,15 @@
|
||||
</b-row>
|
||||
<b-row>
|
||||
<b-col class="font-weight-bold">
|
||||
<div v-if="!communityUuid">
|
||||
<community-switch
|
||||
v-model="form.targetCommunity"
|
||||
:disabled="isBalanceDisabled"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="mb-4">
|
||||
<b-row>
|
||||
<b-col class="font-weight-bold">{{ recipientCommunity.name }}</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
<community-switch
|
||||
v-model="form.targetCommunity"
|
||||
:disabled="isBalanceDisabled"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-col>
|
||||
<b-col cols="12" v-if="radioSelected === sendTypes.send">
|
||||
<div v-if="!gradidoID">
|
||||
<div v-if="!userIdentifier">
|
||||
<input-identifier
|
||||
:name="$t('form.recipient')"
|
||||
:label="$t('form.recipient')"
|
||||
@ -150,8 +143,7 @@ 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 { userAndCommunity } from '@/graphql/queries'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { user } from '@/graphql/queries'
|
||||
import { COMMUNITY_NAME } from '@/config'
|
||||
|
||||
export default {
|
||||
@ -193,11 +185,7 @@ export default {
|
||||
this.$refs.formValidator.validate()
|
||||
},
|
||||
onSubmit() {
|
||||
if (this.gradidoID) this.form.identifier = this.gradidoID
|
||||
if (this.communityUuid) {
|
||||
this.recipientCommunity.uuid = this.communityUuid
|
||||
this.form.targetCommunity = this.recipientCommunity
|
||||
}
|
||||
if (this.userIdentifier) this.form.identifier = this.userIdentifier.identifier
|
||||
this.$emit('set-transaction', {
|
||||
selected: this.radioSelected,
|
||||
identifier: this.form.identifier,
|
||||
@ -214,29 +202,23 @@ export default {
|
||||
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 })
|
||||
this.$router.replace('/send')
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
UserName: {
|
||||
query() {
|
||||
return userAndCommunity
|
||||
return user
|
||||
},
|
||||
fetchPolicy: 'network-only',
|
||||
variables() {
|
||||
return {
|
||||
identifier: this.gradidoID,
|
||||
communityUuid: this.communityUuid,
|
||||
}
|
||||
return this.userIdentifier
|
||||
},
|
||||
skip() {
|
||||
return !this.gradidoID
|
||||
return !this.userIdentifier
|
||||
},
|
||||
update({ user, community }) {
|
||||
update({ user }) {
|
||||
this.userName = `${user.firstName} ${user.lastName}`
|
||||
this.recipientCommunity.name = community.name
|
||||
this.recipientCommunity.uuid = this.communityUuid
|
||||
},
|
||||
error({ message }) {
|
||||
this.toastError(message)
|
||||
@ -261,11 +243,18 @@ export default {
|
||||
sendTypes() {
|
||||
return SEND_TYPES
|
||||
},
|
||||
gradidoID() {
|
||||
return this.$route.query && this.$route.query.gradidoID
|
||||
},
|
||||
communityUuid() {
|
||||
return this.$route.query && this.$route.query.communityUuid
|
||||
userIdentifier() {
|
||||
if (
|
||||
this.$route.params &&
|
||||
this.$route.params.userIdentifier &&
|
||||
this.$route.params.communityIdentifier
|
||||
) {
|
||||
return {
|
||||
identifier: this.$route.params.userIdentifier,
|
||||
communityIdentifier: this.$route.params.communityIdentifier,
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@ -47,7 +47,12 @@ describe('Name', () => {
|
||||
describe('with linked user', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({
|
||||
linkedUser: { firstName: 'Bibi', lastName: 'Bloxberg', gradidoID: 'gradido-ID' },
|
||||
linkedUser: {
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
gradidoID: 'gradido-ID',
|
||||
communityUuid: 'community UUID',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@ -70,10 +75,11 @@ describe('Name', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('pushes query for gradidoID', () => {
|
||||
it('pushes params for gradidoID and community UUID', () => {
|
||||
expect(routerPushMock).toBeCalledWith({
|
||||
query: {
|
||||
gradidoID: 'gradido-ID',
|
||||
params: {
|
||||
communityIdentifier: 'community UUID',
|
||||
userIdentifier: 'gradido-ID',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@ -37,9 +37,9 @@ export default {
|
||||
async tunnelEmail() {
|
||||
if (this.$route.path !== '/send') await this.$router.push({ path: '/send' })
|
||||
this.$router.push({
|
||||
query: {
|
||||
gradidoID: this.linkedUser.gradidoID,
|
||||
communityUuid: this.linkedUser.communityUuid,
|
||||
params: {
|
||||
userIdentifier: this.linkedUser.gradidoID,
|
||||
communityIdentifier: this.linkedUser.communityUuid,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
@ -285,23 +285,10 @@ export const openCreations = gql`
|
||||
`
|
||||
|
||||
export const user = gql`
|
||||
query($identifier: String!) {
|
||||
user(identifier: $identifier) {
|
||||
firstName
|
||||
lastName
|
||||
communityName
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const userAndCommunity = gql`
|
||||
query($identifier: String!, $communityUuid: String!) {
|
||||
user(identifier: $identifier) {
|
||||
query($identifier: String!, $communityIdentifier: String!) {
|
||||
user(identifier: $identifier, communityIdentifier: $communityIdentifier) {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
community(communityUuid: $communityUuid) {
|
||||
name
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -29,6 +29,7 @@ describe('Login', () => {
|
||||
commit: mockStoreCommit,
|
||||
state: {
|
||||
publisherId: 12345,
|
||||
redirectPath: '/overview',
|
||||
},
|
||||
},
|
||||
$loading: {
|
||||
|
||||
@ -106,7 +106,7 @@ export default {
|
||||
if (this.$route.params.code) {
|
||||
this.$router.push(`/redeem/${this.$route.params.code}`)
|
||||
} else {
|
||||
this.$router.push('/overview')
|
||||
this.$router.push(this.$store.state.redirectPath)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@ -38,6 +38,7 @@ describe('Send', () => {
|
||||
},
|
||||
$route: {
|
||||
query: {},
|
||||
params: {},
|
||||
},
|
||||
$router: {
|
||||
push: routerPushMock,
|
||||
@ -175,7 +176,9 @@ describe('Send', () => {
|
||||
|
||||
describe('with gradidoID query', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$route.query.gradidoID = 'gradido-ID'
|
||||
jest.clearAllMocks()
|
||||
mocks.$route.params.userIdentifier = 'gradido-ID'
|
||||
mocks.$route.params.communityIdentifier = 'community-ID'
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
@ -226,11 +229,7 @@ describe('Send', () => {
|
||||
})
|
||||
|
||||
it('resets the gradido ID query in route', () => {
|
||||
expect(routerPushMock).toBeCalledWith({
|
||||
query: {
|
||||
gradidoID: undefined,
|
||||
},
|
||||
})
|
||||
expect(routerPushMock).toBeCalledWith('send')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -172,7 +172,7 @@ export default {
|
||||
throw new Error(`undefined transactionData.selected : ${this.transactionData.selected}`)
|
||||
}
|
||||
this.loading = false
|
||||
this.$router.push({ query: { gradidoID: undefined, communityUuid: undefined } })
|
||||
this.$router.push('send')
|
||||
},
|
||||
onBack() {
|
||||
this.currentTransactionStep = TRANSACTION_STEPS.transactionForm
|
||||
|
||||
@ -36,6 +36,8 @@ const addNavigationGuards = (router, store, apollo) => {
|
||||
// handle authentication
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.meta.requiresAuth && !store.state.token) {
|
||||
// store redirect path
|
||||
store.commit('redirectPath', to.path)
|
||||
next({ path: '/login' })
|
||||
} else {
|
||||
next()
|
||||
|
||||
@ -66,11 +66,11 @@ describe('router', () => {
|
||||
|
||||
describe('send', () => {
|
||||
it('requires authorization', () => {
|
||||
expect(routes.find((r) => r.path === '/send').meta.requiresAuth).toBeTruthy()
|
||||
expect(routes.find((r) => r.path.startsWith('/send')).meta.requiresAuth).toBeTruthy()
|
||||
})
|
||||
|
||||
it('loads the "Send" page', async () => {
|
||||
const component = await routes.find((r) => r.path === '/send').component()
|
||||
const component = await routes.find((r) => r.path.startsWith('/send')).component()
|
||||
expect(component.default.name).toBe('Send')
|
||||
})
|
||||
})
|
||||
|
||||
@ -19,7 +19,9 @@ const routes = [
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/send',
|
||||
// userIdentifier can be username, email or gradidoID
|
||||
// communityIdentifier can be community name or community UUID
|
||||
path: '/send/:communityIdentifier?/:userIdentifier?',
|
||||
component: () => import('@/pages/Send'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
|
||||
@ -58,6 +58,9 @@ export const mutations = {
|
||||
setDarkMode: (state, darkMode) => {
|
||||
state.darkMode = !!darkMode
|
||||
},
|
||||
redirectPath: (state, redirectPath) => {
|
||||
state.redirectPath = redirectPath || '/overview'
|
||||
},
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
@ -89,6 +92,7 @@ export const actions = {
|
||||
commit('hideAmountGDT', true)
|
||||
commit('email', '')
|
||||
commit('setDarkMode', false)
|
||||
commit('redirectPath', '/overview')
|
||||
localStorage.clear()
|
||||
},
|
||||
}
|
||||
@ -119,6 +123,7 @@ try {
|
||||
hideAmountGDT: null,
|
||||
email: '',
|
||||
darkMode: false,
|
||||
redirectPath: '/overview',
|
||||
},
|
||||
getters: {},
|
||||
// Syncronous mutation of the state
|
||||
|
||||
@ -264,7 +264,7 @@ describe('Vuex store', () => {
|
||||
|
||||
it('calls twelve commits', () => {
|
||||
logout({ commit, state })
|
||||
expect(commit).toHaveBeenCalledTimes(13)
|
||||
expect(commit).toHaveBeenCalledTimes(14)
|
||||
})
|
||||
|
||||
it('commits token', () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user