diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index fcee2d19e..733201776 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -36,7 +36,6 @@ export const isAuthorized: AuthChecker = async ({ context }, rights) => withDeleted: true, relations: ['emailContact', 'userRoles'], }) - // console.log('isAuthorized user=', user) context.user = user context.role = ROLE_USER if (user.userRoles && user.userRoles.length > 0) { @@ -51,9 +50,7 @@ export const isAuthorized: AuthChecker = async ({ context }, rights) => context.role = ROLE_USER } } - // console.log('context.role=', context.role) } catch { - // console.log('401 Unauthorized for decoded', decoded) // in case the database query fails (user deleted) throw new LogError('401 Unauthorized') } diff --git a/backend/src/graphql/model/AdminUser.ts b/backend/src/graphql/model/AdminUser.ts index b3f82d76d..d849762bd 100644 --- a/backend/src/graphql/model/AdminUser.ts +++ b/backend/src/graphql/model/AdminUser.ts @@ -6,7 +6,7 @@ export class AdminUser { constructor(user: User) { this.firstName = user.firstName this.lastName = user.lastName - this.role = user.userRoles ? user.userRoles[0].role : '' + this.role = user.userRoles.length > 0 ? user.userRoles[0].role : '' } @Field(() => String) diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 551567a13..c69585a2a 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -20,12 +20,7 @@ export class User { this.createdAt = user.createdAt this.language = user.language this.publisherId = user.publisherId - if (user.userRoles) { - this.roles = [] as string[] - user.userRoles.forEach((userRole) => { - this.roles?.push(userRole.role) - }) - } + this.roles = user.userRoles?.map((userRole) => userRole.role) ?? [] this.klickTipp = null this.hasElopage = null this.hideAmountGDD = user.hideAmountGDD @@ -75,22 +70,16 @@ export class User { @Field(() => Boolean, { nullable: true }) hasElopage: boolean | null - @Field(() => [String], { nullable: true }) - roles: string[] | null + @Field(() => [String]) + roles: string[] @Field(() => Boolean) isAdmin(): boolean { - if (this.roles) { - return this.roles.includes(ROLE_NAMES.ROLE_NAME_ADMIN) - } - return false + return this.roles.includes(ROLE_NAMES.ROLE_NAME_ADMIN) } @Field(() => Boolean) isModerator(): boolean { - if (this.roles) { - return this.roles.includes(ROLE_NAMES.ROLE_NAME_MODERATOR) - } - return false + return this.roles.includes(ROLE_NAMES.ROLE_NAME_MODERATOR) } } diff --git a/backend/src/graphql/model/UserAdmin.ts b/backend/src/graphql/model/UserAdmin.ts index b5dba89b9..989ce1f8c 100644 --- a/backend/src/graphql/model/UserAdmin.ts +++ b/backend/src/graphql/model/UserAdmin.ts @@ -16,12 +16,7 @@ export class UserAdmin { this.hasElopage = hasElopage this.deletedAt = user.deletedAt this.emailConfirmationSend = emailConfirmationSend - if (user.userRoles) { - this.roles = [] as string[] - user.userRoles.forEach((userRole) => { - this.roles?.push(userRole.role) - }) - } + this.roles = user.userRoles?.map((userRole) => userRole.role) ?? [] } @Field(() => Int) @@ -51,23 +46,17 @@ export class UserAdmin { @Field(() => String, { nullable: true }) emailConfirmationSend: string | null - @Field(() => [String], { nullable: true }) - roles: string[] | null + @Field(() => [String]) + roles: string[] @Field(() => Boolean) isAdmin(): boolean { - if (this.roles) { - return this.roles.includes(ROLE_NAMES.ROLE_NAME_ADMIN) - } - return false + return this.roles.includes(ROLE_NAMES.ROLE_NAME_ADMIN) } @Field(() => Boolean) isModerator(): boolean { - if (this.roles) { - return this.roles.includes(ROLE_NAMES.ROLE_NAME_MODERATOR) - } - return false + return this.roles.includes(ROLE_NAMES.ROLE_NAME_MODERATOR) } } diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index e9d1f1d36..6a9ca7590 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -165,7 +165,7 @@ describe('UserResolver', () => { createdAt: expect.any(Date), // emailChecked: false, language: 'de', - userRoles: expect.any(Array), + userRoles: [], // expect.any(Array), deletedAt: null, publisherId: 1234, referrerId: null, diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 859d90a57..f59b5b704 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -69,6 +69,7 @@ import { getUserCreations } from './util/creations' import { findUserByIdentifier } from './util/findUserByIdentifier' import { findUsers } from './util/findUsers' import { getKlicktippState } from './util/getKlicktippState' +import { setUserRole, deleteUserRole } from './util/modifyUserRole' import { validateAlias } from './util/validateAlias' const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl'] @@ -135,7 +136,6 @@ export class UserResolver { logger.info(`login with ${email}, ***, ${publisherId} ...`) email = email.trim().toLowerCase() const dbUser = await findUserByEmail(email) - // console.log('login dbUser=', dbUser) if (dbUser.deletedAt) { throw new LogError('This user was permanently deleted. Contact support for questions', dbUser) } @@ -738,31 +738,13 @@ export class UserResolver { throw new LogError('Administrator can not change his own role') } // if user role(s) should be deleted by role=null as parameter - if (role === null && user.userRoles) { - if (user.userRoles.length > 0) { - // remove all roles of the user - await UserRole.delete({ userId: user.id }) - user.userRoles.length = 0 - } else if (user.userRoles.length === 0) { - throw new LogError('User is already an usual user') - } + if (role === null) { + await deleteUserRole(user) } else if (isUserInRole(user, role)) { throw new LogError('User already has role=', role) + } else { + await setUserRole(user, role) } - // if role shoud be set - if (role) { - if (user.userRoles === undefined) { - user.userRoles = [] as UserRole[] - } - if (user.userRoles.length < 1) { - user.userRoles.push(UserRole.create()) - } - user.userRoles[0].createdAt = new Date() - user.userRoles[0].role = role - user.userRoles[0].userId = user.id - await UserRole.save(user.userRoles[0]) - } - // await user.save() await EVENT_ADMIN_USER_ROLE_SET(user, moderator) const newUser = await DbUser.findOne({ where: { id: userId }, relations: ['userRoles'] }) return newUser?.userRoles ? newUser.userRoles[0].role : null @@ -899,10 +881,10 @@ const canEmailResend = (updatedAt: Date): boolean => { return !isTimeExpired(updatedAt, CONFIG.EMAIL_CODE_REQUEST_TIME) } -export function isUserInRole(user: DbUser, role: string | null): boolean { - if (user?.userRoles) { - for (const usrRole of user.userRoles) { - if (usrRole.role === role) { +export function isUserInRole(user: DbUser, role: string): boolean { + if (user && role) { + for (const userRole of user.userRoles) { + if (userRole.role === role) { return true } } diff --git a/backend/src/graphql/resolver/util/modifyUserRole.ts b/backend/src/graphql/resolver/util/modifyUserRole.ts new file mode 100644 index 000000000..bcd140c07 --- /dev/null +++ b/backend/src/graphql/resolver/util/modifyUserRole.ts @@ -0,0 +1,30 @@ +import { User as DbUser } from '@entity/User' +import { UserRole } from '@entity/UserRole' + +import { LogError } from '@/server/LogError' + +export async function setUserRole(user: DbUser, role: string | null): Promise { + // if role should be set + if (role) { + // in case user has still no associated userRole + if (user.userRoles.length < 1) { + // instanciate a userRole + user.userRoles.push(UserRole.create()) + } + // and initialize the userRole + user.userRoles[0].createdAt = new Date() + user.userRoles[0].role = role + user.userRoles[0].userId = user.id + await UserRole.save(user.userRoles[0]) + } +} + +export async function deleteUserRole(user: DbUser): Promise { + if (user.userRoles.length > 0) { + // remove all roles of the user + await UserRole.delete({ userId: user.id }) + user.userRoles.length = 0 + } else if (user.userRoles.length === 0) { + throw new LogError('User is already an usual user') + } +} diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 4d1d59f14..af6b1c3b9 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/unbound-method */ import { User } from '@entity/User' -import { UserRole } from '@entity/UserRole' import { ApolloServerTestClient } from 'apollo-server-testing' import { ROLE_NAMES } from '@/auth/ROLES' +import { setUserRole } from '@/graphql/resolver/util/modifyUserRole' import { createUser, setPassword } from '@/seeds/graphql/mutations' import { UserInterface } from '@/seeds/users/UserInterface' @@ -44,12 +44,7 @@ export const userFactory = async ( user.role && (user.role === ROLE_NAMES.ROLE_NAME_ADMIN || user.role === ROLE_NAMES.ROLE_NAME_MODERATOR) ) { - dbUser.userRoles = [] as UserRole[] - dbUser.userRoles[0] = UserRole.create() - dbUser.userRoles[0].createdAt = new Date() - dbUser.userRoles[0].role = user.role - dbUser.userRoles[0].userId = dbUser.id - await dbUser.userRoles[0].save() + await setUserRole(dbUser, user.role) } await dbUser.save() } diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index d7c46df36..422c836df 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -26,7 +26,7 @@ const communityDbUser: dbUser = { createdAt: new Date(), // emailChecked: false, language: '', - userRoles: undefined, + userRoles: [], publisherId: 0, // default password encryption type passwordEncryptionType: PasswordEncryptionType.NO_PASSWORD, diff --git a/database/entity/0069-add_user_roles_table/User.ts b/database/entity/0069-add_user_roles_table/User.ts index 666d9dacc..2236fd099 100644 --- a/database/entity/0069-add_user_roles_table/User.ts +++ b/database/entity/0069-add_user_roles_table/User.ts @@ -89,7 +89,7 @@ export class User extends BaseEntity { @OneToMany(() => UserRole, (userRole) => userRole.user) @JoinColumn({ name: 'user_id' }) - userRoles?: UserRole[] + userRoles: UserRole[] @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) referrerId?: number | null diff --git a/database/entity/0069-add_user_roles_table/UserRole.ts b/database/entity/0069-add_user_roles_table/UserRole.ts index 0de0e27a2..4734de8d9 100644 --- a/database/entity/0069-add_user_roles_table/UserRole.ts +++ b/database/entity/0069-add_user_roles_table/UserRole.ts @@ -18,7 +18,7 @@ export class UserRole extends BaseEntity { @Column({ name: 'updated_at', nullable: true, default: null, type: 'datetime' }) updatedAt: Date | null - @ManyToOne(() => User, (user) => user.userRoles, { nullable: true }) + @ManyToOne(() => User, (user) => user.userRoles) @JoinColumn({ name: 'user_id' }) - user: User | null + user: User }