Merge branch 'master' into 2247-links-in-contribution-messages-clickable

This commit is contained in:
Moriz Wahl 2022-10-24 06:04:07 +02:00 committed by GitHub
commit fa7bb026e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 156 additions and 6 deletions

View File

@ -10,7 +10,7 @@ Decimal.set({
})
const constants = {
DB_VERSION: '0050-add_messageId_to_event_protocol',
DB_VERSION: '0051-add_delete_by_to_contributions',
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

View File

@ -17,6 +17,7 @@ import {
setUserRole,
deleteUser,
unDeleteUser,
createContribution,
adminCreateContribution,
adminCreateContributions,
adminUpdateContribution,
@ -77,6 +78,7 @@ afterAll(async () => {
let admin: User
let user: User
let creation: Contribution | void
let result: any
describe('AdminResolver', () => {
describe('set user role', () => {
@ -1365,6 +1367,38 @@ describe('AdminResolver', () => {
})
})
describe('admin deletes own user contribution', () => {
beforeAll(async () => {
await query({
query: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
})
result = await mutate({
mutation: createContribution,
variables: {
amount: 100.0,
memo: 'Test env contribution',
creationDate: new Date().toString(),
},
})
})
it('throws an error', async () => {
await expect(
mutate({
mutation: adminDeleteContribution,
variables: {
id: result.data.createContribution.id,
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Own contribution can not be deleted as admin')],
}),
)
})
})
describe('creation id does exist', () => {
it('returns true', async () => {
await expect(

View File

@ -400,13 +400,24 @@ export class AdminResolver {
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
@Mutation(() => Boolean)
async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise<boolean> {
async adminDeleteContribution(
@Arg('id', () => Int) id: number,
@Ctx() context: Context,
): Promise<boolean> {
const contribution = await DbContribution.findOne(id)
if (!contribution) {
logger.error(`Contribution not found for given id: ${id}`)
throw new Error('Contribution not found for given id.')
}
const moderator = getUser(context)
if (
contribution.contributionType === ContributionType.USER &&
contribution.userId === moderator.id
) {
throw new Error('Own contribution can not be deleted as admin')
}
contribution.contributionStatus = ContributionStatus.DELETED
contribution.deletedBy = moderator.id
await contribution.save()
const res = await contribution.softRemove()
return !!res

View File

@ -91,6 +91,7 @@ export class ContributionResolver {
}
contribution.contributionStatus = ContributionStatus.DELETED
contribution.deletedBy = user.id
contribution.deletedAt = new Date()
await contribution.save()

View File

@ -26,7 +26,7 @@ describe('sendAddedContributionMessageEmail', () => {
it('calls sendEMail', () => {
expect(sendEMail).toBeCalledWith({
to: `Bibi Bloxberg <bibi@bloxberg.de>`,
subject: 'Gradido Frage zur Schöpfung',
subject: 'Rückfrage zu Deinem Gemeinwohl-Beitrag',
text:
expect.stringContaining('Hallo Bibi Bloxberg') &&
expect.stringContaining('Peter Lustig') &&

View File

@ -1,6 +1,6 @@
export const contributionMessageReceived = {
de: {
subject: 'Gradido Frage zur Schöpfung',
subject: 'Rückfrage zu Deinem Gemeinwohl-Beitrag',
text: (data: {
senderFirstName: string
senderLastName: string

View File

@ -0,0 +1,92 @@
import Decimal from 'decimal.js-light'
import {
BaseEntity,
Column,
Entity,
PrimaryGeneratedColumn,
DeleteDateColumn,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
import { User } from '../User'
import { ContributionMessage } from '../ContributionMessage'
@Entity('contributions')
export class Contribution extends BaseEntity {
@PrimaryGeneratedColumn('increment', { unsigned: true })
id: number
@Column({ unsigned: true, nullable: false, name: 'user_id' })
userId: number
@ManyToOne(() => User, (user) => user.contributions)
@JoinColumn({ name: 'user_id' })
user: User
@Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' })
createdAt: Date
@Column({ type: 'datetime', nullable: false, name: 'contribution_date' })
contributionDate: Date
@Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
memo: string
@Column({
type: 'decimal',
precision: 40,
scale: 20,
nullable: false,
transformer: DecimalTransformer,
})
amount: Decimal
@Column({ unsigned: true, nullable: true, name: 'moderator_id' })
moderatorId: number
@Column({ unsigned: true, nullable: true, name: 'contribution_link_id' })
contributionLinkId: number
@Column({ unsigned: true, nullable: true, name: 'confirmed_by' })
confirmedBy: number
@Column({ nullable: true, name: 'confirmed_at' })
confirmedAt: Date
@Column({ unsigned: true, nullable: true, name: 'denied_by' })
deniedBy: number
@Column({ nullable: true, name: 'denied_at' })
deniedAt: Date
@Column({
name: 'contribution_type',
length: 12,
nullable: false,
collation: 'utf8mb4_unicode_ci',
})
contributionType: string
@Column({
name: 'contribution_status',
length: 12,
nullable: false,
collation: 'utf8mb4_unicode_ci',
})
contributionStatus: string
@Column({ unsigned: true, nullable: true, name: 'transaction_id' })
transactionId: number
@DeleteDateColumn({ name: 'deleted_at' })
deletedAt: Date | null
@DeleteDateColumn({ unsigned: true, nullable: true, name: 'deleted_by' })
deletedBy: number
@OneToMany(() => ContributionMessage, (message) => message.contribution)
@JoinColumn({ name: 'contribution_id' })
messages?: ContributionMessage[]
}

View File

@ -1 +1 @@
export { Contribution } from './0047-messages_tables/Contribution'
export { Contribution } from './0051-add_delete_by_to_contributions/Contribution'

View File

@ -0,0 +1,12 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(
`ALTER TABLE \`contributions\` ADD COLUMN \`deleted_by\` int(10) unsigned DEFAULT NULL;`,
)
}
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(`ALTER TABLE \`contributions\` DROP COLUMN \`deleted_by\`;`)
}

View File

@ -34,7 +34,7 @@
"contribution": {
"activity": "Tätigkeit",
"alert": {
"answerQuestion": "Bitte beantworte die Nachfrage",
"answerQuestion": "Bitte beantworte die Rückfrage!",
"communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.",
"confirm": "bestätigt",
"in_progress": "Es gibt eine Rückfrage der Moderatoren.",