Files
mira/backend/internal/users/routes.go
Cauê Faleiros 0b920da187
All checks were successful
CI / backend (push) Successful in 13m8s
CI / frontend (push) Successful in 10m46s
CI / docker (push) Successful in 2m59s
Build post chat and attachment workflows
2026-06-08 16:44:33 -03:00

131 lines
3.6 KiB
Go

package users
import (
"net/http"
"strings"
"time"
"mira/backend/internal/mail"
"github.com/gin-gonic/gin"
)
type Routes struct {
store Store
appPublicURL string
mailSender mail.Sender
}
func NewRoutes(store Store, appPublicURL string, mailSender mail.Sender) Routes {
return Routes{
store: store,
appPublicURL: strings.TrimRight(appPublicURL, "/"),
mailSender: mailSender,
}
}
func (r Routes) Register(router *gin.RouterGroup, requireAuth gin.HandlerFunc) {
router.Use(requireAuth)
router.GET("", r.list)
router.GET("/invitations", r.listInvitations)
router.POST("/invitations", r.createInvitation)
}
func (r Routes) list(c *gin.Context) {
if c.GetString("auth_role") != RoleSuperAdmin {
c.JSON(http.StatusForbidden, gin.H{"message": "Permissao insuficiente."})
return
}
users, err := r.store.List(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Nao foi possivel listar usuarios."})
return
}
c.JSON(http.StatusOK, gin.H{"users": users})
}
func (r Routes) listInvitations(c *gin.Context) {
if c.GetString("auth_role") != RoleSuperAdmin {
c.JSON(http.StatusForbidden, gin.H{"message": "Permissao insuficiente."})
return
}
invitations, err := r.store.ListInvitations(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Nao foi possivel listar convites."})
return
}
c.JSON(http.StatusOK, gin.H{"invitations": invitations})
}
type createInvitationRequest struct {
Email string `json:"email" binding:"required,email"`
Role string `json:"role" binding:"required"`
ClientID string `json:"client_id"`
}
func (r Routes) createInvitation(c *gin.Context) {
if c.GetString("auth_role") != RoleSuperAdmin {
c.JSON(http.StatusForbidden, gin.H{"message": "Permissao insuficiente."})
return
}
var input createInvitationRequest
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "Informe os dados do convite."})
return
}
role := strings.TrimSpace(input.Role)
if role != RoleAgencyUser && role != RoleClientViewer {
c.JSON(http.StatusBadRequest, gin.H{"message": "Perfil invalido para convite."})
return
}
if role == RoleClientViewer && strings.TrimSpace(input.ClientID) == "" {
c.JSON(http.StatusBadRequest, gin.H{"message": "Convites de cliente precisam de um cliente vinculado."})
return
}
token, tokenHash, err := NewInvitationToken()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Nao foi possivel gerar o convite."})
return
}
invitation, err := r.store.CreateInvitation(c.Request.Context(), CreateInvitationInput{
Email: strings.TrimSpace(input.Email),
Role: role,
ClientID: strings.TrimSpace(input.ClientID),
TokenHash: tokenHash,
ExpiresAt: time.Now().Add(7 * 24 * time.Hour),
CreatedBy: c.GetString("auth_user_id"),
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Nao foi possivel criar o convite."})
return
}
invitation.InvitationURL = r.invitationURL(token)
invitation.EmailSent = false
if r.mailSender.IsConfigured() {
if err := r.mailSender.SendInvitation(invitation.Email, invitation.InvitationURL); err != nil {
invitation.EmailError = "Convite criado, mas nao foi possivel enviar o e-mail."
} else {
invitation.EmailSent = true
}
}
c.JSON(http.StatusCreated, gin.H{"invitation": invitation})
}
func (r Routes) invitationURL(token string) string {
if r.appPublicURL == "" {
return "/accept-invitation?token=" + token
}
return r.appPublicURL + "/accept-invitation?token=" + token
}