init push
This commit is contained in:
93
internal/transport/http/handlers/audit_fields.go
Normal file
93
internal/transport/http/handlers/audit_fields.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"wucher/internal/shared/pkg/userctx"
|
||||
"wucher/internal/shared/pkg/uuidv7"
|
||||
responsedto "wucher/internal/transport/http/dto/response"
|
||||
)
|
||||
|
||||
func userRef(id []byte, name string) *responsedto.UserRef {
|
||||
trimmed := strings.TrimSpace(name)
|
||||
if len(id) == 0 && trimmed == "" {
|
||||
return nil
|
||||
}
|
||||
if trimmed == "" && len(id) > 0 {
|
||||
trimmed = userctx.GetDisplayName(context.TODO(), id)
|
||||
}
|
||||
return &responsedto.UserRef{
|
||||
UUID: idString(id),
|
||||
Name: trimmed,
|
||||
}
|
||||
}
|
||||
|
||||
// updatedAuditOrCreated returns the "last modified" timestamp (RFC3339) and actor for an
|
||||
// audited row, falling back to the creation timestamp/actor when the row was never
|
||||
// updated after creation (updated_by unset — e.g. seed/legacy rows). This guarantees an
|
||||
// updated_at/updated_by is always presentable instead of silently omitted.
|
||||
func updatedAuditOrCreated(updatedAt, createdAt time.Time, updatedBy []byte, updatedByName string, createdBy []byte, createdByName string) (string, *responsedto.UserRef) {
|
||||
if len(updatedBy) == 0 {
|
||||
updatedBy, updatedByName = createdBy, createdByName
|
||||
}
|
||||
if updatedAt.IsZero() {
|
||||
updatedAt = createdAt
|
||||
}
|
||||
at := ""
|
||||
if !updatedAt.IsZero() {
|
||||
at = updatedAt.UTC().Format(time.RFC3339)
|
||||
}
|
||||
return at, userRef(updatedBy, updatedByName)
|
||||
}
|
||||
|
||||
func actorUserID(c *fiber.Ctx) []byte {
|
||||
raw := c.Locals("user_id")
|
||||
userID, ok := raw.([]byte)
|
||||
if !ok || len(userID) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Return a copy to avoid accidental mutation of local context values.
|
||||
return append([]byte(nil), userID...)
|
||||
}
|
||||
|
||||
// uuidStringOrEmpty resolves a user ID to their last name using the global userctx getter
|
||||
// if set; otherwise falls back to the UUID string representation.
|
||||
func uuidStringOrEmpty(id []byte) string {
|
||||
if len(id) == 0 {
|
||||
return ""
|
||||
}
|
||||
if name := userctx.GetDisplayName(context.TODO(), id); name != "" {
|
||||
return name
|
||||
}
|
||||
// Fallback to UUID string when no getter is available or user not found.
|
||||
val, err := uuidv7.BytesToString(id)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// idString converts a resource ID byte slice to a UUID string.
|
||||
// Unlike uuidStringOrEmpty, this does not attempt user name resolution.
|
||||
// Use this for primary keys and resource IDs, not for audit/user reference fields.
|
||||
func idString(id []byte) string {
|
||||
if len(id) == 0 {
|
||||
return ""
|
||||
}
|
||||
val, err := uuidv7.BytesToString(id)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func timeStringOrEmpty(t *time.Time) string {
|
||||
if t == nil || t.IsZero() {
|
||||
return ""
|
||||
}
|
||||
return t.UTC().Format(time.RFC3339)
|
||||
}
|
||||
Reference in New Issue
Block a user