From 359344c9dd3b2d5dc6adf6776a8052b85a39080b Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 8 Jun 2017 22:16:12 +0200 Subject: [PATCH 1/2] Fixed link for Oauth sign with. Added administration pages for OAuth20 module. --- examples/demo/demo.ecf | 5 +- .../demo/launcher/any/application_launcher.e | 19 -- .../launcher/any/application_launcher_i.e | 127 ------------- .../launcher/default/application_launcher.e | 19 -- .../launcher/default/application_launcher_i.e | 26 --- .../modules/oauth20/templates/block_login.tpl | 2 +- modules/oauth20/cms_oauth_20_api.e | 15 +- modules/oauth20/cms_oauth_20_consumer.e | 13 +- modules/oauth20/cms_oauth_20_module.e | 20 +- .../cms_oauth_20_module_administration.e | 178 ++++++++++++++++++ modules/oauth20/cms_oauth_20_workflow.e | 13 +- modules/oauth20/oauth20-safe.ecf | 1 + .../persistence/cms_oauth_20_storage_i.e | 13 +- .../persistence/cms_oauth_20_storage_null.e | 14 +- .../persistence/cms_oauth_20_storage_sql.e | 41 +++- .../oauth20/site/templates/block_login.tpl | 2 +- 16 files changed, 277 insertions(+), 231 deletions(-) delete mode 100644 examples/demo/launcher/any/application_launcher.e delete mode 100644 examples/demo/launcher/any/application_launcher_i.e delete mode 100644 examples/demo/launcher/default/application_launcher.e delete mode 100644 examples/demo/launcher/default/application_launcher_i.e create mode 100644 modules/oauth20/cms_oauth_20_module_administration.e diff --git a/examples/demo/demo.ecf b/examples/demo/demo.ecf index ffc4e67..ebd52ed 100644 --- a/examples/demo/demo.ecf +++ b/examples/demo/demo.ecf @@ -20,7 +20,6 @@ - @@ -28,12 +27,10 @@ - - @@ -42,7 +39,7 @@ - + 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/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/oauth20-safe.ecf b/modules/oauth20/oauth20-safe.ecf index d20ea48..3d2eae8 100644 --- a/modules/oauth20/oauth20-safe.ecf +++ b/modules/oauth20/oauth20-safe.ecf @@ -25,6 +25,7 @@ + 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}
From 78ef7af5f8e0754a481cbda0148ed76837323ca0 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 9 Jun 2017 09:29:41 +0200 Subject: [PATCH 2/2] Removed obsolete calls, harmonized predefine response, added non admin user pages. When access is denied, also provide when possible and wanted, the needed permissions so that in the future, user will be able to ask for permission easily. Renamed previous user handlers as admin user handlers. Added non admin user handler /user/{uid} . Add new `send_...` response to `CMS_API.response_api`, and use them instead of `create {...RESPONSE}.... ; execute`. Fixed potential issue with storage mailer initialization if folder does not exist. Added utf_8_encoded helpers function on CMS_API interface. Fixed a few unicode potential issues. Removed a few obsolete calls. --- .../masquerade_auth/masquerade_auth_module.e | 4 +- .../site/themes/admin/assets/scss/style.scss | 110 ++++++++++++++++++ examples/demo/site/themes/admin/debug.tpl | 38 ++++++ library/model/src/user/cms_user.e | 10 +- library/recaptcha/recaptcha-safe.ecf | 7 +- library/recaptcha/recaptcha.ecf | 11 +- library/recaptcha/src/recaptcha_api.e | 20 ++-- .../admin/cms_admin_module_administration.e | 2 +- .../admin/handler/cms_admin_cache_handler.e | 8 +- .../admin/handler/cms_admin_export_handler.e | 8 +- modules/admin/handler/cms_admin_handler.e | 12 +- .../admin/handler/cms_admin_import_handler.e | 9 +- .../admin/handler/cms_admin_modules_handler.e | 19 ++- .../handler/cms_admin_path_alias_handler.e | 10 +- .../format/cms_admin_formats_handler.e | 12 +- modules/admin/handler/logs/cms_logs_handler.e | 7 +- .../handler/role/cms_role_form_response.e | 16 +-- modules/admin/handler/role/cms_role_handler.e | 13 +-- .../handler/role/cms_role_view_response.e | 2 +- ...ponse.e => cms_admin_user_form_response.e} | 10 +- ...ser_handler.e => cms_admin_user_handler.e} | 24 ++-- ...ponse.e => cms_admin_user_view_response.e} | 5 +- .../handler/user/cms_admin_users_handler.e | 5 +- .../auth/cms_authentication_email_service.e | 4 +- ..._authentication_email_service_parameters.e | 11 +- modules/auth/cms_authentication_module.e | 44 +++---- ...cms_authentication_module_administration.e | 5 +- modules/auth/cms_user_handler.e | 103 ++++++++++++++++ modules/auth/cms_user_view_response.e | 103 ++++++++++++++++ modules/blog/handler/blog_user_handler.e | 8 +- modules/contact/src/cms_contact_module.e | 8 +- .../src/contact_email_service_parameters.e | 7 +- .../src/persistence/contact_storage_fs.e | 5 +- .../embedded_video/src/video_content_filter.e | 12 +- modules/feed_aggregator/feed_aggregator_api.e | 9 +- .../feed_aggregator/feed_aggregator_module.e | 9 +- modules/files/cms_files_module.e | 19 ++- modules/files/cms_uploaded_file.e | 12 +- .../src/google_custom_search_module_20.e | 4 +- modules/messaging/src/cms_messaging_module.e | 9 +- modules/node/cms_node_module.e | 2 +- .../handler/cms_node_type_webform_manager.e | 6 +- modules/node/handler/node_form_response.e | 6 +- modules/node/handler/node_handler.e | 17 +-- modules/node/handler/trash_handler.e | 3 +- modules/openid/cms_openid_api.e | 2 +- modules/openid/cms_openid_module.e | 12 +- .../openid/persitence/cms_openid_storage_i.e | 4 +- .../persitence/cms_openid_storage_null.e | 2 +- .../persitence/cms_openid_storage_sql.e | 2 +- .../cms_recent_changes_module.e | 13 +-- modules/sitemap/cms_sitemap_module.e | 3 +- modules/taxonomy/handler/taxonomy_handler.e | 4 +- .../taxonomy_vocabulary_admin_handler.e | 8 +- .../handler/taxonomy_vocabulary_handler.e | 4 +- src/configuration/cms_default_setup.e | 22 ++-- src/kernel/content/cms_encoders.e | 12 +- src/persistence/cms_storage_null.e | 4 +- src/persistence/core/cms_core_storage_i.e | 4 +- src/persistence/core/cms_core_storage_sql_i.e | 2 +- src/service/cms_api.e | 24 +++- src/service/cms_execution.e | 32 ++--- src/service/cms_file_system_utilities.e | 78 ++++++++++--- .../handler/cms_admin_install_handler.e | 15 ++- src/service/handler/cms_handler.e | 35 +++--- .../handler/cms_theme_file_system_handler.e | 4 +- src/service/response/cms_response.e | 14 ++- src/service/response/cms_response_api.e | 87 ++++++++++++++ .../error/forbidden_error_cms_response.e | 73 +++++++++++- src/service/user/cms_user_api.e | 11 ++ src/theme/missing_theme/missing_cms_theme.e | 2 +- src/theme/smarty_theme/smarty_cms_theme.e | 3 +- tests/all-safe.ecf | 2 +- 73 files changed, 903 insertions(+), 343 deletions(-) create mode 100644 examples/demo/site/themes/admin/assets/scss/style.scss create mode 100644 examples/demo/site/themes/admin/debug.tpl rename modules/admin/handler/user/{cms_user_form_response.e => cms_admin_user_form_response.e} (98%) rename modules/admin/handler/user/{cms_user_handler.e => cms_admin_user_handler.e} (89%) rename modules/admin/handler/user/{cms_user_view_response.e => cms_admin_user_view_response.e} (97%) create mode 100644 modules/auth/cms_user_handler.e create mode 100644 modules/auth/cms_user_view_response.e create mode 100644 src/service/response/cms_response_api.e 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/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-safe.ecf b/library/recaptcha/recaptcha-safe.ecf index 0b7df94..b4f6ede 100644 --- a/library/recaptcha/recaptcha-safe.ecf +++ b/library/recaptcha/recaptcha-safe.ecf @@ -3,17 +3,18 @@ - /.git$ + /\.git$ /EIFGENs$ /CVS$ - /.svn$ + /\.svn$ - + + diff --git a/library/recaptcha/recaptcha.ecf b/library/recaptcha/recaptcha.ecf index 47d123d..0eaf801 100644 --- a/library/recaptcha/recaptcha.ecf +++ b/library/recaptcha/recaptcha.ecf @@ -3,19 +3,18 @@ - /.git$ + /\.git$ /EIFGENs$ /CVS$ - /.svn$ + /\.svn$ - + - - + + 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/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