Skip to content

Commit fab775e

Browse files
Merge pull request #13 from DevAnseSenior/feat-gyms
Feat gyms
2 parents 6cb1cbf + 910c3e9 commit fab775e

26 files changed

Lines changed: 584 additions & 27 deletions

src/app.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@ import fastifyJwt from '@fastify/jwt'
22
import fastify from 'fastify'
33
import { ZodError } from 'zod'
44
import { env } from './env'
5-
import { appRoutes } from './http/routes'
5+
import { checkInsRoutes } from './http/controllers/check-ins/routes'
6+
import { gymsRoutes } from './http/controllers/gyms/routes'
7+
import { usersRoutes } from './http/controllers/users/routes'
68

79
export const app = fastify()
810

911
app.register(fastifyJwt, {
1012
secret: env.JWT_SECRET,
1113
})
1214

13-
app.register(appRoutes)
15+
app.register(usersRoutes)
16+
app.register(gymsRoutes)
17+
app.register(checkInsRoutes)
1418

1519
app.setErrorHandler((error, _, reply) => {
1620
if (error instanceof ZodError) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { app } from '@/app'
2+
import { prisma } from '@/lib/prisma'
3+
import { createAndAuthenticateUser } from '@/utils/test/create-and-authenticate-user'
4+
import request from 'supertest'
5+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
6+
7+
describe('Create Check-In (e2e)', () => {
8+
beforeAll(async () => {
9+
await app.ready()
10+
})
11+
12+
afterAll(async () => {
13+
await app.close()
14+
})
15+
16+
it('should be able to create a check-in', async () => {
17+
const { token } = await createAndAuthenticateUser(app)
18+
19+
const gym = await prisma.gym.create({
20+
data: {
21+
title: 'JS Gym',
22+
latitude: -3.07446,
23+
longitude: -59.9450322,
24+
},
25+
})
26+
27+
const response = await request(app.server)
28+
.post(`/gyms/${gym.id}/check-ins`)
29+
.set('Authorization', `Bearer ${token}`)
30+
.send({
31+
latitude: -3.07446,
32+
longitude: -59.9450322,
33+
})
34+
35+
expect(response.statusCode).toEqual(201)
36+
})
37+
})
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { makeGCheckInUseCase } from '@/use-cases/factories/make-check-in-use-case'
2+
import { FastifyReply, FastifyRequest } from 'fastify'
3+
import { z } from 'zod'
4+
5+
export async function create(request: FastifyRequest, reply: FastifyReply) {
6+
const createCheckInParamsSchema = z.object({
7+
gymId: z.string().uuid(),
8+
})
9+
10+
const createCheckInBodySchema = z.object({
11+
latitude: z.number().refine((value) => {
12+
return Math.abs(value) <= 90
13+
}),
14+
longitude: z.number().refine((value) => {
15+
return Math.abs(value) <= 180
16+
}),
17+
})
18+
19+
const { gymId } = createCheckInParamsSchema.parse(request.params)
20+
const { latitude, longitude } = createCheckInBodySchema.parse(request.body)
21+
22+
const createGymUseCase = makeGCheckInUseCase()
23+
24+
await createGymUseCase.execute({
25+
gymId,
26+
userId: request.user.sub,
27+
userLatitude: latitude,
28+
userLongitude: longitude,
29+
})
30+
31+
return reply.status(201).send()
32+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { app } from '@/app'
2+
import { prisma } from '@/lib/prisma'
3+
import { createAndAuthenticateUser } from '@/utils/test/create-and-authenticate-user'
4+
import request from 'supertest'
5+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
6+
7+
describe('Check-In History (e2e)', () => {
8+
beforeAll(async () => {
9+
await app.ready()
10+
})
11+
12+
afterAll(async () => {
13+
await app.close()
14+
})
15+
16+
it('should be able to list the history of a check-ins', async () => {
17+
const { token } = await createAndAuthenticateUser(app)
18+
19+
const user = await prisma.user.findFirstOrThrow()
20+
21+
const gym = await prisma.gym.create({
22+
data: {
23+
title: 'JS Gym',
24+
latitude: -3.07446,
25+
longitude: -59.9450322,
26+
},
27+
})
28+
29+
await prisma.checkIn.createMany({
30+
data: [
31+
{
32+
gym_id: gym.id,
33+
user_id: user.id,
34+
},
35+
{
36+
gym_id: gym.id,
37+
user_id: user.id,
38+
},
39+
],
40+
})
41+
42+
const response = await request(app.server)
43+
.get('/check-ins/history')
44+
.set('Authorization', `Bearer ${token}`)
45+
.send()
46+
47+
expect(response.statusCode).toEqual(200)
48+
expect(response.body.checkIns).toEqual([
49+
expect.objectContaining({
50+
gym_id: gym.id,
51+
user_id: user.id,
52+
}),
53+
expect.objectContaining({
54+
gym_id: gym.id,
55+
user_id: user.id,
56+
}),
57+
])
58+
})
59+
})
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { makeFetchUserCheckInsHistoryUseCase } from '@/use-cases/factories/make-fetch-user-check-ins-history-use-case'
2+
import { FastifyReply, FastifyRequest } from 'fastify'
3+
import { z } from 'zod'
4+
5+
export async function history(request: FastifyRequest, reply: FastifyReply) {
6+
const checkInHistoryQuerySchema = z.object({
7+
page: z.coerce.number().min(1).default(1),
8+
})
9+
10+
const { page } = checkInHistoryQuerySchema.parse(request.query)
11+
12+
const fetchUserCheckInsUseCase = makeFetchUserCheckInsHistoryUseCase()
13+
14+
const { checkIns } = await fetchUserCheckInsUseCase.execute({
15+
userId: request.user.sub,
16+
page,
17+
})
18+
19+
return reply.status(200).send({
20+
checkIns,
21+
})
22+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { app } from '@/app'
2+
import { prisma } from '@/lib/prisma'
3+
import { createAndAuthenticateUser } from '@/utils/test/create-and-authenticate-user'
4+
import request from 'supertest'
5+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
6+
7+
describe('Check-In Metrics (e2e)', () => {
8+
beforeAll(async () => {
9+
await app.ready()
10+
})
11+
12+
afterAll(async () => {
13+
await app.close()
14+
})
15+
16+
it('should be able to get the count of check-ins', async () => {
17+
const { token } = await createAndAuthenticateUser(app)
18+
19+
const user = await prisma.user.findFirstOrThrow()
20+
21+
const gym = await prisma.gym.create({
22+
data: {
23+
title: 'JS Gym',
24+
latitude: -3.07446,
25+
longitude: -59.9450322,
26+
},
27+
})
28+
29+
await prisma.checkIn.createMany({
30+
data: [
31+
{
32+
gym_id: gym.id,
33+
user_id: user.id,
34+
},
35+
{
36+
gym_id: gym.id,
37+
user_id: user.id,
38+
},
39+
],
40+
})
41+
42+
const response = await request(app.server)
43+
.get('/check-ins/metrics')
44+
.set('Authorization', `Bearer ${token}`)
45+
.send()
46+
47+
expect(response.statusCode).toEqual(200)
48+
expect(response.body.checkInsCount).toEqual(2)
49+
})
50+
})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { makeGetUserMetricsUseCase } from '@/use-cases/factories/make-get-user-metrics-use-case'
2+
import { FastifyReply, FastifyRequest } from 'fastify'
3+
4+
export async function metrics(request: FastifyRequest, reply: FastifyReply) {
5+
const getUserMetricsUseCase = makeGetUserMetricsUseCase()
6+
7+
const { checkInsCount } = await getUserMetricsUseCase.execute({
8+
userId: request.user.sub,
9+
})
10+
11+
return reply.status(200).send({
12+
checkInsCount,
13+
})
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { verifyJwt } from '@/http/middlewares/verify-jwt'
2+
import { FastifyInstance } from 'fastify'
3+
4+
import { create } from './create'
5+
import { history } from './history'
6+
import { metrics } from './metrics'
7+
import { validate } from './validate'
8+
9+
export async function checkInsRoutes(app: FastifyInstance) {
10+
app.addHook('onRequest', verifyJwt)
11+
12+
app.get('/check-ins/history', history)
13+
app.get('/check-ins/metrics', metrics)
14+
15+
app.post('/gyms/:gymId/check-ins', create)
16+
app.patch('/check-ins/:checkInId/validate', validate)
17+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { app } from '@/app'
2+
import { prisma } from '@/lib/prisma'
3+
import { createAndAuthenticateUser } from '@/utils/test/create-and-authenticate-user'
4+
import request from 'supertest'
5+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
6+
7+
describe('Validate Check-In (e2e)', () => {
8+
beforeAll(async () => {
9+
await app.ready()
10+
})
11+
12+
afterAll(async () => {
13+
await app.close()
14+
})
15+
16+
it('should be able to validate a check-in', async () => {
17+
const { token } = await createAndAuthenticateUser(app)
18+
19+
const user = await prisma.user.findFirstOrThrow()
20+
21+
const gym = await prisma.gym.create({
22+
data: {
23+
title: 'JS Gym',
24+
latitude: -3.07446,
25+
longitude: -59.9450322,
26+
},
27+
})
28+
29+
let checkIn = await prisma.checkIn.create({
30+
data: {
31+
gym_id: gym.id,
32+
user_id: user.id,
33+
},
34+
})
35+
36+
const response = await request(app.server)
37+
.patch(`/check-ins/${checkIn.id}/validate`)
38+
.set('Authorization', `Bearer ${token}`)
39+
.send()
40+
41+
expect(response.statusCode).toEqual(204)
42+
43+
checkIn = await prisma.checkIn.findUniqueOrThrow({
44+
where: {
45+
id: checkIn.id,
46+
},
47+
})
48+
49+
expect(checkIn.validated_at).toEqual(expect.any(Date))
50+
})
51+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { makeValidateCheckInUseCase } from '@/use-cases/factories/make-validate-check-in-use-case'
2+
import { FastifyReply, FastifyRequest } from 'fastify'
3+
import { z } from 'zod'
4+
5+
export async function validate(request: FastifyRequest, reply: FastifyReply) {
6+
const validateCheckInParamsSchema = z.object({
7+
checkInId: z.string().uuid(),
8+
})
9+
10+
const { checkInId } = validateCheckInParamsSchema.parse(request.params)
11+
12+
const validateCheckInUseCase = makeValidateCheckInUseCase()
13+
14+
await validateCheckInUseCase.execute({
15+
checkInId,
16+
})
17+
18+
return reply.status(204).send()
19+
}

0 commit comments

Comments
 (0)