Merged CMS based on concurrent EWF (i.e ewf_v1) with blog branch.

This commit is contained in:
Jocelyn Fiat
2015-06-15 11:27:44 +02:00
75 changed files with 2069 additions and 512 deletions

View File

@@ -16,20 +16,21 @@ inherit
REFACTORING_HELPER
create
make
create {NODE_MODULE}
make_with_storage
feature {NONE} -- Implementation
feature {NONE} -- Initialization
make_with_storage (a_api: CMS_API; a_node_storage: CMS_NODE_STORAGE_I)
do
node_storage := a_node_storage
make (a_api)
end
initialize
-- <Precursor>
do
Precursor
if attached {CMS_STORAGE_SQL_I} storage as l_storage_sql then
create {CMS_NODE_STORAGE_SQL} node_storage.make (l_storage_sql)
else
create {CMS_NODE_STORAGE_NULL} node_storage.make
end
initialize_node_types
end
@@ -170,9 +171,9 @@ feature -- URL
-- or URI of path for selection of new content possibilities if ct is Void.
do
if ct /= Void then
Result := "/node/add/" + ct.name
Result := "node/add/" + ct.name
else
Result := "/node/"
Result := "node/"
end
end
@@ -190,18 +191,18 @@ feature -- URL
require
a_node.has_id
do
Result := "/node/" + a_node.id.out
Result := "node/" + a_node.id.out
end
nodes_path: STRING
-- URI path for list of nodes.
do
Result := "/nodes"
Result := "nodes"
end
feature -- Access: Node
nodes_count: INTEGER_64
nodes_count: NATURAL_64
do
Result := node_storage.nodes_count
end
@@ -212,10 +213,17 @@ feature -- Access: Node
Result := node_storage.nodes
end
recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE]
trashed_nodes (a_user: CMS_USER): LIST [CMS_NODE]
-- List of nodes with status in {CMS_NODE_API}.trashed.
-- if the current user is admin, it will retrieve all the trashed nodes
do
Result := node_storage.trashed_nodes (a_user.id)
end
recent_nodes (params: CMS_DATA_QUERY_PARAMETERS): ITERABLE [CMS_NODE]
-- List of the `a_rows' most recent nodes starting from `a_offset'.
do
Result := node_storage.recent_nodes (a_offset, a_rows)
Result := node_storage.recent_nodes (params.offset.to_integer_32, params.size.to_integer_32)
end
node (a_id: INTEGER_64): detachable CMS_NODE
@@ -316,6 +324,21 @@ feature -- Change: Node
node_storage.update_node (a_node)
end
trash_node (a_node: CMS_NODE)
-- Trash node `a_node'.
--! remove the node from the storage.
do
node_storage.trash_node (a_node)
end
restore_node (a_node: CMS_NODE)
-- Restore node `a_node'.
-- From {CMS_NODE_API}.trashed to {CMS_NODE_API}.not_published.
do
node_storage.restore_node (a_node)
end
feature -- Node status

View File

@@ -9,6 +9,8 @@ deferred class
inherit
CMS_NODE_TYPE_WEBFORM_MANAGER_I [G]
SHARED_WSF_PERCENT_ENCODER
feature -- Forms ...
populate_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
@@ -19,9 +21,10 @@ feature -- Forms ...
tselect: WSF_FORM_SELECT
opt: WSF_FORM_SELECT_OPTION
cms_format: CMS_EDITOR_CONTENT_FORMAT
l_uri: detachable READABLE_STRING_8
do
create cms_format
create ti.make ("title")
ti.set_label ("Title")
ti.set_size (70)
@@ -97,10 +100,31 @@ feature -- Forms ...
ti.set_size (70)
if a_node /= Void and then a_node.has_id then
if attached a_node.link as lnk then
ti.set_text_value (lnk.location)
l_uri := lnk.location
else
ti.set_text_value (response.api.path_alias (response.node_api.node_path (a_node)))
l_uri := percent_encoder.percent_decoded_string (response.api.path_alias (response.node_api.node_path (a_node)))
end
ti.set_text_value (l_uri)
ti.set_description ("Optionally specify an alternative URL path by which this content can be accessed. For example, type 'about' when writing an about page. Use a relative path or the URL alias won't work.")
ti.set_validation_action (agent (fd: WSF_FORM_DATA; a_response: CMS_RESPONSE)
do
if
attached fd.string_item ("path_alias") as f_path_alias
then
if a_response.api.is_valid_path_alias (f_path_alias) then
-- Ok.
elseif f_path_alias.is_empty then
-- Ok
elseif f_path_alias.starts_with_general ("/") then
fd.report_invalid_field ("path_alias", "Path alias should not start with a slash '/' .")
elseif f_path_alias.has_substring ("://") then
fd.report_invalid_field ("path_alias", "Path alias should not be absolute url .")
else
-- TODO: implement full path alias validation
end
end
end(?, response)
)
end
if
attached f.fields_by_name ("title") as l_title_fields and then
@@ -224,13 +248,31 @@ feature -- Output
node_api := a_response.node_api
a_response.add_variable (a_node, "node")
create lnk.make (a_response.translation ("View", Void), a_response.node_local_link (a_node).location)
lnk := a_response.node_local_link (a_node, a_response.translation ("View", Void))
lnk.set_weight (1)
a_response.add_to_primary_tabs (lnk)
a_response.add_to_primary_tabs (lnk)
create lnk.make ("Edit", node_api.node_path (a_node) + "/edit")
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
if a_node.status = {CMS_NODE_API}.trashed then
create lnk.make ("Trash", node_api.node_path (a_node) + "/trash")
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
else
-- Node in {{CMS_NODE_API}.published} or {CMS_NODE_API}.not_published} status.
create lnk.make ("Edit", node_api.node_path (a_node) + "/edit")
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
if
a_node /= Void and then
a_node.id > 0 and then
attached node_api.node_type_for (a_node) as l_type and then
node_api.has_permission_for_action_on_node ("delete", a_node, a_response.current_user (a_response.request))
then
create lnk.make ("Delete", node_api.node_path (a_node) + "/delete")
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
end
create s.make_empty
s.append ("<div class=%"info%"> ")

View File

@@ -26,7 +26,7 @@ feature {NONE} -- Initialization
initialize
do
Precursor
create {WSF_CMS_THEME} wsf_theme.make (Current, theme)
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
@@ -48,7 +48,11 @@ feature -- Execution
attached node_api.node (nid) as l_node
then
if attached node_api.node_type_for (l_node) as l_type then
if node_api.has_permission_for_action_on_node ("edit", l_node, current_user (request)) then
fixme ("refactor: process_edit, process_create porcess edit")
if
request.path_info.ends_with_general ("/edit") and then
node_api.has_permission_for_action_on_node ("edit", l_node, current_user (request))
then
f := new_edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
invoke_form_alter (f, fd)
if request.is_post_request_method then
@@ -58,8 +62,9 @@ feature -- Execution
fd := f.last_data
end
if l_node.has_id then
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), node_url (l_node)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "/node/" + l_node.id.out + "/edit"), primary_tabs)
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (l_node) + "/delete"), primary_tabs)
end
if attached redirection as l_location then
@@ -70,6 +75,53 @@ feature -- Execution
set_title (formatted_string (translation ("Edit $1 #$2", Void), [l_type.title, l_node.id]))
f.append_to_html (wsf_theme, b)
end
elseif
request.path_info.ends_with_general ("/delete") and then
node_api.has_permission_for_action_on_node ("delete", l_node, current_user (request))
then
f := new_delete_form (l_node, url (request.path_info, Void), "delete-" + l_type.name, l_type)
invoke_form_alter (f, fd)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
end
if l_node.has_id then
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (l_node) + "/delete"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (l_node.title)
b.append (html_encoded (l_type.title) + " deleted")
else
set_title (formatted_string (translation ("Delete $1 #$2", Void), [l_type.title, l_node.id]))
f.append_to_html (wsf_theme, b)
end
elseif
request.path_info.ends_with_general ("/trash") and then
node_api.has_permission_for_action_on_node ("trash", l_node, current_user (request))
then
f := new_trash_form (l_node, url (request.path_info, Void), "trash-" + l_type.name, l_type)
invoke_form_alter (f, fd)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
end
if l_node.has_id then
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Trash", node_api.node_path (l_node) + "/Trash"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (l_node.title)
b.append (html_encoded (l_type.title) + " trashed")
else
set_title (formatted_string (translation ("Trash $1 #$2", Void), [l_type.title, l_node.id]))
f.append_to_html (wsf_theme, b)
end
else
b.append ("<h1>")
b.append (translation ("Access denied", Void))
@@ -96,8 +148,8 @@ feature -- Execution
set_title ("Edit " + html_encoded (l_type.title) + " #" + l_node.id.out)
if l_node.has_id then
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), node_url (l_node)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "/node/" + l_node.id.out + "/edit"), primary_tabs)
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
end
f.append_to_html (wsf_theme, b)
@@ -121,7 +173,7 @@ feature -- Execution
attached ic.item as l_node_type and then
has_permissions (<<"create any", "create " + l_node_type.name>>)
then
b.append ("<li>" + link (l_node_type.name, "/node/add/" + l_node_type.name, Void))
b.append ("<li>" + link (l_node_type.name, "node/add/" + l_node_type.name, Void))
if attached l_node_type.description as d then
b.append ("<div class=%"description%">" + d + "</div>")
end
@@ -167,6 +219,7 @@ feature -- Form
l_preview: BOOLEAN
l_node: detachable CMS_NODE
s: STRING
l_path_alias: detachable READABLE_STRING_8
do
l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview")
if not l_preview then
@@ -198,20 +251,29 @@ feature -- Form
end
node_api.save_node (l_node)
if attached current_user (request) as u then
api.log ("node", "User %"" + user_html_link (u) + "%" " + s + " node " + link (a_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node))
api.log ("node",
"User %"" + user_html_link (u) + "%" " + s + " node " + node_html_link (l_node, a_type.name + " #" + l_node.id.out),
0, node_local_link (l_node, Void)
)
else
api.log ("node", "Anonymous " + s + " node " + a_type.name +" #" + l_node.id.out, 0, node_local_link (l_node))
api.log ("node", "Anonymous " + s + " node " + a_type.name +" #" + l_node.id.out, 0, node_local_link (l_node, Void))
end
add_success_message ("Node #" + l_node.id.out + " saved.")
if attached fd.string_item ("path_alias") as l_path_alias then
if
attached fd.string_item ("path_alias") as f_path_alias and then
not f_path_alias.is_empty
then
l_path_alias := percent_encoder.partial_encoded_string (f_path_alias, <<'/'>>)
-- Path alias, are always from the root of the cms.
api.set_path_alias (node_api.node_path (l_node), l_path_alias, False)
l_node.set_link (create {CMS_LOCAL_LINK}.make (l_node.title, l_path_alias))
else
l_node.set_link (node_api.node_link (l_node))
end
set_redirection (node_url (l_node))
if attached l_node.link as lnk then
set_redirection (lnk.location)
end
end
end
@@ -243,10 +305,25 @@ feature -- Form
ts.set_default_value ("Preview")
f.extend (ts)
Result := f
end
new_delete_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_node_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM
-- Create a web form named `a_name' for node `a_node' (if set), using form action url `a_url', and for type of node `a_node_type'.
local
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
do
create f.make (a_url, a_name)
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Are you sure you want to delete?</legend>")
-- TODO check if we need to check for has_permissions!!
if
a_node /= Void and then
a_node.id > 0 and then
has_permission ("delete " + a_name)
a_node.id > 0
then
create ts.make ("op")
ts.set_default_value ("Delete")
@@ -254,11 +331,52 @@ feature -- Form
ts.set_default_value (translation ("Delete"))
]")
f.extend (ts)
fixme ("wsf_html: add support for HTML5 input attributes!!! ")
f.extend_html_text("<input type='submit' value='Cancel' formmethod='GET', formaction='/node/"+a_node.id.out+"'>" )
end
Result := f
end
new_trash_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_node_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM
-- Create a web form named `a_name' for node `a_node' (if set), using form action url `a_url', and for type of node `a_node_type'.
local
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
do
create f.make (a_url, a_name)
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Are you sure you want to trash the current node?</legend>")
if
a_node /= Void and then
a_node.id > 0
then
create ts.make ("op")
ts.set_default_value ("Trash")
fixme ("[
ts.set_default_value (translation ("Trash"))
]")
f.extend (ts)
end
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Do you want to restore the current node?</legend>")
if
a_node /= Void and then
a_node.id > 0
then
create ts.make ("op")
ts.set_default_value ("Restore")
fixme ("[
ts.set_default_value (translation ("Restore"))
]")
f.extend (ts)
end
Result := f
end
populate_form (a_content_type: CMS_NODE_TYPE [CMS_NODE]; a_form: WSF_FORM; a_node: detachable CMS_NODE)
-- Fill the web form `a_form' with data from `a_node' if set,
-- and apply this to content type `a_content_type'.

View File

@@ -89,6 +89,14 @@ feature -- HTTP Methods
check valid_url: req.path_info.starts_with_general ("/node/") end
create edit_response.make (req, res, api, node_api)
edit_response.execute
elseif req.path_info.ends_with_general ("/delete") then
check valid_url: req.path_info.starts_with_general ("/node/") end
create edit_response.make (req, res, api, node_api)
edit_response.execute
elseif req.path_info.ends_with_general ("/trash") then
check valid_url: req.path_info.starts_with_general ("/node/") end
create edit_response.make (req, res, api, node_api)
edit_response.execute
else
-- Display existing node
l_nid := node_id_path_parameter (req)
@@ -116,14 +124,26 @@ feature -- HTTP Methods
do
fixme ("Refactor code: extract methods: edit_node and add_node")
if req.path_info.ends_with_general ("/edit") then
create edit_response.make (req, res, api, node_api)
edit_response.execute
elseif req.path_info.ends_with_general ("/delete") then
if
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Delete")
then
do_delete (req, res)
else
create edit_response.make (req, res, api, node_api)
edit_response.execute
end
elseif req.path_info.ends_with_general ("/trash") then
if
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Trash")
then
do_trash (req, res)
elseif
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Restore")
then
do_restore (req, res)
end
elseif req.path_info.starts_with_general ("/node/add/") then
create edit_response.make (req, res, api, node_api)
@@ -174,6 +194,62 @@ feature -- HTTP Methods
send_not_implemented ("REST API not yet implemented", req, res)
end
feature {NONE} -- Trash:Restore
do_trash (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Trash a node from the database.
do
if attached current_user (req) as l_user then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if
l_id.is_integer and then
attached node_api.node (l_id.integer_value) as l_node
then
if node_api.has_permission_for_action_on_node ("trash", l_node, current_user (req)) then
node_api.trash_node (l_node)
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
else
send_access_denied (req, res)
-- send_not_authorized ?
end
else
do_error (req, res, l_id)
end
else
(create {INTERNAL_SERVER_ERROR_CMS_RESPONSE}.make (req, res, api)).execute
end
else
send_access_denied (req, res)
end
end
do_restore (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Restore a node: From {CMS_NODE_API}.trashed to {CMS_NODE_API}.not_published.
do
if attached current_user (req) as l_user then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if
l_id.is_integer and then
attached node_api.node (l_id.integer_value) as l_node
then
if node_api.has_permission_for_action_on_node ("trash", l_node, current_user (req)) then
node_api.restore_node (l_node)
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
else
send_access_denied (req, res)
-- send_not_authorized ?
end
else
do_error (req, res, l_id)
end
else
(create {INTERNAL_SERVER_ERROR_CMS_RESPONSE}.make (req, res, api)).execute
end
else
send_access_denied (req, res)
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: detachable WSF_STRING)

View File

@@ -53,30 +53,45 @@ feature -- Helpers
feature -- Helpers: cms link
user_local_link (u: CMS_USER): CMS_LOCAL_LINK
user_local_link (u: CMS_USER; a_opt_title: detachable READABLE_STRING_GENERAL): CMS_LOCAL_LINK
do
create Result.make (u.name, user_url (u))
if a_opt_title /= Void then
create Result.make (a_opt_title, user_url (u))
else
create Result.make (u.name, user_url (u))
end
end
node_local_link (n: CMS_NODE): CMS_LOCAL_LINK
node_local_link (n: CMS_NODE; a_opt_title: detachable READABLE_STRING_GENERAL): CMS_LOCAL_LINK
do
if attached n.link as lnk then
Result := lnk
else
Result := node_api.node_link (n)
end
if a_opt_title /= Void and then not Result.title.same_string_general (a_opt_title) then
create Result.make (a_opt_title, Result.location)
end
end
feature -- Helpers: html link
user_html_link (u: CMS_USER): like link
do
Result := link (u.name, "/user/" + u.id.out, Void)
Result := link (u.name, "user/" + u.id.out, Void)
end
node_html_link (n: CMS_NODE): like link
node_html_link (n: CMS_NODE; a_opt_title: detachable READABLE_STRING_GENERAL): like link
local
l_title: detachable READABLE_STRING_GENERAL
do
Result := link (n.title, "/node/" + n.id.out, Void)
if a_opt_title /= Void then
l_title := a_opt_title
else
l_title := n.title
end
Result := link (l_title, node_api.node_path (n), Void)
end
feature -- Helpers: URL
@@ -85,7 +100,7 @@ feature -- Helpers: URL
require
u_with_id: u.has_id
do
Result := url ("/user/" + u.id.out, Void)
Result := url ("user/" + u.id.out, Void)
end
node_url (n: CMS_NODE): like url

View File

@@ -27,7 +27,7 @@ feature {NONE} -- Initialization
initialize
do
Precursor
create {WSF_CMS_THEME} wsf_theme.make (Current, theme)
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME

View File

@@ -37,22 +37,40 @@ feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: CMS_RESPONSE
l_response: CMS_RESPONSE
s: STRING
n: CMS_NODE
lnk: CMS_LOCAL_LINK
l_page_helper: CMS_PAGINATION_GENERATOR
s_pager: STRING
l_count: NATURAL_64
do
-- At the moment the template is hardcoded, but we can
-- At the moment the template are hardcoded, but we can
-- get them from the configuration file and load them into
-- the setup class.
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
l_page.add_variable (node_api.nodes, "nodes")
l_count := node_api.nodes_count
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
-- NOTE: for development purposes we have the following hardcode output.
create s.make_from_string ("<p>Nodes:</p>")
if attached node_api.nodes as lst then
create s.make_empty
if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " nodes")
else
l_response.set_title ("Listing " + l_count.out + " node")
end
create s_pager.make_empty
create l_page_helper.make ("nodes/?page={page}&size={size}", node_api.nodes_count, 25) -- FIXME: Make this default page size a global CMS settings
l_page_helper.get_setting_from_request (req)
if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then
l_page_helper.append_to_html (l_response, s_pager)
if l_page_helper.page_size > 25 then
s.append (s_pager)
end
end
if attached node_api.recent_nodes (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size)) as lst then
s.append ("<ul class=%"cms-nodes%">%N")
across
lst as ic
@@ -60,16 +78,23 @@ feature -- HTTP Methods
n := ic.item
lnk := node_api.node_link (n)
s.append ("<li class=%"cms_type_"+ n.content_type +"%">")
s.append (l_page.link (lnk.title, lnk.location, Void))
-- s.append (l_page.link (n.title + " (#" + n.id.out + ")", node_api.node_path (n), Void))
s.append (l_response.link (lnk.title, lnk.location, Void))
debug
if attached node_api.content_type (n.content_type) as ct then
s.append ("<span class=%"description%">")
s.append (html_encoded (ct.title))
s.append ("</span>")
end
end
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
-- Again the pager at the bottom, if needed
s.append (s_pager)
l_page.set_main_content (s)
l_page.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet fully implemented<br/>", Void), "highlighted")
l_page.execute
l_response.set_main_content (s)
l_response.execute
end
end

View File

@@ -0,0 +1,80 @@
note
description: "Request handler related to /trash "
date: "$Date$"
revision: "$Revision$"
class
TRASH_HANDLER
inherit
CMS_NODE_HANDLER
WSF_URI_HANDLER
rename
new_mapping as new_uri_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: CMS_RESPONSE
s: STRING
n: CMS_NODE
lnk: CMS_LOCAL_LINK
do
-- At the moment the template is hardcoded, but we can
-- get them from the configuration file and load them into
-- the setup class.
if attached current_user (req) as l_user then
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
l_page.add_variable (node_api.trashed_nodes (l_user), "nodes")
-- NOTE: for development purposes we have the following hardcode output.
create s.make_from_string ("<p>Nodes:</p>")
if attached node_api.trashed_nodes (l_user) as lst then
s.append ("<ul class=%"cms-nodes%">%N")
across
lst as ic
loop
n := ic.item
lnk := node_api.node_link (n)
s.append ("<li class=%"cms_type_"+ n.content_type +"%">")
s.append (l_page.link (lnk.title, lnk.location, Void))
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
l_page.set_main_content (s)
-- l_page.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet fully implemented<br/>", Void), "highlighted")
l_page.execute
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_page.make (req, res, api)
l_page.execute
end
end
end

View File

@@ -1,58 +0,0 @@
note
description: "Summary description for {WSF_CMS_THEME}."
date: "$Date$"
revision: "$Revision$"
class
WSF_CMS_THEME
inherit
WSF_THEME
create
make
feature {NONE} -- Initialization
make (res: CMS_RESPONSE; a_cms_theme: CMS_THEME)
do
request := res.request
cms_theme := a_cms_theme
set_response (res)
end
feature -- Access
request: WSF_REQUEST
response: detachable CMS_RESPONSE
cms_theme: CMS_THEME
feature -- Element change
set_response (a_response: CMS_RESPONSE)
do
response := a_response
end
feature -- Core
site_url: READABLE_STRING_8
do
if attached response as r then
Result := r.site_url
else
Result := request.absolute_script_url ("")
end
end
base_url: detachable READABLE_STRING_8
-- Base url if any.
do
if attached response as r then
Result := r.base_url
end
end
end

View File

@@ -1,30 +0,0 @@
note
description: " Null theme for void-safety purpose."
date: "$Date$"
revision: "$Revision$"
class
WSF_NULL_THEME
inherit
WSF_THEME
create
make
feature {NONE} -- Initialization
make
do
end
feature -- Core
site_url: STRING = ""
base_url: detachable READABLE_STRING_8
-- Base url if any.
do
end
end

View File

@@ -9,14 +9,12 @@ class
inherit
CMS_MODULE
rename
module_api as node_api
redefine
register_hooks,
initialize,
is_installed,
install,
node_api
module_api
end
CMS_HOOK_MENU_SYSTEM_ALTER
@@ -43,15 +41,26 @@ feature {NONE} -- Initialization
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
initialize (a_api: CMS_API)
-- <Precursor>
local
p1,p2: CMS_PAGE
ct: CMS_PAGE_NODE_TYPE
l_node_api: like node_api
l_node_storage: CMS_NODE_STORAGE_I
do
Precursor (api)
create l_node_api.make (api)
Precursor (a_api)
-- Storage initialization
if attached {CMS_STORAGE_SQL_I} a_api.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
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
@@ -61,7 +70,7 @@ feature {CMS_API} -- Module Initialization
-- 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 api.user_api.user_by_id (1) as u 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")
@@ -81,29 +90,42 @@ feature {CMS_API} -- Module Initialization
-- 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
ensure then
node_api_set: node_api /= Void
end
feature {CMS_API} -- Module management
is_installed (api: CMS_API): BOOLEAN
is_installed (a_api: CMS_API): BOOLEAN
-- Is Current module installed?
do
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
Result := l_sql_storage.sql_table_exists ("nodes") and
l_sql_storage.sql_table_exists ("page_nodes")
end
end
install (api: CMS_API)
install (a_api: CMS_API)
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (api.setup.environment.path.extended ("scripts").extended (name).appended_with_extension ("sql"))
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (a_api.setup.environment.path.extended ("scripts").extended (name).appended_with_extension ("sql"))
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>
@@ -111,15 +133,10 @@ feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
local
l_node_api: like node_api
do
l_node_api := node_api
if l_node_api = Void then
create l_node_api.make (a_api)
node_api := l_node_api
if attached node_api as l_node_api then
configure_web (a_api, l_node_api, a_router)
end
configure_web (a_api, l_node_api, a_router)
end
configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER)
@@ -127,6 +144,7 @@ feature -- Access: router
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)
@@ -135,6 +153,8 @@ feature -- Access: router
a_router.handle_with_request_methods ("/node/add/{type}", l_node_handler, a_router.methods_get_post)
a_router.handle_with_request_methods ("/node/{id}/edit", l_node_handler, a_router.methods_get_post)
a_router.handle_with_request_methods ("/node/{id}/delete", l_node_handler, a_router.methods_get_post)
a_router.handle_with_request_methods ("/node/{id}/trash", l_node_handler, a_router.methods_get_post)
a_router.handle_with_request_methods ("/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)
@@ -143,6 +163,13 @@ feature -- Access: router
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_with_request_methods (l_uri_mapping, 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_with_request_methods (l_uri_mapping, a_router.methods_get)
end
feature -- Hooks
@@ -173,10 +200,13 @@ feature -- Hooks
lnk: CMS_LOCAL_LINK
-- perms: detachable ARRAYED_LIST [READABLE_STRING_8]
do
create lnk.make ("List of nodes", a_response.url ("/nodes", Void))
create lnk.make ("List of nodes", "nodes")
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Create ..", a_response.url ("/node/", Void))
create lnk.make ("Trash", "trash")
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Create ..", "node")
a_menu_system.primary_menu.extend (lnk)
end

View File

@@ -43,6 +43,8 @@ feature {NONE} -- Implementation
extended_store (a_node: CMS_NODE)
-- Store extended data from `a_node'.
require
not error_handler.has_error
do
if attached node_storage_extension (a_node) as ext then
ext.store_node (a_node)
@@ -51,16 +53,17 @@ feature {NONE} -- Implementation
extended_load (a_node: CMS_NODE)
-- Load extended data into `a_node'.
require
not error_handler.has_error
do
if attached node_storage_extension (a_node) as ext then
ext.load_node (a_node)
end
end
feature -- Access
nodes_count: INTEGER_64
nodes_count: NATURAL_64
-- Count of nodes.
deferred
end
@@ -70,6 +73,11 @@ feature -- Access
deferred
end
trashed_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE]
-- List of nodes by user `a_user_id'.
deferred
end
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- List of recent `a_count' nodes with an offset of `lower'.
deferred
@@ -108,7 +116,7 @@ feature -- Change: Node
valid_user: attached a_node.author as l_author and then l_author.id > 0
deferred
ensure
has_id: a_node.has_id
has_id: not error_handler.has_error implies a_node.has_id
end
update_node (a_node: CMS_NODE)
@@ -135,32 +143,35 @@ feature -- Change: Node
deferred
end
-- update_node_title (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
-- -- Update node title to `a_title', node identified by id `a_node_id'.
-- -- The user `a_user_id' is an existing or new collaborator.
-- require
-- valid_node_id: a_node_id > 0
-- valid_user_id: a_user_id > 0
-- deferred
-- end
trash_node (a_node: CMS_NODE)
-- Trash `a_node'.
do
if a_node.has_id then
trash_node_by_id (a_node.id)
end
end
-- update_node_summary (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
-- -- Update node summary to `a_summary', node identified by id `a_node_id'.
-- -- The user `a_user_id' is an existing or new collaborator.
-- require
-- valid_id: a_node_id > 0
-- valid_user_id: a_user_id > 0
-- deferred
-- end
restore_node (a_node: CMS_NODE)
-- Restore `a_node'.
do
if a_node.has_id then
restore_node_by_id (a_node.id)
end
end
-- update_node_content (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
-- -- Update node content to `a_content', node identified by id `a_node_id'.
-- -- The user `a_user_id' is an existing or new collaborator.
-- require
-- valid_id: a_node_id > 0
-- valid_user_id: a_user_id > 0
-- deferred
-- end
trash_node_by_id (a_id: INTEGER_64)
-- Trash node by id `a_id'.
require
valid_node_id: a_id > 0
deferred
end
restore_node_by_id (a_id: INTEGER_64)
-- Restore node by id `a_id'.
require
valid_node_id: a_id > 0
deferred
end
feature -- Helpers

View File

@@ -30,7 +30,7 @@ feature -- Error Handling
feature -- Access: node
nodes_count: INTEGER_64
nodes_count: NATURAL_64
-- Count of nodes.
do
end
@@ -41,6 +41,12 @@ feature -- Access: node
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
end
trashed_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE]
-- List of nodes by user `a_user_id'.
do
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
end
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- List of the `a_count' most recent nodes, starting from `a_lower'.
do
@@ -80,6 +86,16 @@ feature -- Node
do
end
trash_node_by_id (a_id: INTEGER_64)
-- <Precursor>
do
end
restore_node_by_id (a_id: INTEGER_64)
-- <Precursor>
do
end
-- update_node_title (a_user_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
-- -- <Precursor>
-- do

View File

@@ -22,14 +22,14 @@ create
feature -- Access
nodes_count: INTEGER_64
nodes_count: NATURAL_64
-- Number of items nodes.
do
error_handler.reset
write_information_log (generator + ".nodes_count")
sql_query (sql_select_nodes_count, Void)
if sql_rows_count = 1 then
Result := sql_read_integer_64 (1)
Result := sql_read_natural_64 (1)
end
end
@@ -60,6 +60,36 @@ feature -- Access
-- end
end
trashed_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE]
-- List of nodes.
local
l_parameters: STRING_TABLE [detachable ANY]
do
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
error_handler.reset
write_information_log (generator + ".trash_nodes")
from
create l_parameters.make (1)
if a_user_id > 1 then
-- Not admin user
l_parameters.put (a_user_id, "author")
sql_query (sql_select_trash_nodes_by_author, l_parameters)
else
sql_query (sql_select_trash_nodes, Void)
end
sql_start
until
sql_after
loop
if attached fetch_node as l_node then
Result.force (l_node)
end
sql_forth
end
end
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- List of recent `a_count' nodes with an offset of `lower'.
local
@@ -148,7 +178,7 @@ feature -- Change: Node
l_time: DATE_TIME
do
create l_time.make_now_utc
write_information_log (generator + ".delete_node")
write_information_log (generator + ".delete_node {" + a_id.out + "}")
error_handler.reset
create l_parameters.make (1)
@@ -158,6 +188,40 @@ feature -- Change: Node
sql_change (sql_delete_node, l_parameters)
end
trash_node_by_id (a_id: INTEGER_64)
-- <Precursor>
local
l_parameters: STRING_TABLE [ANY]
l_time: DATE_TIME
do
create l_time.make_now_utc
write_information_log (generator + ".trash_node {" + a_id.out + "}")
error_handler.reset
create l_parameters.make (1)
l_parameters.put (a_id, "nid")
sql_change (sql_trash_node, l_parameters)
end
restore_node_by_id (a_id: INTEGER_64)
-- <Precursor>
local
l_parameters: STRING_TABLE [ANY]
l_time: DATE_TIME
do
create l_time.make_now_utc
write_information_log (generator + ".restore_node {" + a_id.out + "}")
error_handler.reset
create l_parameters.make (1)
l_parameters.put (l_time, "changed")
l_parameters.put ({CMS_NODE_API}.not_published, "status")
l_parameters.put (a_id, "nid")
sql_change (sql_restore_node, l_parameters)
end
feature {NONE} -- Implementation
store_node (a_node: CMS_NODE)
@@ -204,8 +268,14 @@ feature {NONE} -- Implementation
a_node.set_revision (1) -- New object.
end
end
extended_store (a_node)
sql_commit_transaction
if not error_handler.has_error then
extended_store (a_node)
end
if error_handler.has_error then
sql_rollback_transaction
else
sql_commit_transaction
end
end
feature -- Helpers
@@ -229,6 +299,14 @@ feature {NONE} -- Queries
-- SQL Query to retrieve all nodes.
--| note: {CMS_NODE_API}.trashed = -1
sql_select_trash_nodes: STRING = "SELECT * FROM Nodes WHERE status = -1 ;"
-- SQL Query to retrieve all trahsed nodes.
--| note: {CMS_NODE_API}.trashed = -1
sql_select_trash_nodes_by_author: STRING = "SELECT * FROM Nodes WHERE status = -1 and author = :author ;"
-- SQL Query to retrieve all nodes by a given author.
--| note: {CMS_NODE_API}.trashed = -1
sql_select_node_by_id: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes WHERE nid =:nid ORDER BY revision DESC, publish DESC LIMIT 1;"
sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM Nodes ORDER BY nid DESC, publish DESC LIMIT :rows OFFSET :offset ;"
@@ -244,6 +322,12 @@ feature {NONE} -- Queries
sql_delete_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
-- Soft deletion with free metadata.
sql_trash_node: STRING = "DELETE FROM nodes WHERE nid=:nid"
-- Physical deletion with free metadata.
sql_restore_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
-- Restore node to {CMS_NODE_API}.not_publised.
-- sql_update_node_author: STRING = "UPDATE nodes SET author=:author WHERE nid=:nid;"
-- sql_update_node_title: STRING ="UPDATE nodes SET title=:title, changed=:changed, revision = revision + 1 WHERE nid=:nid;"