feat: versão 1.5 - CRM Beta com leads, funis, campanhas e portal do cliente

This commit is contained in:
Erik Silva
2025-12-24 17:36:52 -03:00
parent 99d828869a
commit dfb91c8ba5
98 changed files with 18255 additions and 1465 deletions

View File

@@ -167,3 +167,94 @@ func (h *AuthHandler) ChangePassword(w http.ResponseWriter, r *http.Request) {
"message": "Password changed successfully",
})
}
// UnifiedLogin handles login for all user types (agency, customer, superadmin)
func (h *AuthHandler) UnifiedLogin(w http.ResponseWriter, r *http.Request) {
log.Printf("🔐 UNIFIED LOGIN HANDLER CALLED - Method: %s", r.Method)
if r.Method != http.MethodPost {
log.Printf("❌ Method not allowed: %s", r.Method)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
bodyBytes, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("❌ Failed to read body: %v", err)
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
defer r.Body.Close()
log.Printf("📥 Raw body: %s", string(bodyBytes))
sanitized := strings.TrimSpace(string(bodyBytes))
var req domain.UnifiedLoginRequest
if err := json.Unmarshal([]byte(sanitized), &req); err != nil {
log.Printf("❌ JSON parse error: %v", err)
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
log.Printf("📧 Unified login attempt for email: %s", req.Email)
response, err := h.authService.UnifiedLogin(req)
if err != nil {
log.Printf("❌ authService.UnifiedLogin error: %v", err)
if err == service.ErrInvalidCredentials || strings.Contains(err.Error(), "não autorizado") {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": err.Error(),
})
} else {
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
return
}
// VALIDAÇÃO DE SEGURANÇA: Verificar se o tenant corresponde ao subdomain acessado
tenantIDFromContext := ""
if ctxTenantID := r.Context().Value(middleware.TenantIDKey); ctxTenantID != nil {
tenantIDFromContext, _ = ctxTenantID.(string)
}
// Se foi detectado um tenant no contexto E o usuário tem tenant
if tenantIDFromContext != "" && response.TenantID != "" {
if response.TenantID != tenantIDFromContext {
log.Printf("❌ LOGIN BLOCKED: User from tenant %s tried to login in tenant %s subdomain",
response.TenantID, tenantIDFromContext)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusForbidden)
json.NewEncoder(w).Encode(map[string]string{
"error": "Credenciais inválidas para esta agência",
})
return
}
log.Printf("✅ TENANT LOGIN VALIDATION PASSED: %s", response.TenantID)
}
log.Printf("✅ Unified login successful: email=%s, type=%s, role=%s",
response.Email, response.UserType, response.Role)
// Montar resposta compatível com frontend antigo E com novos campos
compatibleResponse := map[string]interface{}{
"token": response.Token,
"user": map[string]interface{}{
"id": response.UserID,
"email": response.Email,
"name": response.Name,
"role": response.Role,
"tenant_id": response.TenantID,
"user_type": response.UserType,
},
// Campos adicionais do sistema unificado
"user_type": response.UserType,
"user_id": response.UserID,
"subdomain": response.Subdomain,
"tenant_id": response.TenantID,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(compatibleResponse)
}