ilk
This commit is contained in:
286
svc/repository/activitylog_repository.go
Normal file
286
svc/repository/activitylog_repository.go
Normal file
@@ -0,0 +1,286 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ActivityLogRow struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
RequestStartedAt *time.Time `json:"request_started_at,omitempty"`
|
||||
RequestFinishedAt *time.Time `json:"request_finished_at,omitempty"`
|
||||
DurationMs *int `json:"duration_ms,omitempty"`
|
||||
HttpStatus *int `json:"http_status,omitempty"`
|
||||
|
||||
Username string `json:"username"`
|
||||
RoleCode string `json:"role_code"`
|
||||
|
||||
ActionCategory string `json:"action_category"`
|
||||
ActionType string `json:"action_type"`
|
||||
ActionTarget string `json:"action_target"`
|
||||
Description string `json:"description"`
|
||||
|
||||
// ✅ TARGET USER
|
||||
TargetDfUsrID int64 `json:"target_dfusr_id"`
|
||||
TargetUsername string `json:"target_username"`
|
||||
|
||||
// ✅ DIFF
|
||||
ChangeBefore string `json:"change_before"`
|
||||
ChangeAfter string `json:"change_after"`
|
||||
|
||||
IpAddress string `json:"ip_address"`
|
||||
IsSuccess bool `json:"is_success"`
|
||||
ErrorMsg string `json:"error_message"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
SessionID string `json:"session_id"`
|
||||
|
||||
// audit ids
|
||||
UserUUID string `json:"user_id"`
|
||||
DfUsrID int64 `json:"dfusr_id"`
|
||||
|
||||
Email string `json:"email"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type ActivityLogQuery struct {
|
||||
Username string
|
||||
RoleCode string
|
||||
ActionCategory string
|
||||
ActionType string
|
||||
ActionTarget string
|
||||
Success *bool
|
||||
|
||||
StatusMin *int
|
||||
StatusMax *int
|
||||
|
||||
DateFrom *time.Time
|
||||
DateTo *time.Time
|
||||
|
||||
Page int
|
||||
Limit int
|
||||
}
|
||||
|
||||
type ActivityLogResult struct {
|
||||
Total int64 `json:"total"`
|
||||
Items []ActivityLogRow `json:"items"`
|
||||
}
|
||||
|
||||
func ListActivityLogs(
|
||||
ctx context.Context,
|
||||
db *sql.DB,
|
||||
q ActivityLogQuery,
|
||||
) (ActivityLogResult, error) {
|
||||
|
||||
// ---------- defaults ----------
|
||||
if q.Page <= 0 {
|
||||
q.Page = 1
|
||||
}
|
||||
// limit <=0 → unlimited
|
||||
if q.Limit < 0 {
|
||||
q.Limit = 50
|
||||
}
|
||||
if q.Limit > 200 {
|
||||
q.Limit = 200
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if q.Limit > 0 {
|
||||
offset = (q.Page - 1) * q.Limit
|
||||
}
|
||||
|
||||
where := []string{}
|
||||
args := []interface{}{}
|
||||
|
||||
add := func(cond string, val interface{}) {
|
||||
where = append(where, cond)
|
||||
args = append(args, val)
|
||||
}
|
||||
|
||||
// ---------- filters ----------
|
||||
if strings.TrimSpace(q.Username) != "" {
|
||||
add(fmt.Sprintf("l.username ILIKE $%d", len(args)+1),
|
||||
"%"+strings.TrimSpace(q.Username)+"%")
|
||||
}
|
||||
if strings.TrimSpace(q.RoleCode) != "" {
|
||||
add(fmt.Sprintf("r.code = $%d", len(args)+1),
|
||||
strings.TrimSpace(q.RoleCode))
|
||||
}
|
||||
if strings.TrimSpace(q.ActionCategory) != "" {
|
||||
add(fmt.Sprintf("l.action_category = $%d", len(args)+1),
|
||||
strings.TrimSpace(q.ActionCategory))
|
||||
}
|
||||
if strings.TrimSpace(q.ActionType) != "" {
|
||||
add(fmt.Sprintf("l.action_type = $%d", len(args)+1),
|
||||
strings.TrimSpace(q.ActionType))
|
||||
}
|
||||
if strings.TrimSpace(q.ActionTarget) != "" {
|
||||
add(fmt.Sprintf("l.action_target ILIKE $%d", len(args)+1),
|
||||
"%"+strings.TrimSpace(q.ActionTarget)+"%")
|
||||
}
|
||||
if q.Success != nil {
|
||||
add(fmt.Sprintf("l.is_success = $%d", len(args)+1), *q.Success)
|
||||
}
|
||||
if q.StatusMin != nil {
|
||||
add(fmt.Sprintf("l.http_status >= $%d", len(args)+1), *q.StatusMin)
|
||||
}
|
||||
if q.StatusMax != nil {
|
||||
add(fmt.Sprintf("l.http_status <= $%d", len(args)+1), *q.StatusMax)
|
||||
}
|
||||
if q.DateFrom != nil {
|
||||
add(fmt.Sprintf("l.created_at >= $%d", len(args)+1), *q.DateFrom)
|
||||
}
|
||||
if q.DateTo != nil {
|
||||
add(fmt.Sprintf("l.created_at < $%d", len(args)+1),
|
||||
q.DateTo.Add(24*time.Hour))
|
||||
}
|
||||
|
||||
whereSQL := ""
|
||||
if len(where) > 0 {
|
||||
whereSQL = "WHERE " + strings.Join(where, " AND ")
|
||||
}
|
||||
|
||||
// ---------- COUNT ----------
|
||||
countSQL := fmt.Sprintf(`
|
||||
SELECT count(*)
|
||||
FROM mk_user_activity_log l
|
||||
LEFT JOIN mk_dfusr u ON u.id = l.dfusr_id
|
||||
LEFT JOIN dfrole_usr ru ON ru.dfusr_id = u.id
|
||||
LEFT JOIN dfrole r ON r.id = ru.dfrole_id
|
||||
%s
|
||||
`, whereSQL)
|
||||
|
||||
var total int64
|
||||
if err := db.QueryRowContext(ctx, countSQL, args...).Scan(&total); err != nil {
|
||||
return ActivityLogResult{}, err
|
||||
}
|
||||
|
||||
// ---------- LIST ----------
|
||||
listArgs := append([]interface{}{}, args...)
|
||||
|
||||
listSQL := fmt.Sprintf(`
|
||||
SELECT
|
||||
l.created_at,
|
||||
l.request_started_at,
|
||||
l.request_finished_at,
|
||||
l.duration_ms,
|
||||
l.http_status,
|
||||
|
||||
COALESCE(u.username, l.username, '') AS username,
|
||||
COALESCE(r.code,''),
|
||||
|
||||
COALESCE(l.action_category,''),
|
||||
COALESCE(l.action_type,''),
|
||||
COALESCE(l.action_target,''),
|
||||
COALESCE(l.description,''),
|
||||
|
||||
COALESCE(l.target_dfusr_id, 0),
|
||||
COALESCE(l.target_username, ''),
|
||||
COALESCE(l.change_before::text, ''),
|
||||
COALESCE(l.change_after::text, ''),
|
||||
|
||||
COALESCE(l.ip_address,''),
|
||||
COALESCE(l.is_success,false),
|
||||
COALESCE(l.error_message,''),
|
||||
COALESCE(l.user_agent,''),
|
||||
COALESCE(l.session_id,''),
|
||||
|
||||
COALESCE(l.user_id::text,''),
|
||||
COALESCE(l.dfusr_id,0),
|
||||
|
||||
COALESCE(u.email,''),
|
||||
COALESCE(u.is_active,false)
|
||||
|
||||
FROM mk_user_activity_log l
|
||||
LEFT JOIN mk_dfusr u ON u.id = l.dfusr_id
|
||||
LEFT JOIN dfrole_usr ru ON ru.dfusr_id = u.id
|
||||
LEFT JOIN dfrole r ON r.id = ru.dfrole_id
|
||||
%s
|
||||
ORDER BY l.created_at DESC
|
||||
`, whereSQL)
|
||||
// LIMIT sadece istenirse
|
||||
if q.Limit > 0 {
|
||||
|
||||
listSQL += fmt.Sprintf(
|
||||
" LIMIT $%d OFFSET $%d",
|
||||
len(listArgs)+1,
|
||||
len(listArgs)+2,
|
||||
)
|
||||
|
||||
listArgs = append(listArgs, q.Limit, offset)
|
||||
}
|
||||
|
||||
rows, err := db.QueryContext(ctx, listSQL, listArgs...)
|
||||
if err != nil {
|
||||
return ActivityLogResult{}, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
items := []ActivityLogRow{}
|
||||
|
||||
for rows.Next() {
|
||||
var it ActivityLogRow
|
||||
var started, finished sql.NullTime
|
||||
var dur, status sql.NullInt64
|
||||
|
||||
if err := rows.Scan(
|
||||
&it.CreatedAt,
|
||||
&started,
|
||||
&finished,
|
||||
&dur,
|
||||
&status,
|
||||
|
||||
&it.Username,
|
||||
&it.RoleCode,
|
||||
|
||||
&it.ActionCategory,
|
||||
&it.ActionType,
|
||||
&it.ActionTarget,
|
||||
&it.Description,
|
||||
|
||||
// ✅ NEW
|
||||
&it.TargetDfUsrID,
|
||||
&it.TargetUsername,
|
||||
&it.ChangeBefore,
|
||||
&it.ChangeAfter,
|
||||
|
||||
&it.IpAddress,
|
||||
&it.IsSuccess,
|
||||
&it.ErrorMsg,
|
||||
&it.UserAgent,
|
||||
&it.SessionID,
|
||||
|
||||
&it.UserUUID,
|
||||
&it.DfUsrID,
|
||||
|
||||
&it.Email,
|
||||
&it.IsActive,
|
||||
); err != nil {
|
||||
return ActivityLogResult{}, err
|
||||
}
|
||||
|
||||
if started.Valid {
|
||||
it.RequestStartedAt = &started.Time
|
||||
}
|
||||
if finished.Valid {
|
||||
it.RequestFinishedAt = &finished.Time
|
||||
}
|
||||
if dur.Valid {
|
||||
v := int(dur.Int64)
|
||||
it.DurationMs = &v
|
||||
}
|
||||
if status.Valid {
|
||||
v := int(status.Int64)
|
||||
it.HttpStatus = &v
|
||||
}
|
||||
|
||||
items = append(items, it)
|
||||
}
|
||||
|
||||
return ActivityLogResult{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user