Merge pull request #2727 from gradido/alias-update-user-info

feat(backend): alias in update user info
This commit is contained in:
Moriz Wahl 2023-05-11 13:19:03 +02:00 committed by GitHub
commit 4ce9eddd4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 196 additions and 0 deletions

View File

@ -8,6 +8,9 @@ export class UpdateUserInfosArgs {
@Field({ nullable: true })
lastName?: string
@Field({ nullable: true })
alias?: string
@Field({ nullable: true })
language?: string

View File

@ -1198,6 +1198,28 @@ describe('UserResolver', () => {
})
})
describe('alias', () => {
beforeEach(() => {
jest.clearAllMocks()
})
describe('valid alias', () => {
it('updates the user in DB', async () => {
await mutate({
mutation: updateUserInfos,
variables: {
alias: 'bibi_Bloxberg',
},
})
await expect(User.findOne()).resolves.toEqual(
expect.objectContaining({
alias: 'bibi_Bloxberg',
}),
)
})
})
})
describe('language is not valid', () => {
it('throws an error', async () => {
jest.clearAllMocks()

View File

@ -73,6 +73,7 @@ import { getTimeDurationObject, printTimeDuration } from '@/util/time'
import { FULL_CREATION_AVAILABLE } from './const/const'
import { getUserCreations } from './util/creations'
import { findUserByIdentifier } from './util/findUserByIdentifier'
import { validateAlias } from './util/validateAlias'
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs
const random = require('random-bigint')
@ -504,6 +505,7 @@ export class UserResolver {
{
firstName,
lastName,
alias,
language,
password,
passwordNew,
@ -523,6 +525,10 @@ export class UserResolver {
user.lastName = lastName
}
if (alias && (await validateAlias(alias))) {
user.alias = alias
}
if (language) {
if (!isLanguage(language)) {
throw new LogError('Given language is not a valid language', language)

View File

@ -0,0 +1,125 @@
import { Connection } from '@dbTools/typeorm'
import { User } from '@entity/User'
import { ApolloServerTestClient } from 'apollo-server-testing'
import { testEnvironment, cleanDB } from '@test/helpers'
import { logger, i18n as localization } from '@test/testSetup'
import { userFactory } from '@/seeds/factory/user'
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
import { validateAlias } from './validateAlias'
let con: Connection
let testEnv: {
mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query']
con: Connection
}
beforeAll(async () => {
testEnv = await testEnvironment(logger, localization)
con = testEnv.con
await cleanDB()
})
afterAll(async () => {
await cleanDB()
await con.close()
})
describe('validate alias', () => {
beforeAll(() => {
jest.clearAllMocks()
})
describe('alias too short', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('Bi')).rejects.toEqual(new Error('Given alias is too short'))
expect(logger.error).toBeCalledWith('Given alias is too short', 'Bi')
})
})
describe('alias too long', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('BibiBloxbergHexHexHex')).rejects.toEqual(
new Error('Given alias is too long'),
)
expect(logger.error).toBeCalledWith('Given alias is too long', 'BibiBloxbergHexHexHex')
})
})
describe('alias contains invalid characters', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('Bibi.Bloxberg')).rejects.toEqual(
new Error('Invalid characters in alias'),
)
expect(logger.error).toBeCalledWith('Invalid characters in alias', 'Bibi.Bloxberg')
})
})
describe('alias is a reserved word', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('admin')).rejects.toEqual(new Error('Alias is not allowed'))
expect(logger.error).toBeCalledWith('Alias is not allowed', 'admin')
})
})
describe('alias is a reserved word with uppercase characters', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('Admin')).rejects.toEqual(new Error('Alias is not allowed'))
expect(logger.error).toBeCalledWith('Alias is not allowed', 'Admin')
})
})
describe('hyphens and underscore', () => {
describe('alias starts with underscore', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('_bibi')).rejects.toEqual(
new Error('Invalid characters in alias'),
)
expect(logger.error).toBeCalledWith('Invalid characters in alias', '_bibi')
})
})
describe('alias contains two following hyphens', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('bi--bi')).rejects.toEqual(
new Error('Invalid characters in alias'),
)
expect(logger.error).toBeCalledWith('Invalid characters in alias', 'bi--bi')
})
})
})
describe('test against existing alias in database', () => {
beforeAll(async () => {
const bibi = await userFactory(testEnv, bibiBloxberg)
const user = await User.findOne({ id: bibi.id })
if (user) {
user.alias = 'b-b'
await user.save()
}
})
describe('alias exists in database', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('b-b')).rejects.toEqual(new Error('Alias already in use'))
expect(logger.error).toBeCalledWith('Alias already in use', 'b-b')
})
})
describe('alias exists in database with in lower-case', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('b-B')).rejects.toEqual(new Error('Alias already in use'))
expect(logger.error).toBeCalledWith('Alias already in use', 'b-B')
})
})
describe('valid alias', () => {
it('resolves to true', async () => {
await expect(validateAlias('bibi')).resolves.toEqual(true)
})
})
})
})

View File

@ -0,0 +1,38 @@
import { Raw } from '@dbTools/typeorm'
import { User as DbUser } from '@entity/User'
import { LogError } from '@/server/LogError'
const reservedAlias = [
'admin',
'email',
'gast',
'gdd',
'gradido',
'guest',
'home',
'root',
'support',
'temp',
'tmp',
'tmp',
'user',
'usr',
'var',
]
export const validateAlias = async (alias: string): Promise<boolean> => {
if (alias.length < 3) throw new LogError('Given alias is too short', alias)
if (alias.length > 20) throw new LogError('Given alias is too long', alias)
/* eslint-disable-next-line security/detect-unsafe-regex */
if (!alias.match(/^[0-9A-Za-z]([_-]?[A-Za-z0-9])+$/))
throw new LogError('Invalid characters in alias', alias)
if (reservedAlias.includes(alias.toLowerCase())) throw new LogError('Alias is not allowed', alias)
const aliasInUse = await DbUser.find({
where: { alias: Raw((a) => `LOWER(${a}) = "${alias.toLowerCase()}"`) },
})
if (aliasInUse.length !== 0) {
throw new LogError('Alias already in use', alias)
}
return true
}

View File

@ -28,6 +28,7 @@ export const updateUserInfos = gql`
mutation (
$firstName: String
$lastName: String
$alias: String
$password: String
$passwordNew: String
$locale: String
@ -37,6 +38,7 @@ export const updateUserInfos = gql`
updateUserInfos(
firstName: $firstName
lastName: $lastName
alias: $alias
password: $password
passwordNew: $passwordNew
language: $locale