Skip to content

Commit

Permalink
feat(user-emails): create user emails table and type (#2470)
Browse files Browse the repository at this point in the history
* feat(user-emails): create user emails table and type

* chore(user-emails): add delete cascade

* chore(user-emails): fix tests

* chore(user-emails): add unique constraint for email and userId

* chore(user-emails): use random email in tests

* chore(user-emails): add todo to remove user-email in test

* chore(user-emails): code review changes

* chore(user-emails): use random passwords for tests

* chore(user-emails): fix test and code review changes
  • Loading branch information
alemagio authored Jul 8, 2024
1 parent 95184b6 commit a9e6dc5
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 1 deletion.
51 changes: 51 additions & 0 deletions packages/server/modules/core/tests/integration/user-emails.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { before } from 'mocha'
import { createUser } from '@/modules/core/services/users'
import { beforeEachContext } from '@/test/hooks'
import { expect } from 'chai'
import { getUserByEmail } from '@/modules/core/repositories/users'
import crs from 'crypto-random-string'

function createRandomEmail() {
return `${crs({ length: 6 })}@example.org`
}
function createRandomPassword() {
return crs({ length: 10 })
}

describe('Core @user-emails', () => {
before(async () => {
await beforeEachContext()
})
describe('getUserByEmail', () => {
it('should return null if user does not exist', async () => {
expect(await getUserByEmail('test@example.org')).to.be.null
})

it('should return user if user-email does not exist', async () => {
const email = createRandomEmail()
await createUser({
name: 'John Doe',
email,
password: createRandomPassword()
})
// TODO: delete user email

const user = (await getUserByEmail(email))!
expect(user.name).to.eq('John Doe')
expect(user.email).to.eq(email)
})

it('should return user merged with user-email', async () => {
const email = createRandomEmail()
await createUser({
name: 'John Doe',
email,
password: createRandomPassword()
})

const user = (await getUserByEmail(email))!
expect(user.name).to.eq('John Doe')
expect(user.email).to.eq(email)
})
})
})
3 changes: 2 additions & 1 deletion packages/server/modules/emails/tests/verifications.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ import { Express } from 'express'
import { getUser } from '@/modules/core/repositories/users'
import dayjs from 'dayjs'
import { EmailSendingServiceMock } from '@/test/mocks/global'
import { USER_EMAILS_TABLE_NAME } from '@/modules/user-emails/constants'

const mailerMock = EmailSendingServiceMock

const cleanup = async () => {
await truncateTables([Users.name, EmailVerifications.name])
await truncateTables([Users.name, EmailVerifications.name, USER_EMAILS_TABLE_NAME])
}

describe('Email verifications @emails', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/server/modules/user-emails/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const USER_EMAILS_TABLE_NAME = 'user_emails'
9 changes: 9 additions & 0 deletions packages/server/modules/user-emails/domain/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type UserEmail = {
id: string
email: string
primary: boolean
verified: boolean
userId: string
createdAt: Date
updatedAt: Date
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Knex } from 'knex'

export async function up(knex: Knex): Promise<void> {
await knex.schema.createTable('user_emails', (table) => {
table.string('id').notNullable().primary()
table.string('email').notNullable()
table.boolean('primary').defaultTo(false)
table.boolean('verified').defaultTo(false)
table
.string('userId')
.notNullable()
.references('id')
.inTable('users')
.onDelete('cascade')
table
.timestamp('createdAt', { precision: 3, useTz: true })
.defaultTo(knex.fn.now())
.notNullable()
table
.timestamp('updatedAt', { precision: 3, useTz: true })
.defaultTo(knex.fn.now())
.notNullable()
table.unique(['userId', 'email'])
})
}

export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists('user_emails')
}

0 comments on commit a9e6dc5

Please sign in to comment.