Files
bssapp/svc/repository/mk_user_repository.go
2026-02-11 17:46:22 +03:00

353 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package repository
import (
"bssapp-backend/models"
"database/sql"
"errors"
"strings"
"time"
"github.com/lib/pq"
)
var ErrMkUserNotFound = errors.New("mk_user not found")
type MkUserRepository struct {
DB *sql.DB
}
func NewMkUserRepository(db *sql.DB) *MkUserRepository {
return &MkUserRepository{DB: db}
}
// -------------------------------------------------------
// 🔍 GET BY USERNAME
// -------------------------------------------------------
func (r *MkUserRepository) GetByUsername(username string) (*models.MkUser, error) {
username = strings.TrimSpace(username)
var u models.MkUser
err := r.DB.QueryRow(`SELECT
u.id,
u.username,
COALESCE(u.email,'') AS email,
u.is_active,
COALESCE(u.password_hash,'') AS password_hash,
u.force_password_change,
COALESCE(r.id, 0) AS role_id,
COALESCE(r.code, '') AS role_code,
-- ✅ DEPARTMENTS
COALESCE(
array_agg(DISTINCT d.code)
FILTER (WHERE d.code IS NOT NULL),
'{}'
) AS department_codes,
u.password_updated_at,
u.created_at,
u.updated_at,
u.last_login_at
FROM mk_dfusr u
LEFT JOIN dfrole_usr ru
ON ru.dfusr_id = u.id
LEFT JOIN dfrole r
ON r.id = ru.dfrole_id
-- ✅ USER → DEPT
LEFT JOIN dfusr_dprt ud
ON ud.dfusr_id = u.id
AND ud.is_active = true
LEFT JOIN mk_dprt d
ON d.id = ud.dprt_id
WHERE LOWER(u.username) = LOWER($1)
GROUP BY
u.id, r.id
LIMIT 1
`, username).Scan(
&u.ID,
&u.Username,
&u.Email,
&u.IsActive,
&u.PasswordHash,
&u.ForcePasswordChange,
&u.RoleID,
&u.RoleCode,
pq.Array(&u.DepartmentCodes), // ✅
&u.PasswordUpdatedAt,
&u.CreatedAt,
&u.UpdatedAt,
&u.LastLoginAt,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrMkUserNotFound
}
return nil, err
}
return &u, nil
}
// -------------------------------------------------------
// 🔍 GET BY ID
// -------------------------------------------------------
func (r *MkUserRepository) GetByID(id int64) (*models.MkUser, error) {
var u models.MkUser
err := r.DB.QueryRow(`
SELECT
u.id,
u.username,
COALESCE(u.email,'') AS email,
u.is_active,
COALESCE(u.password_hash,'') AS password_hash,
u.force_password_change,
COALESCE(r.id, 0) AS role_id,
COALESCE(r.code, '') AS role_code,
-- ✅ DEPARTMENTS
COALESCE(
array_agg(DISTINCT d.code)
FILTER (WHERE d.code IS NOT NULL),
'{}'
) AS department_codes,
u.password_updated_at,
u.created_at,
u.updated_at,
u.last_login_at
FROM mk_dfusr u
LEFT JOIN dfrole_usr ru
ON ru.dfusr_id = u.id
LEFT JOIN dfrole r
ON r.id = ru.dfrole_id
-- ✅ USER → DEPT
LEFT JOIN dfusr_dprt ud
ON ud.dfusr_id = u.id
AND ud.is_active = true
LEFT JOIN mk_dprt d
ON d.id = ud.dprt_id
WHERE LOWER(u.username) = LOWER($1)
GROUP BY
u.id, r.id
LIMIT 1
`, id).Scan(
&u.ID,
&u.Username,
&u.Email,
&u.IsActive,
&u.PasswordHash,
&u.ForcePasswordChange,
&u.RoleID,
&u.RoleCode,
pq.Array(&u.DepartmentCodes), // ✅
&u.PasswordUpdatedAt,
&u.CreatedAt,
&u.UpdatedAt,
&u.LastLoginAt,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrMkUserNotFound
}
return nil, err
}
return &u, nil
}
// -------------------------------------------------------
// 🔁 CREATE FROM LEGACY (dfusr → mk_dfusr)
// - id = dfusr.id ✅
// - role / v3 YOK
// -------------------------------------------------------
// -------------------------------------------------------
// 🔁 CREATE FROM LEGACY (dfusr → mk_dfusr) FULL MIGRATION
// -------------------------------------------------------
func (r *MkUserRepository) CreateFromLegacy(
legacy *models.User,
passwordHash string,
) (*models.MkUser, error) {
var u models.MkUser
err := r.DB.QueryRow(`
INSERT INTO mk_dfusr (
id,
username,
email,
full_name,
mobile,
address,
is_active,
password_hash,
force_password_change,
created_at,
updated_at
)
VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,true,now(),now()
)
ON CONFLICT (id)
DO UPDATE SET
email = EXCLUDED.email,
full_name = EXCLUDED.full_name,
mobile = EXCLUDED.mobile,
address = EXCLUDED.address,
password_hash = EXCLUDED.password_hash,
force_password_change= true,
updated_at = now()
RETURNING
id,
username,
COALESCE(email,''),
is_active,
COALESCE(password_hash,''),
force_password_change,
password_updated_at,
created_at,
updated_at,
last_login_at
`,
legacy.ID,
legacy.Username,
legacy.Email,
legacy.FullName,
legacy.Mobile,
legacy.Address,
legacy.IsActive,
passwordHash,
).Scan(
&u.ID,
&u.Username,
&u.Email,
&u.IsActive,
&u.PasswordHash,
&u.ForcePasswordChange,
&u.PasswordUpdatedAt,
&u.CreatedAt,
&u.UpdatedAt,
&u.LastLoginAt,
)
if err != nil {
return nil, err
}
return &u, nil
}
// -------------------------------------------------------
// CREATE NEW USER (NON-LEGACY)
// - id = sequence (>=1000)
// -------------------------------------------------------
func (r *MkUserRepository) CreateNewUser(
username string,
email string,
isActive bool,
) (*models.MkUser, error) {
var u models.MkUser
err := r.DB.QueryRow(`
INSERT INTO mk_dfusr (
username,
email,
is_active,
force_password_change,
created_at,
updated_at
)
VALUES (
$1,$2,$3,true,now(),now()
)
RETURNING
id,
username,
COALESCE(email,'') AS email,
is_active,
COALESCE(password_hash,'') AS password_hash,
force_password_change,
password_updated_at,
created_at,
updated_at,
last_login_at
`,
strings.TrimSpace(username),
strings.TrimSpace(email),
isActive,
).Scan(
&u.ID,
&u.Username,
&u.Email,
&u.IsActive,
&u.PasswordHash,
&u.ForcePasswordChange,
&u.PasswordUpdatedAt,
&u.CreatedAt,
&u.UpdatedAt,
&u.LastLoginAt,
)
if err != nil {
return nil, err
}
return &u, nil
}
// -------------------------------------------------------
// 🕒 TOUCH LAST LOGIN
// -------------------------------------------------------
func (r *MkUserRepository) TouchLastLogin(userID int64) error {
_, err := r.DB.Exec(`
UPDATE mk_dfusr
SET last_login_at = $1,
updated_at = $1
WHERE id = $2
`, time.Now(), userID)
return err
}
// -------------------------------------------------------
// 🔐 UPDATE PASSWORD
// -------------------------------------------------------
func (r *MkUserRepository) UpdatePassword(userID int64, newHash string) error {
_, err := r.DB.Exec(`
UPDATE mk_dfusr
SET
password_hash = $1,
force_password_change = false,
password_updated_at = NOW(),
updated_at = NOW()
WHERE id = $2
`, newHash, userID)
return err
}