forked from IT-Academy-BCN/ita-wiki
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
173 get user favorite resources (IT-Academy-BCN#234)
- Loading branch information
1 parent
2fb4dde
commit e9e6d15
Showing
11 changed files
with
349 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import supertest from 'supertest' | ||
import { RESOURCE_TYPE, User, Topic } from '@prisma/client' | ||
import { expect, test, describe, beforeAll, afterAll } from 'vitest' | ||
import { server, testUserData } from '../globalSetup' | ||
import { prisma } from '../../prisma/client' | ||
|
||
let testUser: User | ||
let testTopic: Topic | ||
|
||
beforeAll(async () => { | ||
testUser = (await prisma.user.findUnique({ | ||
where: { dni: testUserData.admin.dni }, | ||
})) as User | ||
|
||
const resourceData = [ | ||
{ | ||
title: 'test-resource-1-favorites', | ||
slug: 'test-resource-1-favorites', | ||
description: 'random description', | ||
url: 'https://sample.com', | ||
userId: testUser.id, | ||
resourceType: 'BLOG' as RESOURCE_TYPE, | ||
}, | ||
{ | ||
title: 'test-resource-2-favorites', | ||
slug: 'test-resource-2-favorites', | ||
description: 'random description', | ||
url: 'https://sample.com', | ||
userId: testUser.id, | ||
resourceType: 'VIDEO' as RESOURCE_TYPE, | ||
}, | ||
] | ||
|
||
const resources = await prisma.$transaction( | ||
resourceData.map((resource) => prisma.resource.create({ data: resource })) | ||
) | ||
|
||
const favoritesData = [ | ||
{ | ||
userId: testUser.id, | ||
resourceId: resources[0].id, | ||
}, | ||
] | ||
|
||
await prisma.favorites.createMany({ | ||
data: favoritesData, | ||
}) | ||
|
||
testTopic = (await prisma.topic.findUnique({ | ||
where: { slug: 'testing' }, | ||
})) as Topic | ||
|
||
const topicsOnResources = [ | ||
{ | ||
topicId: testTopic.id, | ||
resourceId: resources[0].id, | ||
}, | ||
] | ||
|
||
await prisma.topicsOnResources.createMany({ | ||
data: topicsOnResources, | ||
}) | ||
}) | ||
|
||
afterAll(async () => { | ||
await prisma.topicsOnResources.deleteMany({ | ||
where: { topicId: testTopic.id }, | ||
}) | ||
|
||
await prisma.favorites.deleteMany({ | ||
where: { userId: testUser.id }, | ||
}) | ||
|
||
await prisma.resource.deleteMany({ | ||
where: { userId: testUser.id }, | ||
}) | ||
}) | ||
|
||
describe('Testing /favorites/ endpoint', () => { | ||
describe('Testing GET /by-user/:userId?/:categorySlug?', () => { | ||
test('Should respond OK status', async () => { | ||
const userId = testUser.id | ||
const response = await supertest(server).get( | ||
`/api/v1/favorites/by-user/${userId}` | ||
) | ||
expect(response.status).toBe(200) | ||
}) | ||
test('Should respond 400 status without userId', async () => { | ||
const response = await supertest(server).get(`/api/v1/favorites/by-user/`) | ||
expect(response.status).toBe(400) | ||
}) | ||
test('Should respond 404 status without valid userId', async () => { | ||
const userId = 'invalidUserId' | ||
const response = await supertest(server).get( | ||
`/api/v1/favorites/by-user/${userId}/testing` | ||
) | ||
expect(response.status).toBe(404) | ||
}) | ||
|
||
test('Should return favorites as an array of objects.', async () => { | ||
const userId = testUser.id | ||
const categorySlug = 'testing' | ||
const response = await supertest(server).get( | ||
`/api/v1/favorites/by-user/${userId}/${categorySlug}` | ||
) | ||
|
||
expect(response.body).toBeInstanceOf(Array) | ||
expect(response.body.length).toBeGreaterThan(0) | ||
expect(response.body).toEqual( | ||
expect.arrayContaining([ | ||
expect.objectContaining({ | ||
resource: expect.objectContaining({ | ||
id: expect.any(String), | ||
title: expect.any(String), | ||
slug: expect.any(String), | ||
description: expect.any(String), | ||
url: expect.any(String), | ||
resourceType: expect.any(String), | ||
userId: expect.any(String), | ||
createdAt: expect.any(String), | ||
updatedAt: expect.any(String), | ||
}), | ||
}), | ||
]) | ||
) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import Koa, { Middleware } from 'koa' | ||
import { prisma } from '../prisma/client' | ||
import { NotFoundError, DefaultError } from '../helpers/errors' | ||
|
||
export const getUserFavoriteResources: Middleware = async ( | ||
ctx: Koa.Context | ||
) => { | ||
const { userId, categorySlug } = ctx.params | ||
if (!userId) throw new DefaultError(400, 'User is needed') | ||
|
||
const user = await prisma.user.findUnique({ where: { id: userId } }) | ||
if (!user) throw new NotFoundError('User not found') | ||
let favorites | ||
if (categorySlug) { | ||
favorites = await prisma.favorites.findMany({ | ||
where: { | ||
userId, | ||
resource: { | ||
topics: { | ||
some: { | ||
topic: { | ||
category: { slug: categorySlug }, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
select: { | ||
resource: true, | ||
}, | ||
}) | ||
} else { | ||
favorites = await prisma.favorites.findMany({ | ||
where: { | ||
userId, | ||
}, | ||
select: { | ||
resource: true, | ||
}, | ||
}) | ||
} | ||
ctx.status = 200 | ||
ctx.body = favorites | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { pathRoot } from '../../routes/routes' | ||
import { registry } from '../registry' | ||
import { resourceSchema } from '../../schemas' | ||
import { z } from '../zod' | ||
|
||
registry.registerPath({ | ||
method: 'get', | ||
tags: ['favorites'], | ||
path: `${pathRoot.v1.favorites}/by-user/:userId`, | ||
description: | ||
'Takes a user Id and returns the list of favorites saved by that user', | ||
summary: 'Returns favorite resources by user', | ||
parameters: [ | ||
{ | ||
name: 'userId', | ||
in: 'path', | ||
required: true, | ||
description: 'ID of the user for which to retrieve favorite resources', | ||
}, | ||
{ | ||
name: 'categorySlug', | ||
in: 'path', | ||
required: true, | ||
description: | ||
'Slug of the category for which to retrieve favorite resources', | ||
example: 'node', | ||
}, | ||
], | ||
responses: { | ||
200: { | ||
description: 'Favorite resources retireved successfully.', | ||
content: { | ||
'application/json': { | ||
schema: z.array( | ||
z.object({ | ||
resource: resourceSchema.omit({ | ||
topics: true, | ||
}), | ||
}) | ||
), | ||
}, | ||
}, | ||
}, | ||
400: { | ||
description: 'User ID is required', | ||
content: { | ||
'application/json': { | ||
schema: z.object({ | ||
error: z.string().openapi({ example: 'UserId is required' }), | ||
}), | ||
}, | ||
}, | ||
}, | ||
404: { | ||
description: 'User not found', | ||
content: { | ||
'application/json': { | ||
schema: z.object({ | ||
error: z.string().openapi({ example: 'User not found' }), | ||
}), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Router from '@koa/router' | ||
import { getUserFavoriteResources } from '../controllers' | ||
import { pathRoot } from './routes' | ||
|
||
const favoritesRouter = new Router() | ||
|
||
favoritesRouter.prefix(pathRoot.v1.favorites) | ||
|
||
favoritesRouter.get( | ||
'/by-user/:userId?/:categorySlug?', | ||
getUserFavoriteResources | ||
) | ||
|
||
export { favoritesRouter } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.