additional tests for userRoles and userContact

This commit is contained in:
Claus-Peter Huebner 2023-07-07 17:55:52 +02:00
parent 0fca31799b
commit bbcb97abfb
6 changed files with 259 additions and 46 deletions

View File

@ -53,29 +53,24 @@ export class UserAdmin {
@Field(() => [String], { nullable: true }) @Field(() => [String], { nullable: true })
roles: string[] | null roles: string[] | null
@Field(() => Boolean)
isAdmin(): boolean {
if (this.roles) {
return this.roles.includes(ROLE_NAMES.ROLE_NAME_ADMIN)
}
return false
}
@Field(() => Boolean)
isModerator(): boolean {
if (this.roles) {
return this.roles.includes(ROLE_NAMES.ROLE_NAME_MODERATOR)
}
return false
}
} }
export function isAdmin(user: UserAdmin): boolean {
if (user.roles) {
for (const role of user.roles) {
if (role === ROLE_NAMES.ROLE_NAME_ADMIN) {
return true
}
}
}
return false
}
export function isModerator(user: UserAdmin): boolean {
if (user.roles) {
for (const role of user.roles) {
if (role === ROLE_NAMES.ROLE_NAME_MODERATOR) {
return true
}
}
}
return false
}
@ObjectType() @ObjectType()
export class SearchUsersResult { export class SearchUsersResult {

View File

@ -56,6 +56,7 @@ import {
searchUsers, searchUsers,
user as userQuery, user as userQuery,
checkUsername, checkUsername,
userContact,
} from '@/seeds/graphql/queries' } from '@/seeds/graphql/queries'
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { bobBaumeister } from '@/seeds/users/bob-baumeister'
@ -699,13 +700,15 @@ describe('UserResolver', () => {
firstName: 'Bibi', firstName: 'Bibi',
hasElopage: false, hasElopage: false,
id: expect.any(Number), id: expect.any(Number),
roles: expect.any(Array),
klickTipp: { klickTipp: {
newsletterState: false, newsletterState: false,
}, },
language: 'de', language: 'de',
lastName: 'Bloxberg', lastName: 'Bloxberg',
publisherId: 1234, publisherId: 1234,
roles: [],
isAdmin: false,
isModerator: false,
}, },
}, },
}), }),
@ -976,7 +979,9 @@ describe('UserResolver', () => {
}, },
hasElopage: false, hasElopage: false,
publisherId: 1234, publisherId: 1234,
roles: expect.any(Array), roles: [],
isAdmin: false,
isModerator: false,
}, },
}, },
}), }),
@ -992,6 +997,35 @@ describe('UserResolver', () => {
}), }),
) )
}) })
it('returns usercontact object', async () => {
await expect(
query({
query: userContact,
variables: {
userId: user[0].id,
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
userContact: {
id: expect.any(Number),
type: UserContactType.USER_CONTACT_EMAIL,
userId: user[0].id,
email: 'bibi@bloxberg.de',
emailOptInTypeId: expect.any(Number),
emailResendCount: expect.any(Number),
emailChecked: expect.any(Boolean),
phone: null,
createdAt: expect.any(Date),
updatedAt: expect.any(Date),
deletedAt: null,
},
},
}),
)
})
}) })
}) })
}) })
@ -1417,6 +1451,7 @@ describe('UserResolver', () => {
expect.objectContaining({ expect.objectContaining({
firstName: 'Peter', firstName: 'Peter',
lastName: 'Lustig', lastName: 'Lustig',
role: ROLE_NAMES.ROLE_NAME_ADMIN,
}), }),
]), ]),
}, },
@ -1498,13 +1533,15 @@ describe('UserResolver', () => {
firstName: 'Bibi', firstName: 'Bibi',
hasElopage: false, hasElopage: false,
id: expect.any(Number), id: expect.any(Number),
roles: expect.any(Array),
klickTipp: { klickTipp: {
newsletterState: false, newsletterState: false,
}, },
language: 'de', language: 'de',
lastName: 'Bloxberg', lastName: 'Bloxberg',
publisherId: 1234, publisherId: 1234,
roles: [],
isAdmin: false,
isModerator: false,
}, },
}, },
}), }),
@ -1536,7 +1573,7 @@ describe('UserResolver', () => {
}) })
describe('authenticated', () => { describe('authenticated', () => {
describe('without admin rights', () => { describe('with user rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
await mutate({ await mutate({
@ -1564,8 +1601,45 @@ describe('UserResolver', () => {
}) })
}) })
describe('with moderator rights', () => {
beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg)
admin = await userFactory(testEnv, peterLustig)
// set Moderator-Role for Peter
const userRole = await UserRole.findOneOrFail({ where: { userId: admin.id } })
userRole.role = ROLE_NAMES.ROLE_NAME_MODERATOR
userRole.userId = admin.id
await UserRole.save(userRole)
await mutate({
mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
})
})
afterAll(async () => {
await cleanDB()
resetToken()
})
it('returns an error', async () => {
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_ADMIN },
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('with admin rights', () => { describe('with admin rights', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg)
admin = await userFactory(testEnv, peterLustig) admin = await userFactory(testEnv, peterLustig)
await mutate({ await mutate({
mutation: login, mutation: login,
@ -1578,7 +1652,26 @@ describe('UserResolver', () => {
resetToken() resetToken()
}) })
it('returns user with new moderator-role', async () => {
const result = await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_MODERATOR },
})
expect(result).toEqual(
expect.objectContaining({
data: {
setUserRole: ROLE_NAMES.ROLE_NAME_MODERATOR,
},
}),
)
})
describe('user to get a new role does not exist', () => { describe('user to get a new role does not exist', () => {
afterAll(async () => {
await cleanDB()
resetToken()
})
it('throws an error', async () => { it('throws an error', async () => {
jest.clearAllMocks() jest.clearAllMocks()
await expect( await expect(
@ -1601,11 +1694,21 @@ describe('UserResolver', () => {
describe('change role with success', () => { describe('change role with success', () => {
beforeAll(async () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg) user = await userFactory(testEnv, bibiBloxberg)
admin = await userFactory(testEnv, peterLustig)
await mutate({
mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
})
})
afterAll(async () => {
await cleanDB()
resetToken()
}) })
describe('user gets new role', () => { describe('user gets new role', () => {
describe('to admin', () => { describe('to admin', () => {
it('returns date string', async () => { it('returns admin-rolename', async () => {
const result = await mutate({ const result = await mutate({
mutation: setUserRole, mutation: setUserRole,
variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_ADMIN }, variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_ADMIN },
@ -1613,7 +1716,41 @@ describe('UserResolver', () => {
expect(result).toEqual( expect(result).toEqual(
expect.objectContaining({ expect.objectContaining({
data: { data: {
setUserRole: expect.any(String), setUserRole: ROLE_NAMES.ROLE_NAME_ADMIN,
},
}),
)
})
it('stores the ADMIN_USER_ROLE_SET event in the database', async () => {
const userContact = await UserContact.findOneOrFail({
where: { email: 'bibi@bloxberg.de' },
relations: ['user'],
})
const adminContact = await UserContact.findOneOrFail({
where: { email: 'peter@lustig.de' },
relations: ['user'],
})
await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventType.ADMIN_USER_ROLE_SET,
affectedUserId: userContact.user.id,
actingUserId: adminContact.user.id,
}),
)
})
})
describe('to moderator', () => {
it('returns date string', async () => {
const result = await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_MODERATOR },
})
expect(result).toEqual(
expect.objectContaining({
data: {
setUserRole: ROLE_NAMES.ROLE_NAME_MODERATOR,
}, },
}), }),
) )
@ -1656,7 +1793,21 @@ describe('UserResolver', () => {
}) })
describe('change role with error', () => { describe('change role with error', () => {
describe('is own role', () => { beforeAll(async () => {
user = await userFactory(testEnv, bibiBloxberg)
admin = await userFactory(testEnv, peterLustig)
await mutate({
mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
})
})
afterAll(async () => {
await cleanDB()
resetToken()
})
describe('his own role', () => {
it('throws an error', async () => { it('throws an error', async () => {
jest.clearAllMocks() jest.clearAllMocks()
await expect( await expect(
@ -1672,6 +1823,29 @@ describe('UserResolver', () => {
}) })
}) })
describe('to not allowed role', () => {
it('throws an error', async () => {
jest.clearAllMocks()
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id, role: 'unknown rolename' },
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Not allowed to set user role=')],
}),
)
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'Not allowed to set user role=',
'unknown rolename',
)
})
})
describe('user has already role to be set', () => { describe('user has already role to be set', () => {
describe('to admin', () => { describe('to admin', () => {
it('throws an error', async () => { it('throws an error', async () => {
@ -1700,6 +1874,33 @@ describe('UserResolver', () => {
}) })
}) })
describe('to moderator', () => {
it('throws an error', async () => {
jest.clearAllMocks()
await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_MODERATOR },
})
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id, role: ROLE_NAMES.ROLE_NAME_MODERATOR },
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('User already has role=')],
}),
)
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'User already has role=',
ROLE_NAMES.ROLE_NAME_MODERATOR,
)
})
})
describe('to usual user', () => { describe('to usual user', () => {
it('throws an error', async () => { it('throws an error', async () => {
jest.clearAllMocks() jest.clearAllMocks()

View File

@ -69,6 +69,7 @@ import { findUserByIdentifier } from './util/findUserByIdentifier'
import { findUsers } from './util/findUsers' import { findUsers } from './util/findUsers'
import { getKlicktippState } from './util/getKlicktippState' import { getKlicktippState } from './util/getKlicktippState'
import { validateAlias } from './util/validateAlias' import { validateAlias } from './util/validateAlias'
import { UserContact } from '../model/UserContact'
const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl'] const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl']
const DEFAULT_LANGUAGE = 'de' const DEFAULT_LANGUAGE = 'de'
@ -223,6 +224,7 @@ export class UserResolver {
// check if user with email still exists? // check if user with email still exists?
email = email.trim().toLowerCase() email = email.trim().toLowerCase()
if (await checkEmailExists(email)) { if (await checkEmailExists(email)) {
// console.log('email still exists! email', email)
const foundUser = await findUserByEmail(email) const foundUser = await findUserByEmail(email)
logger.info('DbUser.findOne', email, foundUser) logger.info('DbUser.findOne', email, foundUser)
@ -355,7 +357,6 @@ export class UserResolver {
} else { } else {
await EVENT_USER_REGISTER(dbUser) await EVENT_USER_REGISTER(dbUser)
} }
console.log('createUser dbUser=', dbUser)
return new User(dbUser) return new User(dbUser)
} }
@ -723,44 +724,33 @@ export class UserResolver {
default: default:
throw new LogError('Not allowed to set user role=', role) throw new LogError('Not allowed to set user role=', role)
} }
console.log('1')
const user = await DbUser.findOne({ const user = await DbUser.findOne({
where: { id: userId }, where: { id: userId },
relations: ['userRoles'], relations: ['userRoles'],
}) })
console.log('2')
// user exists ? // user exists ?
if (!user) { if (!user) {
throw new LogError('Could not find user with given ID', userId) throw new LogError('Could not find user with given ID', userId)
} }
console.log('3')
// administrator user changes own role? // administrator user changes own role?
const moderator = getUser(context) const moderator = getUser(context)
console.log('4')
if (moderator.id === userId) { if (moderator.id === userId) {
throw new LogError('Administrator can not change his own role') throw new LogError('Administrator can not change his own role')
} }
console.log('5')
// if user role(s) should be deleted by role=null as parameter // if user role(s) should be deleted by role=null as parameter
if (role === null && user.userRoles) { if (role === null && user.userRoles) {
console.log('6')
if (user.userRoles.length > 0) { if (user.userRoles.length > 0) {
console.log('7')
// remove all roles of the user // remove all roles of the user
await UserRole.delete({ userId: user.id }) await UserRole.delete({ userId: user.id })
console.log('8')
user.userRoles.length = 0 user.userRoles.length = 0
} else if (user.userRoles.length === 0) { } else if (user.userRoles.length === 0) {
console.log('9')
throw new LogError('User is already an usual user') throw new LogError('User is already an usual user')
} }
} else if (isUserInRole(user, role)) { } else if (isUserInRole(user, role)) {
console.log('10')
throw new LogError('User already has role=', role) throw new LogError('User already has role=', role)
} }
// if role shoud be set // if role shoud be set
if (role) { if (role) {
console.log('11 ', role)
if (user.userRoles === undefined) { if (user.userRoles === undefined) {
user.userRoles = [] as UserRole[] user.userRoles = [] as UserRole[]
} }
@ -774,9 +764,7 @@ export class UserResolver {
} }
// await user.save() // await user.save()
await EVENT_ADMIN_USER_ROLE_SET(user, moderator) await EVENT_ADMIN_USER_ROLE_SET(user, moderator)
console.log('12 ')
const newUser = await DbUser.findOne({ where: { id: userId }, relations: ['userRoles'] }) const newUser = await DbUser.findOne({ where: { id: userId }, relations: ['userRoles'] })
console.log('13 ', newUser)
return newUser?.userRoles ? newUser.userRoles[0].role : null return newUser?.userRoles ? newUser.userRoles[0].role : null
} }
@ -858,6 +846,18 @@ export class UserResolver {
async user(@Arg('identifier') identifier: string): Promise<User> { async user(@Arg('identifier') identifier: string): Promise<User> {
return new User(await findUserByIdentifier(identifier)) return new User(await findUserByIdentifier(identifier))
} }
@Authorized([RIGHTS.USER])
@Query(() => UserContact)
async userContact(@Arg('userId', () => Int) userId: number): Promise<UserContact> {
return new UserContact(
await DbUserContact.findOneOrFail({
where: { userId },
withDeleted: true,
relations: ['user'],
}),
)
}
} }
export async function findUserByEmail(email: string): Promise<DbUser> { export async function findUserByEmail(email: string): Promise<DbUser> {

View File

@ -19,10 +19,10 @@ export const userFactory = async (
createUser: { id }, createUser: { id },
}, },
} = await mutate({ mutation: createUser, variables: user }) } = await mutate({ mutation: createUser, variables: user })
console.log('creatUser:', { id }, { user }) // console.log('after creatUser:', { id }, { user })
// get user from database // get user from database
let dbUser = await User.findOneOrFail({ where: { id }, relations: ['emailContact', 'userRoles'] }) let dbUser = await User.findOneOrFail({ where: { id }, relations: ['emailContact', 'userRoles'] })
console.log('dbUser:', dbUser) // console.log('dbUser:', dbUser)
const emailContact = dbUser.emailContact const emailContact = dbUser.emailContact
// console.log('emailContact:', emailContact) // console.log('emailContact:', emailContact)

View File

@ -387,3 +387,20 @@ export const user = gql`
} }
} }
` `
export const userContact = gql`
query ($userId: Int!) {
userContact(userId: $userId) {
id
type
userId
email
emailOptInTypeId
emailResendCount
emailChecked
phone
createdAt
updatedAt
deletedAt
}
}
`

View File

@ -18,7 +18,7 @@ export class UserRole extends BaseEntity {
@Column({ name: 'updated_at', nullable: true, default: null, type: 'datetime' }) @Column({ name: 'updated_at', nullable: true, default: null, type: 'datetime' })
updatedAt: Date | null updatedAt: Date | null
@ManyToOne(() => User, (user) => user.userRoles) @ManyToOne(() => User, (user) => user.userRoles, { nullable: true })
@JoinColumn({ name: 'user_id' }) @JoinColumn({ name: 'user_id' })
user: User user: User | null
} }