diff --git a/examples/demo/demo-safe.ecf b/examples/demo/demo-safe.ecf
index 1c12f20..8f28c4b 100644
--- a/examples/demo/demo-safe.ecf
+++ b/examples/demo/demo-safe.ecf
@@ -19,6 +19,7 @@
+
diff --git a/examples/demo/install_modules.bat b/examples/demo/install_modules.bat
index 1880e20..8e578be 100644
--- a/examples/demo/install_modules.bat
+++ b/examples/demo/install_modules.bat
@@ -10,3 +10,4 @@ set ROC_CMS_DIR=%~dp0
%ROC_CMD% install --module ..\..\modules\oauth20 --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\openid --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\recent_changes --dir %ROC_CMS_DIR%
+%ROC_CMD% install --module ..\..\modules\feed_aggregator --dir %ROC_CMS_DIR%
diff --git a/examples/demo/site/config/cms.ini b/examples/demo/site/config/cms.ini
index cf32a1c..9a90715 100644
--- a/examples/demo/site/config/cms.ini
+++ b/examples/demo/site/config/cms.ini
@@ -33,6 +33,9 @@ openid=on
[blocks]
#navigation.region=sidebar_first
+feed__bertrandmeyer.region=content
+feed__eiffelroom.region=content
+feed__bertrandmeyer.condition=is_front
[admin]
# CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none)
diff --git a/examples/demo/src/ewf_roc_server_execution.e b/examples/demo/src/ewf_roc_server_execution.e
index 40c16c4..db4dbf7 100644
--- a/examples/demo/src/ewf_roc_server_execution.e
+++ b/examples/demo/src/ewf_roc_server_execution.e
@@ -82,6 +82,9 @@ feature -- CMS setup
create {CMS_RECENT_CHANGES_MODULE} m.make
a_setup.register_module (m)
+ -- Recent changes
+ create {FEED_AGGREGATOR_MODULE} m.make
+ a_setup.register_module (m)
-- Miscellanious
create {CMS_DEBUG_MODULE} m.make
diff --git a/modules/feed_aggregator/feed_aggregation.e b/modules/feed_aggregator/feed_aggregation.e
new file mode 100644
index 0000000..1688089
--- /dev/null
+++ b/modules/feed_aggregator/feed_aggregation.e
@@ -0,0 +1,42 @@
+note
+ description: "Feed aggregation parameters."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ FEED_AGGREGATION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: READABLE_STRING_GENERAL)
+ do
+ create name.make_from_string_general (a_name)
+ create {ARRAYED_LIST [READABLE_STRING_8]} locations.make (0)
+ end
+
+feature -- Access
+
+ name: IMMUTABLE_STRING_32
+ -- Associated name.
+
+ description: detachable IMMUTABLE_STRING_32
+ -- Optional description.
+
+ locations: LIST [READABLE_STRING_8]
+ -- List of feed location aggregated into current.
+
+feature -- Element change
+
+ set_description (a_desc: detachable READABLE_STRING_GENERAL)
+ do
+ if a_desc = Void then
+ description := Void
+ else
+ create description.make_from_string_general (a_desc)
+ end
+ end
+
+end
diff --git a/modules/feed_aggregator/feed_aggregator-safe.ecf b/modules/feed_aggregator/feed_aggregator-safe.ecf
new file mode 100644
index 0000000..6baa236
--- /dev/null
+++ b/modules/feed_aggregator/feed_aggregator-safe.ecf
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/feed_aggregator/feed_aggregator_api.e b/modules/feed_aggregator/feed_aggregator_api.e
new file mode 100644
index 0000000..3928a77
--- /dev/null
+++ b/modules/feed_aggregator/feed_aggregator_api.e
@@ -0,0 +1,39 @@
+note
+ description: "API for Feed aggregator module."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ FEED_AGGREGATOR_API
+
+inherit
+ CMS_MODULE_API
+
+create
+ make
+
+feature -- Access
+
+ aggregations: HASH_TABLE [FEED_AGGREGATION, STRING]
+ -- List of feed aggregations.
+ local
+ agg: FEED_AGGREGATION
+ do
+ create Result.make (2)
+ create agg.make ("Blog from Bertrand Meyer")
+ agg.locations.force ("https://bertrandmeyer.com/category/computer-science/feed/")
+ Result.force (agg, "bertrandmeyer")
+
+ create agg.make ("Eiffel Room")
+ agg.locations.force ("https://room.eiffel.com/recent_changes/feed")
+ Result.force (agg, "eiffelroom")
+ end
+
+ aggregation (a_name: READABLE_STRING_GENERAL): detachable FEED_AGGREGATION
+ do
+ if attached a_name.is_valid_as_string_8 then
+ Result := aggregations.item (a_name.as_string_8)
+ end
+ end
+
+end
diff --git a/modules/feed_aggregator/feed_aggregator_module.e b/modules/feed_aggregator/feed_aggregator_module.e
new file mode 100644
index 0000000..c510cb8
--- /dev/null
+++ b/modules/feed_aggregator/feed_aggregator_module.e
@@ -0,0 +1,146 @@
+note
+ description: "CMS module bringing support for feed aggregation."
+ date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
+ revision: "$Revision: 96616 $"
+
+class
+ FEED_AGGREGATOR_MODULE
+
+inherit
+ CMS_MODULE
+ rename
+ module_api as feed_aggregator_api
+ redefine
+ initialize,
+ register_hooks,
+ permissions,
+ feed_aggregator_api
+ end
+
+ CMS_HOOK_BLOCK
+
+ CMS_HOOK_RESPONSE_ALTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ -- Create Current module, disabled by default.
+ do
+ version := "1.0"
+ description := "Feed aggregation"
+ package := "feed"
+ end
+
+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 ("manage feed aggregator")
+ end
+
+feature {CMS_API} -- Module Initialization
+
+ initialize (api: CMS_API)
+ --
+ do
+ Precursor (api)
+ create feed_aggregator_api.make (api)
+ end
+
+feature {CMS_API} -- Access: API
+
+ feed_aggregator_api: detachable FEED_AGGREGATOR_API
+ -- Eventual module api.
+
+feature -- Access: router
+
+ setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
+ --
+ 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)
+ end
+
+feature -- Hooks configuration
+
+ register_hooks (a_response: CMS_RESPONSE)
+ -- Module hooks configuration.
+ do
+ a_response.hooks.subscribe_to_block_hook (Current)
+ a_response.hooks.subscribe_to_response_alter_hook (Current)
+ end
+
+feature -- Hook
+
+ block_list: ITERABLE [like {CMS_BLOCK}.name]
+ -- List of block names, managed by current object.
+ local
+ res: ARRAYED_LIST [like {CMS_BLOCK}.name]
+ do
+ create res.make (5)
+ if attached feed_aggregator_api as l_feed_api then
+ across
+ l_feed_api.aggregations as ic
+ loop
+ res.force ("feed__" + ic.key)
+ end
+ end
+ Result := res
+ end
+
+ get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
+ -- Get block object identified by `a_block_id' and associate with `a_response'.
+ local
+ i: INTEGER
+ s: READABLE_STRING_8
+ b: CMS_CONTENT_BLOCK
+ l_content: STRING
+ pref: STRING
+ do
+ if attached feed_aggregator_api as l_feed_api then
+ pref := "feed__"
+ if a_block_id.starts_with (pref) then
+ s := a_block_id.substring (pref.count + 1, a_block_id.count)
+ else
+ s := a_block_id
+ end
+ if attached l_feed_api.aggregation (s) as l_agg then
+ create l_content.make_empty
+ if attached l_agg.description as l_desc then
+ l_content.append_string_general (l_desc)
+ l_content.append_character ('%N')
+ l_content.append_character ('%N')
+ end
+ across
+ l_agg.locations as ic
+ loop
+ l_content.append ("%T-" + ic.item)
+ l_content.append_character ('%N')
+ end
+ create b.make (a_block_id, l_agg.name, l_content, Void)
+ a_response.add_block (b, Void)
+ end
+ end
+ end
+
+feature -- Hook
+
+ response_alter (a_response: CMS_RESPONSE)
+ do
+-- a_response.add_additional_head_line ("[
+--
+-- ]", True)
+ end
+
+end
diff --git a/package.iron b/package.iron
index fd2052a..be2ec6b 100644
--- a/package.iron
+++ b/package.iron
@@ -1,4 +1,4 @@
-package ROC_cms
+package ROC
project
cms = "cms-safe.ecf"
@@ -19,6 +19,21 @@ project
basic_auth = "modules/basic_auth/basic_auth.ecf"
node = "modules/node/node-safe.ecf"
node = "modules/node/node.ecf"
+ demo = "examples/demo/demo-safe.ecf"
+ cms_demo_module = "examples/demo/modules/demo/cms_demo_module-safe.ecf"
+ config_tests = "library/configuration/tests/config_tests-safe.ecf"
+ email_service = "library/email/email-safe.ecf"
+ persistence_sqlite3 = "library/persistence/sqlite3/persistence_sqlite3-safe.ecf"
+ store_mysql = "library/persistence/store_mysql/store_mysql-safe.ecf"
+ persistence_store_odbc = "library/persistence/store_odbc/store_odbc-safe.ecf"
+ tests_store_odbc = "library/persistence/store_odbc/tests/tests-safe.ecf"
+ admin = "modules/admin/admin-safe.ecf"
+ auth_module = "modules/auth/auth-safe.ecf"
+ cms_blog_module = "modules/blog/cms_blog_module-safe.ecf"
+ feed_aggregator = "modules/feed_aggregator/feed_aggregator-safe.ecf"
+ oauth_module = "modules/oauth20/oauth20-safe.ecf"
+ openid_module = "modules/openid/openid-safe.ecf"
+ recent_changes = "modules/recent_changes/recent_changes-safe.ecf"
note
title: ROC CMS
@@ -27,5 +42,6 @@ note
license: Eiffel Forum v2
copyright: Jocelyn Fiat, Javier Velilla, Eiffel Software
link[source]: "Github" https://github.com/EiffelWebFramework/ROC.git
+-- link[doc]: "Documentation" http://
end
diff --git a/src/kernel/content/block/condition/cms_block_condition.e b/src/kernel/content/block/condition/cms_block_condition.e
new file mode 100644
index 0000000..4c4c7a5
--- /dev/null
+++ b/src/kernel/content/block/condition/cms_block_condition.e
@@ -0,0 +1,24 @@
+note
+ description: "Condition for block to be displayed."
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ CMS_BLOCK_CONDITION
+
+feature -- Access
+
+ description: READABLE_STRING_32
+ deferred
+ end
+
+feature -- Evaluation
+
+ satisfied_for_response (res: CMS_RESPONSE): BOOLEAN
+ deferred
+ 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/kernel/content/block/condition/cms_block_expression_condition.e b/src/kernel/content/block/condition/cms_block_expression_condition.e
new file mode 100644
index 0000000..72e5be5
--- /dev/null
+++ b/src/kernel/content/block/condition/cms_block_expression_condition.e
@@ -0,0 +1,46 @@
+note
+ description: "Condition for block to be displayed."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ CMS_BLOCK_EXPRESSION_CONDITION
+
+inherit
+ CMS_BLOCK_CONDITION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_exp: READABLE_STRING_8)
+ do
+ expression := a_exp
+ end
+
+feature -- Access
+
+ description: READABLE_STRING_32
+ do
+ create Result.make_from_string_general ("Expression: %"")
+ Result.append_string_general (expression)
+ Result.append_character ('%"')
+ end
+
+ expression: STRING
+
+feature -- Evaluation
+
+ satisfied_for_response (res: CMS_RESPONSE): BOOLEAN
+ do
+ if expression.same_string ("is_front") then
+ Result := res.is_front
+ elseif expression.starts_with ("path=") then
+ 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)"
+end
diff --git a/src/kernel/content/cms_block.e b/src/kernel/content/cms_block.e
index 94d4ed1..0bbf1aa 100644
--- a/src/kernel/content/cms_block.e
+++ b/src/kernel/content/cms_block.e
@@ -39,6 +39,9 @@ feature -- Status report
deferred
end
+ conditions: detachable LIST [CMS_BLOCK_CONDITION]
+ -- Optional block condition to be enabled.
+
feature -- Element change
add_css_class (a_class: READABLE_STRING_8)