Skip to content

Commit

Permalink
feat(modules/users): implement controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Mnigos committed Oct 18, 2023
1 parent f1ea030 commit fc72424
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 20 deletions.
27 changes: 12 additions & 15 deletions src/modules/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import { AuthService } from './auth.service'
import { SecretData } from './dtos'

import { formattedProfileMock, profileMock, userMock } from '@common/mocks'
import { ProfilesRepository, ProfilesService } from '@modules/profiles'
import { ProfilesService } from '@modules/profiles'
import { UsersRepository } from '@modules/users'

describe('AuthController', () => {
const redirectUrl = 'http://test.com'

let authController: AuthController
let authService: AuthService
let profilesRepository: ProfilesRepository

let profilesService: ProfilesService
let usersRepository: UsersRepository

Expand All @@ -44,24 +44,18 @@ describe('AuthController', () => {
create: vi.fn(),
},
},
{
provide: ProfilesRepository,
useValue: {
findProfileById: vi.fn(),
},
},
{
provide: UsersRepository,
useValue: {
createUser: vi.fn(),
findUserByProfileId: vi.fn(),
},
},
],
}).compile()

authController = module.get<AuthController>(AuthController)
authService = module.get<AuthService>(AuthService)
profilesRepository = module.get<ProfilesRepository>(ProfilesRepository)
profilesService = module.get<ProfilesService>(ProfilesService)
usersRepository = module.get<UsersRepository>(UsersRepository)
})
Expand Down Expand Up @@ -109,9 +103,9 @@ describe('AuthController', () => {
vi.spyOn(authService, 'token').mockReturnValue(of(tokenResponse))
vi.spyOn(authService, 'profile').mockReturnValue(of(formattedProfileMock))

const findProfileByIdSpy = vi
.spyOn(profilesRepository, 'findProfileById')
.mockResolvedValue(profileMock)
const findUserByProfileId = vi
.spyOn(usersRepository, 'findUserByProfileId')
.mockResolvedValue(userMock)
const createSpy = vi.spyOn(profilesService, 'create')
const createUserSpy = vi.spyOn(usersRepository, 'createUser')

Expand All @@ -123,7 +117,7 @@ describe('AuthController', () => {
statusCode: HttpStatus.PERMANENT_REDIRECT,
})

expect(findProfileByIdSpy).toHaveBeenCalledWith(formattedProfileMock.id)
expect(findUserByProfileId).toHaveBeenCalledWith(formattedProfileMock.id)
expect(createSpy).not.toHaveBeenCalled()
expect(createUserSpy).not.toHaveBeenCalled()
})
Expand All @@ -132,7 +126,10 @@ describe('AuthController', () => {
vi.spyOn(authService, 'token').mockReturnValue(of(tokenResponse))
vi.spyOn(authService, 'profile').mockReturnValue(of(formattedProfileMock))

const findProfileByIdSpy = vi.spyOn(profilesRepository, 'findProfileById')
const findUserByProfileId = vi.spyOn(
usersRepository,
'findUserByProfileId'
)
const createSpy = vi
.spyOn(profilesService, 'create')
.mockResolvedValue(profileMock)
Expand All @@ -148,7 +145,7 @@ describe('AuthController', () => {
statusCode: HttpStatus.PERMANENT_REDIRECT,
})

expect(findProfileByIdSpy).toHaveBeenCalledWith(formattedProfileMock.id)
expect(findUserByProfileId).toHaveBeenCalledWith(formattedProfileMock.id)
expect(createSpy).toHaveBeenCalledWith(formattedProfileMock)
expect(createUserSpy).toHaveBeenCalledWith({
profile: profileMock,
Expand Down
7 changes: 3 additions & 4 deletions src/modules/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ProfileDto, SecretData } from './dtos'
import { Environment } from '@config/environment'
import { AuthenticationType } from '@modules/auth/enums'
import { UsersRepository } from '@modules/users'
import { ProfilesRepository, ProfilesService } from '@modules/profiles'
import { ProfilesService } from '@modules/profiles'

const {
SPOTIFY_CALLBACK_URL,
Expand All @@ -28,7 +28,6 @@ export class AuthController {
private readonly authService: AuthService,
private readonly configService: ConfigService,
private readonly profilesService: ProfilesService,
private readonly profilesRepository: ProfilesRepository,
private readonly usersRepository: UsersRepository
) {}

Expand Down Expand Up @@ -61,11 +60,11 @@ export class AuthController {
this.authService.profile(accessToken)
)

const foundProfile = await this.profilesRepository.findProfileById(
const foundUser = await this.usersRepository.findUserByProfileId(
spotifyProfile.id
)

if (!foundProfile) {
if (!foundUser) {
const profile = await this.profilesService.create(spotifyProfile)

await this.usersRepository.createUser({
Expand Down
122 changes: 122 additions & 0 deletions src/modules/users/users.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { beforeEach, describe, expect, test, vi } from 'vitest'
import { Test, TestingModule } from '@nestjs/testing'

import { UsersController } from './users.controller'
import { UsersRepository } from './users.repository'

import { userMock, usersMock } from '@common/mocks'

describe('UsersController', () => {
let usersController: UsersController
let usersRepository: UsersRepository

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersController,
{
provide: UsersRepository,
useValue: {
findUsers: vi.fn(),
findUserById: vi.fn(),
findUserByProfileId: vi.fn(),
findUserByDisplayName: vi.fn(),
},
},
],
}).compile()

usersController = module.get<UsersController>(UsersController)
usersRepository = module.get<UsersRepository>(UsersRepository)
})

test('should be defined', () => {
expect(usersController).toBeDefined()
})

describe('getAll', () => {
test('should get all users', async () => {
vi.spyOn(usersRepository, 'findUsers').mockResolvedValue(usersMock)

expect(await usersController.getAll()).toEqual(usersMock)

expect(usersRepository.findUsers).toHaveBeenCalled()
})

test('should get one user by username', async () => {
vi.spyOn(usersRepository, 'findUserByDisplayName').mockResolvedValue(
userMock
)

const username = 'username'

expect(await usersController.getAll(username)).toEqual(userMock)

expect(usersRepository.findUserByDisplayName).toHaveBeenCalledWith(
username
)
})

test('should throw an error if no user is found', async () => {
vi.spyOn(usersRepository, 'findUserByDisplayName')

const username = 'username'

await expect(usersController.getAll(username)).rejects.toThrowError()
})
})

describe('getOneById', () => {
test('should get one user by id', async () => {
vi.spyOn(usersRepository, 'findUserById').mockResolvedValue(userMock)

const id = '1'

expect(await usersController.getOneById(id)).toEqual(userMock)

expect(usersRepository.findUserById).toHaveBeenCalledWith(id)
})

test('should throw an error if no user is found', async () => {
vi.spyOn(usersRepository, 'findUserById')

const id = '1'

await expect(usersController.getOneById(id)).rejects.toThrowError()

expect(usersRepository.findUserById).toHaveBeenCalledWith(id)
})
})

describe('getOneByProfileId', () => {
test('should get one user by profile id', async () => {
vi.spyOn(usersRepository, 'findUserByProfileId').mockResolvedValue(
userMock
)

const profileId = '1'

expect(await usersController.getOneByProfileId(profileId)).toEqual(
userMock
)

expect(usersRepository.findUserByProfileId).toHaveBeenCalledWith(
profileId
)
})

test('should throw an error if no user is found', async () => {
vi.spyOn(usersRepository, 'findUserByProfileId')

const profileId = '1'

await expect(
usersController.getOneByProfileId(profileId)
).rejects.toThrowError()

expect(usersRepository.findUserByProfileId).toHaveBeenCalledWith(
profileId
)
})
})
})
105 changes: 105 additions & 0 deletions src/modules/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {
Controller,
Get,
HttpException,
HttpStatus,
NotFoundException,
Param,
ParseUUIDPipe,
Query,
} from '@nestjs/common'
import {
ApiBadRequestResponse,
ApiNoContentResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiParam,
ApiQuery,
ApiTags,
} from '@nestjs/swagger'

import { UsersRepository } from './users.repository'

import {
MANY_SUCCESFULLY_FOUND,
NOT_BEEN_FOUND,
ONE_IS_INVALID,
ONE_SUCCESFULLY_FOUND,
} from '@common/constants'

export const USER = 'user'
export const USERS = 'users'

@Controller(USERS)
@ApiTags(USERS)
export class UsersController {
constructor(private readonly usersRepository: UsersRepository) {}

@Get()
@ApiOperation({
summary: 'Getting all users.',
})
@ApiQuery({ name: 'username', required: false })
@ApiOkResponse({
description: MANY_SUCCESFULLY_FOUND(USERS),
})
@ApiNoContentResponse({
description: NOT_BEEN_FOUND(USER),
})
async getAll(@Query('username') username?: string) {
if (username) {
const foundUser = await this.usersRepository.findUserByDisplayName(
username
)

if (!foundUser)
throw new HttpException(NOT_BEEN_FOUND(USER), HttpStatus.NO_CONTENT)

return foundUser
}

return await this.usersRepository.findUsers()
}

@Get(':id')
@ApiOperation({
summary: 'Getting one user by id.',
})
@ApiParam({ name: 'id' })
@ApiOkResponse({
description: ONE_SUCCESFULLY_FOUND(USER),
})
@ApiNotFoundResponse({
description: NOT_BEEN_FOUND(USER),
})
@ApiBadRequestResponse({
description: ONE_IS_INVALID('uuid'),
})
async getOneById(@Param('id', ParseUUIDPipe) id: string) {
const foundUser = await this.usersRepository.findUserById(id)

if (!foundUser) throw new NotFoundException(NOT_BEEN_FOUND(USER))

return foundUser
}

@Get('profile/:id')
@ApiOperation({
summary: 'Getting one user by profile id.',
})
@ApiParam({ name: 'id' })
@ApiOkResponse({
description: ONE_SUCCESFULLY_FOUND(USER),
})
@ApiNotFoundResponse({
description: NOT_BEEN_FOUND(USER),
})
async getOneByProfileId(@Param('id') id: string) {
const foundUser = await this.usersRepository.findUserByProfileId(id)

if (!foundUser) throw new NotFoundException(NOT_BEEN_FOUND(USER))

return foundUser
}
}
2 changes: 2 additions & 0 deletions src/modules/users/users.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { TypeOrmModule } from '@nestjs/typeorm'

import { User } from './user.entity'
import { UsersRepository } from './users.repository'
import { UsersController } from './users.controller'

@Module({
imports: [TypeOrmModule.forFeature([User])],
providers: [UsersRepository],
controllers: [UsersController],
exports: [UsersRepository],
})
export class UsersModule {}
1 change: 1 addition & 0 deletions src/modules/users/users.repository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('UsersRepository', () => {
expect(user).toEqual(userMock)
expect(usersRepository.findOne).toHaveBeenCalledWith({
where: { profile: { id: profileId } },
relations: ['profile'],
})
})

Expand Down
5 changes: 4 additions & 1 deletion src/modules/users/users.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export class UsersRepository extends Repository<User> {
}

findUserByProfileId(profileId: string) {
return this.findOne({ where: { profile: { id: profileId } } })
return this.findOne({
where: { profile: { id: profileId } },
relations: ['profile'],
})
}

findUserByDisplayName(displayName: string) {
Expand Down

0 comments on commit fc72424

Please sign in to comment.