From 420051cd1473b64001fab46c2f32371e30d9cd09 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Mon, 9 Nov 2015 21:07:02 +0100 Subject: [PATCH] Redesigned hooks system (moving from CMS_RESPONSE to CMS_API). Indeed, hooks does not require RESPONSE interface, and should be setup before, at the system level (i.e CMS_API) Added exportation solution via CMS_HOOK_EXPORT. Updated blocks settings for demo example project. --- examples/demo/modules/demo/cms_demo_module.e | 8 +- examples/demo/site/config/blocks.ini | 25 +---- modules/admin/cms_admin_module.e | 20 +++- .../admin/handler/cms_admin_export_handler.e | 104 ++++++++++++++++++ modules/auth/cms_authentication_module.e | 10 +- modules/basic_auth/cms_basic_auth_module.e | 10 +- modules/blog/cms_blog_api.e | 15 +++ modules/blog/cms_blog_module-safe.ecf | 2 + modules/blog/cms_blog_module.e | 56 +++++++++- modules/blog/persistence/cms_blog_storage_i.e | 8 +- .../feed_aggregator/feed_aggregator_module.e | 12 +- modules/node/cms_node_api.e | 8 ++ modules/node/cms_node_module.e | 82 +++++++++++++- .../node/export/cms_export_node_utilities.e | 55 +++++++++ modules/node/node-safe.ecf | 5 +- modules/node/node.ecf | 1 + modules/node/persistence/cms_node_storage_i.e | 20 ++++ .../node/persistence/cms_node_storage_sql.e | 34 ++++++ modules/oauth20/cms_oauth_20_module.e | 10 +- modules/openid/cms_openid_module.e | 10 +- .../cms_recent_changes_module.e | 10 +- src/hooks/cms_hook_auto_register.e | 4 +- src/hooks/cms_hook_core_manager.e | 28 +++++ src/hooks/export/cms_export_json_utilities.e | 35 ++++++ src/hooks/export/cms_export_parameters.e | 43 ++++++++ src/hooks/export/cms_hook_export.e | 31 ++++++ src/modules/cms_debug_module.e | 8 +- src/service/cms_api.e | 31 ++++++ src/service/cms_module.e | 2 +- src/service/response/cms_response.e | 22 +--- 30 files changed, 609 insertions(+), 100 deletions(-) create mode 100644 modules/admin/handler/cms_admin_export_handler.e create mode 100644 modules/node/export/cms_export_node_utilities.e create mode 100644 src/hooks/export/cms_export_json_utilities.e create mode 100644 src/hooks/export/cms_export_parameters.e create mode 100644 src/hooks/export/cms_hook_export.e diff --git a/examples/demo/modules/demo/cms_demo_module.e b/examples/demo/modules/demo/cms_demo_module.e index d85bf34..7f477ef 100644 --- a/examples/demo/modules/demo/cms_demo_module.e +++ b/examples/demo/modules/demo/cms_demo_module.e @@ -10,7 +10,7 @@ class inherit CMS_MODULE redefine - register_hooks, + setup_hooks, initialize, install end @@ -85,10 +85,10 @@ feature -- Access: router feature -- Hooks - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) do - a_response.hooks.subscribe_to_menu_system_alter_hook (Current) - a_response.hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_block_hook (Current) end block_list: ITERABLE [like {CMS_BLOCK}.name] diff --git a/examples/demo/site/config/blocks.ini b/examples/demo/site/config/blocks.ini index deb55b7..1afcb15 100644 --- a/examples/demo/site/config/blocks.ini +++ b/examples/demo/site/config/blocks.ini @@ -9,30 +9,17 @@ management.conditions[]=is_front feed.news.weight=3 feed.news.region=feed_news feed.news.region=content -feed.news.condition= +feed.news.condition=is_front + feed.forum.weight=2 feed.forum.region=feed_forum -feed.forum.region= -feed.forum.condition= -feed.forum.options[size]=15 +feed.forum.region=content +feed.forum.condition=is_front +feed.forum.options[size]=5 #Updates recent_changes.region=content recent_changes.condition=is_front recent_changes.title=Updates -recent_changes.options[size]=3 - -#Aliases -&aliases[foo]=management -&aliases[bar]=feed.forum - -foo.region=content -foo.condition=is_front -foo.weight=-10 - -bar.region=content -bar.condition=is_front -bar.title=Bar - - +recent_changes.options[size]=4 diff --git a/modules/admin/cms_admin_module.e b/modules/admin/cms_admin_module.e index 8e5d724..c767778 100644 --- a/modules/admin/cms_admin_module.e +++ b/modules/admin/cms_admin_module.e @@ -9,7 +9,7 @@ class inherit CMS_MODULE redefine - register_hooks, + setup_hooks, permissions end @@ -54,6 +54,7 @@ feature -- Access: router l_role_handler: CMS_ROLE_HANDLER l_admin_cache_handler: CMS_ADMIN_CACHE_HANDLER + l_admin_export_handler: CMS_ADMIN_EXPORT_HANDLER l_uri_mapping: WSF_URI_MAPPING do @@ -73,6 +74,10 @@ feature -- Access: router 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_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) @@ -84,8 +89,6 @@ feature -- Access: router 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 @@ -101,15 +104,16 @@ feature -- Security Result.force ("install modules") Result.force ("admin core caches") Result.force ("clear blocks cache") + Result.force ("admin export") end feature -- Hooks - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- do - a_response.hooks.subscribe_to_menu_system_alter_hook (Current) - a_response.hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_response_alter_hook (Current) end response_alter (a_response: CMS_RESPONSE) @@ -132,6 +136,10 @@ feature -- Hooks end -- Per module cache permission! create lnk.make ("Cache", "admin/cache") + a_menu_system.management_menu.extend (lnk) + + -- Per module export permission! + create lnk.make ("Export", "admin/export") a_menu_system.management_menu.extend (lnk) end diff --git a/modules/admin/handler/cms_admin_export_handler.e b/modules/admin/handler/cms_admin_export_handler.e new file mode 100644 index 0000000..7dd391e --- /dev/null +++ b/modules/admin/handler/cms_admin_export_handler.e @@ -0,0 +1,104 @@ +note + description: "[ + Administrate export functionality. + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_ADMIN_EXPORT_HANDLER + +inherit + CMS_HANDLER + + WSF_URI_HANDLER + rename + new_mapping as new_uri_mapping + end + + WSF_RESOURCE_HANDLER_HELPER + redefine + do_get, + do_post + end + + REFACTORING_HELPER + +create + make + +feature -- Execution + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute_methods (req, res) + end + + do_get (req: WSF_REQUEST; res: WSF_RESPONSE) + local + l_response: CMS_RESPONSE + s: STRING + f: CMS_FORM + do + create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) + f := exportation_web_form (l_response) + create s.make_empty + f.append_to_html (create {CMS_TO_WSF_THEME}.make (l_response, l_response.theme), s) + l_response.set_main_content (s) + l_response.execute + end + + do_post (req: WSF_REQUEST; res: WSF_RESPONSE) + local + l_response: CMS_RESPONSE + s: STRING + f: CMS_FORM + l_exportation_parameters: CMS_EXPORT_PARAMETERS + do + create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) + f := exportation_web_form (l_response) + f.process (l_response) + if + attached f.last_data as fd and then + fd.is_valid + then + if attached fd.string_item ("op") as l_op and then l_op.same_string (text_export_all_data) then + create l_exportation_parameters.make (api.site_location.extended ("export").extended ((create {DATE_TIME}.make_now_utc).formatted_out ("yyyy-[0]mm-[0]dd_hh12-[0]mi-[0]ss"))) + l_response.hooks.invoke_export_to (Void, l_exportation_parameters, l_response) + l_response.add_notice_message ("All data exported (if allowed)!") + create s.make_empty + across + l_exportation_parameters.logs as ic + loop + s.append (ic.item) + s.append ("
") + s.append_character ('%N') + end + l_response.add_notice_message (s) + else + fd.report_error ("Invalid form data!") + end + end + create s.make_empty + f.append_to_html (create {CMS_TO_WSF_THEME}.make (l_response, l_response.theme), s) + l_response.set_main_content (s) + l_response.execute + end + +feature -- Widget + + exportation_web_form (a_response: CMS_RESPONSE): CMS_FORM + local + but: WSF_FORM_SUBMIT_INPUT + do + create Result.make (a_response.url (a_response.location, Void), "export_all_data") + create but.make_with_text ("op", text_export_all_data) + Result.extend (but) + end + +feature -- Interface text. + + text_export_all_data: STRING_32 = "Export all data" + +end diff --git a/modules/auth/cms_authentication_module.e b/modules/auth/cms_authentication_module.e index 5c786bb..e0a7c55 100644 --- a/modules/auth/cms_authentication_module.e +++ b/modules/auth/cms_authentication_module.e @@ -9,7 +9,7 @@ class inherit CMS_MODULE redefine - register_hooks + setup_hooks end @@ -91,12 +91,12 @@ feature -- Router feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - auto_subscribe_to_hooks (a_response) - a_response.hooks.subscribe_to_block_hook (Current) - a_response.hooks.subscribe_to_value_table_alter_hook (Current) + auto_subscribe_to_hooks (a_hooks) + a_hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_value_table_alter_hook (Current) end value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE) diff --git a/modules/basic_auth/cms_basic_auth_module.e b/modules/basic_auth/cms_basic_auth_module.e index 132ced8..43c0bf7 100644 --- a/modules/basic_auth/cms_basic_auth_module.e +++ b/modules/basic_auth/cms_basic_auth_module.e @@ -13,7 +13,7 @@ inherit CMS_MODULE redefine filters, - register_hooks + setup_hooks end CMS_HOOK_AUTO_REGISTER @@ -101,12 +101,12 @@ feature {NONE} -- Implementation: routes feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - auto_subscribe_to_hooks (a_response) - a_response.hooks.subscribe_to_block_hook (Current) - a_response.hooks.subscribe_to_value_table_alter_hook (Current) + auto_subscribe_to_hooks (a_hooks) + a_hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_value_table_alter_hook (Current) end feature -- Hooks diff --git a/modules/blog/cms_blog_api.e b/modules/blog/cms_blog_api.e index c9128a9..8c63dcd 100644 --- a/modules/blog/cms_blog_api.e +++ b/modules/blog/cms_blog_api.e @@ -97,6 +97,21 @@ feature -- Access node Result := nodes_to_blogs (blog_storage.blogs_from_user_limited (a_user, a_limit, a_offset)) end +feature -- Conversion + + full_blog_node (a_blog: CMS_BLOG): CMS_BLOG + -- If `a_blog' is partial, return the full blog node from `a_blog', + -- otherwise return directly `a_blog'. + require + a_blog_set: a_blog /= Void + do + if attached {CMS_BLOG} node_api.full_node (a_blog) as l_full_blog then + Result := l_full_blog + else + Result := a_blog + end + end + feature {NONE} -- Helpers nodes_to_blogs (a_nodes: LIST [CMS_NODE]): ARRAYED_LIST [CMS_BLOG] diff --git a/modules/blog/cms_blog_module-safe.ecf b/modules/blog/cms_blog_module-safe.ecf index e7d4082..72f9a73 100644 --- a/modules/blog/cms_blog_module-safe.ecf +++ b/modules/blog/cms_blog_module-safe.ecf @@ -14,6 +14,8 @@ + + diff --git a/modules/blog/cms_blog_module.e b/modules/blog/cms_blog_module.e index 5e6f13b..bbe806a 100644 --- a/modules/blog/cms_blog_module.e +++ b/modules/blog/cms_blog_module.e @@ -12,7 +12,7 @@ inherit rename module_api as blog_api redefine - register_hooks, + setup_hooks, initialize, install, blog_api @@ -22,6 +22,10 @@ inherit CMS_HOOK_RESPONSE_ALTER + CMS_HOOK_EXPORT + + CMS_EXPORT_NODE_UTILITIES + create make @@ -149,10 +153,11 @@ feature -- Access: router feature -- Hooks - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) do - a_response.hooks.subscribe_to_menu_system_alter_hook (Current) - a_response.hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_export_hook (Current) end response_alter (a_response: CMS_RESPONSE) @@ -168,4 +173,47 @@ feature -- Hooks create lnk.make ("Blogs", "blogs/") a_menu_system.primary_menu.extend (lnk) end + + export_to (a_export_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_export_parameters: CMS_EXPORT_PARAMETERS; a_response: CMS_RESPONSE) + -- Export data identified by `a_export_id_list', + -- or export all data if `a_export_id_list' is Void. + local + n: CMS_BLOG + p: PATH + d: DIRECTORY + f: PLAIN_TEXT_FILE + lst: LIST [CMS_BLOG] + do + if + a_export_id_list = Void + or else across a_export_id_list as ic some ic.item.same_string ("blog") end + then + if attached blog_api as l_blog_api then + lst := l_blog_api.blogs_order_created_desc + a_export_parameters.log ("Exporting " + lst.count.out + " blogs") + across + lst as ic + loop + n := l_blog_api.full_blog_node (ic.item) + a_export_parameters.log (n.content_type + " #" + n.id.out) + p := a_export_parameters.location.extended ("nodes").extended (n.content_type).extended (n.id.out) + create d.make_with_path (p.parent) + if not d.exists then + d.recursive_create_dir + end + create f.make_with_path (p) + if not f.exists or else f.is_access_writable then + f.open_write + f.put_string (json_to_string (blog_node_to_json (n))) + f.close + end + end + end + end + end + + blog_node_to_json (a_blog: CMS_BLOG): JSON_OBJECT + do + Result := node_to_json (a_blog) + end end diff --git a/modules/blog/persistence/cms_blog_storage_i.e b/modules/blog/persistence/cms_blog_storage_i.e index 08c2447..cee1d47 100644 --- a/modules/blog/persistence/cms_blog_storage_i.e +++ b/modules/blog/persistence/cms_blog_storage_i.e @@ -6,8 +6,12 @@ note deferred class CMS_BLOG_STORAGE_I -inherit - CMS_NODE_STORAGE_I +feature -- Error Handling + + error_handler: ERROR_HANDLER + -- Error handler. + deferred + end feature -- Access diff --git a/modules/feed_aggregator/feed_aggregator_module.e b/modules/feed_aggregator/feed_aggregator_module.e index 308f332..6c64df5 100644 --- a/modules/feed_aggregator/feed_aggregator_module.e +++ b/modules/feed_aggregator/feed_aggregator_module.e @@ -12,7 +12,7 @@ inherit module_api as feed_aggregator_api redefine initialize, - register_hooks, + setup_hooks, permissions, feed_aggregator_api end @@ -181,13 +181,13 @@ feature -- Handle feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - a_response.hooks.subscribe_to_block_hook (Current) - a_response.hooks.subscribe_to_response_alter_hook (Current) - a_response.hooks.subscribe_to_menu_system_alter_hook (Current) - a_response.hooks.subscribe_to_cache_hook (Current) + 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 diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index 9aff292..c77e926 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -330,6 +330,14 @@ feature -- Access: Node end end + nodes_of_type (a_node_type: CMS_CONTENT_TYPE): LIST [CMS_NODE] + -- List of nodes of type `a_node_type'. + do + Result := node_storage.nodes_of_type (a_node_type) + ensure + expected_type: across Result as ic all ic.item.content_type.same_string (a_node_type.name) end + end + feature -- Access: page/book outline children (a_node: CMS_NODE): detachable LIST [CMS_NODE] diff --git a/modules/node/cms_node_module.e b/modules/node/cms_node_module.e index 1e23a28..9a35515 100644 --- a/modules/node/cms_node_module.e +++ b/modules/node/cms_node_module.e @@ -9,7 +9,7 @@ class inherit CMS_MODULE redefine - register_hooks, + setup_hooks, initialize, is_installed, install, @@ -25,6 +25,10 @@ inherit CMS_RECENT_CHANGES_HOOK + CMS_HOOK_EXPORT + + CMS_EXPORT_NODE_UTILITIES + create make @@ -224,15 +228,16 @@ feature -- Access: router feature -- Hooks - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- do - a_response.hooks.subscribe_to_menu_system_alter_hook (Current) - a_response.hooks.subscribe_to_block_hook (Current) - a_response.hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_export_hook (Current) -- Module specific hook, if available. - a_response.hooks.subscribe_to_hook (Current, {CMS_RECENT_CHANGES_HOOK}) + a_hooks.subscribe_to_hook (Current, {CMS_RECENT_CHANGES_HOOK}) end response_alter (a_response: CMS_RESPONSE) @@ -353,4 +358,69 @@ feature -- Hooks end end + export_to (a_export_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_export_parameters: CMS_EXPORT_PARAMETERS; a_response: CMS_RESPONSE) + -- Export data identified by `a_export_id_list', + -- or export all data if `a_export_id_list' is Void. + local + l_node_type: CMS_CONTENT_TYPE + n: CMS_NODE + p: PATH + d: DIRECTORY + f: PLAIN_TEXT_FILE + lst: LIST [CMS_NODE] + do + if attached node_api as l_node_api then + across + l_node_api.node_types as types_ic + loop + l_node_type := types_ic.item + if + l_node_type.name.same_string_general ("page") and then + ( a_export_id_list = Void + or else across a_export_id_list as ic some ic.item.same_string (l_node_type.name) end + ) + then + + -- For now, handle only page from this node module. + lst := l_node_api.nodes_of_type (l_node_type) + a_export_parameters.log ("Exporting " + lst.count.out + " nodes of type " + l_node_type.name) + across + lst as ic + loop + n := l_node_api.full_node (ic.item) + a_export_parameters.log (l_node_type.name + " #" + n.id.out) + p := a_export_parameters.location.extended ("nodes").extended (l_node_type.name).extended (n.id.out) + create d.make_with_path (p.parent) + if not d.exists then + d.recursive_create_dir + end + create f.make_with_path (p) + if not f.exists or else f.is_access_writable then + f.open_write + if attached {CMS_PAGE} n as l_page then + f.put_string (json_to_string (page_node_to_json (l_page))) + else + f.put_string (json_to_string (node_to_json (n))) + end + f.close + end + end + end + end + end + end + + page_node_to_json (a_page: CMS_PAGE): JSON_OBJECT + local + j: JSON_OBJECT + do + Result := node_to_json (a_page) + if attached a_page.parent as l_parent_page then + create j.make_empty + j.put_string (l_parent_page.content_type, "type") + j.put_integer (l_parent_page.id, "nid") + Result.put (j, "parent") + end + end + end diff --git a/modules/node/export/cms_export_node_utilities.e b/modules/node/export/cms_export_node_utilities.e new file mode 100644 index 0000000..e05360e --- /dev/null +++ b/modules/node/export/cms_export_node_utilities.e @@ -0,0 +1,55 @@ +note + description: "[ + Routines usefull during node exportation (see {CMS_HOOK_EXPORT}). + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_EXPORT_NODE_UTILITIES + +inherit + CMS_EXPORT_JSON_UTILITIES + +feature -- Access + + node_to_json (n: CMS_NODE): JSON_OBJECT + local + jo,j_author: JSON_OBJECT + do + create Result.make_empty + Result.put_string (n.content_type, "type") + Result.put_integer (n.id, "nid") + Result.put_integer (n.revision, "revision") + Result.put_string (n.title, "title") + put_date_into_json (n.creation_date, "creation_date", Result) + put_date_into_json (n.modification_date, "modification_date", Result) + put_date_into_json (n.publication_date, "publication_date", Result) + Result.put_integer (n.status, "status") + if attached n.author as u then + create j_author.make + j_author.put_integer (u.id, "uid") + j_author.put_string (u.name, "name") + Result.put (j_author, "author") + end + create jo.make_empty + if attached n.format as l_format then + jo.put_string (l_format, "format") + end + if attached n.summary as s then + jo.put_string (s, "summary") + end + if attached n.content as s then + jo.put_string (s, "content") + end + Result.put (jo, "data") + if attached n.link as lnk then + create jo.make_empty + jo.put_string (lnk.title, "title") + jo.put_string (lnk.location, "location") + jo.put_integer (lnk.weight, "weight") + Result.put (jo, "link") + end + end + +end diff --git a/modules/node/node-safe.ecf b/modules/node/node-safe.ecf index fccaeea..f024e33 100644 --- a/modules/node/node-safe.ecf +++ b/modules/node/node-safe.ecf @@ -1,5 +1,5 @@ - + @@ -7,7 +7,7 @@ /CVS$ /.svn$ - @@ -17,6 +17,7 @@ + diff --git a/modules/node/node.ecf b/modules/node/node.ecf index 87508e6..3fe2d71 100644 --- a/modules/node/node.ecf +++ b/modules/node/node.ecf @@ -17,6 +17,7 @@ + diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e index ef97a66..dc941c2 100644 --- a/modules/node/persistence/cms_node_storage_i.e +++ b/modules/node/persistence/cms_node_storage_i.e @@ -127,6 +127,26 @@ feature -- Access deferred end + nodes_of_type (a_node_type: CMS_CONTENT_TYPE): LIST [CMS_NODE] + -- List of nodes of type `a_node_type'. + --| Redefine to optimize! + do + Result := nodes + from + Result.start + until + Result.after + loop + if Result.item.content_type.same_string (a_node_type.name) then + Result.forth + else + Result.remove + end + end + ensure + expected_type: across Result as ic all ic.item.content_type.same_string (a_node_type.name) end + end + feature -- Access: outline children (a_node: CMS_NODE): detachable LIST [CMS_NODE] diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 2be4789..72ffff8 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -12,6 +12,9 @@ inherit CMS_PROXY_STORAGE_SQL CMS_NODE_STORAGE_I + redefine + nodes_of_type + end CMS_STORAGE_SQL_I @@ -264,6 +267,33 @@ feature -- Access -- end end + nodes_of_type (a_node_type: CMS_CONTENT_TYPE): LIST [CMS_NODE] + -- + local + l_parameters: STRING_TABLE [detachable ANY] + do + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + + error_handler.reset + write_information_log (generator + ".nodes_of_type") + create l_parameters.make (1) + l_parameters.put (a_node_type.name, "node_type") + + from + sql_query (sql_select_nodes_of_type, l_parameters) + sql_start + until + sql_after + loop + if attached fetch_node as l_node then + check expected_node_type: l_node.content_type.same_string (a_node_type.name) end + Result.force (l_node) + end + sql_forth + end + sql_finalize + end + feature -- Access: outline children (a_node: CMS_NODE): detachable LIST [CMS_NODE] @@ -495,6 +525,10 @@ feature {NONE} -- Queries -- SQL Query to retrieve all nodes. --| note: {CMS_NODE_API}.trashed = -1 + sql_select_nodes_of_type: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE status != -1 AND type=:node_type ;" + -- SQL Query to retrieve all nodes of type :node_type. + --| note: {CMS_NODE_API}.trashed = -1 + sql_select_node_revisions: STRING = "SELECT nodes.nid, node_revisions.revision, nodes.type, node_revisions.title, node_revisions.summary, node_revisions.content, node_revisions.format, node_revisions.author, nodes.publish, nodes.created, node_revisions.changed, node_revisions.status FROM nodes INNER JOIN node_revisions ON nodes.nid = node_revisions.nid WHERE nodes.nid = :nid AND node_revisions.revision < :revision ORDER BY node_revisions.revision DESC;" -- SQL query to get node revisions (missing the latest one). diff --git a/modules/oauth20/cms_oauth_20_module.e b/modules/oauth20/cms_oauth_20_module.e index 321f451..ea96685 100644 --- a/modules/oauth20/cms_oauth_20_module.e +++ b/modules/oauth20/cms_oauth_20_module.e @@ -12,7 +12,7 @@ inherit module_api as user_oauth_api redefine filters, - register_hooks, + setup_hooks, initialize, install, user_oauth_api @@ -190,12 +190,12 @@ feature -- Router feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - auto_subscribe_to_hooks (a_response) - a_response.hooks.subscribe_to_block_hook (Current) - a_response.hooks.subscribe_to_value_table_alter_hook (Current) + auto_subscribe_to_hooks (a_hooks) + a_hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_value_table_alter_hook (Current) end feature -- Hooks diff --git a/modules/openid/cms_openid_module.e b/modules/openid/cms_openid_module.e index 988085b..dca1c0b 100644 --- a/modules/openid/cms_openid_module.e +++ b/modules/openid/cms_openid_module.e @@ -14,7 +14,7 @@ inherit module_api as user_openid_api redefine filters, - register_hooks, + setup_hooks, initialize, install, user_openid_api @@ -166,12 +166,12 @@ feature -- Router feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - auto_subscribe_to_hooks (a_response) - a_response.hooks.subscribe_to_block_hook (Current) - a_response.hooks.subscribe_to_value_table_alter_hook (Current) + auto_subscribe_to_hooks (a_hooks) + a_hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_value_table_alter_hook (Current) end feature -- Hooks diff --git a/modules/recent_changes/cms_recent_changes_module.e b/modules/recent_changes/cms_recent_changes_module.e index d2f1dfe..e46ecb6 100644 --- a/modules/recent_changes/cms_recent_changes_module.e +++ b/modules/recent_changes/cms_recent_changes_module.e @@ -11,7 +11,7 @@ inherit rename module_api as recent_changes_api redefine - register_hooks, + setup_hooks, permissions end @@ -397,12 +397,12 @@ feature -- Handler feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - a_response.hooks.subscribe_to_menu_system_alter_hook (Current) - a_response.hooks.subscribe_to_response_alter_hook (Current) - a_response.hooks.subscribe_to_block_hook (Current) + a_hooks.subscribe_to_menu_system_alter_hook (Current) + a_hooks.subscribe_to_response_alter_hook (Current) + a_hooks.subscribe_to_block_hook (Current) end feature -- Hook diff --git a/src/hooks/cms_hook_auto_register.e b/src/hooks/cms_hook_auto_register.e index 9ce4852..ecc4e69 100644 --- a/src/hooks/cms_hook_auto_register.e +++ b/src/hooks/cms_hook_auto_register.e @@ -16,11 +16,11 @@ inherit feature -- Hook - auto_subscribe_to_hooks (a_response: CMS_RESPONSE) + auto_subscribe_to_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) local l_manager: CMS_HOOK_CORE_MANAGER do - l_manager := a_response.hooks + l_manager := a_hooks if attached {CMS_HOOK_MENU_SYSTEM_ALTER} Current as h_menu_system_alter then l_manager.subscribe_to_menu_system_alter_hook (h_menu_system_alter) end diff --git a/src/hooks/cms_hook_core_manager.e b/src/hooks/cms_hook_core_manager.e index 0ce47aa..eaa2dc1 100644 --- a/src/hooks/cms_hook_core_manager.e +++ b/src/hooks/cms_hook_core_manager.e @@ -223,6 +223,34 @@ feature -- Hook: cache end end +feature -- Hook: export + + subscribe_to_export_hook (h: CMS_HOOK_EXPORT) + -- Add `h' as subscriber of export hooks CMS_HOOK_EXPORT. + do + subscribe_to_hook (h, {CMS_HOOK_EXPORT}) + end + + invoke_export_to (a_export_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_export_parameters: CMS_EXPORT_PARAMETERS; a_response: CMS_RESPONSE) + -- Invoke response alter hook for response `a_response'. + local + d: DIRECTORY + do + if attached subscribers ({CMS_HOOK_EXPORT}) as lst then + create d.make_with_path (a_export_parameters.location) + if not d.exists then + d.recursive_create_dir + end + across + lst as ic + loop + if attached {CMS_HOOK_EXPORT} ic.item as h then + h.export_to (a_export_id_list, a_export_parameters, a_response) + end + end + end + end + note copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/src/hooks/export/cms_export_json_utilities.e b/src/hooks/export/cms_export_json_utilities.e new file mode 100644 index 0000000..1a68966 --- /dev/null +++ b/src/hooks/export/cms_export_json_utilities.e @@ -0,0 +1,35 @@ +note + description: "[ + Usefull routines to export to JSON. + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_EXPORT_JSON_UTILITIES + +feature -- Access + + put_date_into_json (dt: detachable DATE_TIME; a_key: JSON_STRING; j: JSON_OBJECT) + local + hd: HTTP_DATE + do + if dt /= Void then + create hd.make_from_date_time (dt) + j.put_integer (hd.timestamp, a_key) + end + end + + json_to_string (j: JSON_OBJECT): STRING + local + pp: JSON_PRETTY_STRING_VISITOR + do + create Result.make_empty + create pp.make (Result) + j.accept (pp) + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/src/hooks/export/cms_export_parameters.e b/src/hooks/export/cms_export_parameters.e new file mode 100644 index 0000000..63af447 --- /dev/null +++ b/src/hooks/export/cms_export_parameters.e @@ -0,0 +1,43 @@ +note + description: "[ + Parameters used by CMS_HOOK_EXPORT subscribers. + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_EXPORT_PARAMETERS + +create + make + +feature {NONE} -- Initialization + + make (a_location: PATH) + do + location := a_location + create logs.make (10) + end + +feature -- Access + + location: PATH + -- Location of export folder. + +feature -- Logs + + logs: ARRAYED_LIST [READABLE_STRING_8] + -- Associated exportation logs. + + log (m: READABLE_STRING_8) + -- Add message `m' into `logs'. + do + logs.force (m) + end + +invariant + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/src/hooks/export/cms_hook_export.e b/src/hooks/export/cms_hook_export.e new file mode 100644 index 0000000..b943d45 --- /dev/null +++ b/src/hooks/export/cms_hook_export.e @@ -0,0 +1,31 @@ +note + description: "[ + CMS HOOK providing a way to export module data according to specific export parameters. + ]" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_HOOK_EXPORT + +inherit + CMS_HOOK + +feature -- Hook + + export_to (a_export_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_export_parameters: CMS_EXPORT_PARAMETERS; a_response: CMS_RESPONSE) + -- Export data identified by `a_export_id_list', + -- or export all data if `a_export_id_list' is Void. + deferred + end + +-- export_identifiers: detachable ITERABLE [READABLE_STRING_32] +-- -- Optional list of exportation ids, if any. +-- do +-- -- To redefine if needed. +-- end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/src/modules/cms_debug_module.e b/src/modules/cms_debug_module.e index 72b1cca..a73dd32 100644 --- a/src/modules/cms_debug_module.e +++ b/src/modules/cms_debug_module.e @@ -9,7 +9,7 @@ class inherit CMS_MODULE redefine - register_hooks + setup_hooks end CMS_HOOK_BLOCK @@ -47,11 +47,11 @@ feature -- Router feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. do - auto_subscribe_to_hooks (a_response) - a_response.hooks.subscribe_to_block_hook (Current) + auto_subscribe_to_hooks (a_hooks) + a_hooks.subscribe_to_block_hook (Current) end feature -- Hooks diff --git a/src/service/cms_api.e b/src/service/cms_api.e index 964221a..ae1dcb0 100644 --- a/src/service/cms_api.e +++ b/src/service/cms_api.e @@ -24,6 +24,7 @@ feature {NONE} -- Initialize setup := a_setup create error_handler.make create {CMS_ENV_LOGGER} logger.make + create hooks.make initialize ensure setup_set: setup = a_setup @@ -51,6 +52,7 @@ feature {NONE} -- Initialize l_enabled_modules := setup.enabled_modules enabled_modules := l_enabled_modules + -- Complete storage setup. storage.set_api (Current) @@ -82,6 +84,9 @@ feature {NONE} -- Initialize l_enabled_modules.remove (ic.item) end end + + -- Initialize hooks system + setup_hooks end initialize_formats @@ -302,6 +307,32 @@ feature -- Query: module end end +feature -- Hooks + + hooks: CMS_HOOK_CORE_MANAGER + -- Manager handling hook subscriptions. + +feature {NONE} -- Hooks + + setup_hooks + local + l_module: CMS_MODULE + l_enabled_modules: CMS_MODULE_COLLECTION + l_hooks: like hooks + do + l_hooks := hooks + l_enabled_modules := enabled_modules + across + l_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) + end + l_module.setup_hooks (l_hooks) + end + end + feature -- Query: API user_api: CMS_USER_API diff --git a/src/service/cms_module.e b/src/service/cms_module.e index 5dfb22f..ff67968 100644 --- a/src/service/cms_module.e +++ b/src/service/cms_module.e @@ -129,7 +129,7 @@ feature -- Router feature -- Hooks configuration - register_hooks (a_response: CMS_RESPONSE) + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) -- Module hooks configuration. require is_enabled: is_enabled diff --git a/src/service/response/cms_response.e b/src/service/response/cms_response.e index d8cf39e..eb9050f 100644 --- a/src/service/response/cms_response.e +++ b/src/service/response/cms_response.e @@ -33,8 +33,6 @@ feature {NONE} -- Initialization get_theme create menu_system.make initialize_block_region_settings - create hooks.make - register_hooks end initialize_site_url @@ -66,23 +64,6 @@ feature {NONE} -- Initialization site_url_ends_with_slash: site_url.ends_with_general ("/") end - register_hooks - local - l_module: CMS_MODULE - l_enabled_modules: CMS_MODULE_COLLECTION - do - l_enabled_modules := api.enabled_modules - across - l_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 (Current) - end - l_module.register_hooks (Current) - end - end - feature -- Access request: WSF_REQUEST @@ -868,6 +849,9 @@ feature -- Hooks hooks: CMS_HOOK_CORE_MANAGER -- Manager handling hook subscriptions. + do + Result := api.hooks + end feature -- Menu: change