diff --git a/examples/demo/demo.ecf b/examples/demo/demo.ecf
index 861dbe7..d6466eb 100644
--- a/examples/demo/demo.ecf
+++ b/examples/demo/demo.ecf
@@ -38,6 +38,7 @@
+
diff --git a/examples/demo/src/demo_cms_execution.e b/examples/demo/src/demo_cms_execution.e
index 7c6fb30..1d66e23 100644
--- a/examples/demo/src/demo_cms_execution.e
+++ b/examples/demo/src/demo_cms_execution.e
@@ -52,7 +52,7 @@ feature -- CMS modules
a_setup.register_module (create {CMS_OAUTH_20_MODULE}.make)
a_setup.register_module (create {CMS_OPENID_MODULE}.make)
a_setup.register_module (create {CMS_SESSION_AUTH_MODULE}.make)
-
+
-- User
-- Nodes
@@ -68,6 +68,7 @@ feature -- CMS modules
-- Misc
a_setup.register_module (create {CMS_SEO_MODULE}.make)
+ a_setup.register_module (create {CMS_SITEMAP_MODULE}.make)
a_setup.register_module (create {CMS_COMMENTS_MODULE}.make)
-- Taxonomy
diff --git a/modules/node/node-safe.ecf b/modules/node/node-safe.ecf
index aafe6b3..b0322d5 100644
--- a/modules/node/node-safe.ecf
+++ b/modules/node/node-safe.ecf
@@ -15,6 +15,7 @@
+
diff --git a/modules/node/node.ecf b/modules/node/node.ecf
index 046c787..8593493 100644
--- a/modules/node/node.ecf
+++ b/modules/node/node.ecf
@@ -14,6 +14,7 @@
+
diff --git a/modules/sitemap/cms_sitemap.e b/modules/sitemap/cms_sitemap.e
new file mode 100644
index 0000000..eb905f1
--- /dev/null
+++ b/modules/sitemap/cms_sitemap.e
@@ -0,0 +1,71 @@
+note
+ description: "Container of sitemap items."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ CMS_SITEMAP
+
+inherit
+ ITERABLE [CMS_SITEMAP_ITEM]
+
+create
+ make
+
+feature -- Initialization
+
+ make (a_date: DATE_TIME)
+ do
+ create items.make (100)
+ end
+
+feature -- Access
+
+ items: ARRAYED_LIST [CMS_SITEMAP_ITEM]
+ -- List of sitemap entries.
+
+ count: INTEGER
+ -- Number of change items.
+ do
+ Result := items.count
+ end
+
+feature -- Access
+
+ new_cursor: ITERATION_CURSOR [CMS_SITEMAP_ITEM]
+ --
+ do
+ Result := items.new_cursor
+ end
+
+feature -- Change
+
+ force (a_item: CMS_SITEMAP_ITEM)
+ -- Add `a_item'.
+ do
+ items.force (a_item)
+ end
+
+feature -- Sorting
+
+ sort
+ -- Sort `items' from older, to newer.
+ do
+ sitemap_item_sorter.sort (items)
+ end
+
+ reverse_sort
+ -- Sort `items' from newer to older.
+ do
+ sitemap_item_sorter.reverse_sort (items)
+ end
+
+feature {NONE} -- Implementation
+
+ sitemap_item_sorter: QUICK_SORTER [CMS_SITEMAP_ITEM]
+ -- New change item sorter.
+ once
+ create Result.make (create {COMPARABLE_COMPARATOR [CMS_SITEMAP_ITEM]})
+ end
+
+end
diff --git a/modules/sitemap/cms_sitemap_hook.e b/modules/sitemap/cms_sitemap_hook.e
new file mode 100644
index 0000000..3e4318a
--- /dev/null
+++ b/modules/sitemap/cms_sitemap_hook.e
@@ -0,0 +1,19 @@
+note
+ description: "Hook provided by module {CMS_RECENT_CHANGES_MODULE}."
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ CMS_SITEMAP_HOOK
+
+inherit
+ CMS_HOOK
+
+feature -- Invocation
+
+ populate_sitemap (a_sitemap: CMS_SITEMAP)
+ -- Populate `a_sitemap`.
+ deferred
+ end
+
+end
diff --git a/modules/sitemap/cms_sitemap_item.e b/modules/sitemap/cms_sitemap_item.e
new file mode 100644
index 0000000..d1b7449
--- /dev/null
+++ b/modules/sitemap/cms_sitemap_item.e
@@ -0,0 +1,77 @@
+note
+ description: "Information related to sitemap entry."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ CMS_SITEMAP_ITEM
+
+inherit
+ COMPARABLE
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (lnk: CMS_LOCAL_LINK; a_date_time: DATE_TIME)
+ do
+ link := lnk
+ date := a_date_time
+ set_change_frequency_to_weekly
+ priority := 1
+ end
+
+feature -- Access
+
+ link: CMS_LOCAL_LINK
+ -- Local link associated with the resource.
+
+ date: DATE_TIME
+ -- Last modification.
+
+ change_frequency: READABLE_STRING_8
+ -- Frequency of changes
+ -- monthly, daily, ...
+
+ priority: NATURAL_8
+ -- Priority
+
+feature -- Element change
+
+ set_change_frequency_to_monthly
+ do
+ set_change_frequency ("monthly")
+ end
+
+ set_change_frequency_to_weekly
+ do
+ set_change_frequency ("weekly")
+ end
+
+ set_change_frequency_to_daily
+ do
+ set_change_frequency ("daily")
+ end
+
+ set_change_frequency (freq: like change_frequency)
+ -- Set `change_frequency' to `freq'.
+ do
+ change_frequency := freq
+ end
+
+ set_priority (p: like priority)
+ -- Set `priority' to `p'.
+ do
+ priority := p
+ end
+
+feature -- Comparison
+
+ is_less alias "<" (other: like Current): BOOLEAN
+ --
+ do
+ Result := date < other.date
+ end
+
+end
diff --git a/modules/sitemap/cms_sitemap_module.e b/modules/sitemap/cms_sitemap_module.e
new file mode 100644
index 0000000..307af50
--- /dev/null
+++ b/modules/sitemap/cms_sitemap_module.e
@@ -0,0 +1,185 @@
+note
+ description: "CMS module that brings support for recent changes."
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ CMS_SITEMAP_MODULE
+
+inherit
+ CMS_MODULE
+ rename
+ module_api as sitemap_api
+ redefine
+ permissions
+ end
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ -- Create Current module, disabled by default.
+ do
+ version := "1.0"
+ description := "Service to build sitemap"
+ package := "seo"
+ end
+
+feature -- Access
+
+ name: STRING = "sitemap"
+
+ permissions: LIST [READABLE_STRING_8]
+ -- List of permission ids, used by this module, and declared.
+ do
+ Result := Precursor
+ Result.force ("admin sitemap")
+ end
+
+feature -- Access: router
+
+ setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
+ --
+ do
+ a_router.handle ("/sitemap.xml", create {WSF_URI_AGENT_HANDLER}.make (agent handle_sitemp_xml (a_api, ?, ?)), a_router.methods_head_get)
+ end
+
+feature -- Hook
+
+ sitemap (a_response: CMS_RESPONSE): CMS_SITEMAP
+ local
+ l_user: detachable CMS_USER
+-- lnk: FEED_LINK
+-- nb: NATURAL_32
+-- s: STRING_32
+ do
+ l_user := Void -- Public access for the feed!
+ create Result.make (create {DATE_TIME}.make_now_utc)
+ if attached a_response.api.hooks.subscribers ({CMS_SITEMAP_HOOK}) as lst then
+ across
+ lst as ic
+ loop
+ if attached {CMS_SITEMAP_HOOK} ic.item as h then
+ h.populate_sitemap (Result)
+ end
+ end
+ end
+
+-- create l_feed.make ("CMS Recent changes")
+-- l_feed.set_date (create {DATE_TIME}.make_now_utc)
+-- nb := a_size
+-- across
+-- l_changes as ic
+-- until
+-- nb = 0
+-- loop
+-- ch := ic.item
+-- create l_feed_item.make (ch.link.title)
+-- l_feed_item.set_date (ch.date)
+--
+-- create s.make_empty
+-- if attached ch.information as l_information then
+-- s.append (l_information)
+-- end
+-- if attached ch.summary as sum then
+-- if not s.is_empty then
+-- s.append ("%N%N")
+-- end
+-- s.append (sum)
+-- end
+-- l_feed_item.set_description (s)
+-- if attached ch.categories as lst then
+-- across
+-- lst as cats_ic
+-- loop
+-- l_feed_item.set_category (cats_ic.item)
+-- end
+-- end
+-- create lnk.make (a_response.absolute_url (ch.link.location, Void))
+-- l_feed_item.links.force (lnk, "")
+-- l_feed.extend (l_feed_item)
+-- nb := nb - 1
+-- end
+-- l_feed.sort
+-- Result := l_feed
+ end
+
+feature -- Handler
+
+ handle_sitemp_xml (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
+ local
+ r: CMS_RESPONSE
+-- htdate: HTTP_DATE
+ mesg: CMS_CUSTOM_RESPONSE_MESSAGE
+ l_xml: STRING
+ l_cache: CMS_FILE_STRING_8_CACHE
+ do
+ create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
+ create l_cache.make (api.files_location.extended ("sitemap.xml"))
+ if
+ l_cache.exists and then
+ not l_cache.expired (Void, 7*24*60*60) and then
+ attached l_cache.item as l_cached_xml
+ then
+ create mesg.make ({HTTP_STATUS_CODE}.ok)
+ mesg.header.put_content_type ("application/xml")
+ mesg.set_payload (l_cached_xml)
+ res.send (mesg)
+ elseif attached sitemap (r) as l_sitemap then
+ create l_xml.make (1_024)
+ l_xml.append ("%N")
+ l_xml.append ("%N")
+ l_xml.append ("%N")
+ across
+ l_sitemap as ic
+ loop
+ l_xml.append ("%N")
+ l_xml.append (" " + r.absolute_url (ic.item.link.location, Void) + "%N")
+ l_xml.append (" "); append_date_output (ic.item.date, l_xml); l_xml.append ("%N")
+ l_xml.append (" " + ic.item.change_frequency + "%N")
+ l_xml.append (" " + ic.item.priority.out + "%N")
+ l_xml.append ("%N")
+ end
+ l_xml.append ("%N")
+ l_cache.put (l_xml)
+
+ create mesg.make ({HTTP_STATUS_CODE}.ok)
+ mesg.header.put_content_type ("application/xml")
+ mesg.header.put_header ("Accept-Ranges: bytes")
+ mesg.header.put_header ("Vary: Accept-Encoding,User-Agent")
+ mesg.set_payload (l_xml)
+ res.send (mesg)
+ else
+ create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, api)
+ r.execute
+ end
+ end
+
+ append_date_output (dt: DATE_TIME; a_output: STRING)
+ --| 2017-02-07T21:09:21+00:00
+ do
+ a_output.append_integer (dt.year)
+ a_output.append_character ('-')
+ append_two_digits_integer (dt.month, a_output)
+ a_output.append_character ('-')
+ append_two_digits_integer (dt.day, a_output)
+ a_output.append_character ('T')
+ append_two_digits_integer (dt.hour, a_output)
+ a_output.append_character (':')
+ append_two_digits_integer (dt.minute, a_output)
+ a_output.append_character (':')
+ append_two_digits_integer (dt.second, a_output)
+ a_output.append_string ("+00:00")
+ end
+
+ append_two_digits_integer (i: INTEGER; s: STRING_8)
+ do
+ if i < 10 then
+ s.append_character ('0')
+ end
+ s.append_integer (i)
+ end
+
+end
diff --git a/modules/sitemap/sitemap-safe.ecf b/modules/sitemap/sitemap-safe.ecf
new file mode 100644
index 0000000..484d43c
--- /dev/null
+++ b/modules/sitemap/sitemap-safe.ecf
@@ -0,0 +1,26 @@
+
+
+
+
+
+ /.svn$
+ /CVS$
+ /EIFGENs$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/sitemap/sitemap.ecf b/modules/sitemap/sitemap.ecf
new file mode 100644
index 0000000..e3b4e65
--- /dev/null
+++ b/modules/sitemap/sitemap.ecf
@@ -0,0 +1,26 @@
+
+
+
+
+
+ /.svn$
+ /CVS$
+ /EIFGENs$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+