package redis import ( "context" "encoding/json" "fmt" "time" "wm-backend/global" "github.com/rs/zerolog/log" ) const ( userRBACPrefix = "user:rbac:" defaultTTL = 60 * time.Minute ) // RBACCachedData represents the cached roles and permissions for a user. type RBACCachedData struct { Roles []RoleCacheItem `json:"roles"` Permissions []string `json:"permissions"` } // RoleCacheItem represents a cached role item. type RoleCacheItem struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` } func buildKey(userID string) string { return fmt.Sprintf("%s%s", userRBACPrefix, userID) } // CacheUserPermissions stores the user's roles and permissions in Redis with TTL. func CacheUserPermissions(ctx context.Context, userID string, data RBACCachedData, ttl time.Duration) error { jsonData, err := json.Marshal(data) if err != nil { log.Error().Err(err).Str("userID", userID).Msg("Failed to marshal RBAC data for caching") return err } if err := global.Cache.Set(ctx, buildKey(userID), jsonData, ttl).Err(); err != nil { log.Error().Err(err).Str("userID", userID).Msg("Failed to cache user permissions in Redis") return err } return nil } // GetCachedUserPermissions retrieves the cached RBAC data from Redis. // Returns (nil, false) if not found or on error (graceful fallback). func GetCachedUserPermissions(ctx context.Context, userID string) (*RBACCachedData, bool) { val, err := global.Cache.Get(ctx, buildKey(userID)).Result() if err != nil { // Key doesn't exist or Redis error; silently fallback to DB return nil, false } var data RBACCachedData if err := json.Unmarshal([]byte(val), &data); err != nil { log.Error().Err(err).Str("userID", userID).Msg("Failed to unmarshal cached RBAC data") return nil, false } return &data, true } // RefreshTTL resets the TTL on a cached RBAC entry when a cache hit occurs. func RefreshTTL(ctx context.Context, userID string, ttl time.Duration) { if err := global.Cache.Expire(ctx, buildKey(userID), ttl).Err(); err != nil { log.Error().Err(err).Str("userID", userID).Msg("Failed to refresh TTL for RBAC cache") } } // DeleteUserPermissionsCache removes the cached RBAC data for a user (for cache invalidation). func DeleteUserPermissionsCache(ctx context.Context, userID string) { if err := global.Cache.Del(ctx, buildKey(userID)).Err(); err != nil { log.Error().Err(err).Str("userID", userID).Msg("Failed to delete RBAC cache") } }