Files
ROC/src/service/cms_api.e
Jocelyn Fiat ebc5924c01 Made CMS_MODULE.name deferred, and implemented by constant so that it can be use as static call.
Copied site resources on related module source folder.
Renamed "login" module as "auth" module, and updated related locations and files.
2015-06-29 16:24:17 +02:00

479 lines
13 KiB
Plaintext

note
description: "API for a CMS"
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
class
CMS_API
inherit
ANY
REFACTORING_HELPER
CMS_ENCODERS
create
make
feature {NONE} -- Initialize
make (a_setup: CMS_SETUP)
-- Create the API service with a setup `a_setup'
do
setup := a_setup
create error_handler.make
create {CMS_ENV_LOGGER} logger.make
initialize
ensure
setup_set: setup = a_setup
error_handler_set: not error_handler.has_error
end
initialize
-- Initialize the persitent layer.
local
l_module: CMS_MODULE
do
if attached setup.storage (error_handler) as l_storage then
storage := l_storage
else
create {CMS_STORAGE_NULL} storage
end
storage.set_api (Current)
across
setup.enabled_modules as ic
loop
l_module := ic.item
-- FIXME: should we initialize first, and then install
-- or the reverse, or merge installation and initialization
-- and leave the responsability to the module to know
-- if this is installed or not...
if not l_module.is_installed (Current) then
l_module.install (Current)
end
l_module.initialize (Current)
end
end
feature -- Access
setup: CMS_SETUP
-- CMS setup.
logger: CMS_LOGGER
-- Logger
storage: CMS_STORAGE
-- Default persistence storage.
feature -- Formats
formats: CMS_FORMATS
-- Available content formats.
once
create Result
end
format (a_format_name: detachable READABLE_STRING_GENERAL): detachable CONTENT_FORMAT
-- Content format name `a_format_name' if any.
do
Result := formats.item (a_format_name)
end
feature -- Status Report
has_error: BOOLEAN
-- Has error?
do
Result := error_handler.has_error
end
string_representation_of_errors: STRING_32
-- String representation of all error(s).
do
Result := error_handler.as_string_representation
end
feature -- Logging
log (a_category: READABLE_STRING_8; a_message: READABLE_STRING_8; a_level: INTEGER; a_link: detachable CMS_LINK)
local
l_log: CMS_LOG
m: STRING
do
create l_log.make (a_category, a_message, a_level, Void)
if a_link /= Void then
l_log.set_link (a_link)
end
storage.save_log (l_log)
create m.make_from_string ("[" + a_category + "] ")
m.append (a_message)
if a_link /= Void then
m.append (" [" + url_encoded (a_link.title) + "]("+ a_link.location +")")
end
inspect a_level
when {CMS_LOG}.level_emergency then
logger.put_alert (m, Void)
when {CMS_LOG}.level_alert then
logger.put_alert (m, Void)
when {CMS_LOG}.level_critical then
logger.put_critical (m, Void)
when {CMS_LOG}.level_error then
logger.put_error (m, Void)
when {CMS_LOG}.level_warning then
logger.put_warning (m, Void)
when {CMS_LOG}.level_notice then
logger.put_information (m, Void)
when {CMS_LOG}.level_info then
logger.put_information (m, Void)
when {CMS_LOG}.level_debug then
logger.put_debug (m, Void)
else
logger.put_debug (m, Void)
end
end
feature -- Permissions system
user_has_permission (a_user: detachable CMS_USER; a_permission: detachable READABLE_STRING_GENERAL): BOOLEAN
-- Anonymous or user `a_user' has permission for `a_permission'?
--| `a_permission' could be for instance "create page".
do
Result := user_api.user_has_permission (a_user, a_permission)
end
feature -- Query: module
module (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE
-- Enabled module typed `a_type', if any.
--| usage: if attached module ({FOO_MODULE}) as mod then ...
local
l_type: TYPE [detachable CMS_MODULE]
do
across
setup.modules as ic
until
Result /= Void
loop
Result := ic.item
if not Result.is_enabled then
Result := Void
else
l_type := Result.generating_type
if a_type ~ l_type then
-- Found
elseif
attached a_type.attempt (Result) and then attached l_type.generating_type.attempt (a_type)
then
-- Found
else
Result := Void
end
end
end
ensure
Result /= Void implies (Result.is_enabled) -- and a_type.is_conforming_to (Result.generating_type))
end
module_api (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE_API
-- Enabled module API associated with module typed `a_type'.
do
if attached module (a_type) as mod then
if mod.is_enabled then
if not mod.is_initialized then
mod.initialize (Current)
end
Result := mod.module_api
end
end
end
module_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_MODULE
-- Enabled module named `a_name', if any.
do
across
setup.modules as ic
until
Result /= Void
loop
Result := ic.item
if
not Result.is_enabled
or else not Result.name.is_case_insensitive_equal_general (a_name)
then
Result := Void
end
end
ensure
Result /= Void implies (Result.is_enabled and Result.name.is_case_insensitive_equal_general (a_name))
end
module_api_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_MODULE_API
-- Enabled module API associated with module named `a_name'.
do
if attached module_by_name (a_name) as mod then
Result := mod.module_api
end
end
feature -- Query: API
user_api: CMS_USER_API
local
l_api: like internal_user_api
do
l_api := internal_user_api
if l_api = Void then
create l_api.make (Current)
internal_user_api := l_api
end
Result := l_api
end
feature -- Path aliases
is_valid_path_alias (a_alias: READABLE_STRING_8): BOOLEAN
do
Result := a_alias.is_empty or else not a_alias.starts_with_general ("/")
end
set_path_alias (a_source, a_alias: READABLE_STRING_8; a_keep_previous: BOOLEAN)
-- Set `a_alias' as alias of `a_source',
-- and eventually unset previous alias if any.
require
valid_alias: is_valid_path_alias (a_alias)
local
l_continue: BOOLEAN
do
if attached storage.path_alias (a_source) as l_existing_alias then
if a_alias.same_string (l_existing_alias) then
-- Already aliased as expected
else
-- New alias
if a_keep_previous then
l_continue := True
else
storage.replace_path_alias (a_source, l_existing_alias, a_alias)
end
end
elseif a_alias.is_whitespace then
-- Ignore
elseif a_source.same_string (a_alias) then
-- No need for alias
else
l_continue := True
end
if l_continue then
storage.set_path_alias (a_source, a_alias)
end
end
unset_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
do
storage.unset_path_alias (a_source, a_alias)
end
path_alias (a_source: READABLE_STRING_8): READABLE_STRING_8
-- Path alias associated with `a_source' or the source itself.
do
Result := a_source
if attached storage.path_alias (Result) as l_path then
Result := "/" + l_path
end
end
source_of_path_alias (a_alias: READABLE_STRING_8): READABLE_STRING_8
-- Resolved path for alias `a_alias'.
--| the CMS supports aliases for path, and then this function simply returns
--| the effective target path/url for this `a_alias'.
--| For instance: articles/2015/may/this-is-an-article can be an alias to node/123
--| This function will return "node/123".
--| If the alias is bad (i.e does not alias real path), then this function
--| returns the alias itself.
do
Result := a_alias
if attached storage.source_of_path_alias (Result) as l_path then
Result := l_path
end
end
feature -- Element Change: Error
reset_error
-- Reset error handler.
do
error_handler.reset
end
feature {NONE}-- Implemenation
error_handler: ERROR_HANDLER
-- Error handler.
internal_user_api: detachable like user_api
-- Cached value for `user_api'.
feature -- Environment/ theme
site_location: PATH
-- CMS site location.
do
Result := setup.site_location
end
theme_location: PATH
-- Active theme location.
do
Result := setup.theme_location
end
theme_assets_location: PATH
-- assets (js, css, images, etc).
do
debug ("refactor_fixme")
fixme ("Check if we really need it")
end
-- Check how to get this path from the CMS_THEME information.
Result := theme_location.extended ("assets")
end
feature -- Environment/ module
module_configuration_by_name (a_module_name: READABLE_STRING_GENERAL; a_name: detachable READABLE_STRING_GENERAL): detachable CONFIG_READER
-- Configuration reader for `a_module', and if `a_name' is set, using name `a_name'.
local
p, l_path: detachable PATH
l_name: READABLE_STRING_GENERAL
ut: FILE_UTILITIES
do
if a_name = Void then
l_name := a_module_name
else
l_name := a_name
end
p := setup.environment.config_path
p := module_location_by_name (a_module_name).extended ("config").extended (l_name)
l_path := p.appended_with_extension ("json")
if ut.file_path_exists (l_path) then
create {JSON_CONFIG} Result.make_from_file (l_path)
else
l_path := p.appended_with_extension ("ini")
if ut.file_path_exists (l_path) then
create {INI_CONFIG} Result.make_from_file (l_path)
end
end
if Result = Void and a_name /= Void then
-- Use sub config from default?
if attached {CONFIG_READER} module_configuration_by_name (a_module_name, Void) as cfg then
Result := cfg.sub_config (a_name)
else
-- Maybe try to use the global cms.ini ?
end
end
end
modules_location: PATH
-- Directory containing cms modules.
do
Result := setup.modules_location
end
module_location (a_module: CMS_MODULE): PATH
-- Location associated with `a_module'.
do
Result := module_location_by_name (a_module.name)
end
module_location_by_name (a_module_name: READABLE_STRING_GENERAL): PATH
-- Location associated with `a_module_name'.
do
Result := modules_location.extended (a_module_name)
end
module_resource_location (a_module: CMS_MODULE; a_resource: PATH): PATH
-- Location of resource `a_resource' for `a_module'.
do
--| site/modules/$modname/$a_name.json
Result := module_resource_location_by_name (a_module.name, a_resource)
end
module_resource_location_by_name (a_module_name: READABLE_STRING_GENERAL; a_resource: PATH): PATH
-- Location of resource `a_resource' for `a_module'.
do
--| site/modules/$modname/$a_name.json
Result := module_location_by_name (a_module_name).extended_path (a_resource)
end
feature -- Environment/ modules and theme
module_theme_resource_location (a_module: CMS_MODULE; a_resource: PATH): detachable PATH
-- Theme resource location of `a_resource' for module `a_module', if exists.
-- By default, located under the module location folder, but could be overriden
-- from files located under modules subfolder of active `theme_location'.
--| First search in themes/$theme/modules/$a_module.name/$a_resource,
--| and if not found then search in
--| modules/$a_module_name/$a_resource.
local
ut: FILE_UTILITIES
do
-- Check first in selected theme folder.
Result := module_theme_location (a_module).extended_path (a_resource)
if not ut.file_path_exists (Result) then
-- And if not found, look into site/modules/$a_module.name/.... folders.
Result := module_resource_location (a_module, a_resource)
if not ut.file_path_exists (Result) then
Result := Void
end
end
end
module_theme_resource_location_by_name (a_module_name: READABLE_STRING_GENERAL; a_resource: PATH): detachable PATH
-- Theme resource location of `a_resource' for module named `a_module_name', if exists.
-- By default, located under the module location folder, but could be overriden
-- from files located under modules subfolder of active `theme_location'.
--| First search in themes/$theme/modules/$a_module.name/$a_resource,
--| and if not found then search in
--| modules/$a_module_name/$a_resource.
local
ut: FILE_UTILITIES
do
-- Check first in selected theme folder.
Result := module_theme_location_by_name (a_module_name).extended_path (a_resource)
if not ut.file_path_exists (Result) then
-- And if not found, look into site/modules/$a_module.name/.... folders.
Result := module_resource_location_by_name (a_module_name, a_resource)
if not ut.file_path_exists (Result) then
Result := Void
end
end
end
module_theme_location (a_module: CMS_MODULE): PATH
-- Location for overriden files associated with `a_module_name'.
do
Result := module_theme_location_by_name (a_module.name)
end
module_theme_location_by_name (a_module_name: READABLE_STRING_GENERAL): PATH
-- Location for overriden files associated with `a_module_name'.
do
Result := theme_location.extended ("modules").extended (a_module_name)
end
module_configuration (a_module: CMS_MODULE; a_name: detachable READABLE_STRING_GENERAL): detachable CONFIG_READER
do
Result := module_configuration_by_name (a_module.name, a_name)
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end