Merge pull request #1521 from gradido/user_soft_delete_backend

feature: Soft-Delete for users (backend)
This commit is contained in:
Ulf Gebhardt 2022-02-18 17:22:56 +01:00 committed by GitHub
commit a45a6961cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 39 deletions

View File

@ -23,6 +23,7 @@ import { calculateDecay } from '../../util/decay'
import { AdminPendingCreation } from '@entity/AdminPendingCreation'
import { hasElopageBuys } from '../../util/hasElopageBuys'
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
import { User } from '@entity/User'
// const EMAIL_OPT_IN_REGISTER = 1
// const EMAIL_OPT_UNKNOWN = 3 // elopage?
@ -82,8 +83,13 @@ export class AdminResolver {
async createPendingCreation(
@Args() { email, amount, memo, creationDate, moderator }: CreatePendingCreationArgs,
): Promise<number[]> {
const userRepository = getCustomRepository(UserRepository)
const user = await userRepository.findByEmail(email)
const user = await User.findOne({ email }, { withDeleted: true })
if (!user) {
throw new Error(`Could not find user with email: ${email}`)
}
if (user.deletedAt) {
throw new Error('This user was deleted. Cannot make a creation.')
}
if (!user.emailChecked) {
throw new Error('Creation could not be saved, Email is not activated')
}
@ -134,8 +140,13 @@ export class AdminResolver {
async updatePendingCreation(
@Args() { id, email, amount, memo, creationDate, moderator }: UpdatePendingCreationArgs,
): Promise<UpdatePendingCreation> {
const userRepository = getCustomRepository(UserRepository)
const user = await userRepository.findByEmail(email)
const user = await User.findOne({ email }, { withDeleted: true })
if (!user) {
throw new Error(`Could not find user with email: ${email}`)
}
if (user.deletedAt) {
throw new Error(`User was deleted (${email})`)
}
const pendingCreationToUpdate = await AdminPendingCreation.findOneOrFail({ id })

View File

@ -272,16 +272,6 @@ async function addUserTransaction(
})
}
async function getPublicKey(email: string): Promise<string | null> {
const user = await dbUser.findOne({ email: email })
// User not found
if (!user) {
return null
}
return user.pubKey.toString('hex')
}
@Resolver()
export class TransactionResolver {
@Authorized([RIGHTS.TRANSACTION_LIST])
@ -301,7 +291,7 @@ export class TransactionResolver {
const userRepository = getCustomRepository(UserRepository)
let userEntity: dbUser | undefined
if (userId) {
userEntity = await userRepository.findOneOrFail({ id: userId })
userEntity = await userRepository.findOneOrFail({ id: userId }, { withDeleted: true })
} else {
userEntity = await userRepository.findByPubkeyHex(context.pubKey)
}
@ -357,18 +347,15 @@ export class TransactionResolver {
// validate recipient user
// TODO: the detour over the public key is unnecessary
const recipiantPublicKey = await getPublicKey(email)
if (!recipiantPublicKey) {
const recipientUser = await dbUser.findOne({ email: email }, { withDeleted: true })
if (!recipientUser) {
throw new Error('recipient not known')
}
if (!isHexPublicKey(recipiantPublicKey)) {
throw new Error('invalid recipiant public key')
if (recipientUser.deletedAt) {
throw new Error('The recipient account was deleted')
}
const recipiantUser = await userRepository.findByPubkeyHex(recipiantPublicKey)
if (!recipiantUser) {
throw new Error('Cannot find recipiant user by local send coins transaction')
} else if (recipiantUser.deletedAt) {
throw new Error('recipiant user account is disabled')
if (!isHexPublicKey(recipientUser.pubKey.toString('hex'))) {
throw new Error('invalid recipient public key')
}
// validate amount
@ -405,7 +392,7 @@ export class TransactionResolver {
// Insert Transaction: recipient + amount
const recipiantUserTransactionBalance = await addUserTransaction(
recipiantUser,
recipientUser,
transaction,
centAmount,
queryRunner,
@ -421,7 +408,7 @@ export class TransactionResolver {
// Update Balance: recipiant + amount
const recipiantStateBalance = await updateStateBalance(
recipiantUser,
recipientUser,
centAmount,
transaction.received,
queryRunner,
@ -439,8 +426,8 @@ export class TransactionResolver {
transactionSendCoin.transactionId = transaction.id
transactionSendCoin.userId = senderUser.id
transactionSendCoin.senderPublic = senderUser.pubKey
transactionSendCoin.recipiantUserId = recipiantUser.id
transactionSendCoin.recipiantPublic = Buffer.from(recipiantPublicKey, 'hex')
transactionSendCoin.recipiantUserId = recipientUser.id
transactionSendCoin.recipiantPublic = recipientUser.pubKey
transactionSendCoin.amount = centAmount
transactionSendCoin.senderFinalBalance = senderStateBalance.amount
await queryRunner.manager.save(transactionSendCoin).catch((error) => {
@ -474,9 +461,9 @@ export class TransactionResolver {
await sendTransactionReceivedEmail({
senderFirstName: senderUser.firstName,
senderLastName: senderUser.lastName,
recipientFirstName: recipiantUser.firstName,
recipientLastName: recipiantUser.lastName,
email: recipiantUser.email,
recipientFirstName: recipientUser.firstName,
recipientLastName: recipientUser.lastName,
email: recipientUser.email,
amount,
memo,
})

View File

@ -250,9 +250,12 @@ export class UserResolver {
@Ctx() context: any,
): Promise<User> {
email = email.trim().toLowerCase()
const dbUser = await DbUser.findOneOrFail({ email }).catch(() => {
const dbUser = await DbUser.findOneOrFail({ email }, { withDeleted: true }).catch(() => {
throw new Error('No user with this credentials')
})
if (dbUser.deletedAt) {
throw new Error('This user was permanently disabled. Contact support for questions.')
}
if (!dbUser.emailChecked) {
throw new Error('User email not validated')
}
@ -335,9 +338,9 @@ export class UserResolver {
// Validate email unique
// TODO: i can register an email in upper/lower case twice
const userRepository = getCustomRepository(UserRepository)
const usersFound = await userRepository.count({ email })
if (usersFound !== 0) {
// TODO we cannot use repository.count(), since it does not allow to specify if you want to include the soft deletes
const userFound = await DbUser.findOne({ email }, { withDeleted: true })
if (userFound) {
// TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent.
throw new Error(`User already exists.`)
}

View File

@ -14,10 +14,6 @@ export class UserRepository extends Repository<User> {
return await this.findByPubkeyHex(pubKeyString)
}
async findByEmail(email: string): Promise<User> {
return this.createQueryBuilder('user').where('user.email = :email', { email }).getOneOrFail()
}
async getUsersIndiced(userIds: number[]): Promise<User[]> {
if (!userIds.length) return []
const users = await this.createQueryBuilder('user')
@ -33,6 +29,7 @@ export class UserRepository extends Repository<User> {
async findBySearchCriteria(searchCriteria: string): Promise<User[]> {
return await this.createQueryBuilder('user')
.withDeleted()
.where(
'user.firstName like :name or user.lastName like :lastName or user.email like :email',
{