From 42f03d3d907c41ba525036225442a492a32c0367 Mon Sep 17 00:00:00 2001 From: Mnigos Date: Sat, 23 Dec 2023 08:43:56 +0100 Subject: [PATCH] feat(modules/users/users-profile.controller): add `/state` route --- src/common/constants/errors.ts | 1 + src/modules/player/player.module.ts | 1 + .../users/users-profile.controller.spec.ts | 41 +++++++++++++++++++ src/modules/users/users-profile.controller.ts | 33 ++++++++++++++- src/modules/users/users.module.ts | 2 + 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/common/constants/errors.ts diff --git a/src/common/constants/errors.ts b/src/common/constants/errors.ts new file mode 100644 index 00000000..f04e3238 --- /dev/null +++ b/src/common/constants/errors.ts @@ -0,0 +1 @@ +export const NO_TOKEN_PROVIDED = 'No token provided' as const diff --git a/src/modules/player/player.module.ts b/src/modules/player/player.module.ts index 46da824a..f33621fa 100644 --- a/src/modules/player/player.module.ts +++ b/src/modules/player/player.module.ts @@ -22,5 +22,6 @@ import { Environment } from '@config/environment' ], controllers: [PlayerController], providers: [PlayerService], + exports: [PlayerService], }) export class PlayerModule {} diff --git a/src/modules/users/users-profile.controller.spec.ts b/src/modules/users/users-profile.controller.spec.ts index 75737676..b7cdcc27 100644 --- a/src/modules/users/users-profile.controller.spec.ts +++ b/src/modules/users/users-profile.controller.spec.ts @@ -14,8 +14,10 @@ import { spotifyResponseWithOffsetMockFactory, artistsMock, analysisMock, + playbackStateMock, } from '@common/mocks' import { SecretData } from '@modules/auth/dtos' +import { PlayerService } from '@modules/player' describe('UsersProfileController', () => { const accessToken = 'accessToken' @@ -34,6 +36,7 @@ describe('UsersProfileController', () => { let usersRepository: UsersRepository let authService: AuthService let statisticsService: StatisticsService + let playerService: PlayerService beforeEach(async () => { const module = await Test.createTestingModule({ @@ -63,6 +66,12 @@ describe('UsersProfileController', () => { analysis: vi.fn(), }, }, + { + provide: PlayerService, + useValue: { + currentPlaybackState: vi.fn(), + }, + }, ], }).compile() @@ -70,6 +79,7 @@ describe('UsersProfileController', () => { usersRepository = module.get(UsersRepository) authService = module.get(AuthService) statisticsService = module.get(StatisticsService) + playerService = module.get(PlayerService) }) test('should be defined', () => { @@ -358,4 +368,35 @@ describe('UsersProfileController', () => { expect(findOneBySpy).toHaveBeenCalledWith({ id }) }) }) + + describe('getState', () => { + test('should get user playback state', async () => { + const findOneBySpy = vi + .spyOn(usersRepository, 'findOneBy') + .mockResolvedValue(userMock) + const tokenSpy = vi + .spyOn(authService, 'token') + .mockResolvedValue(secretDataMock) + const currentPlaybackStateSpy = vi + .spyOn(playerService, 'currentPlaybackState') + .mockResolvedValue(playbackStateMock) + + expect(await usersProfileController.getState(id)).toEqual( + playbackStateMock + ) + expect(currentPlaybackStateSpy).toHaveBeenCalledWith(accessToken) + expect(findOneBySpy).toHaveBeenCalledWith({ id }) + expect(tokenSpy).toHaveBeenCalledWith({ + refreshToken: userMock.refreshToken, + }) + }) + + test('should throw an error if no user is found', async () => { + const findOneBySpy = vi.spyOn(usersRepository, 'findOneBy') + + await expect(usersProfileController.getState(id)).rejects.toThrowError() + + expect(findOneBySpy).toHaveBeenCalledWith({ id }) + }) + }) }) diff --git a/src/modules/users/users-profile.controller.ts b/src/modules/users/users-profile.controller.ts index 892006a0..09ddca62 100644 --- a/src/modules/users/users-profile.controller.ts +++ b/src/modules/users/users-profile.controller.ts @@ -20,6 +20,7 @@ import { import { UsersRepository } from './users.repository' import { USER } from './users.controller' +import { PlayerService } from '@modules/player' import { ApiItemQuery } from '@modules/statistics/decorators' import { StatisticsService, @@ -43,7 +44,8 @@ export class UsersProfileController { private readonly usersRepository: UsersRepository, @Inject(forwardRef(() => AuthService)) private readonly authService: AuthService, - private readonly statisticsService: StatisticsService + private readonly statisticsService: StatisticsService, + private readonly playerService: PlayerService ) {} @Get('last-tracks') @@ -213,4 +215,33 @@ export class UsersProfileController { return this.statisticsService.analysis(accessToken) } + + @Get('state') + @ApiOperation({ + summary: "Getting user's playback state.", + }) + @ApiParam({ name: 'id' }) + @ApiOkResponse({ + description: ONE_SUCCESFULLY_FOUND(USER), + }) + @ApiNotFoundResponse({ + description: NOT_BEEN_FOUND(USER), + }) + @ApiBadRequestResponse({ + description: ONE_IS_INVALID('uuid'), + }) + async getState( + @Param('id', ParseUUIDPipe) id: string, + @Token() _token?: string + ) { + const foundUser = await this.usersRepository.findOneBy({ id }) + + if (!foundUser) throw new NotFoundException(NOT_BEEN_FOUND(USER)) + + const { accessToken } = await this.authService.token({ + refreshToken: foundUser.refreshToken, + }) + + return this.playerService.currentPlaybackState(accessToken) + } } diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index fa7418bf..d0df53e0 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -8,12 +8,14 @@ import { UsersProfileController } from './users-profile.controller' import { AuthModule } from '@modules/auth' import { StatisticsModule } from '@modules/statistics' +import { PlayerModule } from '@modules/player' @Module({ imports: [ TypeOrmModule.forFeature([User]), forwardRef(() => AuthModule), StatisticsModule, + PlayerModule, ], providers: [UsersRepository], controllers: [UsersController, UsersProfileController],