diff --git a/dev_modules/masquerade_auth/masquerade_auth_module.e b/dev_modules/masquerade_auth/masquerade_auth_module.e index ca8a1c1..b5ada33 100644 --- a/dev_modules/masquerade_auth/masquerade_auth_module.e +++ b/dev_modules/masquerade_auth/masquerade_auth_module.e @@ -183,10 +183,10 @@ feature {NONE} -- Implementation: routes create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) r.add_block (login_block ("login", "Wrong username", r), "content") end + r.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + api.response_api.send_access_denied (Void, req, res) end - r.execute end feature -- Hooks configuration diff --git a/examples/demo/demo.ecf b/examples/demo/demo.ecf index 8163de4..2e3a1bb 100644 --- a/examples/demo/demo.ecf +++ b/examples/demo/demo.ecf @@ -26,12 +26,10 @@ - - diff --git a/examples/demo/launcher/any/application_launcher.e b/examples/demo/launcher/any/application_launcher.e deleted file mode 100644 index 095fdc1..0000000 --- a/examples/demo/launcher/any/application_launcher.e +++ /dev/null @@ -1,19 +0,0 @@ -note - description: "[ - Effective class for APPLICATION_LAUNCHER_I - - You can put modification in this class - ]" - date: "$Date$" - revision: "$Revision$" - -class - APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end] - -inherit - APPLICATION_LAUNCHER_I [G] - -feature -- Custom - -end - diff --git a/examples/demo/launcher/any/application_launcher_i.e b/examples/demo/launcher/any/application_launcher_i.e deleted file mode 100644 index cec830f..0000000 --- a/examples/demo/launcher/any/application_launcher_i.e +++ /dev/null @@ -1,127 +0,0 @@ -note - description: "[ - Specific application launcher - - DO NOT EDIT THIS CLASS - - you can customize APPLICATION_LAUNCHER - ]" - date: "$Date$" - revision: "$Revision$" - -deferred class - APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end] - -inherit - SHARED_EXECUTION_ENVIRONMENT - -feature -- Execution - - launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) - local - nature: like launcher_nature - do - nature := launcher_nature - if nature = Void then - launch_standalone (opts) - elseif nature = nature_standalone then - launch_standalone (opts) - elseif nature = nature_nino then - launch_nino (opts) - elseif nature = nature_cgi then - launch_cgi (opts) - elseif nature = nature_libfcgi then - launch_libfcgi (opts) - else - -- bye bye - (create {EXCEPTIONS}).die (-1) - end - end - -feature {NONE} -- Access - - launcher_nature: detachable READABLE_STRING_8 - -- Initialize the launcher nature - -- either cgi, libfcgi, or nino. - --| We could extend with more connector if needed. - --| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time. - local - p: PATH - ext: detachable READABLE_STRING_32 - do - create p.make_from_string (execution_environment.arguments.command_name) - if attached p.entry as l_entry then - ext := l_entry.extension - end - if ext /= Void then - if ext.same_string (nature_standalone) then - Result := nature_standalone - end - if ext.same_string (nature_nino) then - Result := nature_nino - end - if ext.same_string (nature_cgi) then - Result := nature_cgi - end - if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then - Result := nature_libfcgi - end - end - Result := default_nature - end - -feature {NONE} -- standalone - - nature_standalone: STRING = "standalone" - - launch_standalone (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) - local - launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G] - do - create launcher.make_and_launch (opts) - end - -feature {NONE} -- nino - - nature_nino: STRING = "nino" - - launch_nino (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) - local - launcher: WSF_NINO_SERVICE_LAUNCHER [G] - do - create launcher.make_and_launch (opts) - end - -feature {NONE} -- cgi - - nature_cgi: STRING = "cgi" - - launch_cgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) - local - launcher: WSF_CGI_SERVICE_LAUNCHER [G] - do - create launcher.make_and_launch (opts) - end - -feature {NONE} -- libfcgi - - nature_libfcgi: STRING = "libfcgi" - - launch_libfcgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) - local - launcher: WSF_LIBFCGI_SERVICE_LAUNCHER [G] - do - create launcher.make_and_launch (opts) - end - -feature -- Default - - default_nature: STRING - do - Result := nature_standalone - end - - -end - - diff --git a/examples/demo/launcher/default/application_launcher.e b/examples/demo/launcher/default/application_launcher.e deleted file mode 100644 index 095fdc1..0000000 --- a/examples/demo/launcher/default/application_launcher.e +++ /dev/null @@ -1,19 +0,0 @@ -note - description: "[ - Effective class for APPLICATION_LAUNCHER_I - - You can put modification in this class - ]" - date: "$Date$" - revision: "$Revision$" - -class - APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end] - -inherit - APPLICATION_LAUNCHER_I [G] - -feature -- Custom - -end - diff --git a/examples/demo/launcher/default/application_launcher_i.e b/examples/demo/launcher/default/application_launcher_i.e deleted file mode 100644 index cfe2b9d..0000000 --- a/examples/demo/launcher/default/application_launcher_i.e +++ /dev/null @@ -1,26 +0,0 @@ -note - description: "[ - Specific application launcher - - DO NOT EDIT THIS CLASS - - you can customize APPLICATION_LAUNCHER - ]" - date: "$Date$" - revision: "$Revision$" - -deferred class - APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end] - -feature -- Execution - - launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) - local - launcher: WSF_DEFAULT_SERVICE_LAUNCHER [G] - do - create launcher.make_and_launch (opts) - end - -end - - diff --git a/examples/demo/site/modules/oauth20/templates/block_login.tpl b/examples/demo/site/modules/oauth20/templates/block_login.tpl index 44c7bd4..3f7fc6b 100644 --- a/examples/demo/site/modules/oauth20/templates/block_login.tpl +++ b/examples/demo/site/modules/oauth20/templates/block_login.tpl @@ -1,7 +1,7 @@
{foreach item="item" from="$oauth_consumers"} - Login with {$item/}
+ Login with {$item/}
{/foreach}
diff --git a/examples/demo/site/themes/admin/assets/scss/style.scss b/examples/demo/site/themes/admin/assets/scss/style.scss new file mode 100644 index 0000000..e2c4f77 --- /dev/null +++ b/examples/demo/site/themes/admin/assets/scss/style.scss @@ -0,0 +1,110 @@ +ul.horizontal { + li { + display: inline-block; + } +} + +#header { + #primary.menu { + ul { + li { + color: #555; + a { + color: #555; + text-decoration: none; + &:hover { color: black; } + } + background-color: #fff; + padding: 10px; + margin: 0; + } + &.horizontal { + border-bottom: solid 1px #ddd; + li { + border-top: solid 3px #fff; + &:hover { + background-color: #ffe; + border-top: solid 3px #999; + } + &.active { + font-weight: bold; + border-top: solid 3px #ddd; + background-color: #ddd; + } + &.active:hover { + border-top: solid 3px blue; + } + } + } + } + } +} +#content { + margin-left: 20px; + #highlighted { + position: relative; + border: solid 1px #ddd; + background-color: #ffc; + width: 70%; + left: 15%; + right: 15%; + padding: 5px; + font-style: italic; + } + .preview { + border: solid 1px red; + } +} +.sidebar { + padding: 5px; + margin: 3px; + /* border: solid 1px #ccc; */ + &#sidebar_first { + width: 250px; + position: fixed; + top: 45px; + left: 0; + bottom: 0; + width: 200px; + border-right: solid 1px #ddd; + } + &#sidebar_second { + width: 250px; + float: right; + } + + &+.main { + margin-left: 200px; + } +} +#primary-tabs { + ul.horizontal { + list-style-type: none; + li { + display: inline; + padding: 2px 5px; + border: solid 1px #ccf; + } + li.active { + border-color: #99f #99f #ddd; + border-style: solid solid none; + border-width: 2px 1px 0; + padding: 2px 7px 1px; + } + } +} +#message li.error { + background-color: #f99; + border: solid 1px red; + padding: 5px 2px 5px 2px; +} + +table.with_border { + thead td { + font-weight: bold; + } + td { + border: solid 1px #ccc; + padding: 2px 5px 2px 5px; + } +} diff --git a/examples/demo/site/themes/admin/debug.tpl b/examples/demo/site/themes/admin/debug.tpl new file mode 100644 index 0000000..b689091 --- /dev/null +++ b/examples/demo/site/themes/admin/debug.tpl @@ -0,0 +1,38 @@ +{assign name="debug_enabled" value="True"/} +{if condition="$debug_enabled"} + +{literal} + +{/literal} +
Show debug +
    +{assign name="kpage" value="page"/}{assign name="kregions" value="regions"/}{foreach key="k" item="i" from="$page.variables"}{unless condition="$k ~ $kpage"}{unless condition="$k ~ $kregions"}
  • {$k/}={htmlentities}{$i/}{/htmlentities}
  • {/unless}{/unless} +{/foreach} +
+
+ +{/if} diff --git a/library/model/src/user/cms_user.e b/library/model/src/user/cms_user.e index d17b5ef..8f29c6c 100644 --- a/library/model/src/user/cms_user.e +++ b/library/model/src/user/cms_user.e @@ -17,15 +17,19 @@ create feature {NONE} -- Initialization - make (a_name: READABLE_STRING_32) + make (a_name: READABLE_STRING_GENERAL) -- Create an object with name `a_name'. require a_name_not_empty: not a_name.is_whitespace do - name := a_name + if attached {READABLE_STRING_32} a_name as n32 then + name := n32 + else + name := a_name.to_string_32 + end initialize ensure - name_set: name = a_name + name_set: name.same_string_general (a_name) status_not_active: status = not_active end diff --git a/library/recaptcha/recaptcha.ecf b/library/recaptcha/recaptcha.ecf index 1b4ad38..d6f6049 100644 --- a/library/recaptcha/recaptcha.ecf +++ b/library/recaptcha/recaptcha.ecf @@ -3,10 +3,10 @@ - /.git$ - /.svn$ - /CVS$ + /\.git$ /EIFGENs$ + /CVS$ + /\.svn$ @@ -14,5 +14,7 @@ + + diff --git a/library/recaptcha/src/recaptcha_api.e b/library/recaptcha/src/recaptcha_api.e index 1717abb..96d599f 100644 --- a/library/recaptcha/src/recaptcha_api.e +++ b/library/recaptcha/src/recaptcha_api.e @@ -98,26 +98,24 @@ feature {NONE} -- REST API get: detachable RESPONSE -- Reading Data - local - l_request: REQUEST do - create l_request.make ("GET", new_uri) - Result := l_request.execute + Result := (create {REQUEST}.make ("GET", new_uri)).execute end feature {NONE} -- Implementation new_uri: STRING_8 -- new uri (BaseUri?secret=secret_value&response=response_value[&remoteip=remoteip_value] + local + l_uri: URI do - create Result.make_from_string (base_uri) - Result.append ("?secret=") - Result.append (secret) - Result.append ("&response=") - Result.append (response) + create l_uri.make_from_string (base_uri) + l_uri.add_query_parameter ("secret", secret) + l_uri.add_query_parameter ("response", response) if attached remoteip as l_remoteip then - Result.append ("&remoteip=" + l_remoteip) + l_uri.add_query_parameter ("remoteip", l_remoteip) end + Result := l_uri.string end put_error (a_code: READABLE_STRING_GENERAL) @@ -134,7 +132,7 @@ feature {NONE} -- Implementation end note - copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2017 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/modules/admin/cms_admin_module_administration.e b/modules/admin/cms_admin_module_administration.e index 8d33b0e..5977ade 100644 --- a/modules/admin/cms_admin_module_administration.e +++ b/modules/admin/cms_admin_module_administration.e @@ -51,7 +51,7 @@ feature {NONE} -- Router/administration l_roles_handler: CMS_ADMIN_ROLES_HANDLER l_formats_handler: CMS_ADMIN_FORMATS_HANDLER - l_user_handler: CMS_USER_HANDLER + l_user_handler: CMS_ADMIN_USER_HANDLER l_role_handler: CMS_ROLE_HANDLER l_admin_logs_handler: CMS_LOGS_HANDLER diff --git a/modules/admin/handler/cms_admin_cache_handler.e b/modules/admin/handler/cms_admin_cache_handler.e index efdbb0a..3271042 100644 --- a/modules/admin/handler/cms_admin_cache_handler.e +++ b/modules/admin/handler/cms_admin_cache_handler.e @@ -47,10 +47,10 @@ feature -- Execution create s.make_empty f.append_to_html (l_response.wsf_theme, s) l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_custom_access_denied (Void, <<"admin cache">>, req, res) end - l_response.execute end do_post (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -77,10 +77,10 @@ feature -- Execution create s.make_empty f.append_to_html (l_response.wsf_theme, s) l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_custom_access_denied (Void, <<"admin cache">>, req, res) end - l_response.execute end feature -- Widget diff --git a/modules/admin/handler/cms_admin_export_handler.e b/modules/admin/handler/cms_admin_export_handler.e index 85a150b..597e09a 100644 --- a/modules/admin/handler/cms_admin_export_handler.e +++ b/modules/admin/handler/cms_admin_export_handler.e @@ -47,10 +47,10 @@ feature -- Execution create s.make_empty f.append_to_html (l_response.wsf_theme, s) l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_access_denied (req, res) end - l_response.execute end do_post (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -92,10 +92,10 @@ feature -- Execution create s.make_empty f.append_to_html (l_response.wsf_theme, s) l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_access_denied (req, res) end - l_response.execute end feature -- Widget diff --git a/modules/admin/handler/cms_admin_handler.e b/modules/admin/handler/cms_admin_handler.e index 49d123b..c7a3b29 100644 --- a/modules/admin/handler/cms_admin_handler.e +++ b/modules/admin/handler/cms_admin_handler.e @@ -3,7 +3,7 @@ note handler for CMS admin in the CMS interface. TODO: implement REST API. - ]" + ]" date: "$Date$" revision: "$Revision$" @@ -64,12 +64,11 @@ feature -- HTTP Methods local r: CMS_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then + if api.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then create {CMS_ADMIN_RESPONSE} r.make (req, res, api) r.execute else - r.execute + send_access_denied (req, res) end end @@ -77,12 +76,11 @@ feature -- HTTP Methods local r: CMS_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then + if api.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then create {CMS_ADMIN_RESPONSE} r.make (req, res, api) r.execute else - r.execute + send_access_denied (req, res) end end diff --git a/modules/admin/handler/cms_admin_import_handler.e b/modules/admin/handler/cms_admin_import_handler.e index 2122077..710ab54 100644 --- a/modules/admin/handler/cms_admin_import_handler.e +++ b/modules/admin/handler/cms_admin_import_handler.e @@ -47,10 +47,10 @@ feature -- Execution create s.make_empty f.append_to_html (l_response.wsf_theme, s) l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_access_denied (req, res) end - l_response.execute end do_post (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -99,11 +99,10 @@ feature -- Execution create s.make_empty f.append_to_html (l_response.wsf_theme, s) l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_access_denied (req, res) end - - l_response.execute end feature -- Widget diff --git a/modules/admin/handler/cms_admin_modules_handler.e b/modules/admin/handler/cms_admin_modules_handler.e index d635715..ef78bac 100644 --- a/modules/admin/handler/cms_admin_modules_handler.e +++ b/modules/admin/handler/cms_admin_modules_handler.e @@ -60,8 +60,7 @@ feature -- Execution l_denied := True end if l_denied then - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("You do not have permission to access CMS module uninstallation procedure!") + send_custom_access_denied ("You do not have permission to access CMS module uninstallation procedure!", Void, req, res) else create s.make_empty across @@ -82,8 +81,8 @@ feature -- Execution end s.append (r.link ("Back to modules management", r.location, Void)) r.set_main_content (s) + r.execute end - r.execute else create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create s.make_empty @@ -119,8 +118,7 @@ feature -- Execution l_denied := True end if l_denied then - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("You do not have permission to access CMS module installation procedure!") + send_custom_access_denied ("You do not have permission to access CMS module installation procedure!", Void, req, res) else f := modules_to_install_collection_web_form (r) f.submit_actions.extend (agent on_installation_submit) @@ -138,8 +136,8 @@ feature -- Execution r.add_notice_message ("Operation on module(s) succeeded.") r.set_redirection (r.location) end + r.execute end - r.execute elseif l_op.same_string ("Update status") then create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) if api.has_permission ("admin module") then @@ -159,15 +157,12 @@ feature -- Execution r.add_notice_message ("Operation on module(s) succeeded.") r.set_redirection (r.location) end - + r.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("You do not have permission to administrate CMS modules!") + send_custom_access_denied ("You do not have permission to administrate CMS modules!", Void, req, res) end - r.execute else - create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + send_bad_request (req, res) end else do_get (req, res) diff --git a/modules/admin/handler/cms_admin_path_alias_handler.e b/modules/admin/handler/cms_admin_path_alias_handler.e index 9d740f2..6ae3cf8 100644 --- a/modules/admin/handler/cms_admin_path_alias_handler.e +++ b/modules/admin/handler/cms_admin_path_alias_handler.e @@ -81,10 +81,10 @@ feature -- Execution s.append ("") end l_response.set_main_content (s) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) + send_access_denied (req, res) end - l_response.execute end do_post (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -114,11 +114,11 @@ feature -- Execution l_response.set_redirection (l_response.location) l_response.set_redirection_delay (3) + l_response.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) - l_response.set_redirection (l_response.location) + send_access_denied (req, res) + -- CHECK: set redirection? end - l_response.execute end end diff --git a/modules/admin/handler/format/cms_admin_formats_handler.e b/modules/admin/handler/format/cms_admin_formats_handler.e index 1f4c5e9..2f8ca94 100644 --- a/modules/admin/handler/format/cms_admin_formats_handler.e +++ b/modules/admin/handler/format/cms_admin_formats_handler.e @@ -152,8 +152,8 @@ feature -- View/edit Format i := i + 1 l_name := f_ic.item.name l_all_filters.force (f_ic.item, l_name) - create cb.make_with_value ("filters[" + l_name + "]", l_name) - cb.set_title (f_ic.item.title) + create cb.make_with_value ("filters[" + l_name + "]", l_name.to_string_32) + cb.set_title (f_ic.item.title.to_string_32) cb.set_checked (True) create hf.make_with_text ("filter_weight[" + l_name + "]", i.out) @@ -178,8 +178,8 @@ feature -- View/edit Format l_name := f_ic.item.name if l_all_filters.has (l_name) then else - create cb.make_with_value ("filters[" + l_name + "]", l_name) - cb.set_title (f_ic.item.title) + create cb.make_with_value ("filters[" + l_name + "]", l_name.to_string_32) + cb.set_title (f_ic.item.title.to_string_32) create ftb_row.make (2) ftb.add_row (ftb_row) ftb_row.add_widget (cb) @@ -195,8 +195,8 @@ feature -- View/edit Format api.content_types as ct_ic loop l_name := ct_ic.item.name - create cb.make_with_value ("content_types[]", l_name) - cb.set_title (l_name) + create cb.make_with_value ("content_types[]", l_name.to_string_32) + cb.set_title (l_name.to_string_32) if f /= Void and then ct_ic.item.has_format (f.name) then cb.set_checked (True) end diff --git a/modules/admin/handler/logs/cms_logs_handler.e b/modules/admin/handler/logs/cms_logs_handler.e index 1d3c3f9..d89f22a 100644 --- a/modules/admin/handler/logs/cms_logs_handler.e +++ b/modules/admin/handler/logs/cms_logs_handler.e @@ -63,7 +63,7 @@ feature -- HTTP Methods l_logs: LIST [CMS_LOG] l_log: CMS_LOG r: CMS_RESPONSE - l_cat: detachable READABLE_STRING_8 + l_cat: detachable READABLE_STRING_32 l_lower: INTEGER l_count: INTEGER b: STRING @@ -104,11 +104,10 @@ feature -- HTTP Methods r.set_main_content (b) r.set_page_title ("Logs ...") r.set_title ("Logs") + r.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + send_access_denied (req, res) end - r.execute - end end diff --git a/modules/admin/handler/role/cms_role_form_response.e b/modules/admin/handler/role/cms_role_form_response.e index 4232c3d..52c542c 100644 --- a/modules/admin/handler/role/cms_role_form_response.e +++ b/modules/admin/handler/role/cms_role_form_response.e @@ -348,9 +348,9 @@ feature -- Form fs.extend (lab) string_sorter.sort (l_permissions) across l_permissions as ic loop - create cb.make_with_value ("cms_permissions", ic.item) + create cb.make_with_value ("cms_permissions", ic.item.to_string_32) cb.set_checked (across l_role_permissions as rp_ic some rp_ic.item.is_case_insensitive_equal (ic.item) end) - cb.set_title (ic.item) + cb.set_title (ic.item.to_string_32) fs.extend (cb) end end @@ -389,7 +389,7 @@ feature -- Form update_role (a_form_data: WSF_FORM_DATA; a_role: CMS_USER_ROLE) -- Update node `a_node' with form_data `a_form_data' for the given content type `a_content_type'. local - l_perm: READABLE_STRING_8 + l_perm: READABLE_STRING_GENERAL do if attached a_form_data.string_item ("op") as f_op then if f_op.is_case_insensitive_equal_general ("Update role") then @@ -400,16 +400,16 @@ feature -- Form then if attached {WSF_STRING} a_form_data.item ("cms_permissions") as u_role then a_role.permissions.wipe_out - a_role.add_permission (u_role.value) + a_role.add_permission (api.utf_8_encoded (u_role.value)) -- TODO: utf-8 or require valid string 8? elseif attached {WSF_MULTIPLE_STRING} a_form_data.item ("cms_permissions") as u_permissions then a_role.permissions.wipe_out -- Enable checked permissions. across u_permissions as ic loop - l_perm := ic.item.value.as_string_8 + l_perm := ic.item.value if not l_perm.is_whitespace then - a_role.add_permission (l_perm) + a_role.add_permission (api.utf_8_encoded (l_perm)) -- TODO: utf-8 or require valid string 8? end end else @@ -421,9 +421,9 @@ feature -- Form l_cms_perms.values as ic loop if attached {WSF_STRING} ic.item as p then - l_perm := p.value.as_string_8 + l_perm := p.value if not l_perm.is_whitespace then - a_role.add_permission (l_perm) + a_role.add_permission (api.utf_8_encoded (l_perm)) end end end diff --git a/modules/admin/handler/role/cms_role_handler.e b/modules/admin/handler/role/cms_role_handler.e index a97cfab..32a36e5 100644 --- a/modules/admin/handler/role/cms_role_handler.e +++ b/modules/admin/handler/role/cms_role_handler.e @@ -81,10 +81,8 @@ feature -- HTTP Methods l_uid: INTEGER_64 edit_response: CMS_ROLE_FORM_RESPONSE view_response: CMS_ROLE_VIEW_RESPONSE - r: CMS_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("admin roles") then + if api.has_permission ("admin roles") then if req.percent_encoded_path_info.ends_with_general ("/edit") then check valid_url: req.percent_encoded_path_info.starts_with_general (api.administration_path ("/role/")) end create edit_response.make (req, res, api) @@ -111,18 +109,15 @@ feature -- HTTP Methods end end else - r.execute + send_access_denied (req, res) end end - do_post (req: WSF_REQUEST; res: WSF_RESPONSE) local edit_response: CMS_ROLE_FORM_RESPONSE - r: CMS_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("admin roles") then + if api.has_permission ("admin roles") then if req.percent_encoded_path_info.ends_with_general ("/edit") then create edit_response.make (req, res, api) edit_response.execute @@ -138,7 +133,7 @@ feature -- HTTP Methods edit_response.execute end else - r.execute + send_access_denied (req, res) end end diff --git a/modules/admin/handler/role/cms_role_view_response.e b/modules/admin/handler/role/cms_role_view_response.e index c532221..3fc44b3 100644 --- a/modules/admin/handler/role/cms_role_view_response.e +++ b/modules/admin/handler/role/cms_role_view_response.e @@ -71,7 +71,7 @@ feature -- Execution s.append ("
") s.append ("

Role Information

") s.append ("

Role:") - s.append (a_role.name) + s.append (html_encoded (a_role.name)) s.append ("

") s.append ("

Permissions:

") diff --git a/modules/admin/handler/user/cms_user_form_response.e b/modules/admin/handler/user/cms_admin_user_form_response.e similarity index 98% rename from modules/admin/handler/user/cms_user_form_response.e rename to modules/admin/handler/user/cms_admin_user_form_response.e index 8bda43d..4da8244 100644 --- a/modules/admin/handler/user/cms_user_form_response.e +++ b/modules/admin/handler/user/cms_admin_user_form_response.e @@ -1,10 +1,10 @@ note - description: "Summary description for {CMS_USER_FORM_RESPONSE}." + description: "Summary description for {CMS_ADMIN_USER_FORM_RESPONSE}." date: "$Date$" revision: "$Revision$" class - CMS_USER_FORM_RESPONSE + CMS_ADMIN_USER_FORM_RESPONSE inherit CMS_RESPONSE @@ -324,10 +324,10 @@ feature -- Form create fs.make fs.set_legend ("Basic User Account Information") fs.extend_html_text ("

") - fs.extend_html_text (a_user.name) + fs.extend_raw_text (a_user.name) if attached a_user.email as l_email then - create fe.make_with_text ("email", l_email) + create fe.make_with_text ("email", l_email.to_string_32) else create fe.make_with_text ("email", "") end @@ -477,7 +477,7 @@ feature -- Form api.user_api.user_by_email (l_email) = Void then -- Valid email - a_user.set_email (l_email) + a_user.set_email (api.utf_8_encoded (l_email)) else if attached l_user.email as u_email and then not u_email.is_case_insensitive_equal_general (l_email) then a_form_data.report_invalid_field ("email", "Email already exist!") diff --git a/modules/admin/handler/user/cms_user_handler.e b/modules/admin/handler/user/cms_admin_user_handler.e similarity index 89% rename from modules/admin/handler/user/cms_user_handler.e rename to modules/admin/handler/user/cms_admin_user_handler.e index 5f01136..2f2d427 100644 --- a/modules/admin/handler/user/cms_user_handler.e +++ b/modules/admin/handler/user/cms_admin_user_handler.e @@ -1,12 +1,12 @@ note description: "[ - Handler for a CMS user in the CMS interface + Administration handler for a CMS user in the CMS interface ]" date: "$Date$" revision: "$Revision$" class - CMS_USER_HANDLER + CMS_ADMIN_USER_HANDLER inherit CMS_HANDLER @@ -79,12 +79,10 @@ feature -- HTTP Methods local l_user: detachable CMS_USER l_uid: INTEGER_64 - edit_response: CMS_USER_FORM_RESPONSE - view_response: CMS_USER_VIEW_RESPONSE - r: CMS_RESPONSE + edit_response: CMS_ADMIN_USER_FORM_RESPONSE + view_response: CMS_ADMIN_USER_VIEW_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("admin users") then + if api.has_permission ("admin users") then if req.percent_encoded_path_info.ends_with_general ("/edit") then check valid_url: req.percent_encoded_path_info.starts_with_general (api.administration_path ("/user/")) end create edit_response.make (req, res, api) @@ -111,18 +109,16 @@ feature -- HTTP Methods end end else - r.execute + send_access_denied (req, res) end end do_post (req: WSF_REQUEST; res: WSF_RESPONSE) local - edit_response: CMS_USER_FORM_RESPONSE - r: CMS_RESPONSE + edit_response: CMS_ADMIN_USER_FORM_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("admin users") then + if api.has_permission ("admin users") then if req.percent_encoded_path_info.ends_with_general ("/edit") then create edit_response.make (req, res, api) edit_response.execute @@ -138,7 +134,7 @@ feature -- HTTP Methods edit_response.execute end else - r.execute + send_access_denied (req, res) end end @@ -190,7 +186,7 @@ feature {NONE} -- New User create_new_user (req: WSF_REQUEST; res: WSF_RESPONSE) local - edit_response: CMS_USER_FORM_RESPONSE + edit_response: CMS_ADMIN_USER_FORM_RESPONSE do if req.percent_encoded_path_info.starts_with (api.administration_path ("/add/user")) then create edit_response.make (req, res, api) diff --git a/modules/admin/handler/user/cms_user_view_response.e b/modules/admin/handler/user/cms_admin_user_view_response.e similarity index 97% rename from modules/admin/handler/user/cms_user_view_response.e rename to modules/admin/handler/user/cms_admin_user_view_response.e index 00fccc6..07d17e0 100644 --- a/modules/admin/handler/user/cms_user_view_response.e +++ b/modules/admin/handler/user/cms_admin_user_view_response.e @@ -1,10 +1,10 @@ note - description: "Summary description for {CMS_USER_VIEW_RESPONSE}." + description: "Summary description for {CMS_ADMIN_USER_VIEW_RESPONSE}." date: "$Date$" revision: "$Revision$" class - CMS_USER_VIEW_RESPONSE + CMS_ADMIN_USER_VIEW_RESPONSE inherit CMS_RESPONSE @@ -27,7 +27,6 @@ feature -- Query end end - feature -- Execution process diff --git a/modules/admin/handler/user/cms_admin_users_handler.e b/modules/admin/handler/user/cms_admin_users_handler.e index 735fdd4..8451b2c 100644 --- a/modules/admin/handler/user/cms_admin_users_handler.e +++ b/modules/admin/handler/user/cms_admin_users_handler.e @@ -73,8 +73,7 @@ feature -- HTTP Methods -- get them from the configuration file and load them into -- the setup class. - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) - if l_response.has_permission ("admin users") then + if api.has_permission ("admin users") then user_api := api.user_api l_count := user_api.users_count @@ -157,7 +156,7 @@ feature -- HTTP Methods l_response.set_main_content (s) l_response.execute else - l_response.execute + send_access_denied (req, res) end end end diff --git a/modules/auth/cms_authentication_email_service.e b/modules/auth/cms_authentication_email_service.e index f29d80c..57268fb 100644 --- a/modules/auth/cms_authentication_email_service.e +++ b/modules/auth/cms_authentication_email_service.e @@ -81,7 +81,7 @@ feature -- Basic Operations / Internal feature -- Basic Operations / Contact - send_account_evaluation (a_user: CMS_USER; a_application, a_url_activate, a_url_reject, a_host: READABLE_STRING_8) + send_account_evaluation (a_user: CMS_USER; a_application: READABLE_STRING_GENERAL; a_url_activate, a_url_reject, a_host: READABLE_STRING_8) -- Send new user register to webmaster to confirm or reject itt. local l_message: STRING @@ -95,7 +95,7 @@ feature -- Basic Operations / Contact else l_message.replace_substring_all ("$email", "unknown email") end - l_message.replace_substring_all ("$application", a_application) + l_message.replace_substring_all ("$application", cms_api.utf_8_encoded (a_application)) l_message.replace_substring_all ("$activation_url", a_url_activate) l_message.replace_substring_all ("$rejection_url", a_url_reject) send_message (contact_email_address, contact_email_address, parameters.contact_subject_account_evaluation, l_message) diff --git a/modules/auth/cms_authentication_email_service_parameters.e b/modules/auth/cms_authentication_email_service_parameters.e index 161761b..d496927 100644 --- a/modules/auth/cms_authentication_email_service_parameters.e +++ b/modules/auth/cms_authentication_email_service_parameters.e @@ -13,7 +13,6 @@ feature {NONE} -- Initialization make (a_cms_api: CMS_API) local - utf: UTF_CONVERTER s: detachable READABLE_STRING_32 l_utf8_site_name: IMMUTABLE_STRING_8 l_contact_email, l_subject_register, l_subject_activate, l_subject_password, l_subject_oauth: detachable READABLE_STRING_8 @@ -31,23 +30,23 @@ feature {NONE} -- Initialization if attached a_cms_api.module_configuration_by_name ({CMS_AUTHENTICATION_MODULE}.name, Void) as cfg then s := cfg.text_item ("email") if s /= Void then - l_contact_email := utf.utf_32_string_to_utf_8_string_8 (s) + l_contact_email := cms_api.utf_8_encoded (s) end s := cfg.text_item ("subject_register") if s /= Void then - l_subject_register := utf.utf_32_string_to_utf_8_string_8 (s) + l_subject_register := cms_api.utf_8_encoded (s) end s := cfg.text_item ("subject_activate") if s /= Void then - l_subject_register := utf.utf_32_string_to_utf_8_string_8 (s) + l_subject_register := cms_api.utf_8_encoded (s) end s := cfg.text_item ("subject_password") if s /= Void then - l_subject_register := utf.utf_32_string_to_utf_8_string_8 (s) + l_subject_register := cms_api.utf_8_encoded (s) end s := cfg.text_item ("subject_oauth") if s /= Void then - l_subject_oauth := utf.utf_32_string_to_utf_8_string_8 (s) + l_subject_oauth := cms_api.utf_8_encoded (s) end end if l_contact_email = Void then diff --git a/modules/auth/cms_authentication_module.e b/modules/auth/cms_authentication_module.e index 83311aa..c1e3cdf 100644 --- a/modules/auth/cms_authentication_module.e +++ b/modules/auth/cms_authentication_module.e @@ -65,6 +65,7 @@ feature -- Access Result.force ("account reject") Result.force ("account reactivate") Result.force ("change own username") + Result.force ("view user") end feature {CMS_EXECUTION} -- Administration @@ -123,6 +124,8 @@ feature -- Router a_router.handle ("/account/new-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_new_password(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/reset-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reset_password(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/change/{field}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_change_field (a_api, ?, ?)), a_router.methods_get_post) + + a_router.handle ("/user/{uid}", create {CMS_USER_HANDLER}.make (a_api), a_router.methods_get) end feature -- Hooks configuration @@ -382,7 +385,7 @@ feature -- Handler l_exist := True end if attached recaptcha_secret_key (api) as l_recaptcha_key then - if attached {WSF_STRING} req.form_parameter ("g-recaptcha-response") as l_recaptcha_response and then is_captcha_verified (l_recaptcha_key, l_recaptcha_response.value) then + if attached {WSF_STRING} req.form_parameter ("g-recaptcha-response") as l_recaptcha_response and then is_captcha_verified (l_recaptcha_key, l_recaptcha_response.url_encoded_value) then l_captcha_passed := True else --| Bad or missing captcha @@ -428,15 +431,13 @@ feature -- Handler r.set_status_code ({HTTP_CONSTANTS}.bad_request) end else - create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("There were issue with your application, invalid or missing values.") + api.response_api.send_bad_request ("There were issue with your application, invalid or missing values.", req, res) end end + r.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("You can also contact the webmaster to ask for an account.") + api.response_api.send_permissions_access_denied ("You can also contact the webmaster to ask for an account.", Void, req, res) end - r.execute end handle_activation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) @@ -500,8 +501,7 @@ feature -- Handler l_ir.execute end else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + api.response_api.send_access_denied (Void, req, res) end end @@ -536,8 +536,7 @@ feature -- Handler l_ir.execute end else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + api.response_api.send_access_denied (Void, req, res) end end @@ -551,8 +550,8 @@ feature -- Handler l_url_reject: STRING l_email: READABLE_STRING_8 do - create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("account reactivate") then + if api.has_permission ("account reactivate") then + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) if req.is_post_request_method then if attached {WSF_STRING} req.form_parameter ("email") as p_email then if p_email.value.is_valid_as_string_8 then @@ -587,11 +586,10 @@ feature -- Handler end end end - else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) r.execute + else + api.response_api.send_access_denied (Void, req, res) end - r.execute end handle_new_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) @@ -700,7 +698,7 @@ feature -- Handler l_fieldname := p_field.url_encoded_value end if l_fieldname = Void then - create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) + api.response_api.send_bad_request (Void, req, res) else create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) @@ -814,8 +812,8 @@ feature -- Handler end r.set_main_content (b) end + r.execute end - r.execute end block_list: ITERABLE [like {CMS_BLOCK}.name] @@ -1118,36 +1116,30 @@ feature -- Access: configuration form_registration_application_description (api: CMS_API): detachable READABLE_STRING_8 -- Get recaptcha security key. - local - utf: UTF_CONVERTER do if attached api.module_configuration (Current, Void) as cfg then if attached cfg.text_item ("forms.registration.application_description") as l_desc and then not l_desc.is_whitespace then - Result := utf.utf_32_string_to_utf_8_string_8 (l_desc) + Result := api.utf_8_encoded (l_desc) end end end recaptcha_secret_key (api: CMS_API): detachable READABLE_STRING_8 -- Get recaptcha security key. - local - utf: UTF_CONVERTER do if attached api.module_configuration (Current, Void) as cfg then if attached cfg.text_item ("recaptcha.secret_key") as l_recaptcha_key and then not l_recaptcha_key.is_empty then - Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + Result := api.utf_8_encoded (l_recaptcha_key) end end end recaptcha_site_key (api: CMS_API): detachable READABLE_STRING_8 -- Get recaptcha security key. - local - utf: UTF_CONVERTER do if attached api.module_configuration (Current, Void) as cfg then if attached cfg.text_item ("recaptcha.site_key") as l_recaptcha_key and then not l_recaptcha_key.is_empty then - Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + Result := api.utf_8_encoded (l_recaptcha_key) end end end diff --git a/modules/auth/cms_authentication_module_administration.e b/modules/auth/cms_authentication_module_administration.e index e8a984d..9fe173c 100644 --- a/modules/auth/cms_authentication_module_administration.e +++ b/modules/auth/cms_authentication_module_administration.e @@ -54,9 +54,8 @@ feature -- Request handling -- get them from the configuration file and load them into -- the setup class. - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api) if - l_response.has_permission ("admin registration") + api.has_permission ("admin registration") then l_user_api := api.user_api @@ -127,7 +126,7 @@ feature -- Request handling l_response.set_main_content (s) l_response.execute else - l_response.execute + api.response_api.send_access_denied (Void, req, res) end end diff --git a/modules/auth/cms_user_handler.e b/modules/auth/cms_user_handler.e new file mode 100644 index 0000000..d54b431 --- /dev/null +++ b/modules/auth/cms_user_handler.e @@ -0,0 +1,103 @@ +note + description: "[ + Handler for a CMS user in the CMS interface + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_USER_HANDLER + +inherit + CMS_HANDLER + + WSF_URI_HANDLER + rename + execute as uri_execute, + new_mapping as new_uri_mapping + end + + WSF_URI_TEMPLATE_HANDLER + rename + execute as uri_template_execute, + new_mapping as new_uri_template_mapping + select + new_uri_template_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 + + uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute (req, res) + end + + uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute (req, res) + end + +feature -- Query + + user_id_path_parameter (req: WSF_REQUEST): INTEGER_64 + -- User id passed as path parameter for request `req'. + local + s: STRING + do + if attached {WSF_STRING} req.path_parameter ("uid") as p_nid then + s := p_nid.value + if s.is_integer_64 then + Result := s.to_integer_64 + end + end + end + +feature -- HTTP Methods + + do_get (req: WSF_REQUEST; res: WSF_RESPONSE) + -- + local + l_user: detachable CMS_USER + l_uid: INTEGER_64 + view_response: CMS_USER_VIEW_RESPONSE + do + if api.has_permission ("view user") then + -- Display existing node + l_uid := user_id_path_parameter (req) + if l_uid > 0 then + l_user := api.user_api.user_by_id (l_uid) + if + l_user /= Void + then + create view_response.make (req, res, api) + view_response.execute + else + send_not_found (req, res) + end + else + send_bad_request (req, res) + end + else + send_access_denied (req, res) + end + end + +end diff --git a/modules/auth/cms_user_view_response.e b/modules/auth/cms_user_view_response.e new file mode 100644 index 0000000..612180c --- /dev/null +++ b/modules/auth/cms_user_view_response.e @@ -0,0 +1,103 @@ +note + description: "Summary description for {CMS_USER_VIEW_RESPONSE}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_USER_VIEW_RESPONSE + +inherit + CMS_RESPONSE + +create + make + +feature -- Query + + user_id_path_parameter (req: WSF_REQUEST): INTEGER_64 + -- User id passed as path parameter for request `req'. + local + s: STRING + do + if attached {WSF_STRING} req.path_parameter ("uid") as p_nid then + s := p_nid.value + if s.is_integer_64 then + Result := s.to_integer_64 + end + end + end + +feature -- Process + + process + -- Computed response message. + local + b: STRING_8 + uid: INTEGER_64 + user_api: CMS_USER_API + f: CMS_FORM + do + user_api := api.user_api + create b.make_empty + uid := user_id_path_parameter (request) + if + uid > 0 and then + attached user_api.user_by_id (uid) as l_user + then + if + api.has_permission ("view user") + or l_user.same_as (user) -- Same user + then + f := new_view_form (l_user, request.request_uri, "view-user") + f.append_to_html (wsf_theme, b) + else + b.append ("You don't have the permission to view this user!") + end + else + b.append ("User not found!") + end + set_main_content (b) + end + +feature -- Process Edit + + new_view_form (a_user: detachable CMS_USER; a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM + -- Create a web form named `a_name' for user `a_user' (if set), using form action url `a_url'. + local + th: WSF_FORM_HIDDEN_INPUT + do + create Result.make (a_url, a_name) + + create th.make ("user-id") + if a_user /= Void then + th.set_text_value (a_user.id.out) + else + th.set_text_value ("0") + end + Result.extend (th) + + populate_form (Result, a_user) + end + + populate_form (a_form: WSF_FORM; a_user: detachable CMS_USER) + -- Fill the web form `a_form' with data from `a_node' if set, + -- and apply this to content type `a_content_type'. + local + ti: WSF_FORM_TEXT_INPUT + fs: WSF_FORM_FIELD_SET + do + if a_user /= Void then + create fs.make + fs.set_legend ("User Information") + create ti.make_with_text ("profile_name", a_user.name) + if attached a_user.profile_name as l_profile_name then + ti.set_text_value (l_profile_name) + end + ti.set_label ("Profile name") + ti.set_is_readonly (True) + fs.extend (ti) + a_form.extend (fs) + end + end + +end diff --git a/modules/blog/handler/blog_user_handler.e b/modules/blog/handler/blog_user_handler.e index 674788c..d471921 100644 --- a/modules/blog/handler/blog_user_handler.e +++ b/modules/blog/handler/blog_user_handler.e @@ -37,8 +37,6 @@ feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) -- - local - l_error: NOT_FOUND_ERROR_CMS_RESPONSE do check user_void: user = Void end if attached user_from_request (req) as l_user then @@ -47,13 +45,11 @@ feature -- HTTP Methods Precursor (req, res) else -- Throw a bad request error because the user is not valid - create l_error.make (req, res, api) if attached user_parameter (req) as l_user_id then - l_error.set_main_content ("

Error

User with id " + api.html_encoded (l_user_id) + " not found!") + api.response_api.send_not_found ("

Error

User with id " + api.html_encoded (l_user_id) + " not found!", req, res) else - l_error.set_main_content ("

Error

User not found!") + api.response_api.send_not_found ("

Error

User not found!", req, res) end - l_error.execute end user := Void end diff --git a/modules/contact/src/cms_contact_module.e b/modules/contact/src/cms_contact_module.e index 6db9fa3..d7da476 100644 --- a/modules/contact/src/cms_contact_module.e +++ b/modules/contact/src/cms_contact_module.e @@ -123,30 +123,26 @@ feature -- Recaptcha recaptcha_secret_key (api: CMS_API): detachable READABLE_STRING_8 -- Get recaptcha security key. - local - utf: UTF_CONVERTER do if attached api.module_configuration (Current, Void) as cfg then if attached cfg.text_item ("recaptcha.secret_key") as l_recaptcha_key and then not l_recaptcha_key.is_empty then - Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + Result := api.utf_8_encoded (l_recaptcha_key) end end end recaptcha_site_key (api: CMS_API): detachable READABLE_STRING_8 -- Get recaptcha security key. - local - utf: UTF_CONVERTER do if attached api.module_configuration (Current, Void) as cfg then if attached cfg.text_item ("recaptcha.site_key") as l_recaptcha_key and then not l_recaptcha_key.is_empty then - Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + Result := api.utf_8_encoded (l_recaptcha_key) end end end diff --git a/modules/contact/src/contact_email_service_parameters.e b/modules/contact/src/contact_email_service_parameters.e index 4baedbe..6aa0ef4 100644 --- a/modules/contact/src/contact_email_service_parameters.e +++ b/modules/contact/src/contact_email_service_parameters.e @@ -13,13 +13,12 @@ feature {NONE} -- Initialization make (a_cms_api: CMS_API; a_contact_module: CMS_CONTACT_MODULE) local - utf: UTF_CONVERTER l_site_name: READABLE_STRING_8 s: detachable READABLE_STRING_32 l_contact_email, l_contact_subject: detachable READABLE_STRING_8 do -- Use global smtp setting if any, otherwise "localhost" - l_site_name := utf.escaped_utf_32_string_to_utf_8_string_8 (a_cms_api.setup.site_name) + l_site_name := a_cms_api.utf_8_encoded (a_cms_api.setup.site_name) admin_email := a_cms_api.setup.site_email if not admin_email.has ('<') then @@ -29,11 +28,11 @@ feature {NONE} -- Initialization if attached {CONFIG_READER} a_cms_api.module_configuration (a_contact_module, Void) as cfg then s := cfg.text_item ("email") if s /= Void then - l_contact_email := utf.utf_32_string_to_utf_8_string_8 (s) + l_contact_email := a_cms_api.utf_8_encoded (s) end s := cfg.text_item ("subject") if s /= Void then - l_contact_subject := utf.utf_32_string_to_utf_8_string_8 (s) + l_contact_subject := a_cms_api.utf_8_encoded (s) end end if l_contact_email /= Void then diff --git a/modules/contact/src/persistence/contact_storage_fs.e b/modules/contact/src/persistence/contact_storage_fs.e index fa6a921..5af97d5 100644 --- a/modules/contact/src/persistence/contact_storage_fs.e +++ b/modules/contact/src/persistence/contact_storage_fs.e @@ -25,7 +25,6 @@ feature -- Change save_contact_message (m: CONTACT_MESSAGE) local s: STRING - utf: UTF_CONVERTER now: DATE_TIME do error_handler.reset @@ -38,7 +37,7 @@ feature -- Change s.append (m.date.out) s.append_character ('%N') s.append ("name=") - s.append (utf.utf_32_string_to_utf_8_string_8 (m.username)) + s.append (api.utf_8_encoded (m.username)) s.append_character ('%N') if attached m.email as l_email then @@ -47,7 +46,7 @@ feature -- Change s.append_character ('%N') end s.append ("message=%N") - s.append (utf.utf_32_string_to_utf_8_string_8 (m.message)) + s.append (api.utf_8_encoded (m.message)) s.append_character ('%N') save_to_file (s, date_to_yyyymmdd_hhmmss_string (now)) diff --git a/modules/embedded_video/src/video_content_filter.e b/modules/embedded_video/src/video_content_filter.e index 3a28e8d..f1f5f18 100644 --- a/modules/embedded_video/src/video_content_filter.e +++ b/modules/embedded_video/src/video_content_filter.e @@ -253,11 +253,19 @@ feature {NONE} -- Implementation end replace_substring_all (s: STRING_GENERAL; a_old: READABLE_STRING_8; a_new: STRING_GENERAL) + local + utf: UTF_CONVERTER do if attached {STRING_8} s as s8 then - s8.replace_substring_all (a_old, a_new.to_string_8) + if a_new.is_valid_as_string_8 then + s8.replace_substring_all (a_old, a_new.to_string_8) + else + check a_new_is_string_8: False end + -- Use UTF-8 for now. + s8.replace_substring_all (a_old, utf.utf_32_string_to_utf_8_string_8 (a_new)) + end elseif attached {STRING_32} s as s32 then - s32.replace_substring_all (a_old, a_new) + s32.replace_substring_all (a_old.to_string_32, a_new) end end diff --git a/modules/feed_aggregator/feed_aggregator_api.e b/modules/feed_aggregator/feed_aggregator_api.e index 0cffb44..1c35d43 100644 --- a/modules/feed_aggregator/feed_aggregator_api.e +++ b/modules/feed_aggregator/feed_aggregator_api.e @@ -35,7 +35,6 @@ feature -- Access l_feed_id: READABLE_STRING_32 l_title: detachable READABLE_STRING_GENERAL l_locations: detachable STRING_TABLE [READABLE_STRING_8] - utf: UTF_CONVERTER l_table: like internal_aggregations do l_table := internal_aggregations @@ -56,20 +55,20 @@ feature -- Access across l_location_list as loc_ic loop - l_locations.force (utf.utf_32_string_to_utf_8_string_8 (loc_ic.item), loc_ic.item) + l_locations.force (cms_api.utf_8_encoded (loc_ic.item), loc_ic.item) end end if attached cfg.text_table_item ({STRING_32} "feeds." + l_feed_id + ".locations") as l_location_table then across l_location_table as loc_tb_ic loop - l_locations.force (utf.utf_32_string_to_utf_8_string_8 (loc_tb_ic.item), loc_tb_ic.key) + l_locations.force (cms_api.utf_8_encoded (loc_tb_ic.item), loc_tb_ic.key) end end if attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".location") as l_location then - l_locations.force (utf.utf_32_string_to_utf_8_string_8 (l_location), l_location) + l_locations.force (cms_api.utf_8_encoded (l_location), l_location) end if l_locations /= Void and then not l_locations.is_empty then l_title := cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".title") @@ -93,7 +92,7 @@ feature -- Access across l_locations as loc_ic loop - agg.locations.force (utf.utf_32_string_to_utf_8_string_8 (loc_ic.item)) + agg.locations.force (cms_api.utf_8_encoded (loc_ic.item)) end Result.force (agg, l_feed_id) if attached cfg.text_list_item ({STRING_32} "feeds." + l_feed_id + ".categories") as l_cats then diff --git a/modules/feed_aggregator/feed_aggregator_module.e b/modules/feed_aggregator/feed_aggregator_module.e index 60a335a..a843146 100644 --- a/modules/feed_aggregator/feed_aggregator_module.e +++ b/modules/feed_aggregator/feed_aggregator_module.e @@ -98,8 +98,7 @@ feature -- Handle m.header.put_content_type_text_html res.send (m) else - create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, a_api) - r.execute + a_api.response_api.send_not_found (Void, req, res) end else create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api) @@ -143,8 +142,7 @@ feature -- Handle r.execute end else - create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, a_api) - r.execute + a_api.response_api.send_not_found (Void, req, res) end else create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api) @@ -199,7 +197,6 @@ feature -- Hook -- List of block names, managed by current object. local res: ARRAYED_LIST [like {CMS_BLOCK}.name] - utf_conv: UTF_CONVERTER do if attached feed_aggregator_api as l_feed_api and then @@ -209,7 +206,7 @@ feature -- Hook across l_aggs as ic loop - res.force ("?feed." + utf_conv.utf_32_string_to_utf_8_string_8 (ic.item)) + res.force ("?feed." + utf_8_encoded (ic.item)) end else create res.make (0) diff --git a/modules/files/cms_files_module.e b/modules/files/cms_files_module.e index 98df481..129ce7d 100644 --- a/modules/files/cms_files_module.e +++ b/modules/files/cms_files_module.e @@ -140,8 +140,8 @@ feature -- Handler do check req.is_get_request_method end if not api.has_permission (browse_files_permission) then - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.add_error_message ("You are not allowed to browse CMS files!") + create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make_with_permissions (req, res, api, <>) + r.add_error_message ("You are not allowed to browse files!") elseif attached {WSF_STRING} req.path_parameter ("filename") as p_filename then create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) @@ -276,7 +276,7 @@ feature -- Handler body.append ("
") body.append ("
%N") - body.append ("Use basic file uploading.%N") + body.append ("Use basic file uploading.%N") end body.append ("
") end @@ -284,15 +284,15 @@ feature -- Handler if req.is_get_head_request_method then -- Build the response. if r.has_permission (browse_files_permission) then - body.append ("
") + body.append ("
") append_uploaded_file_album_to (req, api, body) else r.add_warning_message ("You are not allowed to browse files!") end end - r.set_main_content (body) + r.execute elseif req.is_post_request_method then if api.has_permission (upload_files_permission) then create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) @@ -305,14 +305,13 @@ feature -- Handler r.set_redirection (r.url (uploads_location, Void)) end r.set_main_content (body) + r.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("You are not allowed to upload file!") + api.response_api.send_permissions_access_denied ("You are not allowed to upload file!", <>, req, res) end else - create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) + api.response_api.send_bad_request (Void, req, res) end - r.execute end process_uploaded_files (req: WSF_REQUEST; api: CMS_API; a_output: STRING) @@ -472,7 +471,7 @@ feature -- Handler do if attached files_api as l_files_api then if not api.has_permission (admin_files_permission) then - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make_with_permissions (req, res, api, <>) r.add_error_message ("You are not allowed to remove file!") elseif attached {WSF_STRING} req.path_parameter ("filename") as p_filename then create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) diff --git a/modules/files/cms_uploaded_file.e b/modules/files/cms_uploaded_file.e index ccc77ab..48a1e8c 100644 --- a/modules/files/cms_uploaded_file.e +++ b/modules/files/cms_uploaded_file.e @@ -83,14 +83,16 @@ feature -- Element change -- sets `a_number' after the name. This is done when the file was already uploaded local position: INTEGER_32 - new_name: STRING_8 + new_name: STRING_32 + l_uploaded_file_string_representation: READABLE_STRING_32 do - position := uploaded_file.string_representation.index_of ('.', 1) + l_uploaded_file_string_representation := uploaded_file.string_representation + position := l_uploaded_file_string_representation.index_of ('.', 1) create new_name.make_empty - new_name := uploaded_file.string_representation.head (position-1) - new_name.append ("_(" + a_number.out + ")") - new_name.append (uploaded_file.string_representation.substring (position, uploaded_file.string_representation.count)) + new_name := l_uploaded_file_string_representation.head (position-1) + new_name.append_string_general ("_(" + a_number.out + ")") + new_name.append (l_uploaded_file_string_representation.substring (position, l_uploaded_file_string_representation.count)) location := uploads_directory.extended (new_name) end diff --git a/modules/google_search_20/src/google_custom_search_module_20.e b/modules/google_search_20/src/google_custom_search_module_20.e index cfa2e8a..9a9f38b 100644 --- a/modules/google_search_20/src/google_custom_search_module_20.e +++ b/modules/google_search_20/src/google_custom_search_module_20.e @@ -57,15 +57,13 @@ feature -- GCSE Keys gcse_cx_key (api: CMS_API): detachable READABLE_STRING_8 -- Get google custom search engine id. - local - utf: UTF_CONVERTER do if attached api.module_configuration (Current, Void) as cfg then if attached cfg.text_item ("gcse.search_engine_id") as l_gcse_cx_key and then not l_gcse_cx_key.is_empty then - Result := utf.utf_32_string_to_utf_8_string_8 (l_gcse_cx_key) + Result := api.utf_8_encoded (l_gcse_cx_key) end end end diff --git a/modules/messaging/src/cms_messaging_module.e b/modules/messaging/src/cms_messaging_module.e index b0f589d..da5f855 100644 --- a/modules/messaging/src/cms_messaging_module.e +++ b/modules/messaging/src/cms_messaging_module.e @@ -223,12 +223,12 @@ $(document).ready(function() { local r: CMS_RESPONSE do - if api.has_permission ("use messaging") or api.has_permission ("message any user") then + if api.has_permissions (<<"use messaging", "message any user">>) then create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) r.values.force ("messaging", "messaging") r.set_main_content (new_html_messaging_form (r, api)) else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make_with_permissions (req, res, api, <<"use messaging", "message any user">>) end r.execute end @@ -314,7 +314,7 @@ $(document).ready(function() { end r.set_main_content (s) else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make_with_permissions (req, res, api, <<"message any user">>) end r.execute end @@ -337,9 +337,8 @@ feature {NONE} -- Contact Message resolved_template_text (api: CMS_API; a_text: READABLE_STRING_GENERAL; a_target_user: detachable CMS_USER): STRING_8 local smt: CMS_SMARTY_TEMPLATE_TEXT - utf: UTF_CONVERTER do - create smt.make (utf.utf_32_string_to_utf_8_string_8 (a_text)) + create smt.make (api.utf_8_encoded (a_text)) across api.builtin_variables as vars_ic loop diff --git a/modules/node/cms_node_module.e b/modules/node/cms_node_module.e index a0d2ba7..3484cb2 100644 --- a/modules/node/cms_node_module.e +++ b/modules/node/cms_node_module.e @@ -372,7 +372,7 @@ feature -- Hooks loop if attached ic.item.typename as l_typename and then - across l_node_typenames as t_ic some t_ic.item.same_string (l_typename) end + 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 diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 27398e1..cfd22a4 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -142,8 +142,8 @@ feature -- Forms ... ti.set_description ("Optionally specify an alternative URL path by which this content can be accessed.
%NFor example, type 'about' when writing an about page. Use a relative path or the URL alias won't work.") end - ti.set_text_value (l_uri) - ti.set_placeholder (l_auto_path_alias) + ti.set_text_value (l_uri.to_string_32) + ti.set_placeholder (l_auto_path_alias.to_string_32) ti.set_validation_action (agent (fd: WSF_FORM_DATA; ia_response: NODE_RESPONSE; ia_node: detachable CMS_NODE) do if @@ -204,7 +204,7 @@ feature -- Forms ... end -- Auto path alias / suggestion create thi.make ("auto_path_alias") - thi.set_text_value (l_auto_path_alias) + thi.set_text_value (l_auto_path_alias.to_string_32) thi.set_is_readonly (True) f.insert_before (thi, w) end diff --git a/modules/node/handler/node_form_response.e b/modules/node/handler/node_form_response.e index 331da77..e4da68e 100644 --- a/modules/node/handler/node_form_response.e +++ b/modules/node/handler/node_form_response.e @@ -241,7 +241,11 @@ feature -- Form if attached fd.string_item ("content") as l_content then b.append ("Content:
") if l_format /= Void then - b.append (l_format.formatted_output (l_content)) + if l_content.is_valid_as_string_8 then + b.append (l_format.formatted_output (l_content.to_string_8)) + else + b.append (l_format.formatted_output (api.utf_8_encoded (l_content))) + end else b.append (html_encoded (l_content)) end diff --git a/modules/node/handler/node_handler.e b/modules/node/handler/node_handler.e index 47ebd16..6b0cf4b 100644 --- a/modules/node/handler/node_handler.e +++ b/modules/node/handler/node_handler.e @@ -75,6 +75,14 @@ feature -- Query end end +feature -- Permissions + + view_unpublished_permissions (a_node: CMS_NODE): ITERABLE [READABLE_STRING_8] + -- Permissions to view unpublished node `a_node`. + do + Result := <<"view unpublished " + a_node.content_type>> + end + feature -- HTTP Methods do_get (req: WSF_REQUEST; res: WSF_RESPONSE) @@ -148,7 +156,7 @@ feature -- HTTP Methods attached api.user as l_user and then ( node_api.is_author_of_node (l_user, l_node) or else ( - api.user_has_permission (l_user, "view unpublished " + l_node.content_type) + api.user_has_permissions (l_user, view_unpublished_permissions (l_node)) ) ) then @@ -403,15 +411,10 @@ feature -- Error send_access_denied_to_unpublished_node (req: WSF_REQUEST; res: WSF_RESPONSE; a_node: CMS_NODE) -- Forbidden response. - local - r: CMS_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("This content is NOT published!") - r.execute + send_custom_access_denied ("This content is NOT published!", view_unpublished_permissions (a_node), req, res) end - feature {NONE} -- Node create_new_node (req: WSF_REQUEST; res: WSF_RESPONSE) diff --git a/modules/node/handler/trash_handler.e b/modules/node/handler/trash_handler.e index e032d3a..9df0e29 100644 --- a/modules/node/handler/trash_handler.e +++ b/modules/node/handler/trash_handler.e @@ -86,8 +86,7 @@ feature -- HTTP Methods -- l_page.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet fully implemented
", Void), "highlighted") l_page.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} l_page.make (req, res, api) - l_page.execute + send_custom_access_denied (Void, <<"view trash", "view any trash", "view own trash">>, req, res) end end diff --git a/modules/oauth20/cms_oauth_20_api.e b/modules/oauth20/cms_oauth_20_api.e index cb5ef6a..d4a2669 100644 --- a/modules/oauth20/cms_oauth_20_api.e +++ b/modules/oauth20/cms_oauth_20_api.e @@ -83,13 +83,13 @@ feature -- Access: Consumers OAuth20 Result := oauth_20_storage.oauth2_consumers end - oauth_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by name `a_name', if any. do Result := oauth_20_storage.oauth_consumer_by_name (a_name) end - oauth_consumer_by_callback (a_callback: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_callback (a_callback: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by callback `a_callback', if any. do Result := oauth_20_storage.oauth_consumer_by_callback (a_callback) @@ -97,7 +97,12 @@ feature -- Access: Consumers OAuth20 feature -- Change: User OAuth20 - new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer: READABLE_STRING_GENERAL) + save_oauth_consumer (a_cons: CMS_OAUTH_20_CONSUMER) + do + oauth_20_storage.save_oauth_consumer (a_cons) + end + + new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer: READABLE_STRING_GENERAL) -- Add a new user with oauth20 using the consumer `a_consumer'. require has_id: a_user.has_id @@ -105,8 +110,7 @@ feature -- Change: User OAuth20 oauth_20_storage.new_user_oauth2 (a_token, a_user_profile, a_user, a_consumer) end - - update_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) + update_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) -- Update user `a_user' with oauth2 for the consumer `a_consumer'. require has_id: a_user.has_id @@ -114,7 +118,6 @@ feature -- Change: User OAuth20 oauth_20_storage.update_user_oauth2 (a_token, a_user_profile, a_user, a_consumer_table) end - remove_user_oauth2 (a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) -- Remove user `a_user' with oauth2 for the consumer `a_consumer'. require diff --git a/modules/oauth20/cms_oauth_20_consumer.e b/modules/oauth20/cms_oauth_20_consumer.e index 1e14806..b297194 100644 --- a/modules/oauth20/cms_oauth_20_consumer.e +++ b/modules/oauth20/cms_oauth_20_consumer.e @@ -38,8 +38,18 @@ feature {NONE} -- Initialization set_name ("") end +feature -- Status report + + has_id: BOOLEAN + do + Result := id > 0 + end + feature -- Access + id: INTEGER_64 + -- unique identifier. + endpoint: READABLE_STRING_8 -- Url that receives the access token request. @@ -68,9 +78,6 @@ feature -- Access name: READABLE_STRING_32 -- consumer name. - id: INTEGER_64 - -- unique identifier. - feature -- Element change set_extractor (a_extractor: like extractor) diff --git a/modules/oauth20/cms_oauth_20_module.e b/modules/oauth20/cms_oauth_20_module.e index 2ea9610..8bd65af 100644 --- a/modules/oauth20/cms_oauth_20_module.e +++ b/modules/oauth20/cms_oauth_20_module.e @@ -21,6 +21,8 @@ inherit oauth20_api end + CMS_ADMINISTRABLE + CMS_HOOK_BLOCK SHARED_EXECUTION_ENVIRONMENT @@ -50,6 +52,13 @@ feature -- Access name: STRING = "oauth20" +feature {CMS_EXECUTION} -- Administration + + administration: CMS_OAUTH_20_MODULE_ADMINISTRATION + do + create Result.make (Current) + end + feature {CMS_API} -- Module Initialization initialize (a_api: CMS_API) @@ -130,7 +139,7 @@ feature {CMS_API} -- Module management end end -feature {CMS_API} -- Access: API +feature {CMS_API, CMS_MODULE_ADMINISTRATION} -- Access: API oauth20_api: detachable CMS_OAUTH_20_API -- @@ -280,7 +289,7 @@ feature -- Hooks attached {WSF_STRING} req.cookie (a_oauth20_api.session_token) as l_cookie_token then -- Logout OAuth - create l_cookie.make (a_oauth20_api.session_token, l_cookie_token.value) + create l_cookie.make (a_oauth20_api.session_token, l_cookie_token.url_encoded_value) l_cookie.set_path ("/") l_cookie.set_max_age (-1) res.add_cookie (l_cookie) @@ -386,7 +395,8 @@ feature -- OAuth2 Login with Provider l_cookie: WSF_COOKIE es: CMS_AUTHENTICATION_EMAIL_SERVICE do - if attached {WSF_STRING} req.path_parameter (oauth_callback_path_parameter) as l_callback and then + if + attached {WSF_STRING} req.path_parameter (oauth_callback_path_parameter) as l_callback and then attached {CMS_OAUTH_20_CONSUMER} a_oauth_api.oauth_consumer_by_callback (l_callback.value) as l_consumer and then attached {WSF_STRING} req.query_parameter (oauth_code_query_parameter) as l_code then @@ -411,7 +421,7 @@ feature -- OAuth2 Login with Provider a_oauth_api.update_user_oauth2 (l_access_token.token, l_user_profile, p_user, l_consumer.name ) else -- create a oauth entry - a_oauth_api.new_user_oauth2 (l_access_token.token, l_user_profile, p_user, l_consumer.name ) + a_oauth_api.new_user_oauth2 (l_access_token.token, l_user_profile.to_string_32, p_user, l_consumer.name ) end create l_cookie.make (a_oauth_api.session_token, l_access_token.token) l_cookie.set_max_age (l_access_token.expires_in) @@ -468,7 +478,7 @@ feature -- OAuth2 Login with Provider attached {WSF_STRING} req.form_parameter ("email") as l_email and then attached r.user as l_user then - l_user.set_email (l_email.value) + l_user.set_email (api.utf_8_encoded (l_email.value)) a_oauth_api.new_user_oauth2 ("none", "none", l_user, l_consumer.value ) -- TODO send email? end diff --git a/modules/oauth20/cms_oauth_20_module_administration.e b/modules/oauth20/cms_oauth_20_module_administration.e new file mode 100644 index 0000000..1e1fd67 --- /dev/null +++ b/modules/oauth20/cms_oauth_20_module_administration.e @@ -0,0 +1,178 @@ +note + description: "Summary description for {CMS_OAUTH_20_MODULE_ADMINISTRATION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_OAUTH_20_MODULE_ADMINISTRATION + +inherit + CMS_MODULE_ADMINISTRATION [CMS_OAUTH_20_MODULE] + redefine + setup_hooks, + permissions + end + + CMS_HOOK_MENU_SYSTEM_ALTER + +create + make + +feature -- Access + + permissions: LIST [READABLE_STRING_8] + -- List of permission ids, used by this module, and declared. + do + Result := Precursor + end + +feature {NONE} -- Router/administration + + setup_administration_router (a_router: WSF_ROUTER; a_api: CMS_API) + do + a_router.handle ("/oauth20/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_admin_consumers (a_api, ?, ?)), a_router.methods_head_get_post) + a_router.handle ("/oauth20/{consumer}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_admin_consumer (a_api, ?, ?)), a_router.methods_head_get_post) + end + +feature -- Handle + + handle_admin_consumers (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + s: STRING + do + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api) + create s.make_empty + s.append ("

Consumers

") + if attached module.oauth20_api as l_oauth20_api then + s.append ("") + end + r.set_main_content (s) + r.execute + end + + handle_admin_consumer (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + s: STRING + f: CMS_FORM + fset: WSF_FORM_FIELD_SET + tf: WSF_FORM_TEXT_INPUT + l_is_protect_predefined_fields: BOOLEAN + do + if attached {WSF_STRING} req.path_parameter ("consumer") as p_consumer then + if + attached module.oauth20_api as l_oauth20_api and then + attached l_oauth20_api.oauth_consumer_by_name (p_consumer.value) as cons + then + l_is_protect_predefined_fields := cons.has_id + + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api) + r.add_to_primary_tabs (a_api.administration_link ("Consumers", "oauth20/")) + create s.make_empty + s.append ("

Consumer %"" + a_api.html_encoded (cons.name) + "%"

") + create f.make (req.percent_encoded_path_info, "consumer") + f.set_method_post + create tf.make_with_text ("name", cons.name) + tf.set_label ("Name"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + f.extend (tf) + + create fset.make + fset.set_legend ("Enter expected data") + f.extend (fset) + create tf.make_with_text ("api_key", cons.api_key) + tf.set_label ("API key"); tf.set_size (70) + fset.extend (tf) + create tf.make_with_text ("api_secret", cons.api_secret) + tf.set_label ("API secret") + fset.extend (tf); tf.set_size (70) + + fset.extend (create {WSF_FORM_SUBMIT_INPUT}.make_with_text ("op", "Submit")) + + create fset.make + fset.set_legend ("Predefine settings (change with care)") + f.extend (fset) + + create tf.make_with_text ("authorize_url", cons.authorize_url) + tf.set_label ("Authorize URL"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + fset.extend (tf) + create tf.make_with_text ("callback_name", cons.callback_name) + tf.set_label ("Callback Name"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + fset.extend (tf) + create tf.make_with_text ("endpoint", cons.endpoint) + tf.set_label ("Endpoint"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + fset.extend (tf) + create tf.make_with_text ("extractor", cons.extractor) + tf.set_label ("Extractor"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + fset.extend (tf) + create tf.make_with_text ("protected_resource_url", cons.protected_resource_url) + tf.set_label ("Protected Resource URL"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + fset.extend (tf) + create tf.make_with_text ("scope", cons.scope) + tf.set_label ("Scope"); tf.set_is_readonly (l_is_protect_predefined_fields); tf.set_size (70) + fset.extend (tf) + + + if req.is_get_head_request_method then + f.append_to_html (r.wsf_theme, s) + else + f.submit_actions.extend (agent (fd: WSF_FORM_DATA; i_cons: CMS_OAUTH_20_CONSUMER; i_oauth20_api: CMS_OAUTH_20_API; l_output: STRING) + do + if + attached fd.string_item ("api_key") as l_api_key and then + attached fd.string_item ("api_secret") as l_api_secret + then + i_cons.set_api_key (l_api_key) + i_cons.set_api_secret (l_api_secret) + i_oauth20_api.save_oauth_consumer (i_cons) + l_output.append ("

Consumer saved...

") + end + end(?, cons, l_oauth20_api, s) + ); + f.process (r) + f.append_to_html (r.wsf_theme, s) + end + r.set_main_content (s) + else + create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, a_api) + end + else + create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, a_api) + end + r.execute + end + + +feature -- Hook + + setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) + -- Module hooks configuration. + do + a_hooks.subscribe_to_menu_system_alter_hook (Current) + end + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + -- Hook execution on collection of menu contained by `a_menu_system' + -- for related response `a_response'. + do + if a_response.is_authenticated then + a_menu_system.navigation_menu.extend (create {CMS_LOCAL_LINK}.make ("OAuth20", a_response.api.administration_path_location ("oauth20/"))) +-- if a_response.has_permission (permission__manage_feed_aggregator) then +-- a_menu_system.management_menu.extend_into (a_response.api.administration_link ("Feeds (admin)", "feed_aggregator/"), "Admin", "admin") +-- end + end + end + + +end diff --git a/modules/oauth20/cms_oauth_20_workflow.e b/modules/oauth20/cms_oauth_20_workflow.e index 039020c..209e8d7 100644 --- a/modules/oauth20/cms_oauth_20_workflow.e +++ b/modules/oauth20/cms_oauth_20_workflow.e @@ -38,15 +38,14 @@ feature {NONE} -- Initialization feature -- Access - authorization_url: detachable READABLE_STRING_32 + authorization_url: detachable READABLE_STRING_8 -- Obtain the Authorization URL. do -- Obtain the Authorization URL write_debug_log (generator + ".authorization_url Fetching the Authorization URL..!") if attached api_service.authorization_url (empty_token) as l_authorization_url then - write_debug_log (generator + ".authorization_url: Got the Authorization URL!") write_debug_log (generator + ".authorization_url:" + l_authorization_url) - Result := l_authorization_url.as_string_32 + Result := l_authorization_url end end @@ -77,8 +76,8 @@ feature -- Access end end - user_email: detachable READABLE_STRING_32 - -- Retrieve user email if any. + user_email: detachable READABLE_STRING_8 + -- User email if any. local l_json: JSON_CONFIG do @@ -91,7 +90,7 @@ feature -- Access then Result := l_email.item elseif attached {JSON_STRING} l_json.item ("email") as l_email then - Result := l_email.unescaped_string_32 + Result := l_email.unescaped_string_8 end end end @@ -101,7 +100,7 @@ feature -- Access access_token: detachable OAUTH_TOKEN -- JSON representing the access token. - user_profile: detachable READABLE_STRING_32 + user_profile: detachable READABLE_STRING_8 -- JSON representing the user profiles. feature {NONE} -- Implementation diff --git a/modules/oauth20/persistence/cms_oauth_20_storage_i.e b/modules/oauth20/persistence/cms_oauth_20_storage_i.e index bd16eb2..6950a76 100644 --- a/modules/oauth20/persistence/cms_oauth_20_storage_i.e +++ b/modules/oauth20/persistence/cms_oauth_20_storage_i.e @@ -46,24 +46,29 @@ feature -- Access: Consumers deferred end - oauth_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by name `a_name', if any. deferred end - oauth_consumer_by_callback (a_callback: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_callback (a_callback: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by callback `a_callback', if any. deferred end feature -- Change: User Oauth2 - new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) + save_oauth_consumer (a_cons: CMS_OAUTH_20_CONSUMER) + -- Save consumer `a_cons`. + deferred + end + + new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) -- Add a new user with oauth2 authentication. deferred end - update_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL ) + update_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL ) -- Update user `a_user' with oauth2 authentication. deferred end diff --git a/modules/oauth20/persistence/cms_oauth_20_storage_null.e b/modules/oauth20/persistence/cms_oauth_20_storage_null.e index 8ddef02..3628206 100644 --- a/modules/oauth20/persistence/cms_oauth_20_storage_null.e +++ b/modules/oauth20/persistence/cms_oauth_20_storage_null.e @@ -37,7 +37,7 @@ feature -- Access: Users do end - user_oauth2_without_consumer_by_token (a_token: READABLE_STRING_GENERAL ): detachable CMS_USER + user_oauth2_without_consumer_by_token (a_token: READABLE_STRING_GENERAL): detachable CMS_USER do end @@ -48,24 +48,28 @@ feature -- Access: Consumers create {ARRAYED_LIST [STRING]} Result.make (0) end - oauth_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by name `a_name', if any. do end - oauth_consumer_by_callback (a_callback: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_callback (a_callback: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by callback `a_callback', if any. do end feature -- Change: User Oauth2 - new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) + save_oauth_consumer (a_cons: CMS_OAUTH_20_CONSUMER) + do + end + + new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL) -- Add a new user with oauth2 authentication. do end - update_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL ) + update_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer_table: READABLE_STRING_GENERAL ) -- Update user `a_user' with oauth2 authentication. do end diff --git a/modules/oauth20/persistence/cms_oauth_20_storage_sql.e b/modules/oauth20/persistence/cms_oauth_20_storage_sql.e index f7fbfe0..3bcc7c9 100644 --- a/modules/oauth20/persistence/cms_oauth_20_storage_sql.e +++ b/modules/oauth20/persistence/cms_oauth_20_storage_sql.e @@ -148,7 +148,7 @@ feature --Access: Consumers sql_finalize end - oauth_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by name `a_name', if any. local l_parameters: STRING_TABLE [detachable ANY] @@ -169,7 +169,7 @@ feature --Access: Consumers sql_finalize end - oauth_consumer_by_callback (a_callback: READABLE_STRING_8): detachable CMS_OAUTH_20_CONSUMER + oauth_consumer_by_callback (a_callback: READABLE_STRING_GENERAL): detachable CMS_OAUTH_20_CONSUMER -- Retrieve a consumer by callback `a_callback', if any. local l_parameters: STRING_TABLE [detachable ANY] @@ -192,7 +192,37 @@ feature --Access: Consumers feature -- Change: User OAuth - new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_32; a_user: CMS_USER; a_consumer: READABLE_STRING_GENERAL) + save_oauth_consumer (a_cons: CMS_OAUTH_20_CONSUMER) + -- Save consumer `a_cons`. + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + if a_cons.has_id then + create l_parameters.make (10) + l_parameters.put (a_cons.id, "cid") + else + create l_parameters.make (9) + end + l_parameters.put (a_cons.name, "name") + l_parameters.put (a_cons.api_secret, "api_secret") + l_parameters.put (a_cons.api_key, "api_key") + l_parameters.put (a_cons.scope, "scope") + l_parameters.put (a_cons.protected_resource_url, "protected_resource_url") + l_parameters.put (a_cons.callback_name, "callback_name") + l_parameters.put (a_cons.extractor, "extractor") + l_parameters.put (a_cons.authorize_url, "authorize_url") + l_parameters.put (a_cons.endpoint, "endpoint") + + if a_cons.has_id then + sql_modify (sql_update_oauth2_consumers, l_parameters) + else + sql_insert (sql_insert_oauth2_consumers, l_parameters) + end + sql_finalize + end + + new_user_oauth2 (a_token: READABLE_STRING_GENERAL; a_user_profile: READABLE_STRING_GENERAL; a_user: CMS_USER; a_consumer: READABLE_STRING_GENERAL) -- Add a new user with oauth2 authentication. -- . local @@ -210,7 +240,6 @@ feature -- Change: User OAuth l_parameters.put (create {DATE_TIME}.make_now_utc, "utc_date") l_parameters.put (a_user.email, "email") - create l_string.make_from_string (sql_insert_oauth2_template) l_string.replace_substring_all ("$table_name", oauth2_sql_table_name (a_consumer)) sql_insert (l_string, l_parameters) @@ -356,4 +385,8 @@ feature {NONE} -- Consumer Sql_oauth_consumer_name: STRING = "SELECT * FROM oauth2_consumers where name =:name;" + sql_insert_oauth2_consumers: STRING = "INSERT INTO oauth2_consumers (name, api_secret, api_key, scope, protected_resource_url, callback_name, extractor, authorize_url, endpoint) VALUES (:name, :api_secret, :api_key, :scope, :protected_resource_url, :callback_name, :extractor, :authorize_url, :endpoint);" + + sql_update_oauth2_consumers: STRING = "UPDATE oauth2_consumers SET name = :name, api_secret = :api_secret, api_key = :api_key, scope = :scope, protected_resource_url = :protected_resource_url, callback_name = :callback_name, extractor = :extractor, authorize_url = :authorize_url, endpoint = :endpoint WHERE cid = :cid;" + end diff --git a/modules/oauth20/site/templates/block_login.tpl b/modules/oauth20/site/templates/block_login.tpl index 44c7bd4..3f7fc6b 100644 --- a/modules/oauth20/site/templates/block_login.tpl +++ b/modules/oauth20/site/templates/block_login.tpl @@ -1,7 +1,7 @@
{foreach item="item" from="$oauth_consumers"} - Login with {$item/}
+ Login with {$item/}
{/foreach}
diff --git a/modules/openid/cms_openid_api.e b/modules/openid/cms_openid_api.e index d0543fd..0023b6b 100644 --- a/modules/openid/cms_openid_api.e +++ b/modules/openid/cms_openid_api.e @@ -79,7 +79,7 @@ feature -- Access: Consumers OAuth20 Result := openid_storage.openid_consumers end - openid_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OPENID_CONSUMER + openid_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OPENID_CONSUMER -- Retrieve a consumer by name `a_name', if any. do Result := openid_storage.openid_consumer_by_name (a_name) diff --git a/modules/openid/cms_openid_module.e b/modules/openid/cms_openid_module.e index 211607a..05cba2b 100644 --- a/modules/openid/cms_openid_module.e +++ b/modules/openid/cms_openid_module.e @@ -226,7 +226,7 @@ feature -- Hooks create o.make (req.absolute_script_url ("/account/auth/login-with-openid")) o.ask_email (True) o.ask_all_info (False) - if attached o.auth_url (p_openid) as l_url then + if p_openid.is_valid_as_string_8 and then attached o.auth_url (p_openid.to_string_8) as l_url then r.set_redirection (l_url) else s.append (" Failure") @@ -248,7 +248,7 @@ feature -- Hooks attached {WSF_STRING} req.cookie (a_openid_api.session_token) as l_cookie_token then -- Logout OAuth - create l_cookie.make (a_openid_api.session_token, l_cookie_token.value) + create l_cookie.make (a_openid_api.session_token, l_cookie_token.url_encoded_value) l_cookie.set_path ("/") l_cookie.set_max_age (-1) res.add_cookie (l_cookie) @@ -335,6 +335,7 @@ feature -- Openid Login b: STRING o: OPENID_CONSUMER v: OPENID_CONSUMER_VALIDATION + l_email: STRING_8 do create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create b.make_empty @@ -346,8 +347,9 @@ feature -- Openid Login v.validate if v.is_valid then if attached v.identity as l_identity and then - attached v.email_attribute as l_email + attached v.email_attribute as l_email_attrib then + l_email := api.utf_8_encoded (l_email_attrib) l_user_api := api.user_api if attached l_user_api.user_by_email (l_email) as p_user then -- User with email exist @@ -355,7 +357,7 @@ feature -- Openid Login -- Update openid entry? else -- create a oauth entry - a_openid_api.new_user_openid (l_identity,p_user) + a_openid_api.new_user_openid (l_identity, p_user) end create l_cookie.make (a_openid_api.session_token, l_identity) l_cookie.set_max_age (a_openid_api.session_max_age) @@ -368,7 +370,7 @@ feature -- Openid Login l_roles.force (l_user_api.authenticated_user_role) -- Create a new user and oauth entry - create l_user.make (l_email) + create l_user.make (l_email_attrib) l_user.set_email (l_email) l_user.set_password (new_token) -- generate a random password. l_user.set_roles (l_roles) diff --git a/modules/openid/persitence/cms_openid_storage_i.e b/modules/openid/persitence/cms_openid_storage_i.e index bb0ae47..690e87b 100644 --- a/modules/openid/persitence/cms_openid_storage_i.e +++ b/modules/openid/persitence/cms_openid_storage_i.e @@ -37,7 +37,7 @@ feature -- Access: Consumers deferred end - openid_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OPENID_CONSUMER + openid_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OPENID_CONSUMER -- Retrieve a consumer by name `a_name', if any. deferred end @@ -49,6 +49,6 @@ feature -- Change: User Oauth2 deferred end - + end diff --git a/modules/openid/persitence/cms_openid_storage_null.e b/modules/openid/persitence/cms_openid_storage_null.e index bd552da..b822dba 100644 --- a/modules/openid/persitence/cms_openid_storage_null.e +++ b/modules/openid/persitence/cms_openid_storage_null.e @@ -39,7 +39,7 @@ feature -- Access: Consumers create {ARRAYED_LIST[STRING]}Result.make(0) end - openid_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OPENID_CONSUMER + openid_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OPENID_CONSUMER -- do end diff --git a/modules/openid/persitence/cms_openid_storage_sql.e b/modules/openid/persitence/cms_openid_storage_sql.e index 9239205..268f861 100644 --- a/modules/openid/persitence/cms_openid_storage_sql.e +++ b/modules/openid/persitence/cms_openid_storage_sql.e @@ -99,7 +99,7 @@ feature --Access: Consumers sql_finalize end - openid_consumer_by_name (a_name: READABLE_STRING_8): detachable CMS_OPENID_CONSUMER + openid_consumer_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_OPENID_CONSUMER -- Retrieve a consumer by name `a_name', if any. local l_parameters: STRING_TABLE [detachable ANY] diff --git a/modules/recent_changes/cms_recent_changes_module.e b/modules/recent_changes/cms_recent_changes_module.e index 0bc1a7d..e976dac 100644 --- a/modules/recent_changes/cms_recent_changes_module.e +++ b/modules/recent_changes/cms_recent_changes_module.e @@ -141,7 +141,7 @@ feature -- Hook create s.make_empty if attached ch.information as l_information then - s.append (l_information) + s.append_string_general (l_information) end if attached ch.summary as sum then if not s.is_empty then @@ -248,9 +248,9 @@ feature -- Handler l_size := 25 end - create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("view recent changes") then - l_user := r.user + if api.has_permission ("view recent changes") then + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + l_user := api.user create l_changes.make (l_size, l_until_date, l_filter_source) create l_content.make (1024) @@ -406,11 +406,10 @@ feature -- Handler create htdate.make_from_date_time (l_until_date) r.set_title ("Recent changes before " + htdate.string) end + r.execute else - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + api.response_api.send_permissions_access_denied (Void, <<"view recent changes">>, req, res) end - - r.execute end feature -- Hooks configuration diff --git a/modules/sitemap/cms_sitemap_module.e b/modules/sitemap/cms_sitemap_module.e index 2d4a3bc..23ad907 100644 --- a/modules/sitemap/cms_sitemap_module.e +++ b/modules/sitemap/cms_sitemap_module.e @@ -123,8 +123,7 @@ feature -- Handler mesg.set_payload (l_sitemap_xml) res.send (mesg) else - create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + api.response_api.send_not_found (Void, req, res) end end end diff --git a/modules/taxonomy/handler/taxonomy_handler.e b/modules/taxonomy/handler/taxonomy_handler.e index 444a1cb..a0e13a3 100644 --- a/modules/taxonomy/handler/taxonomy_handler.e +++ b/modules/taxonomy/handler/taxonomy_handler.e @@ -143,11 +143,11 @@ feature -- HTTP Methods s.append ("No entity found.") end l_page.set_main_content (s) + l_page.execute else -- Responding with `main_content_html (l_page)'. - create {NOT_FOUND_ERROR_CMS_RESPONSE} l_page.make (req, res, api) + send_not_found (req, res) end - l_page.execute else -- Responding with `main_content_html (l_page)'. create {BAD_REQUEST_ERROR_CMS_RESPONSE} l_page.make (req, res, api) diff --git a/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e b/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e index 9d9e281..ad765b7 100644 --- a/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e +++ b/modules/taxonomy/handler/taxonomy_vocabulary_admin_handler.e @@ -277,13 +277,13 @@ feature -- HTTP Methods l_typename := ic.item.name create w_cb.make_with_value ("typenames[]", api.html_encoded (l_typename)) - w_cb.set_title (ic.item.name) + w_cb.set_title (ic.item.name.to_string_32) wtb_row.set_item (create {WSF_WIDGET_TABLE_ITEM}.make_with_content (w_cb), 1) v := Void if l_typenames /= Void and then - across l_typenames as tn_ic some l_typename.is_case_insensitive_equal (tn_ic.item) end + across l_typenames as tn_ic some l_typename.is_case_insensitive_equal_general (tn_ic.item) end then w_cb.set_checked (True) if attached taxonomy_api.vocabularies_for_type (l_typename) as v_list then @@ -319,11 +319,11 @@ feature -- HTTP Methods create s.make_empty f.append_to_html (l_page.wsf_theme, s) l_page.set_main_content (s) + l_page.execute else -- Responding with `main_content_html (l_page)'. - create {NOT_FOUND_ERROR_CMS_RESPONSE} l_page.make (req, res, api) + send_not_found (req, res) end - l_page.execute end do_get_vocabularies (req: WSF_REQUEST; res: WSF_RESPONSE) diff --git a/modules/taxonomy/handler/taxonomy_vocabulary_handler.e b/modules/taxonomy/handler/taxonomy_vocabulary_handler.e index 6db90f4..41ac365 100644 --- a/modules/taxonomy/handler/taxonomy_vocabulary_handler.e +++ b/modules/taxonomy/handler/taxonomy_vocabulary_handler.e @@ -99,11 +99,11 @@ feature -- HTTP Methods end s.append ("") l_page.set_main_content (s) + l_page.execute else -- Responding with `main_content_html (l_page)'. - create {NOT_FOUND_ERROR_CMS_RESPONSE} l_page.make (req, res, api) + send_not_found (req, res) end - l_page.execute else -- Responding with `main_content_html (l_page)'. create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) diff --git a/src/configuration/cms_default_setup.e b/src/configuration/cms_default_setup.e index 3c502ac..8212b53 100644 --- a/src/configuration/cms_default_setup.e +++ b/src/configuration/cms_default_setup.e @@ -87,7 +87,7 @@ feature -- Access do if attached text_item (a_name) as s then if s.is_valid_as_string_8 then - Result := s.as_string_8 + Result := s.to_string_8 else Result := utf.escaped_utf_32_string_to_utf_8_string_8 (s) end @@ -101,10 +101,11 @@ feature -- Access l_chain: NOTIFICATION_CHAIN_MAILER l_storage_mailer: NOTIFICATION_STORAGE_MAILER l_mailer: detachable NOTIFICATION_MAILER + b: BOOLEAN do if not retried then - if attached text_item ("mailer.smtp") as l_smtp then - create {NOTIFICATION_SMTP_MAILER} l_mailer.make (l_smtp.as_string_8_conversion) + if attached text_item ("mailer.smtp") as l_smtp and then l_smtp.is_valid_as_string_8 then + create {NOTIFICATION_SMTP_MAILER} l_mailer.make (l_smtp.to_string_8) elseif attached text_item ("mailer.sendmail") as l_sendmail then create {NOTIFICATION_SENDMAIL_MAILER} l_mailer.make_with_location (l_sendmail) end @@ -120,19 +121,24 @@ feature -- Access if f.exists and then f.is_directory then create {NOTIFICATION_STORAGE_MAILER} l_storage_mailer.make (create {NOTIFICATION_EMAIL_DIRECTORY_STORAGE}.make (f.path)) else - if not f.exists then - f.create_read_write - f.close + if f.exists then + b := True + else + b := (create {CMS_FILE_SYSTEM_UTILITIES}).safe_create_raw_file (f.path) + end + if b then + create {NOTIFICATION_STORAGE_MAILER} l_storage_mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (f)) end - create {NOTIFICATION_STORAGE_MAILER} l_storage_mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (f)) end end if l_mailer /= Void then create l_chain.make (l_mailer) l_chain.set_next (l_storage_mailer) l_mailer := l_chain - else + elseif l_storage_mailer /= Void then l_mailer := l_storage_mailer + else + create {NOTIFICATION_NULL_MAILER} l_mailer end elseif l_mailer = Void then create {NOTIFICATION_STORAGE_MAILER} l_mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (io.error)) diff --git a/src/kernel/content/cms_encoders.e b/src/kernel/content/cms_encoders.e index 46aedd7..42d4433 100644 --- a/src/kernel/content/cms_encoders.e +++ b/src/kernel/content/cms_encoders.e @@ -21,6 +21,14 @@ inherit feature -- Encoders + utf_8_encoded (a_string: READABLE_STRING_GENERAL): STRING_8 + -- `a_string' encoded using UTF-8. + local + utf: UTF_CONVERTER + do + Result := utf.utf_32_string_to_utf_8_string_8 (a_string) + end + html_encoded (a_string: READABLE_STRING_GENERAL): STRING_8 -- `a_string' encoded for html output. do @@ -36,7 +44,7 @@ feature -- Encoders Result := "" end end - + url_encoded, percent_encoded (a_string: READABLE_STRING_GENERAL): STRING_8 -- `a_string' encoded with percent encoding, mainly used for url. @@ -45,6 +53,6 @@ feature -- Encoders end note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/persistence/cms_storage_null.e b/src/persistence/cms_storage_null.e index 2025986..31ec294 100644 --- a/src/persistence/cms_storage_null.e +++ b/src/persistence/cms_storage_null.e @@ -75,7 +75,7 @@ feature -- URL aliases do end - source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8 + source_of_path_alias (a_alias: READABLE_STRING_GENERAL): detachable READABLE_STRING_8 -- Source path for alias `a_alias'. do end @@ -136,6 +136,6 @@ feature -- Custom end note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/persistence/core/cms_core_storage_i.e b/src/persistence/core/cms_core_storage_i.e index b285e22..ba2006a 100644 --- a/src/persistence/core/cms_core_storage_i.e +++ b/src/persistence/core/cms_core_storage_i.e @@ -42,7 +42,7 @@ feature -- URL aliases deferred end - source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8 + source_of_path_alias (a_alias: READABLE_STRING_GENERAL): detachable READABLE_STRING_8 -- Source path for alias `a_alias'. deferred end @@ -89,6 +89,6 @@ feature -- Misc end note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/persistence/core/cms_core_storage_sql_i.e b/src/persistence/core/cms_core_storage_sql_i.e index 7f96523..87474c8 100644 --- a/src/persistence/core/cms_core_storage_sql_i.e +++ b/src/persistence/core/cms_core_storage_sql_i.e @@ -123,7 +123,7 @@ feature -- URL aliases sql_finalize end - source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8 + source_of_path_alias (a_alias: READABLE_STRING_GENERAL): detachable READABLE_STRING_8 -- local l_parameters: STRING_TABLE [detachable ANY] diff --git a/src/service/cms_api.e b/src/service/cms_api.e index 78fcc64..4c6b215 100644 --- a/src/service/cms_api.e +++ b/src/service/cms_api.e @@ -642,7 +642,7 @@ feature -- Status Report feature -- Logging - logs (a_category: detachable READABLE_STRING_8; a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG] + logs (a_category: detachable READABLE_STRING_GENERAL; a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG] -- List of recent logs from `a_lower' to `a_lower+a_count'. -- If `a_category' is set, filter to return only associated logs. -- If `a_count' <= 0 then, return all logs. @@ -1001,6 +1001,19 @@ feature -- Access: API Result := l_api end + response_api: CMS_RESPONSE_API + -- API to send predefined cms responses. + local + l_api: like internal_response_api + do + l_api := internal_response_api + if l_api = Void then + create l_api.make (Current) + internal_response_api := l_api + end + Result := l_api + end + feature -- Hooks setup_core_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) @@ -1014,9 +1027,9 @@ feature -- Hooks feature -- Path aliases - is_valid_path_alias (a_alias: READABLE_STRING_8): BOOLEAN + is_valid_path_alias (a_alias: READABLE_STRING_GENERAL): BOOLEAN do - Result := a_alias.is_empty or else not a_alias.starts_with_general ("/") + Result := a_alias.is_empty or else not a_alias.starts_with ("/") end set_path_alias (a_source, a_alias: READABLE_STRING_8; a_keep_previous: BOOLEAN) @@ -1076,7 +1089,7 @@ feature -- Path aliases end end - source_of_path_alias (a_alias: READABLE_STRING_8): detachable READABLE_STRING_8 + source_of_path_alias (a_alias: READABLE_STRING_GENERAL): detachable READABLE_STRING_8 -- Resolved path for alias `a_alias'. --| the CMS supports aliases for path, and then this function simply returns --| the effective target path/url for this `a_alias'. @@ -1106,6 +1119,9 @@ feature {NONE}-- Implementation internal_user_api: detachable like user_api -- Cached value for `user_api`. + internal_response_api: detachable like response_api + -- Cached value for `response_api`. + feature -- Environment/ theme site_location: PATH diff --git a/src/service/cms_execution.e b/src/service/cms_execution.e index bcac24c..0173c5a 100644 --- a/src/service/cms_execution.e +++ b/src/service/cms_execution.e @@ -196,24 +196,24 @@ feature -- Settings: router local fhdl: WSF_FILE_SYSTEM_HANDLER themehdl: CMS_THEME_FILE_SYSTEM_HANDLER + l_not_found_handler_agent: PROCEDURE [READABLE_STRING_8, WSF_REQUEST, WSF_RESPONSE] do api.logger.put_information (generator + ".configure_api_file_handler", Void) - create themehdl.make (api) - themehdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE) + l_not_found_handler_agent := agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE) do execute_default (ia_req, ia_res) - end) + end + + create themehdl.make (api) + themehdl.set_not_found_handler (l_not_found_handler_agent) -- See CMS_API.api.theme_path_for (...) for the hardcoded "/theme/" path. a_router.handle ("/theme/{theme_id}{/vars}", themehdl, router.methods_GET) -- "/files/.." create fhdl.make_hidden_with_path (api.files_location) fhdl.disable_index - fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE) - do - execute_default (ia_req, ia_res) - end) + fhdl.set_not_found_handler (l_not_found_handler_agent) a_router.handle (api.files_path, fhdl, router.methods_GET) -- files folder from specific module. @@ -222,10 +222,7 @@ feature -- Settings: router -- www folder. Should we keep this?? create fhdl.make_hidden_with_path (setup.environment.www_path) fhdl.disable_index - fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE) - do - execute_default (ia_req, ia_res) - end) + fhdl.set_not_found_handler (l_not_found_handler_agent) a_router.handle ("/", fhdl, router.methods_GET) end @@ -328,7 +325,6 @@ feature -- Execution local ut: FILE_UTILITIES p: PATH - r: NOT_FOUND_ERROR_CMS_RESPONSE f: WSF_FILE_RESPONSE do p := api.theme_assets_location.extended ("favicon.ico") @@ -337,8 +333,7 @@ feature -- Execution f.set_expires_in_seconds (86_400) -- 24h = 60 sec * 60 min * 24 = 86 400 minutes res.send (f) else - create r.make (req, res, api) - r.execute + api.response_api.send_not_found (Void, req, res) end end @@ -347,7 +342,6 @@ feature -- Execution -- i.e: "/module/{modname}/files{/vars}" local fhdl: WSF_FILE_SYSTEM_HANDLER - r: NOT_FOUND_ERROR_CMS_RESPONSE do if attached {WSF_STRING} req.path_parameter ("modname") as l_mod_name then create fhdl.make_with_path (api.module_location_by_name (l_mod_name.url_encoded_value).extended ("files")) @@ -358,19 +352,15 @@ feature -- Execution end) fhdl.execute_starts_with ("/module/" + l_mod_name.url_encoded_value + "/files/", req, res) else - create r.make (req, res, api) - r.execute + api.response_api.send_not_found (Void, req, res) end end execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) -- Default request handler if no other are relevant - local - r: NOT_FOUND_ERROR_CMS_RESPONSE do to_implement ("Default response for CMS_SERVICE") - create r.make (req, res, api) - r.execute + api.response_api.send_not_found (Void, req, res) end note diff --git a/src/service/cms_file_system_utilities.e b/src/service/cms_file_system_utilities.e index 5ed222d..87492bf 100644 --- a/src/service/cms_file_system_utilities.e +++ b/src/service/cms_file_system_utilities.e @@ -6,7 +6,7 @@ note class CMS_FILE_SYSTEM_UTILITIES -feature -- Files +feature -- File path relative_path_inside (a_path: PATH; a_root_path: PATH): detachable PATH -- Relative path from `a_root_path` to `a_path`, or Void if `a_path` is not inside `a_root_path`. @@ -43,6 +43,8 @@ feature -- Files end end +feature -- Read + files_from_location (a_loc: PATH; is_recursive: BOOLEAN): detachable LIST [PATH] local d: DIRECTORY @@ -82,13 +84,14 @@ feature -- Files retry end +feature -- Read/Write + safe_copy_file (src,dst: PATH): BOOLEAN -- Copy file from `src` to `dst' -- and return True on success, False on failure. local retried: BOOLEAN f_src, f_dst: RAW_FILE - d: DIRECTORY do Result := False if retried then @@ -96,20 +99,45 @@ feature -- Files else create f_src.make_with_path (src) if f_src.exists and then f_src.is_access_readable then - if attached dst.parent as l_parent then - create d.make_with_path (l_parent) - if not d.exists then - d.recursive_create_dir + if safe_create_parent_directory (dst) then + create f_dst.make_with_path (dst) + if not f_dst.exists or else f_dst.is_access_writable then + f_src.open_read + f_dst.open_write + f_src.copy_to (f_dst) + f_dst.close + f_src.close + Result := True -- Succeed! end + else + Result := False -- No parent directory! end - create f_dst.make_with_path (dst) - if not f_dst.exists or else f_dst.is_access_writable then - f_src.open_read - f_dst.open_write - f_src.copy_to (f_dst) - f_dst.close - f_src.close - Result := True -- Succeed! + end + end + rescue + retried := True + retry + end + +feature -- Create + + safe_create_raw_file (p: PATH): BOOLEAN + -- Create file at `p` + -- and return True on success or if file already exists, False on failure. + local + retried: BOOLEAN + f: RAW_FILE + do + Result := False + if not retried then + if safe_create_parent_directory (p) then + create f.make_with_path (p) + if f.exists then + Result := True + else + f.create_read_write + f.close + Result := f.exists end end end @@ -118,6 +146,28 @@ feature -- Files retry end + safe_create_parent_directory (p: PATH): BOOLEAN + -- Create parent directory of `p` + -- and return True on success or if parent already exists, False on failure. + local + retried: BOOLEAN + d: DIRECTORY + do + Result := False + if not retried then + create d.make_with_path (p.parent) + if d.exists then + Result := True + else + d.recursive_create_dir + Result := d.exists + end + end + rescue + retried := True + retry + end + note copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/src/service/handler/cms_admin_install_handler.e b/src/service/handler/cms_admin_install_handler.e index 0eaf680..d065c8b 100644 --- a/src/service/handler/cms_admin_install_handler.e +++ b/src/service/handler/cms_admin_install_handler.e @@ -45,7 +45,10 @@ feature -- HTTP Methods lst: ARRAYED_LIST [CMS_MODULE] l_access: detachable READABLE_STRING_8 l_denied: BOOLEAN + l_is_fresh_installation: BOOLEAN do + l_is_fresh_installation := api.enabled_modules.count <= 1 --| Should have at least the required Core module! + --| FIXME: improve the installer. create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) l_access := api.setup.string_8_item ("admin.installation_access") @@ -62,8 +65,7 @@ feature -- HTTP Methods l_denied := True end if l_denied then - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.set_main_content ("You do not have permission to access CMS installation procedure!") + send_custom_access_denied ("You do not have permission to access CMS installation procedure!", Void, req, res) else create s.make_from_string ("

Modules

    ") create lst.make (1) @@ -107,9 +109,14 @@ feature -- HTTP Methods s.append ("
") s.append ("
Back to the " + r.link ("Administration", api.administration_path (Void), Void) + " ...
") r.set_main_content (s) + + if l_is_fresh_installation then + r.set_title (r.translation ("New installation ...", Void)) + else + r.set_title (r.translation ("Update installation ...", Void)) + end + r.execute end - r.set_title (r.translation ("CMS Installation ...", Void)) - r.execute end note diff --git a/src/service/handler/cms_handler.e b/src/service/handler/cms_handler.e index 789f87a..1a3a6ad 100644 --- a/src/service/handler/cms_handler.e +++ b/src/service/handler/cms_handler.e @@ -29,7 +29,7 @@ feature -- API Service api: CMS_API -feature -- Response helpers +feature -- Response message helpers redirect_to (a_location: READABLE_STRING_8; res: WSF_RESPONSE) -- Send via `res' a redirection message for location `a_location'. @@ -56,46 +56,39 @@ feature -- Response helpers res.send (create {CMS_FORBIDDEN_RESPONSE_MESSAGE}.make) end +feature -- Response helpers + send_access_denied (req: WSF_REQUEST; res: WSF_RESPONSE) -- Forbidden response. - local - r: CMS_RESPONSE do - create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + api.response_api.send_access_denied (Void, req, res) + end + + send_custom_access_denied (a_message: detachable READABLE_STRING_8; a_perms: detachable ITERABLE [READABLE_STRING_8]; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Forbidden response with custom message `a_message`. + do + api.response_api.send_permissions_access_denied (a_message, a_perms, req, res) end send_not_found (req: WSF_REQUEST; res: WSF_RESPONSE) -- Send via `res' a not found response. - local - r: CMS_RESPONSE do - create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + api.response_api.send_not_found (Void, req, res) end send_bad_request (req: WSF_REQUEST; res: WSF_RESPONSE) -- Send via `res' a bad request response. - local - r: CMS_RESPONSE do - create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) - r.execute + api.response_api.send_bad_request (Void, req, res) end send_not_implemented (a_message: detachable READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) -- Send via `res' a not implemented response. - local - r: CMS_RESPONSE do - create {NOT_IMPLEMENTED_ERROR_CMS_RESPONSE} r.make (req, res, api) - if a_message /= Void then - r.set_main_content (a_message) - end - r.execute + api.response_api.send_not_implemented (a_message, req, res) end note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/handler/cms_theme_file_system_handler.e b/src/service/handler/cms_theme_file_system_handler.e index f599ce1..ae077f6 100644 --- a/src/service/handler/cms_theme_file_system_handler.e +++ b/src/service/handler/cms_theme_file_system_handler.e @@ -28,7 +28,6 @@ feature -- Execution -- Execute `req' responding in `res'. local fhdl: WSF_FILE_SYSTEM_HANDLER - not_found: NOT_FOUND_ERROR_CMS_RESPONSE do if attached {WSF_STRING} req.path_parameter ("theme_id") as l_theme_id then create fhdl.make_hidden_with_path (api.theme_assets_location_for (l_theme_id.value)) @@ -39,8 +38,7 @@ feature -- Execution elseif attached not_found_handler as h then h.call (req.percent_encoded_path_info, req, res) else - create not_found.make (req, res, api) - not_found.execute + api.response_api.send_not_found (Void, req, res) end end diff --git a/src/service/response/cms_response.e b/src/service/response/cms_response.e index 1c7a3cc..79aac8b 100644 --- a/src/service/response/cms_response.e +++ b/src/service/response/cms_response.e @@ -460,7 +460,7 @@ feature -- Blocks initialization block_region_preference (a_block_id: READABLE_STRING_8; a_default_region: READABLE_STRING_8): READABLE_STRING_8 -- Region associated with `a_block_id' in configuration, if any. do - Result := setup.text_item_or_default ("blocks." + a_block_id + ".region", a_default_region).as_string_8_conversion + Result := setup.string_8_item_or_default ("blocks." + a_block_id + ".region", a_default_region) end feature -- Block management @@ -1119,9 +1119,14 @@ feature -- Generation add_to_primary_menu (lnk) api.hooks.invoke_menu_system_alter (menu_system, Current) - if api.enabled_modules.count = 1 then + if api.enabled_modules.count <= 1 then -- It is the required CMS_CORE_MODULE! - add_to_primary_menu (api.administration_link ("Install", "install")) + lnk := api.administration_link ("Install", "install") + if lnk.location.same_string (location) then + -- We are on the Install page! + else + add_to_primary_menu (lnk) + end end -- Blocks @@ -1454,7 +1459,6 @@ feature {NONE} -- Execution local cms_page: CMS_HTML_PAGE page: CMS_HTML_PAGE_RESPONSE - utf: UTF_CONVERTER h: HTTP_HEADER l_new_location: detachable READABLE_STRING_8 l_redirection_delay: like redirection_delay @@ -1473,7 +1477,7 @@ feature {NONE} -- Execution end if attached {READABLE_STRING_GENERAL} optional_content_type as l_type then - create cms_page.make_typed (utf.utf_32_string_to_utf_8_string_8 (l_type)) + create cms_page.make_typed (api.utf_8_encoded (l_type)) else create cms_page.make end diff --git a/src/service/response/cms_response_api.e b/src/service/response/cms_response_api.e new file mode 100644 index 0000000..29f0d93 --- /dev/null +++ b/src/service/response/cms_response_api.e @@ -0,0 +1,87 @@ +note + description: "[ + CMS Response API to send predefined CMS Response. + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_RESPONSE_API + +create + make + +feature {NONE} -- Initialization + + make (a_api: CMS_API) + do + cms_api := a_api + end + + cms_api: CMS_API + +feature -- Response helpers + + send_access_denied (a_message: detachable READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Forbidden response with custom message `a_message`. + local + r: FORBIDDEN_ERROR_CMS_RESPONSE + do + create r.make (req, res, cms_api) + impl_response_execute (r, a_message) + end + + send_permissions_access_denied (a_message: detachable READABLE_STRING_8; a_perms: detachable ITERABLE [READABLE_STRING_8]; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Forbidden response with custom message `a_message` and associated permissions `a_perms`. + local + r: FORBIDDEN_ERROR_CMS_RESPONSE + do + if a_perms = Void then + create r.make (req, res, cms_api) + else + create r.make_with_permissions (req, res, cms_api, a_perms) + end + impl_response_execute (r, a_message) + end + + send_not_found (a_message: detachable READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Send via `res' a not found response. + local + r: NOT_FOUND_ERROR_CMS_RESPONSE + do + create r.make (req, res, cms_api) + impl_response_execute (r, a_message) + end + + send_bad_request (a_message: detachable READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Send via `res' a bad request response. + local + r: BAD_REQUEST_ERROR_CMS_RESPONSE + do + create r.make (req, res, cms_api) + impl_response_execute (r, a_message) + end + + send_not_implemented (a_message: detachable READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Send via `res' a not implemented response. + local + r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE + do + create r.make (req, res, cms_api) + impl_response_execute (r, a_message) + end + +feature {NONE} -- Implementation + + impl_response_execute (a_response: CMS_RESPONSE; a_message: detachable READABLE_STRING_8) + do + if a_message /= Void then + a_response.set_main_content (a_message) + end + a_response.execute + end + +note + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/src/service/response/error/forbidden_error_cms_response.e b/src/service/response/error/forbidden_error_cms_response.e index 7009ace..7b74803 100644 --- a/src/service/response/error/forbidden_error_cms_response.e +++ b/src/service/response/error/forbidden_error_cms_response.e @@ -14,7 +14,16 @@ inherit end create - make + make, + make_with_permissions + +feature {NONE} -- Initialization + + make_with_permissions (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api; a_perms: ITERABLE [READABLE_STRING_8]) + do + make (req, res, a_api) + set_associated_permissions (a_perms) + end feature -- Generation @@ -26,17 +35,75 @@ feature -- Generation page.register_variable (status_code.out, "code") end +feature -- Access + + associated_permissions: detachable ARRAYED_LIST [READABLE_STRING_8] + +feature -- Basic operations + + set_associated_permissions (a_perms: ITERABLE [READABLE_STRING_8]) + local + lst: like associated_permissions + do + lst := associated_permissions + if lst = Void then + create lst.make (1) + associated_permissions := lst + end + across + a_perms as ic + loop + lst.extend (ic.item) + end + end + + set_associated_permission (a_perm: READABLE_STRING_8) + local + lst: like associated_permissions + do + lst := associated_permissions + if lst = Void then + create lst.make (1) + associated_permissions := lst + end + lst.extend (a_perm) + end + feature -- Execution process -- Computed response message. + local + s: STRING do set_title ("Forbidden") set_page_title ("Forbidden") - set_main_content ("Access denied for resource " + request.request_uri + ".") + s := "Access denied for resource " + request.request_uri + "." +-- TODO: add a form to ask for missing permissions. +-- if +-- attached user as u and +-- attached associated_permissions as l_permissions and then +-- not l_permissions.is_empty +-- then +-- -- User signed in +-- -- Form to request access to this resource. +-- s.append ("Request access ...") +-- s.append (": ") +-- across +-- l_permissions as ic +-- loop +-- s.append_character ('"') +-- s.append (ic.item) +-- s.append_character ('"') +-- s.append (" ") +-- end +-- end + + set_main_content (s) end + note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/user/cms_user_api.e b/src/service/user/cms_user_api.e index 76ca1dc..a8078d3 100644 --- a/src/service/user/cms_user_api.e +++ b/src/service/user/cms_user_api.e @@ -126,6 +126,17 @@ feature -- Access: user Result := storage.recent_users (params.offset.to_integer_32, params.size.to_integer_32) end + admin_user: detachable CMS_USER + -- Admin user if any. + do + if + attached user_by_id (1) as u and then + is_admin_user (u) + then + Result := u + end + end + feature -- Change User new_user (a_user: CMS_USER) diff --git a/src/theme/missing_theme/missing_cms_theme.e b/src/theme/missing_theme/missing_cms_theme.e index fa536c3..db1820c 100644 --- a/src/theme/missing_theme/missing_cms_theme.e +++ b/src/theme/missing_theme/missing_cms_theme.e @@ -47,7 +47,7 @@ feature -- Access page_html (page: CMS_HTML_PAGE): STRING_8 do to_implement ("Add a better response message, maybe using smarty template") - Result := "Service Unavailable" + Result := "Service Unavailable (missing theme!)" end note copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" diff --git a/src/theme/smarty_theme/smarty_cms_theme.e b/src/theme/smarty_theme/smarty_cms_theme.e index e16732c..7182b91 100644 --- a/src/theme/smarty_theme/smarty_cms_theme.e +++ b/src/theme/smarty_theme/smarty_cms_theme.e @@ -40,7 +40,6 @@ feature -- Access regions: ARRAY [STRING] local i: INTEGER - utf: UTF_CONVERTER l_regions: like internal_regions do l_regions := internal_regions @@ -51,7 +50,7 @@ feature -- Access across tb as ic loop - l_regions.force (utf.utf_32_string_to_utf_8_string_8 (ic.key), i) -- NOTE: UTF-8 encoded ! + l_regions.force (utf_8_encoded (ic.key), i) -- NOTE: UTF-8 encoded ! i := i + 1 end else diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf index 89f7ab9..b320050 100644 --- a/tests/all-safe.ecf +++ b/tests/all-safe.ecf @@ -1,5 +1,5 @@ - + Integration project including many lib