diff --git a/cms-safe.ecf b/cms-safe.ecf
index 69affe6..91fdb85 100644
--- a/cms-safe.ecf
+++ b/cms-safe.ecf
@@ -19,6 +19,7 @@
+
diff --git a/cms.ecf b/cms.ecf
index 0e8620c..f642c2a 100644
--- a/cms.ecf
+++ b/cms.ecf
@@ -17,6 +17,7 @@
+
diff --git a/examples/demo/modules/blog/cms_blog_module.e b/examples/demo/modules/blog/cms_blog_module.e
index 7390683..b75fdcd 100644
--- a/examples/demo/modules/blog/cms_blog_module.e
+++ b/examples/demo/modules/blog/cms_blog_module.e
@@ -84,11 +84,10 @@ CREATE TABLE "blog_post_nodes"(
feature -- Access: router
- router (a_api: CMS_API): WSF_ROUTER
- -- Node router.
+ setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
+ --
do
- create Result.make (1)
- Result.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), Result.methods_get)
+ a_router.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), a_router.methods_get)
end
feature -- Hooks
diff --git a/examples/demo/modules/demo/cms_demo_module.e b/examples/demo/modules/demo/cms_demo_module.e
index 3867a16..e0f1ff1 100644
--- a/examples/demo/modules/demo/cms_demo_module.e
+++ b/examples/demo/modules/demo/cms_demo_module.e
@@ -80,12 +80,11 @@ CREATE TABLE "tb_demo"(
feature -- Access: router
- router (a_api: CMS_API): WSF_ROUTER
- -- Node router.
+ setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
+ --
do
- create Result.make (2)
- map_uri_template_agent (Result, "/demo/", agent handle_demo (?,?,a_api))
- map_uri_template_agent (Result, "/demo/{id}", agent handle_demo_entry (?,?,a_api))
+ map_uri_template_agent (a_router, "/demo/", agent handle_demo (?,?,a_api))
+ map_uri_template_agent (a_router, "/demo/{id}", agent handle_demo_entry (?,?,a_api))
end
feature -- Hooks
diff --git a/examples/demo/site/scripts/core.sql b/examples/demo/site/scripts/core.sql
index 0c26f42..04dbec8 100644
--- a/examples/demo/site/scripts/core.sql
+++ b/examples/demo/site/scripts/core.sql
@@ -1,35 +1,5 @@
BEGIN;
-CREATE TABLE "users"(
- "uid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("uid">=0),
- "name" VARCHAR(100) NOT NULL,
- "password" VARCHAR(100) NOT NULL,
- "salt" VARCHAR(100) NOT NULL,
- "email" VARCHAR(250) NOT NULL,
- "status" INTEGER,
- "created" DATETIME NOT NULL,
- "signed" DATETIME,
- CONSTRAINT "name"
- UNIQUE("name")
-);
-
-CREATE TABLE "roles"(
- "rid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("rid">=0),
- "name" VARCHAR(100) NOT NULL,
- CONSTRAINT "name"
- UNIQUE("name")
-);
-
-CREATE TABLE "users_roles"(
- "uid" INTEGER NOT NULL CHECK("uid">=0),
- "rid" INTEGER NOT NULL CHECK("rid">=0)
-);
-
-CREATE TABLE "role_permissions"(
- "rid" INTEGER NOT NULL CHECK("rid">=0),
- "permission" VARCHAR(255) NOT NULL,
- "module" VARCHAR(255)
-);
CREATE TABLE "logs"(
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("id">=0),
@@ -48,4 +18,11 @@ CREATE TABLE "custom_values"(
"value" VARCHAR(255) NOT NULL
);
+CREATE TABLE "path_aliases"(
+ "pid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("pid">=0),
+ "source" VARCHAR(255) NOT NULL,
+ "alias" VARCHAR(255) NOT NULL,
+ "lang" VARCHAR(12)
+);
+
COMMIT;
diff --git a/examples/demo/site/scripts/user.sql b/examples/demo/site/scripts/user.sql
new file mode 100644
index 0000000..707dbc2
--- /dev/null
+++ b/examples/demo/site/scripts/user.sql
@@ -0,0 +1,34 @@
+BEGIN;
+
+CREATE TABLE "users"(
+ "uid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("uid">=0),
+ "name" VARCHAR(100) NOT NULL,
+ "password" VARCHAR(100) NOT NULL,
+ "salt" VARCHAR(100) NOT NULL,
+ "email" VARCHAR(250) NOT NULL,
+ "status" INTEGER,
+ "created" DATETIME NOT NULL,
+ "signed" DATETIME,
+ CONSTRAINT "name"
+ UNIQUE("name")
+);
+
+CREATE TABLE "roles"(
+ "rid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("rid">=0),
+ "name" VARCHAR(100) NOT NULL,
+ CONSTRAINT "name"
+ UNIQUE("name")
+);
+
+CREATE TABLE "users_roles"(
+ "uid" INTEGER NOT NULL CHECK("uid">=0),
+ "rid" INTEGER NOT NULL CHECK("rid">=0)
+);
+
+CREATE TABLE "role_permissions"(
+ "rid" INTEGER NOT NULL CHECK("rid">=0),
+ "permission" VARCHAR(255) NOT NULL,
+ "module" VARCHAR(255)
+);
+
+COMMIT;
diff --git a/library/model/src/link/cms_local_link.e b/library/model/src/link/cms_local_link.e
index db41482..376ccac 100644
--- a/library/model/src/link/cms_local_link.e
+++ b/library/model/src/link/cms_local_link.e
@@ -28,12 +28,8 @@ feature {NONE} -- Initialization
make (a_title: detachable like title; a_location: like location)
-- Create current local link with optional title `a_title' and location `a_location'.
do
- if a_title /= Void then
- title := a_title
- else
- title := a_location
- end
location := a_location
+ set_title (a_title)
end
feature -- Access
@@ -75,6 +71,16 @@ feature -- Status report
feature -- Element change
+ set_title (a_title: detachable like title)
+ -- Set `title' to `a_title' or `location'.
+ do
+ if a_title /= Void then
+ title := a_title
+ else
+ title := location
+ end
+ end
+
add_link (lnk: CMS_LINK)
--
local
diff --git a/library/persistence/implementation/store/cms_storage_store_sql.e b/library/persistence/implementation/store/cms_storage_store_sql.e
index 3a8a4c0..acfec12 100644
--- a/library/persistence/implementation/store/cms_storage_store_sql.e
+++ b/library/persistence/implementation/store/cms_storage_store_sql.e
@@ -1,6 +1,5 @@
note
- description: "Summary description for {CMS_STORAGE_STORE_SQL}."
- author: ""
+ description: "Storage based on Eiffel Store component."
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
@@ -8,9 +7,7 @@ deferred class
CMS_STORAGE_STORE_SQL
inherit
- CMS_STORAGE
-
- CMS_STORAGE_SQL_I
+ CMS_STORAGE_SQL
feature {NONE} -- Initialization
@@ -25,7 +22,6 @@ feature {NONE} -- Initialization
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
create error_handler.make
--- error_handler.add_synchronization (db_handler.database_error_handler)
end
feature -- Status report
diff --git a/library/persistence/implementation/store/cms_storage_store_sql_builder.e b/library/persistence/implementation/store/cms_storage_store_sql_builder.e
new file mode 100644
index 0000000..6fc4b15
--- /dev/null
+++ b/library/persistence/implementation/store/cms_storage_store_sql_builder.e
@@ -0,0 +1,16 @@
+note
+ description: "[
+ Common ancestor for builders responsible to instantiate storage based
+ on Eiffel Store storage.
+ ]"
+ author: "$Author: jfiat $"
+ date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
+ revision: "$Revision: 96616 $"
+
+deferred class
+ CMS_STORAGE_STORE_SQL_BUILDER
+
+inherit
+ CMS_STORAGE_SQL_BUILDER
+
+end
diff --git a/library/persistence/mysql/src/cms_storage_mysql_builder.e b/library/persistence/mysql/src/cms_storage_mysql_builder.e
index 4889f73..2249df3 100644
--- a/library/persistence/mysql/src/cms_storage_mysql_builder.e
+++ b/library/persistence/mysql/src/cms_storage_mysql_builder.e
@@ -1,6 +1,6 @@
note
description: "[
- Objects that ...
+ Interface responsible to instantiate CMS_STORAGE_MYSQL object.
]"
author: "$Author: jfiat $"
date: "$Date: 2015-01-27 19:15:02 +0100 (mar., 27 janv. 2015) $"
@@ -10,7 +10,9 @@ class
CMS_STORAGE_MYSQL_BUILDER
inherit
- CMS_STORAGE_SQL_BUILDER
+ CMS_STORAGE_STORE_SQL_BUILDER
+
+ GLOBAL_SETTINGS
create
make
@@ -32,6 +34,12 @@ feature -- Factory
create {DATABASE_CONNECTION_MYSQL} conn.login_with_connection_string (l_database_config.connection_string)
if conn.is_connected then
create Result.make (conn)
+ set_map_zero_null_value (False) --| This way we map 0 to 0, instead of Null as default.
+ if Result.is_available then
+ if not Result.is_initialized then
+ initialize (a_setup, Result)
+ end
+ end
end
end
end
diff --git a/library/persistence/sqlite/src/cms_storage_sqlite.e b/library/persistence/sqlite/src/cms_storage_sqlite.e
index 78b9942..218b09e 100644
--- a/library/persistence/sqlite/src/cms_storage_sqlite.e
+++ b/library/persistence/sqlite/src/cms_storage_sqlite.e
@@ -1,5 +1,5 @@
note
- description: "Summary description for {CMS_STORAGE_MYSQL}."
+ description: "Summary description for {CMS_STORAGE_SQLITE}."
date: "$Date: 2015-02-09 22:29:56 +0100 (lun., 09 févr. 2015) $"
revision: "$Revision: 96596 $"
diff --git a/library/persistence/sqlite/src/cms_storage_sqlite_builder.e b/library/persistence/sqlite/src/cms_storage_sqlite_builder.e
index bb4dcf3..f59beee 100644
--- a/library/persistence/sqlite/src/cms_storage_sqlite_builder.e
+++ b/library/persistence/sqlite/src/cms_storage_sqlite_builder.e
@@ -1,6 +1,6 @@
note
description: "[
- Objects that ...
+ Interface responsible to instantiate CMS_STORAGE_SQLITE object.
]"
author: "$Author: jfiat $"
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
@@ -10,7 +10,7 @@ class
CMS_STORAGE_SQLITE_BUILDER
inherit
- CMS_STORAGE_SQL_BUILDER
+ CMS_STORAGE_STORE_SQL_BUILDER
GLOBAL_SETTINGS
@@ -29,6 +29,7 @@ feature -- Factory
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE_SQLITE
local
s: STRING
+ conn: DATABASE_CONNECTION
do
if attached (create {APPLICATION_JSON_CONFIGURATION_HELPER}).new_database_configuration (a_setup.environment.application_config_path) as l_database_config then
s := "Driver=SQLite3 ODBC Driver;Database="
@@ -36,77 +37,17 @@ feature -- Factory
s.append (db_name)
end
s.append (";LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;")
- create Result.make (create {DATABASE_CONNECTION_ODBC}.login_with_connection_string (s))
- set_map_zero_null_value (False)
- -- This way we map 0 to 0, instead of Null as default.
- --create Result.make (create {DATABASE_CONNECTION_ODBC}.login_with_connection_string (l_database_config.connection_string))
- if Result.is_available then
- if not Result.is_initialized then
- initialize (a_setup, Result)
+ create {DATABASE_CONNECTION_ODBC} conn.login_with_connection_string (s)
+ if conn.is_connected then
+ create Result.make (conn)
+ set_map_zero_null_value (False) --| This way we map 0 to 0, instead of Null as default.
+ if Result.is_available then
+ if not Result.is_initialized then
+ initialize (a_setup, Result)
+ end
end
end
end
end
- initialize (a_setup: CMS_SETUP; a_storage: CMS_STORAGE_STORE_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"))
-
- --| 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 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 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
diff --git a/modules/basic_auth/basic_auth_module.e b/modules/basic_auth/basic_auth_module.e
index 1cb025c..3efe2c2 100644
--- a/modules/basic_auth/basic_auth_module.e
+++ b/modules/basic_auth/basic_auth_module.e
@@ -37,12 +37,11 @@ feature {NONE} -- Initialization
feature -- Access: router
- router (a_api: CMS_API): WSF_ROUTER
- -- Node router.
+ setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
+ --
do
- create Result.make (2)
- configure_api_login (a_api, Result)
- configure_api_logoff (a_api, Result)
+ configure_api_login (a_api, a_router)
+ configure_api_logoff (a_api, a_router)
end
feature -- Access: filter
diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e
index 9922722..8f0a8d9 100644
--- a/modules/node/cms_node_api.e
+++ b/modules/node/cms_node_api.e
@@ -176,6 +176,14 @@ feature -- URL
end
end
+ node_link (a_node: CMS_NODE): CMS_LOCAL_LINK
+ -- CMS link for node `a_node'.
+ require
+ a_node.has_id
+ do
+ create Result.make (a_node.title, cms_api.path_alias (node_path (a_node)))
+ end
+
node_path (a_node: CMS_NODE): STRING
-- URI path for node `a_node'.
-- using the /node/{nid} url.
@@ -234,6 +242,11 @@ feature -- Access: Node
Result := a_node
end
+ -- Update link with aliasing.
+ if a_node /= Void and then a_node.has_id then
+ a_node.set_link (node_link (a_node))
+ end
+
-- Update partial user if needed.
if
Result /= Void and then
@@ -259,16 +272,17 @@ feature -- Access: Node
feature -- Permission Scope: Node
- permission_scope (u: detachable CMS_USER; a_node: CMS_NODE): STRING
- -- Result 'own' if the user `u' is the owner of the node `a_node', in other case
- -- `any'.
+ has_permission_for_action_on_node (a_action: READABLE_STRING_8; a_node: CMS_NODE; a_user: detachable CMS_USER; ): BOOLEAN
+ -- Has permission to execute action `a_action' on node `a_node', by eventual user `a_user'?
+ local
+ l_type_name: READABLE_STRING_8
do
- -- FIXME: check if this is ok, since a role may have "any" permission enabled, and "own" disabled,
- -- in this case, we should check both permissions
- -- obviously such case should be rare, and look like bad configured permissions, but this may occurs.
- Result := "any"
- if u /= Void and then is_author_of_node (u, a_node) then
- Result := "own"
+ l_type_name := a_node.content_type
+ Result := cms_api.user_has_permission (a_user, a_action + " any " + l_type_name)
+ if not Result and a_user /= Void then
+ if is_author_of_node (a_user, a_node) then
+ Result := cms_api.user_has_permission (a_user, a_action + " own " + l_type_name)
+ end
end
end
diff --git a/modules/node/content/cms_node.e b/modules/node/content/cms_node.e
index 51808b2..e01a814 100644
--- a/modules/node/content/cms_node.e
+++ b/modules/node/content/cms_node.e
@@ -54,6 +54,7 @@ feature -- Conversion
a_node.format
)
set_status (a_node.status)
+ set_link (a_node.link)
end
feature -- Access
@@ -142,6 +143,11 @@ feature -- status report
Result := a_content_type.is_case_insensitive_equal (content_type)
end
+feature -- Access: menu
+
+ link: detachable CMS_LOCAL_LINK
+ -- Associated menu link.
+
feature -- Element change
set_content (a_content: like content; a_summary: like summary; a_format: like format)
@@ -158,6 +164,9 @@ feature -- Element change
-- Assign `title' with `a_title'.
do
title := a_title
+ if attached link as lnk then
+ lnk.set_title (a_title)
+ end
ensure
title_assigned: title = a_title
end
@@ -211,6 +220,14 @@ feature -- Element change
auther_set: author = u
end
+ set_link (a_link: like link)
+ -- Set `link' to `a_link'.
+ do
+ link := a_link
+ end
+
+feature -- Status change
+
mark_not_published
-- Set status to not_published.
do
@@ -235,7 +252,6 @@ feature -- Element change
status_trash: status = {CMS_NODE_API}.trashed
end
-
feature {CMS_NODE_STORAGE_I} -- Access: status change.
set_status (a_status: like status)
diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e
index 88161a4..f571c26 100644
--- a/modules/node/handler/cms_node_type_webform_manager.e
+++ b/modules/node/handler/cms_node_type_webform_manager.e
@@ -65,6 +65,26 @@ feature -- Forms ...
fset.extend (tselect)
f.extend (fset)
+
+ -- Path aliase
+ create ti.make ("path_alias")
+ ti.set_label ("Path")
+ ti.set_size (70)
+ if a_node /= Void and then a_node.has_id then
+ if attached a_node.link as lnk then
+ ti.set_text_value (lnk.location)
+ else
+ ti.set_text_value (response.api.path_alias (response.node_api.node_path (a_node)))
+ end
+ end
+ if
+ attached f.fields_by_name ("title") as l_title_fields and then
+ attached l_title_fields.first as l_title_field
+ then
+ f.insert_after (ti, l_title_field)
+ else
+ f.extend (ti)
+ end
end
update_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: CMS_NODE)
@@ -160,8 +180,9 @@ feature -- Output
node_api := a_response.node_api
a_response.add_variable (a_node, "node")
- create lnk.make ("View", node_api.node_path (a_node))
+ create lnk.make (a_response.translation ("View", Void), a_response.node_local_link (a_node).location)
lnk.set_weight (1)
+
a_response.add_to_primary_tabs (lnk)
create lnk.make ("Edit", node_api.node_path (a_node) + "/edit")
lnk.set_weight (2)
diff --git a/modules/node/handler/cms_page_node_type_webform_manager.e b/modules/node/handler/cms_page_node_type_webform_manager.e
index e538aa7..498f392 100644
--- a/modules/node/handler/cms_page_node_type_webform_manager.e
+++ b/modules/node/handler/cms_page_node_type_webform_manager.e
@@ -1,6 +1,5 @@
note
description: "Summary description for {CMS_PAGE_NODE_TYPE_WEBFORM_MANAGER}."
- author: ""
date: "$Date$"
revision: "$Revision$"
diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e
index 8ade0b6..c01330a 100644
--- a/modules/node/handler/node_form_response.e
+++ b/modules/node/handler/node_form_response.e
@@ -37,7 +37,7 @@ feature -- Execution
-- Computed response message.
local
b: STRING_8
- f: like edit_form
+ f: like new_edit_form
fd: detachable WSF_FORM_DATA
nid: INTEGER_64
do
@@ -48,43 +48,44 @@ feature -- Execution
attached node_api.node (nid) as l_node
then
if attached node_api.node_type_for (l_node) as l_type then
- if has_permission ("edit " + node_api.permission_scope (current_user (request), l_node) + " " + l_type.name) then
- f := edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
+ if node_api.has_permission_for_action_on_node ("edit", l_node, current_user (request)) then
+ f := new_edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
+ invoke_form_alter (f, fd)
if request.is_post_request_method then
f.validation_actions.extend (agent edit_form_validate (?, b))
f.submit_actions.extend (agent edit_form_submit (?, l_node, l_type, b))
f.process (Current)
fd := f.last_data
end
+ if l_node.has_id then
+ add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), node_url (l_node)), primary_tabs)
+ add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "/node/" + l_node.id.out + "/edit"), primary_tabs)
+ end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (l_node.title)
- add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs)
- add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs)
-
b.append (html_encoded (l_type.title) + " saved")
else
- set_title ("Edit " + html_encoded (l_type.title) + " #" + l_node.id.out)
-
- add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs)
- add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs)
-
+ set_title (formatted_string (translation ("Edit $1 #$2", Void), [l_type.title, l_node.id]))
f.append_to_html (wsf_theme, b)
end
else
- b.append ("Access denied
")
+ b.append ("")
+ b.append (translation ("Access denied", Void))
+ b.append ("
")
end
else
- set_title ("Unknown node")
+ set_title (translation ("Unknown node", Void))
end
elseif
attached {WSF_STRING} request.path_parameter ("type") as p_type and then
attached node_api.node_type (p_type.value) as l_type
then
- if has_permission ("create " + l_type.name) then
+ if has_permissions (<<"create any", "create " + l_type.name>>) then
if attached l_type.new_node (Void) as l_node then
- f := edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
+ f := new_edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
+ invoke_form_alter (f, fd)
if request.is_post_request_method then
f.validation_actions.extend (agent edit_form_validate (?, b))
f.submit_actions.extend (agent edit_form_submit (?, l_node, l_type, b))
@@ -94,25 +95,31 @@ feature -- Execution
set_title ("Edit " + html_encoded (l_type.title) + " #" + l_node.id.out)
- add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs)
- add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs)
+ if l_node.has_id then
+ add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), node_url (l_node)), primary_tabs)
+ add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "/node/" + l_node.id.out + "/edit"), primary_tabs)
+ end
f.append_to_html (wsf_theme, b)
else
- b.append ("Server error
")
+ b.append ("")
+ b.append (translation ("Server error", Void))
+ b.append ("
")
end
else
- b.append ("Access denied
")
+ b.append ("")
+ b.append (translation ("Access denied", Void))
+ b.append ("
")
end
else
- set_title ("Create new content ...")
+ set_title (translation ("Create new content ...", Void))
b.append ("")
across
node_api.node_types as ic
loop
if
attached ic.item as l_node_type and then
- (has_permission ("create any") or has_permission ("create " + l_node_type.name))
+ has_permissions (<<"create any", "create " + l_node_type.name>>)
then
b.append ("- " + link (l_node_type.name, "/node/add/" + l_node_type.name, Void))
if attached l_node_type.description as d then
@@ -191,16 +198,25 @@ feature -- Form
end
node_api.save_node (l_node)
if attached current_user (request) as u then
- api.log ("node", "User %"" + user_link (u) + "%" " + s + " node " + link (a_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node))
+ api.log ("node", "User %"" + user_html_link (u) + "%" " + s + " node " + link (a_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node))
else
api.log ("node", "Anonymous " + s + " node " + a_type.name +" #" + l_node.id.out, 0, node_local_link (l_node))
end
add_success_message ("Node #" + l_node.id.out + " saved.")
+
+ if attached fd.string_item ("path_alias") as l_path_alias then
+ api.set_path_alias (node_api.node_path (l_node), l_path_alias, False)
+ l_node.set_link (create {CMS_LOCAL_LINK}.make (l_node.title, l_path_alias))
+ else
+ l_node.set_link (node_api.node_link (l_node))
+ end
+
set_redirection (node_url (l_node))
end
end
- edit_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM
+ new_edit_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_node_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM
+ -- Create a web form named `a_name' for node `a_node' (if set), using form action url `a_url', and for type of node `a_node_type'.
local
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
@@ -216,8 +232,7 @@ feature -- Form
end
f.extend (th)
- fill_edit_form (a_type, f, a_node)
-
+ populate_form (a_node_type, f, a_node)
f.extend_html_text ("
")
create ts.make ("op")
@@ -228,11 +243,15 @@ feature -- Form
ts.set_default_value ("Preview")
f.extend (ts)
- if a_node /= Void and then a_node.id > 0 and then has_permission ("delete " + a_name) then
+ if
+ a_node /= Void and then
+ a_node.id > 0 and then
+ has_permission ("delete " + a_name)
+ then
create ts.make ("op")
ts.set_default_value ("Delete")
fixme ("[
- ts.set_default_value (i18n ("Delete"))i18n or other name such as "translated" or "translation
+ ts.set_default_value (translation ("Delete"))
]")
f.extend (ts)
end
@@ -240,8 +259,18 @@ feature -- Form
Result := f
end
+ populate_form (a_content_type: CMS_NODE_TYPE [CMS_NODE]; a_form: WSF_FORM; a_node: detachable CMS_NODE)
+ -- Fill the web form `a_form' with data from `a_node' if set,
+ -- and apply this to content type `a_content_type'.
+ do
+ if attached node_api.node_type_webform_manager (a_content_type) as wf then
+ wf.populate_form (Current, a_form, a_node)
+ end
+ end
+
new_node (a_content_type: CMS_NODE_TYPE [CMS_NODE]; a_form_data: WSF_FORM_DATA; a_node: detachable CMS_NODE): CMS_NODE
- --
+ -- Node creation with form_data `a_form_data' for the given content type `a_content_type'
+ -- using optional `a_node' to get extra node data.
do
if attached node_api.node_type_webform_manager (a_content_type) as wf then
Result := wf.new_node (Current, a_form_data, a_node)
@@ -258,11 +287,4 @@ feature -- Form
end
end
- fill_edit_form (a_content_type: CMS_NODE_TYPE [CMS_NODE]; a_form: WSF_FORM; a_node: detachable CMS_NODE)
- do
- if attached node_api.node_type_webform_manager (a_content_type) as wf then
- wf.populate_form (Current, a_form, a_node)
- end
- end
-
end
diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e
index 0e6d8b9..de50f39 100644
--- a/modules/node/handler/node_handler.e
+++ b/modules/node/handler/node_handler.e
@@ -150,7 +150,7 @@ feature -- HTTP Methods
l_id.is_integer and then
attached node_api.node (l_id.integer_value) as l_node
then
- if api.user_has_permission (l_user, "delete " + node_api.permission_scope (l_user, l_node) + " " + l_node.content_type) then
+ if node_api.has_permission_for_action_on_node ("delete", l_node, current_user (req)) then
node_api.delete_node (l_node)
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
else
diff --git a/modules/node/handler/node_response.e b/modules/node/handler/node_response.e
index 0bb7210..1bad113 100644
--- a/modules/node/handler/node_response.e
+++ b/modules/node/handler/node_response.e
@@ -51,36 +51,48 @@ feature -- Helpers
end
end
-feature -- Helpers
+feature -- Helpers: cms link
- user_local_link (u: CMS_USER): CMS_LINK
+ user_local_link (u: CMS_USER): CMS_LOCAL_LINK
do
- create {CMS_LOCAL_LINK} Result.make (u.name, user_url (u))
+ create Result.make (u.name, user_url (u))
end
- node_local_link (n: CMS_NODE): CMS_LINK
+ node_local_link (n: CMS_NODE): CMS_LOCAL_LINK
do
- create {CMS_LOCAL_LINK} Result.make (n.title, node_url (n))
+ if attached n.link as lnk then
+ Result := lnk
+ else
+ Result := node_api.node_link (n)
+ end
end
- user_link (u: CMS_USER): like link
+feature -- Helpers: html link
+
+ user_html_link (u: CMS_USER): like link
do
Result := link (u.name, "/user/" + u.id.out, Void)
end
- node_link (n: CMS_NODE): like link
+ node_html_link (n: CMS_NODE): like link
do
Result := link (n.title, "/node/" + n.id.out, Void)
end
+feature -- Helpers: URL
+
user_url (u: CMS_USER): like url
+ require
+ u_with_id: u.has_id
do
Result := url ("/user/" + u.id.out, Void)
end
node_url (n: CMS_NODE): like url
+ require
+ n_with_id: n.has_id
do
- Result := url ("/node/" + n.id.out, Void)
+ Result := url (node_api.node_link (n).location, Void)
end
end
diff --git a/modules/node/handler/nodes_handler.e b/modules/node/handler/nodes_handler.e
index 2619a90..18462d2 100644
--- a/modules/node/handler/nodes_handler.e
+++ b/modules/node/handler/nodes_handler.e
@@ -40,6 +40,7 @@ feature -- HTTP Methods
l_page: CMS_RESPONSE
s: STRING
n: CMS_NODE
+ lnk: CMS_LOCAL_LINK
do
-- At the moment the template is hardcoded, but we can
-- get them from the configuration file and load them into
@@ -57,8 +58,10 @@ feature -- HTTP Methods
lst as ic
loop
n := ic.item
+ lnk := node_api.node_link (n)
s.append (" - ")
- s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void))
+ s.append (l_page.link (lnk.title, lnk.location, Void))
+-- s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void))
s.append ("
%N")
end
s.append ("
%N")
diff --git a/modules/node/node_module.e b/modules/node/node_module.e
index ba6ca2d..8df4eab 100644
--- a/modules/node/node_module.e
+++ b/modules/node/node_module.e
@@ -109,8 +109,8 @@ feature {CMS_API} -- Access: API
feature -- Access: router
- router (a_api: CMS_API): WSF_ROUTER
- -- Node router.
+ setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
+ --
local
l_node_api: like node_api
do
@@ -119,8 +119,7 @@ feature -- Access: router
create l_node_api.make (a_api)
node_api := l_node_api
end
- create Result.make (2)
- configure_web (a_api, l_node_api, Result)
+ configure_web (a_api, l_node_api, a_router)
end
configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER)
diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e
index 815593c..6090d95 100644
--- a/modules/node/persistence/cms_node_storage_i.e
+++ b/modules/node/persistence/cms_node_storage_i.e
@@ -107,6 +107,8 @@ feature -- Change: Node
no_id: not a_node.has_id
valid_user: attached a_node.author as l_author and then l_author.id > 0
deferred
+ ensure
+ has_id: a_node.has_id
end
update_node (a_node: CMS_NODE)
diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e
index ebbf4a8..06ecadc 100644
--- a/modules/node/persistence/cms_node_storage_sql.e
+++ b/modules/node/persistence/cms_node_storage_sql.e
@@ -157,51 +157,6 @@ feature -- Change: Node
sql_change (sql_delete_node, l_parameters)
end
--- update_node_title (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
--- --
--- local
--- l_parameters: STRING_TABLE [detachable ANY]
--- do
--- -- FIXME: unused a_user_id !
--- error_handler.reset
--- write_information_log (generator + ".update_node_title")
--- create l_parameters.make (3)
--- l_parameters.put (a_title, "title")
--- l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
--- l_parameters.put (a_node_id, "nid")
--- sql_change (sql_update_node_title, l_parameters)
--- end
-
--- update_node_summary (a_user_id: Like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
--- --
--- local
--- l_parameters: STRING_TABLE [detachable ANY]
--- do
--- -- FIXME: unused a_user_id !
--- error_handler.reset
--- write_information_log (generator + ".update_node_summary")
--- create l_parameters.make (3)
--- l_parameters.put (a_summary, "summary")
--- l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
--- l_parameters.put (a_node_id, "nid")
--- sql_change (sql_update_node_summary, l_parameters)
--- end
-
--- update_node_content (a_user_id: Like {CMS_USER}.id;a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
--- --
--- local
--- l_parameters: STRING_TABLE [detachable ANY]
--- do
--- -- FIXME: unused a_user_id !
--- error_handler.reset
--- write_information_log (generator + ".update_node_content")
--- create l_parameters.make (3)
--- l_parameters.put (a_content, "content")
--- l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
--- l_parameters.put (a_node_id, "nid")
--- sql_change (sql_update_node_content, l_parameters)
--- end
-
feature {NONE} -- Implementation
store_node (a_node: CMS_NODE)
@@ -273,9 +228,9 @@ feature {NONE} -- Queries
-- SQL Query to retrieve all nodes.
--| note: {CMS_NODE_API}.trashed = -1
- sql_select_node_by_id: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes WHERE nid =:nid ORDER BY revision desc, publish desc LIMIT 1;"
+ sql_select_node_by_id: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes WHERE nid =:nid ORDER BY revision DESC, publish DESC LIMIT 1;"
- sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes ORDER BY nid desc, publish desc LIMIT :rows OFFSET :offset ;"
+ sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes ORDER BY nid DESC, publish DESC LIMIT :rows OFFSET :offset ;"
sql_insert_node: STRING = "INSERT INTO nodes (revision, type, title, summary, content, format, publish, created, changed, status, author) VALUES (1, :type, :title, :summary, :content, :format, :publish, :created, :changed, :status, :author);"
-- SQL Insert to add a new node.
diff --git a/src/configuration/cms_default_setup.e b/src/configuration/cms_default_setup.e
index 6730fb5..9a16640 100644
--- a/src/configuration/cms_default_setup.e
+++ b/src/configuration/cms_default_setup.e
@@ -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
diff --git a/src/modules/cms_debug_module.e b/src/modules/cms_debug_module.e
index c851be6..9b51d1b 100644
--- a/src/modules/cms_debug_module.e
+++ b/src/modules/cms_debug_module.e
@@ -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)
+ --
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
diff --git a/src/persistence/cms_storage_null.e b/src/persistence/cms_storage_null.e
index 37ada00..17028e6 100644
--- a/src/persistence/cms_storage_null.e
+++ b/src/persistence/cms_storage_null.e
@@ -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)
+ -- .
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
diff --git a/src/persistence/cms_storage_sql_builder.e b/src/persistence/cms_storage_sql_builder.e
deleted file mode 100644
index d43ea79..0000000
--- a/src/persistence/cms_storage_sql_builder.e
+++ /dev/null
@@ -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
diff --git a/src/persistence/core/cms_core_storage_i.e b/src/persistence/core/cms_core_storage_i.e
index 6267dba..89926de 100644
--- a/src/persistence/core/cms_core_storage_i.e
+++ b/src/persistence/core/cms_core_storage_i.e
@@ -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)
diff --git a/src/persistence/core/cms_core_storage_sql_i.e b/src/persistence/core/cms_core_storage_sql_i.e
index 07a5910..c21305f 100644
--- a/src/persistence/core/cms_core_storage_sql_i.e
+++ b/src/persistence/core/cms_core_storage_sql_i.e
@@ -18,6 +18,123 @@ inherit
SHARED_LOGGER
+feature -- URL aliases
+
+ set_path_alias (a_source: READABLE_STRING_8; a_alias: READABLE_STRING_8)
+ --
+ 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)
+ --
+ 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)
+ --
+ 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
+ --
+ 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
+ --
+ 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)
diff --git a/src/persistence/cms_proxy_storage_sql.e b/src/persistence/sql/cms_proxy_storage_sql.e
similarity index 100%
rename from src/persistence/cms_proxy_storage_sql.e
rename to src/persistence/sql/cms_proxy_storage_sql.e
diff --git a/src/persistence/sql/cms_storage_sql.e b/src/persistence/sql/cms_storage_sql.e
new file mode 100644
index 0000000..afd4793
--- /dev/null
+++ b/src/persistence/sql/cms_storage_sql.e
@@ -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
diff --git a/src/persistence/sql/cms_storage_sql_builder.e b/src/persistence/sql/cms_storage_sql_builder.e
new file mode 100644
index 0000000..6000207
--- /dev/null
+++ b/src/persistence/sql/cms_storage_sql_builder.e
@@ -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
diff --git a/src/persistence/cms_storage_sql_i.e b/src/persistence/sql/cms_storage_sql_i.e
similarity index 100%
rename from src/persistence/cms_storage_sql_i.e
rename to src/persistence/sql/cms_storage_sql_i.e
diff --git a/src/persistence/user/cms_user_storage_null.e b/src/persistence/user/cms_user_storage_null.e
new file mode 100644
index 0000000..7422618
--- /dev/null
+++ b/src/persistence/user/cms_user_storage_null.e
@@ -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
diff --git a/src/service/cms_api.e b/src/service/cms_api.e
index d9bbf54..655ed43 100644
--- a/src/service/cms_api.e
+++ b/src/service/cms_api.e
@@ -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
diff --git a/src/service/cms_module.e b/src/service/cms_module.e
index 58b048d..adc48c6 100644
--- a/src/service/cms_module.e
+++ b/src/service/cms_module.e
@@ -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
diff --git a/src/service/cms_service.e b/src/service/cms_service.e
index 7153654..918d0ef 100644
--- a/src/service/cms_service.e
+++ b/src/service/cms_service.e
@@ -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
--
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)
diff --git a/src/service/path/cms_router.e b/src/service/path/cms_router.e
new file mode 100644
index 0000000..fdc0452
--- /dev/null
+++ b/src/service/path/cms_router.e
@@ -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
diff --git a/src/service/response/cms_response.e b/src/service/response/cms_response.e
index 13db564..18d99d4 100644
--- a/src/service/response/cms_response.e
+++ b/src/service/response/cms_response.e
@@ -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)
diff --git a/src/support/cms_string_formatter.e b/src/support/cms_string_formatter.e
new file mode 100644
index 0000000..19f394b
--- /dev/null
+++ b/src/support/cms_string_formatter.e
@@ -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