From 44d14c41001d0bb5d1ebd3142aabccc60e511483 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Wed, 13 May 2015 12:27:02 -0300 Subject: [PATCH 1/8] delete with tabs --- .../handler/cms_node_type_webform_manager.e | 11 ++++++++++ modules/node/handler/node_form_response.e | 20 +++++++++---------- modules/node/node_module.e | 3 +++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 88161a4..5c99396 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -167,6 +167,17 @@ feature -- Output 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 + a_response.has_permission ("delete " + node_api.permission_scope (a_response.current_user (a_response.request), a_node) + " " + l_type.name) + then + create lnk.make ("Delete", node_api.node_path (a_node) + "/delete") + lnk.set_weight (3) + a_response.add_to_primary_tabs (lnk) + end + create s.make_empty s.append ("
") if attached a_node.author as l_author then diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e index 8ade0b6..c39c5c0 100644 --- a/modules/node/handler/node_form_response.e +++ b/modules/node/handler/node_form_response.e @@ -61,13 +61,13 @@ feature -- Execution -- FIXME: Hack for now set_title (l_node.title) add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs) + add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", "/node/" + l_node.id.out + "/delete"), primary_tabs) add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs) - b.append (html_encoded (l_type.title) + " saved") else set_title ("Edit " + html_encoded (l_type.title) + " #" + l_node.id.out) - add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs) + add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", "/node/" + l_node.id.out + "/delete"), primary_tabs) add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs) f.append_to_html (wsf_theme, b) @@ -228,14 +228,14 @@ feature -- Form ts.set_default_value ("Preview") f.extend (ts) - if a_node /= Void and then a_node.id > 0 and then has_permission ("delete " + a_name) then - create ts.make ("op") - ts.set_default_value ("Delete") - fixme ("[ - ts.set_default_value (i18n ("Delete"))i18n or other name such as "translated" or "translation - ]") - f.extend (ts) - end +-- if a_node /= Void and then a_node.id > 0 and then has_permission ("delete " + a_name) then +-- create ts.make ("op") +-- ts.set_default_value ("Delete") +-- fixme ("[ +-- ts.set_default_value (i18n ("Delete"))i18n or other name such as "translated" or "translation +-- ]") +-- f.extend (ts) +-- end Result := f end diff --git a/modules/node/node_module.e b/modules/node/node_module.e index ba6ca2d..2a5272b 100644 --- a/modules/node/node_module.e +++ b/modules/node/node_module.e @@ -177,6 +177,9 @@ feature -- Hooks create lnk.make ("List of nodes", a_response.url ("/nodes", Void)) a_menu_system.primary_menu.extend (lnk) + create lnk.make ("Trash nodes", a_response.url ("/trash", Void)) + a_menu_system.primary_menu.extend (lnk) + create lnk.make ("Create ..", a_response.url ("/node/", Void)) a_menu_system.primary_menu.extend (lnk) end From 57bf5ad0dce2f55da3ec08c67305db540d654524 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Wed, 13 May 2015 15:17:19 -0300 Subject: [PATCH 2/8] Added delete option as a tab only if the current user has permissions to delete the current resource --- .../handler/cms_node_type_webform_manager.e | 2 +- modules/node/handler/node_form_response.e | 51 +++++++++++++++++-- modules/node/handler/node_handler.e | 10 ++-- modules/node/node_module.e | 1 + 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index eda76d9..5d991e9 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -192,7 +192,7 @@ feature -- Output a_node /= Void and then a_node.id > 0 and then attached node_api.node_type_for (a_node) as l_type and then - a_response.has_permission ("delete " + node_api.permission_scope (a_response.current_user (a_response.request), a_node) + " " + l_type.name) + 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) diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e index 40b14dd..598a09b 100644 --- a/modules/node/handler/node_form_response.e +++ b/modules/node/handler/node_form_response.e @@ -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 @@ -71,6 +75,30 @@ 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 (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 (create {CMS_LOCAL_LINK}.make ("Delete", "/node/" + l_node.id.out + "/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 else b.append ("

") b.append (translation ("Access denied", Void)) @@ -244,10 +272,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 ("
") + f.extend_html_text ("Are you sure you want to delete?") + + -- 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") @@ -255,6 +298,8 @@ feature -- Form ts.set_default_value (translation ("Delete")) ]") f.extend (ts) + fixme ("wsf_html: add support for HTML5 input attributes!!! ") + f.extend_html_text("" ) end Result := f diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e index de50f39..5ef662d 100644 --- a/modules/node/handler/node_handler.e +++ b/modules/node/handler/node_handler.e @@ -89,6 +89,10 @@ 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 else -- Display existing node l_nid := node_id_path_parameter (req) @@ -116,14 +120,14 @@ 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.starts_with_general ("/node/add/") then create edit_response.make (req, res, api, node_api) diff --git a/modules/node/node_module.e b/modules/node/node_module.e index 65b07f1..2f49c9c 100644 --- a/modules/node/node_module.e +++ b/modules/node/node_module.e @@ -135,6 +135,7 @@ 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}", l_node_handler, a_router.methods_get) -- For now: no REST API handling... a_router.methods_get_put_delete + a_router.methods_get_post) From 9fbadac7aca771227a1b35968f945c4d82700b54 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 14 May 2015 11:07:15 -0300 Subject: [PATCH 3/8] Added trash feature: Remove or revert a node. Added Handler to show the current trash nodes for a given user. An admin can see all the trash nodes. Updated storage to handle trash and revert nodes. --- modules/node/cms_node_api.e | 23 ++++++ .../handler/cms_node_type_webform_manager.e | 31 ++++--- modules/node/handler/node_form_response.e | 64 +++++++++++++++ modules/node/handler/node_handler.e | 72 +++++++++++++++++ modules/node/handler/trash_handler.e | 78 ++++++++++++++++++ modules/node/node_module.e | 9 +++ modules/node/persistence/cms_node_storage_i.e | 35 ++++++++ .../node/persistence/cms_node_storage_null.e | 16 ++++ .../node/persistence/cms_node_storage_sql.e | 80 ++++++++++++++++++- src/persistence/sql/cms_storage_sql_builder.e | 6 ++ 10 files changed, 401 insertions(+), 13 deletions(-) create mode 100644 modules/node/handler/trash_handler.e diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index 8f0a8d9..2e8caf4 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -212,6 +212,14 @@ feature -- Access: Node Result := node_storage.nodes end + + trash_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.trash_nodes (a_user.id) + end + recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE] -- List of the `a_rows' most recent nodes starting from `a_offset'. do @@ -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 + + + revert_node (a_node: CMS_NODE) + -- Revert node `a_node'. + -- From {CMS_NODE_API}.trashed to {CMS_NODE_API}.not_published. + do + node_storage.revert_node (a_node) + end + feature -- Node status diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 5d991e9..fd90c12 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -182,21 +182,28 @@ feature -- Output a_response.add_variable (a_node, "node") create lnk.make (a_response.translation ("View", Void), a_response.node_local_link (a_node).location) lnk.set_weight (1) - - 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 /= 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) + 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 diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e index 598a09b..dc57770 100644 --- a/modules/node/handler/node_form_response.e +++ b/modules/node/handler/node_form_response.e @@ -99,6 +99,29 @@ feature -- Execution 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 (create {CMS_LOCAL_LINK}.make (translation ("View", Void), node_url (l_node)), primary_tabs) + add_to_menu (create {CMS_LOCAL_LINK}.make ("Trash", "/node/" + l_node.id.out + "/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) + " trasged") + 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 ("

") b.append (translation ("Access denied", Void)) @@ -305,6 +328,47 @@ feature -- Form 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 ("
") + f.extend_html_text ("Are you sure you want to trash the current node?") + 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 ("
") + f.extend_html_text ("Do you want to revert the current node?") + if + a_node /= Void and then + a_node.id > 0 + then + create ts.make ("op") + ts.set_default_value ("Revert") + fixme ("[ + ts.set_default_value (translation ("Revert")) + ]") + 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'. diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e index 5ef662d..83ea7e6 100644 --- a/modules/node/handler/node_handler.e +++ b/modules/node/handler/node_handler.e @@ -93,6 +93,10 @@ 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 ("/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) @@ -129,6 +133,18 @@ feature -- HTTP Methods then do_delete (req, res) 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 ("Revert") + then + do_revert (req, res) + end elseif req.path_info.starts_with_general ("/node/add/") then create edit_response.make (req, res, api, node_api) edit_response.execute @@ -178,6 +194,62 @@ feature -- HTTP Methods send_not_implemented ("REST API not yet implemented", req, res) end +feature {NONE} -- Trash:Revert + + 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_revert (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Revert 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.revert_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) diff --git a/modules/node/handler/trash_handler.e b/modules/node/handler/trash_handler.e new file mode 100644 index 0000000..0811073 --- /dev/null +++ b/modules/node/handler/trash_handler.e @@ -0,0 +1,78 @@ +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) + -- + 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. + + create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) + + if attached current_user (req) as l_user then + + l_page.add_variable (node_api.trash_nodes (l_user), "nodes") + + -- NOTE: for development purposes we have the following hardcode output. + create s.make_from_string ("

Nodes:

") + if attached node_api.trash_nodes (l_user) as lst then + s.append ("
    %N") + across + lst as ic + loop + n := ic.item + lnk := node_api.node_link (n) + s.append ("
  • ") + s.append (l_page.link (lnk.title, lnk.location, Void)) + s.append ("
  • %N") + end + s.append ("
%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
", Void), "highlighted") + l_page.execute + end + end + +end diff --git a/modules/node/node_module.e b/modules/node/node_module.e index 2f49c9c..4431205 100644 --- a/modules/node/node_module.e +++ b/modules/node/node_module.e @@ -127,6 +127,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) @@ -136,6 +137,7 @@ 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) @@ -144,6 +146,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 diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e index 6090d95..e359796 100644 --- a/modules/node/persistence/cms_node_storage_i.e +++ b/modules/node/persistence/cms_node_storage_i.e @@ -70,6 +70,11 @@ feature -- Access deferred end + trash_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 @@ -135,6 +140,36 @@ feature -- Change: Node 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 + + revert_node (a_node: CMS_NODE) + -- Revert `a_node'. + do + if a_node.has_id then + revert_node_by_id (a_node.id) + end + end + + trash_node_by_id (a_id: INTEGER_64) + -- Trash node by id `a_id'. + require + valid_node_id: a_id > 0 + deferred + end + + revert_node_by_id (a_id: INTEGER_64) + -- Revert node by id `a_id'. + require + valid_node_id: a_id > 0 + 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. diff --git a/modules/node/persistence/cms_node_storage_null.e b/modules/node/persistence/cms_node_storage_null.e index 87559af..02aaeb2 100644 --- a/modules/node/persistence/cms_node_storage_null.e +++ b/modules/node/persistence/cms_node_storage_null.e @@ -41,6 +41,12 @@ feature -- Access: node create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end + trash_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) + -- + do + end + + revert_node_by_id (a_id: INTEGER_64) + -- + do + end + -- update_node_title (a_user_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32) -- -- -- do diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 06ecadc..971f8c8 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -59,6 +59,36 @@ feature -- Access -- end end + trash_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 @@ -147,7 +177,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) @@ -157,6 +187,40 @@ feature -- Change: Node sql_change (sql_delete_node, l_parameters) end + + trash_node_by_id (a_id: INTEGER_64) + -- + 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 + + revert_node_by_id (a_id: INTEGER_64) + -- + local + l_parameters: STRING_TABLE [ANY] + l_time: DATE_TIME + do + create l_time.make_now_utc + write_information_log (generator + ".revert_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_revert_node, l_parameters) + end + + feature {NONE} -- Implementation store_node (a_node: CMS_NODE) @@ -228,6 +292,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 ;" @@ -243,6 +315,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_revert_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid" + -- Revert 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;" diff --git a/src/persistence/sql/cms_storage_sql_builder.e b/src/persistence/sql/cms_storage_sql_builder.e index 6000207..a1bec3b 100644 --- a/src/persistence/sql/cms_storage_sql_builder.e +++ b/src/persistence/sql/cms_storage_sql_builder.e @@ -40,6 +40,10 @@ feature -- Initialization --| Node -- FIXME: move that initialization to node module + -- TODO: should we move the initialization to an + --! external configuration file? + --! at the moment we only have 1 admin to the whole site. + --! is that ok? l_anonymous_role.add_permission ("view any page") a_storage.save_user_role (l_anonymous_role) @@ -47,9 +51,11 @@ feature -- Initialization l_authenticated_role.add_permission ("view any page") l_authenticated_role.add_permission ("edit any page") l_authenticated_role.add_permission ("delete page") + l_authenticated_role.add_permission ("trash page") l_authenticated_role.add_permission ("view own page") l_authenticated_role.add_permission ("edit own page") l_authenticated_role.add_permission ("delete own page") + l_authenticated_role.add_permission ("trash own page") a_storage.save_user_role (l_authenticated_role) From 1c59a6598358f1edd9613caede15fccc872d2ee6 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 15 May 2015 09:40:18 -0300 Subject: [PATCH 4/8] Updated code based on Jocelyn suggestions. --- modules/node/cms_node_api.e | 8 ++++---- modules/node/handler/node_handler.e | 2 +- modules/node/persistence/cms_node_storage_i.e | 12 ++++++------ modules/node/persistence/cms_node_storage_null.e | 4 ++-- modules/node/persistence/cms_node_storage_sql.e | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index 2e8caf4..dd88fd3 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -217,7 +217,7 @@ feature -- Access: 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.trash_nodes (a_user.id) + Result := node_storage.trashed_nodes (a_user.id) end recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE] @@ -332,11 +332,11 @@ feature -- Change: Node end - revert_node (a_node: CMS_NODE) - -- Revert node `a_node'. + restore_node (a_node: CMS_NODE) + -- Restore node `a_node'. -- From {CMS_NODE_API}.trashed to {CMS_NODE_API}.not_published. do - node_storage.revert_node (a_node) + node_storage.restore_node (a_node) end diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e index 83ea7e6..583170e 100644 --- a/modules/node/handler/node_handler.e +++ b/modules/node/handler/node_handler.e @@ -233,7 +233,7 @@ feature {NONE} -- Trash:Revert 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.revert_node (l_node) + node_api.restore_node (l_node) res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url (""))) else send_access_denied (req, res) diff --git a/modules/node/persistence/cms_node_storage_i.e b/modules/node/persistence/cms_node_storage_i.e index e359796..5bbf8ca 100644 --- a/modules/node/persistence/cms_node_storage_i.e +++ b/modules/node/persistence/cms_node_storage_i.e @@ -70,7 +70,7 @@ feature -- Access deferred end - trash_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE] + trashed_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE] -- List of nodes by user `a_user_id'. deferred end @@ -148,11 +148,11 @@ feature -- Change: Node end end - revert_node (a_node: CMS_NODE) - -- Revert `a_node'. + restore_node (a_node: CMS_NODE) + -- Restore `a_node'. do if a_node.has_id then - revert_node_by_id (a_node.id) + restore_node_by_id (a_node.id) end end @@ -163,8 +163,8 @@ feature -- Change: Node deferred end - revert_node_by_id (a_id: INTEGER_64) - -- Revert node by id `a_id'. + restore_node_by_id (a_id: INTEGER_64) + -- Restore node by id `a_id'. require valid_node_id: a_id > 0 deferred diff --git a/modules/node/persistence/cms_node_storage_null.e b/modules/node/persistence/cms_node_storage_null.e index 02aaeb2..b5a9406 100644 --- a/modules/node/persistence/cms_node_storage_null.e +++ b/modules/node/persistence/cms_node_storage_null.e @@ -41,7 +41,7 @@ feature -- Access: node create {ARRAYED_LIST [CMS_NODE]} Result.make (0) end - trash_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE] + 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) @@ -91,7 +91,7 @@ feature -- Node do end - revert_node_by_id (a_id: INTEGER_64) + restore_node_by_id (a_id: INTEGER_64) -- do end diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 971f8c8..8575567 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -59,7 +59,7 @@ feature -- Access -- end end - trash_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE] + trashed_nodes (a_user_id: INTEGER_64): LIST [CMS_NODE] -- List of nodes. local l_parameters: STRING_TABLE [detachable ANY] @@ -203,7 +203,7 @@ feature -- Change: Node sql_change (sql_trash_node, l_parameters) end - revert_node_by_id (a_id: INTEGER_64) + restore_node_by_id (a_id: INTEGER_64) -- local l_parameters: STRING_TABLE [ANY] @@ -217,7 +217,7 @@ feature -- Change: Node l_parameters.put (l_time, "changed") l_parameters.put ({CMS_NODE_API}.not_published, "status") l_parameters.put (a_id, "nid") - sql_change (sql_revert_node, l_parameters) + sql_change (sql_restore_node, l_parameters) end @@ -315,10 +315,10 @@ 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" + sql_trash_node: STRING = "DELETE FROM nodes WHERE nid=:nid" -- Physical deletion with free metadata. - sql_revert_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid" + sql_restore_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid" -- Revert node to {CMS_NODE_API}.not_publised. -- sql_update_node_author: STRING = "UPDATE nodes SET author=:author WHERE nid=:nid;" From 3b90d522f92af2dfa033a630409455e1266c646b Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 15 May 2015 10:44:04 -0300 Subject: [PATCH 5/8] Refactor rename: using trashed_nodes instead of trash_nodes. --- modules/node/cms_node_api.e | 2 +- modules/node/handler/trash_handler.e | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/node/cms_node_api.e b/modules/node/cms_node_api.e index dd88fd3..9ae9d85 100644 --- a/modules/node/cms_node_api.e +++ b/modules/node/cms_node_api.e @@ -213,7 +213,7 @@ feature -- Access: Node end - trash_nodes (a_user: CMS_USER): 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 diff --git a/modules/node/handler/trash_handler.e b/modules/node/handler/trash_handler.e index 0811073..5f12770 100644 --- a/modules/node/handler/trash_handler.e +++ b/modules/node/handler/trash_handler.e @@ -51,11 +51,11 @@ feature -- HTTP Methods if attached current_user (req) as l_user then - l_page.add_variable (node_api.trash_nodes (l_user), "nodes") + 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 ("

Nodes:

") - if attached node_api.trash_nodes (l_user) as lst then + if attached node_api.trashed_nodes (l_user) as lst then s.append ("
    %N") across lst as ic From 68fb21a4c1998c09b1550cb341d9be43fba8577c Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 15 May 2015 11:01:59 -0300 Subject: [PATCH 6/8] Fixed typo --- modules/node/handler/node_form_response.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e index dc57770..3006b63 100644 --- a/modules/node/handler/node_form_response.e +++ b/modules/node/handler/node_form_response.e @@ -117,7 +117,7 @@ feature -- Execution if attached redirection as l_location then -- FIXME: Hack for now set_title (l_node.title) - b.append (html_encoded (l_type.title) + " trasged") + 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) From f0668e660e5d755a3f5cdfbbeeef53ca49ea3614 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 15 May 2015 11:34:21 -0300 Subject: [PATCH 7/8] refactor rename NODE_HANLDER.do_restore instead of do_revert. --- modules/node/handler/node_handler.e | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e index 583170e..5f71573 100644 --- a/modules/node/handler/node_handler.e +++ b/modules/node/handler/node_handler.e @@ -143,7 +143,7 @@ feature -- HTTP Methods attached {WSF_STRING} req.form_parameter ("op") as l_op and then l_op.value.same_string ("Revert") then - do_revert (req, res) + do_restore (req, res) end elseif req.path_info.starts_with_general ("/node/add/") then create edit_response.make (req, res, api, node_api) @@ -223,7 +223,7 @@ feature {NONE} -- Trash:Revert end end - do_revert (req: WSF_REQUEST; res: WSF_RESPONSE) + do_restore (req: WSF_REQUEST; res: WSF_RESPONSE) -- Revert a node: From {CMS_NODE_API}.trashed to {CMS_NODE_API}.not_published. do if attached current_user (req) as l_user then From e4e2d662b834352215013013c7c73dd4711160de Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 15 May 2015 13:10:12 -0300 Subject: [PATCH 8/8] Renaming revert string to restore. --- modules/node/handler/node_form_response.e | 6 +++--- modules/node/handler/node_handler.e | 6 +++--- modules/node/persistence/cms_node_storage_sql.e | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e index 3006b63..cb20a57 100644 --- a/modules/node/handler/node_form_response.e +++ b/modules/node/handler/node_form_response.e @@ -351,15 +351,15 @@ feature -- Form f.extend (ts) end f.extend_html_text ("
    ") - f.extend_html_text ("Do you want to revert the current node?") + f.extend_html_text ("Do you want to restore the current node?") if a_node /= Void and then a_node.id > 0 then create ts.make ("op") - ts.set_default_value ("Revert") + ts.set_default_value ("Restore") fixme ("[ - ts.set_default_value (translation ("Revert")) + ts.set_default_value (translation ("Restore")) ]") f.extend (ts) end diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e index 5f71573..88fb687 100644 --- a/modules/node/handler/node_handler.e +++ b/modules/node/handler/node_handler.e @@ -141,7 +141,7 @@ feature -- HTTP Methods do_trash (req, res) elseif attached {WSF_STRING} req.form_parameter ("op") as l_op and then - l_op.value.same_string ("Revert") + l_op.value.same_string ("Restore") then do_restore (req, res) end @@ -194,7 +194,7 @@ feature -- HTTP Methods send_not_implemented ("REST API not yet implemented", req, res) end -feature {NONE} -- Trash:Revert +feature {NONE} -- Trash:Restore do_trash (req: WSF_REQUEST; res: WSF_RESPONSE) -- Trash a node from the database. @@ -224,7 +224,7 @@ feature {NONE} -- Trash:Revert end do_restore (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Revert a node: From {CMS_NODE_API}.trashed to {CMS_NODE_API}.not_published. + -- 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 diff --git a/modules/node/persistence/cms_node_storage_sql.e b/modules/node/persistence/cms_node_storage_sql.e index 8575567..b409851 100644 --- a/modules/node/persistence/cms_node_storage_sql.e +++ b/modules/node/persistence/cms_node_storage_sql.e @@ -210,7 +210,7 @@ feature -- Change: Node l_time: DATE_TIME do create l_time.make_now_utc - write_information_log (generator + ".revert_node {" + a_id.out + "}") + write_information_log (generator + ".restore_node {" + a_id.out + "}") error_handler.reset create l_parameters.make (1) @@ -319,7 +319,7 @@ feature {NONE} -- Queries -- Physical deletion with free metadata. sql_restore_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid" - -- Revert node to {CMS_NODE_API}.not_publised. + -- Restore node to {CMS_NODE_API}.not_publised. -- sql_update_node_author: STRING = "UPDATE nodes SET author=:author WHERE nid=:nid;"