Files
ROC/modules/node/cms_node_module.e
Jocelyn Fiat 78ef7af5f8 Removed obsolete calls, harmonized predefine response, added non admin user pages.
When access is denied, also provide when possible and wanted, the needed
permissions so that in the future, user will be able to ask for
permission easily.
Renamed previous user handlers as admin user handlers.
Added non admin user handler /user/{uid} .
Add new `send_...` response to `CMS_API.response_api`, and use them
instead of `create {...RESPONSE}.... ; execute`.
Fixed potential issue with storage mailer initialization if folder does
not exist.
Added utf_8_encoded helpers function on CMS_API interface.
Fixed a few unicode potential issues.
Removed a few obsolete calls.
2017-06-09 09:29:41 +02:00

415 lines
12 KiB
Plaintext

note
description: "CMS module bringing support for NODE management."
date: "$Date$"
revision: "$Revision$"
class
CMS_NODE_MODULE
inherit
CMS_MODULE
redefine
setup_hooks,
initialize,
is_installed,
install,
module_api,
permissions
end
CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_RESPONSE_ALTER
CMS_HOOK_BLOCK
CMS_RECENT_CHANGES_HOOK
CMS_SITEMAP_HOOK
CMS_TAXONOMY_HOOK
create
make
feature {NONE} -- Initialization
make
-- Create Current module, disabled by default.
do
version := "1.0.0.1"
description := "Service to manage content based on 'node'"
package := "core"
-- Optional dependencies, mainly for information.
put_dependency ({CMS_RECENT_CHANGES_MODULE}, False)
put_dependency ({CMS_SITEMAP_MODULE}, False)
put_dependency ({CMS_TAXONOMY_MODULE}, False)
end
feature -- Access
name: STRING = "node"
feature {CMS_API} -- Module Initialization
initialize (a_api: CMS_API)
-- <Precursor>
local
l_node_api: like node_api
l_node_storage: CMS_NODE_STORAGE_I
do
Precursor (a_api)
-- Storage initialization
if attached a_api.storage.as_sql_storage as l_storage_sql then
create {CMS_NODE_STORAGE_SQL} l_node_storage.make (l_storage_sql)
else
-- FIXME: in case of NULL storage, should Current be disabled?
create {CMS_NODE_STORAGE_NULL} l_node_storage.make
end
-- Node API initialization
create l_node_api.make_with_storage (a_api, l_node_storage)
node_api := l_node_api
ensure then
node_api_set: node_api /= Void
end
feature {CMS_API} -- Module management
is_installed (a_api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := Precursor (a_api)
if Result and attached a_api.storage.as_sql_storage as l_sql_storage then
Result := l_sql_storage.sql_table_exists ("nodes")
end
end
install (a_api: CMS_API)
do
-- Schema
if attached a_api.storage.as_sql_storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void)
if l_sql_storage.has_error then
a_api.logger.put_error ("Could not initialize database for module [" + name + "]", generating_type)
else
Precursor {CMS_MODULE} (a_api)
end
end
end
feature {CMS_API} -- Access: API
module_api: detachable CMS_MODULE_API
-- <Precursor>
do
if attached node_api as l_api then
Result := l_api
else
-- Current is initialized, so node_api should be set.
check has_node_api: False end
end
end
node_api: detachable CMS_NODE_API
-- <Precursor>
feature -- Access
permissions: LIST [READABLE_STRING_8]
-- <Precursor>.
local
l_type_name: READABLE_STRING_8
do
Result := Precursor
Result.force ("create any node")
Result.force ("export any node")
if attached node_api as l_node_api then
across
l_node_api.node_types as ic
loop
l_type_name := ic.item.name
if not l_type_name.is_whitespace then
Result.force ("create " + l_type_name)
Result.force ("view any " + l_type_name)
Result.force ("edit any " + l_type_name)
Result.force ("delete any " + l_type_name)
Result.force ("trash any " + l_type_name)
Result.force ("restore any " + l_type_name)
Result.force ("view revisions any " + l_type_name)
Result.force ("view own " + l_type_name)
Result.force ("edit own " + l_type_name)
Result.force ("delete own " + l_type_name)
Result.force ("trash own " + l_type_name)
Result.force ("restore own " + l_type_name)
Result.force ("view unpublished " + l_type_name)
Result.force ("view revisions own " + l_type_name)
Result.force ("export " + l_type_name)
end
end
Result.force ("view trash")
Result.force ("view own trash")
end
end
feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
if attached node_api as l_node_api then
configure_web (a_api, l_node_api, a_router)
end
end
configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER)
local
l_node_handler: NODE_HANDLER
l_nodes_handler: NODES_HANDLER
l_uri_mapping: WSF_URI_MAPPING
l_trash_handler: TRASH_HANDLER
do
-- TODO: for now, focused only on web interface, add REST api later. [2015-April-29]
create l_node_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/node", l_node_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
a_router.handle ("/node/add/{type}", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/revision", l_node_handler, a_router.methods_get)
a_router.handle ("/node/{id}/edit", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/delete", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/trash", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}", l_node_handler, a_router.methods_get)
-- For now: no REST API handling... a_router.methods_get_put_delete + a_router.methods_get_post)
-- Nodes
create l_nodes_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/nodes", l_nodes_handler)
a_router.map (l_uri_mapping, a_router.methods_get)
a_router.handle ("/nodes/{type}", l_nodes_handler, a_router.methods_get)
a_router.handle ("/nodes/{type}/feed", l_nodes_handler, a_router.methods_get)
-- Trash
create l_trash_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/trash", l_trash_handler)
a_router.map (l_uri_mapping, a_router.methods_get)
end
feature -- Hooks
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
-- <Precursor>
do
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_hooks.subscribe_to_hook (Current, {CMS_RECENT_CHANGES_HOOK})
a_hooks.subscribe_to_hook (Current, {CMS_SITEMAP_HOOK})
a_hooks.subscribe_to_hook (Current, {CMS_TAXONOMY_HOOK})
end
response_alter (a_response: CMS_RESPONSE)
-- <Precursor>
do
a_response.add_style (a_response.module_resource_url (Current, "/files/css/node.css", Void), Void)
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
-- <Precursor>
do
Result := <<"?node-info">>
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
local
-- b: CMS_CONTENT_BLOCK
do
-- create b.make (a_block_id, "Block::node", "This is a block test", Void)
-- a_response.add_block (b, "sidebar_second")
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
perms: ARRAYED_LIST [READABLE_STRING_8]
do
debug
create lnk.make ("List of nodes", "nodes")
a_menu_system.navigation_menu.extend (lnk)
end
create lnk.make ("Trash", "trash")
a_menu_system.navigation_menu.extend (lnk)
lnk.set_permission_arguments (<<"view trash">>)
create lnk.make ("Create ..", "node")
a_menu_system.navigation_menu.extend (lnk)
if attached node_api as l_node_api then
create perms.make (2)
perms.force ("create any node")
across
l_node_api.node_types as ic
loop
perms.force ("create " + ic.item.name)
end
lnk.set_permission_arguments (perms)
end
end
recent_changes_sources: detachable LIST [READABLE_STRING_8]
-- <Precursor>
local
lst: ARRAYED_LIST [READABLE_STRING_8]
do
if
attached node_api as l_node_api and then
attached l_node_api.node_types as l_types and then
not l_types.is_empty
then
create lst.make (l_types.count)
across
l_types as ic
loop
lst.force (ic.item.name)
end
Result := lst
end
end
populate_recent_changes (a_changes: CMS_RECENT_CHANGE_CONTAINER; a_current_user: detachable CMS_USER)
local
params: CMS_DATA_QUERY_PARAMETERS
ch: CMS_RECENT_CHANGE_ITEM
n: CMS_NODE
l_info: STRING_8
l_src: detachable READABLE_STRING_8
l_nodes: ITERABLE [CMS_NODE]
l_date: detachable DATE_TIME
do
create params.make (0, a_changes.limit)
if attached node_api as l_node_api then
l_src := a_changes.source
l_date := a_changes.date
if l_date = Void then
create l_date.make_now_utc
end
l_nodes := l_node_api.recent_node_changes_before (params, l_date)
across l_nodes as ic loop
n := ic.item
if l_src = Void or else l_src.is_case_insensitive_equal_general (n.content_type) then
if l_node_api.has_permission_for_action_on_node ("view", n, a_current_user) then
n := l_node_api.full_node (n)
create ch.make (n.content_type, create {CMS_LOCAL_LINK}.make (n.title, "node/" + n.id.out), n.modification_date)
if n.creation_date ~ n.modification_date then
l_info := "new"
if not n.is_published then
l_info.append (" (unpublished)")
end
else
if n.is_trashed then
l_info := "deleted"
else
l_info := "updated"
if not n.is_published then
l_info.append (" (unpublished)")
end
end
end
ch.set_information (l_info)
ch.set_author (n.editor)
ch.set_summary (n.summary)
if attached {CMS_TAXONOMY_API} l_node_api.cms_api.module_api ({CMS_TAXONOMY_MODULE}) as l_taxonomy_api then
if attached l_taxonomy_api.terms_of_content (n, Void) as l_terms then
across
l_terms as t_ic
loop
ch.add_category (t_ic.item.text)
end
end
end
a_changes.force (ch)
else
-- Forbidden
-- FIXME: provide a visual indication!
end
end
end
end
end
populate_content_associated_with_term (t: CMS_TERM; a_contents: CMS_TAXONOMY_ENTITY_CONTAINER)
local
l_node_typenames: ARRAYED_LIST [READABLE_STRING_8]
nid: INTEGER_64
l_info_to_remove: ARRAYED_LIST [TUPLE [entity: READABLE_STRING_32; typename: detachable READABLE_STRING_32]]
do
if
attached node_api as l_node_api and then
attached l_node_api.node_types as l_node_types and then
not l_node_types.is_empty
then
create l_node_typenames.make (l_node_types.count)
across
l_node_types as ic
loop
l_node_typenames.force (ic.item.name)
end
create l_info_to_remove.make (0)
across
a_contents.taxonomy_info as ic
loop
if
attached ic.item.typename as l_typename and then
across l_node_typenames as t_ic some t_ic.item.same_string_general (l_typename) end
then
if ic.item.entity.is_integer then
nid := ic.item.entity.to_integer_64
if nid > 0 and then attached l_node_api.node (nid) as l_node then
if l_node.link = Void then
l_node.set_link (l_node_api.node_link (l_node))
end
a_contents.force (create {CMS_TAXONOMY_ENTITY}.make (l_node, l_node.modification_date))
l_info_to_remove.force (ic.item)
end
end
end
end
across
l_info_to_remove as ic
loop
a_contents.taxonomy_info.prune_all (ic.item)
end
end
end
populate_sitemap (a_sitemap: CMS_SITEMAP)
-- Populate `a_sitemap`.
local
i: CMS_SITEMAP_ITEM
n: CMS_NODE
do
if attached node_api as l_node_api then
across
l_node_api.nodes as ic -- FIXME: do not load all nodes at once!
loop
n := ic.item
create i.make (l_node_api.node_link (n), n.modification_date)
a_sitemap.force (i)
end
end
end
end