diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 7600f12b9..31e2384d4 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -9,7 +9,6 @@ import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { GdtResolver } from './GdtResolver' import { getLastTransaction } from './util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' - import { Balance } from '@model/Balance' import { backendLogger as logger } from '@/server/logger' diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index f4352c095..5513a73b8 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Community as DbCommunity } from '@entity/Community' -import { getCommunities } from '@/seeds/graphql/queries' import { testEnvironment } from '@test/helpers' +import { getCommunities } from '@/seeds/graphql/queries' let query: any diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 6a69e257e..7dfb44e55 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -9,6 +9,7 @@ import { GraphQLError } from 'graphql' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Event as DbEvent } from '@entity/Event' import { logger } from '@test/testSetup' +import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { login, createContributionLink, @@ -16,7 +17,6 @@ import { updateContributionLink, } from '@/seeds/graphql/mutations' import { listContributionLinks } from '@/seeds/graphql/queries' -import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 55a23187f..4b19c36e1 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -3,20 +3,20 @@ import { Resolver, Args, Arg, Authorized, Mutation, Query, Int, Ctx } from 'type import { MoreThan, IsNull } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' +import { isStartEndDateValid } from './util/creations' import { CONTRIBUTIONLINK_NAME_MAX_CHARS, CONTRIBUTIONLINK_NAME_MIN_CHARS, MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' -import { isStartEndDateValid } from './util/creations' -import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import { ContributionLinkList } from '@model/ContributionLinkList' import { ContributionLink } from '@model/ContributionLink' import ContributionLinkArgs from '@arg/ContributionLinkArgs' -import { RIGHTS } from '@/auth/RIGHTS' import { Order } from '@enum/Order' import Paginated from '@arg/Paginated' +import { RIGHTS } from '@/auth/RIGHTS' // TODO: this is a strange construct import LogError from '@/server/LogError' diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 201d04db1..5570f953f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -13,6 +13,18 @@ import { Transaction as DbTransaction } from '@entity/Transaction' import { User } from '@entity/User' import { UserInputError } from 'apollo-server-express' import { Event as DbEvent } from '@entity/Event' +import { + cleanDB, + resetToken, + testEnvironment, + contributionDateFormatter, + resetEntity, +} from '@test/helpers' +import { logger, i18n as localization } from '@test/testSetup' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { ContributionListResult } from '@model/Contribution' +import { ContributionStatus } from '@enum/ContributionStatus' +import { Order } from '@enum/Order' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { stephenHawking } from '@/seeds/users/stephen-hawking' @@ -40,24 +52,12 @@ import { sendContributionDeletedEmail, sendContributionDeniedEmail, } from '@/emails/sendEmailVariants' -import { - cleanDB, - resetToken, - testEnvironment, - contributionDateFormatter, - resetEntity, -} from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' import { EventType } from '@/event/Event' -import { logger, i18n as localization } from '@test/testSetup' import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { ContributionListResult } from '@model/Contribution' -import { ContributionStatus } from '@enum/ContributionStatus' -import { Order } from '@enum/Order' jest.mock('@/emails/sendEmailVariants') @@ -2040,6 +2040,50 @@ describe('ContributionResolver', () => { }), ) }) + + describe('user tries to update admin contribution', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + }) + + it('logs and throws "Cannot update contribution of moderator" error', async () => { + jest.clearAllMocks() + const adminContribution = await Contribution.findOne({ + where: { + moderatorId: admin.id, + userId: bibi.id, + }, + }) + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: (adminContribution && adminContribution.id) || -1, + amount: 100.0, + memo: 'Test Test Test', + creationDate: new Date().toString(), + }, + }), + ).resolves.toMatchObject({ + errors: [new GraphQLError('Cannot update contribution of moderator')], + }) + expect(logger.error).toBeCalledWith( + 'Cannot update contribution of moderator', + expect.any(Object), + bibi.id, + ) + }) + }) }) describe('second creation surpasses the available amount ', () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index a9446db7f..f756b3a0d 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -9,9 +9,6 @@ import { UserContact } from '@entity/UserContact' import { User as DbUser } from '@entity/User' import { Transaction as DbTransaction } from '@entity/Transaction' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { getLastTransaction } from './util/getLastTransaction' -import { findContributions } from './util/findContributions' import { getUserCreation, validateContribution, @@ -19,6 +16,9 @@ import { isValidDateString, getOpenCreations, } from './util/creations' +import { findContributions } from './util/findContributions' +import { getLastTransaction } from './util/getLastTransaction' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { AdminUpdateContribution } from '@model/AdminUpdateContribution' import { Contribution, ContributionListResult } from '@model/Contribution' import { Decay } from '@model/Decay' @@ -201,6 +201,9 @@ export class ContributionResolver { user.id, ) } + if (contributionToUpdate.moderatorId) { + throw new LogError('Cannot update contribution of moderator', contributionToUpdate, user.id) + } if ( contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS && contributionToUpdate.contributionStatus !== ContributionStatus.PENDING diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index fd2a44b4b..4f72276d4 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -14,9 +14,11 @@ import { Transaction } from '@entity/Transaction' import { Event as DbEvent } from '@entity/Event' import { UserContact } from '@entity/UserContact' import { transactionLinkCode } from './TransactionLinkResolver' +import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { logger } from '@test/testSetup' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' -import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { userFactory } from '@/seeds/factory/user' @@ -33,9 +35,7 @@ import { confirmContribution, } from '@/seeds/graphql/mutations' import { listTransactionLinksAdmin } from '@/seeds/graphql/queries' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' -import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' // mock semaphore to allow use fake timers diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 6aa829ac1..3ff6fd36a 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -10,10 +10,10 @@ import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query, Int } from 'type-graphql' -import { getUserCreation, validateContribution } from './util/creations' -import { executeTransaction } from './TransactionResolver' -import { getLastTransaction } from './util/getLastTransaction' import transactionLinkList from './util/transactionLinkList' +import { getLastTransaction } from './util/getLastTransaction' +import { executeTransaction } from './TransactionResolver' +import { getUserCreation, validateContribution } from './util/creations' import { User } from '@model/User' import { ContributionLink } from '@model/ContributionLink' import { Decay } from '@model/Decay' @@ -25,12 +25,12 @@ import { ContributionCycleType } from '@enum/ContributionCycleType' import TransactionLinkArgs from '@arg/TransactionLinkArgs' import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' +import QueryLinkResult from '@union/QueryLinkResult' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { calculateBalance } from '@/util/validate' import { RIGHTS } from '@/auth/RIGHTS' import { calculateDecay } from '@/util/decay' -import QueryLinkResult from '@union/QueryLinkResult' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import LogError from '@/server/LogError' import { diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index f26234363..6d039784e 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -11,6 +11,8 @@ import { User } from '@entity/User' import { GraphQLError } from 'graphql' import { Event as DbEvent } from '@entity/Event' import { findUserByEmail } from './UserResolver' +import { cleanDB, testEnvironment } from '@test/helpers' +import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' import { userFactory } from '@/seeds/factory/user' import { @@ -23,8 +25,6 @@ import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' -import { cleanDB, testEnvironment } from '@test/helpers' -import { logger } from '@test/testSetup' let mutate: any, query: any, con: any let testEnv: any diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index f38a4a07b..a699e7291 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -9,10 +9,10 @@ import { getCustomRepository, getConnection, In } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { BalanceResolver } from './BalanceResolver' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { findUserByEmail } from './UserResolver' import { getLastTransaction } from './util/getLastTransaction' +import { findUserByEmail } from './UserResolver' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { BalanceResolver } from './BalanceResolver' import { TransactionRepository } from '@repository/Transaction' import { TransactionLinkRepository } from '@repository/TransactionLink' @@ -21,9 +21,9 @@ import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { Order } from '@enum/Order' import { TransactionTypeId } from '@enum/TransactionTypeId' -import { calculateBalance } from '@/util/validate' import TransactionSendArgs from '@arg/TransactionSendArgs' import Paginated from '@arg/Paginated' +import { calculateBalance } from '@/util/validate' import { backendLogger as logger } from '@/server/logger' import { Context, getUser } from '@/server/context' diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index aebd0f0eb..1b6239fea 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -15,9 +15,10 @@ import { Event as DbEvent } from '@entity/Event' import { OptInType } from '@enum/OptInType' import { UserContactType } from '@enum/UserContactType' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' -import { objectValuesToArray } from '@/util/utilities' import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { logger, i18n as localization } from '@test/testSetup' +import { ContributionLink } from '@model/ContributionLink' +import { objectValuesToArray } from '@/util/utilities' import { printTimeDuration } from '@/util/time' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' @@ -44,7 +45,6 @@ import { } from '@/emails/sendEmailVariants' import { contributionLinkFactory } from '@/seeds/factory/contributionLink' import { transactionLinkFactory } from '@/seeds/factory/transactionLink' -import { ContributionLink } from '@model/ContributionLink' import { EventType } from '@/event/Event' import { peterLustig } from '@/seeds/users/peter-lustig' import { bobBaumeister } from '@/seeds/users/bob-baumeister' diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 54d4f583f..0c1cefd12 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -21,8 +21,8 @@ import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { getUserCreations } from './util/creations' import { FULL_CREATION_AVAILABLE } from './const/const' +import { getUserCreations } from './util/creations' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { UserRepository } from '@repository/User' @@ -33,18 +33,17 @@ import { OptInType } from '@enum/OptInType' import { Order } from '@enum/Order' import { UserContactType } from '@enum/UserContactType' -import { - sendAccountActivationEmail, - sendAccountMultiRegistrationEmail, - sendResetPasswordEmail, -} from '@/emails/sendEmailVariants' - -import { getTimeDurationObject, printTimeDuration } from '@/util/time' import CreateUserArgs from '@arg/CreateUserArgs' import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' import Paginated from '@arg/Paginated' import SearchUsersArgs from '@arg/SearchUsersArgs' +import { getTimeDurationObject, printTimeDuration } from '@/util/time' +import { + sendAccountActivationEmail, + sendAccountMultiRegistrationEmail, + sendResetPasswordEmail, +} from '@/emails/sendEmailVariants' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 6b1976021..cc4d589dc 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -5,12 +5,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Decimal } from 'decimal.js-light' +import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' 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 { creationFactory, nMonthsBefore } from '@/seeds/factory/creation' -import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { confirmContribution, createContribution, diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index 6ebeae8b9..dba0c8c81 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -3,9 +3,9 @@ import { getConnection } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import { Decimal } from 'decimal.js-light' +import { OpenCreation } from '@model/OpenCreation' import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '@/graphql/resolver/const/const' import { backendLogger as logger } from '@/server/logger' -import { OpenCreation } from '@model/OpenCreation' import LogError from '@/server/LogError' interface CreationMap { diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index 0469b4ccc..568120fe8 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ import { MiddlewareFn } from 'type-graphql' -import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' import { KlickTipp } from '@model/KlickTipp' +import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' import CONFIG from '@/config' import { klickTippLogger as logger } from '@/server/logger' diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index b4531b3bb..ab8a333d2 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -2,10 +2,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { User } from '@entity/User' +import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import CONFIG from '@/config' import LogError from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs const sodium = require('sodium-native') diff --git a/backend/src/seeds/factory/contributionLink.ts b/backend/src/seeds/factory/contributionLink.ts index 5925cdcfe..6e1d9bd50 100644 --- a/backend/src/seeds/factory/contributionLink.ts +++ b/backend/src/seeds/factory/contributionLink.ts @@ -2,8 +2,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/unbound-method */ import { ApolloServerTestClient } from 'apollo-server-testing' -import { login, createContributionLink } from '@/seeds/graphql/mutations' import { ContributionLink } from '@model/ContributionLink' +import { login, createContributionLink } from '@/seeds/graphql/mutations' import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface' export const contributionLinkFactory = async ( diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index dfa477da9..d086727bf 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -3,9 +3,9 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { UserContact } from '@entity/UserContact' +import { User } from '@model/User' import { PasswordEncryptionType } from '@/graphql/enum/PasswordEncryptionType' // import { UserContact as EmailContact } from '@entity/UserContact' -import { User } from '@model/User' const communityDbUser: dbUser = { id: -1, diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index d35eb83a4..3c76b0995 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -1,6 +1,6 @@ import { Decimal } from 'decimal.js-light' -import CONFIG from '@/config' import { Decay } from '@model/Decay' +import CONFIG from '@/config' import LogError from '@/server/LogError' // TODO: externalize all those definitions and functions into an external decay library diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index ec28dfa13..aaadbdd31 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -2,9 +2,9 @@ import { Decimal } from 'decimal.js-light' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { calculateDecay } from './decay' -import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' import { Decay } from '@model/Decay' +import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' function isStringBoolean(value: string): boolean { const lowerValue = value.toLowerCase()