Skip to content

Commit

Permalink
Feat(Image, Video): Get video/image details by id route
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur-Poffo committed Feb 28, 2024
1 parent e271382 commit 7355306
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { makeImage } from '../../../../../test/factories/make-image'
import { InMemoryImagesRepository } from './../../../../../test/repositories/in-memory-images-repository'
import { GetImageDetailsByIdByIdUseCase } from './get-image-details-by-id'

let inMemoryImagesRepository: InMemoryImagesRepository
let sut: GetImageDetailsByIdByIdUseCase

describe('Get image details use case', async () => {
beforeEach(() => {
inMemoryImagesRepository = new InMemoryImagesRepository()
sut = new GetImageDetailsByIdByIdUseCase(inMemoryImagesRepository)
})

it('should be able to get image details', async () => {
const name = 'john-doe-image.jpeg'

const image = makeImage({ imageName: name, imageKey: '23323232-image.jpeg' })

await inMemoryImagesRepository.create(image)

const result = await sut.exec({
imageId: image.id.toString()
})

expect(result.isRight()).toBe(true)
expect(result.value).toMatchObject({
image: expect.objectContaining({
imageName: name
})
})
})

it('should not be able to get image details of a inexistent image', async () => {
const result = await sut.exec({
imageId: 'inexistentImageId'
})

expect(result.isLeft()).toBe(true)
expect(result.value).toBeInstanceOf(ResourceNotFoundError)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { left, right, type Either } from '@/core/either'
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { type UseCase } from '@/core/use-cases/use-case'
import { type Image } from '../../enterprise/entities/image'
import { type ImagesRepository } from '../repositories/images-repository'

interface GetImageDetailsByIdUseCaseRequest {
imageId: string
}

type GetImageDetailsByIdUseCaseResponse = Either<
ResourceNotFoundError,
{
image: Image
}
>

export class GetImageDetailsByIdByIdUseCase implements UseCase<GetImageDetailsByIdUseCaseRequest, GetImageDetailsByIdUseCaseResponse> {
constructor(
private readonly imagesRepository: ImagesRepository
) { }

async exec({
imageId
}: GetImageDetailsByIdUseCaseRequest): Promise<GetImageDetailsByIdUseCaseResponse> {
const image = await this.imagesRepository.findById(imageId)

if (!image) {
return left(new ResourceNotFoundError())
}

return right({
image
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('Get image details use case', async () => {

it('should not be able to get image details of a inexistent image', async () => {
const result = await sut.exec({
fileKey: 'inexistentImageId'
fileKey: 'inexistentImageKey'
})

expect(result.isLeft()).toBe(true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { makeVideo } from '../../../../../test/factories/make-video'
import { InMemoryVideosRepository } from './../../../../../test/repositories/in-memory-videos-repository'
import { GetVideoDetailsByIdUseCase } from './get-video-details-by-id'

let inMemoryVideosRepository: InMemoryVideosRepository
let sut: GetVideoDetailsByIdUseCase

describe('Get video details use case', async () => {
beforeEach(() => {
inMemoryVideosRepository = new InMemoryVideosRepository()
sut = new GetVideoDetailsByIdUseCase(inMemoryVideosRepository)
})

it('should be able to get video details', async () => {
const name = 'john-doe-video.mp4'

const video = makeVideo({ videoName: name, videoKey: '2332323-video.mp4' })

await inMemoryVideosRepository.create(video)

const result = await sut.exec({
videoId: video.id.toString()
})

expect(result.isRight()).toBe(true)
expect(result.value).toMatchObject({
video: expect.objectContaining({
videoName: name
})
})
})

it('should not be able to get video details of a inexistent video', async () => {
const result = await sut.exec({
videoId: 'inexistentVideoId'
})

expect(result.isLeft()).toBe(true)
expect(result.value).toBeInstanceOf(ResourceNotFoundError)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { left, right, type Either } from '@/core/either'
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { type UseCase } from '@/core/use-cases/use-case'
import { type Video } from '../../enterprise/entities/video'
import { type VideosRepository } from '../repositories/videos-repository'

interface GetVideoDetailsByIdUseCaseRequest {
videoId: string
}

type GetVideoDetailsByIdUseCaseResponse = Either<
ResourceNotFoundError,
{
video: Video
}
>

export class GetVideoDetailsByIdUseCase implements UseCase<GetVideoDetailsByIdUseCaseRequest, GetVideoDetailsByIdUseCaseResponse> {
constructor(
private readonly videosRepository: VideosRepository
) { }

async exec({
videoId
}: GetVideoDetailsByIdUseCaseRequest): Promise<GetVideoDetailsByIdUseCaseResponse> {
const video = await this.videosRepository.findById(videoId)

if (!video) {
return left(new ResourceNotFoundError())
}

return right({
video
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('Get video details use case', async () => {

it('should not be able to get video details of a inexistent video', async () => {
const result = await sut.exec({
fileKey: 'inexistentVideoId'
fileKey: 'inexistentVideoKey'
})

expect(result.isLeft()).toBe(true)
Expand Down
37 changes: 37 additions & 0 deletions src/infra/http/controllers/get-image-details-by-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { ImageMapper } from '@/infra/database/prisma/mappers/image-mapper'
import { makeGetImageDetailsByIdUseCase } from '@/infra/use-cases/factories/make-get-image-details-by-id-use-case'
import { type FastifyReply, type FastifyRequest } from 'fastify'
import { z } from 'zod'
import { ImagePresenter } from '../presenters/image-presenter'

const getImageDetailsByIdParamsSchema = z.object({
imageId: z.string()
})

export async function getImageDetailsByIdController(request: FastifyRequest, reply: FastifyReply) {
const { imageId } = getImageDetailsByIdParamsSchema.parse(request.params)

const getImageInfoUseCase = makeGetImageDetailsByIdUseCase()

const result = await getImageInfoUseCase.exec({
imageId
})

if (result.isLeft()) {
const error = result.value

switch (error.constructor) {
case ResourceNotFoundError:
return await reply.status(404).send({ message: error.message })
default:
return await reply.status(500).send({ message: error.message })
}
}

const image = ImageMapper.toPrisma(result.value.image)

return await reply.status(200).send({
image: ImagePresenter.toHTTP(image)
})
}
37 changes: 37 additions & 0 deletions src/infra/http/controllers/get-video-details-by-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { VideoMapper } from '@/infra/database/prisma/mappers/video-mapper'
import { makeGetVideoDetailsByIdUseCase } from '@/infra/use-cases/factories/make-get-video-details-by-id-use-case'
import { type FastifyReply, type FastifyRequest } from 'fastify'
import { z } from 'zod'
import { VideoPresenter } from '../presenters/video-presenter'

const getVideoDetailsByIdParamsSchema = z.object({
videoId: z.string()
})

export async function getVideoDetailsByIdController(request: FastifyRequest, reply: FastifyReply) {
const { videoId } = getVideoDetailsByIdParamsSchema.parse(request.params)

const getVideoInfoUseCase = makeGetVideoDetailsByIdUseCase()

const result = await getVideoInfoUseCase.exec({
videoId
})

if (result.isLeft()) {
const error = result.value

switch (error.constructor) {
case ResourceNotFoundError:
return await reply.status(404).send({ message: error.message })
default:
return await reply.status(500).send({ message: error.message })
}
}

const video = VideoMapper.toPrisma(result.value.video)

return await reply.status(200).send({
video: VideoPresenter.toHTTP(video)
})
}
4 changes: 3 additions & 1 deletion src/infra/http/routes/image.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { type FastifyInstance } from 'fastify'
import { getImageDetailsController } from '../controllers/get-image-details'
import { getImageDetailsByIdController } from '../controllers/get-image-details-by-id'
import { verifyJwt } from '../middlewares/verify-jwt'

export async function imageRoutes(app: FastifyInstance) {
app.get('/images/:fileKey', { onRequest: [verifyJwt] }, getImageDetailsController)
app.get('/images/find/key/:fileKey', { onRequest: [verifyJwt] }, getImageDetailsController)
app.get('/images/find/id/:imageId', { onRequest: [verifyJwt] }, getImageDetailsByIdController)
}
4 changes: 3 additions & 1 deletion src/infra/http/routes/video.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { type FastifyInstance } from 'fastify'
import { getVideoDetailsController } from '../controllers/get-video-details'
import { getVideoDetailsByIdController } from '../controllers/get-video-details-by-id'
import { verifyJwt } from '../middlewares/verify-jwt'

export async function videoRoutes(app: FastifyInstance) {
app.get('/videos/:fileKey', { onRequest: [verifyJwt] }, getVideoDetailsController)
app.get('/videos/find/key/:fileKey', { onRequest: [verifyJwt] }, getVideoDetailsController)
app.get('/videos/find/id/:videoId', { onRequest: [verifyJwt] }, getVideoDetailsByIdController)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { GetImageDetailsByIdByIdUseCase } from '@/domain/course-management/application/use-cases/get-image-details-by-id'
import { PrismaImagesRepository } from '@/infra/database/prisma/repositories/prisma-images-repository'

export function makeGetImageDetailsByIdUseCase() {
const prismaImagesRepository = new PrismaImagesRepository()

const getImageDetailsByIdUseCase = new GetImageDetailsByIdByIdUseCase(
prismaImagesRepository
)

return getImageDetailsByIdUseCase
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { GetVideoDetailsByIdUseCase } from '@/domain/course-management/application/use-cases/get-video-details-by-id'
import { PrismaVideosRepository } from '@/infra/database/prisma/repositories/prisma-videos-repository'

export function makeGetVideoDetailsByIdUseCase() {
const prismaVideosRepository = new PrismaVideosRepository()

const getVideoDetailsByIdUseCase = new GetVideoDetailsByIdUseCase(
prismaVideosRepository
)

return getVideoDetailsByIdUseCase
}

0 comments on commit 7355306

Please sign in to comment.