Files
ROC/modules/node/submodules/page/cms_page_module.e
Jocelyn Fiat c10faceaf6 Better log message during import.
Fixed SQL storage for comments.
2017-01-27 23:53:27 +01:00

407 lines
13 KiB
Plaintext

note
description: "Node page implementation."
date: "$Date$"
revision: "$Revision$"
class
CMS_PAGE_MODULE
inherit
CMS_MODULE
rename
module_api as page_api
redefine
setup_hooks,
initialize,
install, is_installed,
page_api
end
CMS_HOOK_EXPORT
CMS_HOOK_IMPORT
CMS_EXPORT_NODE_UTILITIES
CMS_IMPORT_NODE_UTILITIES
create
make
feature {NONE} -- Initialization
make
do
version := "1.0"
description := "Page service"
package := "content"
add_dependency ({CMS_NODE_MODULE})
end
feature -- Access
name: STRING = "page"
feature {CMS_API} -- Module Initialization
initialize (a_api: CMS_API)
-- <Precursor>
local
p1,p2: CMS_PAGE
ct: CMS_PAGE_NODE_TYPE
do
Precursor (a_api)
if attached {CMS_NODE_API} a_api.module_api ({CMS_NODE_MODULE}) as l_node_api then
node_api := l_node_api
create page_api.make (a_api, l_node_api)
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
-- For now, we only have extension based on SQL statement.
if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_PAGE_EXTENSION}.make (l_node_api, l_sql_node_storage))
-- FIXME: the following code is mostly for test purpose/initialization, remove later
if l_sql_node_storage.sql_table_items_count ("page_nodes") = 0 then
if attached a_api.user_api.user_by_id (1) as u then
create ct
p1 := ct.new_node (Void)
p1.set_title ("Welcome")
p1.set_content ("Welcome, you are using the ROC Eiffel CMS", Void, Void) -- Use default format
p1.set_author (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_parent (p1)
l_sql_node_storage.save_node (p2)
end
end
else
-- FIXME: maybe provide a default solution based on file system, when no SQL storage is available.
-- IDEA: we could also have generic extension to node system, that handle generic addition field.
end
end
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 ("page_nodes")
end
end
install (a_api: CMS_API)
do
-- Schema
if attached a_api.storage.as_sql_storage as l_sql_storage then
if attached a_api.module ({CMS_NODE_MODULE}) as l_node_module then
l_sql_storage.sql_execute_file_script (a_api.module_resource_location (l_node_module, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void)
end
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
page_api: detachable CMS_PAGE_API
-- <Precursor>
node_api: detachable CMS_NODE_API
feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
end
feature -- Hooks
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
do
a_hooks.subscribe_to_export_hook (Current)
a_hooks.subscribe_to_import_hook (Current)
end
export_to (a_export_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_export_ctx: CMS_EXPORT_CONTEXT; 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_PAGE
p: PATH
d: DIRECTORY
f: PLAIN_TEXT_FILE
lst: LIST [CMS_NODE]
do
if
attached node_api as l_node_api and then
attached l_node_api.node_type ("page") as l_node_type 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
if
a_response.has_permissions (<<"export any node", "export " + l_node_type.name>>) and then
attached page_api as l_page_api
then
lst := l_page_api.pages
a_export_ctx.log ("Exporting " + lst.count.out + " notes of type `" + l_node_type.name + "`.")
create d.make_with_path (a_export_ctx.location.extended ("nodes").extended (l_node_type.name))
if d.exists then
d.recursive_delete
end
across
lst as ic
loop
if attached {CMS_PAGE} ic.item as l_page_node then
n := l_page_api.full_page_node (l_page_node)
a_export_ctx.log (n.content_type + " #" + n.id.out)
p := a_export_ctx.location.extended ("nodes").extended (n.content_type).extended (n.id.out).appended_with_extension ("json")
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 (page_node_to_json (n, l_page_api)))
f.close
end
-- Revisions.
if
attached l_node_api.node_revisions (n) as l_revisions and then
l_revisions.count > 1
then
a_export_ctx.log (n.content_type + " " + l_revisions.count.out + " revisions.")
p := a_export_ctx.location.extended ("nodes").extended (n.content_type).extended (n.id.out)
create d.make_with_path (p)
if not d.exists then
d.recursive_create_dir
end
across
l_revisions as revs_ic
loop
if attached {CMS_PAGE} revs_ic.item as l_rev_page then
create f.make_with_path (p.extended ("rev-" + n.revision.out).appended_with_extension ("json"))
if not f.exists or else f.is_access_writable then
f.open_write
f.put_string (json_to_string (page_node_to_json (l_rev_page, l_page_api)))
end
f.close
end
end
end
end
end
end
end
end
page_node_to_json (a_page: CMS_PAGE; a_page_api: CMS_PAGE_API): JSON_OBJECT
local
j: JSON_OBJECT
p: CMS_PAGE
do
Result := node_to_json (a_page, a_page_api.node_api)
if attached a_page.parent as l_parent_page then
p := a_page_api.full_page_node (l_parent_page)
create j.make_empty
j.put_string (p.content_type, "type")
j.put_string (p.title, "title")
j.put_integer (p.id, "nid")
if attached p.link as lnk then
j.put (link_to_json (lnk), "link")
end
Result.put (j, "parent")
end
end
import_from (a_import_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_import_ctx: CMS_IMPORT_CONTEXT; a_response: CMS_RESPONSE)
-- Import data identified by `a_import_id_list',
-- or import all data if `a_import_id_list' is Void.
local
l_id: STRING_32
p, fp: PATH
d: DIRECTORY
loc: READABLE_STRING_8
l_parentable_list: ARRAYED_LIST [TUPLE [page: CMS_PAGE; parent: CMS_PAGE]]
l_new_pages: STRING_TABLE [CMS_PAGE] -- indexed by link location, if any.
l_entity: detachable CMS_PAGE
do
if
attached node_api as l_node_api and then
attached {CMS_PAGE_NODE_TYPE} l_node_api.node_type ({CMS_PAGE_NODE_TYPE}.name) as l_node_type and then
attached page_api as l_page_api and then
( a_import_id_list = Void
or else across a_import_id_list as ic some ic.item.same_string (l_node_type.name) end
)
then
if
a_response.has_permissions (<<"import any node", "import " + l_node_type.name>>)
then
p := a_import_ctx.location.extended ("nodes").extended (l_node_type.name)
create d.make_with_path (p)
if d.exists and then d.is_readable then
create l_parentable_list.make (0)
create l_new_pages.make (0)
a_import_ctx.log ("Importing [" + l_node_type.name + "] items ..")
across
d.entries as ic
loop
if attached ic.item.extension as ext and then ext.same_string_general ("json") then
l_id := ic.item.name
l_id.remove_tail (ext.count + 1)
fp := p.extended_path (ic.item)
if attached json_object_from_location (fp) as j then
if
attached json_string_item (j, "type") as l_type and then
l_type.same_string_general (l_node_type.name)
then
l_entity := json_to_node_page (l_node_type, j, l_node_api)
if l_entity /= Void then
if l_entity.is_published then
if l_entity.author = Void then
-- FIXME!!!
l_entity.set_author (l_page_api.cms_api.user)
a_import_ctx.log (l_node_type.name + " %"" + fp.utf_8_name + "%" WARNING (Author is unknown!)")
end
if attached l_entity.author as l_author then
if
attached l_page_api.pages_with_title (l_entity.title) as l_pages and then
not l_pages.is_empty
then
-- Page Already exists!
-- FIXME/TODO
l_entity := l_pages.first
a_import_ctx.log (l_node_type.name + " from %"" + fp.utf_8_name + "%" SKIPPED (already exists for user #" + l_author.id.out + ")!")
else
if
attached l_entity.parent as l_parent and then
not l_parent.has_id
then
l_parentable_list.extend ([l_entity, l_parent])
l_entity.set_parent (Void)
end
l_page_api.import_page (l_entity)
apply_taxonomy_to_node (j, l_entity, l_page_api.cms_api)
l_new_pages.force (l_entity, l_node_api.node_path (l_entity))
a_import_ctx.log (l_node_type.name + " #" + l_entity.id.out + " imported from %"" + fp.utf_8_name + "%" for user #" + l_author.id.out + ".")
if attached {CMS_LOCAL_LINK} l_entity.link as l_link then
loc := l_node_api.node_path (l_entity)
if not l_link.location.starts_with_general ("node/") then
l_page_api.cms_api.set_path_alias (loc, l_link.location, False)
l_new_pages.force (l_entity, l_link.location)
end
end
end
if l_entity /= Void and then l_entity.has_id then
-- Support for comments
import_comments_file_for_entity (p.extended (l_id).extended ("comments.json"), l_entity, l_node_api.cms_api, a_import_ctx)
end
else
a_import_ctx.log (l_node_type.name + " %"" + fp.utf_8_name + "%" skipped (Author is unknown!)")
end
else
a_import_ctx.log (l_node_type.name + " %"" + fp.utf_8_name + "%" skipped (Status is Not Published!)")
end
end
end
end
end
end
across
l_parentable_list as ic
loop
l_entity := ic.item.page
update_page_parent (l_entity, ic.item.parent, l_new_pages)
if attached l_entity.parent as l_parent then
a_import_ctx.log (l_node_type.name + " #" + l_entity.id.out + " assigned to parent #" + l_parent.id.out)
l_page_api.import_page (l_entity)
else
a_import_ctx.log (l_node_type.name + " #" + l_entity.id.out + " : unable to find parent!")
end
end
end
else
a_import_ctx.log ("Importing [" + l_node_type.name + "] NOT ALLOWED!")
end
end
end
json_to_node_page (a_node_type: CMS_PAGE_NODE_TYPE; j: JSON_OBJECT; a_node_api: CMS_NODE_API): detachable CMS_PAGE
local
p: detachable CMS_PAGE
do
if attached json_to_node (a_node_type, j, a_node_api) as l_node then
Result := a_node_type.new_node (l_node)
if
attached {JSON_OBJECT} j.item ("parent") as j_parent and then
attached json_string_item (j_parent, "title") as l_title
then
p := a_node_type.new_node_with_title (l_title, Void)
if
attached {JSON_OBJECT} j_parent.item ("link") as j_link and then
attached json_to_local_link (j_link) as l_parent_lnk and then
not l_parent_lnk.location.starts_with ("node/")
then
p.set_link (l_parent_lnk)
else
-- No link ..
end
if not Result.is_parent_of (p) then
Result.set_parent (p)
end
end
end
end
update_page_parent (a_page: CMS_PAGE; a_parent: CMS_PAGE; a_new_pages: STRING_TABLE [CMS_PAGE])
require
no_parent_set: a_page.parent = Void
local
lst: detachable LIST [CMS_PAGE]
p: detachable CMS_PAGE
do
p := a_parent
if attached page_api as l_page_api then
if attached a_parent.link as l_parent_lnk then
lst := l_page_api.pages_with_title (a_parent.title)
across
lst as ic
until
p.has_id
loop
if
attached ic.item.link as lnk and then
lnk.location.same_string_general (l_parent_lnk.location)
then
p := ic.item
end
end
else
lst := l_page_api.pages_with_title (a_parent.title)
if lst.count = 1 then
p := lst.first
end
end
end
if p.has_id then
a_page.set_parent (p)
end
end
end