diff --git a/examples/demo/site/config/cms.ini b/examples/demo/site/config/cms.ini index 682dd5c..03c4f01 100644 --- a/examples/demo/site/config/cms.ini +++ b/examples/demo/site/config/cms.ini @@ -22,6 +22,7 @@ email=noreply@example.com # Name of website theme. theme=bootstrap + [notification] # By default, notification.email = site.email # you can change here the email that will receive internal messages. @@ -34,7 +35,7 @@ subject_prefix=[Eiffel CMS] #from=... smtp=localhost:25 #sendmail=site\bin\roc_sendmail.bat -output=site\db\mailer.log +output=site\db\mails [modules] # Module status @@ -56,6 +57,9 @@ output=site\db\mailer.log #openid.token= #oauth.token= -[admin] + +[administration] +base_path=/roc-admin +#theme=admin # CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none) installation_access=all diff --git a/modules/admin/cms_admin_module.e b/modules/admin/cms_admin_module.e index b59d893..5fbdab3 100644 --- a/modules/admin/cms_admin_module.e +++ b/modules/admin/cms_admin_module.e @@ -9,13 +9,10 @@ class inherit CMS_MODULE redefine - setup_hooks, permissions end - CMS_HOOK_MENU_SYSTEM_ALTER - - CMS_HOOK_RESPONSE_ALTER + CMS_ADMINISTRABLE create make @@ -35,83 +32,18 @@ feature -- Access name: STRING = "admin" -feature {CMS_API} -- Module Initialization +feature {CMS_EXECUTION} -- Administration + + administration: CMS_ADMIN_MODULE_ADMINISTRATION + do + create Result.make (Current) + end feature -- Access: router setup_router (a_router: WSF_ROUTER; a_api: CMS_API) -- do - configure_web (a_api, a_router) - end - - configure_web (a_api: CMS_API; a_router: WSF_ROUTER) - local - l_admin_handler: CMS_ADMIN_HANDLER - - l_modules_handler: CMS_ADMIN_MODULES_HANDLER - l_users_handler: CMS_ADMIN_USERS_HANDLER - l_roles_handler: CMS_ADMIN_ROLES_HANDLER - - l_user_handler: CMS_USER_HANDLER - l_role_handler: CMS_ROLE_HANDLER - l_admin_logs_handler: CMS_LOGS_HANDLER - - l_admin_cache_handler: CMS_ADMIN_CACHE_HANDLER - l_admin_export_handler: CMS_ADMIN_EXPORT_HANDLER - l_admin_import_handler: CMS_ADMIN_IMPORT_HANDLER - l_admin_path_alias_handler: CMS_ADMIN_PATH_ALIAS_HANDLER - - l_uri_mapping: WSF_URI_MAPPING - do - create l_admin_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin", l_admin_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_modules_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/modules", l_modules_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_users_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/users", l_users_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_roles_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/roles", l_roles_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_admin_logs_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/logs", l_admin_logs_handler) - a_router.map (l_uri_mapping, a_router.methods_get) - - create l_admin_path_alias_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/path_alias", l_admin_path_alias_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - - create l_admin_cache_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/cache", l_admin_cache_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_admin_export_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/export", l_admin_export_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_admin_import_handler.make (a_api) - create l_uri_mapping.make_trailing_slash_ignored ("/admin/import", l_admin_import_handler) - a_router.map (l_uri_mapping, a_router.methods_get_post) - - create l_user_handler.make (a_api) - a_router.handle ("/admin/add/user", l_user_handler, a_router.methods_get_post) - a_router.handle ("/admin/user/{id}", l_user_handler, a_router.methods_get) - a_router.handle ("/admin/user/{id}/edit", l_user_handler, a_router.methods_get_post) - a_router.handle ("/admin/user/{id}/delete", l_user_handler, a_router.methods_get_post) - - create l_role_handler.make (a_api) - a_router.handle ("/admin/add/role", l_role_handler, a_router.methods_get_post) - a_router.handle ("/admin/role/{id}", l_role_handler, a_router.methods_get) - a_router.handle ("/admin/role/{id}/edit", l_role_handler, a_router.methods_get_post) - a_router.handle ("/admin/role/{id}/delete", l_role_handler, a_router.methods_get_post) end feature -- Security @@ -121,57 +53,7 @@ feature -- Security do Result := Precursor Result.force ("access admin") - Result.force ("admin users") - Result.force ("admin roles") - Result.force ("admin modules") - Result.force ("admin cache") - Result.force ("admin core caches") Result.force ("clear blocks cache") - Result.force ("admin export") - Result.force ("admin import") - end - -feature -- Hooks - - setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) - -- - do - a_hooks.subscribe_to_menu_system_alter_hook (Current) - a_hooks.subscribe_to_response_alter_hook (Current) - end - - response_alter (a_response: CMS_RESPONSE) - -- - do - a_response.add_style (a_response.url ("/module/" + name + "/files/css/admin.css", Void), Void) - end - - menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) - local - lnk: CMS_LOCAL_LINK - admin_lnk: CMS_LINK_COMPOSITE - do - if a_response.api.user_is_authenticated then - admin_lnk := a_menu_system.management_menu.new_composite_item ("Admin", "admin") - - create lnk.make ("Module", "admin/modules") - lnk.set_permission_arguments (<<"manage module">>) - admin_lnk.extend (lnk) - - -- Per module cache permission! - create lnk.make ("Cache", "admin/cache") - lnk.set_permission_arguments (<<"admin cache">>) - admin_lnk.extend (lnk) - - -- Per module export permission! - create lnk.make ("Export", "admin/export") - lnk.set_permission_arguments (<<"admin export">>) - admin_lnk.extend (lnk) - -- Per module import permission! - create lnk.make ("Import", "admin/import") - lnk.set_permission_arguments (<<"admin import">>) - admin_lnk.extend (lnk) - end end note diff --git a/modules/admin/cms_admin_module_administration.e b/modules/admin/cms_admin_module_administration.e new file mode 100644 index 0000000..befb5d2 --- /dev/null +++ b/modules/admin/cms_admin_module_administration.e @@ -0,0 +1,159 @@ +note + description: "Summary description for {CMS_ADMIN_MODULE_ADMINISTRATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_ADMIN_MODULE_ADMINISTRATION + +inherit + CMS_MODULE_ADMINISTRATION [CMS_ADMIN_MODULE] + redefine + setup_hooks, + permissions + end + + CMS_HOOK_MENU_SYSTEM_ALTER + + CMS_HOOK_RESPONSE_ALTER + +create + make + +feature -- Security + + permissions: LIST [READABLE_STRING_8] + -- List of permission ids, used by this module, and declared. + do + Result := Precursor + Result.force ("access admin") + Result.force ("admin users") + Result.force ("admin roles") + Result.force ("admin modules") + Result.force ("admin cache") + Result.force ("admin core caches") + Result.force ("clear blocks cache") + Result.force ("admin export") + Result.force ("admin import") + end + +feature {NONE} -- Router/administration + + setup_administration_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- + local + l_admin_handler: CMS_ADMIN_HANDLER + + l_modules_handler: CMS_ADMIN_MODULES_HANDLER + l_users_handler: CMS_ADMIN_USERS_HANDLER + l_roles_handler: CMS_ADMIN_ROLES_HANDLER + + l_user_handler: CMS_USER_HANDLER + l_role_handler: CMS_ROLE_HANDLER + l_admin_logs_handler: CMS_LOGS_HANDLER + + l_admin_cache_handler: CMS_ADMIN_CACHE_HANDLER + l_admin_export_handler: CMS_ADMIN_EXPORT_HANDLER + l_admin_import_handler: CMS_ADMIN_IMPORT_HANDLER + l_admin_path_alias_handler: CMS_ADMIN_PATH_ALIAS_HANDLER + + l_uri_mapping: WSF_URI_MAPPING + do + create l_admin_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("", l_admin_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_modules_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/modules", l_modules_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_users_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/users", l_users_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_roles_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/roles", l_roles_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_admin_logs_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/logs", l_admin_logs_handler) + a_router.map (l_uri_mapping, a_router.methods_get) + + create l_admin_path_alias_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/path_alias", l_admin_path_alias_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + + create l_admin_cache_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/cache", l_admin_cache_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_admin_export_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/export", l_admin_export_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_admin_import_handler.make (a_api) + create l_uri_mapping.make_trailing_slash_ignored ("/import", l_admin_import_handler) + a_router.map (l_uri_mapping, a_router.methods_get_post) + + create l_user_handler.make (a_api) + a_router.handle ("/add/user", l_user_handler, a_router.methods_get_post) + a_router.handle ("/user/{id}", l_user_handler, a_router.methods_get) + a_router.handle ("/user/{id}/edit", l_user_handler, a_router.methods_get_post) + a_router.handle ("/user/{id}/delete", l_user_handler, a_router.methods_get_post) + + create l_role_handler.make (a_api) + a_router.handle ("/add/role", l_role_handler, a_router.methods_get_post) + a_router.handle ("/role/{id}", l_role_handler, a_router.methods_get) + a_router.handle ("/role/{id}/edit", l_role_handler, a_router.methods_get_post) + a_router.handle ("/role/{id}/delete", l_role_handler, a_router.methods_get_post) + end + +feature -- Hooks + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + -- + do + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_response_alter_hook (Current) + end + + response_alter (a_response: CMS_RESPONSE) + -- + do + a_response.add_style (a_response.url ("/module/" + name + "/files/css/admin.css", Void), Void) + end + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + local + lnk: CMS_LOCAL_LINK + admin_lnk: CMS_LINK_COMPOSITE + l_api: CMS_API + do + l_api := a_response.api + if l_api.user_is_authenticated then + admin_lnk := a_menu_system.management_menu.new_composite_item ("Admin", l_api.administration_path_location ("")) + + create lnk.make ("Module", l_api.administration_path_location ("modules")) + lnk.set_permission_arguments (<<"manage module">>) + admin_lnk.extend (lnk) + + -- Per module cache permission! + create lnk.make ("Cache", l_api.administration_path_location ("cache")) + lnk.set_permission_arguments (<<"admin cache">>) + admin_lnk.extend (lnk) + + -- Per module export permission! + create lnk.make ("Export", l_api.administration_path_location ("export")) + lnk.set_permission_arguments (<<"admin export">>) + admin_lnk.extend (lnk) + -- Per module import permission! + create lnk.make ("Import", l_api.administration_path_location ("import")) + lnk.set_permission_arguments (<<"admin import">>) + admin_lnk.extend (lnk) + end + end + + +end diff --git a/modules/admin/handler/cms_admin_modules_handler.e b/modules/admin/handler/cms_admin_modules_handler.e index 388927b..3a57e55 100644 --- a/modules/admin/handler/cms_admin_modules_handler.e +++ b/modules/admin/handler/cms_admin_modules_handler.e @@ -204,10 +204,10 @@ feature -- Execution create l_mods_to_install.make (0) across - a_response.api.setup.modules as ic + api.setup.modules as ic loop mod := ic.item - if not a_response.api.is_module_installed (mod) then + if not api.is_module_installed (mod) then l_mods_to_install.extend (mod) else create l_extra.make_empty @@ -286,10 +286,10 @@ feature -- Execution create Result.make (a_response.url (a_response.location, Void), "modules_collection") create l_mods_to_install.make (0) across - a_response.api.setup.modules as ic + api.setup.modules as ic loop mod := ic.item - if not a_response.api.is_module_installed (mod) then + if not api.is_module_installed (mod) then l_mods_to_install.extend (mod) end end diff --git a/modules/admin/handler/cms_admin_response.e b/modules/admin/handler/cms_admin_response.e index b9dbbb1..ef5512e 100644 --- a/modules/admin/handler/cms_admin_response.e +++ b/modules/admin/handler/cms_admin_response.e @@ -23,14 +23,14 @@ feature -- Process l_package: READABLE_STRING_8 do create l_admin_links.make (5) - l_admin_links.force (["core", <<"admin users">>, local_link ("Users", "admin/users"), "View/Edit/Add Users"]) - l_admin_links.force (["core", <<"admin roles">>, local_link ("Roles", "admin/roles"), "View/Edit/Add Roles"]) - l_admin_links.force (["core", <<"admin modules">>, local_link ("Modules", "admin/modules"), "(un)Install modules"]) - l_admin_links.force (["core", <<"view logs">>, local_link ("Logs", "admin/logs"), "View logs"]) - l_admin_links.force (["core", <<"admin path_alias">>, local_link ("Path Alias", "admin/path_alias"), "Manage path aliases"]) - l_admin_links.force (["support", <<"admin cache">>, local_link ("Cache", "admin/cache"), "Clear caches"]) - l_admin_links.force (["support", <<"admin export">>, local_link ("Export", "admin/export"), "Export CMS contents, and modules contents."]) - l_admin_links.force (["support", <<"admin import">>, local_link ("Import", "admin/import"), "Import CMS contents, and modules contents."]) + l_admin_links.force (["core", <<"admin users">>, administration_link ("Users", "users"), "View/Edit/Add Users"]) + l_admin_links.force (["core", <<"admin roles">>, administration_link ("Roles", "roles"), "View/Edit/Add Roles"]) + l_admin_links.force (["core", <<"admin modules">>, administration_link ("Modules", "modules"), "(un)Install modules"]) + l_admin_links.force (["core", <<"view logs">>, administration_link ("Logs", "logs"), "View logs"]) + l_admin_links.force (["core", <<"admin path_alias">>, administration_link ("Path Alias", "path_alias"), "Manage path aliases"]) + l_admin_links.force (["support", <<"admin cache">>, administration_link ("Cache", "cache"), "Clear caches"]) + l_admin_links.force (["support", <<"admin export">>, administration_link ("Export", "export"), "Export CMS contents, and modules contents."]) + l_admin_links.force (["support", <<"admin import">>, administration_link ("Import", "import"), "Import CMS contents, and modules contents."]) create categories.make_caseless (3) across l_admin_links as ic diff --git a/modules/admin/handler/role/cms_admin_roles_handler.e b/modules/admin/handler/role/cms_admin_roles_handler.e index aeedba8..0c9fb6f 100644 --- a/modules/admin/handler/role/cms_admin_roles_handler.e +++ b/modules/admin/handler/role/cms_admin_roles_handler.e @@ -91,7 +91,7 @@ feature -- HTTP Methods u := ic.item s.append ("
  • ") s.append ("") s.append (html_encoded (u.name)) s.append ("") @@ -101,7 +101,7 @@ feature -- HTTP Methods end if l_response.has_permission ("admin roles") then - s.append (l_response.link ("Add Role", "admin/add/role", Void)) + s.append (l_response.link ("Add Role", api.administration_path_location ("add/role"), Void)) end diff --git a/modules/admin/handler/role/cms_role_form_response.e b/modules/admin/handler/role/cms_role_form_response.e index 7cdec58..0d824fd 100644 --- a/modules/admin/handler/role/cms_role_form_response.e +++ b/modules/admin/handler/role/cms_role_form_response.e @@ -72,9 +72,9 @@ feature -- Process Edit fd := f.last_data end if a_role.has_id then - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), "admin/role/" + a_role.id.out), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "admin/role/" + a_role.id.out + "/edit"), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void), "admin/role/" + a_role.id.out + "/delete"), primary_tabs) + add_to_menu (api.administration_link (translation ("View", Void), "role/" + a_role.id.out), primary_tabs) + add_to_menu (api.administration_link (translation ("Edit", Void), "role/" + a_role.id.out + "/edit"), primary_tabs) + add_to_menu (api.administration_link (translation ("Delete", Void), "role/" + a_role.id.out + "/delete"), primary_tabs) end if attached redirection as l_location then -- FIXME: Hack for now @@ -103,9 +103,9 @@ feature -- Process Delete fd := f.last_data end if a_role.has_id then - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), "admin/role/" + a_role.id.out), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "admin/role/" + a_role.id.out + "/edit"), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void), "admin/role/" + a_role.id.out + "/delete"), primary_tabs) + add_to_menu (api.administration_link (translation ("View", Void), "role/" + a_role.id.out), primary_tabs) + add_to_menu (api.administration_link (translation ("Edit", Void), "role/" + a_role.id.out + "/edit"), primary_tabs) + add_to_menu (api.administration_link (translation ("Delete", Void), "role/" + a_role.id.out + "/delete"), primary_tabs) end if attached redirection as l_location then -- FIXME: Hack for now @@ -283,7 +283,7 @@ feature -- Form create ts.make ("op") ts.set_default_value ("Cancel") ts.set_formmethod ("GET") - ts.set_formaction ("/admin/role/" + a_role.id.out) + ts.set_formaction (api.administration_path ("/role/" + a_role.id.out)) f.extend (ts) end Result := f @@ -434,7 +434,7 @@ feature -- Form api.user_api.save_user_role (a_role) if not api.user_api.has_error then add_success_message ("Permissions updated") - set_redirection (absolute_url ("admin/role/" + a_role.id.out, Void)) + set_redirection (absolute_url (api.administration_path_location ("role/" + a_role.id.out), Void)) else add_error_message ("Error during permissions update operation.") end @@ -458,8 +458,8 @@ feature -- Form if api.user_api.has_error then -- handle error else - add_success_message ("Created Role " + link (l_role, "admin/role/" + u.id.out, Void)) - set_redirection (absolute_url ("admin/role/" + u.id.out, Void)) + add_success_message ("Created Role " + link (l_role, api.administration_path_location ("role/" + u.id.out), Void)) + set_redirection (absolute_url (api.administration_path_location ("role/" + u.id.out), Void)) end else a_form_data.report_invalid_field ("username", "Missing role!") diff --git a/modules/admin/handler/role/cms_role_handler.e b/modules/admin/handler/role/cms_role_handler.e index e145643..a97cfab 100644 --- a/modules/admin/handler/role/cms_role_handler.e +++ b/modules/admin/handler/role/cms_role_handler.e @@ -86,11 +86,11 @@ feature -- HTTP Methods create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) if r.has_permission ("admin roles") then if req.percent_encoded_path_info.ends_with_general ("/edit") then - check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/role/") end + check valid_url: req.percent_encoded_path_info.starts_with_general (api.administration_path ("/role/")) end create edit_response.make (req, res, api) edit_response.execute elseif req.percent_encoded_path_info.ends_with_general ("/delete") then - check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/role/") end + check valid_url: req.percent_encoded_path_info.starts_with_general (api.administration_path ("/role/")) end create edit_response.make (req, res, api) edit_response.execute else @@ -192,7 +192,7 @@ feature {NONE} -- New role local edit_response: CMS_ROLE_FORM_RESPONSE do - if req.percent_encoded_path_info.starts_with_general ("/admin/add/role") then + if req.percent_encoded_path_info.starts_with_general (api.administration_path ("/add/role")) then create edit_response.make (req, res, api) edit_response.execute else diff --git a/modules/admin/handler/role/cms_role_view_response.e b/modules/admin/handler/role/cms_role_view_response.e index a6887ae..c532221 100644 --- a/modules/admin/handler/role/cms_role_view_response.e +++ b/modules/admin/handler/role/cms_role_view_response.e @@ -52,16 +52,17 @@ feature -- Execution s: STRING do a_response.set_value (a_role, "role") - create lnk.make (a_response.translation ("View", Void), "admin/role/" + a_role.id.out) + lnk := api.administration_link (a_response.translation ("View", Void), "role/" + a_role.id.out) lnk.set_is_active (True) lnk.set_weight (1) a_response.add_to_primary_tabs (lnk) - create lnk.make (a_response.translation ("Edit", Void), "admin/role/" + a_role.id.out + "/edit") + + lnk := api.administration_link (a_response.translation ("Edit", Void), "role/" + a_role.id.out + "/edit") lnk.set_weight (2) a_response.add_to_primary_tabs (lnk) if a_role /= Void and then a_role.id > 0 then - create lnk.make (a_response.translation ("Delete", Void), "admin/role/" + a_role.id.out + "/delete") + lnk := api.administration_link (a_response.translation ("Delete", Void), "role/" + a_role.id.out + "/delete") lnk.set_weight (3) a_response.add_to_primary_tabs (lnk) end diff --git a/modules/admin/handler/user/cms_admin_users_handler.e b/modules/admin/handler/user/cms_admin_users_handler.e index a1054fe..735fdd4 100644 --- a/modules/admin/handler/user/cms_admin_users_handler.e +++ b/modules/admin/handler/user/cms_admin_users_handler.e @@ -89,7 +89,7 @@ feature -- HTTP Methods end create s_pager.make_empty - create l_page_helper.make ("admin/users/?page={page}&size={size}", user_api.users_count.as_natural_64, 25) -- FIXME: Make this default page size a global CMS settings + create l_page_helper.make (api.administration_path_location ("users/?page={page}&size={size}"), user_api.users_count.as_natural_64, 25) -- FIXME: Make this default page size a global CMS settings l_page_helper.get_setting_from_request (req) if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then l_page_helper.append_to_html (l_response, s_pager) @@ -107,7 +107,7 @@ feature -- HTTP Methods u := ic.item s.append ("
  • ") s.append ("") l_display_name := user_api.user_display_name (u) s.append (html_encoded (l_display_name)) @@ -151,7 +151,7 @@ feature -- HTTP Methods s.append (s_pager) if l_response.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then - s.append (l_response.link ("Add User", "admin/add/user", Void)) + s.append (api.link ("Add User", api.administration_path_location ("add/user"), Void)) end l_response.set_main_content (s) diff --git a/modules/admin/handler/user/cms_user_form_response.e b/modules/admin/handler/user/cms_user_form_response.e index 6fccfa7..c88518b 100644 --- a/modules/admin/handler/user/cms_user_form_response.e +++ b/modules/admin/handler/user/cms_user_form_response.e @@ -72,9 +72,9 @@ feature -- Process Edit fd := f.last_data end if a_user.has_id then - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void),"admin/user/" + a_user.id.out), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void),"admin/user/" + a_user.id.out + "/edit"), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void),"admin/user/" + a_user.id.out + "/delete"), primary_tabs) + add_to_menu (api.administration_link (translation ("View", Void), "user/" + a_user.id.out), primary_tabs) + add_to_menu (api.administration_link (translation ("Edit", Void), "user/" + a_user.id.out + "/edit"), primary_tabs) + add_to_menu (api.administration_link (translation ("Delete", Void), "user/" + a_user.id.out + "/delete"), primary_tabs) end if attached redirection as l_location then -- FIXME: Hack for now @@ -103,9 +103,9 @@ feature -- Process Delete fd := f.last_data end if a_user.has_id then - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void),"admin/user/" + a_user.id.out ), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void),"admin/user/" + a_user.id.out + "/edit"), primary_tabs) - add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void),"admin/user/" + a_user.id.out + "/delete"), primary_tabs) + add_to_menu (api.administration_link (translation ("View", Void),"user/" + a_user.id.out ), primary_tabs) + add_to_menu (api.administration_link (translation ("Edit", Void),"user/" + a_user.id.out + "/edit"), primary_tabs) + add_to_menu (api.administration_link (translation ("Delete", Void),"user/" + a_user.id.out + "/delete"), primary_tabs) end if attached redirection as l_location then -- FIXME: Hack for now @@ -180,7 +180,7 @@ feature -- Form if a_user /= Void then l_user := a_user if l_user.has_id then - create {CMS_LOCAL_LINK} lnk.make (translation ("View", Void),"admin/user/" + l_user.id.out ) + lnk := api.administration_link (translation ("View", Void),"user/" + l_user.id.out) change_user (fd, a_user) s := "modified" set_redirection (lnk.location) @@ -302,7 +302,7 @@ feature -- Form create ts.make ("op") ts.set_default_value ("Cancel") ts.set_formmethod ("GET") - ts.set_formaction ("/admin/user/" + a_user.id.out) + ts.set_formaction (api.administration_path ("/user/" + a_user.id.out)) f.extend (ts) end diff --git a/modules/admin/handler/user/cms_user_handler.e b/modules/admin/handler/user/cms_user_handler.e index 28656ff..5f01136 100644 --- a/modules/admin/handler/user/cms_user_handler.e +++ b/modules/admin/handler/user/cms_user_handler.e @@ -86,11 +86,11 @@ feature -- HTTP Methods create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) if r.has_permission ("admin users") then if req.percent_encoded_path_info.ends_with_general ("/edit") then - check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/user/") end + check valid_url: req.percent_encoded_path_info.starts_with_general (api.administration_path ("/user/")) end create edit_response.make (req, res, api) edit_response.execute elseif req.percent_encoded_path_info.ends_with_general ("/delete") then - check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/user/") end + check valid_url: req.percent_encoded_path_info.starts_with_general (api.administration_path ("/user/")) end create edit_response.make (req, res, api) edit_response.execute else @@ -192,7 +192,7 @@ feature {NONE} -- New User local edit_response: CMS_USER_FORM_RESPONSE do - if req.percent_encoded_path_info.starts_with ("/admin/add/user") then + if req.percent_encoded_path_info.starts_with (api.administration_path ("/add/user")) then create edit_response.make (req, res, api) edit_response.execute else diff --git a/modules/admin/handler/user/cms_user_view_response.e b/modules/admin/handler/user/cms_user_view_response.e index 7a9fd2e..00fccc6 100644 --- a/modules/admin/handler/user/cms_user_view_response.e +++ b/modules/admin/handler/user/cms_user_view_response.e @@ -53,17 +53,17 @@ feature -- Execution ago: DATE_TIME_AGO_CONVERTER do a_response.set_value (a_user, "user") - create lnk.make (a_response.translation ("View", Void), "admin/user/" + a_user.id.out) + lnk := api.administration_link (a_response.translation ("View", Void), "user/" + a_user.id.out) lnk.set_is_active (True) lnk.set_weight (1) a_response.add_to_primary_tabs (lnk) - create lnk.make (a_response.translation ("Edit", Void), "admin/user/" + a_user.id.out + "/edit") + lnk := api.administration_link (a_response.translation ("Edit", Void), "user/" + a_user.id.out + "/edit") lnk.set_permission_arguments (<<"manage admin", "manage users", "manage own user">>) lnk.set_weight (2) a_response.add_to_primary_tabs (lnk) if a_user /= Void and then a_user.id > 0 then - create lnk.make (a_response.translation ("Delete", Void), "admin/user/" + a_user.id.out + "/delete") + lnk := api.administration_link (a_response.translation ("Delete", Void), "user/" + a_user.id.out + "/delete") lnk.set_weight (3) a_response.add_to_primary_tabs (lnk) end @@ -102,7 +102,7 @@ feature -- Execution across l_roles as ic loop l_role := ic.item s.append ("
  • ") - s.append (link (l_role.name, "admin/role/" + l_role.id.out, Void)) + s.append (link (l_role.name, api.administration_path_location ("role/" + l_role.id.out), Void)) s.append ("
  • ") if request.query_parameter ("debug") /= Void then s.append ("
    Permissions:
    ") diff --git a/modules/auth/cms_authentication_module.e b/modules/auth/cms_authentication_module.e index a1b24bb..e5f1712 100644 --- a/modules/auth/cms_authentication_module.e +++ b/modules/auth/cms_authentication_module.e @@ -13,6 +13,8 @@ inherit permissions end + CMS_ADMINISTRABLE + CMS_HOOK_AUTO_REGISTER CMS_HOOK_RESPONSE_ALTER @@ -62,10 +64,16 @@ feature -- Access Result.force ("account activate") Result.force ("account reject") Result.force ("account reactivate") - Result.force ("admin registration") Result.force ("change own username") end +feature {CMS_EXECUTION} -- Administration + + administration: CMS_AUTHENTICATION_MODULE_ADMINISTRATION + do + create Result.make (Current) + end + feature -- Access: docs root_dir: PATH @@ -91,7 +99,6 @@ feature -- Router -- do configure_web (a_api, a_router) - configure_web_admin (a_api, a_router) end configure_web (a_api: CMS_API; a_router: WSF_ROUTER) @@ -116,13 +123,6 @@ feature -- Router a_router.handle ("/account/change/{field}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_change_field (a_api, ?, ?)), a_router.methods_get_post) end - - configure_web_admin (a_api: CMS_API; a_router: WSF_ROUTER) - -- Configure router mapping for admin web interface. - do - a_router.handle ("/admin/pending-registrations/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_admin_pending_registrations (?, ?, a_api)), a_router.methods_get) - end - feature -- Hooks configuration setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) @@ -194,9 +194,10 @@ feature -- Hooks configuration a_menu_system.primary_menu.extend (lnk) -- Add the link to the taxonomy to the main menu - if a_response.has_permission ("admin registration") then - create lnk.make ("Registration", "admin/pending-registrations/") - a_menu_system.management_menu.extend_into (lnk, "Admin", "admin") + if a_response.has_permission ("access admin") then + create lnk.make ("Administration", a_response.api.administration_path_location (Void)) + lnk.set_weight (999) + a_menu_system.navigation_menu.extend (lnk) end end @@ -797,97 +798,6 @@ feature -- Handler r.execute end - handle_admin_pending_registrations (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API) - local - l_response: CMS_RESPONSE - s: STRING - u: CMS_TEMP_USER - l_page_helper: CMS_PAGINATION_GENERATOR - s_pager: STRING - l_count: INTEGER - l_user_api: CMS_USER_API - do - -- At the moment the template are hardcoded, but we can - -- get them from the configuration file and load them into - -- the setup class. - - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) - if - l_response.has_permission ("admin registration") - then - l_user_api := api.user_api - - l_count := l_user_api.temp_users_count - - create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) - - create s.make_empty - if l_count > 1 then - l_response.set_title ("Listing " + l_count.out + " Pending Registrations") - else - l_response.set_title ("Listing " + l_count.out + " Pending Registration") - end - - create s_pager.make_empty - create l_page_helper.make ("admin/pending-registrations/?page={page}&size={size}", l_user_api.temp_users_count.as_natural_64, 25) -- FIXME: Make this default page size a global CMS settings - l_page_helper.get_setting_from_request (req) - if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then - l_page_helper.append_to_html (l_response, s_pager) - if l_page_helper.page_size > 25 then - s.append (s_pager) - end - end - - if attached l_user_api.temp_recent_users (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size)) as lst then - s.append ("
    %N") - end - -- Again the pager at the bottom, if needed - s.append (s_pager) - - l_response.set_main_content (s) - l_response.execute - else - l_response.execute - end - end - block_list: ITERABLE [like {CMS_BLOCK}.name] do Result := <<"register", "reactivate", "new_password", "reset_password">> diff --git a/modules/auth/cms_authentication_module_administration.e b/modules/auth/cms_authentication_module_administration.e new file mode 100644 index 0000000..e8a984d --- /dev/null +++ b/modules/auth/cms_authentication_module_administration.e @@ -0,0 +1,157 @@ +note + description: "Summary description for {CMS_AUTHENTICATION_MODULE_ADMINISTRATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_AUTHENTICATION_MODULE_ADMINISTRATION + +inherit + CMS_MODULE_ADMINISTRATION [CMS_AUTHENTICATION_MODULE] + redefine + setup_hooks, + permissions + end + + CMS_HOOK_AUTO_REGISTER + + CMS_HOOK_MENU_SYSTEM_ALTER + +create + make + +feature -- Security + + permissions: LIST [READABLE_STRING_8] + -- List of permission ids, used by this module, and declared. + do + Result := Precursor + Result.force ("admin registration") + end + +feature {NONE} -- Router/administration + + setup_administration_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- + do + a_router.handle ("/pending-registrations/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_admin_pending_registrations (?, ?, a_api)), a_router.methods_get) + end + +feature -- Request handling + + handle_admin_pending_registrations (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API) + local + l_response: CMS_RESPONSE + s: STRING + u: CMS_TEMP_USER + l_page_helper: CMS_PAGINATION_GENERATOR + s_pager: STRING + l_count: INTEGER + l_user_api: CMS_USER_API + do + -- At the moment the template are hardcoded, but we can + -- get them from the configuration file and load them into + -- the setup class. + + create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + if + l_response.has_permission ("admin registration") + then + l_user_api := api.user_api + + l_count := l_user_api.temp_users_count + + create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) + + create s.make_empty + if l_count > 1 then + l_response.set_title ("Listing " + l_count.out + " Pending Registrations") + else + l_response.set_title ("Listing " + l_count.out + " Pending Registration") + end + + create s_pager.make_empty + create l_page_helper.make (api.administration_path_location ("pending-registrations/?page={page}&size={size}"), l_user_api.temp_users_count.as_natural_64, 25) -- FIXME: Make this default page size a global CMS settings + l_page_helper.get_setting_from_request (req) + if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then + l_page_helper.append_to_html (l_response, s_pager) + if l_page_helper.page_size > 25 then + s.append (s_pager) + end + end + + if attached l_user_api.temp_recent_users (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size)) as lst then + s.append ("
      %N") + across + lst as ic + loop + u := ic.item + s.append ("
    • ") + s.append ("User:" + html_encoded (u.name)) + s.append ("
        ") + if attached u.personal_information as l_information then + s.append ("
      • ") + s.append (html_encoded (l_information)) + s.append ("
      • %N") + end + if attached u.email as l_email then + s.append ("
      • ") + s.append (l_email) + s.append ("
      • %N") + end + if attached l_user_api.token_by_temp_user_id (u.id) as l_token then + s.append ("
      • ") + s.append ("") + s.append (html_encoded ("Activate")) + s.append ("") + s.append ("
      • %N") + s.append ("
      • ") + s.append ("") + s.append (html_encoded ("Reject")) + s.append ("") + s.append ("
      • %N") + end + s.append ("
      %N") + s.append ("
    • %N") + end + s.append ("
    %N") + end + -- Again the pager at the bottom, if needed + s.append (s_pager) + + l_response.set_main_content (s) + l_response.execute + else + l_response.execute + end + end + +feature -- Hooks configuration + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + -- Module hooks configuration. + do + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (module) + a_hooks.subscribe_to_value_table_alter_hook (module) + end + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + -- Hook execution on collection of menu contained by `a_menu_system' + -- for related response `a_response'. + local + lnk: CMS_LOCAL_LINK + do + -- Add the link to the taxonomy to the main menu + if a_response.has_permission ("admin registration") then + create lnk.make ("Registration", a_response.api.administration_path_location ("pending-registrations/")) + a_menu_system.management_menu.extend_into (lnk, "Admin", a_response.api.administration_path_location ("")) + end + end + +end diff --git a/modules/feed_aggregator/feed_aggregator_module.e b/modules/feed_aggregator/feed_aggregator_module.e index 74563b6..d6d5160 100644 --- a/modules/feed_aggregator/feed_aggregator_module.e +++ b/modules/feed_aggregator/feed_aggregator_module.e @@ -13,18 +13,17 @@ inherit redefine initialize, setup_hooks, - permissions, feed_aggregator_api end + CMS_ADMINISTRABLE + CMS_HOOK_BLOCK CMS_HOOK_RESPONSE_ALTER CMS_HOOK_MENU_SYSTEM_ALTER - CMS_HOOK_CACHE - create make @@ -42,16 +41,12 @@ feature -- Access name: STRING = "feed_aggregator" - permissions: LIST [READABLE_STRING_8] - -- List of permission ids, used by this module, and declared. - do - Result := Precursor - Result.force (permission__manage_feed_aggregator) - Result.force (permission__clear_feed_cache) - end +feature {CMS_EXECUTION} -- Administration - permission__manage_feed_aggregator: STRING = "manage feed aggregator" - permission__clear_feed_cache: STRING = "clear feed cache" + administration: FEED_AGGREGATOR_MODULE_ADMINISTRATION + do + create Result.make (Current) + end feature {CMS_API} -- Module Initialization @@ -74,7 +69,6 @@ feature -- Access: router local h: WSF_URI_TEMPLATE_HANDLER do - a_router.handle ("/admin/feed_aggregator/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_feed_aggregator_admin (a_api, ?, ?)), a_router.methods_head_get_post) create {WSF_URI_TEMPLATE_AGENT_HANDLER} h.make (agent handle_feed_aggregation (a_api, ?, ?)) a_router.handle ("/feed_aggregation/", h, a_router.methods_head_get) a_router.handle ("/feed_aggregation/{feed_id}", h, a_router.methods_head_get) @@ -82,14 +76,6 @@ feature -- Access: router feature -- Handle - handle_feed_aggregator_admin (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) - local - nyi: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE - do - create nyi.make (req, res, a_api) - nyi.execute - end - handle_feed_aggregation (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) local m: WSF_PAGE_RESPONSE @@ -205,29 +191,10 @@ feature -- Hooks configuration a_hooks.subscribe_to_block_hook (Current) a_hooks.subscribe_to_response_alter_hook (Current) a_hooks.subscribe_to_menu_system_alter_hook (Current) - a_hooks.subscribe_to_cache_hook (Current) end feature -- Hook - clear_cache (a_cache_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_response: CMS_RESPONSE) - -- . - local - p: PATH - dir: DIRECTORY - do - if a_response.has_permissions (<>) then - if a_cache_id_list = Void then - -- Clear all cache. - p := a_response.api.files_location.extended (".cache").extended (name) - create dir.make_with_path (p) - if dir.exists then - dir.recursive_delete - end - end - end - end - block_list: ITERABLE [like {CMS_BLOCK}.name] -- List of block names, managed by current object. local @@ -300,7 +267,7 @@ feature -- Hook do if attached feed_aggregator_api as l_feed_api then if attached l_feed_api.aggregation (a_feed_id) as l_agg then - create l_cache.make (a_response.api.files_location.extended (".cache").extended (name).extended ("feed__" + a_feed_id + "__" + a_count.out + "_" + with_feed_info.out)) + create l_cache.make (l_feed_api.cms_api.cache_location.extended (name).extended ("feed__" + a_feed_id + "__" + a_count.out + "_" + with_feed_info.out)) Result := l_cache.item if Result = Void or l_cache.expired (Void, l_agg.expiration) then @@ -368,9 +335,6 @@ feature -- Hook do if a_response.is_authenticated then a_menu_system.navigation_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds", "feed_aggregation/")) - if a_response.has_permission (permission__manage_feed_aggregator) then - a_menu_system.management_menu.extend_into (create {CMS_LOCAL_LINK}.make ("Feeds (admin)", "admin/feed_aggregator/"), "Admin", "admin") - end end end diff --git a/modules/feed_aggregator/feed_aggregator_module_administration.e b/modules/feed_aggregator/feed_aggregator_module_administration.e new file mode 100644 index 0000000..d2fdcb1 --- /dev/null +++ b/modules/feed_aggregator/feed_aggregator_module_administration.e @@ -0,0 +1,103 @@ +note + description: "Summary description for {FEED_AGGREGATOR_MODULE_ADMINISTRATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + FEED_AGGREGATOR_MODULE_ADMINISTRATION + +inherit + CMS_MODULE_ADMINISTRATION [FEED_AGGREGATOR_MODULE] + redefine + setup_hooks, + permissions + end + + CMS_HOOK_RESPONSE_ALTER + + CMS_HOOK_MENU_SYSTEM_ALTER + + CMS_HOOK_CACHE + +create + make + +feature -- Access + + permissions: LIST [READABLE_STRING_8] + -- List of permission ids, used by this module, and declared. + do + Result := Precursor + Result.force (permission__clear_feed_cache) + Result.force (permission__manage_feed_aggregator) + end + + permission__clear_feed_cache: STRING = "clear feed cache" + + permission__manage_feed_aggregator: STRING = "manage feed aggregator" + +feature {NONE} -- Router/administration + + setup_administration_router (a_router: WSF_ROUTER; a_api: CMS_API) + do + a_router.handle ("/feed_aggregator/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_feed_aggregator_admin (a_api, ?, ?)), a_router.methods_head_get_post) + end + +feature -- Handle + + handle_feed_aggregator_admin (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + nyi: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE + do + create nyi.make (req, res, a_api) + nyi.execute + end + +feature -- Hook + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + -- Module hooks configuration. + do + a_hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_cache_hook (Current) + end + + clear_cache (a_cache_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_response: CMS_RESPONSE) + -- . + local + p: PATH + dir: DIRECTORY + do + if a_response.has_permissions (<>) then + if a_cache_id_list = Void then + -- Clear all cache. + p := a_response.api.cache_location.extended (name) + create dir.make_with_path (p) + if dir.exists then + dir.recursive_delete + end + a_response.add_notice_message ("Cache cleared from " + name) + end + end + end + + response_alter (a_response: CMS_RESPONSE) + do + module.response_alter (a_response) + end + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + -- Hook execution on collection of menu contained by `a_menu_system' + -- for related response `a_response'. + do + if a_response.is_authenticated then + a_menu_system.navigation_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds", "feed_aggregation/")) + if a_response.has_permission (permission__manage_feed_aggregator) then + a_menu_system.management_menu.extend_into (a_response.api.administration_link ("Feeds (admin)", "feed_aggregator/"), "Admin", "admin") + end + end + end + +end diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index 1804e4b..e7eead4 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -250,7 +250,7 @@ feature -- Access: Node -- Update partial user if needed. if Result /= Void then - if attached {CMS_PARTIAL_USER} Result.author as l_partial_author then + if attached {CMS_PARTIAL_USER} Result.author as l_partial_author and then l_partial_author.has_id then if attached cms_api.user_api.user_by_id (l_partial_author.id) as l_author then Result.set_author (l_author) else @@ -259,7 +259,7 @@ feature -- Access: Node end end end - if attached {CMS_PARTIAL_USER} Result.editor as l_partial_editor then + if attached {CMS_PARTIAL_USER} Result.editor as l_partial_editor and then l_partial_editor.has_id then if attached cms_api.user_api.user_by_id (l_partial_editor.id) as l_editor then Result.set_editor (l_editor) else diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 2dcce8f..39a7af2 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -679,10 +679,10 @@ feature {NONE} -- Implementation if attached sql_read_string (7) as l_format then Result.set_format (l_format) end - if attached sql_read_integer_64 (8) as l_author_id then + if attached sql_read_integer_64 (8) as l_author_id and then l_author_id > 0 then Result.set_author (create {CMS_PARTIAL_USER}.make_with_id (l_author_id)) end - if attached sql_read_integer_64 (9) as l_editor_id then + if attached sql_read_integer_64 (9) as l_editor_id and then l_editor_id > 0 then Result.set_editor (create {CMS_PARTIAL_USER}.make_with_id (l_editor_id)) end if attached sql_read_date_time (10) as l_publication_date then diff --git a/modules/node/submodules/page/cms_page_module.e b/modules/node/submodules/page/cms_page_module.e index 9d0dd1f..eb89b74 100644 --- a/modules/node/submodules/page/cms_page_module.e +++ b/modules/node/submodules/page/cms_page_module.e @@ -69,12 +69,14 @@ feature {CMS_API} -- Module Initialization p1.set_title ("Welcome") p1.set_content ("Welcome, you are using the ROC Eiffel CMS", Void, Void) -- Use default format p1.set_author (u) + p1.set_editor (u) l_sql_node_storage.save_node (p1) p2 := ct.new_node (Void) p2.set_title ("A new page example") p2.set_content ("This is the content of a page", Void, Void) -- Use default format p2.set_author (u) + p2.set_editor (u) p2.set_parent (p1) l_sql_node_storage.save_node (p2) end diff --git a/modules/sitemap/cms_sitemap_module.e b/modules/sitemap/cms_sitemap_module.e index 47f3686..2d4a3bc 100644 --- a/modules/sitemap/cms_sitemap_module.e +++ b/modules/sitemap/cms_sitemap_module.e @@ -75,7 +75,7 @@ feature -- Handler d: HTTP_DATE do create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - create l_cache.make (api.files_location.extended ("modules").extended ("sitemap").extended ("sitemap.xml")) + create l_cache.make (api.cache_location.extended (name).extended ("sitemap.xml")) if l_cache.exists and then not l_cache.expired (Void, 24*60*60) -- 1 day diff --git a/modules/taxonomy/cms_taxonomy_module.e b/modules/taxonomy/cms_taxonomy_module.e index b4c9534..a61745d 100644 --- a/modules/taxonomy/cms_taxonomy_module.e +++ b/modules/taxonomy/cms_taxonomy_module.e @@ -21,7 +21,7 @@ inherit permissions end - CMS_HOOK_MENU_SYSTEM_ALTER + CMS_ADMINISTRABLE CMS_HOOK_RESPONSE_ALTER @@ -46,12 +46,18 @@ feature -- Access -- List of permission ids, used by this module, and declared. do Result := Precursor - Result.force ("admin taxonomy") Result.force ("update any taxonomy") Result.force ("update page taxonomy") -- related to node module Result.force ("update blog taxonomy") -- related to blog module end +feature {CMS_EXECUTION} -- Administration + + administration: CMS_TAXONOMY_MODULE_ADMINISTRATION + do + create Result.make (Current) + end + feature {CMS_API} -- Module Initialization initialize (api: CMS_API) @@ -99,7 +105,7 @@ feature {CMS_API} -- Module management Precursor (api) end -feature {CMS_API} -- Access: API +feature {CMS_API, CMS_MODULE_ADMINISTRATION} -- Access: API taxonomy_api: detachable CMS_TAXONOMY_API -- @@ -111,7 +117,6 @@ feature -- Access: router do if attached taxonomy_api as l_taxonomy_api then configure_web (a_api, l_taxonomy_api, a_router) - configure_web_amin (a_api, l_taxonomy_api, a_router) else -- Issue with api/dependencies, -- thus Current module should not be used! @@ -133,45 +138,10 @@ feature -- Access: router a_router.handle ("/taxonomy/vocabulary/{vocid}", l_voc_handler, a_router.methods_get) end - configure_web_amin (a_api: CMS_API; a_taxonomy_api: CMS_TAXONOMY_API; a_router: WSF_ROUTER) - -- Configure router mapping for web interface. - local - l_taxonomy_handler: TAXONOMY_TERM_ADMIN_HANDLER - l_voc_handler: TAXONOMY_VOCABULARY_ADMIN_HANDLER - do - a_router.handle ("/admin/taxonomy/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_admin_taxonomy (?, ?, a_api)), a_router.methods_get) - - create l_taxonomy_handler.make (a_api, a_taxonomy_api) - a_router.handle ("/admin/taxonomy/term/", l_taxonomy_handler, a_router.methods_get_post) - a_router.handle ("/admin/taxonomy/term/{termid}", l_taxonomy_handler, a_router.methods_get_post) - - create l_voc_handler.make (a_api, a_taxonomy_api) - a_router.handle ("/admin/taxonomy/vocabulary/", l_voc_handler, a_router.methods_get_post) - a_router.handle ("/admin/taxonomy/vocabulary/{vocid}", l_voc_handler, a_router.methods_get_post) - end - -feature -- Handler - - handle_admin_taxonomy (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API) - local - l_page: CMS_RESPONSE - lnk: CMS_LOCAL_LINK - do - create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) - create lnk.make ("Admin Vocabularies", "admin/taxonomy/vocabulary/") - l_page.add_to_primary_tabs (lnk) - - create lnk.make ("Create terms", "admin/taxonomy/term/") - l_page.add_to_primary_tabs (lnk) - - l_page.execute - end - feature -- Hooks setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) do - a_hooks.subscribe_to_menu_system_alter_hook (Current) a_hooks.subscribe_to_response_alter_hook (Current) end @@ -180,15 +150,4 @@ feature -- Hooks a_response.add_style (a_response.url ("/module/" + name + "/files/css/taxonomy.css", Void), Void) end - menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) - local - lnk: CMS_LOCAL_LINK - do - -- Add the link to the taxonomy to the main menu - if a_response.has_permission ("admin taxonomy") then - create lnk.make ("Taxonomy", "admin/taxonomy/") - a_menu_system.management_menu.extend_into (lnk, "Admin", "admin") - end - end - end diff --git a/modules/taxonomy/cms_taxonomy_module_administration.e b/modules/taxonomy/cms_taxonomy_module_administration.e new file mode 100644 index 0000000..5d848b3 --- /dev/null +++ b/modules/taxonomy/cms_taxonomy_module_administration.e @@ -0,0 +1,100 @@ +note + description: "Summary description for {CMS_TAXONOMY_MODULE_ADMINISTRATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_TAXONOMY_MODULE_ADMINISTRATION + +inherit + CMS_MODULE_ADMINISTRATION [CMS_TAXONOMY_MODULE] + redefine + setup_hooks, + permissions + end + + CMS_HOOK_MENU_SYSTEM_ALTER + + CMS_HOOK_RESPONSE_ALTER + +create + make + +feature -- Security + + permissions: LIST [READABLE_STRING_8] + -- List of permission ids, used by this module, and declared. + do + Result := Precursor + Result.force ("admin taxonomy") + end + +feature {NONE} -- Router/administration + + setup_administration_router (a_router: WSF_ROUTER; a_api: CMS_API) + do + if attached module.taxonomy_api as l_taxonomy_api then + configure_web_admin (a_api, l_taxonomy_api, a_router) + end + end + + configure_web_admin (a_api: CMS_API; a_taxonomy_api: CMS_TAXONOMY_API; a_router: WSF_ROUTER) + -- Configure router mapping for web interface. + local + l_taxonomy_handler: TAXONOMY_TERM_ADMIN_HANDLER + l_voc_handler: TAXONOMY_VOCABULARY_ADMIN_HANDLER + do + a_router.handle ("/taxonomy/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_admin_taxonomy (?, ?, a_api)), a_router.methods_get) + + create l_taxonomy_handler.make (a_api, a_taxonomy_api) + a_router.handle ("/taxonomy/term/", l_taxonomy_handler, a_router.methods_get_post) + a_router.handle ("/taxonomy/term/{termid}", l_taxonomy_handler, a_router.methods_get_post) + + create l_voc_handler.make (a_api, a_taxonomy_api) + a_router.handle ("/taxonomy/vocabulary/", l_voc_handler, a_router.methods_get_post) + a_router.handle ("/taxonomy/vocabulary/{vocid}", l_voc_handler, a_router.methods_get_post) + end + +feature -- Handler + + handle_admin_taxonomy (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API) + local + l_page: CMS_RESPONSE + lnk: CMS_LOCAL_LINK + do + create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) + create lnk.make ("Admin Vocabularies", api.administration_path_location ("taxonomy/vocabulary/")) + l_page.add_to_primary_tabs (lnk) + + create lnk.make ("Create terms", api.administration_path_location ("taxonomy/term/")) + l_page.add_to_primary_tabs (lnk) + + l_page.execute + end + +feature -- Hooks + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + do + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_response_alter_hook (Current) + end + + response_alter (a_response: CMS_RESPONSE) + do + module.response_alter (a_response) + end + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + local + lnk: CMS_LOCAL_LINK + do + -- Add the link to the taxonomy to the main menu + if a_response.has_permission ("admin taxonomy") then + create lnk.make ("Taxonomy", a_response.api.administration_path_location ("taxonomy/")) + a_menu_system.management_menu.extend_into (lnk, "Admin", "admin") + end + end + +end diff --git a/modules/taxonomy/handler/taxonomy_term_admin_handler.e b/modules/taxonomy/handler/taxonomy_term_admin_handler.e index 9e97d36..c50caf3 100644 --- a/modules/taxonomy/handler/taxonomy_term_admin_handler.e +++ b/modules/taxonomy/handler/taxonomy_term_admin_handler.e @@ -118,7 +118,7 @@ feature -- HTTP Methods else l_page.add_success_message ("Term creation succeed.") s.append ("
    View term: ") - s.append (l_page.link (t.text, "admin/taxonomy/term/" + t.id.out, Void)) + s.append (l_page.link (t.text, api.administration_path_location ("taxonomy/term/" + t.id.out), Void)) s.append ("
    ") if diff --git a/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e b/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e index 9bdcb61..9d9e281 100644 --- a/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e +++ b/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e @@ -88,7 +88,7 @@ feature -- HTTP Methods l_page.add_error_message ("Vocabulary creation failed!") else l_page.add_success_message ("Vocabulary creation succeed!") - l_page.set_redirection ("admin/taxonomy/vocabulary/" + voc.id.out) + l_page.set_redirection (api.administration_path_location ("taxonomy/vocabulary/" + voc.id.out)) end else create {BAD_REQUEST_ERROR_CMS_RESPONSE} l_page.make (req, res, api) @@ -143,7 +143,7 @@ feature -- HTTP Methods end end if not taxonomy_api.has_error then - l_page.add_notice_message (l_page.link ({STRING_32} "Back to vocabulary %"" + l_vocabulary.name + "%"", "admin/taxonomy/vocabulary/" + l_vocabulary.id.out, Void)) + l_page.add_notice_message (l_page.link ({STRING_32} "Back to vocabulary %"" + l_vocabulary.name + "%"", api.administration_path_location ("taxonomy/vocabulary/" + l_vocabulary.id.out), Void)) end l_page.set_main_content (s) else @@ -239,7 +239,7 @@ feature -- HTTP Methods create wtb_row.make (3) wtb.add_row (wtb_row) - create wtb_item.make_with_text (l_page.link (ic.item.text, "admin/taxonomy/term/" + l_term.id.out, Void)) + create wtb_item.make_with_text (l_page.link (ic.item.text, api.administration_path_location ("taxonomy/term/" + l_term.id.out), Void)) wtb_row.set_item (wtb_item, 1) if attached ic.item.description as l_desc then create wtb_item.make_with_text (api.html_encoded (l_desc)) @@ -362,7 +362,7 @@ feature -- HTTP Methods create wtb_row.make (3) wtb.add_row (wtb_row) - create wtb_item.make_with_text (l_page.link (ic.item.name, "admin/taxonomy/vocabulary/" + ic.item.id.out, Void)) + create wtb_item.make_with_text (l_page.link (ic.item.name, api.administration_path_location ("taxonomy/vocabulary/" + ic.item.id.out), Void)) -- if attached ic.item.description as l_desc then -- s.append (" : ") -- s.append (api.html_encoded (l_desc)) @@ -385,7 +385,7 @@ feature -- HTTP Methods wtb_row.set_item (wtb_item, 2) end - s := l_page.link ("edit", "admin/taxonomy/vocabulary/" + voc.id.out, Void) + s := l_page.link ("edit", api.administration_path_location ("taxonomy/vocabulary/" + voc.id.out), Void) create wtb_item.make_with_text (s) wtb_row.set_item (wtb_item, 3) end diff --git a/src/configuration/cms_setup.e b/src/configuration/cms_setup.e index 5c2d179..8f10e0f 100644 --- a/src/configuration/cms_setup.e +++ b/src/configuration/cms_setup.e @@ -36,7 +36,7 @@ feature {NONE} -- Initialization site_url := l_url -- Site name - site_name := text_item_or_default ("site.name", "Another Eiffel ROC Website") + site_name := text_item_or_default ("site.name", "Your ROC CMS") -- Website email used to send email. -- used as real "From:" email. @@ -77,6 +77,13 @@ feature {NONE} -- Initialization temp_location := site_location.extended ("temp") end + -- Location for cache folder + if attached text_item ("cache-dir") as l_cache_dir then + create cache_location.make_from_string (l_cache_dir) + else + cache_location := temp_location.extended ("cache") + end + -- Location for modules folders. if attached text_item ("modules-dir") as l_modules_dir then create modules_location.make_from_string (l_modules_dir) @@ -92,13 +99,23 @@ feature {NONE} -- Initialization end -- Selected theme's name - theme_name := text_item_or_default ("theme", "default") + site_theme_name := text_item_or_default ("theme", "default") + set_theme (site_theme_name) - debug ("refactor_fixme") - fixme ("Review export clause for configuration and environment") + -- Administration + l_url := string_8_item ("administration.base_path") + if l_url /= Void and then not l_url.is_empty then + if l_url [l_url.count] = '/' then + l_url := l_url.substring (1, l_url.count - 1) + end + if l_url [1] /= '/' then + l_url := "/" + l_url + end + create administration_base_path.make_from_string (l_url) + else + create administration_base_path.make_from_string (default_administration_base_path) end - - theme_location := themes_location.extended (theme_name) + administration_theme_name := text_item_or_default ("administration.theme", theme_name) -- TODO: Default to builtin theme? end feature -- Access @@ -296,11 +313,37 @@ feature -- Access: Site -- Optional path defining the front page. -- By default "" or "/". + administration_base_path: IMMUTABLE_STRING_8 + -- Administration base url, default=`default_administration_base_path`. + +feature {NONE} -- Constants + + default_administration_base_path: STRING = "/admin" + feature -- Settings is_debug: BOOLEAN -- Is debug mode enabled? + set_administration_mode + -- Switch to administration mode. + --| - Change theme + --| - .. + do + if is_theme_valid (administration_theme_name) then + set_theme (administration_theme_name) + else + -- Keep previous theme! + end + end + + set_theme (a_name: READABLE_STRING_GENERAL) + -- Set theme to `a_name`. + do + theme_name := a_name.as_string_32 + theme_location := themes_location.extended (theme_name) + end + feature -- Query text_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 @@ -343,7 +386,7 @@ feature -- Query end end -feature -- Access: Theme +feature -- Access: directory site_location: PATH -- Path to CMS site root dir. @@ -353,7 +396,10 @@ feature -- Access: Theme -- (Mainly for uploaded file). files_location: PATH - -- Path to public "files" dir. + -- Path to public "files" dir. + + cache_location: PATH + -- Path to internal cache dir. modules_location: PATH -- Path to modules. @@ -361,9 +407,19 @@ feature -- Access: Theme themes_location: PATH -- Path to themes. +feature -- Access: theme + theme_location: PATH -- Path to a active theme. + is_theme_valid (a_theme_name: READABLE_STRING_GENERAL): BOOLEAN + -- Does `a_theme_name` exists? + local + fu: FILE_UTILITIES + do + Result := fu.directory_path_exists (themes_location.extended (a_theme_name)) + end + theme_information_location: PATH -- Active theme informations. do @@ -373,6 +429,14 @@ feature -- Access: Theme theme_name: READABLE_STRING_32 -- theme name. + site_theme_name: READABLE_STRING_32 + -- Site theme name. + + administration_theme_name: READABLE_STRING_32 + -- Administration theme name. + -- Default: same as site theme. + -- TODO: change to builtin "admin" theme? + feature -- Access mailer: NOTIFICATION_MAILER diff --git a/src/hooks/cms_hook_core_manager.e b/src/hooks/cms_hook_core_manager.e index 8146a9b..b504d46 100644 --- a/src/hooks/cms_hook_core_manager.e +++ b/src/hooks/cms_hook_core_manager.e @@ -212,18 +212,46 @@ feature -- Hook: cache invoke_clear_cache (a_cache_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_response: CMS_RESPONSE) -- Invoke cache hook for identifiers `a_cache_id_list'. + local + retried: BOOLEAN do - if attached subscribers ({CMS_HOOK_CACHE}) as lst then - across - lst as c - loop - if attached {CMS_HOOK_CACHE} c.item as h then - h.clear_cache (a_cache_id_list, a_response) + if not retried then + if attached subscribers ({CMS_HOOK_CACHE}) as lst then + across + lst as c + loop + if attached {CMS_HOOK_CACHE} c.item as h then + safe_call_clear_cache_on_hook (h, a_cache_id_list, a_response) + end end + a_response.clear_cache (a_cache_id_list) end - - a_response.clear_cache (a_cache_id_list) + else + a_response.add_error_message ("Error occurred while clearing cache.") end + rescue + retried := True + retry + end + +feature {NONE} -- Hook: cache + + safe_call_clear_cache_on_hook (a_hook: CMS_HOOK_CACHE; a_cache_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_response: CMS_RESPONSE) + local + retried: BOOLEAN + do + if not retried then + a_hook.clear_cache (a_cache_id_list, a_response) + else + if attached {CMS_MODULE} a_hook as mod then + a_response.add_error_message ("Exception occurred for `clear_cache` [" + mod.name + "]") + else + a_response.add_error_message ("Exception occurred for `clear_cache`") + end + end + rescue + retried := True + retry end feature -- Hook: export diff --git a/src/modules/cms_debug_module.e b/src/modules/cms_debug_module.e index 6a72605..1c795e4 100644 --- a/src/modules/cms_debug_module.e +++ b/src/modules/cms_debug_module.e @@ -107,7 +107,7 @@ feature -- Handler append_info_to ("Assets dir", api.setup.environment.assets_path.utf_8_name, r, s) append_info_to ("Config dir", api.setup.environment.config_path.utf_8_name, r, s) s.append ("
    ") - append_info_to ("Theme", api.setup.theme_name, r, s) + append_info_to ("Theme", api.theme_name, r, s) append_info_to ("Theme location", api.theme_location.utf_8_name, r, s) s.append ("
    ") append_info_to ("Files location", api.files_location.utf_8_name, r, s) @@ -139,7 +139,7 @@ feature -- Handler end note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/src/service/cms_administrable.e b/src/service/cms_administrable.e new file mode 100644 index 0000000..a3d9210 --- /dev/null +++ b/src/service/cms_administrable.e @@ -0,0 +1,36 @@ +note + description: "Interface providing administration module." + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_ADMINISTRABLE + +feature -- Administration + + module_administration: like administration + -- Associated administration module. + do + Result := internal_module_administration + if Result = Void then + Result := administration + internal_module_administration := Result + end + end + +feature {NONE} -- Implementation + + internal_module_administration: detachable like module_administration + -- Cached version of `module_administration`. + +feature {NONE} -- Administration + + administration: CMS_MODULE_ADMINISTRATION [CMS_MODULE] + -- Administration module. + deferred + end + +note + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/src/service/cms_api.e b/src/service/cms_api.e index 1a590f1..4c7ab49 100644 --- a/src/service/cms_api.e +++ b/src/service/cms_api.e @@ -15,6 +15,8 @@ inherit CMS_ENCODERS + CMS_URL_UTILITIES + REFACTORING_HELPER create @@ -43,10 +45,15 @@ feature {NONE} -- Initialize l_module: CMS_MODULE l_enabled_modules: CMS_MODULE_COLLECTION l_uninstalled_mods: detachable ARRAYED_LIST [CMS_MODULE] + s: IMMUTABLE_STRING_8 do -- Initialize site_url initialize_site_url + -- Administration backend + s := setup.administration_base_path + administration_base_path_location := s.shared_substring (2, s.count) + -- Initialize formats. initialize_formats -- Initialize contents. @@ -100,8 +107,8 @@ feature {NONE} -- Initialize l_enabled_modules.remove (ic.item) end end - -- Initialize hooks system - setup_hooks + + -- hooks initialization, is done after site/admin switch. end initialize_site_url @@ -233,16 +240,121 @@ feature -- Access feature -- Access: url - site_url: IMMUTABLE_STRING_8 - -- Site url - base_url: detachable IMMUTABLE_STRING_8 -- Base url if any. --| Usually it is Void, but it could be --| /project/demo/ + site_url: IMMUTABLE_STRING_8 + -- Site url + + is_administration_request (req: WSF_REQUEST): BOOLEAN + do + Result := req.percent_encoded_path_info.starts_with_general (setup.administration_base_path) + end + + administration_path (a_relative_path: detachable READABLE_STRING_8): STRING_8 + do + create Result.make_from_string (setup.administration_base_path) + if a_relative_path /= Void and then not a_relative_path.is_empty then + if a_relative_path[1] /= '/' then + Result.append_character ('/') + end + Result.append (a_relative_path) + end + end + + administration_path_location (a_relative_location: detachable READABLE_STRING_8): STRING_8 + require + no_first_slash: a_relative_location = Void or else not a_relative_location.starts_with_general ("/") + do + create Result.make_from_string (administration_base_path_location) + if a_relative_location /= Void then + Result.append_character ('/') + Result.append (a_relative_location) + end + end + +feature {NONE} -- Url implementation. + + administration_base_path_location: IMMUTABLE_STRING_8 + -- Administration path without first slash! + +feature -- CMS links + + administration_link (a_title: READABLE_STRING_GENERAL; a_location: READABLE_STRING_8): CMS_LOCAL_LINK + do + Result := local_link (a_title, administration_path_location (a_location)) + end + + local_link (a_title: READABLE_STRING_GENERAL; a_location: READABLE_STRING_8): CMS_LOCAL_LINK + do + create Result.make (a_title, a_location) + end + + user_local_link (u: CMS_USER; a_opt_title: detachable READABLE_STRING_GENERAL): CMS_LOCAL_LINK + do + if a_opt_title /= Void then + create Result.make (a_opt_title, user_url (u)) + else + create Result.make (user_display_name (u), user_url (u)) + end + end + + user_html_link (u: CMS_USER): STRING + require + u_with_name: not u.name.is_whitespace + do + Result := link (user_display_name (u), "user/" + u.id.out, Void) + end + +feature -- Helpers: URLs + + location_absolute_url (a_location: READABLE_STRING_8; opts: detachable CMS_API_OPTIONS): STRING + -- Absolute URL for `a_location'. + --| Options `opts' could be + --| - absolute: True|False => return absolute url + --| - query: string => append "?query" + --| - fragment: string => append "#fragment" + do + Result := absolute_url (a_location, opts) + end + + location_url (a_location: READABLE_STRING_8; opts: detachable CMS_API_OPTIONS): STRING + -- URL for `a_location'. + --| Options `opts' could be + --| - absolute: True|False => return absolute url + --| - query: string => append "?query" + --| - fragment: string => append "#fragment" + do + Result := url (a_location, opts) + end + + user_url (u: CMS_USER): like url + require + u_with_id: u.has_id + do + Result := location_url ("user/" + u.id.out, Void) + end + +feature -- Helpers: html links + + user_display_name (u: CMS_USER): READABLE_STRING_32 + do + Result := user_api.user_display_name (u) + end + feature -- Settings + switch_to_administration_mode + do + setup.set_administration_mode + is_administration_mode := True + end + + is_administration_mode: BOOLEAN + -- Is administration mode? + is_debug: BOOLEAN -- Is debug mode enabled? do @@ -646,13 +758,13 @@ feature -- Hooks hooks: CMS_HOOK_CORE_MANAGER -- Manager handling hook subscriptions. -feature {NONE} -- Hooks +feature {CMS_EXECUTION} -- Hooks setup_hooks -- Set up CMS hooks. --| Each module has to opportunity to subscribe to various hooks. local - l_module: CMS_MODULE + l_module: detachable CMS_MODULE l_hooks: like hooks do l_hooks := hooks @@ -661,10 +773,19 @@ feature {NONE} -- Hooks enabled_modules as ic loop l_module := ic.item - if attached {CMS_HOOK_AUTO_REGISTER} l_module as l_auto then - l_auto.auto_subscribe_to_hooks (l_hooks) + if is_administration_mode then + if attached {CMS_ADMINISTRABLE} l_module as adm then + l_module := adm.module_administration + else + l_module := Void + end + end + if l_module /= Void then + if attached {CMS_HOOK_AUTO_REGISTER} l_module as l_auto then + l_auto.auto_subscribe_to_hooks (l_hooks) + end + l_module.setup_hooks (l_hooks) end - l_module.setup_hooks (l_hooks) end end @@ -695,8 +816,10 @@ feature -- Hooks setup_core_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Register hooks associated with the cms core. do - a_hooks.subscribe_to_export_hook (Current) - a_hooks.subscribe_to_import_hook (Current) + if is_administration_mode then + a_hooks.subscribe_to_export_hook (Current) + a_hooks.subscribe_to_import_hook (Current) + end end feature -- Path aliases @@ -813,12 +936,23 @@ feature -- Environment/ theme Result := setup.files_location end + cache_location: PATH + -- CMS internal cache location. + do + Result := setup.cache_location + end + theme_location: PATH -- Active theme location. do Result := setup.theme_location end + theme_name: READABLE_STRING_32 + do + Result := setup.theme_name + end + theme_assets_location: PATH -- assets (js, css, images, etc). do @@ -831,6 +965,11 @@ feature -- Environment/ theme feature -- Environment/ module + 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 + 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 @@ -970,11 +1109,6 @@ feature -- Environment/ modules and theme 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 - feature -- Access: active user user_is_authenticated: BOOLEAN diff --git a/src/service/cms_execution.e b/src/service/cms_execution.e index d74fcf6..0054e0b 100644 --- a/src/service/cms_execution.e +++ b/src/service/cms_execution.e @@ -19,8 +19,7 @@ inherit execute_default, filter_execute, initialize, - initialize_router, - initialize_filter + initialize_router end WSF_NO_PROXY_POLICY @@ -57,10 +56,7 @@ feature {NONE} -- Initialization initialize_cms do - write_debug_log (generator + ".initialize_cms") - -- CMS Initialization - -- for void-safety concern. create {WSF_MAINTENANCE_FILTER} filter end @@ -69,16 +65,7 @@ feature {NONE} -- Initialization -- Initialize `router`. do create_router - -- router setup is delayed toi `initialize_execution`. - -- setup_router - end - - initialize_filter - -- Initialize `filter`. - do - create_filter - -- filter setup is delayed toi `initialize_execution`. - -- setup_filter + -- setup_router: delayed to `initialize_execution`. end initialize_modules @@ -108,7 +95,7 @@ feature -- Access end modules: CMS_MODULE_COLLECTION - -- Configurator of possible modules. + -- Declared modules. feature -- CMS setup @@ -139,14 +126,15 @@ feature -- Settings: router l_router: like router l_module: CMS_MODULE do - api.logger.put_debug (generator + ".setup_router", Void) - -- Configure root of api handler. + l_api := api + l_api.logger.put_debug (generator + ".setup_router", Void) l_router := router + + -- Configure root of api handler. configure_api_root (l_router) -- Include routes from modules. - l_api := api across modules as ic loop @@ -159,6 +147,37 @@ feature -- Settings: router configure_api_file_handler (l_router) end + setup_router_for_administration + -- + local + l_api: like api + l_router: like router + l_module: CMS_MODULE + do + l_api := api + l_router := router + + l_api.logger.put_debug (generator + ".setup_router_for_administration", Void) + + -- Configure root of api handler. + l_router.set_base_url (l_api.administration_path ("")) + + -- Include routes from modules. + across + modules as ic + loop + l_module := ic.item + if + l_module.is_initialized and then + attached {CMS_ADMINISTRABLE} l_module as l_administration and then + attached l_administration.module_administration as adm + then + adm.setup_router (l_router, l_api) + end + end + map_uri ("/install", create {CMS_ADMIN_INSTALL_HANDLER}.make (api), l_router.methods_head_get) + end + configure_api_root (a_router: WSF_ROUTER) local l_root_handler: CMS_ROOT_HANDLER @@ -171,8 +190,6 @@ feature -- Settings: router a_router.handle ("/", l_root_handler, l_methods) a_router.handle ("", l_root_handler, l_methods) map_uri_agent ("/favicon.ico", agent handle_favicon, a_router.methods_head_get) - - map_uri ("/admin/install", create {CMS_ADMIN_INSTALL_HANDLER}.make (api), a_router.methods_head_get) end configure_api_file_handler (a_router: WSF_ROUTER) @@ -217,10 +234,28 @@ feature -- Request execution -- Initialize CMS execution. do request.set_uploaded_file_path (api.temp_location) - setup_filter + if api.is_administration_request (request) then + initialize_administration_execution + else + initialize_site_execution + end + end + + initialize_site_execution + -- Initialize for site execution. + do + api.setup_hooks setup_router end + initialize_administration_execution + -- Initialize for administration execution. + do + api.switch_to_administration_mode + api.setup_hooks + setup_router_for_administration + end + execute -- . do @@ -233,6 +268,7 @@ feature -- Request execution do res.put_header_line ("Date: " + (create {HTTP_DATE}.make_now_utc).string) res.put_header_line ("X-EWF-Server: CMS_v1.0") + Precursor (req, res) end @@ -282,8 +318,6 @@ feature -- Filters setup_filter -- Setup `filter'. do - api.logger.put_debug (generator + ".setup_filter", Void) - append_filter (Current) end feature -- Execution diff --git a/src/service/cms_module.e b/src/service/cms_module.e index 142e73c..7567084 100644 --- a/src/service/cms_module.e +++ b/src/service/cms_module.e @@ -7,10 +7,10 @@ deferred class CMS_MODULE inherit - REFACTORING_HELPER - CMS_ENCODERS + REFACTORING_HELPER + feature -- Access is_enabled: BOOLEAN @@ -80,7 +80,7 @@ feature -- Status is_initialized: BOOLEAN -- Is Current module initialized? -feature {CMS_API} -- Access: API +feature {CMS_API, CMS_MODULE_ADMINISTRATION} -- Access: API module_api: detachable CMS_MODULE_API -- Eventual module api. @@ -180,33 +180,6 @@ feature {CMS_API} -- Module management api.storage.set_custom_value ("is_installed", "no", "module-" + name) end -feature -- Router - - setup_router (a_router: WSF_ROUTER; a_api: CMS_API) - -- Setup url dispatching for Current module. - require - is_initialized: is_initialized - deferred - end - -feature -- Hooks configuration - - setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) - -- Module hooks configuration. - require - is_enabled: is_enabled - do - end - -feature -- Filter - - filters (a_api: CMS_API): detachable LIST [WSF_FILTER] - -- Optional list of filter for Current module. - require - is_enabled: is_enabled - do - end - feature -- Settings enable @@ -225,12 +198,39 @@ feature -- Settings module_disbaled: not is_enabled end -feature -- Hooks +feature -- Filter + + filters (a_api: CMS_API): detachable LIST [WSF_FILTER] + -- Optional list of filter for Current module. + require + is_enabled: is_enabled + do + end + +feature -- Router + + setup_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- Setup url dispatching for Current module. + require + is_initialized: is_initialized + deferred + end + +feature -- Hooks configuration + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + -- Module hooks configuration. + require + is_enabled: is_enabled + do + end + +feature -- Help help_text (a_path: STRING): STRING do debug ("refactor_fixme") - to_implement ("Add the corresponing implementation.") + to_implement ("Add the corresponding implementation.") end create Result.make_empty end diff --git a/src/service/cms_module_administration.e b/src/service/cms_module_administration.e new file mode 100644 index 0000000..b4c6f4c --- /dev/null +++ b/src/service/cms_module_administration.e @@ -0,0 +1,80 @@ +note + description: "[ + Objects that ... + ]" + author: "$Author$" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_MODULE_ADMINISTRATION [G -> CMS_MODULE] + +inherit + CMS_MODULE + rename + is_initialized as module_is_initialized, + is_enabled as module_is_enabled + end + +feature {NONE} -- Initialization + + make (a_module: G) + -- Initialize `Current'. + do + module := a_module + version := a_module.version + description := a_module.description + package := a_module.package + + module_is_initialized := a_module.is_initialized + module_is_enabled := a_module.is_enabled + end + +feature -- Access + + module: G + + name: STRING + do + Result := module.name + end + +feature -- Status + + is_initialized: BOOLEAN + -- Is Current module initialized? + do + Result := module.is_initialized + end + + is_enabled: BOOLEAN + -- Is Current module enabled? + do + Result := module.is_enabled + end + +feature -- Router + + setup_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- + do + if a_router.base_url /= Void then + setup_administration_router (a_router, a_api) + end + end + +feature {NONE} -- Router/administration + + setup_administration_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- Setup url dispatching for Current module administration. + -- (note: `a_router` is already based with admin path prefix). + require + is_initialized: is_initialized + router_has_base_url: a_router.base_url /= Void + deferred + end + +note + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/src/service/handler/cms_admin_install_handler.e b/src/service/handler/cms_admin_install_handler.e index c878f96..c696ef0 100644 --- a/src/service/handler/cms_admin_install_handler.e +++ b/src/service/handler/cms_admin_install_handler.e @@ -43,11 +43,16 @@ feature -- HTTP Methods l_module: CMS_MODULE s: STRING lst: ARRAYED_LIST [CMS_MODULE] + l_access: detachable READABLE_STRING_8 l_denied: BOOLEAN do --| FIXME: improve the installer. create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - if attached api.setup.string_8_item ("admin.installation_access") as l_access then + l_access := api.setup.string_8_item ("admin.installation_access") + if l_access = Void then + l_access := api.setup.string_8_item ("administration.installation_access") + end + if l_access /= Void then if l_access.is_case_insensitive_equal ("none") then l_denied := True elseif l_access.is_case_insensitive_equal ("permission") then @@ -100,6 +105,7 @@ feature -- HTTP Methods s.append ("%N") end s.append ("") + s.append ("
    Back to the " + r.link ("Administration", api.administration_path (""), Void) + " ...
    ") r.set_main_content (s) end r.set_title (r.translation ("CMS Installation ...", Void)) diff --git a/src/service/misc/cms_url_utilities.e b/src/service/misc/cms_url_utilities.e index 5c9e609..48533d6 100644 --- a/src/service/misc/cms_url_utilities.e +++ b/src/service/misc/cms_url_utilities.e @@ -193,6 +193,6 @@ feature -- Url end note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/response/cms_response.e b/src/service/response/cms_response.e index f2fc91b..4c212a7 100644 --- a/src/service/response/cms_response.e +++ b/src/service/response/cms_response.e @@ -30,10 +30,19 @@ feature {NONE} -- Initialization end initialize + local + s: READABLE_STRING_8 do get_theme create menu_system.make initialize_block_region_settings + + s := request.percent_encoded_path_info + if not s.is_empty and then s[1] = '/' then + create location.make_from_string (s.substring (2, s.count)) + else + create location.make_from_string (s) + end end feature -- Access @@ -48,6 +57,14 @@ feature -- Access main_content: detachable STRING_8 +feature -- Settings + + is_administration_mode: BOOLEAN + -- Is administration mode? + do + Result := api.is_administration_mode + end + feature -- Access: metadata title: detachable READABLE_STRING_32 @@ -76,15 +93,8 @@ feature -- Access: metadata feature -- Access: query - location: STRING_8 + location: IMMUTABLE_STRING_8 -- Associated cms local location. - do - create Result.make_from_string (request.percent_encoded_path_info) - if not Result.is_empty and then Result[1] = '/' then - Result.remove_head (1) - end - end - feature -- API @@ -496,7 +506,7 @@ feature -- Block management nb_secs.is_integer then if attached block_region_preference (a_block_id, "none") as l_region and then not l_region.same_string_general ("none") then - create l_cache.make (api.files_location.extended (".cache").extended ("blocks").extended (a_block_id).appended_with_extension ("html")) + create l_cache.make (api.cache_location.extended ("_blocks").extended (a_block_id).appended_with_extension ("html")) if l_cache.exists and then not l_cache.expired (Void, nb_secs.to_integer) @@ -517,7 +527,7 @@ feature -- Block management dir: DIRECTORY l_cache: CMS_FILE_STRING_8_CACHE do - p := api.files_location.extended (".cache").extended ("blocks") + p := api.cache_location.extended ("_blocks") if a_block_id_list /= Void then across a_block_id_list as ic @@ -535,6 +545,7 @@ feature -- Block management create dir.make_with_path (p) dir.recursive_delete end + add_notice_message ("Blocks cache cleared.") end feature {CMS_HOOK_CORE_MANAGER} -- Block management: internal @@ -1002,9 +1013,9 @@ feature -- Theme create l_info.make_default end if l_info.engine.is_case_insensitive_equal_general ("smarty") then - create {SMARTY_CMS_THEME} theme.make (setup, l_info, site_url) + create {SMARTY_CMS_THEME} theme.make (api, l_info, site_url) else - create {MISSING_CMS_THEME} theme.make (setup, l_info, site_url) + create {MISSING_CMS_THEME} theme.make (api, l_info, site_url) status_code := {HTTP_STATUS_CODE}.service_unavailable to_implement ("Check how to add the Retry-after, http://tools.ietf.org/html/rfc7231#section-6.6.4 and http://tools.ietf.org/html/rfc7231#section-7.1.3") end @@ -1083,7 +1094,7 @@ feature -- Generation if api.enabled_modules.count = 1 then -- It is the required CMS_CORE_MODULE! - add_to_primary_menu (create {CMS_LOCAL_LINK}.make ("Install", "admin/install")) + add_to_primary_menu (api.administration_link ("Install", "install")) end -- Blocks @@ -1322,32 +1333,33 @@ feature -- Generation feature -- Helpers: cms link + administration_link (a_title: READABLE_STRING_GENERAL; a_location: READABLE_STRING_8): CMS_LOCAL_LINK + do + Result := api.administration_link (a_title, a_location) + end + local_link (a_title: READABLE_STRING_GENERAL; a_location: READABLE_STRING_8): CMS_LOCAL_LINK do - create Result.make (a_title, a_location) + Result := api.local_link (a_title, a_location) end user_local_link (u: CMS_USER; a_opt_title: detachable READABLE_STRING_GENERAL): CMS_LOCAL_LINK do - if a_opt_title /= Void then - create Result.make (a_opt_title, user_url (u)) - else - create Result.make (user_profile_name (u), user_url (u)) - end + Result := api.user_local_link (u, a_opt_title) end feature -- Helpers: html links user_profile_name, user_display_name (u: CMS_USER): READABLE_STRING_32 do - Result := api.user_api.user_display_name (u) + Result := api.user_display_name (u) end user_html_link (u: CMS_USER): STRING require u_with_name: not u.name.is_whitespace do - Result := link (user_profile_name (u), "user/" + u.id.out, Void) + Result := api.user_html_link (u) end feature -- Helpers: URLs @@ -1359,7 +1371,7 @@ feature -- Helpers: URLs --| - query: string => append "?query" --| - fragment: string => append "#fragment" do - Result := absolute_url (a_location, opts) + Result := api.location_absolute_url (a_location, opts) end location_url (a_location: READABLE_STRING_8; opts: detachable CMS_API_OPTIONS): STRING @@ -1369,14 +1381,14 @@ feature -- Helpers: URLs --| - query: string => append "?query" --| - fragment: string => append "#fragment" do - Result := url (a_location, opts) + Result := api.location_url (a_location, opts) end user_url (u: CMS_USER): like url require u_with_id: u.has_id do - Result := location_url ("user/" + u.id.out, Void) + Result := api.user_url (u) end feature -- Execution diff --git a/src/service/user/cms_user_api.e b/src/service/user/cms_user_api.e index 082b4a5..5a22917 100644 --- a/src/service/user/cms_user_api.e +++ b/src/service/user/cms_user_api.e @@ -263,7 +263,7 @@ feature -- User roles. role_permissions: HASH_TABLE [LIST [READABLE_STRING_8], STRING_8] -- Possible known permissions indexed by modules. local - lst, l_used_permissions: LIST [READABLE_STRING_8] + lst, l_full_lst, l_used_permissions: LIST [READABLE_STRING_8] do create Result.make (cms_api.enabled_modules.count + 1) @@ -272,6 +272,28 @@ feature -- User roles. cms_api.enabled_modules as ic loop lst := ic.item.permissions + if attached {CMS_ADMINISTRABLE} ic.item as adm then + create {ARRAYED_LIST [READABLE_STRING_8]} l_full_lst.make (lst.count) + l_full_lst.compare_objects + -- l_full_lst.append (lst) + across + lst as lst_ic + loop + if not l_full_lst.has (lst_ic.item) then + l_full_lst.extend (lst_ic.item) + end + end + -- l_full_lst.append (adm.module_administration.permissions) + lst := adm.module_administration.permissions + across + lst as lst_ic + loop + if not l_full_lst.has (lst_ic.item) then + l_full_lst.extend (lst_ic.item) + end + end + lst := l_full_lst + end Result.force (lst, ic.item.name) across lst as p_ic diff --git a/src/theme/cms_theme.e b/src/theme/cms_theme.e index ed6ca3b..3db5e57 100644 --- a/src/theme/cms_theme.e +++ b/src/theme/cms_theme.e @@ -16,7 +16,7 @@ inherit feature {NONE} -- Access - setup: CMS_SETUP + api: CMS_API site_url: IMMUTABLE_STRING_8 -- Absolute URL for Current CMS site. @@ -186,7 +186,7 @@ feature {NONE} -- Implementation end note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/src/theme/missing_theme/missing_cms_theme.e b/src/theme/missing_theme/missing_cms_theme.e index ff2822a..fa536c3 100644 --- a/src/theme/missing_theme/missing_cms_theme.e +++ b/src/theme/missing_theme/missing_cms_theme.e @@ -18,13 +18,13 @@ create feature {NONE} -- Initialization - make (a_setup: like setup; a_info: like information; abs_site_url: READABLE_STRING_8) + make (a_api: like api; a_info: like information; abs_site_url: READABLE_STRING_8) do - setup := a_setup + api := a_api information := a_info set_site_url (abs_site_url) ensure - setup_set: setup = a_setup + api_set: api = a_api end feature -- Access @@ -49,4 +49,7 @@ feature -- Access to_implement ("Add a better response message, maybe using smarty template") Result := "Service Unavailable" end +note + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/theme/smarty_theme/smarty_cms_theme.e b/src/theme/smarty_theme/smarty_cms_theme.e index a75e0df..3e44846 100644 --- a/src/theme/smarty_theme/smarty_cms_theme.e +++ b/src/theme/smarty_theme/smarty_cms_theme.e @@ -14,18 +14,18 @@ create feature {NONE} -- Initialization - make (a_setup: like setup; a_info: like information; abs_site_url: READABLE_STRING_8) + make (a_api: like api; a_info: like information; abs_site_url: READABLE_STRING_8) do - setup := a_setup + api := a_api information := a_info if attached a_info.item ("template_dir") as s then - templates_directory := a_setup.theme_location.extended (s) + templates_directory := a_api.theme_location.extended (s) else - templates_directory := a_setup.theme_location + templates_directory := a_api.theme_location end set_site_url (abs_site_url) ensure - setup_set: setup = a_setup + api_set: api = a_api information_set: information = a_info end @@ -129,7 +129,7 @@ feature {NONE} -- Internal invariant attached internal_page_template as inv_p implies inv_p.theme = Current note - copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software