diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index c0e6d66f3..1f690a3d8 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -2,7 +2,6 @@ import { ObjectType, Field, Int } from 'type-graphql' import Decimal from 'decimal.js-light' import { Contribution as dbContribution } from '@entity/Contribution' import { User } from '@entity/User' -import { ContributionMessage } from './ContributionMessage' @ObjectType() export class Contribution { @@ -18,9 +17,7 @@ export class Contribution { this.confirmedBy = contribution.confirmedBy this.contributionDate = contribution.contributionDate this.state = contribution.contributionStatus - this.messages = contribution.messages - ? contribution.messages.map((message) => new ContributionMessage(message, message.user)) - : [] + this.messagesCount = contribution.messages ? contribution.messages.length : 0 } @Field(() => Number) @@ -53,8 +50,8 @@ export class Contribution { @Field(() => Date) contributionDate: Date - @Field(() => [ContributionMessage]) - messages: ContributionMessage[] + @Field(() => Number) + messagesCount: number @Field(() => String) state: string diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts new file mode 100644 index 000000000..c66a85700 --- /dev/null +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -0,0 +1,109 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ + +import { cleanDB, resetToken, testEnvironment } from '@test/helpers' +import { GraphQLError } from 'graphql' +import { createContributionMessage } from '@/seeds/graphql/mutations' +import { listContributionMessages, login } from '@/seeds/graphql/queries' +import { userFactory } from '@/seeds/factory/user' +import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' + +let mutate: any, query: any, con: any +let testEnv: any + +beforeAll(async () => { + testEnv = await testEnvironment() + mutate = testEnv.mutate + query = testEnv.query + con = testEnv.con + await cleanDB() +}) + +afterAll(async () => { + await cleanDB() + await con.close() +}) + +describe('ContributionMessageResolver', () => { + describe('createContributionMessage', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: createContributionMessage, + variables: { contributionId: 1, message: 'This is a test message' }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await cleanDB() + resetToken() + }) + + describe('input not valid', () => { + it('throws error when contribution does not exist', async () => { + await expect( + mutate({ + mutation: createContributionMessage, + variables: { + contributionId: -1, + message: 'Test', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Contribution not found')], + }), + ) + }) + }) + }) + }) + + describe('listContributionMessages', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: listContributionMessages, + variables: { contributionId: 1 }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await cleanDB() + resetToken() + }) + }) + }) +}) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index f8300f164..fc93880f1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -97,7 +97,6 @@ export class ContributionResolver { .select('c') .from(dbContribution, 'c') .leftJoinAndSelect('c.messages', 'm') - .leftJoinAndSelect('m.user', 'u') .where(where) .orderBy('c.createdAt', order) .limit(pageSize) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index bf898bd7d..e5f290645 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -261,3 +261,31 @@ export const deleteContribution = gql` deleteContribution(id: $id) } ` + +export const createContributionMessage = gql` + mutation ($contributionId: Float!, $message: String!) { + createContributionMessage(contributionId: $contributionId, message: $message) { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + } + } +` + +export const adminCreateContributionMessage = gql` + mutation ($contributionId: Float!, $message: String!) { + adminCreateContributionMessage(contributionId: $contributionId, message: $message) { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + } + } +` diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 3bd042ac2..60dffa21b 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -292,3 +292,26 @@ export const searchAdminUsers = gql` } } ` + +export const listContributionMessages = gql` + query ($contributionId: Float!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { + listContributionMessages( + contributionId: $contributionId + pageSize: $pageSize + currentPage: $currentPage + order: $order + ) { + count + messages { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + userId + } + } + } +` diff --git a/database/entity/0046-adapt_users_table_for_gradidoid/User.ts b/database/entity/0046-adapt_users_table_for_gradidoid/User.ts index a772a3c99..3f2547cad 100644 --- a/database/entity/0046-adapt_users_table_for_gradidoid/User.ts +++ b/database/entity/0046-adapt_users_table_for_gradidoid/User.ts @@ -8,7 +8,6 @@ import { JoinColumn, } from 'typeorm' import { Contribution } from '../Contribution' -import { ContributionMessage } from '../ContributionMessage' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -109,8 +108,4 @@ export class User extends BaseEntity { @OneToMany(() => Contribution, (contribution) => contribution.user) @JoinColumn({ name: 'user_id' }) contributions?: Contribution[] - - @OneToMany(() => ContributionMessage, (message) => message.user) - @JoinColumn({ name: 'user_id' }) - messages?: ContributionMessage[] } diff --git a/database/entity/0047-messages_tables/User.ts b/database/entity/0047-messages_tables/User.ts new file mode 100644 index 000000000..a772a3c99 --- /dev/null +++ b/database/entity/0047-messages_tables/User.ts @@ -0,0 +1,116 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'gradido_id', + length: 36, + nullable: false, + unique: true, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'alias', + length: 20, + nullable: true, + unique: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @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 + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null + + @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 + + @Column({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] + + @OneToMany(() => ContributionMessage, (message) => message.user) + @JoinColumn({ name: 'user_id' }) + messages?: ContributionMessage[] +} diff --git a/database/entity/User.ts b/database/entity/User.ts index 02a99fcd1..7d15bf559 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0046-adapt_users_table_for_gradidoid/User' +export { User } from './0047-messages_tables/User'