forked from Giveth/impact-graph
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from GeneralMagicio/addUserEmailVerification
Add user email verification
- Loading branch information
Showing
13 changed files
with
607 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { MigrationInterface, QueryRunner } from 'typeorm'; | ||
|
||
export class AddUserEmailVerificationFields1723583534955 | ||
implements MigrationInterface | ||
{ | ||
public async up(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query(` | ||
ALTER TABLE "user" | ||
ADD "emailConfirmationToken" character varying, | ||
ADD "emailConfirmationTokenExpiredAt" TIMESTAMP, | ||
ADD "emailConfirmed" boolean DEFAULT false, | ||
ADD "emailConfirmationSent" boolean DEFAULT false, | ||
ADD "emailConfirmationSentAt" TIMESTAMP, | ||
ADD "emailConfirmedAt" TIMESTAMP; | ||
`); | ||
} | ||
|
||
public async down(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query(` | ||
ALTER TABLE "user" | ||
DROP COLUMN "emailConfirmationToken", | ||
DROP COLUMN "emailConfirmationTokenExpiredAt", | ||
DROP COLUMN "emailConfirmed", | ||
DROP COLUMN "emailConfirmationSent", | ||
DROP COLUMN "emailConfirmationSentAt", | ||
DROP COLUMN "emailConfirmedAt"; | ||
`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,11 +11,14 @@ import { User, UserRole } from '../entities/user'; | |
import { | ||
findAdminUserByEmail, | ||
findAllUsers, | ||
findUserByEmailConfirmationToken, | ||
findUserById, | ||
findUserByWalletAddress, | ||
findUsersWhoDonatedToProjectExcludeWhoLiked, | ||
findUsersWhoLikedProjectExcludeProjectOwner, | ||
findUsersWhoSupportProject, | ||
updateUserEmailConfirmationStatus, | ||
updateUserEmailConfirmationToken, | ||
} from './userRepository'; | ||
import { Reaction } from '../entities/reaction'; | ||
|
||
|
@@ -44,6 +47,19 @@ describe( | |
findUsersWhoDonatedToProjectTestCases, | ||
); | ||
|
||
describe( | ||
'userRepository.findUserByEmailConfirmationToken', | ||
findUserByEmailConfirmationTokenTestCases, | ||
); | ||
describe( | ||
'userRepository.updateUserEmailConfirmationStatus', | ||
updateUserEmailConfirmationStatusTestCases, | ||
); | ||
describe( | ||
'userRepository.updateUserEmailConfirmationToken', | ||
updateUserEmailConfirmationTokenTestCases, | ||
); | ||
|
||
function findUsersWhoDonatedToProjectTestCases() { | ||
it('should find wallet addresses of who donated to a project, exclude who liked', async () => { | ||
const project = await saveProjectDirectlyToDb(createProjectData()); | ||
|
@@ -489,3 +505,107 @@ function findUsersWhoSupportProjectTestCases() { | |
); | ||
}); | ||
} | ||
|
||
function findUserByEmailConfirmationTokenTestCases() { | ||
it('should return a user if a valid email confirmation token is provided', async () => { | ||
await User.create({ | ||
email: '[email protected]', | ||
emailConfirmationToken: 'validToken123', | ||
loginType: 'wallet', | ||
}).save(); | ||
|
||
const foundUser = await findUserByEmailConfirmationToken('validToken123'); | ||
assert.isNotNull(foundUser); | ||
assert.equal(foundUser!.email, '[email protected]'); | ||
assert.equal(foundUser!.emailConfirmationToken, 'validToken123'); | ||
}); | ||
|
||
it('should return null if no user is found with the provided email confirmation token', async () => { | ||
const foundUser = await findUserByEmailConfirmationToken('invalidToken123'); | ||
assert.isNull(foundUser); | ||
}); | ||
} | ||
|
||
function updateUserEmailConfirmationStatusTestCases() { | ||
it('should update the email confirmation status of a user', async () => { | ||
const user = await User.create({ | ||
email: '[email protected]', | ||
emailConfirmed: false, | ||
emailConfirmationToken: 'validToken123', | ||
loginType: 'wallet', | ||
}).save(); | ||
|
||
await updateUserEmailConfirmationStatus({ | ||
userId: user.id, | ||
emailConfirmed: true, | ||
emailConfirmationTokenExpiredAt: null, | ||
emailConfirmationToken: null, | ||
emailConfirmationSentAt: null, | ||
}); | ||
|
||
// Using findOne with options object | ||
const updatedUser = await User.findOne({ where: { id: user.id } }); | ||
assert.isNotNull(updatedUser); | ||
assert.isTrue(updatedUser!.emailConfirmed); | ||
assert.isNull(updatedUser!.emailConfirmationToken); | ||
}); | ||
|
||
it('should not update any user if the userId does not exist', async () => { | ||
const result = await updateUserEmailConfirmationStatus({ | ||
userId: 999, // non-existent userId | ||
emailConfirmed: true, | ||
emailConfirmationTokenExpiredAt: null, | ||
emailConfirmationToken: null, | ||
emailConfirmationSentAt: null, | ||
}); | ||
|
||
assert.equal(result.affected, 0); // No rows should be affected | ||
}); | ||
} | ||
|
||
function updateUserEmailConfirmationTokenTestCases() { | ||
it('should update the email confirmation token and expiry date for a user', async () => { | ||
const user = await User.create({ | ||
email: '[email protected]', | ||
loginType: 'wallet', | ||
}).save(); | ||
|
||
const newToken = 'newToken123'; | ||
const newExpiryDate = new Date(Date.now() + 3600 * 1000); // 1 hour from now | ||
const sentAtDate = new Date(); | ||
|
||
await updateUserEmailConfirmationToken({ | ||
userId: user.id, | ||
emailConfirmationToken: newToken, | ||
emailConfirmationTokenExpiredAt: newExpiryDate, | ||
emailConfirmationSentAt: sentAtDate, | ||
}); | ||
|
||
// Using findOne with options object | ||
const updatedUser = await User.findOne({ where: { id: user.id } }); | ||
assert.isNotNull(updatedUser); | ||
assert.equal(updatedUser!.emailConfirmationToken, newToken); | ||
assert.equal( | ||
updatedUser!.emailConfirmationTokenExpiredAt!.getTime(), | ||
newExpiryDate.getTime(), | ||
); | ||
assert.equal( | ||
updatedUser!.emailConfirmationSentAt!.getTime(), | ||
sentAtDate.getTime(), | ||
); | ||
}); | ||
|
||
it('should throw an error if the userId does not exist', async () => { | ||
try { | ||
await updateUserEmailConfirmationToken({ | ||
userId: 999, // non-existent userId | ||
emailConfirmationToken: 'newToken123', | ||
emailConfirmationTokenExpiredAt: new Date(), | ||
emailConfirmationSentAt: new Date(), | ||
}); | ||
assert.fail('Expected an error to be thrown'); | ||
} catch (error) { | ||
assert.equal(error.message, 'User not found'); | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.