update: shared,packages,lua (2 files)

This commit is contained in:
Richard Ward
2025-12-30 14:40:43 +00:00
parent ea389f1b20
commit 0541368948
2 changed files with 337 additions and 0 deletions

View File

@@ -0,0 +1,164 @@
---@class PackageConfig
---@field enabled boolean Whether the package is enabled
---@field required_level number Minimum permission level required to access
---@field features table<string, boolean> Feature flags for the package
---@field database_enabled boolean Whether database access is enabled
---@field components table<string, ComponentConfig> Component-specific configuration
---@class ComponentConfig
---@field enabled boolean Whether the component is enabled
---@field required_level number|nil Minimum permission level (inherits from package if nil)
---@field props table|nil Default props for the component
---@class FeatureFlag
---@field name string Feature flag name
---@field enabled boolean Whether the feature is enabled
---@field description string Feature description
---@field required_level number Minimum permission level to toggle
---@class DatabaseConfig
---@field enabled boolean Whether database is enabled
---@field connection string|nil Database connection string
---@field pool_size number|nil Connection pool size
---@field timeout number|nil Query timeout in milliseconds
local M = {}
---Create default package configuration
---@param package_name string The package name
---@param required_level number|nil Minimum permission level (default: 1 - USER)
---@return PackageConfig config Default package configuration
function M.create_package_config(package_name, required_level)
return {
enabled = true,
required_level = required_level or 1,
features = {},
database_enabled = false,
components = {}
}
end
---Check if a package is enabled
---@param config PackageConfig The package configuration
---@return boolean enabled True if package is enabled
function M.is_package_enabled(config)
return config.enabled == true
end
---Check if a component is enabled
---@param package_config PackageConfig The package configuration
---@param component_id string The component ID
---@return boolean enabled True if component is enabled
function M.is_component_enabled(package_config, component_id)
if not M.is_package_enabled(package_config) then
return false
end
local component_config = package_config.components[component_id]
if not component_config then
return true -- Components enabled by default if no specific config
end
return component_config.enabled ~= false
end
---Get required permission level for a component
---@param package_config PackageConfig The package configuration
---@param component_id string The component ID
---@return number required_level The required permission level
function M.get_component_level(package_config, component_id)
local component_config = package_config.components[component_id]
if component_config and component_config.required_level then
return component_config.required_level
end
return package_config.required_level
end
---Check if a feature is enabled
---@param config PackageConfig The package configuration
---@param feature_name string The feature name
---@return boolean enabled True if feature is enabled
function M.is_feature_enabled(config, feature_name)
return config.features[feature_name] == true
end
---Enable or disable a feature
---@param config PackageConfig The package configuration
---@param feature_name string The feature name
---@param enabled boolean Whether to enable the feature
---@return PackageConfig config Updated configuration
function M.set_feature(config, feature_name, enabled)
config.features[feature_name] = enabled
return config
end
---Enable or disable database access
---@param config PackageConfig The package configuration
---@param enabled boolean Whether to enable database access
---@return PackageConfig config Updated configuration
function M.set_database_enabled(config, enabled)
config.database_enabled = enabled
return config
end
---Merge two configurations (deep merge)
---@param base PackageConfig Base configuration
---@param override PackageConfig Override configuration
---@return PackageConfig merged Merged configuration
function M.merge_config(base, override)
local merged = {}
-- Copy base
for k, v in pairs(base) do
merged[k] = v
end
-- Override values
for k, v in pairs(override) do
if type(v) == "table" and type(merged[k]) == "table" then
merged[k] = M.merge_config(merged[k], v)
else
merged[k] = v
end
end
return merged
end
---Validate package configuration
---@param config table The configuration to validate
---@return boolean valid True if configuration is valid
---@return string|nil error Error message if invalid
function M.validate_config(config)
if type(config) ~= "table" then
return false, "Configuration must be a table"
end
if type(config.enabled) ~= "boolean" then
return false, "config.enabled must be a boolean"
end
if type(config.required_level) ~= "number" then
return false, "config.required_level must be a number"
end
if config.required_level < 0 or config.required_level > 5 then
return false, "config.required_level must be between 0 and 5"
end
if type(config.features) ~= "table" then
return false, "config.features must be a table"
end
if type(config.database_enabled) ~= "boolean" then
return false, "config.database_enabled must be a boolean"
end
if type(config.components) ~= "table" then
return false, "config.components must be a table"
end
return true, nil
end
return M

View File

@@ -0,0 +1,173 @@
---@class PermissionLevel
---@field PUBLIC number 0 - Public (no login required)
---@field USER number 1 - Logged in users
---@field MODERATOR number 2 - Moderators
---@field ADMIN number 3 - Administrators
---@field GOD number 4 - God mode (full access)
---@field SUPERGOD number 5 - Supergod (system level)
---@class PermissionLevels
---@field PUBLIC number
---@field USER number
---@field MODERATOR number
---@field ADMIN number
---@field GOD number
---@field SUPERGOD number
---@type PermissionLevels
local LEVELS = {
PUBLIC = 0,
USER = 1,
MODERATOR = 2,
ADMIN = 3,
GOD = 4,
SUPERGOD = 5
}
---@class PermissionContext
---@field user_id string|nil The user's ID
---@field username string|nil The user's username
---@field level number The user's permission level
---@field tenant_id string|nil The tenant ID
---@field features table<string, boolean>|nil Enabled features
---@class PermissionCheck
---@field required_level number Minimum permission level required
---@field feature string|nil Feature flag that must be enabled
---@field tenant_specific boolean|nil Whether permission is tenant-specific
---@class PermissionResult
---@field allowed boolean Whether the action is allowed
---@field reason string|nil Reason for denial
local M = {}
---Check if a user has the required permission level
---@param ctx PermissionContext The user's permission context
---@param required_level number The required permission level
---@return boolean allowed True if the user has sufficient permissions
function M.has_level(ctx, required_level)
return ctx.level >= required_level
end
---Check if a user can access a feature
---@param ctx PermissionContext The user's permission context
---@param check PermissionCheck The permission check configuration
---@return PermissionResult result The permission check result
function M.can_access(ctx, check)
-- Check permission level
if ctx.level < check.required_level then
return {
allowed = false,
reason = string.format(
"Requires level %d (%s), user has level %d",
check.required_level,
M.level_name(check.required_level),
ctx.level
)
}
end
-- Check feature flag if specified
if check.feature and ctx.features then
if not ctx.features[check.feature] then
return {
allowed = false,
reason = string.format("Feature '%s' is not enabled", check.feature)
}
end
end
-- Check tenant-specific permissions
if check.tenant_specific and not ctx.tenant_id then
return {
allowed = false,
reason = "Tenant-specific operation requires valid tenant_id"
}
end
return { allowed = true }
end
---Get the name of a permission level
---@param level number The permission level
---@return string name The level name
function M.level_name(level)
local names = {
[0] = "PUBLIC",
[1] = "USER",
[2] = "MODERATOR",
[3] = "ADMIN",
[4] = "GOD",
[5] = "SUPERGOD"
}
return names[level] or "UNKNOWN"
end
---Create a permission context for an anonymous user
---@return PermissionContext ctx Anonymous permission context
function M.anonymous()
return {
level = LEVELS.PUBLIC,
features = {}
}
end
---Create a permission context for a logged-in user
---@param user_id string The user's ID
---@param username string The user's username
---@param level number The user's permission level
---@param tenant_id string|nil The tenant ID
---@param features table<string, boolean>|nil Enabled features
---@return PermissionContext ctx User permission context
function M.user_context(user_id, username, level, tenant_id, features)
return {
user_id = user_id,
username = username,
level = level,
tenant_id = tenant_id,
features = features or {}
}
end
---Check if user is admin or higher
---@param ctx PermissionContext The user's permission context
---@return boolean is_admin True if user is admin or higher
function M.is_admin(ctx)
return ctx.level >= LEVELS.ADMIN
end
---Check if user is moderator or higher
---@param ctx PermissionContext The user's permission context
---@return boolean is_moderator True if user is moderator or higher
function M.is_moderator(ctx)
return ctx.level >= LEVELS.MODERATOR
end
---Check if user is god mode or higher
---@param ctx PermissionContext The user's permission context
---@return boolean is_god True if user is god mode or higher
function M.is_god(ctx)
return ctx.level >= LEVELS.GOD
end
---Filter a list based on permission requirements
---@param items table[] List of items to filter
---@param ctx PermissionContext User permission context
---@param get_required_level fun(item: table): number Function to get required level for item
---@return table[] filtered Filtered list of items user can access
function M.filter_by_permission(items, ctx, get_required_level)
local filtered = {}
for _, item in ipairs(items) do
local required = get_required_level(item)
if M.has_level(ctx, required) then
table.insert(filtered, item)
end
end
return filtered
end
-- Export permission levels
M.LEVELS = LEVELS
return M