Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e00990f
chore: removed deprecated version and put especifc version on docker …
andersonnaz Feb 9, 2026
defc19d
feat: add image field on database
andersonnaz Feb 9, 2026
7acfb11
feat: create update image on guardian repository
andersonnaz Feb 9, 2026
5a237d6
refactor: change pet image field name
andersonnaz Feb 9, 2026
c2e04c1
feat: add image field and new dependencies on add guardian use case
andersonnaz Feb 9, 2026
3826a63
feat: updated to receive image on create guardian use case implementa…
andersonnaz Feb 9, 2026
1f704b1
feat: updated to get image on signup controller
andersonnaz Feb 9, 2026
78f5c1c
feat: add upload middleware on signup route
andersonnaz Feb 9, 2026
8bb1b15
feat: updated add guardian use case implementation factory
andersonnaz Feb 9, 2026
a448a61
docs: update documentation with new type of request on signup route
andersonnaz Feb 9, 2026
f6d44db
fix: add verification if guardian already exists
andersonnaz Feb 9, 2026
05c9cee
test: add methods in mocks and stubs to test add guardian image field
andersonnaz Feb 9, 2026
98c9ed5
test: add image field on signup
andersonnaz Feb 9, 2026
ccbd100
test: add image field and filestorage dependencies on add guardian us…
andersonnaz Feb 9, 2026
634c85d
test: add default image field on add pet use case
andersonnaz Feb 9, 2026
d960a82
test: delete property of fakeUser in pet route
andersonnaz Feb 9, 2026
032abca
test: change test structure to multpart form data in signup route
andersonnaz Feb 9, 2026
74f150a
Update src/infra/repos/postgresql/guardian-account-repository.ts
andersonnaz Feb 12, 2026
a3a41ae
refactor: change select to omit in prisma update query
andersonnaz Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
version: '3.8'

services:
db:
image: postgres
image: postgres:16-alpine
container_name: petjournal_db
restart: always
ports:
Expand Down
4 changes: 3 additions & 1 deletion src/application/controllers/signup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ export class SignUpController implements Controller {
}

const { firstName, lastName, email, phone, password } = httpRequest.body
const image = httpRequest.file ?? null
const guardian = await this.addGuardian.add({
firstName,
lastName,
email,
phone,
password,
verificationToken: ''
verificationToken: '',
image
})

if (!guardian) {
Expand Down
1 change: 1 addition & 0 deletions src/data/protocols/db/guardian/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './update-verification-token-repository'
export * from './update-guardian-password-repository'
export * from './save-token-repository'
export * from './update-email-confirmation-repository'
export * from './update-guardian-image-repository'
19 changes: 19 additions & 0 deletions src/data/protocols/db/guardian/update-guardian-image-repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface UpdateGuardianImageRepository {
updateImage: (params: UpdateGuardianImageRepository.Params) => Promise<UpdateGuardianImageRepository.Result>
}

export namespace UpdateGuardianImageRepository {
export type Params = {
guardianId: string
image?: string
}

export type Result = {
id: string
firstName: string
lastName: string
email: string
phone: string
image: string
} | undefined
}
34 changes: 30 additions & 4 deletions src/data/use-cases/db-add-guardian.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,43 @@
import { type AddGuardian } from '@/domain/use-cases'
import { type AddGuardianRepository, type HashGenerator } from '@/data/protocols'
import { type FileStorage, type AddGuardianRepository, type HashGenerator, type UpdateGuardianImageRepository } from '@/data/protocols'

export class DbAddGuardian implements AddGuardian {
private readonly guardianRepository: AddGuardianRepository
private readonly guardianRepository: AddGuardianRepository & UpdateGuardianImageRepository
private readonly hashService: HashGenerator
private readonly fileStorage: FileStorage
private readonly defaultGuardianImageUrl: string

constructor ({ guardianRepository, hashService }: AddGuardian.Dependencies) {
constructor ({ guardianRepository, hashService, fileStorage, defaultGuardianImageUrl }: AddGuardian.Dependencies) {
this.guardianRepository = guardianRepository
this.hashService = hashService
this.fileStorage = fileStorage
this.defaultGuardianImageUrl = defaultGuardianImageUrl
}

async add (guardianData: AddGuardian.Params): Promise<AddGuardian.Result> {
const hashedPassword = await this.hashService.encrypt({ value: guardianData.password })
return await this.guardianRepository.add(Object.assign({}, guardianData, { password: hashedPassword }))
const guardian = await this.guardianRepository.add(Object.assign({}, { ...guardianData, image: '' }, { password: hashedPassword }))

if (!guardian) {
return undefined
}

let imageUrl: string = ''
if (guardianData.image) {
imageUrl = await this.fileStorage.save({ file: guardianData.image, fileName: `images/guardian-${guardian?.id}` })
}

if (imageUrl) {
await this.guardianRepository.updateImage({ guardianId: guardian?.id, image: imageUrl })
}

return {
id: guardian?.id,
email: guardian?.email,
firstName: guardian?.firstName,
lastName: guardian?.lastName,
phone: guardian?.phone,
image: imageUrl ?? this.defaultGuardianImageUrl
}
}
}
8 changes: 4 additions & 4 deletions src/data/use-cases/pet/db-add-pet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ export class DbAddPet implements AddPet {
private readonly petRepository: AddPetRepository & UpdatePetRepository
private readonly appointPet: AppointPet
private readonly fileStorage: FileStorage
private readonly defaultImageUrl: string
private readonly defaultPetImageUrl: string

constructor ({
guardianRepository,
petRepository,
appointPet,
fileStorage,
defaultImageUrl
defaultPetImageUrl
}: AddPet.Dependencies) {
this.guardianRepository = guardianRepository
this.petRepository = petRepository
this.appointPet = appointPet
this.fileStorage = fileStorage
this.defaultImageUrl = defaultImageUrl
this.defaultPetImageUrl = defaultPetImageUrl
}

async add (petData: AddPet.Params): Promise<AddPet.Result> {
Expand Down Expand Up @@ -96,7 +96,7 @@ export class DbAddPet implements AddPet {
size: pet?.size as Size & { id: string },
castrated: pet?.castrated as boolean,
dateOfBirth: pet?.dateOfBirth as Date,
image: imageUrl || this.defaultImageUrl
image: imageUrl || this.defaultPetImageUrl
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/domain/use-cases/add-guardian.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type AddGuardianRepository, type HashGenerator } from '@/data/protocols'
import { type FileStorage, type AddGuardianRepository, type HashGenerator } from '@/data/protocols'
import { type UpdateGuardianImageRepository } from '@/data/protocols/db/guardian/update-guardian-image-repository'

export interface AddGuardian {
add: (guardianData: AddGuardian.Params) => Promise<AddGuardian.Result>
Expand All @@ -12,6 +13,7 @@ export namespace AddGuardian {
phone: string
password: string
verificationToken: string
image: Buffer | null
}

export type Result = {
Expand All @@ -20,10 +22,13 @@ export namespace AddGuardian {
lastName: string
email: string
phone: string
image: string
} | undefined

export type Dependencies = {
guardianRepository: AddGuardianRepository
guardianRepository: AddGuardianRepository & UpdateGuardianImageRepository
hashService: HashGenerator
fileStorage: FileStorage
defaultGuardianImageUrl: string
}
}
2 changes: 1 addition & 1 deletion src/domain/use-cases/pet/add-pet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ export namespace AddPet {
petRepository: AddPetRepository & UpdatePetRepository
appointPet: AppointPet
fileStorage: FileStorage
defaultImageUrl: string
defaultPetImageUrl: string
}
}
19 changes: 18 additions & 1 deletion src/infra/repos/postgresql/guardian-account-repository.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { type UpdateGuardianImageRepository } from '@/data/protocols/db/guardian/update-guardian-image-repository'
import { prisma as db } from './prisma'
import {
type AddGuardianRepository,
Expand All @@ -15,7 +16,8 @@ implements AddGuardianRepository, LoadGuardianByEmailRepository,
UpdateAccessTokenRepository,
UpdateGuardianPasswordRepository,
UpdateVerificationTokenRepository,
UpdateEmailConfirmationRepository {
UpdateEmailConfirmationRepository,
UpdateGuardianImageRepository {
async add (
guardianData: AddGuardianRepository.Params
): Promise<AddGuardianRepository.Result> {
Expand Down Expand Up @@ -136,4 +138,19 @@ implements AddGuardianRepository, LoadGuardianByEmailRepository,

return result.emailConfirmation
}

async updateImage (params: UpdateGuardianImageRepository.Params): Promise<UpdateGuardianImageRepository.Result> {
const { guardianId, image } = params
const result = await db.guardian.update({
where: { id: guardianId },
data: { image },
omit: {
password: true,
verificationToken: true,
verificationTokenCreatedAt: true
}
})

return result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "guardians" ADD COLUMN "image" TEXT NOT NULL DEFAULT '';
1 change: 1 addition & 0 deletions src/infra/repos/postgresql/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ model Guardian {
verificationToken String @map("verification_token")
verificationTokenCreatedAt DateTime @default(now()) @map("verification_token_created_at")
emailConfirmation Boolean @default(false) @map("email_confirmation")
image String @default("")
pets Pet[]
tags Tag[]
scheduler Scheduler[]
Expand Down
3 changes: 2 additions & 1 deletion src/main/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export default {
firebase: {
projectId: process.env.FIREBASE_PROJECT_ID ?? '',
storageBucket: process.env.FIREBASE_STORAGE_BUCKET ?? '',
defaultImageUrl: process.env.FIREBASE_DEFAULT_IMAGE_URL ?? ''
defaultPetImageUrl: process.env.FIREBASE_DEFAULT_PET_IMAGE_URL ?? '',
defaultGuardianImageUrl: process.env.FIREBASE_DEFAULT_GUARDIAN_IMAGE_URL ?? ''
},
mailerooApiKey: process.env.MAILEROO_API_KEY ?? '',
mailerooApiSenderUrl: process.env.MAILEROO_API_URL ?? '',
Expand Down
44 changes: 36 additions & 8 deletions src/main/docs/paths/signup-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,42 @@ import { DocBuilder } from '../utils/doc-builder'
export const signUpPath = DocBuilder.postBuilder()
.addTags(['guardian'])
.addSummary('adds a new guardian')
.addJsonBody('#/schemas/signUpParams', true, {
firstName: 'John',
lastName: 'Doe',
email: 'johndoe@email.com',
password: 'Teste@123',
passwordConfirmation: 'Teste@123',
phone: '11987654321',
isPrivacyPolicyAccepted: true
.addMultipartFormDataBody({
type: 'object',
properties: {
firstName: {
type: 'string',
example: 'John'
},
lastName: {
type: 'string',
example: 'Doe'
},
email: {
type: 'string',
example: 'johndoe@email.com'
},
password: {
type: 'string',
example: 'Teste@123'
},
passwordConfirmation: {
type: 'string',
example: 'Teste@123'
},
phone: {
type: 'string',
example: '11987654321'
},
isPrivacyPolicyAccepted: {
type: 'boolean',
example: true
},
image: {
type: 'string',
format: 'binary'
}
}
})
.addResponse(201, {
description: 'Success',
Expand Down
3 changes: 3 additions & 0 deletions src/main/docs/schemas/guardian-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export const guardianSchema = {
},
phone: {
type: 'string'
},
image: {
type: 'binary'
}
}
}
3 changes: 3 additions & 0 deletions src/main/docs/schemas/signup-params-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export const signUpParamsSchema = {
},
isPrivacyPolicyAccepted: {
type: 'boolean'
},
image: {
type: 'binary'
}
}
}
7 changes: 6 additions & 1 deletion src/main/factories/usecases/db-add-guardian-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import { type AddGuardian } from '@/domain/use-cases'
import { BcryptAdapter } from '@/infra/cryptography'
import { GuardianAccountRepository } from '@/infra/repos/postgresql'
import { DbAddGuardian } from '@/data/use-cases'
import { FirebaseStorageAdapter } from '@/infra/repos/firebase'

export const makeDbAddGuardian = (): AddGuardian => {
const salt = Number(env.salt)
const hashService = new BcryptAdapter(salt)
const guardianRepository = new GuardianAccountRepository()
const fileStorage = new FirebaseStorageAdapter(env.firebase.projectId, env.firebase.storageBucket)
const defaultGuardianImageUrl = env.firebase.defaultGuardianImageUrl
const addGuardian = new DbAddGuardian({
fileStorage,
guardianRepository,
hashService
hashService,
defaultGuardianImageUrl
})
return addGuardian
}
4 changes: 2 additions & 2 deletions src/main/factories/usecases/pet/db-add-pet-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export const makeDbAddPet = (): AddPet => {
const petRepository = new PetRepository()
const appointPet = makeDbAppointPet()
const fileStorage = new FirebaseStorageAdapter(env.firebase.projectId, env.firebase.storageBucket)
const defaultImageUrl = env.firebase.defaultImageUrl
const defaultPetImageUrl = env.firebase.defaultPetImageUrl
const addPet = new DbAddPet({
guardianRepository,
petRepository,
appointPet,
fileStorage,
defaultImageUrl
defaultPetImageUrl
})
return addPet
}
3 changes: 2 additions & 1 deletion src/main/routes/signup-routes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { type Router } from 'express'
import { adaptRoute } from '@/main/adapters'
import { makeSignUpController } from '@/main/factories'
import { upload } from '../middlewares'

export default (router: Router): void => {
router.post('/signup', adaptRoute(makeSignUpController()))
router.post('/signup', upload, adaptRoute(makeSignUpController()))
}
3 changes: 2 additions & 1 deletion tests/helpers/prisma-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export const PrismaHelper = {
password: await bcryptAdapter.encrypt({ value: 'Test@1234' }),
phone: '11987654321',
emailConfirmation: true,
verificationToken: ''
verificationToken: '',
image: ''
}
})
},
Expand Down
3 changes: 2 additions & 1 deletion tests/src/application/controllers/signup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ describe('SignUp Controller', () => {
email: httpRequest.body.email,
password: httpRequest.body.password,
phone: httpRequest.body.phone,
verificationToken: ''
verificationToken: '',
image: httpRequest.file
})
})
})
Expand Down
Loading