From 58d4decc580dd99324816961b16a8f1f587853b3 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 28 Sep 2012 14:53:16 +0200 Subject: [PATCH] Added initial experimentation of a CMS built with Eiffel --- draft/application/cms/.gitignore | 1 + draft/application/cms/README.md | 2 + draft/application/cms/cms-safe.ecf | 30 + draft/application/cms/cms.ini | 3 + draft/application/cms/ewf.ini | 4 + draft/application/cms/favicon.ico | Bin 0 -> 786 bytes draft/application/cms/files/favicon.ico | Bin 0 -> 786 bytes .../cms/src/core/cms_configuration.e | 146 ++++ .../application/cms/src/core/cms_execution.e | 648 ++++++++++++++++++ .../cms/src/core/cms_html_page_response.e | 77 +++ draft/application/cms/src/core/cms_service.e | 341 +++++++++ draft/application/cms/src/core/cms_session.e | 33 + .../default_theme/default_cms_html_template.e | 81 +++ .../default_theme/default_cms_page_template.e | 84 +++ .../core/default_theme/default_cms_theme.e | 134 ++++ .../cms/src/core/handler/any_cms_execution.e | 48 ++ .../core/handler/cms_file_system_handler.e | 16 + .../cms/src/core/handler/cms_handler.e | 64 ++ .../cms/src/core/handler/home_cms_execution.e | 52 ++ .../core/handler/not_found_cms_execution.e | 34 + .../src/core/handler/theme_cms_execution.e | 47 ++ .../application/cms/src/core/hooks/cms_hook.e | 10 + .../cms/src/core/hooks/cms_hook_block.e | 23 + .../cms/src/core/hooks/cms_hook_form_alter.e | 19 + .../cms/src/core/hooks/cms_hook_menu_alter.e | 19 + .../cms/src/core/kernel/api/cms_api_options.e | 75 ++ .../cms/src/core/kernel/api/cms_common_api.e | 204 ++++++ .../src/core/kernel/api/cms_url_api_options.e | 25 + .../src/core/kernel/auth/cms_auth_engine.e | 16 + .../kernel/auth/cms_storage_auth_engine.e | 34 + .../cms/src/core/kernel/cms_html_page.e | 225 ++++++ .../src/core/kernel/cms_session_controler.e | 134 ++++ .../cms/src/core/kernel/cms_user.e | 158 +++++ .../cms/src/core/kernel/cms_user_profile.e | 51 ++ .../cms/src/core/kernel/content/cms_block.e | 32 + .../core/kernel/content/cms_content_block.e | 46 ++ .../core/kernel/content/cms_content_type.e | 60 ++ .../src/core/kernel/content/cms_menu_block.e | 45 ++ .../cms/src/core/kernel/content/cms_node.e | 101 +++ .../content/format/cms_filtered_html_format.e | 44 ++ .../core/kernel/content/format/cms_format.e | 46 ++ .../core/kernel/content/format/cms_formats.e | 54 ++ .../content/format/cms_full_html_format.e | 35 + .../content/format/cms_plain_text_format.e | 49 ++ .../content/format/filters/cms_filter.e | 35 + .../content/format/filters/cms_html_filter.e | 126 ++++ .../format/filters/cms_html_to_text_filter.e | 34 + .../filters/cms_line_break_converter_filter.e | 34 + .../format/filters/cms_no_html_filter.e | 77 +++ .../content/format/filters/cms_url_filter.e | 33 + .../cms/src/core/kernel/form/cms_form.e | 166 +++++ .../core/kernel/form/cms_form_button_input.e | 20 + .../kernel/form/cms_form_checkbox_input.e | 46 ++ .../cms/src/core/kernel/form/cms_form_data.e | 195 ++++++ .../cms/src/core/kernel/form/cms_form_field.e | 133 ++++ .../src/core/kernel/form/cms_form_field_set.e | 70 ++ .../core/kernel/form/cms_form_file_input.e | 46 ++ .../core/kernel/form/cms_form_hidden_input.e | 36 + .../core/kernel/form/cms_form_image_input.e | 58 ++ .../cms/src/core/kernel/form/cms_form_input.e | 109 +++ .../cms/src/core/kernel/form/cms_form_item.e | 16 + .../kernel/form/cms_form_password_input.e | 26 + .../core/kernel/form/cms_form_radio_input.e | 46 ++ .../src/core/kernel/form/cms_form_raw_text.e | 49 ++ .../core/kernel/form/cms_form_reset_input.e | 20 + .../src/core/kernel/form/cms_form_select.e | 116 ++++ .../core/kernel/form/cms_form_select_option.e | 50 ++ .../core/kernel/form/cms_form_submit_input.e | 20 + .../core/kernel/form/cms_form_text_input.e | 20 + .../src/core/kernel/form/cms_form_textarea.e | 85 +++ .../src/core/kernel/link/cms_external_link.e | 36 + .../cms/src/core/kernel/link/cms_link.e | 43 ++ .../cms/src/core/kernel/link/cms_local_link.e | 72 ++ .../cms/src/core/kernel/link/cms_menu.e | 73 ++ .../src/core/kernel/link/cms_menu_system.e | 88 +++ .../cms/src/core/kernel/log/cms_log.e | 152 ++++ .../admin/admin_blocks_cms_execution.e | 57 ++ .../core/modules/admin/admin_cms_execution.e | 43 ++ .../modules/admin/admin_logs_cms_execution.e | 47 ++ .../cms/src/core/modules/admin/admin_module.e | 100 +++ .../admin/admin_modules_cms_execution.e | 57 ++ .../modules/admin/admin_users_cms_execution.e | 56 ++ .../modules/admin/log_view_cms_execution.e | 39 ++ .../cms/src/core/modules/cms_module.e | 57 ++ .../cms/src/core/modules/cms_module_link.e | 50 ++ .../cms/src/core/modules/node/cms_page.e | 75 ++ .../core/modules/node/cms_page_content_type.e | 177 +++++ .../modules/node/node_add_cms_execution.e | 143 ++++ .../modules/node/node_edit_cms_execution.e | 148 ++++ .../cms/src/core/modules/node/node_module.e | 113 +++ .../modules/node/node_view_cms_execution.e | 41 ++ .../modules/user/user_account_cms_execution.e | 59 ++ .../core/modules/user/user_cms_execution.e | 182 +++++ .../modules/user/user_edit_cms_execution.e | 168 +++++ .../modules/user/user_login_cms_execution.e | 114 +++ .../modules/user/user_logout_cms_execution.e | 39 ++ .../cms/src/core/modules/user/user_module.e | 157 +++++ .../src/core/modules/user/user_module_lib.e | 29 + .../user/user_new_password_cms_execution.e | 154 +++++ .../user/user_register_cms_execution.e | 205 ++++++ .../user/user_reset_password_cms_execution.e | 86 +++ .../src/core/notification/cms_chain_mailer.e | 58 ++ .../cms/src/core/notification/cms_email.e | 94 +++ .../core/notification/cms_external_mailer.e | 190 +++++ .../cms/src/core/notification/cms_mailer.e | 48 ++ .../core/notification/cms_sendmail_mailer.e | 34 + .../core/notification/cms_storage_mailer.e | 38 + .../cms/src/core/storage/cms_sed_storage.e | 518 ++++++++++++++ .../cms/src/core/storage/cms_storage.e | 105 +++ .../cms/src/core/theme/cms_html_template.e | 13 + .../cms/src/core/theme/cms_page_template.e | 12 + .../cms/src/core/theme/cms_template.e | 81 +++ .../cms/src/core/theme/cms_theme.e | 69 ++ .../cms/src/module/demo/demo_module.e | 60 ++ .../module/shutdown/shutdown_cms_execution.e | 33 + .../cms/src/module/shutdown/shutdown_module.e | 72 ++ draft/application/cms/src/web_cms.e | 116 ++++ .../cms/themes/default/res/favicon.ico | Bin 0 -> 786 bytes .../cms/themes/default/res/logo.png | Bin 0 -> 3193 bytes .../cms/themes/default/res/style.css | 182 +++++ 120 files changed, 9599 insertions(+) create mode 100644 draft/application/cms/.gitignore create mode 100644 draft/application/cms/README.md create mode 100644 draft/application/cms/cms-safe.ecf create mode 100644 draft/application/cms/cms.ini create mode 100644 draft/application/cms/ewf.ini create mode 100644 draft/application/cms/favicon.ico create mode 100644 draft/application/cms/files/favicon.ico create mode 100644 draft/application/cms/src/core/cms_configuration.e create mode 100644 draft/application/cms/src/core/cms_execution.e create mode 100644 draft/application/cms/src/core/cms_html_page_response.e create mode 100644 draft/application/cms/src/core/cms_service.e create mode 100644 draft/application/cms/src/core/cms_session.e create mode 100644 draft/application/cms/src/core/default_theme/default_cms_html_template.e create mode 100644 draft/application/cms/src/core/default_theme/default_cms_page_template.e create mode 100644 draft/application/cms/src/core/default_theme/default_cms_theme.e create mode 100644 draft/application/cms/src/core/handler/any_cms_execution.e create mode 100644 draft/application/cms/src/core/handler/cms_file_system_handler.e create mode 100644 draft/application/cms/src/core/handler/cms_handler.e create mode 100644 draft/application/cms/src/core/handler/home_cms_execution.e create mode 100644 draft/application/cms/src/core/handler/not_found_cms_execution.e create mode 100644 draft/application/cms/src/core/handler/theme_cms_execution.e create mode 100644 draft/application/cms/src/core/hooks/cms_hook.e create mode 100644 draft/application/cms/src/core/hooks/cms_hook_block.e create mode 100644 draft/application/cms/src/core/hooks/cms_hook_form_alter.e create mode 100644 draft/application/cms/src/core/hooks/cms_hook_menu_alter.e create mode 100644 draft/application/cms/src/core/kernel/api/cms_api_options.e create mode 100644 draft/application/cms/src/core/kernel/api/cms_common_api.e create mode 100644 draft/application/cms/src/core/kernel/api/cms_url_api_options.e create mode 100644 draft/application/cms/src/core/kernel/auth/cms_auth_engine.e create mode 100644 draft/application/cms/src/core/kernel/auth/cms_storage_auth_engine.e create mode 100644 draft/application/cms/src/core/kernel/cms_html_page.e create mode 100644 draft/application/cms/src/core/kernel/cms_session_controler.e create mode 100644 draft/application/cms/src/core/kernel/cms_user.e create mode 100644 draft/application/cms/src/core/kernel/cms_user_profile.e create mode 100644 draft/application/cms/src/core/kernel/content/cms_block.e create mode 100644 draft/application/cms/src/core/kernel/content/cms_content_block.e create mode 100644 draft/application/cms/src/core/kernel/content/cms_content_type.e create mode 100644 draft/application/cms/src/core/kernel/content/cms_menu_block.e create mode 100644 draft/application/cms/src/core/kernel/content/cms_node.e create mode 100644 draft/application/cms/src/core/kernel/content/format/cms_filtered_html_format.e create mode 100644 draft/application/cms/src/core/kernel/content/format/cms_format.e create mode 100644 draft/application/cms/src/core/kernel/content/format/cms_formats.e create mode 100644 draft/application/cms/src/core/kernel/content/format/cms_full_html_format.e create mode 100644 draft/application/cms/src/core/kernel/content/format/cms_plain_text_format.e create mode 100644 draft/application/cms/src/core/kernel/content/format/filters/cms_filter.e create mode 100644 draft/application/cms/src/core/kernel/content/format/filters/cms_html_filter.e create mode 100644 draft/application/cms/src/core/kernel/content/format/filters/cms_html_to_text_filter.e create mode 100644 draft/application/cms/src/core/kernel/content/format/filters/cms_line_break_converter_filter.e create mode 100644 draft/application/cms/src/core/kernel/content/format/filters/cms_no_html_filter.e create mode 100644 draft/application/cms/src/core/kernel/content/format/filters/cms_url_filter.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_button_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_checkbox_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_data.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_field.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_field_set.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_file_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_hidden_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_image_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_item.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_password_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_radio_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_raw_text.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_reset_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_select.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_select_option.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_submit_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_text_input.e create mode 100644 draft/application/cms/src/core/kernel/form/cms_form_textarea.e create mode 100644 draft/application/cms/src/core/kernel/link/cms_external_link.e create mode 100644 draft/application/cms/src/core/kernel/link/cms_link.e create mode 100644 draft/application/cms/src/core/kernel/link/cms_local_link.e create mode 100644 draft/application/cms/src/core/kernel/link/cms_menu.e create mode 100644 draft/application/cms/src/core/kernel/link/cms_menu_system.e create mode 100644 draft/application/cms/src/core/kernel/log/cms_log.e create mode 100644 draft/application/cms/src/core/modules/admin/admin_blocks_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/admin/admin_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/admin/admin_logs_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/admin/admin_module.e create mode 100644 draft/application/cms/src/core/modules/admin/admin_modules_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/admin/admin_users_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/admin/log_view_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/cms_module.e create mode 100644 draft/application/cms/src/core/modules/cms_module_link.e create mode 100644 draft/application/cms/src/core/modules/node/cms_page.e create mode 100644 draft/application/cms/src/core/modules/node/cms_page_content_type.e create mode 100644 draft/application/cms/src/core/modules/node/node_add_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/node/node_edit_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/node/node_module.e create mode 100644 draft/application/cms/src/core/modules/node/node_view_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_account_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_edit_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_login_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_logout_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_module.e create mode 100644 draft/application/cms/src/core/modules/user/user_module_lib.e create mode 100644 draft/application/cms/src/core/modules/user/user_new_password_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_register_cms_execution.e create mode 100644 draft/application/cms/src/core/modules/user/user_reset_password_cms_execution.e create mode 100644 draft/application/cms/src/core/notification/cms_chain_mailer.e create mode 100644 draft/application/cms/src/core/notification/cms_email.e create mode 100644 draft/application/cms/src/core/notification/cms_external_mailer.e create mode 100644 draft/application/cms/src/core/notification/cms_mailer.e create mode 100644 draft/application/cms/src/core/notification/cms_sendmail_mailer.e create mode 100644 draft/application/cms/src/core/notification/cms_storage_mailer.e create mode 100644 draft/application/cms/src/core/storage/cms_sed_storage.e create mode 100644 draft/application/cms/src/core/storage/cms_storage.e create mode 100644 draft/application/cms/src/core/theme/cms_html_template.e create mode 100644 draft/application/cms/src/core/theme/cms_page_template.e create mode 100644 draft/application/cms/src/core/theme/cms_template.e create mode 100644 draft/application/cms/src/core/theme/cms_theme.e create mode 100644 draft/application/cms/src/module/demo/demo_module.e create mode 100644 draft/application/cms/src/module/shutdown/shutdown_cms_execution.e create mode 100644 draft/application/cms/src/module/shutdown/shutdown_module.e create mode 100644 draft/application/cms/src/web_cms.e create mode 100644 draft/application/cms/themes/default/res/favicon.ico create mode 100644 draft/application/cms/themes/default/res/logo.png create mode 100644 draft/application/cms/themes/default/res/style.css diff --git a/draft/application/cms/.gitignore b/draft/application/cms/.gitignore new file mode 100644 index 00000000..f998b949 --- /dev/null +++ b/draft/application/cms/.gitignore @@ -0,0 +1 @@ +_storage_ diff --git a/draft/application/cms/README.md b/draft/application/cms/README.md new file mode 100644 index 00000000..79620c23 --- /dev/null +++ b/draft/application/cms/README.md @@ -0,0 +1,2 @@ +Experimental a simple CMS using EWF. +Inspired by Drupal diff --git a/draft/application/cms/cms-safe.ecf b/draft/application/cms/cms-safe.ecf new file mode 100644 index 00000000..596289b0 --- /dev/null +++ b/draft/application/cms/cms-safe.ecf @@ -0,0 +1,30 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + + + + + + + + + + + + diff --git a/draft/application/cms/cms.ini b/draft/application/cms/cms.ini new file mode 100644 index 00000000..f1803e45 --- /dev/null +++ b/draft/application/cms/cms.ini @@ -0,0 +1,3 @@ +site.name=EWF Web CMS +#site.base_url=/demo +site.email=your@email.com diff --git a/draft/application/cms/ewf.ini b/draft/application/cms/ewf.ini new file mode 100644 index 00000000..6a794d69 --- /dev/null +++ b/draft/application/cms/ewf.ini @@ -0,0 +1,4 @@ +# For nino connector, use port 9999 +port=9090 + +#verbose=true diff --git a/draft/application/cms/favicon.ico b/draft/application/cms/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..343067f9fc7b0829212336f7f67fa96328ba71a3 GIT binary patch literal 786 zcmV+t1MU0(0096201yxW0096X0Q>>~02TlM0EtjeM-2)Z3IG5A4M|8uQUCw|5C8xG z5C{eU001BJ|6u?C0>eo}K~y-)rITAo({U8XKfnL}o7;5Gf7`#NrbcCZOZiN?Bp`q9v&rArV=Mld@&Dx&PKSEvK3Odzg!e zdg==Y&VlnioXhtJ{y^)!D+Qj;_Oh_%%bysJ<^fo3_I^c8?_0KhQ`6SsL$80&7YRq# zb#dK&yr#S5R<$jsp}U>;>vzx2%kf@ zM}q!Xb8AIj|+G1a}*ss!q;$!u9gNI=~);}Nn|WuPWQtmEGag2R2(H5 z3NY+>%k|po(4MN(TVzjXdzm)kb-1#Z@a91;2P!kRBXF{9OHCrxz`4UXc>%)w-~5YhasShJar1HA|#NK;+d z6ej>-&6h7HPSxMj!LGwqAOt3h72l8tAxZd#Jh&DuB@!Iv+gOBp_laLiofwbi$%)`; z^EJW)FG#g3jQhP@J9&Vw(-Mozt@+e#{WR~MDKqtg;aSx~(aa#Q0)2BUG}^lZF?d<9f9#AXDmi%Q+wN-BEAFDV}@ zZyxPvD3+Ne5QAi6ybF^AsiyeiTvnJ75(_r$y>~02TlM0EtjeM-2)Z3IG5A4M|8uQUCw|5C8xG z5C{eU001BJ|6u?C0>eo}K~y-)rITAo({U8XKfnL}o7;5Gf7`#NrbcCZOZiN?Bp`q9v&rArV=Mld@&Dx&PKSEvK3Odzg!e zdg==Y&VlnioXhtJ{y^)!D+Qj;_Oh_%%bysJ<^fo3_I^c8?_0KhQ`6SsL$80&7YRq# zb#dK&yr#S5R<$jsp}U>;>vzx2%kf@ zM}q!Xb8AIj|+G1a}*ss!q;$!u9gNI=~);}Nn|WuPWQtmEGag2R2(H5 z3NY+>%k|po(4MN(TVzjXdzm)kb-1#Z@a91;2P!kRBXF{9OHCrxz`4UXc>%)w-~5YhasShJar1HA|#NK;+d z6ej>-&6h7HPSxMj!LGwqAOt3h72l8tAxZd#Jh&DuB@!Iv+gOBp_laLiofwbi$%)`; z^EJW)FG#g3jQhP@J9&Vw(-Mozt@+e#{WR~MDKqtg;aSx~(aa#Q0)2BUG}^lZF?d<9f9#AXDmi%Q+wN-BEAFDV}@ zZyxPvD3+Ne5QAi6ybF^AsiyeiTvnJ75(_r$y") + else + m.append ("
  • ") + end + m.append (a_msg + "
  • ") + end + + add_notice_message (a_msg: READABLE_STRING_8) + do + add_message (a_msg, "notice") + end + + add_warning_message (a_msg: READABLE_STRING_8) + do + add_message (a_msg, "warning") + end + + add_error_message (a_msg: READABLE_STRING_8) + do + add_message (a_msg, "error") + end + + add_success_message (a_msg: READABLE_STRING_8) + do + add_message (a_msg, "success") + end + + report_form_errors (fd: CMS_FORM_DATA) + require + has_error: not fd.is_valid + do + if attached fd.errors as errs then + across + errs as err + loop + if attached err.item as e then + if attached e.field as l_field then + if attached e.message as e_msg then + add_error_message (e_msg) --"Field [" + l_field.name + "] is invalid. " + e_msg) + else + add_error_message ("Field [" + l_field.name + "] is invalid.") + end + elseif attached e.message as e_msg then + add_error_message (e_msg) + end + end + end + end + end + + message: detachable STRING_8 + +feature -- Blocks + + formats: CMS_FORMATS + once + create Result + end + + blocks: ARRAYED_LIST [TUPLE [block: CMS_BLOCK; name: READABLE_STRING_8; region: READABLE_STRING_8]] + + add_block (b: CMS_BLOCK; a_region: detachable READABLE_STRING_8) + do + if a_region /= Void then + blocks.extend ([b, b.name, a_region]) + elseif attached block_region (b) as l_region then + blocks.extend ([b, b.name, l_region]) + end + end + + block_region (b: CMS_BLOCK): detachable READABLE_STRING_8 + local + l_name: READABLE_STRING_8 + do + l_name := b.name + if l_name.starts_with ("footer") then + Result := "footer" + elseif l_name.starts_with ("management") then + Result := "first_sidebar" + elseif l_name.starts_with ("navigation") then + Result := "first_sidebar" + elseif l_name.starts_with ("user") then + Result := "first_sidebar" + else + Result := "first_sidebar" + end + -- FIXME: let the user choose ... + end + + get_blocks + local + b: CMS_CONTENT_BLOCK + s: STRING_8 + m: CMS_MENU + do + m := management_menu + if not m.is_empty then + add_block (create {CMS_MENU_BLOCK}.make (m), Void) + end + + m := navigation_menu + if not m.is_empty then + add_block (create {CMS_MENU_BLOCK}.make (m), Void) + end + + m := user_menu + if not m.is_empty then + add_block (create {CMS_MENU_BLOCK}.make (m), Void) + end + + create s.make_empty + s.append ("This site demonstrates a first implementation of CMS using EWF.%N") + create b.make ("about", "About", s, formats.plain_text) + add_block (b, "second_sidebar") + + create s.make_empty + s.append ("Made with EWF") + create b.make ("made_with", Void, s, formats.full_html) + add_block (b, "footer") + + service.hook_block_view (Current) + end + +feature -- Access + + status_code: INTEGER + + header: WSF_HEADER + + title: detachable READABLE_STRING_32 + -- HTML>head>title value + + page_title: detachable READABLE_STRING_32 + -- Page title + + main_content: detachable STRING_8 + + redirection: detachable READABLE_STRING_8 + +feature -- Generation + + prepare_menu_system (a_menu_system: CMS_MENU_SYSTEM) + do + across + a_menu_system as c + loop + prepare_menu (c.item) + end + end + + prepare_menu (a_menu: CMS_MENU) + local + to_remove: ARRAYED_LIST [CMS_LINK] + do + create to_remove.make (0) + across + a_menu as c + loop + if attached {CMS_LOCAL_LINK} c.item as lm then + if not has_permissions (lm.permission_arguments) then + to_remove.force (lm) + else + lm.get_is_active (request) + end + end + end + across + to_remove as c + loop + a_menu.remove (c.item) + end + end + + prepare (page: CMS_HTML_PAGE) + local + s: STRING_8 + do + add_to_main_menu (create {CMS_LOCAL_LINK}.make ("Home", "/")) + + service.call_menu_alter_hooks (menu_system, Current) + prepare_menu_system (menu_system) + + get_blocks + + if attached title as l_title then + page.set_title (l_title) + else + page.set_title ("CMS::" + request.path_info) + end + + page.add_to_header_region (top_header_region) + page.add_to_header_region (header_region) + if attached message as m and then not m.is_empty then + page.add_to_content_region ("
    " + m + "
    ") + end + page.add_to_content_region ("%N") + if attached page_title as l_page_title then + page.add_to_content_region ("

    "+ l_page_title +"

    %N") + end + if attached primary_tabs as tabs_menu and then not tabs_menu.is_empty then + page.add_to_content_region (theme.menu_html (tabs_menu, True)) + end + page.add_to_content_region (content_region) + + -- blocks + across + blocks as c + loop + if attached c.item as b_info then + create s.make_from_string ("
    ") + if attached b_info.block.title as l_title then + s.append ("
    " + html_encoded (l_title) + "
    ") + end + s.append ("
    ") + s.append (b_info.block.to_html (theme)) + s.append ("
    ") + s.append ("
    ") + page.add_to_region (s, b_info.region) + end + end + end + + logo_location: STRING + do + Result := url ("/theme/logo.png", Void) + end + + top_header_region: STRING_8 + do + Result := "
    " + html_encoded (site_name) + "
    " + Result.append ("
    ") + Result.append (theme.menu_html (main_menu, True)) + Result.append ("
    ") + end + + header_region: STRING_8 + do + Result := "" + end + + content_region: STRING_8 + do + if attached main_content as l_content then + Result := l_content + else + Result := "" + debug + Result := "No Content" + end + end + end + +feature -- Element change + + set_title (t: like title) + do + title := t + set_page_title (t) + end + + set_page_title (t: like page_title) + do + page_title := t + end + + set_main_content (s: like main_content) + do + main_content := s + end + + set_redirection (a_url: like redirection) + do + if a_url /= Void and then a_url.same_string (request.path_info) and request.is_get_request_method then + redirection := Void + else + redirection := a_url + end + end + +feature -- Execution + + execute + do + begin + process + terminate + end + +feature {NONE} -- Execution + + begin + do + end + + process + deferred + end + + frozen terminate + local + cms_page: CMS_HTML_PAGE + page: CMS_HTML_PAGE_RESPONSE + do + create cms_page.make + prepare (cms_page) + + create page.make (theme.page_html (cms_page)) + if attached redirection as l_redirection then + if attached message as m then + set_session_item ("cms.pending_messages", m) + end + page.set_status_code ({HTTP_STATUS_CODE}.found) + page.header.put_location (l_redirection) + else + page.set_status_code (status_code) + end + + controller.session_commit (page, Current) + response.send (page) + end + +feature {NONE} -- Implementation + + set_user (u: like user) + do + set_session_item ("user", u) + end + + init_last_user_access_date + do + set_session_item ("last_access", (create {DATE_TIME}.make_now_utc)) + end + + session_item (k: READABLE_STRING_GENERAL): detachable ANY + do + Result := controller.session.item (k) + end + + set_session_item (k: READABLE_STRING_GENERAL; v: detachable ANY) + do + controller.session.remember (v, k) + end + + remove_session_item (k: READABLE_STRING_GENERAL) + do + controller.session.forget (k) + end + +feature -- Storage + + storage: CMS_STORAGE + do + Result := service.storage + end + +feature -- Helper: output + + user_local_link (u: CMS_USER): CMS_LINK + do + create {CMS_LOCAL_LINK} Result.make (u.name, user_url (u)) + end + + node_local_link (n: CMS_NODE): CMS_LINK + do + create {CMS_LOCAL_LINK} Result.make (n.title, node_url (n)) + end + + truncated_string (s: READABLE_STRING_8; nb: INTEGER; a_ellipsis: detachable READABLE_STRING_8): STRING_8 + -- Truncated string `s' to `nb' character + require + a_ellipsis /= Void implies a_ellipsis.count < nb + local + f: CMS_NO_HTML_FILTER + do + if s.count <= nb then + Result := s.string + else + create f + create Result.make_from_string (s) + f.filter (Result) + if Result.count > nb then + if a_ellipsis /= Void and then not a_ellipsis.is_empty then + Result.keep_head (nb - a_ellipsis.count) + Result.append (a_ellipsis) + else + Result.keep_head (nb - 3) + Result.append ("...") + end + end + end + end + +feature -- Helper: request + + non_empty_string_path_parameter (a_name: READABLE_STRING_GENERAL): detachable STRING + do + if + attached {WSF_STRING} request.path_parameter (a_name) as p and then + not p.is_empty + then + Result := p.value + end + end + +invariant + +end diff --git a/draft/application/cms/src/core/cms_html_page_response.e b/draft/application/cms/src/core/cms_html_page_response.e new file mode 100644 index 00000000..97af15fb --- /dev/null +++ b/draft/application/cms/src/core/cms_html_page_response.e @@ -0,0 +1,77 @@ +note + description: "Summary description for {CMS_HTML_PAGE_RESPONSE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_HTML_PAGE_RESPONSE + +inherit + WSF_RESPONSE_MESSAGE + +create + make + +feature {NONE} -- Initialization + + make (a_html: like html) + do + html := a_html + status_code := {HTTP_STATUS_CODE}.ok + create header.make + header.put_content_type_text_html + end + +feature -- Status + + status_code: INTEGER + +feature -- Header + + header: HTTP_HEADER + +feature -- Html access + + html: STRING + +feature -- Element change + + set_status_code (c: like status_code) + do + status_code := c + end + +feature {WSF_RESPONSE} -- Output + + send_to (res: WSF_RESPONSE) + local + h: like header + s: STRING_8 + do + h := header + res.set_status_code (status_code) + s := html + + if not h.has_content_length then + h.put_content_length (s.count) + end + if not h.has_content_type then + h.put_content_type_text_html + end + res.put_header_text (h.string) + res.put_string (s) + end + +note + copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end + diff --git a/draft/application/cms/src/core/cms_service.e b/draft/application/cms/src/core/cms_service.e new file mode 100644 index 00000000..695f56f3 --- /dev/null +++ b/draft/application/cms/src/core/cms_service.e @@ -0,0 +1,341 @@ +note + description: "[ + This class implements the CMS service + + It could be used to implement the main EWF service, or + even for a specific handler. + ]" + +deferred class + CMS_SERVICE + +feature -- Initialization + + initialize_cms + do + site_name := "EWF::CMS" + site_email := "webmaster" + site_url := "" -- FIXME + create content_types.make (3) + initialize_storage + initialize_auth_engine + initialize_session_manager + initialize_mailer + initialize_router + initialize_modules + end + + initialize_session_manager + local + dn: DIRECTORY_NAME + do + create dn.make_from_string ((create {EXECUTION_ENVIRONMENT}).current_working_directory) + dn.extend ("_storage_") + dn.extend ("_sessions_") + create {WSF_FS_SESSION_MANAGER} session_manager.make_with_folder (dn.string) + end + + initialize_storage + local + e: EXECUTION_ENVIRONMENT + dn: DIRECTORY_NAME + u: CMS_USER + do + create e + create dn.make_from_string (e.current_working_directory) + dn.extend ("_storage_") + create {CMS_SED_STORAGE} storage.make (dn.string) + if storage.users_count = 0 then + initialize_users + end + end + + initialize_users + require + has_no_user: storage.users_count = 0 + local + u: CMS_USER + do + create u.make_new ("admin") + u.set_encoded_password (storage.encoded_password ("istrator")) + storage.save_user (u) + end + + initialize_mailer + local + ch_mailer: CMS_CHAIN_MAILER + st_mailer: CMS_STORAGE_MAILER + do + create st_mailer.make (storage) + create ch_mailer.make (st_mailer) + ch_mailer.set_next (create {CMS_SENDMAIL_MAILER}) + mailer := ch_mailer + end + + initialize_router + local +-- h: CMS_HANDLER + file_hdl: CMS_FILE_SYSTEM_HANDLER + do + create router.make (10) + router.set_base_url (base_url) + + router.map (create {WSF_URI_MAPPING}.make ("/", create {CMS_HANDLER}.make (agent handle_home))) + router.map (create {WSF_URI_MAPPING}.make ("/favicon.ico", create {CMS_HANDLER}.make (agent handle_favicon))) + + create file_hdl.make ("files") + file_hdl.disable_index + file_hdl.set_max_age (8*60*60) + router.map (create {WSF_STARTS_WITH_MAPPING}.make ("/files/", file_hdl)) + + create file_hdl.make ("themes/default/res") + file_hdl.set_max_age (8*60*60) + router.map (create {WSF_STARTS_WITH_MAPPING}.make ("/theme/", file_hdl)) + end + + initialize_modules + do + across + modules as m + loop + if m.item.is_enabled then + m.item.register (Current) + end + end + end + + initialize_auth_engine + do + create {CMS_STORAGE_AUTH_ENGINE} auth_engine.make (storage) + end + +feature -- Access + + auth_engine: CMS_AUTH_ENGINE + + modules: ARRAYED_LIST [CMS_MODULE] + local + m: CMS_MODULE + once + create Result.make (10) + -- Core + create {USER_MODULE} m.make (Current) + m.enable + Result.extend (m) + + create {ADMIN_MODULE} m.make (Current) + m.enable + Result.extend (m) + + create {NODE_MODULE} m.make (Current) + m.enable + Result.extend (m) + end + +feature -- Hook: menu_alter + + add_menu_alter_hook (h: like menu_alter_hooks.item) + local + lst: like menu_alter_hooks + do + lst := menu_alter_hooks + if lst = Void then + create lst.make (1) + menu_alter_hooks := lst + end + lst.force (h) + end + + menu_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_MENU_ALTER] + + call_menu_alter_hooks (m: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) + do + if attached menu_alter_hooks as lst then + across + lst as c + loop + c.item.menu_alter (m, a_execution) + end + end + end + +feature -- Hook: form_alter + + add_form_alter_hook (h: like form_alter_hooks.item) + local + lst: like form_alter_hooks + do + lst := form_alter_hooks + if lst = Void then + create lst.make (1) + form_alter_hooks := lst + end + lst.force (h) + end + + form_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_FORM_ALTER] + + call_form_alter_hooks (f: CMS_FORM; a_execution: CMS_EXECUTION) + do + if attached form_alter_hooks as lst then + across + lst as c + loop + c.item.form_alter (f, a_execution) + end + end + end + +feature -- Hook: block + + add_block_hook (h: like block_hooks.item) + local + lst: like block_hooks + do + lst := block_hooks + if lst = Void then + create lst.make (1) + block_hooks := lst + end + lst.force (h) + end + + block_hooks: detachable ARRAYED_LIST [CMS_HOOK_BLOCK] + + hook_block_view (a_execution: CMS_EXECUTION) + do + if attached block_hooks as lst then + across + lst as c + loop + across + c.item.block_list as blst + loop + c.item.get_block_view (blst.item, a_execution) + end + end + end + end + +feature -- Router + + site_name: STRING_32 + + site_email: STRING + + site_url: STRING + + front_path: STRING = "/" + + router: WSF_ROUTER + + base_url: detachable READABLE_STRING_8 + deferred + ensure + valid_base_url: (Result /= Void and then Result.is_empty) implies (Result.starts_with ("/") and not Result.ends_with ("/")) + end + + map_uri_template (tpl: STRING; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) + do + router.map (create {WSF_URI_TEMPLATE_MAPPING}.make_from_template (tpl, create {CMS_HANDLER}.make (proc))) + end + + map_uri (a_uri: STRING; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) + do + router.map (create {WSF_URI_MAPPING}.make (a_uri, create {CMS_HANDLER}.make (proc))) + end + +feature -- Storage + + session_controller (req: WSF_REQUEST): CMS_SESSION_CONTROLER + -- New session controller for request `req' + do + create Result.make (req, session_manager) + end + + session_manager: WSF_SESSION_MANAGER + -- CMS Session manager + + storage: CMS_STORAGE + +feature -- Logging + + log (a_category: READABLE_STRING_8; a_message: READABLE_STRING_8; a_level: INTEGER; a_link: detachable CMS_LINK) + local + l_log: CMS_LOG + do + create l_log.make (a_category, a_message, a_level, Void) + if a_link /= Void then + l_log.set_link (a_link) + end + storage.save_log (l_log) + end + +feature -- Content type + + content_types: ARRAYED_LIST [CMS_CONTENT_TYPE] + -- Available content types + + add_content_type (a_type: CMS_CONTENT_TYPE) + do + content_types.force (a_type) + end + + content_type (a_name: READABLE_STRING_8): detachable CMS_CONTENT_TYPE + do + across + content_types as t + until + Result /= Void + loop + if t.item.name.same_string (a_name) then + Result := t.item + end + end + end + +feature -- Notification + + mailer: CMS_MAILER + +feature -- Core Execution + + handle_favicon (req: WSF_REQUEST; res: WSF_RESPONSE) + local + fres: WSF_FILE_RESPONSE + do + create fres.make ("files/favicon.ico") + fres.set_expires_in_seconds (7 * 24 * 60 * 60) -- 7 jours + res.send (fres) + end + + handle_home (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {HOME_CMS_EXECUTION}.make (req, res, Current)).execute + end + +-- handle_theme (req: WSF_REQUEST; res: WSF_RESPONSE) +-- do +-- (create {THEME_CMS_EXECUTION}.make (req, res, Current)).execute +-- end + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Default request handler if no other are relevant + local + e: CMS_EXECUTION +-- not_found: WSF_NOT_FOUND_RESPONSE + do + if site_url.is_empty then + site_url := req.absolute_script_url ("") + end + if attached router.dispatch_and_return_handler (req, res) as p then + -- ok + else + create {NOT_FOUND_CMS_EXECUTION} e.make (req, res, Current) + e.execute +-- create not_found.make +-- res.send (not_found) + end + end + +end diff --git a/draft/application/cms/src/core/cms_session.e b/draft/application/cms/src/core/cms_session.e new file mode 100644 index 00000000..926d6f35 --- /dev/null +++ b/draft/application/cms/src/core/cms_session.e @@ -0,0 +1,33 @@ +note + description: "Summary description for {WSF_SESSION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION + +inherit + WSF_COOKIE_SESSION + +create + make, + make_new + +feature -- Access + + + +note + copyright: "Copyright (c) 1984-2012, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end + diff --git a/draft/application/cms/src/core/default_theme/default_cms_html_template.e b/draft/application/cms/src/core/default_theme/default_cms_html_template.e new file mode 100644 index 00000000..89994bca --- /dev/null +++ b/draft/application/cms/src/core/default_theme/default_cms_html_template.e @@ -0,0 +1,81 @@ +note + description: "Summary description for {CMS_HTML_TEMPLATE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_CMS_HTML_TEMPLATE + +inherit + CMS_HTML_TEMPLATE + +create + make + +feature {NONE} -- Initialization + + make (t: DEFAULT_CMS_THEME) + do + theme := t + create variables.make (0) + end + + variables: HASH_TABLE [detachable ANY, STRING] + +feature -- Access + + register (v: STRING_8; k: STRING_8) + do + variables.force (v, k) + end + + theme: DEFAULT_CMS_THEME + + prepare (page: CMS_HTML_PAGE) + do + variables.make (10) + if attached page.title as l_title then + variables.force (l_title, "title") + variables.force (l_title, "head_title") + else + variables.force ("", "title") + variables.force ("", "head_title") + end + + variables.force (page.language, "language") + variables.force (page.head_lines_to_string, "head_lines") + end + + to_html (page: CMS_HTML_PAGE): STRING + do + -- Process html generation + create Result.make_from_string (template) + apply_template_engine (Result) + end + +feature {NONE} -- Implementation + + template: STRING + once + Result := "[ + + + + $head + $head_title + $styles + $scripts + $head_lines + + + $page_top + $page + $page_bottom + + + ]" + end + + +end diff --git a/draft/application/cms/src/core/default_theme/default_cms_page_template.e b/draft/application/cms/src/core/default_theme/default_cms_page_template.e new file mode 100644 index 00000000..eba29827 --- /dev/null +++ b/draft/application/cms/src/core/default_theme/default_cms_page_template.e @@ -0,0 +1,84 @@ +note + description: "Summary description for {CMS_PAGE_TEMPLATE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_CMS_PAGE_TEMPLATE + +inherit + CMS_PAGE_TEMPLATE + +create + make + +feature {NONE} -- Initialization + + make (t: DEFAULT_CMS_THEME) + do + theme := t + create variables.make (0) + end + + variables: HASH_TABLE [detachable ANY, STRING] + +feature -- Access + + theme: DEFAULT_CMS_THEME + + prepare (page: CMS_HTML_PAGE) + do + variables.make (10) + + if attached page.title as l_title then + variables.force (l_title, "title") + else + variables.force ("", "title") + end + across + theme.regions as r + loop + variables.force (page.region (r.item), r.item) + end + end + + to_html (page: CMS_HTML_PAGE): STRING + do + -- Process html generation + create Result.make_from_string (template) + apply_template_engine (Result) + end + +feature -- Registration + + register (v: STRING_8; k: STRING_8) + do + variables.force (v, k) + end + +feature {NONE} -- Implementation + + template: STRING + once + Result := "[ +
    +
    + +
    +
    + +
    $content
    + +
    +
    + +
    +
    + ]" + end + + +end diff --git a/draft/application/cms/src/core/default_theme/default_cms_theme.e b/draft/application/cms/src/core/default_theme/default_cms_theme.e new file mode 100644 index 00000000..07826965 --- /dev/null +++ b/draft/application/cms/src/core/default_theme/default_cms_theme.e @@ -0,0 +1,134 @@ +note + description: "Summary description for {CMS_THEME}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEFAULT_CMS_THEME + +inherit + CMS_THEME + +create + make + +feature {NONE} -- Initialization + + make (a_service: like service) + do + service := a_service + end + + service: CMS_SERVICE + +feature -- Access + + name: STRING = "CMS" + + regions: ARRAY [STRING] + once + Result := <<"header", "content", "footer", "first_sidebar", "second_sidebar">> + end + + html_template: DEFAULT_CMS_HTML_TEMPLATE + local + tpl: like internal_html_template + do + tpl := internal_html_template + if tpl = Void then + create tpl.make (Current) + internal_html_template := tpl + end + Result := tpl + end + + page_template: DEFAULT_CMS_PAGE_TEMPLATE + local + tpl: like internal_page_template + do + tpl := internal_page_template + if tpl = Void then + create tpl.make (Current) + internal_page_template := tpl + end + Result := tpl + end + + css: STRING + do + Result := "[ + body { margin: 0; } + div#header { background-color: #00a; color: #fff; border: solid 1px #00a; padding: 10px;} + div#header img#logo { float: left; margin: 3px; } + div#header div#title {font-size: 180%; font-weight: bold; } + ul.horizontal { + list-style-type: none; + } + ul.horizontal li { + display: inline; + padding: 5px; + } + div#first-menu { padding: 5px; color: #ccf; background-color: #006; } + div#first-menu a { color: #ccf; } + div#second-menu { color: #99f; background-color: #333; } + div#second-menu a { color: #99f; } + + div#left_sidebar { + width: 150px; + border: solid 1px #009; + margin: 5px; + padding: 5px; + width: 150px; + display: inline; + float: left; + position: relative; + } + div#main-wrapper { + clear: both; + display: block; + height: 0; + } + div#main { margin: 0; padding: 10px; clear: both; height:0; display: block; } + div#content { padding: 10px; border: solid 1px #00f; + width: 700px; + display: inline; + float: left; + position: relative; + } + div#footer { margin: 10px 0 10px 0; clear: both; display: block; text-align: center; padding: 10px; border-top: solid 1px #00f; color: #fff; background-color: #333;} + div#footer a { color: #ff0; } + ]" + end + +feature -- Conversion + + prepare (page: CMS_HTML_PAGE) + do + if attached css as t_css then +-- page.head_lines.extend ("") + page.add_style (url ("/theme/style.css", Void), Void) + end + end + + page_html (page: CMS_HTML_PAGE): STRING_8 + local + l_content: STRING_8 + do + prepare (page) + page_template.prepare (page) + l_content := page_template.to_html (page) + html_template.prepare (page) + html_template.register (l_content, "page") + Result := html_template.to_html (page) + end + +feature {NONE} -- Internal + + internal_page_template: detachable like page_template + + internal_html_template: detachable like html_template + +invariant + attached internal_page_template as inv_p implies inv_p.theme = Current +end diff --git a/draft/application/cms/src/core/handler/any_cms_execution.e b/draft/application/cms/src/core/handler/any_cms_execution.e new file mode 100644 index 00000000..86312476 --- /dev/null +++ b/draft/application/cms/src/core/handler/any_cms_execution.e @@ -0,0 +1,48 @@ +note + description: "[ + This class implements the web service + + It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready + And from WSF_URI_TEMPLATE_ROUTED_SERVICE to use the router service + + `initialize' can be redefine to provide custom options if needed. + ]" + +class + ANY_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make, + make_with_text + +feature {NONE} -- Initialization + + make_with_text (req: WSF_REQUEST; res: WSF_RESPONSE; h: like service; t: like text) + do + make (req, res, h) + text := t + end + + text: detachable STRING + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + create b.make_empty + if attached text as t then + set_title (request.path_info) + b.append (t) + else + set_title ("Page Not Found") + end + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/handler/cms_file_system_handler.e b/draft/application/cms/src/core/handler/cms_file_system_handler.e new file mode 100644 index 00000000..b90630dc --- /dev/null +++ b/draft/application/cms/src/core/handler/cms_file_system_handler.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {CMS_FILE_SYSTEM_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FILE_SYSTEM_HANDLER + +inherit + WSF_FILE_SYSTEM_HANDLER + +create + make + +end diff --git a/draft/application/cms/src/core/handler/cms_handler.e b/draft/application/cms/src/core/handler/cms_handler.e new file mode 100644 index 00000000..f678e879 --- /dev/null +++ b/draft/application/cms/src/core/handler/cms_handler.e @@ -0,0 +1,64 @@ +note + description: "Summary description for {CMS_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_HANDLER + +inherit + WSF_URI_HANDLER + rename + execute as execute_uri + undefine + new_mapping + end + + WSF_URI_TEMPLATE_HANDLER + rename + execute as execute_uri_template + end + + WSF_STARTS_WITH_HANDLER + rename + execute as execute_starts_with + undefine + new_mapping + end + +create + make + +feature {NONE} -- Initialization + + make (e: like action) + do + action := e + end + + action: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]] + +feature -- Execution + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + do + action.call ([req, res]) + end + + execute_uri (req: WSF_REQUEST; res: WSF_RESPONSE) + do + execute (req, res) + end + + execute_uri_template (req: WSF_REQUEST; res: WSF_RESPONSE) + do + execute_uri (req, res) + end + + execute_starts_with (a_start_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) + do + execute_uri (req, res) + end + +end diff --git a/draft/application/cms/src/core/handler/home_cms_execution.e b/draft/application/cms/src/core/handler/home_cms_execution.e new file mode 100644 index 00000000..fe79855e --- /dev/null +++ b/draft/application/cms/src/core/handler/home_cms_execution.e @@ -0,0 +1,52 @@ +note + description: "[ + ]" + +class + HOME_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local +-- l_url: READABLE_STRING_8 + b: STRING_8 + do + set_title ("Home") + set_page_title (Void) + create b.make_empty + if attached service.storage.recent_nodes (1, 10) as l_nodes then + across + l_nodes as c + loop + b.append ("
    ") + b.append (c.item.to_html (theme)) + b.append ("
    %N") + end + end + +-- b.append ("
      %N") +-- l_url := url ("/", Void) +-- b.append ("
    • Home
    • %N") +-- l_url := url ("/info/", Void) +-- b.append ("
    • EWF Info
    • %N") + +-- b.append ("
    %N") + + debug ("cms") + if attached controller.session as sess then + b.append ("
    Session#" + sess.uuid + "
    %N") + end + end + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/handler/not_found_cms_execution.e b/draft/application/cms/src/core/handler/not_found_cms_execution.e new file mode 100644 index 00000000..8756855c --- /dev/null +++ b/draft/application/cms/src/core/handler/not_found_cms_execution.e @@ -0,0 +1,34 @@ +note + description: "[ + This class implements the web service + + It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready + And from WSF_URI_TEMPLATE_ROUTED_SERVICE to use the router service + + `initialize' can be redefine to provide custom options if needed. + ]" + +class + NOT_FOUND_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + status_code := {HTTP_STATUS_CODE}.not_found + create b.make_empty + set_title ("Page Not Found") + b.append ("The requested page could not be found.%N") + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/handler/theme_cms_execution.e b/draft/application/cms/src/core/handler/theme_cms_execution.e new file mode 100644 index 00000000..32999ade --- /dev/null +++ b/draft/application/cms/src/core/handler/theme_cms_execution.e @@ -0,0 +1,47 @@ +note + description: "[ + ]" + +class + THEME_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local +-- l_url: READABLE_STRING_8 + b: STRING_8 + do + set_title ("Home") + create b.make_empty + + b.append ("

    Home

    %N") + if attached service.storage.recent_nodes (1, 10) as l_nodes then + across + l_nodes as c + loop + b.append ("
    ") + b.append (c.item.to_html (theme)) + b.append ("
    %N") + end + end + +-- b.append ("
      %N") +-- l_url := url ("/", Void) +-- b.append ("
    • Home
    • %N") +-- l_url := url ("/info/", Void) +-- b.append ("
    • EWF Info
    • %N") + +-- b.append ("
    %N") + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/hooks/cms_hook.e b/draft/application/cms/src/core/hooks/cms_hook.e new file mode 100644 index 00000000..9e6ae0e7 --- /dev/null +++ b/draft/application/cms/src/core/hooks/cms_hook.e @@ -0,0 +1,10 @@ +note + description: "Summary description for {CMS_HOOK}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_HOOK + +end diff --git a/draft/application/cms/src/core/hooks/cms_hook_block.e b/draft/application/cms/src/core/hooks/cms_hook_block.e new file mode 100644 index 00000000..4f55b8b6 --- /dev/null +++ b/draft/application/cms/src/core/hooks/cms_hook_block.e @@ -0,0 +1,23 @@ +note + description: "Summary description for {CMS_HOOK_BLOCK}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_HOOK_BLOCK + +inherit + CMS_HOOK + +feature -- Hook + + block_list: ITERABLE [like {CMS_BLOCK}.name] + deferred + end + + get_block_view (a_block_id: detachable READABLE_STRING_8; a_execution: CMS_EXECUTION) + deferred + end + +end diff --git a/draft/application/cms/src/core/hooks/cms_hook_form_alter.e b/draft/application/cms/src/core/hooks/cms_hook_form_alter.e new file mode 100644 index 00000000..141430f5 --- /dev/null +++ b/draft/application/cms/src/core/hooks/cms_hook_form_alter.e @@ -0,0 +1,19 @@ +note + description: "Summary description for {CMS_HOOK_FORM_ALTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_HOOK_FORM_ALTER + +inherit + CMS_HOOK + +feature -- Hook + + form_alter (a_form: CMS_FORM; a_execution: CMS_EXECUTION) + deferred + end + +end diff --git a/draft/application/cms/src/core/hooks/cms_hook_menu_alter.e b/draft/application/cms/src/core/hooks/cms_hook_menu_alter.e new file mode 100644 index 00000000..b3737ab7 --- /dev/null +++ b/draft/application/cms/src/core/hooks/cms_hook_menu_alter.e @@ -0,0 +1,19 @@ +note + description: "Summary description for {CMS_HOOK_MENU_ALTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_HOOK_MENU_ALTER + +inherit + CMS_HOOK + +feature -- Hook + + menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) + deferred + end + +end diff --git a/draft/application/cms/src/core/kernel/api/cms_api_options.e b/draft/application/cms/src/core/kernel/api/cms_api_options.e new file mode 100644 index 00000000..e33c5164 --- /dev/null +++ b/draft/application/cms/src/core/kernel/api/cms_api_options.e @@ -0,0 +1,75 @@ +note + description: "Summary description for {CMS_API_OPTIONS}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_API_OPTIONS + +create + make, + make_from_manifest + +convert + make_from_manifest ({ ARRAY [TUPLE [key: STRING; value: detachable ANY]], + ARRAY [TUPLE [STRING_8, ARRAY [TUPLE [STRING_8, READABLE_STRING_32]]]] + }) + +feature {NONE} -- Initialization + + make (n: INTEGER) + do + create table.make (n) + end + + make_from_manifest (lst: ARRAY [TUPLE [key: STRING; value: detachable ANY]]) + do + make (lst.count) + across + lst as c + loop + force (c.item.value, c.item.key) + end + end + +feature -- Access + + item (k: STRING): detachable ANY + do + Result := table.item (k) + end + + force (v: detachable ANY; k: STRING) + do + table.force (v, k) + end + + boolean_item (k: STRING; dft: BOOLEAN): BOOLEAN + do + if attached {BOOLEAN} item (k) as b then + Result := b + else + Result := dft + end + end + + string_general_item (k: STRING): detachable READABLE_STRING_GENERAL + do + if attached {READABLE_STRING_GENERAL} item (k) as s then + Result := s + end + end + + string_item, string_8_item (k: STRING): detachable READABLE_STRING_8 + do + if attached {READABLE_STRING_8} item (k) as s then + Result := s + end + end + + table: HASH_TABLE [detachable ANY, STRING] + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/api/cms_common_api.e b/draft/application/cms/src/core/kernel/api/cms_common_api.e new file mode 100644 index 00000000..03855975 --- /dev/null +++ b/draft/application/cms/src/core/kernel/api/cms_common_api.e @@ -0,0 +1,204 @@ +note + description: "Summary description for {WSF_CMS_COMMON_API}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_COMMON_API + +feature {NONE} -- Access + + service: CMS_SERVICE + deferred + end + + base_url: detachable READABLE_STRING_8 + -- Base url if any. + deferred + end + + based_path (p: STRING): STRING + -- Path `p' in the context of the `base_url' + do + if attached base_url as l_base_url then + create Result.make_from_string (l_base_url) + Result.append (p) + else + Result := p + end + end + +feature -- Access + + url_encoded (s: detachable READABLE_STRING_GENERAL): STRING_8 + local + enc: URL_ENCODER + do + create enc + if s /= Void then + Result := enc.general_encoded_string (s) + else + create Result.make_empty + end + end + + html_encoded (s: detachable READABLE_STRING_GENERAL): STRING_8 + local + enc: HTML_ENCODER + do + create enc + if s /= Void then + Result := enc.general_encoded_string (s) + else + create Result.make_empty + end + end + + link (a_text: READABLE_STRING_GENERAL; a_path: STRING; opts: detachable CMS_API_OPTIONS): STRING + local + l_html: BOOLEAN + do + l_html := True + if opts /= Void then + l_html := opts.boolean_item ("html", l_html) + end + Result := "" + if l_html then + if attached {READABLE_STRING_8} a_text as t then + Result.append (t) + else + Result.append (a_text.to_string_8) + end + else + Result.append (checked_plain (a_text)) + end + Result.append ("") + end + + user_link (u: CMS_USER): like link + do + Result := link (u.name, "/user/" + u.id.out, Void) + end + + node_link (n: CMS_NODE): like link + do + Result := link (html_encoded (n.title), "/node/" + n.id.out, Void) + end + + user_url (u: CMS_USER): like url + do + Result := url ("/user/" + u.id.out, Void) + end + + node_url (n: CMS_NODE): like url + do + Result := url ("/node/" + n.id.out, Void) + end + + url (a_path: STRING; opts: detachable CMS_API_OPTIONS): STRING + local + q,f: detachable STRING_8 + l_abs: BOOLEAN + do + l_abs := False + + Result := based_path (a_path) + if opts /= Void then + l_abs := opts.boolean_item ("absolute", l_abs) + if attached opts.item ("query") as l_query then + if attached {READABLE_STRING_8} l_query as s_value then + q := s_value + elseif attached {ITERABLE [TUPLE [key, value: READABLE_STRING_GENERAL]]} l_query as lst then + create q.make_empty + across + lst as c + loop + if q.is_empty then + else + q.append_character ('&') + end + q.append (url_encoded (c.item.key)) + q.append_character ('=') + q.append (url_encoded (c.item.value)) + end + end + end + if attached opts.string_item ("fragment") as s_frag then + f := s_frag + end + end + if q /= Void then + Result.append ("?" + q) + end + if f /= Void then + Result.append ("#" + f) + end + if l_abs then + if Result.substring_index ("://", 1) = 0 then + Result.prepend (service.site_url) + end + end + end + + checked_url (a_url: STRING): STRING + do + Result := a_url + end + + checked_plain (a_text: READABLE_STRING_GENERAL): STRING_8 + do + Result := html_encoder.general_encoded_string (a_text) + end + +feature -- Helper + + is_empty (s: detachable READABLE_STRING_GENERAL): BOOLEAN + -- Is `s' is Void or empty ? + do + Result := s = Void or else s.is_empty + end + + unix_timestamp (dt: DATE_TIME): INTEGER_64 + do + Result := (create {HTTP_DATE_TIME_UTILITIES}).unix_time_stamp (dt) + end + + unix_timestamp_to_date_time (t: INTEGER_64): DATE_TIME + do + Result := (create {HTTP_DATE_TIME_UTILITIES}).unix_time_stamp_to_date_time (t) + end + + string_unix_timestamp_to_date_time (s: READABLE_STRING_8): DATE_TIME + do + if s.is_integer_64 then + Result := (create {HTTP_DATE_TIME_UTILITIES}).unix_time_stamp_to_date_time (s.to_integer_64) + else + Result := (create {HTTP_DATE_TIME_UTILITIES}).unix_time_stamp_to_date_time (0) + end + end + +feature {NONE} -- Implementation + + options_boolean (opts: HASH_TABLE [detachable ANY, STRING]; k: STRING; dft: BOOLEAN): BOOLEAN + do + if attached {BOOLEAN} opts.item (k) as h then + Result := h + else + Result := dft + end + end + + options_string (opts: HASH_TABLE [detachable ANY, STRING]; k: STRING): detachable STRING + do + if attached {STRING} opts.item (k) as s then + Result := s + end + end + + html_encoder: HTML_ENCODER + once ("thread") + create Result + end + +end diff --git a/draft/application/cms/src/core/kernel/api/cms_url_api_options.e b/draft/application/cms/src/core/kernel/api/cms_url_api_options.e new file mode 100644 index 00000000..5133d15a --- /dev/null +++ b/draft/application/cms/src/core/kernel/api/cms_url_api_options.e @@ -0,0 +1,25 @@ +note + description: "Summary description for {CMS_URL_API_OPTIONS}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_URL_API_OPTIONS + +inherit + CMS_API_OPTIONS + +create + make, + make_absolute + +feature {NONE} -- Initialization + + make_absolute + do + make (1) + force (True, "absolute") + end + +end diff --git a/draft/application/cms/src/core/kernel/auth/cms_auth_engine.e b/draft/application/cms/src/core/kernel/auth/cms_auth_engine.e new file mode 100644 index 00000000..47561f30 --- /dev/null +++ b/draft/application/cms/src/core/kernel/auth/cms_auth_engine.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {CMS_AUTH_ENGINE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_AUTH_ENGINE + +feature -- Status + + valid_credential (u,p: READABLE_STRING_32): BOOLEAN + deferred + end + +end diff --git a/draft/application/cms/src/core/kernel/auth/cms_storage_auth_engine.e b/draft/application/cms/src/core/kernel/auth/cms_storage_auth_engine.e new file mode 100644 index 00000000..1dc7b0ba --- /dev/null +++ b/draft/application/cms/src/core/kernel/auth/cms_storage_auth_engine.e @@ -0,0 +1,34 @@ +note + description: "Summary description for {CMS_STORAGE_AUTH_ENGINE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_STORAGE_AUTH_ENGINE + +inherit + CMS_AUTH_ENGINE + +create + make + +feature {NONE} -- Initialization + + make (a_storage: like storage) + do + storage := a_storage + end + + storage: CMS_STORAGE + +feature -- Status + + valid_credential (u,p: READABLE_STRING_32): BOOLEAN + do + if attached storage.user_by_name (u) as l_user then + Result := attached l_user.encoded_password as l_pass and then l_pass.same_string (storage.encoded_password (p)) + end + end + +end diff --git a/draft/application/cms/src/core/kernel/cms_html_page.e b/draft/application/cms/src/core/kernel/cms_html_page.e new file mode 100644 index 00000000..2ccc7405 --- /dev/null +++ b/draft/application/cms/src/core/kernel/cms_html_page.e @@ -0,0 +1,225 @@ +note + description: "Summary description for {CMS_HTML_PAGE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_HTML_PAGE + +create + make + +feature {NONE} -- Initialization + + make + do + create regions.make (5) + language := "en" + + status_code := {HTTP_STATUS_CODE}.ok + create header.make + create {ARRAYED_LIST [STRING]} head_lines.make (5) + header.put_content_type_text_html + end + +feature -- Status + + status_code: INTEGER + +feature -- Header + + header: HTTP_HEADER + +feature -- Region + + regions: HASH_TABLE [STRING_8, STRING_8] + -- header + -- content + -- footer + -- could have sidebar first, sidebar second, ... + + region (n: STRING_8): STRING_8 + do + if attached regions.item (n) as r then + Result := r + else + Result := "" + debug + Result := "{{" + n + "}}" + end + end + end + + html_head: STRING_8 + local + t: like title + lines: like head_lines + do + t := title + lines := head_lines + if t /= Void or else lines.count > 0 then + create Result.make (50) + if t /= Void then + Result.append ("" + t + "%N") + end + Result.append_character ('%N') + across + lines as l + loop + Result.append (l.item) + Result.append_character ('%N') + end + else + create Result.make_empty + end + end + + header_region: STRING_8 + do + Result := region ("header") + end + + content_region: STRING_8 + do + Result := region ("content") + end + + footer_region: STRING_8 + do + Result := region ("content") + end + +feature -- Element change + + add_to_region (s: STRING; k: STRING) + local + r: detachable STRING + do + r := regions.item (k) + if r = Void then + create r.make_from_string (s) + set_region (r, k) + else + r.append (s) + end + end + + add_to_header_region (s: STRING) + do + add_to_region (s, "header") + end + + add_to_content_region (s: STRING) + do + add_to_region (s, "content") + end + + add_to_footer_region (s: STRING) + do + add_to_region (s, "footer") + end + + set_region (s: STRING; k: STRING) + do + regions.force (s, k) + end + +-- set_header_region (s: STRING) +-- do +-- set_region (s, "header") +-- end + +-- set_content_region (s: STRING) +-- do +-- set_region (s, "content") +-- end + +-- set_footer_region (s: STRING) +-- do +-- set_region (s, "footer") +-- end + +feature -- Access + + title: detachable STRING + + language: STRING + + head_lines: LIST [STRING] + + head_lines_to_string: STRING + do + create Result.make_empty + across + head_lines as h + loop + Result.append (h.item) + Result.append_character ('%N') + end + end + +-- variables: HASH_TABLE [detachable ANY, STRING_8] + +feature -- Element change + + set_status_code (c: like status_code) + do + status_code := c + end + + set_language (s: like language) + do + language := s + end + + set_title (s: like title) + do + title := s + end + + add_meta_name_content (a_name: STRING; a_content: STRING) + local + s: STRING_8 + do + s := "" + head_lines.extend (s) + end + + add_meta_http_equiv (a_http_equiv: STRING; a_content: STRING) + local + s: STRING_8 + do + s := "" + head_lines.extend (s) + end + + add_style (a_href: STRING; a_media: detachable STRING) + local + s: STRING_8 + do + s := "") + head_lines.extend (s) + end + + add_javascript_url (a_src: STRING) + local + s: STRING_8 + do + s := "" + head_lines.extend (s) + end + + add_javascript_content (a_script: STRING) + local + s: STRING_8 + do + s := "" + head_lines.extend (s) + end + +end diff --git a/draft/application/cms/src/core/kernel/cms_session_controler.e b/draft/application/cms/src/core/kernel/cms_session_controler.e new file mode 100644 index 00000000..9a7eac2c --- /dev/null +++ b/draft/application/cms/src/core/kernel/cms_session_controler.e @@ -0,0 +1,134 @@ +note + description: "[ + Summary description for CMS_SESSION_CONTROLER. + ]" + date: "$Date$" + revision: "$Revision$" + +class + CMS_SESSION_CONTROLER + +inherit + ANY + + WSF_SESSION_FACTORY [WSF_SESSION] + +create + make + +feature -- Initialization + + make (req: WSF_REQUEST; a_mngr: like session_manager) + do + session_manager := a_mngr + initialize + create discarded_sessions.make + get_session (req) + end + + initialize + do + end + +feature -- Session access + + session: WSF_SESSION + + has_pending_session: BOOLEAN + + discarded_sessions: LINKED_LIST [like session] + +feature -- Session operation + + session_commit (page: CMS_HTML_PAGE_RESPONSE; e: CMS_EXECUTION) + do + if has_pending_session then + session.apply_to (page.header, e.request, e.request.script_url ("/")) + end + session.commit + end + + apply_sessions_to (h: HTTP_HEADER; req: WSF_REQUEST; a_path: detachable READABLE_STRING_8) + do + session.apply_to (h, req, a_path) + across + discarded_sessions as c + loop + c.item.apply_to (h, req, a_path) + end + end + + start_session (req: WSF_REQUEST) + -- Start a new session + local + s: like session + do + close_session (req) + s := new_session (req, False, session_manager) + req.set_execution_variable (session_request_variable_name, s) + session := s + if s.is_pending then + has_pending_session := True + end + ensure + session_attached: session /= Void + end + + get_session (req: WSF_REQUEST) + -- Get existing session, or start a new one + local + s: like session + do + if attached {like session} req.execution_variable (session_request_variable_name) as r_session then + session := r_session + else + s := new_session (req, True, session_manager) +-- create {CMS_SESSION} s.make (req, "_EWF_CMS_SESSID") + if s.is_pending then + has_pending_session := True + end + session := s + req.set_execution_variable (session_request_variable_name, s) + end + if session.expired then + start_session (req) + end + end + + close_session (req: WSF_REQUEST) + -- Close `session' if any + do + if session.is_pending then + has_pending_session := has_pending_session or not discarded_sessions.is_empty + else + has_pending_session := True + discarded_sessions.extend (session) + end + session.destroy + end + +feature -- Session internal + + session_manager: WSF_SESSION_MANAGER + + new_session (req: WSF_REQUEST; a_reuse: BOOLEAN; m: WSF_SESSION_MANAGER): like session + local + s: CMS_SESSION + dt: DATE_TIME + do + if a_reuse then + create s.make (req, session_id_name, m) + else + create s.make_new (session_id_name, m) + create dt.make_now_utc + dt.day_add (31) + s.set_expiration (dt) + end + Result := s + end + + session_request_variable_name: STRING = "_EWF_CMS_SESSION_" + + session_id_name: STRING = "_EWF_CMS_SESSID" + +end diff --git a/draft/application/cms/src/core/kernel/cms_user.e b/draft/application/cms/src/core/kernel/cms_user.e new file mode 100644 index 00000000..182447f8 --- /dev/null +++ b/draft/application/cms/src/core/kernel/cms_user.e @@ -0,0 +1,158 @@ +note + description: "Summary description for {CMS_USER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_USER + +inherit + DEBUG_OUTPUT + +create + make_new, + make + +feature {NONE} -- Initialization + + make (a_id: like id; n: like name; dt: like creation_date) + require + a_id > 0 + do + id := a_id + creation_date := dt + name := n + ensure + valid_password: password = Void and encoded_password /= Void + end + + make_new (n: like name) + do + name := n + create creation_date.make_now_utc + end + +feature -- Access + + is_admin: BOOLEAN + do + Result := id = 1 + end + + id: INTEGER + + name: STRING_8 + + password: detachable READABLE_STRING_32 + + encoded_password: detachable READABLE_STRING_8 + + email: detachable READABLE_STRING_8 + + profile: detachable CMS_USER_PROFILE + + creation_date: DATE_TIME + + last_login_date: detachable DATE_TIME + + data: detachable HASH_TABLE [detachable ANY, STRING] + + data_item (k: STRING): detachable ANY + do + if attached data as l_data then + Result := l_data.item (k) + end + end + +feature -- Status report + + has_id: BOOLEAN + do + Result := id > 0 + end + + has_email: BOOLEAN + do + Result := attached email as e and then not e.is_empty + end + + debug_output: STRING + do + Result := name + end + + same_as (u: detachable CMS_USER): BOOLEAN + do + Result := u /= Void and then id = u.id + end + +feature -- Element change + + set_id (a_id: like id) + do + id := a_id + end + + set_password (p: like password) + do + password := p + end + + set_encoded_password (p: like encoded_password) + do + encoded_password := p + end + + set_email (m: like email) + do + email := m + end + + set_profile (prof: like profile) + do + profile := prof + end + + set_data_item (k: READABLE_STRING_8; d: like data_item) + local + l_data: like data + do + l_data := data + if l_data = Void then + create l_data.make (1) + data := l_data + end + l_data.force (d, k) + end + + remove_data_item (k: READABLE_STRING_8) + do + if attached data as l_data then + l_data.remove (k) + end + end + + set_profile_item (k: READABLE_STRING_8; v: READABLE_STRING_8) + local + prof: like profile + do + prof := profile + if prof = Void then + create prof.make + profile := prof + end + prof.force (v, k) + end + + set_last_login_date (dt: like last_login_date) + do + last_login_date := dt + end + + set_last_login_date_now + do + set_last_login_date (create {DATE_TIME}.make_now_utc) + end + +end diff --git a/draft/application/cms/src/core/kernel/cms_user_profile.e b/draft/application/cms/src/core/kernel/cms_user_profile.e new file mode 100644 index 00000000..80d4b773 --- /dev/null +++ b/draft/application/cms/src/core/kernel/cms_user_profile.e @@ -0,0 +1,51 @@ +note + description: "Summary description for {CMS_USER_PROFILE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_USER_PROFILE + +inherit + TABLE_ITERABLE [READABLE_STRING_8, READABLE_STRING_8] + +create + make + +feature {NONE} -- Initialization + + make + do + create items.make (0) + end + +feature -- Access + + item (k: READABLE_STRING_8): detachable READABLE_STRING_8 + do + Result := items.item (k.as_string_8) + end + +feature -- Change + + force (v: READABLE_STRING_8; k: READABLE_STRING_8) + do + items.force (v, k.as_string_8) + end + +feature -- Access + + new_cursor: TABLE_ITERATION_CURSOR [READABLE_STRING_8, READABLE_STRING_8] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +feature {NONE} -- Implementation + + items: HASH_TABLE [READABLE_STRING_8, STRING_8] + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/content/cms_block.e b/draft/application/cms/src/core/kernel/content/cms_block.e new file mode 100644 index 00000000..a96c3bc9 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/cms_block.e @@ -0,0 +1,32 @@ +note + description: "Summary description for {CMS_BLOCK}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_BLOCK + +feature -- Access + + name: READABLE_STRING_8 + deferred + end + + title: detachable READABLE_STRING_32 + deferred + end + +feature -- status report + + is_enabled: BOOLEAN + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + deferred + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/content/cms_content_block.e b/draft/application/cms/src/core/kernel/content/cms_content_block.e new file mode 100644 index 00000000..f3f65c28 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/cms_content_block.e @@ -0,0 +1,46 @@ +note + description: "Summary description for {CMS_CONTENT_BLOCK}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_CONTENT_BLOCK + +inherit + CMS_BLOCK + +create + make + +feature {NONE} -- Initialization + + make (a_name: like name; a_title: like title; a_body: like body; a_format: like format) + do + is_enabled := True + name := a_name + title := a_title + body := a_body + format := a_format + end + +feature -- Access + + name: READABLE_STRING_8 + + title: detachable READABLE_STRING_32 + + body: READABLE_STRING_8 + + format: CMS_FORMAT + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + do + Result := format.to_html (body) + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/content/cms_content_type.e b/draft/application/cms/src/core/kernel/content/cms_content_type.e new file mode 100644 index 00000000..64438267 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/cms_content_type.e @@ -0,0 +1,60 @@ +note + description: "Summary description for {CMS_CONTENT_TYPE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_CONTENT_TYPE + +feature -- Access + + name: READABLE_STRING_8 + -- Internal name + deferred + end + + title: READABLE_STRING_8 + deferred + end + + description: detachable READABLE_STRING_8 + -- Optional description + deferred + end + + available_formats: LIST [CMS_FORMAT] + deferred + end + +feature -- Factory + + fill_edit_form (f: CMS_FORM; a_node: detachable CMS_NODE) + -- Fill the edit form `f' + deferred + end + + change_node (a_execution: CMS_EXECUTION; a_form_data: CMS_FORM_DATA; a_node: like new_node) + -- Apply data from `a_form_data' to a_node + require + a_node.has_id + deferred + end + + new_node (a_execution: CMS_EXECUTION; a_form_data: CMS_FORM_DATA; a_node: detachable like new_node): CMS_NODE + -- New content created with `a_form_data' + deferred + ensure + a_node /= Void implies a_node = Result + end + +feature {NONE} -- Implementation: helper + + formats: CMS_FORMATS + once + create Result + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/content/cms_menu_block.e b/draft/application/cms/src/core/kernel/content/cms_menu_block.e new file mode 100644 index 00000000..9d825726 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/cms_menu_block.e @@ -0,0 +1,45 @@ +note + description: "Summary description for {CMS_MENU_BLOCK}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_MENU_BLOCK + +inherit + CMS_BLOCK + +create + make + +feature {NONE} -- Initialization + + make (a_menu: like menu) + do + is_enabled := True + menu := a_menu + name := a_menu.name + title := a_menu.title + end + +feature -- Access + + menu: CMS_MENU + + name: READABLE_STRING_8 + + title: detachable READABLE_STRING_32 + + is_horizontal: BOOLEAN + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + do + Result := a_theme.menu_html (menu, is_horizontal) + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/content/cms_node.e b/draft/application/cms/src/core/kernel/content/cms_node.e new file mode 100644 index 00000000..545020b8 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/cms_node.e @@ -0,0 +1,101 @@ +note + description: "Summary description for {WSF_CMS_NODE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_NODE + +feature -- Access + + id: INTEGER + -- Unique identifier of Current. + + title: detachable READABLE_STRING_32 + -- Associated title (optional). + deferred + end + + body: detachable READABLE_STRING_8 + -- Body of Current. + deferred + end + + format: CMS_FORMAT + -- Format associated with `body' + deferred + end + + content_type_name: STRING + -- Associated content type name + deferred + end + +feature -- status report + + has_id: BOOLEAN + do + Result := id > 0 + end + +feature -- Access: status + + author: detachable CMS_USER + + creation_date: DATE_TIME + + modification_date: DATE_TIME + +feature -- Change + + set_id (a_id: like id) + require + not has_id + do + id := a_id + end + + set_author (u: like author) + do + author := u + end + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + local + d: STRING + do + Result := "
    " + if attached title as l_title then + Result.append ("
    " + a_theme.node_link (Current) + "
    ") + end + create d.make_empty + if attached author as u then + d.append ("by " + a_theme.user_link (u) + " ") + end + if attached modification_date as dt then + d.append ("last modified: " + dt.year.out + "/" + dt.month.out + "/" + dt.day.out + "") + end + if not d.is_empty then + Result.append ("
    ") + Result.append (d) + Result.append ("
    ") + end + if attached body as b then + Result.append ("
    ") + Result.append (format.to_html (b)) + Result.append ("
    ") + end + Result.append ("
    ") + end + +feature {NONE} -- Implementation: helper + + formats: CMS_FORMATS + once + create Result + end + +end diff --git a/draft/application/cms/src/core/kernel/content/format/cms_filtered_html_format.e b/draft/application/cms/src/core/kernel/content/format/cms_filtered_html_format.e new file mode 100644 index 00000000..43febb3e --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/cms_filtered_html_format.e @@ -0,0 +1,44 @@ +note + description : "[ + Filtered html format + ]" + date : "$Date$" + revision : "$Revision$" + +class + CMS_FILTERED_HTML_FORMAT + +inherit + CMS_FORMAT + redefine + default_create + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + create filters.make (3) + filters.force (create {CMS_URL_FILTER}) + filters.force (create {CMS_HTML_FILTER}) + filters.force (create {CMS_LINE_BREAK_CONVERTER_FILTER}) + +-- help := "
    • Web page addresses and e-mail addresses turn into links automatically.
    • Allowed HTML tags: " +-- across +-- allowed_html_tags as c +-- loop +-- help.append ("<" + c.item + "> ") +-- end +-- help.append ("
    • Lines and paragraphs break automatically.
    ") + end + +feature -- Access + + name: STRING = "filtered_html" + + title: STRING_8 = "Filtered HTML" + + filters: ARRAYED_LIST [CMS_FILTER] + +end diff --git a/draft/application/cms/src/core/kernel/content/format/cms_format.e b/draft/application/cms/src/core/kernel/content/format/cms_format.e new file mode 100644 index 00000000..fe9d8dd3 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/cms_format.e @@ -0,0 +1,46 @@ +note + description: "Summary description for {WSF_CMS_FORMAT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_FORMAT + +feature -- Access + + name: STRING + deferred + end + + title: READABLE_STRING_8 + deferred + end + + help: STRING + do + create Result.make (0) + across + filters as c + loop + if attached c.item.help as h and then not h.is_empty then + Result.append ("
  • " + h + "
  • ") + end + end + end + + filters: LIST [CMS_FILTER] + deferred + end + + to_html (a_text: READABLE_STRING_8): STRING_8 + do + create Result.make_from_string (a_text) + across + filters as c + loop + c.item.filter (Result) + end + end + +end diff --git a/draft/application/cms/src/core/kernel/content/format/cms_formats.e b/draft/application/cms/src/core/kernel/content/format/cms_formats.e new file mode 100644 index 00000000..5c82e097 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/cms_formats.e @@ -0,0 +1,54 @@ +note + description: "Summary description for {CMS_FORMATS}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORMATS + +feature -- Access + + format (a_name: like {CMS_FORMAT}.name): detachable CMS_FORMAT + do + across + all_formats as c + until + Result /= Void + loop + if c.item.name.same_string (a_name) then + Result := c.item + end + end + end + + all_formats: LIST [CMS_FORMAT] + once + create {ARRAYED_LIST [CMS_FORMAT]} Result.make (3) + Result.force (plain_text) + Result.force (full_html) + Result.force (filtered_html) + end + + default_format: CMS_FORMAT + do + Result := plain_text --FIXME + end + + plain_text: CMS_PLAIN_TEXT_FORMAT + once + create Result + end + + full_html: CMS_FULL_HTML_FORMAT + once + create Result + end + + filtered_html: CMS_FILTERED_HTML_FORMAT + once + create Result + end + + +end diff --git a/draft/application/cms/src/core/kernel/content/format/cms_full_html_format.e b/draft/application/cms/src/core/kernel/content/format/cms_full_html_format.e new file mode 100644 index 00000000..c486e975 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/cms_full_html_format.e @@ -0,0 +1,35 @@ +note + description : "[ + Full html format + ]" + date : "$Date$" + revision : "$Revision$" + +class + CMS_FULL_HTML_FORMAT + +inherit + CMS_FORMAT + redefine + default_create + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + create filters.make (2) + filters.force (create {CMS_URL_FILTER}) + filters.force (create {CMS_LINE_BREAK_CONVERTER_FILTER}) + end + +feature -- Access + + name: STRING = "full_html" + + title: STRING_8 = "Full HTML" + + filters: ARRAYED_LIST [CMS_FILTER] + +end diff --git a/draft/application/cms/src/core/kernel/content/format/cms_plain_text_format.e b/draft/application/cms/src/core/kernel/content/format/cms_plain_text_format.e new file mode 100644 index 00000000..76b05d4e --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/cms_plain_text_format.e @@ -0,0 +1,49 @@ +note + description : "[ + Plain Text format + ]" + date : "$Date$" + revision : "$Revision$" + +class + CMS_PLAIN_TEXT_FORMAT + +inherit + CMS_FORMAT + redefine + default_create, + help + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + create filters.make (2) + filters.force (create {CMS_HTML_TO_TEXT_FILTER}) + filters.force (create {CMS_LINE_BREAK_CONVERTER_FILTER}) + end + + +feature -- Access + + name: STRING = "plain_text" + + title: STRING_8 = "Plain text" + + help: STRING + do + Result := "
  • No HTML tags allowed.
  • " + Result.append (Precursor) + end +--
      +--
    • No HTML tags allowed.
    • +--
    • Web page addresses and e-mail addresses turn into links automatically.
    • +--
    • Lines and paragraphs break automatically.
    • +--
    +-- ]" + + filters: ARRAYED_LIST [CMS_FILTER] + +end diff --git a/draft/application/cms/src/core/kernel/content/format/filters/cms_filter.e b/draft/application/cms/src/core/kernel/content/format/filters/cms_filter.e new file mode 100644 index 00000000..1b49552a --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/filters/cms_filter.e @@ -0,0 +1,35 @@ +note + description: "Summary description for {CMS_FILTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_FILTER + +feature -- Access + + name: READABLE_STRING_8 + deferred + end + + title: READABLE_STRING_8 + deferred + end + + description: READABLE_STRING_8 + deferred + end + + help: READABLE_STRING_8 + do + Result := description + end + +feature -- Conversion + + filter (s: STRING_8) + deferred + end + +end diff --git a/draft/application/cms/src/core/kernel/content/format/filters/cms_html_filter.e b/draft/application/cms/src/core/kernel/content/format/filters/cms_html_filter.e new file mode 100644 index 00000000..6c8b2b9f --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/filters/cms_html_filter.e @@ -0,0 +1,126 @@ +note + description: "Summary description for {CMS_HTML_FILTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_HTML_FILTER + +inherit + CMS_FILTER + redefine + default_create + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + allowed_html_tags := <<"a", "em", "strong", "cite", "blockquote", "code", "ul", "ol", "li", "dl">> + description := "Allowed HTML tags: " + across + allowed_html_tags as c + loop + description.append ("<" + c.item + "> ") + end + end + +feature -- Access + + name: STRING_8 = "html_filter" + + title: STRING_8 = "HTML filter" + + description: STRING_8 + + allowed_html_tags: ITERABLE [READABLE_STRING_8] + +feature -- Conversion + + filter (a_text: STRING_8) + local + l_new: STRING_8 + i: INTEGER + n: INTEGER + in_tag: BOOLEAN + p1, p2: INTEGER + do + create l_new.make (a_text.count) + from + p1 := 1 + i := a_text.index_of ('<', 1) + if i > 0 then + l_new.append (a_text.substring (1, i - 1)) + end + n := a_text.count + until + i = 0 or i > n + loop + if a_text[i] = '<' then + in_tag := True + p1 := i + p2 := a_text.index_of ('>', i + 1) + if p2 = 0 then + -- next '<' + i := a_text.index_of ('<', i + 1) + if i > 0 then + l_new.append (a_text.substring (p1, i - 1)) + end + else + if is_authorized (a_text.substring (p1, p2)) then + l_new.append (a_text.substring (p1, p2)) + i := a_text.index_of ('<', p2 + 1) + else + i := a_text.index_of ('<', p2 + 1) + end + if i > 0 then + l_new.append (a_text.substring (p2 + 1, i - 1)) + end + end + else + i := i + 1 + end + end + l_new.append (a_text.substring (p1, n)) + a_text.wipe_out + a_text.append (l_new) + end + + is_authorized (s: READABLE_STRING_8): BOOLEAN + -- Is `s' authorized? + --| `s' has either "<....>" or "<..../>" or "" + local + l_tagname: detachable STRING + i,n,p1: INTEGER + do +-- create l_tagname.make_empty + from + i := 2 -- skip first '<' + n := s.count + until + i > n or l_tagname /= Void + loop + if p1 > 0 then + if s[i].is_space or s[i] = '/' or s[i] = '>' then + l_tagname := s.substring (p1, i - 1) + end + else + if s[i].is_space or s[i] = '/' then + else + p1 := i + end + end + i := i + 1 + end + if l_tagname /= Void then + l_tagname.to_lower + Result := across allowed_html_tags as c some c.item.same_string (l_tagname) end + else + Result := True + end + end + + +end diff --git a/draft/application/cms/src/core/kernel/content/format/filters/cms_html_to_text_filter.e b/draft/application/cms/src/core/kernel/content/format/filters/cms_html_to_text_filter.e new file mode 100644 index 00000000..ebc81bcd --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/filters/cms_html_to_text_filter.e @@ -0,0 +1,34 @@ +note + description: "Summary description for {CMS_HTML_TO_TEXT_FILTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_HTML_TO_TEXT_FILTER + +inherit + CMS_FILTER + +feature -- Access + + name: STRING_8 = "html_to_text" + + title: STRING_8 = "HTML to text" + + description: STRING_8 = "Replaces HTML tags and entities with plain text formatting, moving links at the end. This filter is just for text messages and it isn't safe for rendering content on a web page." + +feature -- Conversion + + filter (a_text: STRING_8) + local + enc: HTML_ENCODER + s: STRING_8 + do + create enc + s := enc.encoded_string (a_text) + a_text.wipe_out + a_text.append (s) + end + +end diff --git a/draft/application/cms/src/core/kernel/content/format/filters/cms_line_break_converter_filter.e b/draft/application/cms/src/core/kernel/content/format/filters/cms_line_break_converter_filter.e new file mode 100644 index 00000000..995cd267 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/filters/cms_line_break_converter_filter.e @@ -0,0 +1,34 @@ +note + description: "Summary description for {CMS_HTML_FILTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_LINE_BREAK_CONVERTER_FILTER + +inherit + CMS_FILTER + redefine + help + end + +feature -- Access + + name: STRING_8 = "line_break_converter" + + title: STRING_8 = "Line break converter" + + help: STRING = "Lines and paragraphs break automatically" + + description: STRING_8 = "Converts line breaks into HTML (i.e. <br> and <p> tags)." + +feature -- Conversion + + filter (a_text: STRING_8) + do + a_text.replace_substring_all ("%N", "
    %N") + -- FIXME jfiat [2012/09/12] :also use

    ... + end + +end diff --git a/draft/application/cms/src/core/kernel/content/format/filters/cms_no_html_filter.e b/draft/application/cms/src/core/kernel/content/format/filters/cms_no_html_filter.e new file mode 100644 index 00000000..8092bce2 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/filters/cms_no_html_filter.e @@ -0,0 +1,77 @@ +note + description: "Summary description for {CMS_NO_HTML_FILTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_NO_HTML_FILTER + +inherit + CMS_FILTER + redefine + default_create + end + +feature {NONE} -- Initialization + + default_create + do + Precursor + end + +feature -- Access + + name: STRING_8 = "no_html_filter" + + title: STRING_8 = "No HTML filter" + + description: STRING_8 = "HTML tags removed! " + +feature -- Conversion + + filter (a_text: STRING_8) + local + l_new: STRING_8 + i: INTEGER + n: INTEGER + in_tag: BOOLEAN + p1, p2: INTEGER + do + create l_new.make (a_text.count) + from + p1 := 1 + i := a_text.index_of ('<', 1) + if i > 0 then + l_new.append (a_text.substring (1, i - 1)) + end + n := a_text.count + until + i = 0 or i > n + loop + if a_text[i] = '<' then + in_tag := True + p1 := i + p2 := a_text.index_of ('>', i + 1) + if p2 = 0 then + -- next '<' + i := a_text.index_of ('<', i + 1) + if i > 0 then + l_new.append (a_text.substring (p1, i - 1)) + end + else + i := a_text.index_of ('<', p2 + 1) + if i > 0 then + l_new.append (a_text.substring (p2 + 1, i - 1)) + end + end + else + i := i + 1 + end + end + l_new.append (a_text.substring (p1, n)) + a_text.wipe_out + a_text.append (l_new) + end + +end diff --git a/draft/application/cms/src/core/kernel/content/format/filters/cms_url_filter.e b/draft/application/cms/src/core/kernel/content/format/filters/cms_url_filter.e new file mode 100644 index 00000000..a53be807 --- /dev/null +++ b/draft/application/cms/src/core/kernel/content/format/filters/cms_url_filter.e @@ -0,0 +1,33 @@ +note + description: "Summary description for {CMS_URL_FILTER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_URL_FILTER + +inherit + CMS_FILTER + redefine + help + end + +feature -- Access + + name: STRING_8 = "url" + + title: STRING_8 = "URL filter" + + description: STRING_8 = "Turns web and e-mail addresses into clickable links." + + help: STRING = "Web page addresses and e-mail addresses turn into links automatically." + +feature -- Conversion + + filter (a_text: STRING_8) + do + --| FIXME jfiat [2012/09/12] : todo + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form.e b/draft/application/cms/src/core/kernel/form/cms_form.e new file mode 100644 index 00000000..4065d98e --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form.e @@ -0,0 +1,166 @@ +note + description: "Summary description for {CMS_FORM}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM + +inherit + ITERABLE [CMS_FORM_ITEM] + +create + make + +feature {NONE} -- Initialization + + make (a_action: READABLE_STRING_8; a_id: READABLE_STRING_8) + do + action := a_action + id := a_id + + create html_classes.make (2) + create items.make (10) + end + +feature -- Access + + action: READABLE_STRING_8 + -- URL for the web form + + id: READABLE_STRING_8 + -- Id of the form + + count: INTEGER + do + Result := items.count + end + +feature -- Validation + + validation_action: detachable PROCEDURE [ANY, TUPLE [CMS_FORM_DATA]] + -- Procedure to validate the data + -- report error if not valid + +-- submit_callbacks_actions: HASH_TABLE [PROCEDURE [ANY, TUPLE [CMS_FORM_DATA]], STRING] +-- -- Submit callbacks indexed by submit names + +feature -- Element change + + set_validation_action (act: like validation_action) + do + validation_action := act + end + +feature -- Access + + new_cursor: ITERATION_CURSOR [CMS_FORM_ITEM] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +feature -- Optional + + html_classes: ARRAYED_LIST [STRING_8] + +feature -- Items + + has_field (a_name: READABLE_STRING_GENERAL): BOOLEAN + do + Result := across items as i some attached {CMS_FORM_FIELD} i.item as l_field and then l_field.name.same_string_general (a_name) end + end + +-- items_by_name (a_name: READABLE_STRING_GENERAL): detachable LIST [CMS_FORM_ITEM] +-- local +-- res: detachable ARRAYED_LIST [CMS_FORM_ITEM] +-- do +-- across +-- items as c +-- loop +-- if c.item.name.same_string_general (a_name) then +-- if res = Void then +-- create res.make (1) +-- end +-- res.force (c.item) +-- end +-- end +-- Result := res +-- end + + fields_by_name (a_name: READABLE_STRING_GENERAL): detachable LIST [CMS_FORM_FIELD] + local + res: detachable ARRAYED_LIST [CMS_FORM_FIELD] + do + across + items as c + loop + if + attached {CMS_FORM_FIELD} c.item as l_field and then + l_field.name.same_string_general (a_name) + then + if res = Void then + create res.make (1) + end + res.force (l_field) + end + end + Result := res + end + + extend (i: CMS_FORM_ITEM) + local + n: READABLE_STRING_8 + do + if attached {CMS_FORM_FIELD} i as l_field then + n := l_field.name + if n.is_empty then + n := (items.count + 1).out + l_field.update_name (n) + end + end + items.force (i) + end + + extend_text (t: READABLE_STRING_8) + do + extend (create {CMS_FORM_RAW_TEXT}.make (t)) + end + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + local + s: STRING + do + Result := "

    %N") + across + items as c + loop + Result.append (c.item.to_html (a_theme)) + end + Result.append ("
    %N") + end + +feature {NONE} -- Implementation + + items: ARRAYED_LIST [CMS_FORM_ITEM] + -- name => item + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_button_input.e b/draft/application/cms/src/core/kernel/form/cms_form_button_input.e new file mode 100644 index 00000000..e7937122 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_button_input.e @@ -0,0 +1,20 @@ +note + description: "Summary description for {CMS_FORM_BUTTON_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_BUTTON_INPUT + +inherit + CMS_FORM_INPUT + +create + make + +feature -- Access + + input_type: STRING = "button" + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_checkbox_input.e b/draft/application/cms/src/core/kernel/form/cms_form_checkbox_input.e new file mode 100644 index 00000000..42b35165 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_checkbox_input.e @@ -0,0 +1,46 @@ +note + description: "Summary description for {CMS_FORM_CHECKBOX_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_CHECKBOX_INPUT + +inherit + CMS_FORM_INPUT + redefine + specific_input_attributes_string + end + +create + make + +feature -- Access + + checked: BOOLEAN + -- Current element should be preselected when the page loads + + input_type: STRING = "checkbox" + +feature -- Change + + set_checked (b: like checked) + do + checked := b + end + +feature {NONE} -- Implementation + + specific_input_attributes_string: detachable STRING_8 + -- Specific input attributes if any. + -- To redefine if needed + do + if checked then + Result := "checked=%"checked%"" + end + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_data.e b/draft/application/cms/src/core/kernel/form/cms_form_data.e new file mode 100644 index 00000000..cf6ebdf2 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_data.e @@ -0,0 +1,195 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + CMS_FORM_DATA + +inherit + TABLE_ITERABLE [detachable WSF_VALUE, READABLE_STRING_8] + +create + make + +feature {NONE} -- Initialization + + make (req: WSF_REQUEST; a_form: CMS_FORM) + -- Initialize `Current'. + do + form := a_form + create items.make (a_form.count) + get_items (req) + validate + end + +feature -- Access + + form: CMS_FORM + +feature -- Status + + is_valid: BOOLEAN + do + Result := errors = Void + end + +feature -- Access + + item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE + do + Result := items.item (a_name.as_string_8) + end + + string_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + do + if attached {WSF_STRING} item (a_name) as s then + Result := s.value + end + end + + integer_item (a_name: READABLE_STRING_GENERAL): INTEGER + do + if attached {WSF_STRING} item (a_name) as s and then s.is_integer then + Result := s.integer_value + end + end + + new_cursor: TABLE_ITERATION_CURSOR [detachable WSF_VALUE, READABLE_STRING_8] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +feature -- Basic operation + + validate + do + across + form as f + loop + if attached {CMS_FORM_FIELD} f.item as l_field then + l_field.validate (Current) + end + end + if attached form.validation_action as act then + act.call ([Current]) + end + end + + set_fields_invalid (b: BOOLEAN; a_name: READABLE_STRING_GENERAL) + do + if attached form.fields_by_name (a_name) as lst then + across + lst as i + loop + i.item.set_is_invalid (b) + end + end + end + + apply_to_associated_form + do + if attached errors as errs then + across + errs as e + loop + if attached e.item as err then + if attached err.field as e_field then + set_fields_invalid (True, e_field.name) + end + end + end + end + across + items as c + loop + across + form as i + loop + if attached {CMS_FORM_FIELD} i.item as l_field then + if not attached {CMS_FORM_SUBMIT_INPUT} l_field then + if l_field.name.same_string (c.key) then + l_field.set_value (c.item) + end + end + end + end + end + end + +feature -- Change + + report_error (a_msg: READABLE_STRING_8) + do + add_error (Void, a_msg) + ensure + is_invalid: not is_valid + end + + report_invalid_field (a_field_name: READABLE_STRING_8; a_msg: READABLE_STRING_8) + require + has_field: form.has_field (a_field_name) + do + if attached form.fields_by_name (a_field_name) as lst then + across + lst as c + loop + add_error (c.item, a_msg) + end + end + ensure + is_invalid: not is_valid + end + +feature {NONE} -- Implementation + + get_items (req: WSF_REQUEST) + do + get_form_items (req, form) + end + + get_form_items (req: WSF_REQUEST; lst: ITERABLE [CMS_FORM_ITEM]) + local + n: READABLE_STRING_8 + v: detachable WSF_VALUE + do + across + lst as c + loop + if attached {CMS_FORM_FIELD} c.item as l_field then + n := l_field.name + v := req.form_parameter (n) + if l_field.is_required and (v = Void or else v.is_empty) then + add_error (l_field, "Field %"" + l_field.name + "%" is required") + else + items.force (v, n) + end + elseif attached {CMS_FORM_FIELD_SET} c.item as l_fieldset then + get_form_items (req, l_fieldset) + end + end + end + + add_error (a_field: detachable CMS_FORM_FIELD; a_msg: detachable READABLE_STRING_8) + local + err: like errors + do + err := errors + if err = Void then + create err.make (1) + errors := err + end + err.force ([a_field, a_msg]) + end + + items: HASH_TABLE [detachable WSF_VALUE, READABLE_STRING_8] + +feature -- Reports + + errors: detachable ARRAYED_LIST [TUPLE [field: detachable CMS_FORM_FIELD; message: detachable READABLE_STRING_8]] + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_field.e b/draft/application/cms/src/core/kernel/form/cms_form_field.e new file mode 100644 index 00000000..17ebf9da --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_field.e @@ -0,0 +1,133 @@ +note + description: "Summary description for {CMS_FORM_ITEM}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_FORM_FIELD + +inherit + CMS_FORM_ITEM + + DEBUG_OUTPUT + +feature -- Access + + name: READABLE_STRING_8 + + label: detachable READABLE_STRING_8 + + description: detachable READABLE_STRING_8 + + is_required: BOOLEAN + + is_invalid: BOOLEAN + + is_readonly: BOOLEAN + + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := name + " {" + generator + "}" + end + +feature -- Validation + + validation_action: detachable PROCEDURE [ANY, TUPLE [CMS_FORM_DATA]] + -- Function returning True if valid, otherwise False + + validate (fd: CMS_FORM_DATA) + do + if attached validation_action as act then + act.call ([fd]) + end + end + +feature -- Element change + + update_name (a_name: like name) + require + name.is_empty + do + name := a_name + end + + set_is_required (b: BOOLEAN) + do + is_required := b + end + + set_is_readonly (b: BOOLEAN) + do + is_readonly := b + end + + set_label (lab: like label) + do + label := lab + end + + set_description (t: like description) + do + description := t + end + + set_validation_action (act: like validation_action) + do + validation_action := act + end + + set_is_invalid (b: BOOLEAN) + do + is_invalid := b + end + + set_value (v: detachable WSF_VALUE) + -- Set value `v' if applicable to Current + deferred + end + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + local + cl: STRING + do + create cl.make_empty + if is_required then + if not cl.is_empty then + cl.append_character (' ') + end + cl.append ("required") + end + if is_invalid then + if not cl.is_empty then + cl.append_character (' ') + end + cl.append ("error") + end + create Result.make_from_string ("
    ") + if attached label as lab then + Result.append ("") + if is_required then + Result.append (" (required)") + end + Result.append ("
    %N") + end + Result.append (item_to_html (a_theme)) + if attached description as desc then + Result.append ("
    " + desc + "
    ") + end + Result.append ("
    ") + end + + item_to_html (a_theme: CMS_THEME): STRING_8 + deferred + end + + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_field_set.e b/draft/application/cms/src/core/kernel/form/cms_form_field_set.e new file mode 100644 index 00000000..9b3588b7 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_field_set.e @@ -0,0 +1,70 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + CMS_FORM_FIELD_SET + +inherit + CMS_FORM_ITEM + + ITERABLE [CMS_FORM_ITEM] + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + do + create items.make (0) + end + +feature -- Access + + legend: detachable READABLE_STRING_8 + +feature -- Access + + new_cursor: ITERATION_CURSOR [CMS_FORM_ITEM] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +feature -- Change + + set_legend (v: like legend) + do + legend := v + end + + extend (i: CMS_FORM_ITEM) + do + items.force (i) + end + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + do + Result := "
    %N" + if attached legend as leg then + Result.append ("" + leg + "%N") + end + across + items as c + loop + Result.append (c.item.to_html (a_theme)) + end + Result.append ("%N
    %N") + end + +feature {NONE} -- Implementation + + items: ARRAYED_LIST [CMS_FORM_ITEM] + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_file_input.e b/draft/application/cms/src/core/kernel/form/cms_form_file_input.e new file mode 100644 index 00000000..df257456 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_file_input.e @@ -0,0 +1,46 @@ +note + description: "Summary description for {CMS_FORM_FILE_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_FILE_INPUT + +inherit + CMS_FORM_INPUT + redefine + specific_input_attributes_string + end + +create + make + +feature -- Access + + input_type: STRING = "file" + + accepted_types: detachable READABLE_STRING_8 + -- Types of files that the server accepts + +feature -- Change + + set_accepted_types (v: like accepted_types) + do + accepted_types := v + end + +feature {NONE} -- Implementation + + specific_input_attributes_string: detachable STRING_8 + -- Specific input attributes if any. + -- To redefine if needed + do + if attached accepted_types as l_accepted_types then + Result := " accept=%"" + l_accepted_types + "%"" + end + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_hidden_input.e b/draft/application/cms/src/core/kernel/form/cms_form_hidden_input.e new file mode 100644 index 00000000..20272d4f --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_hidden_input.e @@ -0,0 +1,36 @@ +note + description: "Summary description for {CMS_FORM_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_HIDDEN_INPUT + +inherit + CMS_FORM_INPUT + redefine + input_type, + item_to_html + end + +create + make + +feature -- Access + + input_type: STRING + once + Result := "hidden" + end + +feature -- Conversion + + item_to_html (a_theme: CMS_THEME): STRING_8 + do + Result := "
    " + Result.append (Precursor (a_theme)) + Result.append ("
    ") + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_image_input.e b/draft/application/cms/src/core/kernel/form/cms_form_image_input.e new file mode 100644 index 00000000..f3d1860d --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_image_input.e @@ -0,0 +1,58 @@ +note + description: "Summary description for {CMS_FORM_IMAGE_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_IMAGE_INPUT + +inherit + CMS_FORM_INPUT + redefine + specific_input_attributes_string + end + +create + make + +feature -- Access + + input_type: STRING = "image" + + src: detachable READABLE_STRING_8 + -- Specifies the URL of the image to use as a submit button + + alt: detachable READABLE_STRING_8 + -- Alternate text for an image. + +feature -- Change + + set_src (v: like src) + do + src := v + end + + set_alt (v: like alt) + do + alt := v + end + +feature {NONE} -- Implementation + + specific_input_attributes_string: detachable STRING_8 + -- Specific input attributes if any. + -- To redefine if needed + do + create Result.make_empty + if attached src as l_src then + Result.append (" src=%"" + l_src + "%"") + end + if attached alt as l_alt then + Result.append (" alt=%"" + l_alt + "%"") + end + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_input.e b/draft/application/cms/src/core/kernel/form/cms_form_input.e new file mode 100644 index 00000000..fae1353d --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_input.e @@ -0,0 +1,109 @@ +note + description: "Summary description for {CMS_FORM_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_FORM_INPUT + +inherit + CMS_FORM_FIELD + +feature {NONE} -- Initialization + + make (a_name: like name) + do + name := a_name + end + +feature -- Access + + default_value: detachable READABLE_STRING_32 + + size: INTEGER + -- Width, in characters, of an element. + + maxlength: INTEGER + -- Maximum number of characters allowed in an element. + + disabled: BOOLEAN + -- Current element should be disabled? + + input_type: STRING + deferred + end + +feature -- Element change + + set_text_value (s: detachable READABLE_STRING_32) + do + set_default_value (s) + end + + set_size (i: like size) + do + size := i + end + + set_maxlength (i: like maxlength) + do + maxlength := i + end + + set_disabled (b: like disabled) + do + disabled := b + end + + set_value (v: detachable WSF_VALUE) + do + if attached {WSF_STRING} v as s then + set_text_value (s.value) + else + set_text_value (Void) + end + end + + set_default_value (v: like default_value) + do + default_value := v + end + +feature -- Conversion + + item_to_html (a_theme: CMS_THEME): STRING_8 + do + Result := " 0 then + Result.append (" size=%"" + size.out + "%"") + end + if maxlength > 0 then + Result.append (" maxlength=%"" + maxlength.out + "%"") + end + + if attached specific_input_attributes_string as s then + Result.append_character (' ') + Result.append (s) + end + Result.append ("/>") + end + +feature {NONE} -- Implementation + + specific_input_attributes_string: detachable STRING_8 + -- Specific input attributes if any. + --| To redefine if needed + do + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_item.e b/draft/application/cms/src/core/kernel/form/cms_form_item.e new file mode 100644 index 00000000..0dafeb60 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_item.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {CMS_FORM_ITEM}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_FORM_ITEM + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + deferred + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_password_input.e b/draft/application/cms/src/core/kernel/form/cms_form_password_input.e new file mode 100644 index 00000000..2949ca44 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_password_input.e @@ -0,0 +1,26 @@ +note + description: "Summary description for {CMS_FORM_PASSWORD_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_PASSWORD_INPUT + +inherit + CMS_FORM_INPUT + redefine + input_type + end + +create + make + +feature -- Access + + input_type: STRING + once + Result := "password" + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_radio_input.e b/draft/application/cms/src/core/kernel/form/cms_form_radio_input.e new file mode 100644 index 00000000..f5c10a52 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_radio_input.e @@ -0,0 +1,46 @@ +note + description: "Summary description for {CMS_FORM_RADIO_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_RADIO_INPUT + +inherit + CMS_FORM_INPUT + redefine + specific_input_attributes_string + end + +create + make + +feature -- Access + + checked: BOOLEAN + -- Current element should be preselected when the page loads + + input_type: STRING = "radio" + +feature -- Change + + set_checked (b: like checked) + do + checked := b + end + +feature {NONE} -- Implementation + + specific_input_attributes_string: detachable STRING_8 + -- Specific input attributes if any. + -- To redefine if needed + do + if checked then + Result := "checked=%"checked%"" + end + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_raw_text.e b/draft/application/cms/src/core/kernel/form/cms_form_raw_text.e new file mode 100644 index 00000000..bd5df16f --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_raw_text.e @@ -0,0 +1,49 @@ +note + description: "Summary description for {CMS_FORM_RAW_TEXT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_RAW_TEXT + +inherit + CMS_FORM_ITEM + redefine + to_html + end + +create + make + +feature {NONE} -- Initialization + + make (a_text: like text) + do + text := a_text + end + +feature -- Access + + text: READABLE_STRING_8 + +feature -- Element change + + set_value (v: detachable WSF_VALUE) + do + -- Not applicable + end + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + do + Result := item_to_html (a_theme) + end + + item_to_html (a_theme: CMS_THEME): STRING_8 + do + Result := text + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_reset_input.e b/draft/application/cms/src/core/kernel/form/cms_form_reset_input.e new file mode 100644 index 00000000..d652d66b --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_reset_input.e @@ -0,0 +1,20 @@ +note + description: "Summary description for {CMS_FORM_RESET_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_RESET_INPUT + +inherit + CMS_FORM_INPUT + +create + make + +feature -- Access + + input_type: STRING = "reset" + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_select.e b/draft/application/cms/src/core/kernel/form/cms_form_select.e new file mode 100644 index 00000000..e8b5375b --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_select.e @@ -0,0 +1,116 @@ +note + description: "Summary description for {CMS_FORM_SELECT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_SELECT + +inherit + CMS_FORM_FIELD + +create + make + +feature {NONE} -- Initialization + + make (a_name: like name) + do + name := a_name + create options.make (0) + end + +feature -- Access + + options: ARRAYED_LIST [CMS_FORM_SELECT_OPTION] + +feature -- Element change + + set_text_value (v: detachable like {CMS_FORM_SELECT_OPTION}.value) + local + opt: CMS_FORM_SELECT_OPTION + l_found: BOOLEAN + do + if v /= Void then + across + options as o + loop + -- FIXME: unicode ... + if o.item.value.same_string (v) then + l_found := True + o.item.set_is_selected (True) + else + o.item.set_is_selected (False) + end + end + if not l_found then + create opt.make (v, Void) + opt.set_is_selected (True) + add_option (opt) + end + else + across + options as o + loop + o.item.set_is_selected (False) + end + end + end + + set_value (v: detachable WSF_VALUE) + do + if attached {WSF_STRING} v as s then + set_text_value (s.value) + else + set_text_value (Void) + end + end + + add_option (opt: CMS_FORM_SELECT_OPTION) + do + options.force (opt) + end + +feature -- Conversion + + item_to_html (a_theme: CMS_THEME): STRING_8 + local + l_is_already_selected: BOOLEAN + h: detachable STRING_8 + do + Result := "%N") + if h /= Void then + Result.append ("
    " + h + "
    %N") + end + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_select_option.e b/draft/application/cms/src/core/kernel/form/cms_form_select_option.e new file mode 100644 index 00000000..441142a0 --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_select_option.e @@ -0,0 +1,50 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + CMS_FORM_SELECT_OPTION + +create + make + +feature {NONE} -- Initialization + + make (a_value: like value; a_text: detachable like text) + -- Initialize `Current'. + do + value := a_value + if a_text = Void then + text := a_value + else + text := a_text + end + end + +feature -- Status + + is_selected: BOOLEAN + +feature -- Access + + value: READABLE_STRING_8 + + text: READABLE_STRING_8 + + description: detachable READABLE_STRING_8 + +feature -- Change + + set_is_selected (b: like is_selected) + do + is_selected := b + end + + set_description (d: like description) + do + description := d + end + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_submit_input.e b/draft/application/cms/src/core/kernel/form/cms_form_submit_input.e new file mode 100644 index 00000000..1eac86ec --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_submit_input.e @@ -0,0 +1,20 @@ +note + description: "Summary description for {CMS_FORM_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_SUBMIT_INPUT + +inherit + CMS_FORM_INPUT + +create + make + +feature -- Access + + input_type: STRING = "submit" + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_text_input.e b/draft/application/cms/src/core/kernel/form/cms_form_text_input.e new file mode 100644 index 00000000..26221cae --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_text_input.e @@ -0,0 +1,20 @@ +note + description: "Summary description for {CMS_FORM_TEXT_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_TEXT_INPUT + +inherit + CMS_FORM_INPUT + +create + make + +feature -- Access + + input_type: STRING = "text" + +end diff --git a/draft/application/cms/src/core/kernel/form/cms_form_textarea.e b/draft/application/cms/src/core/kernel/form/cms_form_textarea.e new file mode 100644 index 00000000..f64bb4dd --- /dev/null +++ b/draft/application/cms/src/core/kernel/form/cms_form_textarea.e @@ -0,0 +1,85 @@ +note + description: "Summary description for {CMS_FORM_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_FORM_TEXTAREA + +inherit + CMS_FORM_FIELD + +create + make + +feature {NONE} -- Initialization + + make (a_name: like name) + do + name := a_name + end + +feature -- Access + + default_value: detachable READABLE_STRING_GENERAL + + rows: INTEGER + + cols: INTEGER + +feature -- Element change + + set_rows (i: like rows) + do + rows := i + end + + set_cols (i: like cols) + do + cols := i + end + + set_text_value (s: like default_value) + do + set_default_value (s) + end + + set_value (v: detachable WSF_VALUE) + do + if attached {WSF_STRING} v as s then + set_text_value (s.value) + else + set_text_value (Void) + end + end + + set_default_value (v: like default_value) + do + default_value := v + end + +feature -- Conversion + + item_to_html (a_theme: CMS_THEME): STRING_8 + do + Result := "") + end + +end diff --git a/draft/application/cms/src/core/kernel/link/cms_external_link.e b/draft/application/cms/src/core/kernel/link/cms_external_link.e new file mode 100644 index 00000000..a73d9638 --- /dev/null +++ b/draft/application/cms/src/core/kernel/link/cms_external_link.e @@ -0,0 +1,36 @@ +note + description: "Summary description for {CMS_EXTERNAL_MENU}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_EXTERNAL_LINK + +inherit + CMS_LINK + +create + make + +feature {NONE} -- Initialization + + make (a_title: like title; a_location: like location) + do + title := a_title + location := a_location + end + +feature -- Status report + + is_active: BOOLEAN = False + + is_expanded: BOOLEAN = False + + is_expandable: BOOLEAN = False + + children: detachable LIST [CMS_LINK] + do + end + +end diff --git a/draft/application/cms/src/core/kernel/link/cms_link.e b/draft/application/cms/src/core/kernel/link/cms_link.e new file mode 100644 index 00000000..c9b37941 --- /dev/null +++ b/draft/application/cms/src/core/kernel/link/cms_link.e @@ -0,0 +1,43 @@ +note + description: "Summary description for {CMS_MENU}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_LINK + +inherit + REFACTORING_HELPER + +feature -- Access + + title: READABLE_STRING_32 + + location: READABLE_STRING_8 + + options: detachable CMS_API_OPTIONS + +feature -- status report + + is_active: BOOLEAN + deferred + end + + is_expanded: BOOLEAN + deferred + end + + is_expandable: BOOLEAN + deferred + end + +feature -- Query + + parent: detachable CMS_LINK + + children: detachable LIST [CMS_LINK] + deferred + end + +end diff --git a/draft/application/cms/src/core/kernel/link/cms_local_link.e b/draft/application/cms/src/core/kernel/link/cms_local_link.e new file mode 100644 index 00000000..152c89ab --- /dev/null +++ b/draft/application/cms/src/core/kernel/link/cms_local_link.e @@ -0,0 +1,72 @@ +note + description: "Summary description for {CMS_LOCAL_MENU}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_LOCAL_LINK + +inherit + CMS_LINK + +create + make + +feature {NONE} -- Initialization + + make (a_title: detachable like title; a_location: like location) + do + if a_title /= Void then + title := a_title + else + title := a_location + end + location := a_location + end + +feature -- Status report + + is_active: BOOLEAN + + is_expanded: BOOLEAN + + is_expandable: BOOLEAN + + permission_arguments: detachable ITERABLE [STRING] + + children: detachable LIST [CMS_LINK] + +feature -- Element change + + set_children (lst: like children) + do + children := lst + end + + set_expanded (b: like is_expanded) + do + is_expanded := b + end + + set_expandable (b: like is_expandable) + do + is_expandable := b + end + + get_is_active (req: WSF_REQUEST) + do + is_active := req.path_info.same_string (location) + end + + set_permission_arguments (args: ITERABLE [STRING]) + do + permission_arguments := args + end + + set_options (opts: like options) + do + options := opts + end + +end diff --git a/draft/application/cms/src/core/kernel/link/cms_menu.e b/draft/application/cms/src/core/kernel/link/cms_menu.e new file mode 100644 index 00000000..67b6bbb2 --- /dev/null +++ b/draft/application/cms/src/core/kernel/link/cms_menu.e @@ -0,0 +1,73 @@ +note + description: "Summary description for {CMS_MENU}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_MENU + +inherit + ITERABLE [CMS_LINK] + +create + make, + make_with_title + +feature {NONE} -- Initialization + + make (a_name: like name; n: INTEGER) + do + name := a_name + create items.make (n) + end + + make_with_title (a_name: like name; a_title: READABLE_STRING_32; n: INTEGER) + do + make (a_name, n) + set_title (a_title) + end + +feature -- Access + + name: READABLE_STRING_8 + + title: detachable READABLE_STRING_32 + + items: ARRAYED_LIST [CMS_LINK] + + extend (lnk: CMS_LINK) + do + items.extend (lnk) + end + + remove (lnk: CMS_LINK) + do + items.prune_all (lnk) + end + +feature -- status report + + is_empty: BOOLEAN + do + Result := items.is_empty + end + +feature -- Element change + + set_title (t: like title) + do + title := t + end + +feature -- Access + + new_cursor: ITERATION_CURSOR [CMS_LINK] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/link/cms_menu_system.e b/draft/application/cms/src/core/kernel/link/cms_menu_system.e new file mode 100644 index 00000000..095c70a6 --- /dev/null +++ b/draft/application/cms/src/core/kernel/link/cms_menu_system.e @@ -0,0 +1,88 @@ +note + description: "Summary description for {CMS_MENU_SYSTEM}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_MENU_SYSTEM + +inherit + ITERABLE [CMS_MENU] + +create + make + +feature {NONE} -- Initialization + + make + do + create items.make (5) + force (create {CMS_MENU}.make ("main-menu", 3)) + force (create {CMS_MENU}.make_with_title ("management", "Management", 3)) + force (create {CMS_MENU}.make_with_title ("navigation", "Navigation", 3)) + force (create {CMS_MENU}.make_with_title ("user", "User", 3)) + end + +feature -- Access + + item (n: like {CMS_MENU}.name): CMS_MENU + local + m: detachable CMS_MENU + do + m := items.item (n) + if m = Void then + create m.make (n, 3) + force (m) + end + Result := m + end + + main_menu: CMS_MENU + do + Result := item ("main-menu") + end + + management_menu: CMS_MENU + do + Result := item ("management") + end + + navigation_menu: CMS_MENU + do + Result := item ("navigation") + end + + user_menu: CMS_MENU + do + Result := item ("user") + end + + primary_tabs: CMS_MENU + do + Result := item ("primary-tabs") + end + +feature -- Change + + force (m: CMS_MENU) + do + items.force (m, m.name) + end + +feature -- Access + + new_cursor: ITERATION_CURSOR [CMS_MENU] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +feature {NONE} -- Implementation + + items: HASH_TABLE [CMS_MENU, like {CMS_MENU}.name] +-- items: ARRAYED_LIST [CMS_MENU] + +invariant + +end diff --git a/draft/application/cms/src/core/kernel/log/cms_log.e b/draft/application/cms/src/core/kernel/log/cms_log.e new file mode 100644 index 00000000..7f71460c --- /dev/null +++ b/draft/application/cms/src/core/kernel/log/cms_log.e @@ -0,0 +1,152 @@ +note + description: "Summary description for {CMS_LOG}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_LOG + +create + make + +feature {NONE} -- Initialization + + make (a_category: like category; a_message: like message; a_level: like level; a_date: detachable like date) + do + category := a_category + message := a_message + set_level (a_level) + if a_date = Void then + create date.make_now_utc + else + date := a_date + end + end + + make_with_id (a_id: like id; a_category: like category; a_message: like message; a_level: like level; a_date: detachable like date) + do + id := a_id + make (a_category, a_message, a_level, a_date) + end + +feature -- Access + + id: INTEGER + -- Unique identifier of Current. + + category: READABLE_STRING_8 + -- Associated title (optional). + + message: READABLE_STRING_8 + -- Log message + + level: INTEGER + -- Severity level + + level_name: STRING + do + Result := level_to_string (level) + end + + info: detachable READABLE_STRING_8 + + link: detachable CMS_LINK + + date: DATE_TIME + +feature -- status report + + has_id: BOOLEAN + do + Result := id > 0 + end + +feature -- Change + + set_id (a_id: like id) + require + not has_id + do + id := a_id + end + + set_level (a_level: like level) + do + if a_level = 0 then + level := level_notice + else + level := a_level + end + end + + set_link (lnk: like link) + do + link := lnk + end + + set_info (inf: like info) + do + info := inf + end + +feature -- Conversion + + to_html (a_theme: CMS_THEME): STRING_8 + do + Result := "
    " + Result.append ("
    ") + Result.append (message) + if attached info as l_info then + Result.append ("
    Information: ") + Result.append (l_info) + end + if attached link as lnk then + Result.append ("
    Associated link: ") + Result.append (a_theme.link (lnk.title, lnk.location, lnk.options)) + end + Result.append ("
    ") + Result.append ("
    ") + Result.append ("(date: " + date.year.out + "/" + date.month.out + "/" + date.day.out + ")") + Result.append ("
    ") + + Result.append ("
    ") + end + +feature -- Constants + + level_to_string (a_level: INTEGER): STRING + do + inspect a_level + when level_emergency then + Result := "emergency" + when level_alert then + Result := "alert" + when level_critical then + Result := "critical" + when level_error then + Result := "error" + when level_warning then + Result := "warning" + when level_notice then + Result := "notice" + when level_info then + Result := "info" + when level_debug then + Result := "debug" + else + Result := "level-" + a_level.out + end + end + + level_emergency: INTEGER = 1 + level_alert: INTEGER = 2 + level_critical: INTEGER = 3 + level_error: INTEGER = 4 + level_warning: INTEGER = 5 + level_notice: INTEGER = 6 + level_info: INTEGER = 7 + level_debug: INTEGER = 8 + + + +end diff --git a/draft/application/cms/src/core/modules/admin/admin_blocks_cms_execution.e b/draft/application/cms/src/core/modules/admin/admin_blocks_cms_execution.e new file mode 100644 index 00000000..27ccfdd7 --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/admin_blocks_cms_execution.e @@ -0,0 +1,57 @@ +note + description: "Summary description for {ADMIN_BLOCKS_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_BLOCKS_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + set_title ("Blocks") + -- check Permission !!! + create b.make_empty + if has_permission ("administrate blocks") then + b.append ("
      ") + across + blocks as c + loop + if attached c.item as b_info then + if b_info.block.is_enabled then + b.append ("
    • ") + else + b.append ("
    • ") + end + b.append ("" + b_info.name + " (region=" + b_info.region + ")") + if b_info.block.is_enabled then + b.append (" [disable]") + else + b.append (" [enable]") + end + if attached b_info.block.title as l_title then + b.append ("
      title=" + l_title + "
      ") + end + b.append ("
    • ") + end + end + b.append ("
    ") + else + b.append ("
    Access denied
    ") + end + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/modules/admin/admin_cms_execution.e b/draft/application/cms/src/core/modules/admin/admin_cms_execution.e new file mode 100644 index 00000000..4b1e7e35 --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/admin_cms_execution.e @@ -0,0 +1,43 @@ +note + description: "Summary description for {CMS_ADMIN_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + set_title ("Administration") + -- check Permission !!! + create b.make_empty + if has_permission ("administrate modules") then + b.append ("
  • " + link ("Modules", "/admin/modules/", Void) + "
  • ") + end + if has_permission ("administrate blocks") then + b.append ("
  • " + link ("Blocks", "/admin/blocks/", Void) + "
  • ") + end + if has_permission ("administrate users") then + b.append ("
  • " + link ("Users", "/admin/users/", Void) + "
  • ") + end + if has_permission ("administrate logs") then + b.append ("
  • " + link ("Logs", "/admin/logs/", Void) + "
  • ") + end + + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/modules/admin/admin_logs_cms_execution.e b/draft/application/cms/src/core/modules/admin/admin_logs_cms_execution.e new file mode 100644 index 00000000..1df94bd2 --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/admin_logs_cms_execution.e @@ -0,0 +1,47 @@ +note + description: "Summary description for {ADMIN_LOGS_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_LOGS_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + set_title ("Logs") + -- check Permission !!! + create b.make_empty + if has_permission ("admin logs") then + b.append ("
      ") + across + storage.recent_logs (1, 25) as c + loop + if attached c.item as l_log then + b.append ("
    • ") + b.append (link ("[" + l_log.id.out + "]", "/admin/log/" + l_log.id.out, Void)) + b.append (" " + l_log.category + " (level=" + l_log.level_name + ")") + b.append (": " + truncated_string (l_log.message, 60, "...")) + b.append ("
    • ") + end + end + b.append ("
    ") + else + b.append ("
    Access denied
    ") + end + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/modules/admin/admin_module.e b/draft/application/cms/src/core/modules/admin/admin_module.e new file mode 100644 index 00000000..a669ab28 --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/admin_module.e @@ -0,0 +1,100 @@ +note + description: "Summary description for {ADMIN_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_MODULE + +inherit + CMS_MODULE + + CMS_HOOK_MENU_ALTER + +create + make + +feature {NONE} -- Initialization + + make (a_service: like service) + do + service := a_service + name := "admin" + version := "1.0" + description := "Set of service to administrate the site" + package := "core" + + enable + end + +feature {CMS_SERVICE} -- Registration + + service: CMS_SERVICE + + register (a_service: CMS_SERVICE) + do + a_service.map_uri ("/admin/", agent handle_admin) + a_service.map_uri ("/admin/users/", agent handle_admin_users) + a_service.map_uri ("/admin/blocks/", agent handle_admin_blocks) + a_service.map_uri ("/admin/modules/", agent handle_admin_modules) + a_service.map_uri ("/admin/logs/", agent handle_admin_logs) + a_service.map_uri_template ("/admin/log/{log-id}", agent handle_admin_log_view) + + a_service.add_menu_alter_hook (Current) + end + +feature -- Hooks + + menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) + local + lnk: CMS_LOCAL_LINK + do + create lnk.make ("Administer", "/admin/") + lnk.set_permission_arguments (<<"administer">>) + a_menu_system.management_menu.extend (lnk) + end + + links: HASH_TABLE [CMS_MODULE_LINK, STRING] + -- Link indexed by path + local +-- lnk: CMS_MODULE_LINK + do + create Result.make (3) +-- create lnk.make ("Date/time demo") +-- lnk.set_callback (agent process_date_time_demo, <<"arg">>) +-- Result["/demo/date/{arg}"] := lnk + end + + handle_admin (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ADMIN_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_admin_users (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ADMIN_USERS_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_admin_blocks (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ADMIN_BLOCKS_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_admin_modules (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ADMIN_MODULES_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_admin_logs (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ADMIN_LOGS_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_admin_log_view (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {LOG_VIEW_CMS_EXECUTION}.make (req, res, service)).execute + end + + +end diff --git a/draft/application/cms/src/core/modules/admin/admin_modules_cms_execution.e b/draft/application/cms/src/core/modules/admin/admin_modules_cms_execution.e new file mode 100644 index 00000000..c674b553 --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/admin_modules_cms_execution.e @@ -0,0 +1,57 @@ +note + description: "Summary description for {ADMIN_MODULES_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_MODULES_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + set_title ("Modules") + -- check Permission !!! + create b.make_empty + if has_permission ("administrate modules") then + b.append ("
      ") + across + service.modules as m + loop + if attached m.item as mod then + if mod.is_enabled then + b.append ("
    • ") + else + b.append ("
    • ") + end + b.append ("" + mod.name + " (version:" + mod.version + ")") + b.append (" package=" + mod.package) + if mod.is_enabled then + b.append (" [disable]") + else + b.append (" [enable]") + end + b.append ("
      " + mod.description + "
      ") + + b.append ("
    • ") + end + end + b.append ("
    ") + else + b.append ("
    Access denied
    ") + end + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/modules/admin/admin_users_cms_execution.e b/draft/application/cms/src/core/modules/admin/admin_users_cms_execution.e new file mode 100644 index 00000000..e785bdbd --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/admin_users_cms_execution.e @@ -0,0 +1,56 @@ +note + description: "Summary description for {ADMIN_USERS_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_USERS_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + set_title ("Users") + -- check Permission !!! + create b.make_empty + if has_permission ("administrate users") then + + b.append ("
      ") + across + service.storage.all_users as c + loop + if attached c.item as u then + b.append ("
    • ") + b.append ("" + user_link (u) + " (id=" + u.id.out + ")") + if attached u.email as l_email then + b.append (" ["+ l_email +"]") + end + if attached u.creation_date as dt then + b.append (" - created: " + dt.out) + end + if attached u.last_login_date as dt then + b.append (" - last signed: " + dt.out) + end + + b.append ("
    • ") + end + end + b.append ("
    ") + else + b.append ("
    Access denied
    ") + end + + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/modules/admin/log_view_cms_execution.e b/draft/application/cms/src/core/modules/admin/log_view_cms_execution.e new file mode 100644 index 00000000..a9fe8718 --- /dev/null +++ b/draft/application/cms/src/core/modules/admin/log_view_cms_execution.e @@ -0,0 +1,39 @@ +note + description: "Summary description for {LOG_VIEW_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + LOG_VIEW_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + if attached {WSF_STRING} request.path_parameter ("log-id") as p_id and then p_id.is_integer then + create b.make_empty + + if attached storage.log (p_id.integer_value) as l_log then + set_title ("Log #" + l_log.id.out) + b.append (l_log.to_html (theme)) + else + set_title ("Log [" + p_id.value + "] does not exists!") + end + set_main_content (b) + else + set_redirection ("/admin/logs") + set_main_content ("not found") + end + end + +end diff --git a/draft/application/cms/src/core/modules/cms_module.e b/draft/application/cms/src/core/modules/cms_module.e new file mode 100644 index 00000000..025e6c8a --- /dev/null +++ b/draft/application/cms/src/core/modules/cms_module.e @@ -0,0 +1,57 @@ +note + description: "Summary description for {WSF_CMS_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_MODULE + +feature -- Access + + is_enabled: BOOLEAN + + name: STRING + + description: STRING + + package: STRING + + version: STRING + +feature {CMS_SERVICE} -- Registration + + register (a_service: CMS_SERVICE) + deferred + end + +feature -- Settings + + enable + do + is_enabled := True + end + + disable + do + is_enabled := False + end + +feature -- Hooks + + help_text (a_path: STRING): STRING + do + Result := "" + end + + permissions: LIST [TUPLE [title: detachable STRING; description: detachable STRING]] + do + create {ARRAYED_LIST [like permissions.item]} Result.make (0) + end + + links: HASH_TABLE [CMS_MODULE_LINK, STRING] + -- Link indexed by path + deferred + end + +end diff --git a/draft/application/cms/src/core/modules/cms_module_link.e b/draft/application/cms/src/core/modules/cms_module_link.e new file mode 100644 index 00000000..490db5a7 --- /dev/null +++ b/draft/application/cms/src/core/modules/cms_module_link.e @@ -0,0 +1,50 @@ +note + description: "Summary description for {CMS_MODULE_LINK}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_MODULE_LINK + +create + make + +feature {NONE} -- Initialization + + make (a_title: like title) + do + title := a_title + end + +feature -- Access + + title: STRING_32 + + description: detachable STRING_32 + + callback: detachable PROCEDURE [ANY, TUPLE [cms: detachable CMS_EXECUTION; args: detachable ITERABLE [STRING]]] + callback_arguments: detachable ITERABLE [STRING] + + permission: detachable LIST [STRING] + + parent: detachable CMS_MODULE_LINK + +feature -- Element change + + set_callback (cb: like callback; args: like callback_arguments) + do + callback := cb + callback_arguments := args + end + +feature -- Execution + + execute + do + if attached callback as cb then + cb.call ([Void, callback_arguments]) + end + end + +end diff --git a/draft/application/cms/src/core/modules/node/cms_page.e b/draft/application/cms/src/core/modules/node/cms_page.e new file mode 100644 index 00000000..79cb4033 --- /dev/null +++ b/draft/application/cms/src/core/modules/node/cms_page.e @@ -0,0 +1,75 @@ +note + description: "Summary description for {CMS_PAGE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_PAGE + +inherit + CMS_NODE + +create + make_new, + make + +feature {NONE} -- Initialization + + make (a_id: like id; a_title: like title; dt: like creation_date) + require + a_id > 0 + do + set_id (a_id) + creation_date := dt + modification_date := dt + title := a_title + initialize + end + + make_new (a_title: like title) + do + title := a_title + create creation_date.make_now_utc + modification_date := creation_date + initialize + end + + initialize + do + format := formats.default_format + end + +feature -- Access + + title: detachable READABLE_STRING_32 + + body: detachable READABLE_STRING_8 + + format: CMS_FORMAT + + content_type_name: STRING = "page" + +feature -- Change + + set_title (a_title: like title) + -- Set `title' to `a_title' + do + title := a_title + end + + set_body (a_body: like body; a_format: like format) + -- Set `body' and associated `format' + do + body := a_body + format := a_format + end + +feature -- Conversion + +-- to_html (a_theme: CMS_THEME): STRING_8 +-- do +-- Result := Precursor (a_theme) +-- end + +end diff --git a/draft/application/cms/src/core/modules/node/cms_page_content_type.e b/draft/application/cms/src/core/modules/node/cms_page_content_type.e new file mode 100644 index 00000000..a6fc6ebb --- /dev/null +++ b/draft/application/cms/src/core/modules/node/cms_page_content_type.e @@ -0,0 +1,177 @@ +note + description: "Summary description for {CMS_PAGE_CONTENT_TYPE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_PAGE_CONTENT_TYPE + +inherit + CMS_CONTENT_TYPE + +create + make + +feature {NONE} -- Initialization + + make + do + create {ARRAYED_LIST [like available_formats.item]} available_formats.make (1) + available_formats.extend (formats.plain_text) + available_formats.extend (formats.filtered_html) + available_formats.extend (formats.full_html) + end + +feature -- Access + + name: STRING = "page" + + title: STRING = "basic page" + + description: detachable READABLE_STRING_8 + -- Optional description + do + Result := "Use basic pages for your static content, such as an 'About us' page." + end + + available_formats: LIST [CMS_FORMAT] + +feature -- Factory + + fill_edit_form (f: CMS_FORM; a_node: detachable CMS_NODE) + local + ti: CMS_FORM_TEXT_INPUT + fset: CMS_FORM_FIELD_SET + ta: CMS_FORM_TEXTAREA + tselect: CMS_FORM_SELECT + opt: CMS_FORM_SELECT_OPTION + do + create ti.make ("title") + ti.set_label ("Title") + ti.set_size (70) + if a_node /= Void then + ti.set_text_value (a_node.title) + end + ti.set_is_required (True) + f.extend (ti) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ta.make ("body") + ta.set_rows (10) + ta.set_cols (70) + if a_node /= Void then + ta.set_text_value (a_node.body) + end +-- ta.set_label ("Body") + ta.set_description ("This is the main content") + ta.set_is_required (False) + + create fset.make + fset.set_legend ("Body") + fset.extend (ta) + + + fset.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create tselect.make ("format") + tselect.set_label ("Body's format") + tselect.set_is_required (True) + across + available_formats as c + loop + create opt.make (c.item.name, c.item.title) + if attached c.item.help as f_help then + opt.set_description ("
      " + f_help + "
    ") + end + tselect.add_option (opt) + end + if a_node /= Void then + tselect.set_text_value (a_node.format.name) + end + + fset.extend (tselect) + + f.extend (fset) + + end + + change_node (a_execution: CMS_EXECUTION; fd: CMS_FORM_DATA; a_node: like new_node) + local + b: detachable READABLE_STRING_8 + f: detachable CMS_FORMAT + do + if attached fd.integer_item ("id") as l_id and then l_id > 0 then + check a_node.id = l_id end + end + if attached fd.string_item ("title") as l_title then + a_node.set_title (l_title) + end + + if attached fd.string_item ("body") as l_body then + b := l_body + end + if attached fd.string_item ("format") as s_format and then attached formats.format (s_format) as f_format then + f := f_format + elseif a_node /= Void then + f := a_node.format + else + f := formats.default_format + end + if b /= Void then + a_node.set_body (b, f) + end + end + + new_node (a_execution: CMS_EXECUTION; fd: CMS_FORM_DATA; a_node: detachable like new_node): CMS_PAGE + -- + local + b: detachable READABLE_STRING_8 + f: detachable CMS_FORMAT + l_node: detachable like new_node + do + l_node := a_node + if attached fd.integer_item ("id") as l_id and then l_id > 0 then + if l_node /= Void then + check l_node.id = l_id end + else + if attached {like new_node} a_execution.service.storage.node (l_id) as n then + l_node := n + else + -- FIXME: Error + end + end + end + if attached fd.string_item ("title") as l_title then + if l_node = Void then + create l_node.make_new (l_title) + else + l_node.set_title (l_title) + end + else + if l_node = Void then + create l_node.make_new ("...") + end + end + l_node.set_author (a_execution.user) + + if attached fd.string_item ("body") as l_body then + b := l_body + end + if attached fd.string_item ("format") as s_format and then attached formats.format (s_format) as f_format then + f := f_format + elseif a_node /= Void then + f := a_node.format + else + f := formats.default_format + end + if b /= Void then + l_node.set_body (b, f) + end + Result := l_node + end + +invariant + +end diff --git a/draft/application/cms/src/core/modules/node/node_add_cms_execution.e b/draft/application/cms/src/core/modules/node/node_add_cms_execution.e new file mode 100644 index 00000000..fafd5eee --- /dev/null +++ b/draft/application/cms/src/core/modules/node/node_add_cms_execution.e @@ -0,0 +1,143 @@ +note + description: "[ + ]" + +class + NODE_ADD_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + f: like edit_form + fd: detachable CMS_FORM_DATA + l_preview: BOOLEAN + l_format: detachable CMS_FORMAT + do + create b.make_empty + if attached non_empty_string_path_parameter ("type") as s_type then + if attached service.content_type (s_type) as l_type then + f := edit_form (Void, request.path_info, "add-" + l_type.name, l_type) + if request.is_post_request_method then + create fd.make (request, f) + l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") + end + + set_title ("Create " + l_type.title) + if has_permission ("create " + l_type.name) then + + if fd /= Void and l_preview then + b.append ("Preview
    ") + if attached fd.string_item ("format") as s_format and then attached formats.format (s_format) as f_format then + l_format := f_format + end + if attached fd.string_item ("title") as l_title then + b.append ("Title:
    " + html_encoded (l_title) + "
    ") + end + if attached fd.string_item ("body") as l_body then + b.append ("Body:
    ") + if l_format /= Void then + b.append (l_format.to_html (l_body)) + else + b.append (html_encoded (l_body)) + end + b.append ("
    ") + end + b.append ("
    ") + end + + if fd /= Void and then fd.is_valid and not l_preview then + across + fd as c + loop + b.append ("
  • " + html_encoded (c.key) + "=") + if attached c.item as v then + b.append (html_encoded (v.string_representation)) + end + b.append ("
  • ") + end + if attached l_type.new_node (Current, fd, Void) as l_node then + service.storage.save_node (l_node) + if attached user as u then + service.log ("node", "User %"" + user_link (u) + "%" created node " + link (l_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node)) + else + service.log ("node", "Anonymous created node "+ l_type.name +" #" + l_node.id.out, 0, node_local_link (l_node)) + end + add_success_message ("Node #" + l_node.id.out + " saved.") + set_redirection (node_url (l_node)) + end + -- Creation ... + else + if fd /= Void then + if not fd.is_valid then + report_form_errors (fd) + end + fd.apply_to_associated_form + end + b.append (f.to_html (theme)) + end + else + set_title ("Access denied") + end + else + set_title ("Unknown content type [" + s_type + "]") + end + else + set_title ("Create new content ...") + b.append ("
      ") + across + service.content_types as c + loop + if has_permission ("create " + c.item.name) then + b.append ("
    • " + link (c.item.name, "/node/add/" + c.item.name, Void)) + if attached c.item.description as d then + b.append ("
      " + d + "
      ") + end + b.append ("
    • ") + end + end + b.append ("
    ") + end + set_main_content (b) + end + + edit_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_type: CMS_CONTENT_TYPE): CMS_FORM + local + f: CMS_FORM + ts: CMS_FORM_SUBMIT_INPUT + th: CMS_FORM_HIDDEN_INPUT + do + create f.make (a_url, a_name) + + create th.make ("node-id") + if a_node /= Void then + th.set_text_value (a_node.id.out) + else + th.set_text_value ("0") + end + f.extend (th) + + a_type.fill_edit_form (f, a_node) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ts.make ("op") + ts.set_default_value ("Save") + f.extend (ts) + + create ts.make ("op") + ts.set_default_value ("Preview") + f.extend (ts) + + Result := f + end + +end diff --git a/draft/application/cms/src/core/modules/node/node_edit_cms_execution.e b/draft/application/cms/src/core/modules/node/node_edit_cms_execution.e new file mode 100644 index 00000000..7e699e13 --- /dev/null +++ b/draft/application/cms/src/core/modules/node/node_edit_cms_execution.e @@ -0,0 +1,148 @@ +note + description: "[ + ]" + +class + NODE_EDIT_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + f: like edit_form + fd: detachable CMS_FORM_DATA + l_preview: BOOLEAN + l_format: detachable CMS_FORMAT + do + create b.make_empty + if + attached {WSF_STRING} request.path_parameter ("nid") as p_nid and then + p_nid.is_integer and then + attached service.storage.node (p_nid.integer_value) as l_node + then + if attached service.content_type (l_node.content_type_name) as l_type then + if has_permission ("edit " + l_type.name) then + f := edit_form (l_node, request.path_info, "edit-" + l_type.name, l_type) + if request.is_post_request_method then + create fd.make (request, f) + l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") + end + + set_title ("Edit #" + l_node.id.out) + + add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs) + add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs) + + if fd /= Void and l_preview then + b.append ("Preview
    ") + if attached fd.string_item ("format") as s_format and then attached formats.format (s_format) as f_format then + l_format := f_format + end + if attached fd.string_item ("title") as l_title then + b.append ("Title:
    " + html_encoded (l_title) + "
    ") + end + if attached fd.string_item ("body") as l_body then + b.append ("Body:
    ") + if l_format /= Void then + b.append (l_format.to_html (l_body)) + else + b.append (html_encoded (l_body)) + end + b.append ("
    ") + end + b.append ("
    ") + end + + if fd /= Void and then fd.is_valid and not l_preview then + across + fd as c + loop + b.append ("
  • " + html_encoded (c.key) + "=") + if attached c.item as v then + b.append (html_encoded (v.string_representation)) + end + b.append ("
  • ") + end + l_type.change_node (Current, fd, l_node) + service.storage.save_node (l_node) + if attached user as u then + service.log ("node", "User %"" + user_link (u) + "%" modified node " + link (l_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node)) + else + service.log ("node", "Anonymous modified node "+ l_type.name +" #" + l_node.id.out, 0, node_local_link (l_node)) + end + add_success_message ("Node #" + l_node.id.out + " saved.") + set_redirection (node_url (l_node)) + else + if fd /= Void then + if not fd.is_valid then + report_form_errors (fd) + end + fd.apply_to_associated_form + end + b.append (f.to_html (theme)) + end + else + b.append ("

    Access denied

    ") + end + else + set_title ("Unknown node") + end + else + set_title ("Create new content ...") + b.append ("
      ") + across + service.content_types as c + loop + if has_permission ("create " + c.item.name) then + b.append ("
    • " + link (c.item.name, "/node/add/" + c.item.name, Void)) + if attached c.item.description as d then + b.append ("
      " + d + "
      ") + end + b.append ("
    • ") + end + end + b.append ("
    ") + end + set_main_content (b) + end + + edit_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_type: CMS_CONTENT_TYPE): CMS_FORM + local + f: CMS_FORM + ts: CMS_FORM_SUBMIT_INPUT + th: CMS_FORM_HIDDEN_INPUT + do + create f.make (a_url, a_name) + + create th.make ("node-id") + if a_node /= Void then + th.set_text_value (a_node.id.out) + else + th.set_text_value ("0") + end + f.extend (th) + + a_type.fill_edit_form (f, a_node) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ts.make ("op") + ts.set_default_value ("Save") + f.extend (ts) + + create ts.make ("op") + ts.set_default_value ("Preview") + f.extend (ts) + + Result := f + end + +end diff --git a/draft/application/cms/src/core/modules/node/node_module.e b/draft/application/cms/src/core/modules/node/node_module.e new file mode 100644 index 00000000..72724c44 --- /dev/null +++ b/draft/application/cms/src/core/modules/node/node_module.e @@ -0,0 +1,113 @@ +note + description: "Summary description for {NODE_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + NODE_MODULE + +inherit + CMS_MODULE + + CMS_HOOK_MENU_ALTER + + CMS_HOOK_BLOCK + +create + make + +feature {NONE} -- Initialization + + make (a_service: like service) + do + service := a_service + name := "node" + version := "1.0" + description := "Service to manage content based on 'node'" + package := "core" + + enable + end + +feature {CMS_SERVICE} -- Registration + + service: CMS_SERVICE + + register (a_service: CMS_SERVICE) + local + h: CMS_HANDLER + do + a_service.map_uri ("/node/add", agent handle_node_add) + a_service.map_uri_template ("/node/add/{type}", agent handle_node_add) + + create {CMS_HANDLER} h.make (agent handle_node_view) + a_service.router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/node/{nid}", h)) + a_service.router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/node/{nid}/view", h)) + + a_service.map_uri_template ("/node/{nid}/edit", agent handle_node_edit) + + a_service.add_content_type (create {CMS_PAGE_CONTENT_TYPE}.make) + + a_service.add_menu_alter_hook (Current) + a_service.add_block_hook (Current) + end + +feature -- Hooks + + block_list: ITERABLE [like {CMS_BLOCK}.name] + do + Result := <<"node-info">> + end + + get_block_view (a_block_id: detachable READABLE_STRING_8; a_execution: CMS_EXECUTION) +-- local +-- b: CMS_CONTENT_BLOCK + do +-- if +-- a_execution.is_front and then +-- attached a_execution.user as u +-- then +-- create b.make ("node-info", "Node", "Node ...", a_execution.formats.plain_text) +-- a_execution.add_block (b, Void) +-- end + end + + menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) + local + lnk: CMS_LOCAL_LINK + do + if a_execution.authenticated then + create lnk.make ("Add content", "/node/add/") + lnk.set_permission_arguments (<<"authenticated">>) + a_menu_system.navigation_menu.extend (lnk) + end + end + + links: HASH_TABLE [CMS_MODULE_LINK, STRING] + -- Link indexed by path + local +-- lnk: CMS_MODULE_LINK + do + create Result.make (3) +-- create lnk.make ("Date/time demo") +-- lnk.set_callback (agent process_date_time_demo, <<"arg">>) +-- Result["/demo/date/{arg}"] := lnk + end + + handle_node_view (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {NODE_VIEW_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_node_edit (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {NODE_EDIT_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_node_add (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {NODE_ADD_CMS_EXECUTION}.make (req, res, service)).execute + end + +end diff --git a/draft/application/cms/src/core/modules/node/node_view_cms_execution.e b/draft/application/cms/src/core/modules/node/node_view_cms_execution.e new file mode 100644 index 00000000..4c67eaa7 --- /dev/null +++ b/draft/application/cms/src/core/modules/node/node_view_cms_execution.e @@ -0,0 +1,41 @@ +note + description: "[ + ]" + +class + NODE_VIEW_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + do + if attached {WSF_STRING} request.path_parameter ("nid") as p_nid and then p_nid.is_integer then + create b.make_empty + + if attached storage.node (p_nid.integer_value) as l_node then + set_title ("Node [" + l_node.id.out + "]") + add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs) + add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs) + + b.append (l_node.to_html (theme)) + else + set_title ("Node [" + p_nid.value + "] does not exists!") + end + set_main_content (b) + else + set_title ("Node ...") + create b.make_empty + set_main_content (b) + end + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_account_cms_execution.e b/draft/application/cms/src/core/modules/user/user_account_cms_execution.e new file mode 100644 index 00000000..3dc2fadf --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_account_cms_execution.e @@ -0,0 +1,59 @@ +note + description: "[ + ]" + +class + USER_ACCOUNT_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + vars: detachable ARRAY [READABLE_STRING_32] + n: INTEGER +-- vars: detachable WSF_TABLE + do + if attached {WSF_TABLE} request.path_parameter ("vars") as tb then + vars := tb.as_array_of_string + end + if vars = Void or else vars.is_empty then + set_title ("Account") + create b.make_empty + b.append ("Account") + set_main_content (b) + else + n := vars.count + create b.make_empty + if n >= 1 then + if vars[1].same_string ("password") then + set_title ("Password") + if n >= 2 then + if vars[2].same_string ("reset") then + b.append ("Reset password") + else + b.append ("password ???") + end + end + elseif vars[1].same_string ("register") then + set_title ("Registration") + b.append ("Register new account") + else + b.append ("???") + end + else + set_title ("Account/") + b.append ("...") + end + set_main_content (b) + end + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_cms_execution.e b/draft/application/cms/src/core/modules/user/user_cms_execution.e new file mode 100644 index 00000000..e02447e3 --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_cms_execution.e @@ -0,0 +1,182 @@ +note + description: "[ + ]" + +class + USER_CMS_EXECUTION + +inherit + CMS_EXECUTION + + USER_MODULE_LIB + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + u: detachable CMS_USER + do + if attached {WSF_STRING} request.path_parameter ("uid") as p_uid then + if p_uid.is_integer then + u := service.storage.user_by_id (p_uid.integer_value) + else + u := service.storage.user_by_name (p_uid.value) + end + else + u := user + end + initialize_primary_tabs (u) + + if u /= Void then + if not u.same_as (user) and then not has_permission ("admin view users") then + set_main_content ("Access denied") + else + service.storage.fill_user_profile (u) + create b.make_empty + set_title ("User [" + u.name + "]") + b.append ("
      %N") + if attached u.email as l_email then + b.append ("
    • Email: "+ l_email +"
    • ") + end + b.append ("
    • Created: "+ u.creation_date.out +"
    • %N") + if attached u.last_login_date as dt then + b.append ("
    • Last signed: "+ dt.out +"
    • %N") + else + b.append ("
    • Never signed yet
    • %N") + end + if u = user and then attached last_user_access_date as dt then + b.append ("
    • Session date: "+ dt.out +"
    • %N") + end + + service.storage.fill_user_profile (u) + if attached u.profile as prof then + across + prof as p + loop + b.append ("
    • " + p.key + "=" + p.item +"
    • %N") + end + end + b.append ("
    ") + set_main_content (b) + end + else + process_login + end + end + + process_login + local + l_url: detachable READABLE_STRING_8 + b: STRING_8 + f: CMS_FORM + fd: detachable CMS_FORM_DATA + do + if + attached {WSF_STRING} request.item ("destination") as s_dest + then + l_url := request.script_url (s_dest.value) + end + if l_url = Void then + l_url := request.script_url ("/user") + end + f := login_form (request.path_info, "login-form", l_url) + service.call_form_alter_hooks (f, Current) + + if request.is_request_method ("post") then + create fd.make (request, f) + if fd.is_valid then + on_form_submitted (fd) + if attached {WSF_STRING} fd.integer_item ("form-destination") as s_dest then + l_url := request.script_url (s_dest.value) + end + end + end + + if authenticated then + set_redirection (l_url) + set_title ("Login") + create b.make_empty + set_main_content (b) + set_redirection (url ("/user", Void)) + else + set_title ("Login") + create b.make_empty + if fd /= Void then + if not fd.is_valid then + report_form_errors (fd) + end + fd.apply_to_associated_form + end + b.append (f.to_html (theme)) + set_main_content (b) + end + end + + on_form_submitted (fd: CMS_FORM_DATA) + local + u: detachable CMS_USER + do + if attached {WSF_STRING} fd.item (form_username_or_email_name) as s_name and then not s_name.is_empty then + u := service.storage.user_by_name (s_name.value) + if u = Void then + u := service.storage.user_by_email (s_name.value) + end + end + if u = Void then + fd.report_error ("Sorry, unrecognized username/email or password. " + link ("Have you forgotten your password?", "/user/password", Void)) + else + if attached {WSF_STRING} fd.item (form_password_name) as s_passwd and then not s_passwd.is_empty then + if service.auth_engine.valid_credential (u.name, s_passwd.value) then + login (u, request) + else + fd.report_error ("Sorry, unrecognized username/email or password. " + link ("Have you forgotten your password?", "/user/password", Void)) + end + end + end + end + + login_form (a_action: READABLE_STRING_8; a_form_name: READABLE_STRING_8; a_destination: READABLE_STRING_8): CMS_FORM + local + th: CMS_FORM_HIDDEN_INPUT + ti: CMS_FORM_TEXT_INPUT + tp: CMS_FORM_PASSWORD_INPUT + ts: CMS_FORM_SUBMIT_INPUT + do + create Result.make (a_action, a_form_name) + + create th.make ("form-destination") + th.set_default_value (a_destination) + Result.extend (th) + + create ti.make (form_username_or_email_name) + ti.set_label ("Username or email") + ti.set_is_required (True) + Result.extend (ti) + + create tp.make (form_password_name) + tp.set_label ("Password") + tp.set_is_required (True) + tp.set_description (link ("Reset password", "/user/password", Void)) + Result.extend (tp) + + Result.extend_text ("[ + login + ]") + + create ts.make ("op") + ts.set_default_value ("Log in") + Result.extend (ts) + + Result.extend_text ("

    Need an account?
    " + link ("Sign up now!", "/user/register", Void) + "

    ") + end + + form_username_or_email_name: STRING = "name" + form_password_name: STRING = "password" + +end diff --git a/draft/application/cms/src/core/modules/user/user_edit_cms_execution.e b/draft/application/cms/src/core/modules/user/user_edit_cms_execution.e new file mode 100644 index 00000000..57fbe5ec --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_edit_cms_execution.e @@ -0,0 +1,168 @@ +note + description: "[ + ]" + +class + USER_EDIT_CMS_EXECUTION + +inherit + CMS_EXECUTION + + USER_MODULE_LIB + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + f: CMS_FORM + fd: detachable CMS_FORM_DATA + u, fu: detachable CMS_USER + up: detachable CMS_USER_PROFILE + l_is_editing_current_user: BOOLEAN + do + if attached {WSF_STRING} request.path_parameter ("uid") as p_uid and then p_uid.is_integer then + u := service.storage.user_by_id (p_uid.integer_value) + if has_permission ("view users") then + else + if u /= Void and then u.same_as (user) then + else + u := Void + end + end + else + u := user + end + if attached user as l_active_user then + l_is_editing_current_user := l_active_user.same_as (u) + end + create b.make_empty + initialize_primary_tabs (u) + if u = Void then + b.append ("Access denied") + set_redirection (url ("/user/register", Void)) + else + service.storage.fill_user_profile (u) + f := edit_form (u, request.path_info, "user-edit") + + if request.is_post_request_method then + create fd.make (request, f) + if attached {WSF_STRING} fd.item ("username") as s_username then + fu := service.storage.user_by_name (s_username.value) + if fu = Void then + fd.report_invalid_field ("username", "User does not exist!") + end + end + if attached {WSF_STRING} fd.item ("email") as s_email then + fu := service.storage.user_by_email (s_email.value) + if fu /= Void and then fu.id /= u.id then + fd.report_invalid_field ("email", "Email is already used by another user!") + end + end + fu := Void + end + if fd /= Void and then fd.is_valid then + across + fd as c + loop + b.append ("
  • " + html_encoded (c.key) + "=") + if attached c.item as v then + b.append (html_encoded (v.string_representation)) + end + b.append ("
  • ") + end + + if attached {WSF_STRING} fd.item ("password") as s_password then + u.set_password (s_password.value) + end + if attached {WSF_STRING} fd.item ("email") as s_email then + u.set_email (s_email.value) + end + + if attached {WSF_STRING} fd.item ("note") as s_note then + up := u.profile + if up = Void then + create up.make + end + up.force (s_note.value, "note") + u.set_profile (up) + end + + service.storage.save_user (u) + if l_is_editing_current_user and u /= user then + set_user (u) + end + set_redirection (url ("/user", Void)) + set_main_content (b) + else + if fd /= Void then + if not fd.is_valid then + report_form_errors (fd) + end + fd.apply_to_associated_form + end + b.append (f.to_html (theme)) + end + end + set_main_content (b) + end + + edit_form (u: CMS_USER; a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM + local + f: CMS_FORM + ti: CMS_FORM_TEXT_INPUT + tp: CMS_FORM_PASSWORD_INPUT + ta: CMS_FORM_TEXTAREA + ts: CMS_FORM_SUBMIT_INPUT + do + create f.make (a_url, a_name) + + create ti.make ("username") + ti.set_label ("Username") + ti.set_default_value (u.name) + ti.set_is_required (False) + ti.set_is_readonly (True) + f.extend (ti) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create tp.make ("password") + tp.set_label ("Password") + tp.set_is_required (False) + f.extend (tp) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ti.make ("email") + ti.set_label ("Valid email address") + if attached u.email as l_email then + ti.set_default_value (l_email) + end + ti.set_is_required (True) + f.extend (ti) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ta.make ("note") + ta.set_label ("Additional note about you") + ta.set_description ("You can use this input to tell us more about you") + if attached u.profile as p and then attached p.item ("note") as l_note then + ta.set_default_value (l_note) + end + ta.set_is_required (False) + f.extend (ta) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ts.make ("op") + ts.set_default_value ("Save") + f.extend (ts) + + Result := f + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_login_cms_execution.e b/draft/application/cms/src/core/modules/user/user_login_cms_execution.e new file mode 100644 index 00000000..56f1a4f0 --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_login_cms_execution.e @@ -0,0 +1,114 @@ +note + description: "[ + ]" + +class + USER_LOGIN_CMS_EXECUTION + +inherit + CMS_EXECUTION + + CMS_AUTH_ENGINE + +create + make + +feature -- Status + + valid_credential (u,p: READABLE_STRING_32): BOOLEAN + do + if attached service.storage.user_by_name (u) as l_user then + Result := attached l_user.encoded_password as l_pass and then l_pass.same_string (service.storage.encoded_password (p)) + end + end + +feature -- Execution + + process + -- Computed response message. + local + auth_engine: CMS_AUTH_ENGINE + l_url: detachable READABLE_STRING_8 + err: detachable STRING_8 + b: STRING_8 + u: detachable STRING_32 + do + if request.is_request_method ("post") then + if + attached {WSF_STRING} request.form_parameter (form_login_name) as s_login and then not s_login.is_empty and + attached {WSF_STRING} request.form_parameter (form_password_name) as s_passwd and then not s_passwd.is_empty + then + auth_engine := Current + u := s_login.value + if attached service.storage.user_by_name (u) as l_user and auth_engine.valid_credential (u, s_passwd.value) then + login (l_user, request) + else + err := "Authentication failed for [" + html_encoded (u) + "]" + end + if attached {WSF_STRING} request.form_parameter ("form-destination") as s_dest then + l_url := request.script_url (s_dest.value) + end + end + else + if + attached {WSF_STRING} request.item ("destination") as s_dest + then + l_url := request.script_url (s_dest.value) + end + end + + if l_url = Void then + l_url := request.script_url ("/user") + end + + if authenticated then + set_redirection (l_url) + set_title ("Login") + create b.make_empty + b.append ("

    Login

    %N") + set_main_content (b) + else + set_title ("Login") + create b.make_empty + b.append ("

    Login

    %N") + + if err /= Void then + b.append ("
    " + err + "
    ") + end + + b.append ("
    %N") +-- b.append ("
    ") + b.append ("
    ") + b.append ("
    ") + b.append (" (required)
    ") + b.append ("") + b.append ("
    ") + b.append ("
    ") + b.append (" (required)
    ") + b.append ("") + b.append ("
    ") + + b.append ("

    Reset password

    %N") + + b.append ("
    ") + b.append ("%N") + b.append ("[ + login + ]") + b.append ("
    ") + b.append ("

    Need an account? Sign up now!

    %N") + b.append ("
    %N") + + set_main_content (b) + end + end + + form_login_name: STRING = "login" + form_password_name: STRING = "password" + +end diff --git a/draft/application/cms/src/core/modules/user/user_logout_cms_execution.e b/draft/application/cms/src/core/modules/user/user_logout_cms_execution.e new file mode 100644 index 00000000..8fa1221d --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_logout_cms_execution.e @@ -0,0 +1,39 @@ +note + description: "[ + ]" + +class + USER_LOGOUT_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local +-- l_url: READABLE_STRING_8 + b: STRING_8 + do + logout (request) + + if + attached {WSF_STRING} request.item ("destination") as s_dest + then + set_redirection (request.script_url (s_dest.value)) + else + set_redirection (request.script_url ("/")) + end + + set_title ("Logout") + create b.make_empty + set_main_content (b) +-- l_url := request.script_url ("/info/") +-- res.redirect_now_with_content (l_url, "Redirection to " + l_url, "text/html") + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_module.e b/draft/application/cms/src/core/modules/user/user_module.e new file mode 100644 index 00000000..44996556 --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_module.e @@ -0,0 +1,157 @@ +note + description: "Summary description for {USER_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + USER_MODULE + +inherit + CMS_MODULE + + CMS_HOOK_MENU_ALTER + + CMS_HOOK_BLOCK + +create + make + +feature {NONE} -- Initialization + + make (a_service: like service) + do + service := a_service + name := "user" + version := "1.0" + description := "Users management" + package := "core" + + enable + end + +feature {CMS_SERVICE} -- Registration + + service: CMS_SERVICE + + register (a_service: CMS_SERVICE) + local + h: CMS_HANDLER + do +-- a_service.map_uri ("/user", agent handle_login) + a_service.map_uri ("/user/logout", agent handle_logout) + a_service.map_uri ("/user/register", agent handle_register) + a_service.map_uri ("/user/password", agent handle_request_new_password) + + create {CMS_HANDLER} h.make (agent handle_user) + a_service.router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/user/{uid}", h)) + a_service.router.map (create {WSF_URI_MAPPING}.make_trailing_slash_ignored ("/user", h)) + a_service.map_uri_template ("/user/{uid}/edit", agent handle_edit) + a_service.map_uri_template ("/user/reset/{uid}/{last-signed}/{extra}", agent handle_reset_password) + + a_service.add_menu_alter_hook (Current) + a_service.add_block_hook (Current) + end + +feature -- Hooks + + block_list: ITERABLE [like {CMS_BLOCK}.name] + do + Result := <<"user-info">> + end + + get_block_view (a_block_id: detachable READABLE_STRING_8; a_execution: CMS_EXECUTION) + local + b: CMS_CONTENT_BLOCK + do + if + a_execution.is_front and then + attached a_execution.user as u + then + create b.make ("user-info", "User", "Welcome " + a_execution.html_encoded (u.name), a_execution.formats.plain_text) + a_execution.add_block (b, Void) + end + end + + menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) + local + lnk: CMS_LOCAL_LINK + opts: CMS_API_OPTIONS + do + if attached a_execution.user as u then + create lnk.make ("Logout", "/user/logout") + a_execution.add_to_main_menu (lnk) + else + create lnk.make ("Login", "/user") + create opts.make_from_manifest (<<["query", <<["destination", a_execution.request.path_info]>> ]>>) + lnk.set_options (opts) + a_execution.add_to_main_menu (lnk) + + create lnk.make ("Sign up", "/user/register") + lnk.set_options (opts) + a_execution.add_to_main_menu (lnk) + end + if a_execution.authenticated then + create lnk.make ("My Account", "/user") + a_menu_system.user_menu.extend (lnk) + create lnk.make ("Logout", "/user/logout") + a_menu_system.user_menu.extend (lnk) + else + create lnk.make ("Login", "/user") + a_menu_system.user_menu.extend (lnk) + end + end + + links: HASH_TABLE [CMS_MODULE_LINK, STRING] + -- Link indexed by path + local +-- lnk: CMS_MODULE_LINK + do + create Result.make (3) +-- create lnk.make ("Date/time demo") +-- lnk.set_callback (agent process_date_time_demo, <<"arg">>) +-- Result["/demo/date/{arg}"] := lnk + end + +-- handle_login (req: WSF_REQUEST; res: WSF_RESPONSE) +-- do +-- (create {USER_LOGIN_CMS_EXECUTION}.make (req, res, service)).execute +-- end + + handle_logout (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {USER_LOGOUT_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_user (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {USER_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_edit (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {USER_EDIT_CMS_EXECUTION}.make (req, res, service)).execute + end + +-- handle_account (req: WSF_REQUEST; res: WSF_RESPONSE) +-- do +-- (create {USER_ACCOUNT_CMS_EXECUTION}.make (req, res, service)).execute +-- end + + handle_register (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {USER_REGISTER_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_request_new_password (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {USER_NEW_PASSWORD_CMS_EXECUTION}.make (req, res, service)).execute + end + + handle_reset_password (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {USER_RESET_PASSWORD_CMS_EXECUTION}.make (req, res, service)).execute + end + + +end diff --git a/draft/application/cms/src/core/modules/user/user_module_lib.e b/draft/application/cms/src/core/modules/user/user_module_lib.e new file mode 100644 index 00000000..e1da1d1d --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_module_lib.e @@ -0,0 +1,29 @@ +note + description: "Summary description for {USER_MODULE_LIB}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + USER_MODULE_LIB + +inherit + CMS_COMMON_API + + CMS_EXECUTION + +feature -- Initialization + + initialize_primary_tabs (u: detachable CMS_USER) + do + if u /= Void then + primary_tabs.extend (create {CMS_LOCAL_LINK}.make ("View", "/user/" + u.id.out)) + primary_tabs.extend (create {CMS_LOCAL_LINK}.make ("Edit", "/user/" + u.id.out + "/edit")) + else + primary_tabs.extend (create {CMS_LOCAL_LINK}.make ("Create new account", "/user/register")) + primary_tabs.extend (create {CMS_LOCAL_LINK}.make ("Log in", "/user")) + primary_tabs.extend (create {CMS_LOCAL_LINK}.make ("Request new password", "/user/password")) + end + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_new_password_cms_execution.e b/draft/application/cms/src/core/modules/user/user_new_password_cms_execution.e new file mode 100644 index 00000000..a4d36faf --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_new_password_cms_execution.e @@ -0,0 +1,154 @@ +note + description: "[ + ]" + +class + USER_NEW_PASSWORD_CMS_EXECUTION + +inherit + CMS_EXECUTION + + USER_MODULE_LIB + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + f: CMS_FORM + u: detachable CMS_USER + fd: detachable CMS_FORM_DATA + e: detachable CMS_EMAIL + l_uuid: UUID + do + set_title ("Request new password") + create b.make_empty + if not request.is_post_request_method and authenticated then + u := user + initialize_primary_tabs (u) + if u /= Void then + if attached u.email as l_email then + f := new_password_form (request.path_info, "new-password") + b.append ("Password reset instructions will be mailed to " + l_email + ". You must " + link ("log out", "/user/logout", Void) + " to use the password reset link in the e-mail.") + b.append (f.to_html (theme)) + else + b.append ("Your account does not have any email address set!") + set_redirection (url ("/user/"+ u.id.out +"/edit", Void)) + end + else + b.append ("Unexpected issue") + end + else + f := new_password_form (request.path_info, "new-password") + if request.is_post_request_method then + create fd.make (request, f) + if attached {WSF_STRING} fd.item ("name") as s_name then + u := service.storage.user_by_name (s_name.value) + if u = Void then + u := service.storage.user_by_email (s_name.value) + if u = Void then + fd.report_invalid_field ("name", "Sorry, " + html_encoded (s_name.value)+ " is not recognized as a user name or an e-mail address.") + end + end + end + end + initialize_primary_tabs (u) + if fd /= Void and then fd.is_valid then + across + fd as c + loop + b.append ("
  • " + html_encoded (c.key) + "=") + if attached c.item as v then + b.append (html_encoded (v.string_representation)) + end + b.append ("
  • ") + end + if u /= Void and then attached u.email as l_mail_address then + l_uuid := (create {UUID_GENERATOR}).generate_uuid + e := new_password_email (u, l_mail_address, l_uuid.out) + u.set_data_item ("new_password_extra", l_uuid.out) + service.storage.save_user (u) + service.mailer.safe_process_email (e) + add_success_message ("Further instructions have been sent to your e-mail address.") + set_redirection (url ("/user", Void)) + end + set_main_content (b) + else + if fd /= Void then + if not fd.is_valid then + report_form_errors (fd) + end + fd.apply_to_associated_form + end + b.append (f.to_html (theme)) + end + end + set_main_content (b) + end + + new_password_form (a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM + require + attached user as l_auth_user implies l_auth_user.has_email + local + u: like user + f: CMS_FORM + ti: CMS_FORM_TEXT_INPUT + th: CMS_FORM_HIDDEN_INPUT + ts: CMS_FORM_SUBMIT_INPUT + err: BOOLEAN + do + create f.make (a_url, a_name) + u := user + if u = Void then + create ti.make ("name") + ti.set_label ("Username or e-mail address") + ti.set_is_required (True) + f.extend (ti) + elseif attached u.email as l_mail then + create th.make ("name") + th.set_default_value (l_mail) + th.set_is_required (True) + f.extend (th) + else + f.extend (create {CMS_FORM_RAW_TEXT}.make ("The associated account has no e-mail address.")) + err := True + end + + if not err then + create ts.make ("op") + ts.set_default_value ("E-mail new password") + f.extend (ts) + end + + Result := f + end + + new_password_email (u: CMS_USER; a_mail_address: STRING; a_extra: READABLE_STRING_8): CMS_EMAIL + local + b: STRING + opts: CMS_URL_API_OPTIONS + dt: detachable DATE_TIME + do + create b.make_empty + create opts.make_absolute + + b.append ("A request to reset the password for your account has been made at " + service.site_name + ".%N") + b.append ("You may now log in by clicking this link or copying and pasting it to your browser:%N%N") + dt := u.last_login_date + if dt = Void then + dt := u.creation_date + end + b.append (url ("/user/reset/" + u.id.out + "/" + unix_timestamp (dt).out + "/" + a_extra, opts)) + b.append ("%N") + b.append ("%N") + b.append ("This link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.%N") + b.append ("%N%N-- The %"" + service.site_name + "%" team") + + create Result.make (service.site_email, a_mail_address, "Account details for " + u.name + " at " + service.site_name, b) + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_register_cms_execution.e b/draft/application/cms/src/core/modules/user/user_register_cms_execution.e new file mode 100644 index 00000000..49602809 --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_register_cms_execution.e @@ -0,0 +1,205 @@ +note + description: "[ + ]" + +class + USER_REGISTER_CMS_EXECUTION + +inherit + CMS_EXECUTION + + USER_MODULE_LIB + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + f: CMS_FORM + fd: detachable CMS_FORM_DATA + u: detachable CMS_USER + up: detachable CMS_USER_PROFILE + e: detachable CMS_EMAIL + l_pass: detachable READABLE_STRING_32 + l_uuid: UUID + do + set_title ("Create new account") + create b.make_empty + if authenticated then + initialize_primary_tabs (user) + b.append ("You are already " + link ("signed in", "/user", Void) + ", please " + link ("signout", "/user/logout", Void) + " before trying to " + link ("register a new account", "/account/register", Void) + ".") + set_redirection (url ("/user", Void)) + else + f := registration_form (request.path_info, "reg") + + if request.is_post_request_method then + create fd.make (request, f) + if attached {WSF_STRING} fd.item ("username") as s_username then + u := service.storage.user_by_name (s_username.value) + if u /= Void then + fd.report_invalid_field ("username", "User already exists!") + end + end + if attached {WSF_STRING} fd.item ("email") as s_email then + u := service.storage.user_by_email (s_email.value) + if u /= Void then + fd.report_invalid_field ("email", "Email is already used!") + end + end + u := Void + end + if fd /= Void and then fd.is_valid then + across + fd as c + loop + b.append ("
  • " + html_encoded (c.key) + "=") + if attached c.item as v then + b.append (html_encoded (v.string_representation)) + end + b.append ("
  • ") + end + if attached {WSF_STRING} fd.item ("username") as s_username then + u := service.storage.user_by_name (s_username.value) + + create u.make_new (s_username.value) + if attached {WSF_STRING} fd.item ("password") as s_password then + u.set_password (s_password.value) + l_pass := u.password + end + if attached {WSF_STRING} fd.item ("email") as s_email then + u.set_email (s_email.value) + end + + if attached {WSF_STRING} fd.item ("note") as s_note then + create up.make + up.force (s_note.value, "note") + u.set_profile (up) + end + + l_uuid := (create {UUID_GENERATOR}).generate_uuid + u.set_data_item ("new_password_extra", l_uuid.out) + + service.storage.save_user (u) + if attached u.email as l_mail_address then + e := new_registration_email (l_mail_address, u, l_pass, l_uuid.out) + service.mailer.safe_process_email (e) + end + e := new_user_account_email (service.site_email, u) + service.mailer.safe_process_email (e) + + login (u, request) + set_redirection (url ("/user", Void)) + end + set_main_content (b) + else + initialize_primary_tabs (user) + if fd /= Void then + if not fd.is_valid then + report_form_errors (fd) + end + fd.apply_to_associated_form + end + b.append (f.to_html (theme)) + end + end + set_main_content (b) + end + + registration_form (a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM + local + f: CMS_FORM + ti: CMS_FORM_TEXT_INPUT + tp: CMS_FORM_PASSWORD_INPUT + ta: CMS_FORM_TEXTAREA + ts: CMS_FORM_SUBMIT_INPUT + do + create f.make (a_url, a_name) + + create ti.make ("username") + ti.set_label ("Username") + ti.set_is_required (True) + ti.set_validation_action (agent (fd: CMS_FORM_DATA) + do + if attached {WSF_STRING} fd.item ("username") as f_username and then f_username.value.count >= 5 then + else + fd.report_invalid_field ("username", "Username should contain at least 5 characters!") + end + end) + f.extend (ti) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create tp.make ("password") + tp.set_label ("Password") + tp.set_is_required (True) + f.extend (tp) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ti.make ("email") + ti.set_label ("Valid email address") + ti.set_is_required (True) + f.extend (ti) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ta.make ("note") + ta.set_label ("Additional note about you") + ta.set_description ("You can use this input to tell us more about you") + ta.set_is_required (False) + f.extend (ta) + + f.extend (create {CMS_FORM_RAW_TEXT}.make ("
    ")) + + create ts.make ("Register") + ts.set_default_value ("Register") + f.extend (ts) + + Result := f + end + + new_registration_email (a_mail_address: STRING; u: CMS_USER; a_password: detachable like {CMS_USER}.password; a_extra: READABLE_STRING_8): CMS_EMAIL + require + has_clear_password: u.password /= Void or else a_password /= Void + local + p: detachable like {CMS_USER}.password + b: STRING + opts: CMS_URL_API_OPTIONS + do + p := a_password + if p = Void then + p := u.password + end + + create b.make_from_string (u.name + "%N" + "Thank you for registering at " + service.site_name + ". ") + create opts.make_absolute +-- if p /= Void then + b.append ("You may now log in to " + url ("/user", opts) + " using your username %""+ u.name +"%" and password%N") +-- b.append ("%Nusername: " + u.name + "%Npassword: " + p + "%N%N") +-- end + b.append ("You may also log in by clicking on this link or copying and pasting it in your browser:%N%N") + b.append (url ("/user/reset/" + u.id.out + "/" + unix_timestamp (u.creation_date).out + "/" + a_extra, opts)) +-- b.append (url ("/user/reset/" + u.id.out + "/" + unix_timestamp (u.creation_date).out + "/", opts)) + b.append ("%N%NThis is a one-time login, so it can be used only once.%N%NAfter logging in, you will be redirected to " + url ("/user/" + u.id.out + "/edit", opts) + " so you can change your password.%N") + b.append ("%N%N-- The %"" + service.site_name + "%" team") + + create Result.make (service.site_email, a_mail_address, "Account details for " + u.name + " at " + service.site_name, b) + end + + new_user_account_email (a_mail_address: STRING; u: CMS_USER): CMS_EMAIL + local + b: STRING + opts: CMS_URL_API_OPTIONS + do + create b.make_from_string ("New user account %"" + u.name + "%" at " + service.site_name + ". ") + create opts.make_absolute + b.append ("See user account: " + user_url (u) + "%N") + b.append ("%N%N-- The %"" + service.site_name + "%" team") + create Result.make (service.site_email, a_mail_address, "New User Account %"" + u.name + "%" at " + service.site_name, b) + end + +end diff --git a/draft/application/cms/src/core/modules/user/user_reset_password_cms_execution.e b/draft/application/cms/src/core/modules/user/user_reset_password_cms_execution.e new file mode 100644 index 00000000..dcf7042d --- /dev/null +++ b/draft/application/cms/src/core/modules/user/user_reset_password_cms_execution.e @@ -0,0 +1,86 @@ +note + description: "[ + ]" + +class + USER_RESET_PASSWORD_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + -- Computed response message. + local + b: STRING_8 + u: detachable CMS_USER + err: BOOLEAN + t: INTEGER_64 + l_extra: detachable READABLE_STRING_8 + do + create b.make_empty + u := user + if u /= Void then + add_success_message ("You are logged in as " + u.name + ". " + link ("Change your password", "/user/" + u.id.out + "/edit", Void)) + set_redirection (front_page_url) + else + if attached {WSF_STRING} request.path_parameter ("uid") as p_uid and then p_uid.is_integer then + u := service.storage.user_by_id (p_uid.integer_value) + end + if u /= Void then + if attached non_empty_string_path_parameter ("last-signed") as p_last_signed then + if p_last_signed.is_integer_64 then + t := p_last_signed.to_integer_64 + else + err := True + end + if t > 0 then + if attached u.last_login_date as l_last then + if t /= unix_timestamp (l_last) then + err := True + end + else + if t /= unix_timestamp (u.creation_date) then + err := True + end + end + end + else + err := True + end + if attached non_empty_string_path_parameter ("extra") as s_extra then + l_extra := s_extra + if l_extra /= Void then + if attached {READABLE_STRING_8} u.data_item ("new_password_extra") as u_extra and then u_extra.same_string (l_extra) then + else + err := True + end + else + err := True + end + else + err := True + end + if not err then + login (u, request) + u.remove_data_item ("new_password_extra") + service.storage.save_user (u) + set_redirection (url ("/user/" + u.id.out + "/edit", Void)) + set_main_content (b) + end + else + err := True + end + if err then + add_warning_message ("The one-time login link you clicked is invalid.") + set_redirection (front_page_url) + end + end + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/core/notification/cms_chain_mailer.e b/draft/application/cms/src/core/notification/cms_chain_mailer.e new file mode 100644 index 00000000..f9f50cad --- /dev/null +++ b/draft/application/cms/src/core/notification/cms_chain_mailer.e @@ -0,0 +1,58 @@ +note + description: "Summary description for {CMS_CHAIN_MAILER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_CHAIN_MAILER + +inherit + CMS_MAILER + +create + make + +feature {NONE} -- Initialization + + make (a_mailer: like active) + do + active := a_mailer + end + +feature -- Access + + active: CMS_MAILER + + next: detachable CMS_MAILER + +feature -- Status + + is_available: BOOLEAN + do + Result := active.is_available + if not Result and attached next as l_next then + Result := l_next.is_available + end + end + +feature -- Change + + set_next (m: like next) + do + next := m + end + +feature -- Basic operation + + process_email (a_email: CMS_EMAIL) + do + if active.is_available then + active.process_email (a_email) + end + if attached next as l_next and then l_next.is_available then + l_next.process_email (a_email) + end + end + +end diff --git a/draft/application/cms/src/core/notification/cms_email.e b/draft/application/cms/src/core/notification/cms_email.e new file mode 100644 index 00000000..90733493 --- /dev/null +++ b/draft/application/cms/src/core/notification/cms_email.e @@ -0,0 +1,94 @@ +note + description : "[ + Component representing an email + ]" + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + CMS_EMAIL + +create + make + +feature {NONE} -- Initialization + + make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_body: like body) + -- Initialize `Current'. + do + initialize + from_address := a_from + subject := a_subject + body := a_body + to_addresses.extend (a_to_address) + + end + + initialize + do + create date.make_now_utc + create to_addresses.make (1) + end + +feature -- Access + + date: DATE_TIME + + from_address: READABLE_STRING_8 + + to_addresses: ARRAYED_LIST [READABLE_STRING_8] + + subject: READABLE_STRING_8 + + body: READABLE_STRING_8 + +feature -- Change + + set_date (d: like date) + do + date := d + end + +feature -- Conversion + + message: STRING_8 + do + Result := header + Result.append ("%N") + Result.append (body) + Result.append ("%N") + Result.append ("%N") + end + + header: STRING_8 + do + create Result.make (20) + Result.append ("From: " + from_address + "%N") + Result.append ("Date: " + date_to_rfc1123_http_date_format (date) + " GMT%N") + Result.append ("To: ") + across + to_addresses as c + loop + Result.append (c.item) + Result.append_character (';') + end + Result.append_character ('%N') + Result.append ("Subject: " + subject + "%N") + ensure + Result.ends_with ("%N") + end + + +feature {NONE} -- Implementation + + date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8 + -- String representation of `dt' using the RFC 1123 + do + Result := dt.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT" + end + +invariant +-- invariant_clause: True + +end diff --git a/draft/application/cms/src/core/notification/cms_external_mailer.e b/draft/application/cms/src/core/notification/cms_external_mailer.e new file mode 100644 index 00000000..0f81db7d --- /dev/null +++ b/draft/application/cms/src/core/notification/cms_external_mailer.e @@ -0,0 +1,190 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + CMS_EXTERNAL_MAILER + +inherit + CMS_MAILER + + EXECUTION_ENVIRONMENT + +create + make + +feature {NONE} -- Initialization + + make (a_exe: like executable_path; args: detachable ITERABLE [READABLE_STRING_8]) + -- Initialize `Current'. + do + set_parameters (a_exe, args) + end + + executable_path: READABLE_STRING_8 + + arguments: detachable ARRAYED_LIST [READABLE_STRING_8] + + stdin_mode_set: BOOLEAN + -- Use `stdin' to pass email message, rather than using local file? + + stdin_termination_sequence: detachable STRING + -- Termination sequence for the stdin mode + --| If any, this tells the executable all the data has been provided + --| For instance, using sendmail, you should have "%N.%N%N" + +feature -- Status + + is_available: BOOLEAN + local + f: RAW_FILE + do + create f.make (executable_path) + Result := f.exists + end + +feature -- Change + + set_parameters (cmd: like executable_path; args: detachable ITERABLE [READABLE_STRING_8]) + -- Set parameters `executable_path' and associated `arguments' + local + l_args: like arguments + do + executable_path := cmd + if args = Void then + arguments := Void + else + create l_args.make (5) + across + args as c + loop + l_args.force (c.item) + end + arguments := l_args + end + end + + set_stdin_mode (b: BOOLEAN; v: like stdin_termination_sequence) + -- Set the `stdin_mode_set' value + -- and provide optional termination sequence when stdin mode is selected. + do + stdin_mode_set := b + stdin_termination_sequence := v + end + +feature -- Basic operation + + process_email (a_email: CMS_EMAIL) + local + l_factory: PROCESS_FACTORY + args: like arguments + p: detachable PROCESS + retried: INTEGER + do + if retried = 0 then + create l_factory + if stdin_mode_set then + p := l_factory.process_launcher (executable_path, arguments, Void) + p.set_hidden (True) + p.set_separate_console (False) + + p.redirect_input_to_stream + p.launch + if p.launched then + p.put_string (a_email.message) + if attached stdin_termination_sequence as v then + p.put_string (v) + end + end + else + if attached arguments as l_args then + args := l_args.twin + else + if attached {RAW_FILE} new_temporary_file (generator) as f then + f.create_read_write + f.put_string (a_email.message) + f.close + create args.make (1) + args.force (f.name) + end + end + p := l_factory.process_launcher (executable_path, args, Void) + p.set_hidden (True) + p.set_separate_console (False) + + p.launch + end + if p.launched and not p.has_exited then + p.wait_for_exit_with_timeout (1_000_000) + if not p.has_exited then + p.terminate + if not p.has_exited then + p.wait_for_exit_with_timeout (1_000_000) + end + end + end + elseif retried = 1 then + if p /= Void and then p.launched and then not p.has_exited then + p.terminate + if not p.has_exited then + p.wait_for_exit_with_timeout (1_000_000) + end + end + end + rescue + retried := retried + 1 + retry + end + +feature {NONE} -- Implementation + + new_temporary_file (a_extension: detachable STRING_8): RAW_FILE + -- Create file with temporary name. + -- With concurrent execution, noting ensures that {FILE_NAME}.make_temporary_name is unique + -- So using `a_extension' may help + local + fn: FILE_NAME + s: like {FILE_NAME}.string + f: detachable like new_temporary_file + i: INTEGER + do + -- With concurrent execution, nothing ensures that {FILE_NAME}.make_temporary_name is unique + -- So let's try to find + from + until + f /= Void or i > 1000 + loop + create fn.make_temporary_name + s := fn.string + if i > 0 then + s.append_character ('-') + s.append_integer (i) + create fn.make_from_string (s) + end + if a_extension /= Void then + fn.add_extension (a_extension) + end + s := fn.string + create f.make (fn.string) + if f.exists then + i := i + 1 + f := Void + end + end + if f = Void then + Result := new_temporary_file (Void) + else + Result := f + check not_temporary_file_exists: not Result.exists end + check temporary_creatable: Result.is_creatable end + end + ensure + not_result_exists: not Result.exists + result_creatable: Result.is_creatable + end + +invariant + +end diff --git a/draft/application/cms/src/core/notification/cms_mailer.e b/draft/application/cms/src/core/notification/cms_mailer.e new file mode 100644 index 00000000..fe98a701 --- /dev/null +++ b/draft/application/cms/src/core/notification/cms_mailer.e @@ -0,0 +1,48 @@ +note + description : "[ + Component responsible to send email + ]" + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +deferred class + CMS_MAILER + +feature -- Status + + is_available: BOOLEAN + -- Is mailer available to use? + deferred + end + +feature -- Basic operation + + process_emails (lst: ITERABLE [CMS_EMAIL]) + -- Process set of emails `lst' + require + is_available + do + across + lst as c + loop + process_email (c.item) + end + end + + safe_process_email (a_email: CMS_EMAIL) + -- Same as `process_email', but include the check of `is_available' + do + if is_available then + process_email (a_email) + end + end + + process_email (a_email: CMS_EMAIL) + -- Process the sending of `a_email' + require + is_available + deferred + end + +end diff --git a/draft/application/cms/src/core/notification/cms_sendmail_mailer.e b/draft/application/cms/src/core/notification/cms_sendmail_mailer.e new file mode 100644 index 00000000..264b7e1c --- /dev/null +++ b/draft/application/cms/src/core/notification/cms_sendmail_mailer.e @@ -0,0 +1,34 @@ +note + description : "[ + CMS_MAILER using sendmail as mailtool + ]" + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + CMS_SENDMAIL_MAILER + +inherit + CMS_EXTERNAL_MAILER + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + Precursor + make ("/usr/sbin/sendmail", <<"-t">>) + if not is_available then + make ("/usr/bin/sendmail", <<"-t">>) + end + set_stdin_mode (True, "%N.%N%N") + end + + +end diff --git a/draft/application/cms/src/core/notification/cms_storage_mailer.e b/draft/application/cms/src/core/notification/cms_storage_mailer.e new file mode 100644 index 00000000..c57e8b58 --- /dev/null +++ b/draft/application/cms/src/core/notification/cms_storage_mailer.e @@ -0,0 +1,38 @@ +note + description: "Summary description for {CMS_CHAIN_MAILER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_STORAGE_MAILER + +inherit + CMS_MAILER + +create + make + +feature {NONE} -- Initialization + + make (a_storage: like storage) + do + storage := a_storage + end + +feature -- Access + + storage: CMS_STORAGE + +feature -- Status + + is_available: BOOLEAN = True + +feature -- Basic operation + + process_email (a_email: CMS_EMAIL) + do + storage.save_email (a_email) + end + +end diff --git a/draft/application/cms/src/core/storage/cms_sed_storage.e b/draft/application/cms/src/core/storage/cms_sed_storage.e new file mode 100644 index 00000000..1ca3f8bb --- /dev/null +++ b/draft/application/cms/src/core/storage/cms_sed_storage.e @@ -0,0 +1,518 @@ +note + description : "[ + CMS Storage implemented using SED + ]" + date : "$Date$" + revision : "$Revision$" + +class + CMS_SED_STORAGE + +inherit + CMS_STORAGE + +create + make + +feature {NONE} -- Initialization + + make (dn: STRING) + -- Initialize `Current'. + do + directory_name := dn + ensure_directory_exists (dn) + create sed + initialize + end + + directory_name: STRING + + sed: SED_STORABLE_FACILITIES + + sed_file_retrieved (f: FILE): detachable ANY + local + r: SED_MEDIUM_READER_WRITER + do + create r.make (f) + r.set_for_reading + Result := sed.retrieved (r, True) + end + + sed_file_store (obj: ANY; f: FILE) + local + w: SED_MEDIUM_READER_WRITER + do + create w.make (f) + w.set_for_writing + sed.store (obj, w) + end + + save_object_with_id (obj: ANY; a_id: INTEGER; a_type: STRING) + local + dn: STRING + fn: FILE_NAME + f: RAW_FILE + do + create fn.make_from_string (directory_name) + fn.extend (a_type) + dn := fn.string + ensure_directory_exists (dn) + create fn.make_from_string (dn) + fn.set_file_name (a_id.out) +-- fn.add_extension ("txt") + create f.make (fn.string) +-- check not f.exists end + f.create_read_write + sed_file_store (obj, f) + f.close + end + + object_with_id (a_id: INTEGER; a_type: STRING): detachable ANY + local + dn: STRING + fn: FILE_NAME + f: RAW_FILE + do + create fn.make_from_string (directory_name) + fn.extend (a_type) + dn := fn.string + ensure_directory_exists (dn) + create fn.make_from_string (dn) + fn.set_file_name (a_id.out) +-- fn.add_extension ("txt") + create f.make (fn.string) + if f.exists and f.is_readable then + f.open_read + Result := sed_file_retrieved (f) + f.close + end + end + +feature -- Access: user + + users_count: INTEGER + do + Result := last_sequence ("user") + end + + fill_user_profile (a_user: CMS_USER) + do + if a_user.profile = Void then + if attached user_profile (a_user) as p then + a_user.set_profile (p) + end + end + end + + all_users: LIST [CMS_USER] + local + res: ARRAYED_LIST [like all_users.item] + i, n: like last_sequence + do + n := last_sequence ("user") + create res.make (n) + from + i := 1 + until + i > n + loop + if attached user_by_id (i) as u then + res.force (u) + end + i := i + 1 + end + Result := res + end + + user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER + do + if attached {like user_by_id} object_with_id (a_id, "user") as u then + Result := u + end + end + + user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER + local + uid: INTEGER + do + if attached users_index as t then + uid := t.by_name.item (a_name) + if uid > 0 then + Result := user_by_id (uid) + end + end + end + + user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER + local + uid: INTEGER + do + if attached users_index as t then + uid := t.by_email.item (a_email) + if uid > 0 then + Result := user_by_id (uid) + end + end + end + + encoded_password (a_raw_password: STRING_32): attached like {CMS_USER}.encoded_password + do + Result := a_raw_password.as_string_8 + "!123!" + end + +feature -- Change: user + + save_user (a_user: CMS_USER) + local + uid: INTEGER + prof: like {CMS_USER}.profile + l_has_new_name: BOOLEAN + l_has_new_email: BOOLEAN + l_stored_user: like user_by_id + do + if a_user.has_id then + uid := a_user.id + l_stored_user := user_by_id (uid) + if l_stored_user /= Void then + l_has_new_name := not l_stored_user.name.same_string (a_user.name) + l_has_new_email := not (l_stored_user.email ~ a_user.email) + end + else + l_has_new_name := True + l_has_new_email := True + uid := next_sequence ("user") + a_user.set_id (uid) + end + if attached a_user.password as p then + a_user.set_encoded_password (encoded_password (p)) + a_user.set_password (Void) + end + + prof := a_user.profile + a_user.set_profile (Void) + if prof /= Void then + save_user_profile (a_user, prof) + end + save_object_with_id (a_user, uid, "user") + if l_has_new_name or l_has_new_email then + if attached users_index as l_index then + l_index.by_name.force (uid, a_user.name) + l_index.by_email.force (uid, a_user.email) + store_users_index (l_index) + end + end + a_user.set_profile (prof) + end + +feature -- Email + + save_email (a_email: CMS_EMAIL) + local + dn: STRING + fn: FILE_NAME + f: RAW_FILE + ts: INTEGER_64 + i: INTEGER + do + create fn.make_from_string (directory_name) + fn.extend ("emails") + dn := fn.string + ensure_directory_exists (dn) + ts := (create {HTTP_DATE_TIME_UTILITIES}).unix_time_stamp (a_email.date) + from + create fn.make_from_string (dn) + fn.set_file_name (ts.out) + fn.add_extension ("txt") + create f.make (fn.string) + until + not f.exists + loop + i := i + 1 + create fn.make_from_string (dn) + fn.set_file_name (ts.out + "-" + i.out) + fn.add_extension ("txt") + f.make (fn.string) + end + f.create_read_write + f.put_string (a_email.message) + f.close + end + +feature -- Log + + log (a_id: like {CMS_LOG}.id): detachable CMS_LOG + do + if attached {CMS_LOG} object_with_id (a_id, "log") as l then + Result := l + end + end + + recent_logs (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG] + local + n: Like last_sequence + i, p1, nb: INTEGER + do + n := last_sequence ("log") + p1 := n - a_lower + 1 + + if p1 > 0 then + create {ARRAYED_LIST [CMS_LOG]} Result.make (a_count) + from + i := p1 + until + i < 1 or nb = a_count + loop + if attached log (i) as obj then + Result.force (obj) + nb := nb + 1 + end + i := i - 1 + end + else + create {ARRAYED_LIST [CMS_LOG]} Result.make (0) + end + end + + + save_log (a_log: CMS_LOG) + do + if not a_log.has_id then + a_log.set_id (next_sequence ("log")) + end + save_object_with_id (a_log, a_log.id, "log") + end + +feature -- Node + + recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] + local + n: Like last_sequence + i, p1, nb: INTEGER + do + n := last_sequence ("node") + p1 := n - a_lower + 1 + + if p1 > 0 then + create {ARRAYED_LIST [CMS_NODE]} Result.make (a_count) + from + i := p1 + until + i < 1 or nb = a_count + loop + if attached node (i) as l_node then + Result.force (l_node) + nb := nb + 1 + end + i := i - 1 + end + else + create {ARRAYED_LIST [CMS_NODE]} Result.make (0) + end + end + + node (a_id: INTEGER): detachable CMS_NODE + do + if attached {like node} object_with_id (a_id, "node") as obj then + Result := obj + end + end + + save_node (a_node: CMS_NODE) + local + nid: INTEGER + do + if a_node.has_id then + nid := a_node.id + else + nid := next_sequence ("node") + a_node.set_id (nid) + end + + save_object_with_id (a_node, nid, "node") + end + +feature {NONE} -- Implementation + + last_sequence (a_type: STRING): INTEGER + local + fn: FILE_NAME + f: RAW_FILE + do + create fn.make_from_string (directory_name) + fn.set_file_name (a_type) + fn.add_extension ("last_id") + create f.make (fn.string) + if f.exists and then f.is_readable then + f.open_read + f.read_line + if f.last_string.is_integer then + Result := f.last_string.to_integer + else + check is_integer: False end + end + f.close + end + end + + next_sequence (a_type: STRING): INTEGER + local + fn: FILE_NAME + f: RAW_FILE + do + create fn.make_from_string (directory_name) + fn.set_file_name (a_type) + fn.add_extension ("last_id") + create f.make (fn.string) + if f.exists and then f.is_readable then + f.open_read + f.read_line + if f.last_string.is_integer then + Result := f.last_string.to_integer + else + check is_integer: False end + end + f.close + end + Result := Result + 1 + f.open_write + f.put_string (Result.out) + f.put_new_line + f.close + end + + users_index: TUPLE [ + by_name: HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.name]; + by_email: HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.email] + ] + local + f: RAW_FILE + fn: FILE_NAME + res: detachable like users_index + retried: INTEGER + do + create fn.make_from_string (directory_name) + fn.set_file_name ("users.db") + create f.make (fn.string) + if retried = 0 then + if f.exists and then f.is_readable then + f.open_read + if attached {like users_index} sed_file_retrieved (f) as r then + res := r + end + f.close + else + end + end + if res = Void then + res := [ create {HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.name]}.make (1), + create {HASH_TABLE [like {CMS_USER}.id, like {CMS_USER}.email]}.make (1) ] + end + Result := res + rescue + retried := retried + 1 + retry + end + + store_users_index (a_users_index: like users_index) + local + f: RAW_FILE + fn: FILE_NAME + do + create fn.make_from_string (directory_name) + fn.set_file_name ("users.db") + create f.make (fn.string) + if not f.exists or else f.is_writable then + f.open_write + sed_file_store (a_users_index, f) + f.close + end + end + + user_profile (a_user: CMS_USER): detachable CMS_USER_PROFILE + do + if attached {like user_profile} object_with_id (a_user.id, "user_profile") as obj then + Result := obj + end + end + + save_user_profile (a_user: CMS_USER; a_prof: CMS_USER_PROFILE) + local + l_id: INTEGER + do + if a_user.has_id then + l_id := a_user.id + end + + save_object_with_id (a_prof, l_id, "user_profile") + end + +-- user_profiles: TUPLE [by_username: HASH_TABLE [CMS_USER_PROFILE, like {CMS_USER}.name]] +-- local +-- f: RAW_FILE +-- fn: FILE_NAME +-- res: detachable like user_profiles +-- retried: INTEGER +-- do +-- if retried = 0 then +-- create fn.make_from_string (directory_name) +-- fn.set_file_name ("user_profiles.db") +-- create f.make (fn.string) +-- if f.exists and then f.is_readable then +-- f.open_read +-- if attached {like user_profiles} sed_file_retrieved (f) as r then +-- res := r +-- end +-- f.close +-- else +-- end +-- end +-- if res = Void then +-- res := [create {HASH_TABLE [CMS_USER_PROFILE, like {CMS_USER}.name]}.make (1)] +-- if retried <= 1 then +-- store_user_profiles (res) +-- end +-- end +-- Result := res +-- rescue +-- retried := retried + 1 +-- retry +-- end + +-- store_user_profiles (a_user_profiles: like user_profiles) +-- local +-- f: RAW_FILE +-- fn: FILE_NAME +-- do +-- create fn.make_from_string (directory_name) +-- fn.set_file_name ("user_profiles.db") +-- create f.make (fn.string) +-- if not f.exists or else f.is_writable then +-- f.open_write +-- sed_file_store (a_user_profiles, f) +-- f.close +-- end +-- end + +feature {NONE} -- Implementation + + ensure_directory_exists (dn: STRING) + local + d: DIRECTORY + do + d := tmp_dir + d.make (dn) + if not d.exists then + d.recursive_create_dir + end + end + +feature {NONE} -- Implementation + + tmp_dir: DIRECTORY + once + create Result.make (directory_name) + end + +invariant + +end diff --git a/draft/application/cms/src/core/storage/cms_storage.e b/draft/application/cms/src/core/storage/cms_storage.e new file mode 100644 index 00000000..cfd9aec5 --- /dev/null +++ b/draft/application/cms/src/core/storage/cms_storage.e @@ -0,0 +1,105 @@ +note + description : "[ + CMS interface to storage + ]" + date : "$Date$" + revision : "$Revision$" + +deferred class + CMS_STORAGE + +feature {NONE} -- Initialization + + initialize + do + end + +feature -- Access: user + + users_count: INTEGER + deferred + end + + fill_user_profile (a_user: CMS_USER) + deferred + end + + all_users: LIST [CMS_USER] + deferred + end + + user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER + require + a_id > 0 + deferred + ensure + same_id: Result /= Void implies Result.id = a_id + no_password: Result /= Void implies Result.password = Void + end + + user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER + require + a_name /= Void and then not a_name.is_empty + deferred + ensure + no_password: Result /= Void implies Result.password = Void + end + + user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER + deferred + ensure + no_password: Result /= Void implies Result.password = Void + end + + encoded_password (a_raw_password: STRING_32): attached like {CMS_USER}.encoded_password + deferred + end + +feature -- Change: user + + save_user (a_user: CMS_USER) + deferred + ensure + a_user_password_is_encoded: a_user.password = Void and a_user.encoded_password /= Void + a_user.has_id + end + +feature -- Email + + save_email (a_email: CMS_EMAIL) + deferred + end + +feature -- Log + + recent_logs (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG] + deferred + end + + log (a_id: like {CMS_LOG}.id): detachable CMS_LOG + require + a_id > 0 + deferred + end + + save_log (a_log: CMS_LOG) + deferred + end + +feature -- Node + + recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE] + deferred + end + + node (a_id: INTEGER): detachable CMS_NODE + require + a_id > 0 + deferred + end + + save_node (a_node: CMS_NODE) + deferred + end + +end diff --git a/draft/application/cms/src/core/theme/cms_html_template.e b/draft/application/cms/src/core/theme/cms_html_template.e new file mode 100644 index 00000000..86a93f50 --- /dev/null +++ b/draft/application/cms/src/core/theme/cms_html_template.e @@ -0,0 +1,13 @@ +note + description: "Summary description for {WSF_CMS_HTML_TEMPLATE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_HTML_TEMPLATE + +inherit + CMS_TEMPLATE + +end diff --git a/draft/application/cms/src/core/theme/cms_page_template.e b/draft/application/cms/src/core/theme/cms_page_template.e new file mode 100644 index 00000000..74c36646 --- /dev/null +++ b/draft/application/cms/src/core/theme/cms_page_template.e @@ -0,0 +1,12 @@ +note + description: "Summary description for {CMS_PAGE_TEMPLATE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_PAGE_TEMPLATE + +inherit + CMS_TEMPLATE +end diff --git a/draft/application/cms/src/core/theme/cms_template.e b/draft/application/cms/src/core/theme/cms_template.e new file mode 100644 index 00000000..791844c9 --- /dev/null +++ b/draft/application/cms/src/core/theme/cms_template.e @@ -0,0 +1,81 @@ +note + description: "Summary description for {WSF_CMS_PAGE_TEMPLATE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_TEMPLATE + +feature -- Access + + theme: CMS_THEME + deferred + end + + variables: HASH_TABLE [detachable ANY, STRING] + deferred + end + + prepare (page: CMS_HTML_PAGE) + deferred + end + + to_html (page: CMS_HTML_PAGE): STRING + deferred + end + +feature {NONE} -- Implementation + + apply_template_engine (s: STRING_8) + local + p,n: INTEGER + k: STRING + sv: detachable STRING + do + from + n := s.count + p := 1 + until + p = 0 + loop + p := s.index_of ('$', p) + if p > 0 then + k := next_identifier (s, p + 1) + s.remove_substring (p, p + k.count) + sv := Void + if attached variables.item (k) as l_value then + + if attached {STRING_8} l_value as s8 then + sv := s8 + elseif attached {STRING_32} l_value as s32 then + sv := s32.as_string_8 -- FIXME: use html encoder + else + sv := l_value.out + end + s.insert_string (sv, p) + p := p + sv.count + else + debug + s.insert_string ("$" + k, p) + end + end + end + end + end + + next_identifier (s: STRING; a_index: INTEGER): STRING + local + i: INTEGER + do + from + i := a_index + until + not (s[i].is_alpha_numeric or s[i] = '_' or s[i] = '.') + loop + i := i + 1 + end + Result := s.substring (a_index, i - 1) + end + +end diff --git a/draft/application/cms/src/core/theme/cms_theme.e b/draft/application/cms/src/core/theme/cms_theme.e new file mode 100644 index 00000000..bc3630a1 --- /dev/null +++ b/draft/application/cms/src/core/theme/cms_theme.e @@ -0,0 +1,69 @@ +note + description: "Summary description for {WSF_CMS_THEME}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_THEME + +inherit + CMS_COMMON_API + + +feature {NONE} -- Access + + service: CMS_SERVICE + deferred + end + + base_url: detachable READABLE_STRING_8 + -- Base url if any. + do + Result := service.base_url + end + +feature -- Access + + name: STRING + deferred + end + + regions: ARRAY [STRING] + deferred +-- Result := <<"header", "content", "footer">> + end + + page_template: CMS_TEMPLATE + deferred + end + +feature -- Conversion + + menu_html (a_menu: CMS_MENU; is_horizontal: BOOLEAN): STRING_8 + do + create Result.make_from_string ("
    ") + if is_horizontal then + Result.append ("
      %N") + else + Result.append ("
        %N") + end + across + a_menu as c + loop + if c.item.is_active then + Result.append ("
      • ") + else + Result.append ("
      • ") + end + Result.append ("" + html_encoded (c.item.title) + "
      • ") + end + Result.append ("
      %N") + Result.append ("
    ") + end + + page_html (page: CMS_HTML_PAGE): STRING_8 + deferred + end + +end diff --git a/draft/application/cms/src/module/demo/demo_module.e b/draft/application/cms/src/module/demo/demo_module.e new file mode 100644 index 00000000..8e028ead --- /dev/null +++ b/draft/application/cms/src/module/demo/demo_module.e @@ -0,0 +1,60 @@ +note + description: "Summary description for {CMS_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DEMO_MODULE + +inherit + CMS_MODULE + +create + make + +feature {NONE} -- Initialization + + make (a_service: like service) + do + service := a_service + name := "demo" + version := "1.0" + description := "demo" + package := "misc" + end + +feature {CMS_SERVICE} -- Registration + + service: CMS_SERVICE + + register (a_service: CMS_SERVICE) + do + a_service.map_uri_template ("/demo/date/{arg}", agent handle_date_time_demo) + a_service.map_uri_template ("/demo/format/{arg}", agent handle_format_demo) + end + +feature -- Hooks + + links: HASH_TABLE [CMS_MODULE_LINK, STRING] + -- Link indexed by path + local +-- lnk: CMS_MODULE_LINK + do + create Result.make (3) +-- create lnk.make ("Date/time demo") +-- lnk.set_callback (agent process_date_time_demo, <<"arg">>) +-- Result["/demo/date/{arg}"] := lnk + end + + handle_date_time_demo (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ANY_CMS_EXECUTION}.make_with_text (req, res, service, "

    Demo::date/time

    ")).execute + end + + handle_format_demo (req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ANY_CMS_EXECUTION}.make_with_text (req, res, service, "

    Demo::format

    ")).execute + end + +end diff --git a/draft/application/cms/src/module/shutdown/shutdown_cms_execution.e b/draft/application/cms/src/module/shutdown/shutdown_cms_execution.e new file mode 100644 index 00000000..4c61e9c9 --- /dev/null +++ b/draft/application/cms/src/module/shutdown/shutdown_cms_execution.e @@ -0,0 +1,33 @@ +note + description: "Summary description for {SHUTDOWN_CMS_EXECUTION}." + date: "$Date$" + revision: "$Revision$" + +class + SHUTDOWN_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + local + b: STRING + do + create b.make_empty + set_title ("Shutting down the service ...") + if has_permission ("admin shutdown") then + if attached {WGI_NINO_CONNECTOR} request.wgi_connector as nino then + nino.server.shutdown_server + end + else + b.append ("Access denied") + end + set_main_content (b) + end + +end diff --git a/draft/application/cms/src/module/shutdown/shutdown_module.e b/draft/application/cms/src/module/shutdown/shutdown_module.e new file mode 100644 index 00000000..2a540066 --- /dev/null +++ b/draft/application/cms/src/module/shutdown/shutdown_module.e @@ -0,0 +1,72 @@ +note + description: "Summary description for {SHUTDOWN_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + SHUTDOWN_MODULE + +inherit + CMS_MODULE + + CMS_HOOK_MENU_ALTER + +create + make + +feature {NONE} -- Initialization + + make + do + name := "shutdown" + version := "1.0" + description := "Shutdown the service if this is EWF Nino or FCGI" + package := "server" + end + +feature {CMS_SERVICE} -- Registration + + service: detachable CMS_SERVICE + + register (a_service: CMS_SERVICE) + do + a_service.map_uri ("/admin/shutdown/", agent handle_shutdown) + + a_service.add_menu_alter_hook (Current) + service := a_service + end + +feature -- Hooks + + menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) + local + lnk: CMS_LOCAL_LINK + do + create lnk.make ("Shutdown", "/admin/shutdown/") + lnk.set_permission_arguments (<<"admin shutdown">>) + a_menu_system.management_menu.extend (lnk) + + end + + links: HASH_TABLE [CMS_MODULE_LINK, STRING] + -- Link indexed by path + local +-- lnk: CMS_MODULE_LINK + do + create Result.make (3) +-- create lnk.make ("Date/time demo") +-- lnk.set_callback (agent process_date_time_demo, <<"arg">>) +-- Result["/demo/date/{arg}"] := lnk + end + + handle_shutdown (req: WSF_REQUEST; res: WSF_RESPONSE) + do + if attached service as l_service then + (create {SHUTDOWN_CMS_EXECUTION}.make (req, res, l_service)).execute ; + else + res.set_status_code ({HTTP_STATUS_CODE}.expectation_failed) + end + end + +end diff --git a/draft/application/cms/src/web_cms.e b/draft/application/cms/src/web_cms.e new file mode 100644 index 00000000..35452815 --- /dev/null +++ b/draft/application/cms/src/web_cms.e @@ -0,0 +1,116 @@ +note + description: "[ + This class implements the Demo of WEB CMS service + + ]" + +class + WEB_CMS + +inherit + CMS_SERVICE + redefine + modules + end + + WSF_DEFAULT_SERVICE + redefine + initialize + end + +create + make_and_launch + +feature -- Initialization + + base_url: detachable READABLE_STRING_8 + + modules: ARRAYED_LIST [CMS_MODULE] + local + m: CMS_MODULE + once + Result := Precursor + + -- Others + create {DEMO_MODULE} m.make (Current) + m.enable + Result.extend (m) + + create {SHUTDOWN_MODULE} m.make + m.enable + Result.extend (m) + +-- create {EIFFEL_LOGIN_MODULE} m.make +-- m.enable +-- Result.extend (m) + end + +feature {NONE} -- Initialization + + initialize + local + args: ARGUMENTS + cfg: detachable STRING + i,n: INTEGER + cms_config: CMS_CONFIGURATION + opts: WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI + do + create args + from + i := 1 + n := args.argument_count + until + i > n or cfg /= Void + loop + if attached args.argument (i) as s then + if s.same_string ("--config") or s.same_string ("-c") then + if i < n then + cfg := args.argument (i + 1) + end + end + end + i := i + 1 + end + if cfg = Void then + if file_exists ("cms.ini") then + cfg := "cms.ini" + end + end + if cfg /= Void then + create cms_config.make_from_file (cfg) +-- (create {EXECUTION_ENVIRONMENT}).change_working_directory (dir) + else + create cms_config.make + end + + --| The following line is to be able to load options from the file ewf.ini + create opts.make_from_file ("ewf.ini") + service_options := opts + + --| If you don't need any custom options, you are not obliged to redefine `initialize' + Precursor + base_url := cms_config.site_base_url (base_url) + initialize_cms + site_email := cms_config.site_email (site_email) + site_name := cms_config.site_name (site_name) + + on_launched + end + + on_launched + local + e: CMS_EMAIL + do + create e.make (site_email, site_email, "[" + site_name + "] launched...", "The site [" + site_name + "] was launched at " + (create {DATE_TIME}.make_now_utc).out + " UTC.") + mailer.safe_process_email (e) + end + + file_exists (fn: STRING): BOOLEAN + local + f: RAW_FILE + do + create f.make (fn) + Result := f.exists and then f.is_readable + end + +end diff --git a/draft/application/cms/themes/default/res/favicon.ico b/draft/application/cms/themes/default/res/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..343067f9fc7b0829212336f7f67fa96328ba71a3 GIT binary patch literal 786 zcmV+t1MU0(0096201yxW0096X0Q>>~02TlM0EtjeM-2)Z3IG5A4M|8uQUCw|5C8xG z5C{eU001BJ|6u?C0>eo}K~y-)rITAo({U8XKfnL}o7;5Gf7`#NrbcCZOZiN?Bp`q9v&rArV=Mld@&Dx&PKSEvK3Odzg!e zdg==Y&VlnioXhtJ{y^)!D+Qj;_Oh_%%bysJ<^fo3_I^c8?_0KhQ`6SsL$80&7YRq# zb#dK&yr#S5R<$jsp}U>;>vzx2%kf@ zM}q!Xb8AIj|+G1a}*ss!q;$!u9gNI=~);}Nn|WuPWQtmEGag2R2(H5 z3NY+>%k|po(4MN(TVzjXdzm)kb-1#Z@a91;2P!kRBXF{9OHCrxz`4UXc>%)w-~5YhasShJar1HA|#NK;+d z6ej>-&6h7HPSxMj!LGwqAOt3h72l8tAxZd#Jh&DuB@!Iv+gOBp_laLiofwbi$%)`; z^EJW)FG#g3jQhP@J9&Vw(-Mozt@+e#{WR~MDKqtg;aSx~(aa#Q0)2BUG}^lZF?d<9f9#AXDmi%Q+wN-BEAFDV}@ zZyxPvD3+Ne5QAi6ybF^AsiyeiTvnJ75(_r$yB$0D_Y3q952X)P+y6pC29P$?E$7oY+GgzT9tlVmapStr|M zoB7>8CbMOhYhGiQFk_kEuCeZKGeJn#AwL{a1hA*#2t{l1>Awq>H#mSC~;DTn&| zl|z<(6@XkBG9V8Lu_%?H79mK|8Xgt*Nmz935uocvR4&YrNJ_iW@MvF8_ub94mFh44 zdO%%y>8z}`yCa}dSY!-2`HM$xU%TF<$;dHdSste&O?i z(}(_`sVymkcHOWNn#9 zb|NCG)_VO1MXzqZ?d- zgmWhjhnzcc=+XA(#=`M=<6|WH+S$_=UU+0hh9e>$RP3a8#}s|$&YO#tBJ{@-C89U(@YOu@2M zNM*qYg7*mj&m;R7=r!~F{(scYUA+7jpwpQtilXypGU)ehz9ZLme+J_H8Hf++WMcJ| zFU3H3cjr&VKmOuL=ldUa{6uu4%-QBfP>#h~AFzU;lP4TUj_mP#iaDonp`tmET zLUQu}kOj+GQTQWgx?HJZ*#l1i5Ti~eG%^|hL-|(#tlGF0S+IP8;hL}uBE#3!et3<>j)b&yOO z`v<5WBa)b!E`sI-y_;=9{T;g-OlItc5O>an?3(cb(-$`?nJZ|7rw~rFg1E8 zN@c;$=Z}lt;)6F{^djQG^~O5llhaAbnTsHi5TBIp%o`l&L!k;KJ~`ck5P+e=PDCPc zImgRCUQ5}RpZcu}pu^Ni#f2~O)M+{`V3Yu~8S6KkI{2nKkfL0nA}%S->!%D22VCwY zSE@)%&2kzoiXxR4&j2{dIeHCTuH_D?EZApVK|xXvxl;$x`6c1eIpV@-u-raQ&@GFQN- z&B}B3NPBYwEe1Vc-+Lry&vwRxQD2UAbY$9filT_Ira}WmN_#uo@B94N0nJ28=8o(1 zo4t3Xeckqg+Gc{i_EgD@5k?mF(c-dM-z$go$sue8sP9nj3X z?R)o0d%D_|S6}{8HW86yZ@t9vw_ov_-_}%5e@{0d;gO`~=Alr90`{P6sndRlsdb-+{OGKM3aiTpofHq^+gfb0d!*EPu5+UJ{fW1fB zjRvgNQ2e-f=u^6K7y{^gHc{KtoY zedNkr_-&8;_T~nx)=}Dx1`<*-J@VY=pP68I$fA-CSqA(PsV}?i@xEZ`N-vr6^Pf4N zD~ivs^3kW9@1iKuSX~N0ZOJ7MBBr`3dOF*tZ@n9aECVXZ@Zg|dBE_E^=i{Qcyk=N` z`1eOgXsEpAdjH#BXs)dU;OHAWv01IoyrMncL-}+uJUFNlu6*|Qnw^i`nGr}ZEHZ|K z)J)_GZ_X_SJsmBs(;JywLH>8XPhWQ@W#>P|eOQl*SChBoPAZGfV5+b7C?{i1fpbZt zzj~e_i{D+X7oL0P@3qokguFDDY#q=GI2WIpz#hic%XM(=b0xl%PCmC02WK@jjYv&$s#vpk3h z_MtrnN9!(%hwr*gs}E$_jjc4h%KA|*M2)S~=f!}<3VW_Xa1cD52jKx`vtU1)Zb1-` z$yFAKL?W0%BV&9DMau(|aL26)<0=4dj&r^1B3vXKD2Rg~0kXmalL&;+$QUFN!6Xfj ziaVW?zxY2cp8n9Qs8F|*jv;&N8G1cs933h5;rH1QuIE{i-uY6&?yjM3i(1nFym}3c z{hqSEVh$iDfAL6oRNQGvSaj@>C2QB4e2clzW&yn!Mr@wHQ6CkwSnU6q;UEz_iHJa} z#eY5RgZ9Q6UyscXktJ)_o5G@Fk4S-Tb-K{UW zlC#4hH58O%u2d(kn0v7C7s^#BR2T69{T-kO_D-<$Jp|98=GS^Df_{-XE*8c7Zpb* zXtkZK#u-p>8CGS6*->^Pj@}SODC>qbK6E}d!lx}TFB;?$K!67`T`s7LfC|^y1JMau zboq;l0TZ~LG-}dwHf?xzkKe1Wpef#nI9gsC0(0yqKh*X4Z*_oSt34jhw8EJd_{6PE z$5+4M**y)K^qftOclX_VQ|8=)Q_0!0pJ=Qu6~HyLf<0*G$3XYEP1@k7Ym{z#HV+rGyaZ$l=XR>ekAH4j5+w}1IS=o*4cV`UX?-Pxv2(`{$m{i1ZdQmiJqXwm9* z`G$(Geth=C;n3YzAwSl>jtcdX21DQ2f3K@mM#o01KiAktoM<_`Q)Q0+@(zQ z>J1pwX5}v3ytnA&?Q0(D`+7{A7`Lx^sBiP$qLYD0z$CAyTN-O#K7aCq#}2;qv)CK> z?Mgrhg22Q7^PBdCcir<&Vshrw6UtBegMsG8!nUURUHe{mDy6>c%GdhAK-x|7#mArD z+YpzO_KdH<_J!$u!tt`9;_Ax%yS61cuGnrA;F!vRhQ2R)7=6H5(&Bmi^OFQJYmY3cgy)?-JG8=wtkvYIWzS6#FmDd z4VE7B+7?5#=JR8J(o|phx2&hL&F2{a*nK}dI*#o5-x^u+gNK?EQ?r|u;SqmLOv!u? zXqm1dGbQ4V(C+Ik_xAU8t+d%h^~lhGYREF6bQ}N%D-;8ArOG0cs|F+z!4wh}^-*Me f;!)s+jEMgaKSv*+{l^)l00000NkvXXu0mjf$2x5w literal 0 HcmV?d00001 diff --git a/draft/application/cms/themes/default/res/style.css b/draft/application/cms/themes/default/res/style.css new file mode 100644 index 00000000..645cec4e --- /dev/null +++ b/draft/application/cms/themes/default/res/style.css @@ -0,0 +1,182 @@ +body { margin: 0; background-color: #eeeeff;} +div#header { background-color: #003; color: #fff; border: solid 1px #003; padding: 0px; margin: 0px;} +div#header img#logo { float: left; margin: 5px 15px 5px 10px; } +div#header div#title {font-size: 180%; font-weight: bold; margin-top: 10px; } +ul.horizontal { + list-style-type: none; +} +ul.horizontal li { + display: inline; + padding: 0 5px 0 5px; +} + +div#menu-bar li.active { + border: solid 1px #ff0; + color: #ff0; +} +div#menu-bar li:hover { + background-color: #fff; + color: #00f; +} +div#menu-bar li a { + text-decoration: none; + color: #fff; +} +div#menu-bar li:hover a { + color: #00f; + font-style: bold; +} + + +div#primary-tabs li { + color: #00f; + padding: 2px 5px 2px 5px; + background-color: #eee; + border: solid 1px #ccf; +} +div#primary-tabs li.active { + padding: 2px 7px 1px 7px; + border-top: solid 2px #99f; + border-left: solid 1px #99f; + border-right: solid 1px #99f; + border-bottom: 0; + background-color: #fff; + color: #00f; +} +div#primary-tabs li:hover { + background-color: #fff; + color: #00f; +} +div#primary-tabs li a { + text-decoration: none; + color: #00f; +} +div#primary-tabs li:hover a { + color: #00f; + font-style: bold; +} + + + +div#menu-first { margin-left: 20%; color: #ccf; background-color: #003; } +div#menu-first a { color: #ccf; } +div#menu-second { color: #99f; background-color: #333; } +div#menu-second a { color: #99f; } + +div#main-wrapper { + clear: both; + display: block; + height: 0; +} +div#main { margin: 0; padding: 0; clear: both; height:0; display: block; } + +div#first_sidebar { + width: 20%; + margin: 5px; + padding: 5px; + display: inline; + float: left; + position: relative; +} +div#second_sidebar { + width: 20%; + margin: 5px; + padding: 5px; + display: inline; + float: left; + position: relative; +} +div.sidebar div.block { + margin-bottom: 5px; + padding: 0; + border: dotted 1px #999; + background-color: #fff; +} +div.sidebar div.block div.title { + padding: 3px 3px 3px 3px; + font-weight: bold; + background-color: #dedede; + border-bottom: dotted 1px #999; +} +div.sidebar div.block div.inside { + margin: 3px; +} + +div#content { padding: 5px 3px 5px 20px; + margin-top: 10px; + width: 50%; + display: inline; + float: left; + position: relative; + background-color: #ffffff; + padding-bottom: 30px; +} +div#footer { margin: 10px 0 10px 0; clear: both; display: block; text-align: center; padding: 10px; border-top: solid 1px #00f; color: #fff; background-color: #333;} +div#footer a { color: #ff0; } + +form div.error { + border-top: dotted 1px #f00; + border-bottom: dotted 1px #f00; + border-left: solid 3px #f00; +} +div.node div.title { + font-weight: bold; + font-size: 110%; + border-bottom: dotted 1 px #009; +} +div.description { + font-style: italic; + font-color: #999; +} + +div.node-wrapper { + margin: 5px 2px 5px 2px; + border: dotted 1px #dddddd; + padding: 5px 3px 5px 3px; +} +div.node div.title { + font-weight: bold; + font-size: 110%; + border-bottom: dotted 1 px #009; + float: left; +} +div.node div.description { + text-align: right; +} +div.node div.inner { + padding: 5px 5px 5px 10px; + border-top: dotted 1px #dddddd; +} + +form#login-form { + border: dotted 1px #099; + display: inline-block; + padding: 10px; + margin: 10px; +} + +div#message { + border: solid 1px #fc0; + background-color: #fed; + color: #000; + padding: 5px; + margin: 5px; +} + +div#message li { + padding-left: 5px; + margin-left: 3px; +} +div#message li.success { + color: #003300; + background-color: #ccffcc; +} + +div#message li.error { + color: #330000; + background-color: #ff9494; +} +div#message li.warning { + color: #aa2200; + background-color: #ffcc99; +}