diff --git a/src/modules/auth/auth.controller.spec.ts b/src/modules/auth/auth.controller.spec.ts index 587861a0..d8ebce87 100644 --- a/src/modules/auth/auth.controller.spec.ts +++ b/src/modules/auth/auth.controller.spec.ts @@ -9,7 +9,7 @@ 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', () => { @@ -17,7 +17,7 @@ describe('AuthController', () => { let authController: AuthController let authService: AuthService - let profilesRepository: ProfilesRepository + let profilesService: ProfilesService let usersRepository: UsersRepository @@ -44,16 +44,11 @@ describe('AuthController', () => { create: vi.fn(), }, }, - { - provide: ProfilesRepository, - useValue: { - findProfileById: vi.fn(), - }, - }, { provide: UsersRepository, useValue: { createUser: vi.fn(), + findUserByProfileId: vi.fn(), }, }, ], @@ -61,7 +56,6 @@ describe('AuthController', () => { authController = module.get(AuthController) authService = module.get(AuthService) - profilesRepository = module.get(ProfilesRepository) profilesService = module.get(ProfilesService) usersRepository = module.get(UsersRepository) }) @@ -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') @@ -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() }) @@ -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) @@ -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, diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index b1681cd1..06b60375 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -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, @@ -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 ) {} @@ -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({ diff --git a/src/modules/users/users.controller.spec.ts b/src/modules/users/users.controller.spec.ts new file mode 100644 index 00000000..cab9d7ff --- /dev/null +++ b/src/modules/users/users.controller.spec.ts @@ -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) + usersRepository = module.get(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 + ) + }) + }) +}) diff --git a/src/modules/users/users.controller.ts b/src/modules/users/users.controller.ts new file mode 100644 index 00000000..d63373f0 --- /dev/null +++ b/src/modules/users/users.controller.ts @@ -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 + } +} diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index fb71ff41..6feb506e 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -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 {} diff --git a/src/modules/users/users.repository.spec.ts b/src/modules/users/users.repository.spec.ts index 9271defa..7fb90073 100644 --- a/src/modules/users/users.repository.spec.ts +++ b/src/modules/users/users.repository.spec.ts @@ -60,6 +60,7 @@ describe('UsersRepository', () => { expect(user).toEqual(userMock) expect(usersRepository.findOne).toHaveBeenCalledWith({ where: { profile: { id: profileId } }, + relations: ['profile'], }) }) diff --git a/src/modules/users/users.repository.ts b/src/modules/users/users.repository.ts index 8ad83aa0..42de3bb4 100644 --- a/src/modules/users/users.repository.ts +++ b/src/modules/users/users.repository.ts @@ -21,7 +21,10 @@ export class UsersRepository extends Repository { } findUserByProfileId(profileId: string) { - return this.findOne({ where: { profile: { id: profileId } } }) + return this.findOne({ + where: { profile: { id: profileId } }, + relations: ['profile'], + }) } findUserByDisplayName(displayName: string) {