Merge branch '2131-crud-for-messages' into Contribution-Messages

This commit is contained in:
ogerly 2022-08-24 14:50:03 +02:00
commit 95abc61964
9 changed files with 178 additions and 5 deletions

View File

@ -33,6 +33,7 @@ export enum RIGHTS {
LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
COMMUNITY_STATISTICS = 'COMMUNITY_STATISTICS',
SEARCH_ADMIN_USERS = 'SEARCH_ADMIN_USERS',
CREATE_CONTRIBUTION_MESSAGE = 'CREATE_CONTRIBUTION_MESSAGE',
// Admin
SEARCH_USERS = 'SEARCH_USERS',
SET_USER_ROLE = 'SET_USER_ROLE',
@ -50,4 +51,5 @@ export enum RIGHTS {
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE',
}

View File

@ -31,6 +31,7 @@ export const ROLE_USER = new Role('user', [
RIGHTS.SEARCH_ADMIN_USERS,
RIGHTS.LIST_CONTRIBUTION_LINKS,
RIGHTS.COMMUNITY_STATISTICS,
RIGHTS.CREATE_CONTRIBUTION_MESSAGE,
])
export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights

View File

@ -0,0 +1,11 @@
import { ArgsType, Field, InputType } from 'type-graphql'
@InputType()
@ArgsType()
export default class ContributionMessageArgs {
@Field(() => Number)
contributionId: number
@Field(() => String)
message: string
}

View File

@ -1,7 +1,8 @@
import { ObjectType, Field, Int } from 'type-graphql'
import Decimal from 'decimal.js-light'
import { Contribution as dbContribution } from '@entity/Contribution'
import { User } from './User'
import { User } from '@entity/User'
import { ContributionMessage } from './ContributionMessage'
@ObjectType()
export class Contribution {
@ -16,6 +17,10 @@ export class Contribution {
this.confirmedAt = contribution.confirmedAt
this.confirmedBy = contribution.confirmedBy
this.contributionDate = contribution.contributionDate
this.state = contribution.contributionStatus
this.messages = contribution.messages
? contribution.messages.map((message) => new ContributionMessage(message, user))
: []
}
@Field(() => Number)
@ -47,6 +52,12 @@ export class Contribution {
@Field(() => Date)
contributionDate: Date
@Field(() => [ContributionMessage])
messages: ContributionMessage[]
@Field(() => String)
state: string
}
@ObjectType()

View File

@ -0,0 +1,37 @@
import { Field, ObjectType } from 'type-graphql'
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
import { User } from '@entity/User'
@ObjectType()
export class ContributionMessage {
constructor(contributionMessage: DbContributionMessage, user: User) {
this.id = contributionMessage.id
this.message = contributionMessage.message
this.createdAt = contributionMessage.createdAt
this.updatedAt = contributionMessage.updatedAt
this.type = contributionMessage.type
this.userFirstName = user.firstName
this.userLastName = user.lastName
}
@Field(() => Number)
id: number
@Field(() => String)
message: string
@Field(() => Date)
createdAt: Date
@Field(() => Date, { nullable: true })
updatedAt?: Date | null
@Field(() => String)
type: string
@Field(() => String, { nullable: true })
userFirstName: string | null
@Field(() => String, { nullable: true })
userLastName: string | null
}

View File

@ -62,6 +62,10 @@ import {
MEMO_MAX_CHARS,
MEMO_MIN_CHARS,
} from './const/const'
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
import ContributionMessageArgs from '@arg/ContributionMessageArgs'
import { ContributionMessageType } from '@enum/MessageType'
import { ContributionMessage } from '@model/ContributionMessage'
// const EMAIL_OPT_IN_REGISTER = 1
// const EMAIL_OPT_UNKNOWN = 3 // elopage?
@ -696,4 +700,46 @@ export class AdminResolver {
logger.debug(`updateContributionLink successful!`)
return new ContributionLink(dbContributionLink)
}
@Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTION_MESSAGE])
@Mutation(() => ContributionMessage)
async adminCreateContributionMessage(
@Args() { contributionId, message }: ContributionMessageArgs,
@Ctx() context: Context,
): Promise<ContributionMessage> {
const user = getUser(context)
const queryRunner = getConnection().createQueryRunner()
await queryRunner.connect()
await queryRunner.startTransaction('READ UNCOMMITTED')
const contributionMessage = DbContributionMessage.create()
try {
const contribution = await Contribution.findOne({ id: contributionId })
if (!contribution) {
throw new Error('Contribution not found')
}
contributionMessage.contributionId = contributionId
contributionMessage.createdAt = new Date()
contributionMessage.message = message
contributionMessage.userId = user.id
contributionMessage.type = ContributionMessageType.DIALOG
await queryRunner.manager.insert(DbContributionMessage, contributionMessage)
if (
contribution.contributionStatus === ContributionStatus.DELETED ||
contribution.contributionStatus === ContributionStatus.DENIED ||
contribution.contributionStatus === ContributionStatus.PENDING
) {
contribution.contributionStatus = ContributionStatus.IN_PROGRESS
await queryRunner.manager.update(Contribution, { id: contributionId }, contribution)
}
await queryRunner.commitTransaction()
} catch (e) {
await queryRunner.rollbackTransaction()
logger.error(`ContributionMessage was not successful: ${e}`)
throw new Error(`ContributionMessage was not successful: ${e}`)
} finally {
await queryRunner.release()
}
return new ContributionMessage(contributionMessage, user)
}
}

View File

@ -0,0 +1,56 @@
import { backendLogger as logger } from '@/server/logger'
import { RIGHTS } from '@/auth/RIGHTS'
import { Context, getUser } from '@/server/context'
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
import { Args, Authorized, Ctx, Mutation, Resolver } from 'type-graphql'
import ContributionMessageArgs from '@arg/ContributionMessageArgs'
import { Contribution } from '@entity/Contribution'
import { ContributionMessageType } from '@enum/MessageType'
import { ContributionStatus } from '@enum/ContributionStatus'
import { getConnection } from '@dbTools/typeorm'
import { ContributionMessage } from '@model/ContributionMessage'
@Resolver()
export class ContributionMessageResolver {
@Authorized([RIGHTS.CREATE_CONTRIBUTION_MESSAGE])
@Mutation(() => ContributionMessage)
async createContributionMessage(
@Args() { contributionId, message }: ContributionMessageArgs,
@Ctx() context: Context,
): Promise<ContributionMessage> {
const user = getUser(context)
const queryRunner = getConnection().createQueryRunner()
await queryRunner.connect()
await queryRunner.startTransaction('READ UNCOMMITTED')
const contributionMessage = DbContributionMessage.create()
try {
const contribution = await Contribution.findOne({ id: contributionId })
if (!contribution) {
throw new Error('Contribution not found')
}
if (contribution.userId !== user.id) {
throw new Error('Can not send message to contribution of another user')
}
contributionMessage.contributionId = contributionId
contributionMessage.createdAt = new Date()
contributionMessage.message = message
contributionMessage.userId = user.id
contributionMessage.type = ContributionMessageType.DIALOG
await queryRunner.manager.insert(DbContributionMessage, contributionMessage)
if (contribution.contributionStatus === ContributionStatus.IN_PROGRESS) {
contribution.contributionStatus = ContributionStatus.PENDING
await queryRunner.manager.update(Contribution, { id: contributionId }, contribution)
}
await queryRunner.commitTransaction()
} catch (e) {
await queryRunner.rollbackTransaction()
logger.error(`ContributionMessage was not successful: ${e}`)
throw new Error(`ContributionMessage was not successful: ${e}`)
} finally {
await queryRunner.release()
}
return new ContributionMessage(contributionMessage, user)
}
}

View File

@ -96,13 +96,14 @@ export class ContributionResolver {
order: {
createdAt: order,
},
relations: ['messages'],
withDeleted: true,
skip: (currentPage - 1) * pageSize,
take: pageSize,
})
return new ContributionListResult(
count,
contributions.map((contribution) => new Contribution(contribution, new User(user))),
contributions.map((contribution) => new Contribution(contribution, user)),
)
}
@ -123,9 +124,7 @@ export class ContributionResolver {
.getManyAndCount()
return new ContributionListResult(
count,
dbContributions.map(
(contribution) => new Contribution(contribution, new User(contribution.user)),
),
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
)
}

View File

@ -206,6 +206,16 @@ export const listContributions = gql`
confirmedAt
confirmedBy
deletedAt
state
messages {
id
message
createdAt
updatedAt
type
userFirstName
userLastName
}
}
}
}