fix: resolved user profile 500 error, fixed frontend build types, enhanced logging, increases test coverage
This commit is contained in:
parent
3fa875ed98
commit
f51a8dd99c
7 changed files with 46 additions and 7 deletions
|
|
@ -80,6 +80,7 @@ O endpoint `/jobs` suporta filtros avançados via query params:
|
||||||
| `DELETE` | `/api/v1/users/{id}` | `superadmin` | Deletar usuário |
|
| `DELETE` | `/api/v1/users/{id}` | `superadmin` | Deletar usuário |
|
||||||
| `POST` | `/jobs` | `admin`, `recruiter` | Criar vaga |
|
| `POST` | `/jobs` | `admin`, `recruiter` | Criar vaga |
|
||||||
| `GET` | `/api/v1/users/me` | `any` (authed) | Perfil do usuário |
|
| `GET` | `/api/v1/users/me` | `any` (authed) | Perfil do usuário |
|
||||||
|
| `DELETE` | `/api/v1/applications/{id}` | `admin`, `recruiter` | Deletar candidatura |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -836,9 +837,11 @@ func (h *CoreHandlers) Me(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
user, err := h.adminService.GetUser(ctx, userID)
|
user, err := h.adminService.GetUser(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("ERROR [Me Handler] GetUser failed for userID %s: %v", userID, err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("SUCCESS [Me Handler] User retrieved: %s", user.Email)
|
||||||
|
|
||||||
company, _ := h.adminService.GetCompanyByUserID(ctx, userID)
|
company, _ := h.adminService.GetCompanyByUserID(ctx, userID)
|
||||||
if company != nil {
|
if company != nil {
|
||||||
|
|
|
||||||
|
|
@ -565,7 +565,7 @@ func (s *AdminService) getTagByID(ctx context.Context, id int) (*models.Tag, err
|
||||||
// GetUser fetches a user by ID
|
// GetUser fetches a user by ID
|
||||||
func (s *AdminService) GetUser(ctx context.Context, id string) (*dto.User, error) {
|
func (s *AdminService) GetUser(ctx context.Context, id string) (*dto.User, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, name, email, role, created_at
|
SELECT id, full_name, email, role, created_at
|
||||||
FROM users WHERE id = $1
|
FROM users WHERE id = $1
|
||||||
`
|
`
|
||||||
var u dto.User
|
var u dto.User
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ func TestAdminService_GetUser(t *testing.T) {
|
||||||
t.Run("returns user by id", func(t *testing.T) {
|
t.Run("returns user by id", func(t *testing.T) {
|
||||||
userID := "019b5290-9680-7c06-9ee3-c9e0e117251b"
|
userID := "019b5290-9680-7c06-9ee3-c9e0e117251b"
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
mock.ExpectQuery("SELECT id, name, email, role, created_at FROM users WHERE id").
|
mock.ExpectQuery("SELECT id, full_name, email, role, created_at FROM users WHERE id").
|
||||||
WithArgs(userID).
|
WithArgs(userID).
|
||||||
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "email", "role", "created_at"}).
|
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "email", "role", "created_at"}).
|
||||||
AddRow(userID, "Test User", "test@example.com", "admin", now))
|
AddRow(userID, "Test User", "test@example.com", "admin", now))
|
||||||
|
|
|
||||||
31
backend/internal/services/application_service_test.go
Normal file
31
backend/internal/services/application_service_test.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplicationService_DeleteApplication(t *testing.T) {
|
||||||
|
db, mock, err := sqlmock.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
s := NewApplicationService(db)
|
||||||
|
appID := "test-app-id"
|
||||||
|
|
||||||
|
mock.ExpectExec("DELETE FROM applications WHERE id = \\$1").
|
||||||
|
WithArgs(appID).
|
||||||
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
|
||||||
|
err = s.DeleteApplication(appID)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error was not expected while deleting application: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mock.ExpectationsWereMet(); err != nil {
|
||||||
|
t.Errorf("there were unfulfilled expectations: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ export async function login(
|
||||||
role?: "candidate" | "admin" | "company" // Deprecated argument, kept for signature compatibility if needed, but ignored
|
role?: "candidate" | "admin" | "company" // Deprecated argument, kept for signature compatibility if needed, but ignored
|
||||||
): Promise<User | null> {
|
): Promise<User | null> {
|
||||||
try {
|
try {
|
||||||
|
console.log("%c[AUTH] Attempting login...", "color: #3b82f6; font-weight: bold", { email });
|
||||||
const res = await fetch(`${API_URL}/auth/login`, {
|
const res = await fetch(`${API_URL}/auth/login`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -43,10 +44,10 @@ export async function login(
|
||||||
// Map backend response to frontend User type
|
// Map backend response to frontend User type
|
||||||
// Note: The backend returns roles as an array of strings. The frontend expects a single 'role' or we need to adapt.
|
// Note: The backend returns roles as an array of strings. The frontend expects a single 'role' or we need to adapt.
|
||||||
// For now we map the first role or main role to the 'role' field.
|
// For now we map the first role or main role to the 'role' field.
|
||||||
let userRole: "candidate" | "admin" | "company" = "candidate";
|
let userRole: "candidate" | "admin" | "company" | "superadmin" = "candidate";
|
||||||
// Check for SuperAdmin (Platform Admin)
|
// Check for SuperAdmin (Platform Admin)
|
||||||
if (data.user.roles.includes("superadmin") || data.user.roles.includes("SUPERADMIN")) {
|
if (data.user.roles.includes("superadmin") || data.user.roles.includes("SUPERADMIN")) {
|
||||||
userRole = "admin";
|
userRole = "superadmin";
|
||||||
// Check for Company Admin (now called 'admin') or Recruiter
|
// Check for Company Admin (now called 'admin') or Recruiter
|
||||||
} else if (data.user.roles.includes("admin") || data.user.roles.includes("recruiter")) {
|
} else if (data.user.roles.includes("admin") || data.user.roles.includes("recruiter")) {
|
||||||
userRole = "company";
|
userRole = "company";
|
||||||
|
|
@ -69,7 +70,7 @@ export async function login(
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Login error:", error);
|
console.error("%c[AUTH] Login Error:", "color: #ef4444; font-weight: bold", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,9 +86,12 @@ export function getCurrentUser(): User | null {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
const stored = localStorage.getItem(AUTH_KEY);
|
const stored = localStorage.getItem(AUTH_KEY);
|
||||||
if (stored) {
|
if (stored) {
|
||||||
return JSON.parse(stored);
|
const user = JSON.parse(stored);
|
||||||
|
console.log("%c[AUTH] User Loaded from Storage", "color: #10b981", user.email);
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.warn("%c[AUTH] No user found in storage", "color: #f59e0b");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export interface User {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
role: "candidate" | "admin" | "company";
|
role: "candidate" | "admin" | "company" | "superadmin";
|
||||||
roles?: string[]; // Added to match backend response structure
|
roles?: string[]; // Added to match backend response structure
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
area?: string;
|
area?: string;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue