Added support for path_aliases.

Refactored CMS_MODULE.router (..): WSF_ROUTER design,
  to create only one router object of type CMS_ROUTER.
Added optional CMS_NODE.link: CMS_LOCAL_LINK
Reviewed permissions related to node module.
Refactor and add CMS_STORAGE_SQL(_BUILDER) abstractions
   for implementation relying only on SQL statements.
Factorized sql builder initialization (to work for sqlite and mysql storage builders).
Added CMS_RESPONSE.formatted_string (a_text: READABLE_STRING_GENERAL; args: TUPLE): STRING_32
Added function "translation", but not implemented for now.
Updated indexing notes and comments.
Code cleaning.
This commit is contained in:
2015-05-13 17:11:39 +02:00
parent 9514f1de9c
commit 29ef17226b
41 changed files with 776 additions and 316 deletions

View File

@@ -84,7 +84,7 @@ feature {NONE} -- Initialization
initialize_modules
-- Intialize core modules.
local
m: CMS_MODULE
-- m: CMS_MODULE
do
-- Core
-- create {BASIC_AUTH_MODULE} m.make

View File

@@ -36,11 +36,10 @@ feature {NONE} -- Initialization
feature -- Router
router (a_api: CMS_API): WSF_ROUTER
-- Router configuration.
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
create Result.make (1)
Result.handle ("/debug/", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_debug (a_api, ?, ?)))
a_router.handle ("/debug/", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_debug (a_api, ?, ?)))
end
feature -- Hooks configuration

View File

@@ -14,6 +14,11 @@ inherit
default_create
end
CMS_USER_STORAGE_NULL
undefine
default_create
end
REFACTORING_HELPER
rename
default_create as default_create_rh
@@ -40,74 +45,34 @@ feature -- Status report
Result := True
end
feature -- Access: user
feature -- URL aliases
has_user: BOOLEAN
-- Has any user?
set_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- <Precursor>.
do
end
users: LIST [CMS_USER]
do
create {ARRAYED_LIST [CMS_USER]} Result.make (0)
end
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
replace_path_alias (a_source: READABLE_STRING_8; a_previous_alias: detachable READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- Replace eventual previous alias `a_previous_alias' with a new alias `a_alias'
-- on source `a_source'.
do
end
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
unset_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- Unalias `a_source' from `a_alias'.
do
end
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
path_alias (a_source: READABLE_STRING_8): detachable READABLE_STRING_8
-- Return eventual path alias associated with `a_source'.
do
end
is_valid_credential (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8
-- Source path for alias `a_alias'.
do
end
feature -- Change: user
new_user (a_user: CMS_USER)
-- Add a new user `a_user'.
do
a_user.set_id (1)
end
update_user (a_user: CMS_USER)
-- Update user `a_user'.
do
end
feature -- Access: roles and permissions
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
do
end
user_roles_for (a_user: CMS_USER): LIST [CMS_USER_ROLE]
-- User roles for user `a_user'.
-- Note: anonymous and authenticated roles are not included.
do
create {ARRAYED_LIST [CMS_USER_ROLE]} Result.make (0)
end
user_roles: LIST [CMS_USER_ROLE]
do
create {ARRAYED_LIST [CMS_USER_ROLE]} Result.make (0)
end
feature -- Change: roles and permissions
save_user_role (a_user_role: CMS_USER_ROLE)
do
end
feature -- Logs
save_log (a_log: CMS_LOG)
@@ -115,6 +80,8 @@ feature -- Logs
do
end
feature -- Custom
set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value; a_type: detachable READABLE_STRING_8)
-- Save data `a_name:a_value' for type `a_type' (or default if none).
do

View File

@@ -1,15 +0,0 @@
note
description: "[
Objects that ...
]"
author: "$Author: jfiat $"
date: "$Date: 2015-01-27 19:15:02 +0100 (mar., 27 janv. 2015) $"
revision: "$Revision: 96542 $"
deferred class
CMS_STORAGE_SQL_BUILDER
inherit
CMS_STORAGE_BUILDER
end

View File

@@ -19,6 +19,34 @@ feature -- Error Handling
deferred
end
feature -- URL aliases
set_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- Alias `a_source' with `a_alias'.
deferred
end
replace_path_alias (a_source: READABLE_STRING_8; a_previous_alias: detachable READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- Replace eventual previous alias `a_previous_alias' with a new alias `a_alias'
-- on source `a_source'.
deferred
end
unset_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- Unalias `a_source' from `a_alias'.
deferred
end
path_alias (a_source: READABLE_STRING_8): detachable READABLE_STRING_8
-- Return eventual path alias associated with `a_source'.
deferred
end
source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8
-- Source path for alias `a_alias'.
deferred
end
feature -- Logs
save_log (a_log: CMS_LOG)

View File

@@ -18,6 +18,123 @@ inherit
SHARED_LOGGER
feature -- URL aliases
set_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- <Precursor>
local
l_parameters: STRING_TABLE [detachable ANY]
do
error_handler.reset
create l_parameters.make (2)
l_parameters.put (a_source, "source")
l_parameters.put (a_alias, "alias")
if attached source_of_path_alias (a_alias) as l_path then
if a_source.same_string (l_path) then
-- already up to date
else
error_handler.add_custom_error (0, "alias exists", "Path alias %"" + a_alias + "%" already exists!")
end
else
sql_change (sql_insert_path_alias, l_parameters)
end
end
replace_path_alias (a_source: READABLE_STRING_8; a_previous_alias: detachable READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- <Precursor>
local
l_parameters: STRING_TABLE [detachable ANY]
l_previous_alias: detachable READABLE_STRING_8
do
error_handler.reset
if a_previous_alias = Void then
l_previous_alias := path_alias (a_source)
else
l_previous_alias := a_previous_alias
end
if
l_previous_alias /= Void and then
not a_alias.same_string (l_previous_alias)
then
create l_parameters.make (3)
l_parameters.put (a_source, "source")
l_parameters.put (l_previous_alias, "old")
l_parameters.put (a_alias, "alias")
sql_change (sql_update_path_alias, l_parameters)
end
end
unset_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
-- <Precursor>
local
l_parameters: STRING_TABLE [detachable ANY]
do
error_handler.reset
if attached source_of_path_alias (a_alias) as l_path then
if a_source.same_string (l_path) then
-- Found
create l_parameters.make (1)
l_parameters.put (a_alias, "alias")
sql_change (sql_delete_path_alias, l_parameters)
else
error_handler.add_custom_error (0, "alias mismatch", "Path alias %"" + a_alias + "%" is not related to source %"" + a_source + "%"!")
end
else
-- No such alias
end
end
path_alias (a_source: READABLE_STRING_8): detachable READABLE_STRING_8
-- <Precursor>
local
l_parameters: STRING_TABLE [detachable ANY]
do
error_handler.reset
create l_parameters.make (1)
l_parameters.put (a_source, "source")
sql_query (sql_select_path_source, l_parameters)
if not has_error then
if sql_rows_count = 1 then
Result := sql_read_string (1)
end
end
end
source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8
-- <Precursor>
local
l_parameters: STRING_TABLE [detachable ANY]
do
error_handler.reset
create l_parameters.make (1)
l_parameters.put (a_alias, "alias")
sql_query (sql_select_path_alias, l_parameters)
if not has_error then
if sql_rows_count = 1 then
Result := sql_read_string (1)
end
end
end
sql_select_path_alias: STRING = "SELECT source FROM path_aliases WHERE alias=:alias ;"
-- SQL select path aliases.
sql_select_path_source: STRING = "SELECT alias FROM path_aliases WHERE source=:source ORDER BY pid DESC LIMIT 1;"
-- SQL select latest path aliasing :source.
sql_insert_path_alias: STRING = "INSERT INTO path_aliases (source, alias) VALUES (:source, :alias);"
-- SQL insert path alias.
sql_update_path_alias: STRING = "UPDATE path_aliases SET alias=:alias WHERE source=:source AND alias=:old ;"
-- SQL update path alias.
sql_delete_path_alias: STRING = "DELETE FROM path_aliases WHERE alias=:alias;"
-- SQL delete path alias
feature -- Logs
save_log (a_log: CMS_LOG)

View File

@@ -0,0 +1,15 @@
note
description: "CMS Storage based on SQL statement."
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
deferred class
CMS_STORAGE_SQL
inherit
CMS_STORAGE
CMS_STORAGE_SQL_I
end

View File

@@ -0,0 +1,85 @@
note
description: "[
Common ancestor for builders responsible to instantiate storage based
on SQL statement storage.
]"
author: "$Author: jfiat $"
date: "$Date: 2015-01-27 19:15:02 +0100 (mar., 27 janv. 2015) $"
revision: "$Revision: 96542 $"
deferred class
CMS_STORAGE_SQL_BUILDER
inherit
CMS_STORAGE_BUILDER
feature -- Initialization
initialize (a_setup: CMS_SETUP; a_storage: CMS_STORAGE_SQL)
local
u: CMS_USER
l_anonymous_role, l_authenticated_role, r: CMS_USER_ROLE
l_roles: LIST [CMS_USER_ROLE]
do
--| Schema
a_storage.sql_execute_file_script (a_setup.environment.path.extended ("scripts").extended ("core.sql"))
a_storage.sql_execute_file_script (a_setup.environment.path.extended ("scripts").extended ("user.sql"))
--| Roles
create l_anonymous_role.make ("anonymous")
a_storage.save_user_role (l_anonymous_role)
create l_authenticated_role.make ("authenticated")
a_storage.save_user_role (l_authenticated_role)
--| Users
create u.make ("admin")
u.set_password ("istrator#")
u.set_email (a_setup.site_email)
a_storage.new_user (u)
--| Node
-- FIXME: move that initialization to node module
l_anonymous_role.add_permission ("view any page")
a_storage.save_user_role (l_anonymous_role)
l_authenticated_role.add_permission ("create page")
l_authenticated_role.add_permission ("view any page")
l_authenticated_role.add_permission ("edit any page")
l_authenticated_role.add_permission ("delete page")
l_authenticated_role.add_permission ("view own page")
l_authenticated_role.add_permission ("edit own page")
l_authenticated_role.add_permission ("delete own page")
a_storage.save_user_role (l_authenticated_role)
--|-------------------------------------------|--
--| For testing purpose, to be removed later. |--
--|-------------------------------------------|--
-- Roles, view role for testing.
create r.make ("view")
r.add_permission ("view any page")
a_storage.save_user_role (r)
create {ARRAYED_LIST [CMS_USER_ROLE]} l_roles.make (1)
l_roles.force (r)
create u.make ("auth")
u.set_password ("enticated#")
u.set_email (a_setup.site_email)
a_storage.new_user (u)
create u.make ("test")
u.set_password ("test#")
u.set_email (a_setup.site_email)
a_storage.new_user (u)
create u.make ("view")
u.set_password ("only#")
u.set_email (a_setup.site_email)
u.set_roles (l_roles)
a_storage.new_user (u)
end
end

View File

@@ -0,0 +1,79 @@
note
description: "Summary description for {CMS_USER_STORAGE_NULL}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_USER_STORAGE_NULL
inherit
CMS_USER_STORAGE_I
feature -- Access: user
has_user: BOOLEAN
-- Has any user?
do
end
users: LIST [CMS_USER]
do
create {ARRAYED_LIST [CMS_USER]} Result.make (0)
end
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
do
end
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
do
end
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
do
end
is_valid_credential (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
do
end
feature -- Change: user
new_user (a_user: CMS_USER)
-- Add a new user `a_user'.
do
a_user.set_id (1)
end
update_user (a_user: CMS_USER)
-- Update user `a_user'.
do
end
feature -- Access: roles and permissions
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
do
end
user_roles_for (a_user: CMS_USER): LIST [CMS_USER_ROLE]
-- User roles for user `a_user'.
-- Note: anonymous and authenticated roles are not included.
do
create {ARRAYED_LIST [CMS_USER_ROLE]} Result.make (0)
end
user_roles: LIST [CMS_USER_ROLE]
do
create {ARRAYED_LIST [CMS_USER_ROLE]} Result.make (0)
end
feature -- Change: roles and permissions
save_user_role (a_user_role: CMS_USER_ROLE)
do
end
end

View File

@@ -232,6 +232,66 @@ feature -- Query: API
Result := l_api
end
feature -- Path aliases
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.
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

View File

@@ -66,10 +66,8 @@ feature {CMS_API} -- Module management
feature -- Router
router (a_api: CMS_API): WSF_ROUTER
-- Router configuration.
require
is_enabled: is_enabled
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- Setup url dispatching for Current module.
deferred
end

View File

@@ -16,7 +16,9 @@ inherit
undefine
requires_proxy
redefine
execute_default
execute_default,
create_router,
router
end
WSF_FILTERED_SERVICE
@@ -82,10 +84,17 @@ feature {NONE} -- Initialization
feature -- Settings: router
router: CMS_ROUTER
create_router
-- Create `router'.
do
create router.make (api, 30)
end
setup_router
-- <Precursor>
local
l_module: CMS_MODULE
l_api: like api
l_router: like router
do
@@ -100,8 +109,7 @@ feature -- Settings: router
across
modules as ic
loop
l_module := ic.item
l_router.import (l_module.router (l_api))
ic.item.setup_router (l_router, l_api)
end
-- Configure files handler.
configure_api_file_handler (l_router)

View File

@@ -0,0 +1,38 @@
note
description: "Specific version of WSF_ROUTER for CMS component."
date: "$Date$"
revision: "$Revision$"
class
CMS_ROUTER
inherit
WSF_ROUTER
rename
make as make_router
redefine
path_to_dispatch
end
create
make
feature {NONE} -- Initialization
make (a_api: CMS_API; a_capacity: INTEGER)
do
api := a_api
make_router (a_capacity)
end
api: CMS_API
feature {WSF_ROUTER_MAPPING} -- Dispatch helper
path_to_dispatch (req: WSF_REQUEST): READABLE_STRING_8
-- Path used by the router, to apply url dispatching of request `req'.
do
Result := api.source_of_path_alias (Precursor (req))
end
end

View File

@@ -76,6 +76,26 @@ feature -- Access
redirection: detachable READABLE_STRING_8
-- Location for eventual redirection.
feature -- Internationalization (i18n)
translation (a_text: READABLE_STRING_GENERAL; opts: detachable CMS_API_OPTIONS): STRING_32
-- Translated text `a_text' according to expected context (lang, ...)
-- and adapt according to options eventually set by `opts'.
do
to_implement ("Implement i18n support [2015-may]")
Result := a_text.as_string_32
end
formatted_string (a_text: READABLE_STRING_GENERAL; args: TUPLE): STRING_32
-- Format `a_text' using arguments `args'.
--| ex: formatted_string ("hello $1, see page $title.", ["bob", "contact"] -> "hello bob, see page contact"
local
l_formatter: CMS_STRING_FORMATTER
do
create l_formatter
Result := l_formatter.formatted_string (a_text, args)
end
feature -- API
api: CMS_API
@@ -185,12 +205,30 @@ feature -- Permission
Result := user_has_permission (current_user (request), a_permission)
end
has_permissions (a_permission_list: ITERABLE [READABLE_STRING_GENERAL]): BOOLEAN
-- Does current user has any of the permissions `a_permission_list' ?
do
Result := user_has_permissions (current_user (request), a_permission_list)
end
user_has_permission (a_user: detachable CMS_USER; a_permission: READABLE_STRING_GENERAL): BOOLEAN
-- Does `a_user' has permission `a_permission' ?
do
Result := api.user_has_permission (a_user, a_permission)
end
user_has_permissions (a_user: detachable CMS_USER; a_permission_list: ITERABLE [READABLE_STRING_GENERAL]): BOOLEAN
-- Does `a_user' has any of the permissions `a_permission_list' ?
do
across
a_permission_list as ic
until
Result
loop
Result := user_has_permission (a_user, ic.item)
end
end
feature -- Head customization
add_additional_head_line (s: READABLE_STRING_8; a_allow_duplication: BOOLEAN)

View File

@@ -0,0 +1,23 @@
note
description: "Format a text using arguments."
date: "$Date$"
revision: "$Revision$"
class
CMS_STRING_FORMATTER
feature -- Conversion
formatted_string (a_string: READABLE_STRING_GENERAL; args: TUPLE): STRING_32
do
Result := i18n_formatter.formatted_string (a_string, args)
end
feature {NONE} -- Implementation
i18n_formatter: I18N_STRING_FORMATTER
once
create Result
end
end