Features: - React 18 + TypeScript frontend with Vite - Go + Gin backend API - PostgreSQL database - JWT authentication with refresh tokens - User management (admin panel) - Docker containerization - Progress tracking system - 4 economic modules structure Fixed: - Login with username or email - User creation without required email - Database nullable timestamps - API response field naming
129 lines
3.6 KiB
Go
129 lines
3.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
"github.com/ren/econ/backend/internal/models"
|
|
)
|
|
|
|
type UserRepository struct {
|
|
db *pgxpool.Pool
|
|
}
|
|
|
|
func NewUserRepository(db *pgxpool.Pool) *UserRepository {
|
|
return &UserRepository{db: db}
|
|
}
|
|
|
|
func (r *UserRepository) Create(ctx context.Context, user *models.Usuario) error {
|
|
user.ID = uuid.New()
|
|
user.CreadoEn = time.Now()
|
|
user.Activo = true
|
|
if user.Rol == "" {
|
|
user.Rol = "estudiante"
|
|
}
|
|
|
|
query := `
|
|
INSERT INTO usuarios (id, email, username, password_hash, nombre, rol, creado_en, activo)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
`
|
|
_, err := r.db.Exec(ctx, query,
|
|
user.ID, user.Email, user.Username, user.PasswordHash, user.Nombre, user.Rol, user.CreadoEn, user.Activo)
|
|
return err
|
|
}
|
|
|
|
func (r *UserRepository) GetByID(ctx context.Context, id uuid.UUID) (*models.Usuario, error) {
|
|
query := `
|
|
SELECT id, email, username, password_hash, nombre, rol, creado_en, ultimo_login, activo
|
|
FROM usuarios WHERE id = $1
|
|
`
|
|
var user models.Usuario
|
|
err := r.db.QueryRow(ctx, query, id).Scan(
|
|
&user.ID, &user.Email, &user.Username, &user.PasswordHash, &user.Nombre,
|
|
&user.Rol, &user.CreadoEn, &user.UltimoLogin, &user.Activo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
func (r *UserRepository) GetByEmail(ctx context.Context, email string) (*models.Usuario, error) {
|
|
query := `
|
|
SELECT id, email, username, password_hash, nombre, rol, creado_en, ultimo_login, activo
|
|
FROM usuarios WHERE email = $1
|
|
`
|
|
var user models.Usuario
|
|
err := r.db.QueryRow(ctx, query, email).Scan(
|
|
&user.ID, &user.Email, &user.Username, &user.PasswordHash, &user.Nombre,
|
|
&user.Rol, &user.CreadoEn, &user.UltimoLogin, &user.Activo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
func (r *UserRepository) GetByUsername(ctx context.Context, username string) (*models.Usuario, error) {
|
|
query := `
|
|
SELECT id, email, username, password_hash, nombre, rol, creado_en, ultimo_login, activo
|
|
FROM usuarios WHERE username = $1
|
|
`
|
|
var user models.Usuario
|
|
err := r.db.QueryRow(ctx, query, username).Scan(
|
|
&user.ID, &user.Email, &user.Username, &user.PasswordHash, &user.Nombre,
|
|
&user.Rol, &user.CreadoEn, &user.UltimoLogin, &user.Activo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
func (r *UserRepository) List(ctx context.Context) ([]models.Usuario, error) {
|
|
query := `
|
|
SELECT id, email, username, password_hash, nombre, rol, creado_en, ultimo_login, activo
|
|
FROM usuarios ORDER BY creado_en DESC
|
|
`
|
|
rows, err := r.db.Query(ctx, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var users []models.Usuario
|
|
for rows.Next() {
|
|
var user models.Usuario
|
|
err := rows.Scan(
|
|
&user.ID, &user.Email, &user.Username, &user.PasswordHash, &user.Nombre,
|
|
&user.Rol, &user.CreadoEn, &user.UltimoLogin, &user.Activo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
users = append(users, user)
|
|
}
|
|
return users, nil
|
|
}
|
|
|
|
func (r *UserRepository) Update(ctx context.Context, user *models.Usuario) error {
|
|
query := `
|
|
UPDATE usuarios SET email = $2, nombre = $3, rol = $4, activo = $5
|
|
WHERE id = $1
|
|
`
|
|
_, err := r.db.Exec(ctx, query,
|
|
user.ID, user.Email, user.Nombre, user.Rol, user.Activo)
|
|
return err
|
|
}
|
|
|
|
func (r *UserRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
|
// Soft delete - set activo to false
|
|
query := `UPDATE usuarios SET activo = false WHERE id = $1`
|
|
_, err := r.db.Exec(ctx, query, id)
|
|
return err
|
|
}
|
|
|
|
func (r *UserRepository) UpdateLastLogin(ctx context.Context, id uuid.UUID) error {
|
|
query := `UPDATE usuarios SET ultimo_login = $2 WHERE id = $1`
|
|
_, err := r.db.Exec(ctx, query, id, time.Now())
|
|
return err
|
|
}
|