feat(api): Implementado novas tabelas ,refatorado a autenticação e aprimorado a documentação Swagger
- Implementado CRUDs para: cursos, empresas, anos_formaturas, tipos_servicos, tipos_eventos - Implementado lógica de precificação de eventos (precos_tipos_eventos) - Refatorado a autenticação: Simplificar o payload de cadastro/login (somente e-mail/senha), função padrão 'profissional' - Corrigido o middleware de autenticação: Resolvido a incompatibilidade de tipo UUID vs String (corrigir erro 500) - Aprimorado o Swagger: Adicionado structs nomeados, validação de duplicatas (409 Conflict) e segurança BearerAuth - Atualizar o esquema do banco de dados: Adicionar tabelas e restrições
This commit is contained in:
parent
f89e1386f7
commit
7f1d4144db
29 changed files with 4416 additions and 152 deletions
|
|
@ -3,11 +3,16 @@ package main
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"photum-backend/internal/anos_formaturas"
|
||||||
"photum-backend/internal/auth"
|
"photum-backend/internal/auth"
|
||||||
"photum-backend/internal/config"
|
"photum-backend/internal/config"
|
||||||
|
"photum-backend/internal/cursos"
|
||||||
"photum-backend/internal/db"
|
"photum-backend/internal/db"
|
||||||
|
"photum-backend/internal/empresas"
|
||||||
"photum-backend/internal/funcoes"
|
"photum-backend/internal/funcoes"
|
||||||
"photum-backend/internal/profissionais"
|
"photum-backend/internal/profissionais"
|
||||||
|
"photum-backend/internal/tipos_eventos"
|
||||||
|
"photum-backend/internal/tipos_servicos"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
|
|
@ -45,11 +50,21 @@ func main() {
|
||||||
profissionaisService := profissionais.NewService(queries)
|
profissionaisService := profissionais.NewService(queries)
|
||||||
authService := auth.NewService(queries, profissionaisService, cfg)
|
authService := auth.NewService(queries, profissionaisService, cfg)
|
||||||
funcoesService := funcoes.NewService(queries)
|
funcoesService := funcoes.NewService(queries)
|
||||||
|
cursosService := cursos.NewService(queries)
|
||||||
|
empresasService := empresas.NewService(queries)
|
||||||
|
anosFormaturasService := anos_formaturas.NewService(queries)
|
||||||
|
tiposServicosService := tipos_servicos.NewService(queries)
|
||||||
|
tiposEventosService := tipos_eventos.NewService(queries)
|
||||||
|
|
||||||
// Initialize handlers
|
// Initialize handlers
|
||||||
authHandler := auth.NewHandler(authService)
|
authHandler := auth.NewHandler(authService)
|
||||||
profissionaisHandler := profissionais.NewHandler(profissionaisService)
|
profissionaisHandler := profissionais.NewHandler(profissionaisService)
|
||||||
funcoesHandler := funcoes.NewHandler(funcoesService)
|
funcoesHandler := funcoes.NewHandler(funcoesService)
|
||||||
|
cursosHandler := cursos.NewHandler(cursosService)
|
||||||
|
empresasHandler := empresas.NewHandler(empresasService)
|
||||||
|
anosFormaturasHandler := anos_formaturas.NewHandler(anosFormaturasService)
|
||||||
|
tiposServicosHandler := tipos_servicos.NewHandler(tiposServicosService)
|
||||||
|
tiposEventosHandler := tipos_eventos.NewHandler(tiposEventosService)
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
|
|
@ -65,8 +80,14 @@ func main() {
|
||||||
authGroup.POST("/logout", authHandler.Logout)
|
authGroup.POST("/logout", authHandler.Logout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API Routes
|
// Public API Routes (Data Lists)
|
||||||
r.GET("/api/funcoes", funcoesHandler.List)
|
r.GET("/api/funcoes", funcoesHandler.List)
|
||||||
|
r.GET("/api/cursos", cursosHandler.List)
|
||||||
|
r.GET("/api/empresas", empresasHandler.List)
|
||||||
|
r.GET("/api/anos-formaturas", anosFormaturasHandler.List)
|
||||||
|
r.GET("/api/tipos-servicos", tiposServicosHandler.List)
|
||||||
|
r.GET("/api/tipos-eventos", tiposEventosHandler.List)
|
||||||
|
r.GET("/api/tipos-eventos/:id/precos", tiposEventosHandler.ListPrices)
|
||||||
|
|
||||||
// Protected Routes
|
// Protected Routes
|
||||||
api := r.Group("/api")
|
api := r.Group("/api")
|
||||||
|
|
@ -94,10 +115,29 @@ func main() {
|
||||||
funcoesGroup := api.Group("/funcoes")
|
funcoesGroup := api.Group("/funcoes")
|
||||||
{
|
{
|
||||||
funcoesGroup.POST("", funcoesHandler.Create)
|
funcoesGroup.POST("", funcoesHandler.Create)
|
||||||
// GET is now public
|
|
||||||
funcoesGroup.PUT("/:id", funcoesHandler.Update)
|
funcoesGroup.PUT("/:id", funcoesHandler.Update)
|
||||||
funcoesGroup.DELETE("/:id", funcoesHandler.Delete)
|
funcoesGroup.DELETE("/:id", funcoesHandler.Delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// protected CRUD (create/update/delete)
|
||||||
|
api.POST("/cursos", cursosHandler.Create)
|
||||||
|
api.PUT("/cursos/:id", cursosHandler.Update)
|
||||||
|
api.DELETE("/cursos/:id", cursosHandler.Delete)
|
||||||
|
|
||||||
|
api.POST("/empresas", empresasHandler.Create)
|
||||||
|
api.PUT("/empresas/:id", empresasHandler.Update)
|
||||||
|
api.DELETE("/empresas/:id", empresasHandler.Delete)
|
||||||
|
|
||||||
|
api.POST("/anos-formaturas", anosFormaturasHandler.Create)
|
||||||
|
api.PUT("/anos-formaturas/:id", anosFormaturasHandler.Update)
|
||||||
|
api.DELETE("/anos-formaturas/:id", anosFormaturasHandler.Delete)
|
||||||
|
|
||||||
|
api.POST("/tipos-servicos", tiposServicosHandler.Create)
|
||||||
|
api.PUT("/tipos-servicos/:id", tiposServicosHandler.Update)
|
||||||
|
api.DELETE("/tipos-servicos/:id", tiposServicosHandler.Delete)
|
||||||
|
|
||||||
|
api.POST("/tipos-eventos", tiposEventosHandler.Create)
|
||||||
|
api.POST("/tipos-eventos/precos", tiposEventosHandler.SetPrice)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Server running on port %s", cfg.AppPort)
|
log.Printf("Server running on port %s", cfg.AppPort)
|
||||||
|
|
|
||||||
1005
backend/docs/docs.go
1005
backend/docs/docs.go
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,26 @@
|
||||||
basePath: /
|
basePath: /
|
||||||
definitions:
|
definitions:
|
||||||
auth.loginRequest:
|
anos_formaturas.AnoFormaturaResponse:
|
||||||
|
properties:
|
||||||
|
ano_semestre:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
anos_formaturas.CreateAnoFormaturaRequest:
|
||||||
|
properties:
|
||||||
|
ano_semestre:
|
||||||
|
example: "2029.1"
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- ano_semestre
|
||||||
|
type: object
|
||||||
|
auth.authRequest:
|
||||||
properties:
|
properties:
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
senha:
|
senha:
|
||||||
|
minLength: 6
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- email
|
- email
|
||||||
|
|
@ -20,25 +36,6 @@ definitions:
|
||||||
user:
|
user:
|
||||||
$ref: '#/definitions/auth.userResponse'
|
$ref: '#/definitions/auth.userResponse'
|
||||||
type: object
|
type: object
|
||||||
auth.registerRequest:
|
|
||||||
properties:
|
|
||||||
email:
|
|
||||||
type: string
|
|
||||||
profissional_data:
|
|
||||||
$ref: '#/definitions/profissionais.CreateProfissionalInput'
|
|
||||||
role:
|
|
||||||
enum:
|
|
||||||
- profissional
|
|
||||||
- empresa
|
|
||||||
type: string
|
|
||||||
senha:
|
|
||||||
minLength: 6
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- email
|
|
||||||
- role
|
|
||||||
- senha
|
|
||||||
type: object
|
|
||||||
auth.userResponse:
|
auth.userResponse:
|
||||||
properties:
|
properties:
|
||||||
email:
|
email:
|
||||||
|
|
@ -48,6 +45,41 @@ definitions:
|
||||||
role:
|
role:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
cursos.CreateCursoRequest:
|
||||||
|
properties:
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- nome
|
||||||
|
type: object
|
||||||
|
cursos.CursoResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
empresas.CreateEmpresaRequest:
|
||||||
|
properties:
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- nome
|
||||||
|
type: object
|
||||||
|
empresas.EmpresaResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
funcoes.CreateFuncaoRequest:
|
||||||
|
properties:
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- nome
|
||||||
|
type: object
|
||||||
funcoes.FuncaoResponse:
|
funcoes.FuncaoResponse:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
|
|
@ -209,6 +241,56 @@ definitions:
|
||||||
whatsapp:
|
whatsapp:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
tipos_eventos.CreateEventoRequest:
|
||||||
|
properties:
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- nome
|
||||||
|
type: object
|
||||||
|
tipos_eventos.EventoResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
tipos_eventos.PrecoResponse:
|
||||||
|
properties:
|
||||||
|
funcao_nome:
|
||||||
|
type: string
|
||||||
|
funcao_profissional_id:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
tipo_evento_id:
|
||||||
|
type: string
|
||||||
|
valor:
|
||||||
|
type: number
|
||||||
|
type: object
|
||||||
|
tipos_eventos.PriceInput:
|
||||||
|
properties:
|
||||||
|
funcao_profissional_id:
|
||||||
|
type: string
|
||||||
|
tipo_evento_id:
|
||||||
|
type: string
|
||||||
|
valor:
|
||||||
|
type: number
|
||||||
|
type: object
|
||||||
|
tipos_servicos.CreateTipoServicoRequest:
|
||||||
|
properties:
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- nome
|
||||||
|
type: object
|
||||||
|
tipos_servicos.TipoServicoResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
nome:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
host: localhost:8080
|
host: localhost:8080
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
|
|
@ -223,6 +305,303 @@ info:
|
||||||
title: Photum Backend API
|
title: Photum Backend API
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
paths:
|
paths:
|
||||||
|
/api/anos-formaturas:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/anos_formaturas.AnoFormaturaResponse'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: List all graduation years
|
||||||
|
tags:
|
||||||
|
- anos_formaturas
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Ano Semestre
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/anos_formaturas.CreateAnoFormaturaRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/anos_formaturas.AnoFormaturaResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Create a new graduation year
|
||||||
|
tags:
|
||||||
|
- anos_formaturas
|
||||||
|
/api/anos-formaturas/{id}:
|
||||||
|
delete:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Delete a graduation year
|
||||||
|
tags:
|
||||||
|
- anos_formaturas
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: Ano Semestre
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/anos_formaturas.CreateAnoFormaturaRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/anos_formaturas.AnoFormaturaResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Update a graduation year
|
||||||
|
tags:
|
||||||
|
- anos_formaturas
|
||||||
|
/api/cursos:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/cursos.CursoResponse'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: List all courses
|
||||||
|
tags:
|
||||||
|
- cursos
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Curso Name
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/cursos.CreateCursoRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/cursos.CursoResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Create a new course
|
||||||
|
tags:
|
||||||
|
- cursos
|
||||||
|
/api/cursos/{id}:
|
||||||
|
delete:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Curso ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Delete a course
|
||||||
|
tags:
|
||||||
|
- cursos
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Curso ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: Curso Name
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/cursos.CreateCursoRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/cursos.CursoResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Update a course
|
||||||
|
tags:
|
||||||
|
- cursos
|
||||||
|
/api/empresas:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/empresas.EmpresaResponse'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: List all companies
|
||||||
|
tags:
|
||||||
|
- empresas
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Empresa Name
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/empresas.CreateEmpresaRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/empresas.EmpresaResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Create a new company
|
||||||
|
tags:
|
||||||
|
- empresas
|
||||||
|
/api/empresas/{id}:
|
||||||
|
delete:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Empresa ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Delete a company
|
||||||
|
tags:
|
||||||
|
- empresas
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Empresa ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: Empresa Name
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/empresas.CreateEmpresaRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/empresas.EmpresaResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Update a company
|
||||||
|
tags:
|
||||||
|
- empresas
|
||||||
/api/funcoes:
|
/api/funcoes:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -243,8 +622,6 @@ paths:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
security:
|
|
||||||
- BearerAuth: []
|
|
||||||
summary: List functions
|
summary: List functions
|
||||||
tags:
|
tags:
|
||||||
- funcoes
|
- funcoes
|
||||||
|
|
@ -258,9 +635,7 @@ paths:
|
||||||
name: request
|
name: request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
additionalProperties:
|
$ref: '#/definitions/funcoes.CreateFuncaoRequest'
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -274,6 +649,12 @@ paths:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
"500":
|
"500":
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -337,9 +718,7 @@ paths:
|
||||||
name: request
|
name: request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
additionalProperties:
|
$ref: '#/definitions/funcoes.CreateFuncaoRequest'
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -353,6 +732,12 @@ paths:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
"500":
|
"500":
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -541,6 +926,194 @@ paths:
|
||||||
summary: Update profissional
|
summary: Update profissional
|
||||||
tags:
|
tags:
|
||||||
- profissionais
|
- profissionais
|
||||||
|
/api/tipos-eventos:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/tipos_eventos.EventoResponse'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: List all event types
|
||||||
|
tags:
|
||||||
|
- tipos_eventos
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Nome
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_eventos.CreateEventoRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_eventos.EventoResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Create a new event type
|
||||||
|
tags:
|
||||||
|
- tipos_eventos
|
||||||
|
/api/tipos-eventos/{id}/precos:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Event ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/tipos_eventos.PrecoResponse'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: List prices for an event
|
||||||
|
tags:
|
||||||
|
- tipos_eventos
|
||||||
|
/api/tipos-eventos/precos:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Price Input
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_eventos.PriceInput'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Set price for an event function
|
||||||
|
tags:
|
||||||
|
- tipos_eventos
|
||||||
|
/api/tipos-servicos:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/tipos_servicos.TipoServicoResponse'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: List all service types
|
||||||
|
tags:
|
||||||
|
- tipos_servicos
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Nome
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_servicos.CreateTipoServicoRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_servicos.TipoServicoResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"409":
|
||||||
|
description: Conflict
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Create a new service type
|
||||||
|
tags:
|
||||||
|
- tipos_servicos
|
||||||
|
/api/tipos-servicos/{id}:
|
||||||
|
delete:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Delete a service type
|
||||||
|
tags:
|
||||||
|
- tipos_servicos
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: Nome
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_servicos.CreateTipoServicoRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/tipos_servicos.TipoServicoResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: Update a service type
|
||||||
|
tags:
|
||||||
|
- tipos_servicos
|
||||||
/auth/login:
|
/auth/login:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -552,7 +1125,7 @@ paths:
|
||||||
name: request
|
name: request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/auth.loginRequest'
|
$ref: '#/definitions/auth.authRequest'
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -630,14 +1203,15 @@ paths:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: Register a new user with optional professional profile
|
description: Register a new user (defaults to 'profissional' role) with email
|
||||||
|
and password
|
||||||
parameters:
|
parameters:
|
||||||
- description: Register Request
|
- description: Register Request
|
||||||
in: body
|
in: body
|
||||||
name: request
|
name: request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/auth.registerRequest'
|
$ref: '#/definitions/auth.authRequest'
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
|
||||||
137
backend/internal/anos_formaturas/handler.go
Normal file
137
backend/internal/anos_formaturas/handler.go
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
package anos_formaturas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
service *Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(service *Service) *Handler {
|
||||||
|
return &Handler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnoFormaturaResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
AnoSemestre string `json:"ano_semestre"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateAnoFormaturaRequest struct {
|
||||||
|
AnoSemestre string `json:"ano_semestre" binding:"required" example:"2029.1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toResponse(a generated.AnosFormatura) AnoFormaturaResponse {
|
||||||
|
return AnoFormaturaResponse{
|
||||||
|
ID: uuid.UUID(a.ID.Bytes).String(),
|
||||||
|
AnoSemestre: a.AnoSemestre,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create godoc
|
||||||
|
// @Summary Create a new graduation year
|
||||||
|
// @Tags anos_formaturas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param request body CreateAnoFormaturaRequest true "Ano Semestre"
|
||||||
|
// @Success 201 {object} AnoFormaturaResponse
|
||||||
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
|
// @Router /api/anos-formaturas [post]
|
||||||
|
func (h *Handler) Create(c *gin.Context) {
|
||||||
|
var req CreateAnoFormaturaRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ano, err := h.service.Create(c.Request.Context(), req.AnoSemestre)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key value") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "Ano/Semestre already exists"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.Contains(err.Error(), "invalid format") {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusCreated, toResponse(*ano))
|
||||||
|
}
|
||||||
|
|
||||||
|
// List godoc
|
||||||
|
// @Summary List all graduation years
|
||||||
|
// @Tags anos_formaturas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Success 200 {array} AnoFormaturaResponse
|
||||||
|
// @Router /api/anos-formaturas [get]
|
||||||
|
func (h *Handler) List(c *gin.Context) {
|
||||||
|
anos, err := h.service.List(c.Request.Context())
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []AnoFormaturaResponse
|
||||||
|
for _, ano := range anos {
|
||||||
|
response = append(response, toResponse(ano))
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update godoc
|
||||||
|
// @Summary Update a graduation year
|
||||||
|
// @Tags anos_formaturas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "ID"
|
||||||
|
// @Param request body CreateAnoFormaturaRequest true "Ano Semestre"
|
||||||
|
// @Success 200 {object} AnoFormaturaResponse
|
||||||
|
// @Router /api/anos-formaturas/{id} [put]
|
||||||
|
func (h *Handler) Update(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var req CreateAnoFormaturaRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ano, err := h.service.Update(c.Request.Context(), id, req.AnoSemestre)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, toResponse(*ano))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete godoc
|
||||||
|
// @Summary Delete a graduation year
|
||||||
|
// @Tags anos_formaturas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "ID"
|
||||||
|
// @Success 204 {object} nil
|
||||||
|
// @Router /api/anos-formaturas/{id} [delete]
|
||||||
|
func (h *Handler) Delete(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
if err := h.service.Delete(c.Request.Context(), id); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
80
backend/internal/anos_formaturas/service.go
Normal file
80
backend/internal/anos_formaturas/service.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package anos_formaturas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
queries *generated.Queries
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(queries *generated.Queries) *Service {
|
||||||
|
return &Service{queries: queries}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Create(ctx context.Context, anoSemestre string) (*generated.AnosFormatura, error) {
|
||||||
|
// Validate format YYYY.S
|
||||||
|
matched, _ := regexp.MatchString(`^\d{4}\.[1-2]$`, anoSemestre)
|
||||||
|
if !matched {
|
||||||
|
return nil, errors.New("invalid format. Expected YYYY.1 or YYYY.2")
|
||||||
|
}
|
||||||
|
|
||||||
|
ano, err := s.queries.CreateAnoFormatura(ctx, anoSemestre)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ano, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) List(ctx context.Context) ([]generated.AnosFormatura, error) {
|
||||||
|
return s.queries.ListAnosFormaturas(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetByID(ctx context.Context, id string) (*generated.AnosFormatura, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
ano, err := s.queries.GetAnoFormaturaByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ano, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Update(ctx context.Context, id, anoSemestre string) (*generated.AnosFormatura, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate format YYYY.S
|
||||||
|
matched, _ := regexp.MatchString(`^\d{4}\.[1-2]$`, anoSemestre)
|
||||||
|
if !matched {
|
||||||
|
return nil, errors.New("invalid format. Expected YYYY.1 or YYYY.2")
|
||||||
|
}
|
||||||
|
|
||||||
|
ano, err := s.queries.UpdateAnoFormatura(ctx, generated.UpdateAnoFormaturaParams{
|
||||||
|
ID: pgtype.UUID{Bytes: uuidVal, Valid: true},
|
||||||
|
AnoSemestre: anoSemestre,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ano, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Delete(ctx context.Context, id string) error {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid id")
|
||||||
|
}
|
||||||
|
return s.queries.DeleteAnoFormatura(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"photum-backend/internal/profissionais"
|
"photum-backend/internal/profissionais"
|
||||||
|
|
||||||
|
|
@ -17,38 +18,39 @@ func NewHandler(service *Service) *Handler {
|
||||||
return &Handler{service: service}
|
return &Handler{service: service}
|
||||||
}
|
}
|
||||||
|
|
||||||
type registerRequest struct {
|
type authRequest struct {
|
||||||
Email string `json:"email" binding:"required,email"`
|
Email string `json:"email" binding:"required,email"`
|
||||||
Senha string `json:"senha" binding:"required,min=6"`
|
Senha string `json:"senha" binding:"required,min=6"`
|
||||||
Role string `json:"role" binding:"required,oneof=profissional empresa"`
|
|
||||||
ProfissionalData *profissionais.CreateProfissionalInput `json:"profissional_data"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register godoc
|
// Register godoc
|
||||||
// @Summary Register a new user
|
// @Summary Register a new user
|
||||||
// @Description Register a new user with optional professional profile
|
// @Description Register a new user (defaults to 'profissional' role) with email and password
|
||||||
// @Tags auth
|
// @Tags auth
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param request body registerRequest true "Register Request"
|
// @Param request body authRequest true "Register Request"
|
||||||
// @Success 201 {object} map[string]string
|
// @Success 201 {object} map[string]string
|
||||||
// @Failure 400 {object} map[string]string
|
// @Failure 400 {object} map[string]string
|
||||||
// @Failure 500 {object} map[string]string
|
// @Failure 500 {object} map[string]string
|
||||||
// @Router /auth/register [post]
|
// @Router /auth/register [post]
|
||||||
func (h *Handler) Register(c *gin.Context) {
|
func (h *Handler) Register(c *gin.Context) {
|
||||||
var req registerRequest
|
var req authRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Role == "profissional" && req.ProfissionalData == nil {
|
// Default simplified registration: Role="profissional", No professional data yet
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "profissional_data is required for role 'profissional'"})
|
role := "profissional"
|
||||||
return
|
var profData *profissionais.CreateProfissionalInput = nil
|
||||||
}
|
|
||||||
|
|
||||||
_, err := h.service.Register(c.Request.Context(), req.Email, req.Senha, req.Role, req.ProfissionalData)
|
_, err := h.service.Register(c.Request.Context(), req.Email, req.Senha, role, profData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "email already registered"})
|
||||||
|
return
|
||||||
|
}
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -56,11 +58,6 @@ func (h *Handler) Register(c *gin.Context) {
|
||||||
c.JSON(http.StatusCreated, gin.H{"message": "user created"})
|
c.JSON(http.StatusCreated, gin.H{"message": "user created"})
|
||||||
}
|
}
|
||||||
|
|
||||||
type loginRequest struct {
|
|
||||||
Email string `json:"email" binding:"required,email"`
|
|
||||||
Senha string `json:"senha" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type loginResponse struct {
|
type loginResponse struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
ExpiresAt string `json:"expires_at"`
|
ExpiresAt string `json:"expires_at"`
|
||||||
|
|
@ -80,13 +77,13 @@ type userResponse struct {
|
||||||
// @Tags auth
|
// @Tags auth
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param request body loginRequest true "Login Request"
|
// @Param request body authRequest true "Login Request"
|
||||||
// @Success 200 {object} loginResponse
|
// @Success 200 {object} loginResponse
|
||||||
// @Failure 401 {object} map[string]string
|
// @Failure 401 {object} map[string]string
|
||||||
// @Failure 500 {object} map[string]string
|
// @Failure 500 {object} map[string]string
|
||||||
// @Router /auth/login [post]
|
// @Router /auth/login [post]
|
||||||
func (h *Handler) Login(c *gin.Context) {
|
func (h *Handler) Login(c *gin.Context) {
|
||||||
var req loginRequest
|
var req authRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
|
|
@ -94,7 +91,7 @@ func (h *Handler) Login(c *gin.Context) {
|
||||||
|
|
||||||
tokenPair, user, profData, err := h.service.Login(c.Request.Context(), req.Email, req.Senha)
|
tokenPair, user, profData, err := h.service.Login(c.Request.Context(), req.Email, req.Senha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,7 +107,7 @@ func (h *Handler) Login(c *gin.Context) {
|
||||||
|
|
||||||
resp := loginResponse{
|
resp := loginResponse{
|
||||||
AccessToken: tokenPair.AccessToken,
|
AccessToken: tokenPair.AccessToken,
|
||||||
ExpiresAt: "2025-...",
|
ExpiresAt: "2025-...", // logic to calculate if needed, or remove field
|
||||||
User: userResponse{
|
User: userResponse{
|
||||||
ID: uuid.UUID(user.ID.Bytes).String(),
|
ID: uuid.UUID(user.ID.Bytes).String(),
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
|
|
@ -131,11 +128,6 @@ func (h *Handler) Login(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, resp)
|
c.JSON(http.StatusOK, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh and Logout handlers should be kept or restored if they were lost.
|
|
||||||
// I will assume they are needed and add them back in a subsequent edit if missing,
|
|
||||||
// or include them here if I can fit them.
|
|
||||||
// The previous content had them. I'll add them to be safe.
|
|
||||||
|
|
||||||
// Refresh godoc
|
// Refresh godoc
|
||||||
// @Summary Refresh access token
|
// @Summary Refresh access token
|
||||||
// @Description Get a new access token using a valid refresh token
|
// @Description Get a new access token using a valid refresh token
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func AuthMiddleware(cfg *config.Config) gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Set("userID", claims.UserID)
|
c.Set("userID", claims.UserID.String())
|
||||||
c.Set("role", claims.Role)
|
c.Set("role", claims.Role)
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
133
backend/internal/cursos/handler.go
Normal file
133
backend/internal/cursos/handler.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
package cursos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
service *Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(service *Service) *Handler {
|
||||||
|
return &Handler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CursoResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateCursoRequest struct {
|
||||||
|
Nome string `json:"nome" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toResponse(c generated.Curso) CursoResponse {
|
||||||
|
return CursoResponse{
|
||||||
|
ID: uuid.UUID(c.ID.Bytes).String(),
|
||||||
|
Nome: c.Nome,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create godoc
|
||||||
|
// @Summary Create a new course
|
||||||
|
// @Tags cursos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param request body CreateCursoRequest true "Curso Name"
|
||||||
|
// @Success 201 {object} CursoResponse
|
||||||
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
|
// @Router /api/cursos [post]
|
||||||
|
func (h *Handler) Create(c *gin.Context) {
|
||||||
|
var req CreateCursoRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
curso, err := h.service.Create(c.Request.Context(), req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key value") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "Curso already exists"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusCreated, toResponse(*curso))
|
||||||
|
}
|
||||||
|
|
||||||
|
// List godoc
|
||||||
|
// @Summary List all courses
|
||||||
|
// @Tags cursos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Success 200 {array} CursoResponse
|
||||||
|
// @Router /api/cursos [get]
|
||||||
|
func (h *Handler) List(c *gin.Context) {
|
||||||
|
cursos, err := h.service.List(c.Request.Context())
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []CursoResponse
|
||||||
|
for _, curso := range cursos {
|
||||||
|
response = append(response, toResponse(curso))
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update godoc
|
||||||
|
// @Summary Update a course
|
||||||
|
// @Tags cursos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "Curso ID"
|
||||||
|
// @Param request body CreateCursoRequest true "Curso Name"
|
||||||
|
// @Success 200 {object} CursoResponse
|
||||||
|
// @Router /api/cursos/{id} [put]
|
||||||
|
func (h *Handler) Update(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var req CreateCursoRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
curso, err := h.service.Update(c.Request.Context(), id, req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, toResponse(*curso))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete godoc
|
||||||
|
// @Summary Delete a course
|
||||||
|
// @Tags cursos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "Curso ID"
|
||||||
|
// @Success 204 {object} nil
|
||||||
|
// @Router /api/cursos/{id} [delete]
|
||||||
|
func (h *Handler) Delete(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
if err := h.service.Delete(c.Request.Context(), id); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
67
backend/internal/cursos/service.go
Normal file
67
backend/internal/cursos/service.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package cursos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
queries *generated.Queries
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(queries *generated.Queries) *Service {
|
||||||
|
return &Service{queries: queries}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Create(ctx context.Context, nome string) (*generated.Curso, error) {
|
||||||
|
curso, err := s.queries.CreateCurso(ctx, nome)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &curso, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) List(ctx context.Context) ([]generated.Curso, error) {
|
||||||
|
return s.queries.ListCursos(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetByID(ctx context.Context, id string) (*generated.Curso, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
curso, err := s.queries.GetCursoByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &curso, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Update(ctx context.Context, id, nome string) (*generated.Curso, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
|
curso, err := s.queries.UpdateCurso(ctx, generated.UpdateCursoParams{
|
||||||
|
ID: pgtype.UUID{Bytes: uuidVal, Valid: true},
|
||||||
|
Nome: nome,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &curso, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Delete(ctx context.Context, id string) error {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid id")
|
||||||
|
}
|
||||||
|
return s.queries.DeleteCurso(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
}
|
||||||
83
backend/internal/db/generated/anos_formaturas.sql.go
Normal file
83
backend/internal/db/generated/anos_formaturas.sql.go
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: anos_formaturas.sql
|
||||||
|
|
||||||
|
package generated
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createAnoFormatura = `-- name: CreateAnoFormatura :one
|
||||||
|
INSERT INTO anos_formaturas (ano_semestre) VALUES ($1) RETURNING id, ano_semestre, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CreateAnoFormatura(ctx context.Context, anoSemestre string) (AnosFormatura, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createAnoFormatura, anoSemestre)
|
||||||
|
var i AnosFormatura
|
||||||
|
err := row.Scan(&i.ID, &i.AnoSemestre, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAnoFormatura = `-- name: DeleteAnoFormatura :exec
|
||||||
|
DELETE FROM anos_formaturas WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAnoFormatura(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteAnoFormatura, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAnoFormaturaByID = `-- name: GetAnoFormaturaByID :one
|
||||||
|
SELECT id, ano_semestre, criado_em FROM anos_formaturas WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAnoFormaturaByID(ctx context.Context, id pgtype.UUID) (AnosFormatura, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getAnoFormaturaByID, id)
|
||||||
|
var i AnosFormatura
|
||||||
|
err := row.Scan(&i.ID, &i.AnoSemestre, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listAnosFormaturas = `-- name: ListAnosFormaturas :many
|
||||||
|
SELECT id, ano_semestre, criado_em FROM anos_formaturas ORDER BY ano_semestre
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListAnosFormaturas(ctx context.Context) ([]AnosFormatura, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listAnosFormaturas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []AnosFormatura
|
||||||
|
for rows.Next() {
|
||||||
|
var i AnosFormatura
|
||||||
|
if err := rows.Scan(&i.ID, &i.AnoSemestre, &i.CriadoEm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateAnoFormatura = `-- name: UpdateAnoFormatura :one
|
||||||
|
UPDATE anos_formaturas SET ano_semestre = $2 WHERE id = $1 RETURNING id, ano_semestre, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateAnoFormaturaParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
AnoSemestre string `json:"ano_semestre"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateAnoFormatura(ctx context.Context, arg UpdateAnoFormaturaParams) (AnosFormatura, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateAnoFormatura, arg.ID, arg.AnoSemestre)
|
||||||
|
var i AnosFormatura
|
||||||
|
err := row.Scan(&i.ID, &i.AnoSemestre, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
83
backend/internal/db/generated/cursos.sql.go
Normal file
83
backend/internal/db/generated/cursos.sql.go
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: cursos.sql
|
||||||
|
|
||||||
|
package generated
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createCurso = `-- name: CreateCurso :one
|
||||||
|
INSERT INTO cursos (nome) VALUES ($1) RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CreateCurso(ctx context.Context, nome string) (Curso, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createCurso, nome)
|
||||||
|
var i Curso
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteCurso = `-- name: DeleteCurso :exec
|
||||||
|
DELETE FROM cursos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteCurso(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteCurso, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCursoByID = `-- name: GetCursoByID :one
|
||||||
|
SELECT id, nome, criado_em FROM cursos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetCursoByID(ctx context.Context, id pgtype.UUID) (Curso, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getCursoByID, id)
|
||||||
|
var i Curso
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listCursos = `-- name: ListCursos :many
|
||||||
|
SELECT id, nome, criado_em FROM cursos ORDER BY nome
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListCursos(ctx context.Context) ([]Curso, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listCursos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Curso
|
||||||
|
for rows.Next() {
|
||||||
|
var i Curso
|
||||||
|
if err := rows.Scan(&i.ID, &i.Nome, &i.CriadoEm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateCurso = `-- name: UpdateCurso :one
|
||||||
|
UPDATE cursos SET nome = $2 WHERE id = $1 RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateCursoParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateCurso(ctx context.Context, arg UpdateCursoParams) (Curso, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateCurso, arg.ID, arg.Nome)
|
||||||
|
var i Curso
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
83
backend/internal/db/generated/empresas.sql.go
Normal file
83
backend/internal/db/generated/empresas.sql.go
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: empresas.sql
|
||||||
|
|
||||||
|
package generated
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createEmpresa = `-- name: CreateEmpresa :one
|
||||||
|
INSERT INTO empresas (nome) VALUES ($1) RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CreateEmpresa(ctx context.Context, nome string) (Empresa, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createEmpresa, nome)
|
||||||
|
var i Empresa
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteEmpresa = `-- name: DeleteEmpresa :exec
|
||||||
|
DELETE FROM empresas WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteEmpresa(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteEmpresa, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEmpresaByID = `-- name: GetEmpresaByID :one
|
||||||
|
SELECT id, nome, criado_em FROM empresas WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetEmpresaByID(ctx context.Context, id pgtype.UUID) (Empresa, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getEmpresaByID, id)
|
||||||
|
var i Empresa
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listEmpresas = `-- name: ListEmpresas :many
|
||||||
|
SELECT id, nome, criado_em FROM empresas ORDER BY nome
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListEmpresas(ctx context.Context) ([]Empresa, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listEmpresas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Empresa
|
||||||
|
for rows.Next() {
|
||||||
|
var i Empresa
|
||||||
|
if err := rows.Scan(&i.ID, &i.Nome, &i.CriadoEm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateEmpresa = `-- name: UpdateEmpresa :one
|
||||||
|
UPDATE empresas SET nome = $2 WHERE id = $1 RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateEmpresaParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateEmpresa(ctx context.Context, arg UpdateEmpresaParams) (Empresa, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateEmpresa, arg.ID, arg.Nome)
|
||||||
|
var i Empresa
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,12 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AnosFormatura struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
AnoSemestre string `json:"ano_semestre"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
}
|
||||||
|
|
||||||
type CadastroProfissionai struct {
|
type CadastroProfissionai struct {
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
UsuarioID pgtype.UUID `json:"usuario_id"`
|
UsuarioID pgtype.UUID `json:"usuario_id"`
|
||||||
|
|
@ -38,6 +44,18 @@ type CadastroProfissionai struct {
|
||||||
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
|
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Curso struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Empresa struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
}
|
||||||
|
|
||||||
type FuncoesProfissionai struct {
|
type FuncoesProfissionai struct {
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
Nome string `json:"nome"`
|
Nome string `json:"nome"`
|
||||||
|
|
@ -45,6 +63,14 @@ type FuncoesProfissionai struct {
|
||||||
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
|
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PrecosTiposEvento struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
TipoEventoID pgtype.UUID `json:"tipo_evento_id"`
|
||||||
|
FuncaoProfissionalID pgtype.UUID `json:"funcao_profissional_id"`
|
||||||
|
Valor pgtype.Numeric `json:"valor"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
}
|
||||||
|
|
||||||
type RefreshToken struct {
|
type RefreshToken struct {
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
UsuarioID pgtype.UUID `json:"usuario_id"`
|
UsuarioID pgtype.UUID `json:"usuario_id"`
|
||||||
|
|
@ -56,6 +82,18 @@ type RefreshToken struct {
|
||||||
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TiposEvento struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TiposServico struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
}
|
||||||
|
|
||||||
type Usuario struct {
|
type Usuario struct {
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
|
|
||||||
184
backend/internal/db/generated/tipos_eventos.sql.go
Normal file
184
backend/internal/db/generated/tipos_eventos.sql.go
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: tipos_eventos.sql
|
||||||
|
|
||||||
|
package generated
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createPrecoEvento = `-- name: CreatePrecoEvento :one
|
||||||
|
INSERT INTO precos_tipos_eventos (tipo_evento_id, funcao_profissional_id, valor)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
ON CONFLICT (tipo_evento_id, funcao_profissional_id) DO UPDATE
|
||||||
|
SET valor = $3
|
||||||
|
RETURNING id, tipo_evento_id, funcao_profissional_id, valor, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreatePrecoEventoParams struct {
|
||||||
|
TipoEventoID pgtype.UUID `json:"tipo_evento_id"`
|
||||||
|
FuncaoProfissionalID pgtype.UUID `json:"funcao_profissional_id"`
|
||||||
|
Valor pgtype.Numeric `json:"valor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreatePrecoEvento(ctx context.Context, arg CreatePrecoEventoParams) (PrecosTiposEvento, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createPrecoEvento, arg.TipoEventoID, arg.FuncaoProfissionalID, arg.Valor)
|
||||||
|
var i PrecosTiposEvento
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.TipoEventoID,
|
||||||
|
&i.FuncaoProfissionalID,
|
||||||
|
&i.Valor,
|
||||||
|
&i.CriadoEm,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const createTipoEvento = `-- name: CreateTipoEvento :one
|
||||||
|
INSERT INTO tipos_eventos (nome) VALUES ($1) RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CreateTipoEvento(ctx context.Context, nome string) (TiposEvento, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createTipoEvento, nome)
|
||||||
|
var i TiposEvento
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletePreco = `-- name: DeletePreco :exec
|
||||||
|
DELETE FROM precos_tipos_eventos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeletePreco(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deletePreco, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteTipoEvento = `-- name: DeleteTipoEvento :exec
|
||||||
|
DELETE FROM tipos_eventos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteTipoEvento(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteTipoEvento, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPreco = `-- name: GetPreco :one
|
||||||
|
SELECT id, tipo_evento_id, funcao_profissional_id, valor, criado_em FROM precos_tipos_eventos WHERE tipo_evento_id = $1 AND funcao_profissional_id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetPrecoParams struct {
|
||||||
|
TipoEventoID pgtype.UUID `json:"tipo_evento_id"`
|
||||||
|
FuncaoProfissionalID pgtype.UUID `json:"funcao_profissional_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetPreco(ctx context.Context, arg GetPrecoParams) (PrecosTiposEvento, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getPreco, arg.TipoEventoID, arg.FuncaoProfissionalID)
|
||||||
|
var i PrecosTiposEvento
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.TipoEventoID,
|
||||||
|
&i.FuncaoProfissionalID,
|
||||||
|
&i.Valor,
|
||||||
|
&i.CriadoEm,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTipoEventoByID = `-- name: GetTipoEventoByID :one
|
||||||
|
SELECT id, nome, criado_em FROM tipos_eventos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTipoEventoByID(ctx context.Context, id pgtype.UUID) (TiposEvento, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getTipoEventoByID, id)
|
||||||
|
var i TiposEvento
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listPrecosByEventoID = `-- name: ListPrecosByEventoID :many
|
||||||
|
SELECT p.id, p.tipo_evento_id, p.funcao_profissional_id, p.valor, p.criado_em, f.nome as funcao_nome
|
||||||
|
FROM precos_tipos_eventos p
|
||||||
|
JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
|
||||||
|
WHERE p.tipo_evento_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListPrecosByEventoIDRow struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
TipoEventoID pgtype.UUID `json:"tipo_evento_id"`
|
||||||
|
FuncaoProfissionalID pgtype.UUID `json:"funcao_profissional_id"`
|
||||||
|
Valor pgtype.Numeric `json:"valor"`
|
||||||
|
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||||
|
FuncaoNome string `json:"funcao_nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListPrecosByEventoID(ctx context.Context, tipoEventoID pgtype.UUID) ([]ListPrecosByEventoIDRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listPrecosByEventoID, tipoEventoID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ListPrecosByEventoIDRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i ListPrecosByEventoIDRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.TipoEventoID,
|
||||||
|
&i.FuncaoProfissionalID,
|
||||||
|
&i.Valor,
|
||||||
|
&i.CriadoEm,
|
||||||
|
&i.FuncaoNome,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const listTiposEventos = `-- name: ListTiposEventos :many
|
||||||
|
SELECT id, nome, criado_em FROM tipos_eventos ORDER BY nome
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListTiposEventos(ctx context.Context) ([]TiposEvento, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listTiposEventos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []TiposEvento
|
||||||
|
for rows.Next() {
|
||||||
|
var i TiposEvento
|
||||||
|
if err := rows.Scan(&i.ID, &i.Nome, &i.CriadoEm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateTipoEvento = `-- name: UpdateTipoEvento :one
|
||||||
|
UPDATE tipos_eventos SET nome = $2 WHERE id = $1 RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateTipoEventoParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateTipoEvento(ctx context.Context, arg UpdateTipoEventoParams) (TiposEvento, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateTipoEvento, arg.ID, arg.Nome)
|
||||||
|
var i TiposEvento
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
83
backend/internal/db/generated/tipos_servicos.sql.go
Normal file
83
backend/internal/db/generated/tipos_servicos.sql.go
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: tipos_servicos.sql
|
||||||
|
|
||||||
|
package generated
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createTipoServico = `-- name: CreateTipoServico :one
|
||||||
|
INSERT INTO tipos_servicos (nome) VALUES ($1) RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CreateTipoServico(ctx context.Context, nome string) (TiposServico, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createTipoServico, nome)
|
||||||
|
var i TiposServico
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteTipoServico = `-- name: DeleteTipoServico :exec
|
||||||
|
DELETE FROM tipos_servicos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteTipoServico(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteTipoServico, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTipoServicoByID = `-- name: GetTipoServicoByID :one
|
||||||
|
SELECT id, nome, criado_em FROM tipos_servicos WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTipoServicoByID(ctx context.Context, id pgtype.UUID) (TiposServico, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getTipoServicoByID, id)
|
||||||
|
var i TiposServico
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const listTiposServicos = `-- name: ListTiposServicos :many
|
||||||
|
SELECT id, nome, criado_em FROM tipos_servicos ORDER BY nome
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListTiposServicos(ctx context.Context) ([]TiposServico, error) {
|
||||||
|
rows, err := q.db.Query(ctx, listTiposServicos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []TiposServico
|
||||||
|
for rows.Next() {
|
||||||
|
var i TiposServico
|
||||||
|
if err := rows.Scan(&i.ID, &i.Nome, &i.CriadoEm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateTipoServico = `-- name: UpdateTipoServico :one
|
||||||
|
UPDATE tipos_servicos SET nome = $2 WHERE id = $1 RETURNING id, nome, criado_em
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateTipoServicoParams struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateTipoServico(ctx context.Context, arg UpdateTipoServicoParams) (TiposServico, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateTipoServico, arg.ID, arg.Nome)
|
||||||
|
var i TiposServico
|
||||||
|
err := row.Scan(&i.ID, &i.Nome, &i.CriadoEm)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
14
backend/internal/db/queries/anos_formaturas.sql
Normal file
14
backend/internal/db/queries/anos_formaturas.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
-- name: CreateAnoFormatura :one
|
||||||
|
INSERT INTO anos_formaturas (ano_semestre) VALUES ($1) RETURNING *;
|
||||||
|
|
||||||
|
-- name: ListAnosFormaturas :many
|
||||||
|
SELECT * FROM anos_formaturas ORDER BY ano_semestre;
|
||||||
|
|
||||||
|
-- name: GetAnoFormaturaByID :one
|
||||||
|
SELECT * FROM anos_formaturas WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateAnoFormatura :one
|
||||||
|
UPDATE anos_formaturas SET ano_semestre = $2 WHERE id = $1 RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteAnoFormatura :exec
|
||||||
|
DELETE FROM anos_formaturas WHERE id = $1;
|
||||||
14
backend/internal/db/queries/cursos.sql
Normal file
14
backend/internal/db/queries/cursos.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
-- name: CreateCurso :one
|
||||||
|
INSERT INTO cursos (nome) VALUES ($1) RETURNING *;
|
||||||
|
|
||||||
|
-- name: ListCursos :many
|
||||||
|
SELECT * FROM cursos ORDER BY nome;
|
||||||
|
|
||||||
|
-- name: GetCursoByID :one
|
||||||
|
SELECT * FROM cursos WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateCurso :one
|
||||||
|
UPDATE cursos SET nome = $2 WHERE id = $1 RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteCurso :exec
|
||||||
|
DELETE FROM cursos WHERE id = $1;
|
||||||
14
backend/internal/db/queries/empresas.sql
Normal file
14
backend/internal/db/queries/empresas.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
-- name: CreateEmpresa :one
|
||||||
|
INSERT INTO empresas (nome) VALUES ($1) RETURNING *;
|
||||||
|
|
||||||
|
-- name: ListEmpresas :many
|
||||||
|
SELECT * FROM empresas ORDER BY nome;
|
||||||
|
|
||||||
|
-- name: GetEmpresaByID :one
|
||||||
|
SELECT * FROM empresas WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateEmpresa :one
|
||||||
|
UPDATE empresas SET nome = $2 WHERE id = $1 RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteEmpresa :exec
|
||||||
|
DELETE FROM empresas WHERE id = $1;
|
||||||
33
backend/internal/db/queries/tipos_eventos.sql
Normal file
33
backend/internal/db/queries/tipos_eventos.sql
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
-- name: CreateTipoEvento :one
|
||||||
|
INSERT INTO tipos_eventos (nome) VALUES ($1) RETURNING *;
|
||||||
|
|
||||||
|
-- name: ListTiposEventos :many
|
||||||
|
SELECT * FROM tipos_eventos ORDER BY nome;
|
||||||
|
|
||||||
|
-- name: GetTipoEventoByID :one
|
||||||
|
SELECT * FROM tipos_eventos WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateTipoEvento :one
|
||||||
|
UPDATE tipos_eventos SET nome = $2 WHERE id = $1 RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteTipoEvento :exec
|
||||||
|
DELETE FROM tipos_eventos WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: CreatePrecoEvento :one
|
||||||
|
INSERT INTO precos_tipos_eventos (tipo_evento_id, funcao_profissional_id, valor)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
ON CONFLICT (tipo_evento_id, funcao_profissional_id) DO UPDATE
|
||||||
|
SET valor = $3
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: ListPrecosByEventoID :many
|
||||||
|
SELECT p.*, f.nome as funcao_nome
|
||||||
|
FROM precos_tipos_eventos p
|
||||||
|
JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
|
||||||
|
WHERE p.tipo_evento_id = $1;
|
||||||
|
|
||||||
|
-- name: GetPreco :one
|
||||||
|
SELECT * FROM precos_tipos_eventos WHERE tipo_evento_id = $1 AND funcao_profissional_id = $2;
|
||||||
|
|
||||||
|
-- name: DeletePreco :exec
|
||||||
|
DELETE FROM precos_tipos_eventos WHERE id = $1;
|
||||||
14
backend/internal/db/queries/tipos_servicos.sql
Normal file
14
backend/internal/db/queries/tipos_servicos.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
-- name: CreateTipoServico :one
|
||||||
|
INSERT INTO tipos_servicos (nome) VALUES ($1) RETURNING *;
|
||||||
|
|
||||||
|
-- name: ListTiposServicos :many
|
||||||
|
SELECT * FROM tipos_servicos ORDER BY nome;
|
||||||
|
|
||||||
|
-- name: GetTipoServicoByID :one
|
||||||
|
SELECT * FROM tipos_servicos WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateTipoServico :one
|
||||||
|
UPDATE tipos_servicos SET nome = $2 WHERE id = $1 RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteTipoServico :exec
|
||||||
|
DELETE FROM tipos_servicos WHERE id = $1;
|
||||||
|
|
@ -64,3 +64,83 @@ CREATE TABLE refresh_tokens (
|
||||||
revogado BOOLEAN NOT NULL DEFAULT FALSE,
|
revogado BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Cursos Table
|
||||||
|
CREATE TABLE cursos (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
nome VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO cursos (nome) VALUES
|
||||||
|
('Administração Empresas'), ('Agronomia'), ('Arquitetura / Urbanismo'), ('Biomedicina'), ('Comunicação'), ('Contábeis'),
|
||||||
|
('Direito'), ('Economia'), ('Educação Física'), ('EFI I/EFI II'), ('EI/EFI'), ('EF II/EM'), ('EFI(5º ano)'), ('EFII'),
|
||||||
|
('EI'), ('EM'), ('EM / TEC'), ('Enfermagem'), ('Eng. Ambiental'), ('Eng. Elétrica'), ('Engenharia'), ('Estética'),
|
||||||
|
('Farmácia'), ('Fisioterapia'), ('Gastronomia'), ('Historia'), ('Jornalismo'), ('Med. Veterinária'), ('Medicina'),
|
||||||
|
('Nutrição'), ('Odontologia'), ('Outro'), ('Pedagogia'), ('Publicidade'), ('Superior Diversos'), ('Tec. Diversos'),
|
||||||
|
('Termomecânica'), ('Unificados'), ('Tec. Enfermagem'), ('Quimica'), ('EFI / EF II / EM'), ('Psicologia'),
|
||||||
|
('Terapia Ocupacinal'), ('R.I');
|
||||||
|
|
||||||
|
-- Empresas Table
|
||||||
|
CREATE TABLE empresas (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
nome VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO empresas (nome) VALUES
|
||||||
|
('Arte Formaturas'), ('JR Formaturas'), ('Perfil'), ('Photum'), ('Populi Formaturas'), ('Prime'), ('Smart'), ('Viva SP'),
|
||||||
|
('Antares'), ('Forcamp'), ('PNI'), ('Fábio Ribeiro'), ('Told - B2_(CAMPINAS)'), ('Told - B2_(RECIFE)'),
|
||||||
|
('NOVO - Told - B2_(SP)'), ('NOVO - Told - RUB_(SP)'), ('NOVO - TOLD'), ('Alpha Digital'), ('Golden'), ('Festa da Beca'),
|
||||||
|
('Ponta Eventos'), ('Toy SP'), ('MVP Formaturas'), ('RUB');
|
||||||
|
|
||||||
|
-- Anos Formaturas Table
|
||||||
|
CREATE TABLE anos_formaturas (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
ano_semestre VARCHAR(20) UNIQUE NOT NULL, -- Ex: 2019.2
|
||||||
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO anos_formaturas (ano_semestre) VALUES
|
||||||
|
('2019.2'), ('2020.1'), ('2020.2'), ('2021.1'), ('2021.2'), ('2022.1'), ('2022.2'), ('2023.1'), ('2023.2'),
|
||||||
|
('2024.1'), ('2024.2'), ('2025.1'), ('2025.2'), ('2026.1'), ('2026.2'), ('2027.1'), ('2027.2'), ('2028.1'),
|
||||||
|
('2028.2'), ('2029.1'), ('2029.2');
|
||||||
|
|
||||||
|
-- Tipos Servicos Table
|
||||||
|
CREATE TABLE tipos_servicos (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
nome VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO tipos_servicos (nome) VALUES
|
||||||
|
('Fotógrafo'), ('Recepcionista'), ('Cinegrafista'), ('Coordenação'), ('Ponto de Foto'), ('Ponto de ID'), ('Estúdio'),
|
||||||
|
('Outro'), ('Controle');
|
||||||
|
|
||||||
|
-- Tipos Eventos Table
|
||||||
|
CREATE TABLE tipos_eventos (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
nome VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO tipos_eventos (nome) VALUES
|
||||||
|
('Identificação'), ('Baile'), ('Colação'), ('Col/Baile (mesmo local)'), ('Col/Baile (local diferente)'), ('Missa / Culto'),
|
||||||
|
('Churrasco'), ('Trote'), ('Outro'), ('Balada'), ('Jantar'), ('Festa Junina'), ('Colação Oficial'), ('Family Day'),
|
||||||
|
('Refeição'), ('Estudio ID e Family Day'), ('Estudio Colação / Baile');
|
||||||
|
|
||||||
|
-- Precos Tipos Eventos Table (Junction Table for Pricing)
|
||||||
|
CREATE TABLE precos_tipos_eventos (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
tipo_evento_id UUID REFERENCES tipos_eventos(id) ON DELETE CASCADE,
|
||||||
|
funcao_profissional_id UUID REFERENCES funcoes_profissionais(id) ON DELETE CASCADE,
|
||||||
|
valor NUMERIC(10,2) NOT NULL DEFAULT 0.00,
|
||||||
|
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
UNIQUE(tipo_evento_id, funcao_profissional_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Initial Pricing Seed (Examples based on image, requires joining IDs which makes raw SQL insert hard without known UUIDs.
|
||||||
|
-- For simplicity in schema.sql, we'll skip complex dynamic inserts.
|
||||||
|
-- The user can populate via API or we can write a more complex PL/pgSQL block if absolutely necessary,
|
||||||
|
-- but usually schema.sql is structure + static data. Dynamic pricing is better handled via admin or separate migration script.
|
||||||
|
-- Leaving table empty for now, or adding a comment.)
|
||||||
|
|
|
||||||
133
backend/internal/empresas/handler.go
Normal file
133
backend/internal/empresas/handler.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
package empresas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
service *Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(service *Service) *Handler {
|
||||||
|
return &Handler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmpresaResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateEmpresaRequest struct {
|
||||||
|
Nome string `json:"nome" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toResponse(e generated.Empresa) EmpresaResponse {
|
||||||
|
return EmpresaResponse{
|
||||||
|
ID: uuid.UUID(e.ID.Bytes).String(),
|
||||||
|
Nome: e.Nome,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create godoc
|
||||||
|
// @Summary Create a new company
|
||||||
|
// @Tags empresas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param request body CreateEmpresaRequest true "Empresa Name"
|
||||||
|
// @Success 201 {object} EmpresaResponse
|
||||||
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
|
// @Router /api/empresas [post]
|
||||||
|
func (h *Handler) Create(c *gin.Context) {
|
||||||
|
var req CreateEmpresaRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
empresa, err := h.service.Create(c.Request.Context(), req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key value") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "Empresa already exists"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusCreated, toResponse(*empresa))
|
||||||
|
}
|
||||||
|
|
||||||
|
// List godoc
|
||||||
|
// @Summary List all companies
|
||||||
|
// @Tags empresas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Success 200 {array} EmpresaResponse
|
||||||
|
// @Router /api/empresas [get]
|
||||||
|
func (h *Handler) List(c *gin.Context) {
|
||||||
|
empresas, err := h.service.List(c.Request.Context())
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []EmpresaResponse
|
||||||
|
for _, empresa := range empresas {
|
||||||
|
response = append(response, toResponse(empresa))
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update godoc
|
||||||
|
// @Summary Update a company
|
||||||
|
// @Tags empresas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "Empresa ID"
|
||||||
|
// @Param request body CreateEmpresaRequest true "Empresa Name"
|
||||||
|
// @Success 200 {object} EmpresaResponse
|
||||||
|
// @Router /api/empresas/{id} [put]
|
||||||
|
func (h *Handler) Update(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var req CreateEmpresaRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
empresa, err := h.service.Update(c.Request.Context(), id, req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, toResponse(*empresa))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete godoc
|
||||||
|
// @Summary Delete a company
|
||||||
|
// @Tags empresas
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "Empresa ID"
|
||||||
|
// @Success 204 {object} nil
|
||||||
|
// @Router /api/empresas/{id} [delete]
|
||||||
|
func (h *Handler) Delete(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
if err := h.service.Delete(c.Request.Context(), id); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
67
backend/internal/empresas/service.go
Normal file
67
backend/internal/empresas/service.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package empresas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
queries *generated.Queries
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(queries *generated.Queries) *Service {
|
||||||
|
return &Service{queries: queries}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Create(ctx context.Context, nome string) (*generated.Empresa, error) {
|
||||||
|
empresa, err := s.queries.CreateEmpresa(ctx, nome)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &empresa, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) List(ctx context.Context) ([]generated.Empresa, error) {
|
||||||
|
return s.queries.ListEmpresas(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetByID(ctx context.Context, id string) (*generated.Empresa, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
empresa, err := s.queries.GetEmpresaByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &empresa, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Update(ctx context.Context, id, nome string) (*generated.Empresa, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
|
empresa, err := s.queries.UpdateEmpresa(ctx, generated.UpdateEmpresaParams{
|
||||||
|
ID: pgtype.UUID{Bytes: uuidVal, Valid: true},
|
||||||
|
Nome: nome,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &empresa, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Delete(ctx context.Context, id string) error {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid id")
|
||||||
|
}
|
||||||
|
return s.queries.DeleteEmpresa(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package funcoes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"photum-backend/internal/db/generated"
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
|
@ -22,6 +23,10 @@ type FuncaoResponse struct {
|
||||||
Nome string `json:"nome"`
|
Nome string `json:"nome"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateFuncaoRequest struct {
|
||||||
|
Nome string `json:"nome" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
func toResponse(f generated.FuncoesProfissionai) FuncaoResponse {
|
func toResponse(f generated.FuncoesProfissionai) FuncaoResponse {
|
||||||
return FuncaoResponse{
|
return FuncaoResponse{
|
||||||
ID: uuid.UUID(f.ID.Bytes).String(),
|
ID: uuid.UUID(f.ID.Bytes).String(),
|
||||||
|
|
@ -36,15 +41,14 @@ func toResponse(f generated.FuncoesProfissionai) FuncaoResponse {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Param request body map[string]string true "Create Function Request"
|
// @Param request body CreateFuncaoRequest true "Create Function Request"
|
||||||
// @Success 201 {object} FuncaoResponse
|
// @Success 201 {object} FuncaoResponse
|
||||||
// @Failure 400 {object} map[string]string
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
// @Failure 500 {object} map[string]string
|
// @Failure 500 {object} map[string]string
|
||||||
// @Router /api/funcoes [post]
|
// @Router /api/funcoes [post]
|
||||||
func (h *Handler) Create(c *gin.Context) {
|
func (h *Handler) Create(c *gin.Context) {
|
||||||
var req struct {
|
var req CreateFuncaoRequest
|
||||||
Nome string `json:"nome" binding:"required"`
|
|
||||||
}
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
|
|
@ -52,6 +56,10 @@ func (h *Handler) Create(c *gin.Context) {
|
||||||
|
|
||||||
funcao, err := h.service.Create(c.Request.Context(), req.Nome)
|
funcao, err := h.service.Create(c.Request.Context(), req.Nome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key value") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "Funcao already exists"})
|
||||||
|
return
|
||||||
|
}
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +73,6 @@ func (h *Handler) Create(c *gin.Context) {
|
||||||
// @Tags funcoes
|
// @Tags funcoes
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security BearerAuth
|
|
||||||
// @Success 200 {array} FuncaoResponse
|
// @Success 200 {array} FuncaoResponse
|
||||||
// @Failure 500 {object} map[string]string
|
// @Failure 500 {object} map[string]string
|
||||||
// @Router /api/funcoes [get]
|
// @Router /api/funcoes [get]
|
||||||
|
|
@ -92,16 +99,15 @@ func (h *Handler) List(c *gin.Context) {
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
// @Param id path string true "Function ID"
|
// @Param id path string true "Function ID"
|
||||||
// @Param request body map[string]string true "Update Function Request"
|
// @Param request body CreateFuncaoRequest true "Update Function Request"
|
||||||
// @Success 200 {object} FuncaoResponse
|
// @Success 200 {object} FuncaoResponse
|
||||||
// @Failure 400 {object} map[string]string
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
// @Failure 500 {object} map[string]string
|
// @Failure 500 {object} map[string]string
|
||||||
// @Router /api/funcoes/{id} [put]
|
// @Router /api/funcoes/{id} [put]
|
||||||
func (h *Handler) Update(c *gin.Context) {
|
func (h *Handler) Update(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
var req struct {
|
var req CreateFuncaoRequest
|
||||||
Nome string `json:"nome" binding:"required"`
|
|
||||||
}
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
|
|
@ -109,6 +115,10 @@ func (h *Handler) Update(c *gin.Context) {
|
||||||
|
|
||||||
funcao, err := h.service.Update(c.Request.Context(), id, req.Nome)
|
funcao, err := h.service.Update(c.Request.Context(), id, req.Nome)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key value") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "Funcao already exists"})
|
||||||
|
return
|
||||||
|
}
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
150
backend/internal/tipos_eventos/handler.go
Normal file
150
backend/internal/tipos_eventos/handler.go
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
package tipos_eventos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
service *Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(service *Service) *Handler {
|
||||||
|
return &Handler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventoResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrecoResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
TipoEventoID string `json:"tipo_evento_id"`
|
||||||
|
FuncaoProfissionalID string `json:"funcao_profissional_id"`
|
||||||
|
FuncaoNome string `json:"funcao_nome"`
|
||||||
|
Valor float64 `json:"valor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toEventoResponse(e generated.TiposEvento) EventoResponse {
|
||||||
|
return EventoResponse{
|
||||||
|
ID: uuid.UUID(e.ID.Bytes).String(),
|
||||||
|
Nome: e.Nome,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromPgNumeric(n pgtype.Numeric) float64 {
|
||||||
|
f, _ := n.Float64Value()
|
||||||
|
return f.Float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateEventoRequest struct {
|
||||||
|
Nome string `json:"nome" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create godoc
|
||||||
|
// @Summary Create a new event type
|
||||||
|
// @Tags tipos_eventos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param request body CreateEventoRequest true "Nome"
|
||||||
|
// @Success 201 {object} EventoResponse
|
||||||
|
// @Router /api/tipos-eventos [post]
|
||||||
|
func (h *Handler) Create(c *gin.Context) {
|
||||||
|
var req CreateEventoRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event, err := h.service.Create(c.Request.Context(), req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusCreated, toEventoResponse(*event))
|
||||||
|
}
|
||||||
|
|
||||||
|
// List godoc
|
||||||
|
// @Summary List all event types
|
||||||
|
// @Tags tipos_eventos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Success 200 {array} EventoResponse
|
||||||
|
// @Router /api/tipos-eventos [get]
|
||||||
|
func (h *Handler) List(c *gin.Context) {
|
||||||
|
events, err := h.service.List(c.Request.Context())
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []EventoResponse
|
||||||
|
for _, e := range events {
|
||||||
|
response = append(response, toEventoResponse(e))
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrice godoc
|
||||||
|
// @Summary Set price for an event function
|
||||||
|
// @Tags tipos_eventos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param request body PriceInput true "Price Input"
|
||||||
|
// @Success 200 {object} map[string]string
|
||||||
|
// @Router /api/tipos-eventos/precos [post]
|
||||||
|
func (h *Handler) SetPrice(c *gin.Context) {
|
||||||
|
var req PriceInput
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := h.service.SetPrice(c.Request.Context(), req)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "price set"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPrices godoc
|
||||||
|
// @Summary List prices for an event
|
||||||
|
// @Tags tipos_eventos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "Event ID"
|
||||||
|
// @Success 200 {array} PrecoResponse
|
||||||
|
// @Router /api/tipos-eventos/{id}/precos [get]
|
||||||
|
func (h *Handler) ListPrices(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
prices, err := h.service.ListPrices(c.Request.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []PrecoResponse
|
||||||
|
for _, p := range prices {
|
||||||
|
response = append(response, PrecoResponse{
|
||||||
|
ID: uuid.UUID(p.ID.Bytes).String(),
|
||||||
|
TipoEventoID: uuid.UUID(p.TipoEventoID.Bytes).String(),
|
||||||
|
FuncaoProfissionalID: uuid.UUID(p.FuncaoProfissionalID.Bytes).String(),
|
||||||
|
FuncaoNome: p.FuncaoNome,
|
||||||
|
Valor: fromPgNumeric(p.Valor),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
112
backend/internal/tipos_eventos/service.go
Normal file
112
backend/internal/tipos_eventos/service.go
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
package tipos_eventos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
queries *generated.Queries
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(queries *generated.Queries) *Service {
|
||||||
|
return &Service{queries: queries}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event CRUD
|
||||||
|
|
||||||
|
func (s *Service) Create(ctx context.Context, nome string) (*generated.TiposEvento, error) {
|
||||||
|
event, err := s.queries.CreateTipoEvento(ctx, nome)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) List(ctx context.Context) ([]generated.TiposEvento, error) {
|
||||||
|
return s.queries.ListTiposEventos(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetByID(ctx context.Context, id string) (*generated.TiposEvento, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
event, err := s.queries.GetTipoEventoByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Update(ctx context.Context, id, nome string) (*generated.TiposEvento, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
event, err := s.queries.UpdateTipoEvento(ctx, generated.UpdateTipoEventoParams{
|
||||||
|
ID: pgtype.UUID{Bytes: uuidVal, Valid: true},
|
||||||
|
Nome: nome,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Delete(ctx context.Context, id string) error {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid id")
|
||||||
|
}
|
||||||
|
return s.queries.DeleteTipoEvento(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pricing Logic
|
||||||
|
|
||||||
|
type PriceInput struct {
|
||||||
|
TipoEventoID string `json:"tipo_evento_id"`
|
||||||
|
FuncaoProfissionalID string `json:"funcao_profissional_id"`
|
||||||
|
Valor float64 `json:"valor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SetPrice(ctx context.Context, input PriceInput) (*generated.PrecosTiposEvento, error) {
|
||||||
|
eventoUUID, err := uuid.Parse(input.TipoEventoID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid tipo_evento_id")
|
||||||
|
}
|
||||||
|
funcaoUUID, err := uuid.Parse(input.FuncaoProfissionalID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid funcao_profissional_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
precio, err := s.queries.CreatePrecoEvento(ctx, generated.CreatePrecoEventoParams{
|
||||||
|
TipoEventoID: pgtype.UUID{Bytes: eventoUUID, Valid: true},
|
||||||
|
FuncaoProfissionalID: pgtype.UUID{Bytes: funcaoUUID, Valid: true},
|
||||||
|
Valor: toPgNumeric(input.Valor),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &precio, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListPrices(ctx context.Context, eventoID string) ([]generated.ListPrecosByEventoIDRow, error) {
|
||||||
|
eventoUUID, err := uuid.Parse(eventoID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid evento_id")
|
||||||
|
}
|
||||||
|
return s.queries.ListPrecosByEventoID(ctx, pgtype.UUID{Bytes: eventoUUID, Valid: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper (Assuming user doesn't have it in shared utils or similar)
|
||||||
|
func toPgNumeric(f float64) pgtype.Numeric {
|
||||||
|
var n pgtype.Numeric
|
||||||
|
n.Scan(f)
|
||||||
|
return n
|
||||||
|
}
|
||||||
133
backend/internal/tipos_servicos/handler.go
Normal file
133
backend/internal/tipos_servicos/handler.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
package tipos_servicos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
service *Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(service *Service) *Handler {
|
||||||
|
return &Handler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TipoServicoResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Nome string `json:"nome"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTipoServicoRequest struct {
|
||||||
|
Nome string `json:"nome" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toResponse(t generated.TiposServico) TipoServicoResponse {
|
||||||
|
return TipoServicoResponse{
|
||||||
|
ID: uuid.UUID(t.ID.Bytes).String(),
|
||||||
|
Nome: t.Nome,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create godoc
|
||||||
|
// @Summary Create a new service type
|
||||||
|
// @Tags tipos_servicos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param request body CreateTipoServicoRequest true "Nome"
|
||||||
|
// @Success 201 {object} TipoServicoResponse
|
||||||
|
// @Failure 400 {object} map[string]string
|
||||||
|
// @Failure 409 {object} map[string]string
|
||||||
|
// @Router /api/tipos-servicos [post]
|
||||||
|
func (h *Handler) Create(c *gin.Context) {
|
||||||
|
var req CreateTipoServicoRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tipo, err := h.service.Create(c.Request.Context(), req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate key value") {
|
||||||
|
c.JSON(http.StatusConflict, gin.H{"error": "Tipo de Servico already exists"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusCreated, toResponse(*tipo))
|
||||||
|
}
|
||||||
|
|
||||||
|
// List godoc
|
||||||
|
// @Summary List all service types
|
||||||
|
// @Tags tipos_servicos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Success 200 {array} TipoServicoResponse
|
||||||
|
// @Router /api/tipos-servicos [get]
|
||||||
|
func (h *Handler) List(c *gin.Context) {
|
||||||
|
tipos, err := h.service.List(c.Request.Context())
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []TipoServicoResponse
|
||||||
|
for _, tipo := range tipos {
|
||||||
|
response = append(response, toResponse(tipo))
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update godoc
|
||||||
|
// @Summary Update a service type
|
||||||
|
// @Tags tipos_servicos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "ID"
|
||||||
|
// @Param request body CreateTipoServicoRequest true "Nome"
|
||||||
|
// @Success 200 {object} TipoServicoResponse
|
||||||
|
// @Router /api/tipos-servicos/{id} [put]
|
||||||
|
func (h *Handler) Update(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var req CreateTipoServicoRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tipo, err := h.service.Update(c.Request.Context(), id, req.Nome)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, toResponse(*tipo))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete godoc
|
||||||
|
// @Summary Delete a service type
|
||||||
|
// @Tags tipos_servicos
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param id path string true "ID"
|
||||||
|
// @Success 204 {object} nil
|
||||||
|
// @Router /api/tipos-servicos/{id} [delete]
|
||||||
|
func (h *Handler) Delete(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
if err := h.service.Delete(c.Request.Context(), id); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
67
backend/internal/tipos_servicos/service.go
Normal file
67
backend/internal/tipos_servicos/service.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package tipos_servicos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"photum-backend/internal/db/generated"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
queries *generated.Queries
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(queries *generated.Queries) *Service {
|
||||||
|
return &Service{queries: queries}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Create(ctx context.Context, nome string) (*generated.TiposServico, error) {
|
||||||
|
tipo, err := s.queries.CreateTipoServico(ctx, nome)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tipo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) List(ctx context.Context) ([]generated.TiposServico, error) {
|
||||||
|
return s.queries.ListTiposServicos(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetByID(ctx context.Context, id string) (*generated.TiposServico, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
tipo, err := s.queries.GetTipoServicoByID(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tipo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Update(ctx context.Context, id, nome string) (*generated.TiposServico, error) {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
|
tipo, err := s.queries.UpdateTipoServico(ctx, generated.UpdateTipoServicoParams{
|
||||||
|
ID: pgtype.UUID{Bytes: uuidVal, Valid: true},
|
||||||
|
Nome: nome,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tipo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Delete(ctx context.Context, id string) error {
|
||||||
|
uuidVal, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid id")
|
||||||
|
}
|
||||||
|
return s.queries.DeleteTipoServico(ctx, pgtype.UUID{Bytes: uuidVal, Valid: true})
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue