diff --git a/draft/application/cms/cms-safe.ecf b/draft/application/cms/cms-safe.ecf index 03be6e2f..28c0c7c0 100644 --- a/draft/application/cms/cms-safe.ecf +++ b/draft/application/cms/cms-safe.ecf @@ -13,13 +13,12 @@ - - + - + diff --git a/draft/application/cms/cms.ecf b/draft/application/cms/cms.ecf index 43bdba7d..486313e8 100644 --- a/draft/application/cms/cms.ecf +++ b/draft/application/cms/cms.ecf @@ -14,14 +14,13 @@ - - + - + diff --git a/draft/application/cms/example/src/module/demo/demo_module.e b/draft/application/cms/example/src/module/demo/demo_module.e index 5edae43e..4576957a 100644 --- a/draft/application/cms/example/src/module/demo/demo_module.e +++ b/draft/application/cms/example/src/module/demo/demo_module.e @@ -9,6 +9,9 @@ class inherit CMS_MODULE + redefine + links + end CMS_HOOK_MENU_ALTER @@ -55,7 +58,7 @@ feature -- Hooks local lnk: CMS_MODULE_LINK do - create Result.make (0) + Result := Precursor create lnk.make ("Date/time demo") -- lnk.set_callback (agent process_date_time_demo, <<"arg">>) -- Result["/demo/date/{arg}"] := lnk diff --git a/draft/application/cms/example/src/module/demo/demo_widget_cms_execution.e b/draft/application/cms/example/src/module/demo/demo_widget_cms_execution.e index d808bfe2..f68d136c 100644 --- a/draft/application/cms/example/src/module/demo/demo_widget_cms_execution.e +++ b/draft/application/cms/example/src/module/demo/demo_widget_cms_execution.e @@ -35,9 +35,9 @@ feature -- Execution set_main_content (s) end - new_table: CMS_WIDGET_TABLE [READABLE_STRING_8] + new_table: CMS_WIDGET_AGENT_TABLE [READABLE_STRING_8] local - l_table: CMS_WIDGET_TABLE [READABLE_STRING_8] + l_table: CMS_WIDGET_AGENT_TABLE [READABLE_STRING_8] do create l_table.make l_table.add_css_style ("width: 85%%; border: solid 1px #999; padding: 2px;") diff --git a/draft/application/cms/example/src/module/shutdown/shutdown_module.e b/draft/application/cms/example/src/module/shutdown/shutdown_module.e index 2a540066..3c250f7b 100644 --- a/draft/application/cms/example/src/module/shutdown/shutdown_module.e +++ b/draft/application/cms/example/src/module/shutdown/shutdown_module.e @@ -9,6 +9,9 @@ class inherit CMS_MODULE + redefine + permissions + end CMS_HOOK_MENU_ALTER @@ -39,25 +42,19 @@ feature {CMS_SERVICE} -- Registration feature -- Hooks + permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION] + do + Result := Precursor (a_service) + Result.extend ("shutdown") + end + 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">>) + lnk.set_permission_arguments (<<"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) diff --git a/draft/application/cms/example/src/web_cms.e b/draft/application/cms/example/src/web_cms.e index c8a5f5e4..0ccfd7da 100644 --- a/draft/application/cms/example/src/web_cms.e +++ b/draft/application/cms/example/src/web_cms.e @@ -101,6 +101,10 @@ feature -- Access create {DEBUG_MODULE} m.make m.enable a_setup.add_module (m) + + create {OPENID_MODULE} m.make + m.enable + a_setup.add_module (m) end setup_storage (a_setup: CMS_SETUP) diff --git a/draft/application/cms/src/cms_configuration.e b/draft/application/cms/src/cms_configuration.e index 2f7f8f53..c229c5f1 100644 --- a/draft/application/cms/src/cms_configuration.e +++ b/draft/application/cms/src/cms_configuration.e @@ -25,20 +25,9 @@ feature {NONE} -- Initialization make configuration_location := a_filename import (a_filename) - resolve analyze end - resolve - -- Resolve options related to variable ${..} - do - across - options as c - loop - options.replace (resolved_string (c.item), c.key) - end - end - analyze do get_root_location @@ -239,15 +228,24 @@ feature {NONE} -- Implementation loop l := f.last_string l.left_adjust - if not l.is_empty and then l[1] /= '#' then - p := l.index_of ('=', 1) - if p > 1 then - v := l.substring (p + 1, l.count) - l.keep_head (p - 1) - v.left_adjust - v.right_adjust - l.right_adjust - set_option (l.as_lower, v) + if not l.is_empty then + if l[1] = '#' then + -- commented line + else + p := l.index_of ('=', 1) + if p > 1 then + v := l.substring (p + 1, l.count) + l.keep_head (p - 1) + v.left_adjust + v.right_adjust + l.right_adjust + + if l.is_case_insensitive_equal ("@include") then + import (resolved_string (v)) + else + set_option (l.as_lower, resolved_string (v)) + end + end end end f.read_line diff --git a/draft/application/cms/src/cms_execution.e b/draft/application/cms/src/cms_execution.e index 3211dd83..8cbcdd42 100644 --- a/draft/application/cms/src/cms_execution.e +++ b/draft/application/cms/src/cms_execution.e @@ -637,6 +637,8 @@ feature {NONE} -- Implementation set_session_item ("last_access", (create {DATE_TIME}.make_now_utc)) end +feature -- Access: Session + session_item (k: READABLE_STRING_GENERAL): detachable ANY do Result := controller.session.item (k) diff --git a/draft/application/cms/src/cms_service.e b/draft/application/cms/src/cms_service.e index 5178eaa6..00003f80 100644 --- a/draft/application/cms/src/cms_service.e +++ b/draft/application/cms/src/cms_service.e @@ -81,10 +81,18 @@ feature {NONE} -- Initialization has_no_user: not storage.has_user local u: CMS_USER + ur: CMS_USER_ROLE do create u.make_new ("admin") u.set_password ("istrator") storage.save_user (u) + + create ur.make_with_id (1, "anonymous") + storage.save_user_role (ur) + create ur.make_with_id (2, "authenticated") + ur.add_permission ("create page") + ur.add_permission ("edit page") + storage.save_user_role (ur) end initialize_mailer @@ -159,7 +167,9 @@ feature -- Hook: menu_alter create lst.make (1) menu_alter_hooks := lst end - lst.force (h) + if not lst.has (h) then + lst.force (h) + end end menu_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_MENU_ALTER] @@ -186,18 +196,20 @@ feature -- Hook: form_alter create lst.make (1) form_alter_hooks := lst end - lst.force (h) + if not lst.has (h) then + lst.force (h) + end end form_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_FORM_ALTER] - call_form_alter_hooks (f: CMS_FORM; a_execution: CMS_EXECUTION) + call_form_alter_hooks (f: CMS_FORM; a_form_data: detachable CMS_FORM_DATA; 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) + c.item.form_alter (f, a_form_data, a_execution) end end end @@ -213,7 +225,9 @@ feature -- Hook: block create lst.make (1) block_hooks := lst end - lst.force (h) + if not lst.has (h) then + lst.force (h) + end end block_hooks: detachable ARRAYED_LIST [CMS_HOOK_BLOCK] diff --git a/draft/application/cms/src/hooks/cms_hook_auto_register.e b/draft/application/cms/src/hooks/cms_hook_auto_register.e index 0bb95c75..8bade763 100644 --- a/draft/application/cms/src/hooks/cms_hook_auto_register.e +++ b/draft/application/cms/src/hooks/cms_hook_auto_register.e @@ -3,7 +3,7 @@ note Summary description for {CMS_HOOK_AUTO_REGISTER}. When inheriting from this class, the declared hooks are automatically registered, otherwise, each descendant has to add it to the cms service - itself. + itself. ]" date: "$Date$" revision: "$Revision$" @@ -24,6 +24,10 @@ feature -- Hook if attached {CMS_HOOK_BLOCK} Current as h_block then a_service.add_block_hook (h_block) end + if attached {CMS_HOOK_FORM_ALTER} Current as h_block then + a_service.add_form_alter_hook (h_block) + end + end end diff --git a/draft/application/cms/src/hooks/cms_hook_form_alter.e b/draft/application/cms/src/hooks/cms_hook_form_alter.e index 141430f5..83499bd1 100644 --- a/draft/application/cms/src/hooks/cms_hook_form_alter.e +++ b/draft/application/cms/src/hooks/cms_hook_form_alter.e @@ -12,7 +12,7 @@ inherit feature -- Hook - form_alter (a_form: CMS_FORM; a_execution: CMS_EXECUTION) + form_alter (a_form: CMS_FORM; a_form_data: detachable CMS_FORM_DATA; a_execution: CMS_EXECUTION) deferred end diff --git a/draft/application/cms/src/kernel/api/cms_api_options.e b/draft/application/cms/src/kernel/api/cms_api_options.e index fb698024..0195f193 100644 --- a/draft/application/cms/src/kernel/api/cms_api_options.e +++ b/draft/application/cms/src/kernel/api/cms_api_options.e @@ -16,7 +16,8 @@ create convert make_from_manifest ({ ARRAY [TUPLE [key: STRING; value: detachable ANY]], - ARRAY [TUPLE [STRING_8, ARRAY [TUPLE [STRING_8, READABLE_STRING_32]]]] + ARRAY [TUPLE [STRING_8, ARRAY [TUPLE [STRING_8, STRING_32]]]], + ARRAY [TUPLE [STRING_8, ARRAY [TUPLE [STRING_8, STRING_8]]]] }) feature {NONE} -- Initialization diff --git a/draft/application/cms/src/kernel/cms_user.e b/draft/application/cms/src/kernel/cms_user.e index 135d3f04..1521bbd4 100644 --- a/draft/application/cms/src/kernel/cms_user.e +++ b/draft/application/cms/src/kernel/cms_user.e @@ -63,6 +63,41 @@ feature -- Access end end +feature -- Permission + + roles: detachable LIST [INTEGER] + -- Associated roles + -- Note: does not include "authenticated" and "anonymous". + + has_role (r: CMS_USER_ROLE): BOOLEAN + do + Result := attached roles as lst and then lst.has (r.id) + end + + clear_roles + do + roles := Void + end + + add_role_by_id (r_id: INTEGER) + local + lst: like roles + do + lst := roles + if r_id <= 2 then -- Anonymous=1 and Authenticated=2 + lst := roles + if lst /= Void and then lst.is_empty then + clear_roles + end + else + if lst = Void then + create {ARRAYED_SET [INTEGER]} lst.make (1) + roles := lst + end + lst.force (r_id) + end + end + feature -- Status report has_id: BOOLEAN diff --git a/draft/application/cms/src/kernel/cms_user_role.e b/draft/application/cms/src/kernel/cms_user_role.e new file mode 100644 index 00000000..75587c72 --- /dev/null +++ b/draft/application/cms/src/kernel/cms_user_role.e @@ -0,0 +1,85 @@ +note + description: "Summary description for {CMS_USER_ROLE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_USER_ROLE + +inherit + ANY + redefine + is_equal + end + +create + make, + make_with_id + +feature {NONE} -- Initialization + + make_with_id (a_id: like id; a_name: like name) + do + id := a_id + make (a_name) + end + + make (a_name: like name) + do + name := a_name + create {ARRAYED_LIST [READABLE_STRING_8]} permissions.make (0) + end + +feature -- Status report + + has_id: BOOLEAN + do + Result := id > 0 + end + + has_permission (p: READABLE_STRING_8): BOOLEAN + do + Result := across permissions as c some c.item.is_case_insensitive_equal (p) end + end + +feature -- Access + + id: INTEGER + + name: READABLE_STRING_8 + + permissions: LIST [READABLE_STRING_8] + +feature -- Comparison + + same_user_role (r: CMS_USER_ROLE): BOOLEAN + do + Result := r.id = id + end + + is_equal (other: like Current): BOOLEAN + -- Is `other' attached to an object considered + -- equal to current object? + do + Result := id = other.id + end + +feature -- Change + + set_id (a_id: like id) + do + id := a_id + end + + set_name (a_name: like name) + do + name := a_name + end + + add_permission (n: READABLE_STRING_8) + do + permissions.force (n) + end + +end diff --git a/draft/application/cms/src/kernel/content/format/filters/cms_html_filter.e b/draft/application/cms/src/kernel/content/format/filters/cms_html_filter.e index 6c8b2b9f..bc35b4eb 100644 --- a/draft/application/cms/src/kernel/content/format/filters/cms_html_filter.e +++ b/draft/application/cms/src/kernel/content/format/filters/cms_html_filter.e @@ -45,6 +45,7 @@ feature -- Conversion i: INTEGER n: INTEGER in_tag: BOOLEAN + t: READABLE_STRING_8 p1, p2: INTEGER do create l_new.make (a_text.count) @@ -75,7 +76,9 @@ feature -- Conversion else i := a_text.index_of ('<', p2 + 1) end - if i > 0 then + if i = 0 then + p1 := p2 + 1 + else l_new.append (a_text.substring (p2 + 1, i - 1)) end end diff --git a/draft/application/cms/src/kernel/form/cms_form.e b/draft/application/cms/src/kernel/form/cms_form.e index 988c522d..2e5e5195 100644 --- a/draft/application/cms/src/kernel/form/cms_form.e +++ b/draft/application/cms/src/kernel/form/cms_form.e @@ -8,7 +8,7 @@ class CMS_FORM inherit - ITERABLE [CMS_FORM_ITEM] + CMS_FORM_COMPOSITE create make @@ -19,10 +19,11 @@ feature {NONE} -- Initialization do action := a_action id := a_id - + initialize_with_count (10) create html_classes.make (2) - create items.make (10) set_method_post + create validation_actions + create submit_actions end feature -- Access @@ -33,11 +34,6 @@ feature -- Access id: READABLE_STRING_8 -- Id of the form - count: INTEGER - do - Result := items.count - end - is_get_method: BOOLEAN do Result := method.same_string ("GET") @@ -52,14 +48,42 @@ feature -- Access -- Form's method --| GET or POST +feature -- Basic operation + + prepare (a_execution: CMS_EXECUTION) + do + a_execution.service.call_form_alter_hooks (Current, Void, a_execution) + end + + process (a_execution: CMS_EXECUTION) + local + fd: CMS_FORM_DATA + do + create fd.make (a_execution.request, Current) + last_data := fd + a_execution.service.call_form_alter_hooks (Current, fd, a_execution) + fd.validate + fd.apply_to_associated_form -- Maybe only when has error? + if fd.is_valid then + fd.submit + if fd.has_error then + a_execution.report_form_errors (fd) + end + else + a_execution.report_form_errors (fd) + end + end + + last_data: detachable CMS_FORM_DATA + feature -- Validation - validation_action: detachable PROCEDURE [ANY, TUPLE [CMS_FORM_DATA]] + validation_actions: ACTION_SEQUENCE [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 + submit_actions: ACTION_SEQUENCE [TUPLE [CMS_FORM_DATA]] + -- Submit actions feature -- Element change @@ -73,141 +97,10 @@ feature -- Element change method := "POST" end - 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 := container_has_field (Current, a_name) - end - - fields_by_name (a_name: READABLE_STRING_GENERAL): detachable LIST [CMS_FORM_FIELD] - do - Result := fields_by_name_from (Current, a_name) - end - - items_by_css_id (a_id: READABLE_STRING_GENERAL): detachable LIST [CMS_FORM_ITEM] - do - Result := items_by_css_id_from (Current, a_id) - end - - first_item_by_css_id (a_id: READABLE_STRING_GENERAL): detachable CMS_FORM_ITEM - do - if attached items_by_css_id_from (Current, a_id) as lst then - if not lst.is_empty then - Result := lst.first - end - end - end - -feature {NONE} -- Implementation: Items - - container_has_field (a_container: ITERABLE [CMS_FORM_ITEM]; a_name: READABLE_STRING_GENERAL): BOOLEAN - do - across - a_container as i - until - Result - loop - if attached {CMS_FORM_FIELD} i.item as l_field and then l_field.name.same_string_general (a_name) then - Result := True - elseif attached {ITERABLE [CMS_FORM_ITEM]} i.item as l_cont then - Result := container_has_field (l_cont, a_name) - end - end - end - - fields_by_name_from (a_container: ITERABLE [CMS_FORM_ITEM]; a_name: READABLE_STRING_GENERAL): detachable ARRAYED_LIST [CMS_FORM_FIELD] - local - res: detachable ARRAYED_LIST [CMS_FORM_FIELD] - do - across - a_container as i - loop - if attached {CMS_FORM_FIELD} i.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) - elseif attached {ITERABLE [CMS_FORM_ITEM]} i.item as l_cont then - if attached fields_by_name_from (l_cont, a_name) as lst then - if res = Void then - res := lst - else - res.append (lst) - end - end - end - end - Result := res - end - - items_by_css_id_from (a_container: ITERABLE [CMS_FORM_ITEM]; a_id: READABLE_STRING_GENERAL): detachable ARRAYED_LIST [CMS_FORM_ITEM] - local - res: detachable ARRAYED_LIST [CMS_FORM_ITEM] - do - across - a_container as i - loop - if - attached {WITH_CSS_ID} i.item as l_with_css_id and then - attached l_with_css_id.css_id as l_css_id and then - l_css_id.same_string_general (a_id) - then - if res = Void then - create res.make (1) - end - res.force (i.item) - elseif attached {ITERABLE [CMS_FORM_ITEM]} i.item as l_cont then - if attached items_by_css_id_from (l_cont, a_id) as lst then - if res = Void then - res := lst - else - res.append (lst) - end - end - end - end - Result := res - end - -feature -- Change - - 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 append_to_html (a_theme: CMS_THEME; a_html: STRING_8) @@ -242,11 +135,4 @@ feature -- Conversion append_to_html (a_theme, Result) end -feature {NONE} -- Implementation - - items: ARRAYED_LIST [CMS_FORM_ITEM] - -- name => item - -invariant - end diff --git a/draft/application/cms/src/kernel/form/cms_form_checkbox_input.e b/draft/application/cms/src/kernel/form/cms_form_checkbox_input.e index 83ba26ea..d0860bf1 100644 --- a/draft/application/cms/src/kernel/form/cms_form_checkbox_input.e +++ b/draft/application/cms/src/kernel/form/cms_form_checkbox_input.e @@ -8,103 +8,16 @@ class CMS_FORM_CHECKBOX_INPUT inherit - CMS_FORM_INPUT - rename - default_value as value - redefine - set_value, - specific_input_attributes_string, - append_child_to_html - end - - CMS_FORM_SELECTABLE_ITEM - rename - is_selected as checked, - set_is_selected as set_checked - end + CMS_FORM_SELECTABLE_INPUT create make, - make_with_text + make_with_value feature -- Access - checked: BOOLEAN - -- Current element should be preselected when the page loads - input_type: STRING = "checkbox" - text: detachable READABLE_STRING_32 - - raw_text: detachable READABLE_STRING_8 - -feature -- Status report - - is_same_value (v: READABLE_STRING_32): BOOLEAN - do - Result := attached value as l_value and then v.same_string (l_value) - end - -feature -- Change - - set_text (t: detachable READABLE_STRING_32) - do - text := t - end - - set_raw_text (t: detachable READABLE_STRING_8) - do - raw_text := t - end - - set_checked (b: like checked) - do - checked := b - end - - set_value (v: detachable WSF_VALUE) - -- Set value `v' if applicable to Current - do - if attached {ITERABLE [WSF_VALUE]} v as lst then - across - lst as c - loop - if - attached {WSF_STRING} c.item as s and then - is_same_value (s.value) - then - set_checked (True) - end - end - else - Precursor (v) - end - end - -feature {NONE} -- Implementation - - append_child_to_html (a_theme: CMS_THEME; a_html: STRING_8) - -- Specific child element if any. - --| To redefine if needed - do - if attached raw_text as t then - a_html.append (t) - elseif attached text as t then - a_html.append (a_theme.html_encoded (t)) - elseif attached value as v then - a_html.append (a_theme.html_encoded (v)) - end - end - - 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/kernel/form/cms_form_composite.e b/draft/application/cms/src/kernel/form/cms_form_composite.e new file mode 100644 index 00000000..55971d07 --- /dev/null +++ b/draft/application/cms/src/kernel/form/cms_form_composite.e @@ -0,0 +1,89 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +deferred class + CMS_FORM_COMPOSITE + +inherit + CMS_WIDGET_COMPOSITE + redefine + extend + end + +feature -- Status + + has_field (a_name: READABLE_STRING_GENERAL): BOOLEAN + do + Result := container_has_field (Current, a_name) + end + +feature -- Access + + fields_by_name (a_name: READABLE_STRING_GENERAL): detachable LIST [CMS_FORM_FIELD] + do + Result := fields_by_name_from (Current, a_name) + end + +feature -- Change + + extend (i: CMS_WIDGET) + 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 + Precursor (i) + end + +feature {NONE} -- Implementation: Items + + container_has_field (a_container: ITERABLE [CMS_WIDGET]; a_name: READABLE_STRING_GENERAL): BOOLEAN + do + across + a_container as i + until + Result + loop + if attached {CMS_FORM_FIELD} i.item as l_field and then l_field.name.same_string_general (a_name) then + Result := True + elseif attached {ITERABLE [CMS_WIDGET]} i.item as l_cont then + Result := container_has_field (l_cont, a_name) + end + end + end + + fields_by_name_from (a_container: ITERABLE [CMS_WIDGET]; a_name: READABLE_STRING_GENERAL): detachable ARRAYED_LIST [CMS_FORM_FIELD] + local + res: detachable ARRAYED_LIST [CMS_FORM_FIELD] + do + across + a_container as i + loop + if attached {CMS_FORM_FIELD} i.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) + elseif attached {ITERABLE [CMS_WIDGET]} i.item as l_cont then + if attached fields_by_name_from (l_cont, a_name) as lst then + if res = Void then + res := lst + else + res.append (lst) + end + end + end + end + Result := res + end + + +end diff --git a/draft/application/cms/src/kernel/form/cms_form_data.e b/draft/application/cms/src/kernel/form/cms_form_data.e index 79896b8e..e02a368a 100644 --- a/draft/application/cms/src/kernel/form/cms_form_data.e +++ b/draft/application/cms/src/kernel/form/cms_form_data.e @@ -10,7 +10,7 @@ class inherit TABLE_ITERABLE [detachable WSF_VALUE, READABLE_STRING_8] -create +create {CMS_FORM} make feature {NONE} -- Initialization @@ -21,7 +21,6 @@ feature {NONE} -- Initialization form := a_form create items.make (a_form.count) get_items (req) - validate end feature -- Access @@ -37,6 +36,14 @@ feature -- Status feature -- Access + item_same_string (a_name: READABLE_STRING_GENERAL; s: READABLE_STRING_GENERAL): BOOLEAN + -- Is there any item named `a_name' with a value `v'? + do + if attached item (a_name) as l_value then + Result := l_value.same_string (s) + end + end + item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE do Result := items.item (a_name.as_string_8) @@ -49,11 +56,49 @@ feature -- Access end end --- table_item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE --- do --- FIXME --- Result := items.item (a_name.as_string_8 + "[]") --- end + table_item (a_name: READABLE_STRING_GENERAL): detachable WSF_TABLE + local + s,k: READABLE_STRING_GENERAL + p,q: INTEGER + do + if attached {WSF_TABLE} item (a_name) as tb then + Result := tb + else + s := a_name + "[" + create Result.make (a_name.to_string_8) -- FIXME + across + items as c + loop + if attached c.item as v then + k := c.key + if k.starts_with (s) then + if attached {WSF_TABLE} v as tb then + across + tb as t + loop + Result.add_value (t.item, t.item.name) + end + else + p := k.index_of_code (91, 1) -- 91 '[' + if p > 0 then + q := k.index_of_code (93, p + 1) -- 93 ']' + if q > p then + if q = p + 1 then + -- [] + Result.add_value (v, (Result.count+1).out) + else + Result.add_value (v, k.substring (p + 1, q - 1)) + end + end + end + end + else + -- skip + end + end + end + end + end integer_item (a_name: READABLE_STRING_GENERAL): INTEGER do @@ -70,17 +115,33 @@ feature -- Access feature -- Basic operation + submit + require + is_valid: is_valid + do + form.submit_actions.call ([Current]) + end + validate do across form as f loop - if attached {CMS_FORM_FIELD} f.item as l_field then - l_field.validate (Current) - end + validate_item (f.item) end - if attached form.validation_action as act then - act.call ([Current]) + form.validation_actions.call ([Current]) + end + + validate_item (w: CMS_WIDGET) + do + if attached {CMS_FORM_FIELD} w as l_field then + l_field.validate (Current) + elseif attached {ITERABLE [CMS_WIDGET]} w as lst then + across + lst as c + loop + validate_item (c.item) + end end end @@ -121,7 +182,7 @@ feature -- Basic operation feature {NONE} -- Implementation: apply - apply_to_associated_form_item (a_name: READABLE_STRING_8; a_value: detachable WSF_VALUE; i: CMS_FORM_ITEM) + apply_to_associated_form_item (a_name: READABLE_STRING_8; a_value: detachable WSF_VALUE; i: CMS_WIDGET) local do if attached {CMS_FORM_FIELD} i as l_field then @@ -130,7 +191,7 @@ feature {NONE} -- Implementation: apply l_field.set_value (a_value) end end - elseif attached {ITERABLE [CMS_FORM_ITEM]} i as l_set then + elseif attached {ITERABLE [CMS_WIDGET]} i as l_set then across l_set as c loop @@ -170,14 +231,14 @@ feature {NONE} -- Implementation get_form_items (req, form) end - get_form_items (req: WSF_REQUEST; lst: ITERABLE [CMS_FORM_ITEM]) + get_form_items (req: WSF_REQUEST; lst: ITERABLE [CMS_WIDGET]) do across lst as c loop if attached {CMS_FORM_FIELD} c.item as l_field then get_form_field_item (req, l_field, l_field.name) - elseif attached {ITERABLE [CMS_FORM_ITEM]} c.item as l_set then + elseif attached {ITERABLE [CMS_WIDGET]} c.item as l_set then get_form_items (req, l_set) end end @@ -186,49 +247,24 @@ feature {NONE} -- Implementation get_form_field_item (req: WSF_REQUEST; i: CMS_FORM_FIELD; n: READABLE_STRING_8) local v: detachable WSF_VALUE --- tb: detachable WSF_TABLE do if form.is_post_method then - v := req.form_parameter (n) + v := req.table_item (n, agent req.form_parameter) else - v := req.query_parameter (n) + v := req.table_item (n, agent req.query_parameter) end - if v = Void and then n.ends_with_general ("[]") then - if form.is_post_method then - v := req.form_parameter (n.substring (1, n.count - 2)) - else - v := req.query_parameter (n.substring (1, n.count - 2)) + if v = Void then + if n.ends_with_general ("[]") then + if form.is_post_method then + v := req.form_parameter (n.substring (1, n.count - 2)) + else + v := req.query_parameter (n.substring (1, n.count - 2)) + end end end if i.is_required and (v = Void or else v.is_empty) then add_error (i, "Field %"" + n + "%" is required") else --- if attached {WSF_TABLE} v then --- -- `v' overwrite any previous values if any --- -- since it is already a WSF_TABLE --- else --- attached items.item (n) as ov then --- if attached {WSF_TABLE} ov as vtb then --- tb := vtb --- elseif attached {WSF_MULTIPLE_STRING} ov as vm then --- if tb = Void then --- create tb.make (n) --- end --- across --- vm as c --- loop --- tb.add_value (c.item, (tb.count + 1).out) --- end --- else --- create tb.make (n) ----- create v_multi.make_with_value (ov) --- end --- if v /= Void then --- tb.add_value (v, (tb.count + 1).out) ----- v_multi.add_value (v) --- end --- v := tb --- end items.force (v, n) end end @@ -247,8 +283,45 @@ feature {NONE} -- Implementation items: HASH_TABLE [detachable WSF_VALUE, READABLE_STRING_8] +feature -- Cached values + + cached_value (k: READABLE_STRING_8): detachable ANY + do + if attached cached_values as tb then + Result := tb.item (k) + end + end + + add_cached_value (k: READABLE_STRING_8; v: detachable ANY) + local + tb: like cached_values + do + tb := cached_values + if tb = Void then + create tb.make (1) + cached_values := tb + end + tb.force (v, k) + end + + remove_cached_value (k: READABLE_STRING_8; v: detachable ANY) + do + if attached cached_values as tb then + tb.remove (k) + end + end + +feature {NONE} -- Implementation: cached values + + cached_values: detachable HASH_TABLE [detachable ANY, READABLE_STRING_8] + feature -- Reports + has_error: BOOLEAN + do + Result := attached errors as err and then not err.is_empty + end + errors: detachable ARRAYED_LIST [TUPLE [field: detachable CMS_FORM_FIELD; message: detachable READABLE_STRING_8]] invariant diff --git a/draft/application/cms/src/kernel/form/cms_form_div.e b/draft/application/cms/src/kernel/form/cms_form_div.e index 65dec274..7b2c6dd6 100644 --- a/draft/application/cms/src/kernel/form/cms_form_div.e +++ b/draft/application/cms/src/kernel/form/cms_form_div.e @@ -10,7 +10,7 @@ class inherit CMS_FORM_ITEM - ITERABLE [CMS_FORM_ITEM] + CMS_FORM_COMPOSITE WITH_CSS_ID @@ -18,14 +18,16 @@ create make, make_with_item, make_with_items, - make_with_text + make_with_text, + make_with_text_and_css_id, + make_with_item_and_css_id feature {NONE} -- Initialization make -- Initialize `Current'. do - create items.make (0) + initialize_with_count (0) end make_with_text (s: READABLE_STRING_8) @@ -33,15 +35,15 @@ feature {NONE} -- Initialization make_with_item (create {CMS_FORM_RAW_TEXT}.make (s)) end - make_with_item (i: CMS_FORM_ITEM) + make_with_item (i: CMS_WIDGET) do - create items.make (1) + initialize_with_count (1) extend (i) end - make_with_items (it: ITERABLE [CMS_FORM_ITEM]) + make_with_items (it: ITERABLE [CMS_WIDGET]) do - create items.make (2) + initialize_with_count (2) across it as c loop @@ -49,19 +51,16 @@ feature {NONE} -- Initialization end end -feature -- Access - - new_cursor: ITERATION_CURSOR [CMS_FORM_ITEM] - -- Fresh cursor associated with current structure + make_with_item_and_css_id (i: CMS_WIDGET; a_css_id: READABLE_STRING_8) do - Result := items.new_cursor + make_with_item (i) + set_css_id (a_css_id) end -feature -- Change - - extend (i: CMS_FORM_ITEM) + make_with_text_and_css_id (s: READABLE_STRING_8; a_css_id: READABLE_STRING_8) do - items.force (i) + make_with_text (s) + set_css_id (a_css_id) end feature -- Conversion @@ -82,8 +81,4 @@ feature -- Conversion a_html.append ("%N%N") end -feature {NONE} -- Implementation - - items: ARRAYED_LIST [CMS_FORM_ITEM] - end diff --git a/draft/application/cms/src/kernel/form/cms_form_field_set.e b/draft/application/cms/src/kernel/form/cms_form_field_set.e index 2a9af0a5..893f39fa 100644 --- a/draft/application/cms/src/kernel/form/cms_form_field_set.e +++ b/draft/application/cms/src/kernel/form/cms_form_field_set.e @@ -10,7 +10,7 @@ class inherit CMS_FORM_ITEM - ITERABLE [CMS_FORM_ITEM] + CMS_FORM_COMPOSITE WITH_CSS_ID @@ -22,7 +22,7 @@ feature {NONE} -- Initialization make -- Initialize `Current'. do - create items.make (0) + initialize_with_count (0) end feature -- Access @@ -31,14 +31,6 @@ feature -- Access is_collapsible: BOOLEAN -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) @@ -46,21 +38,6 @@ feature -- Change legend := v end - extend (i: CMS_FORM_ITEM) - do - items.force (i) - end - - prepend (i: CMS_FORM_ITEM) - do - items.put_front (i) - end - - extend_text (t: READABLE_STRING_8) - do - items.force (create {CMS_FORM_RAW_TEXT}.make (t)) - end - set_collapsible (b: BOOLEAN) do is_collapsible := b @@ -101,8 +78,4 @@ feature -- Conversion a_html.append ("%N%N") end -feature {NONE} -- Implementation - - items: ARRAYED_LIST [CMS_FORM_ITEM] - end diff --git a/draft/application/cms/src/kernel/form/cms_form_item.e b/draft/application/cms/src/kernel/form/cms_form_item.e index 7b7f908f..344fef10 100644 --- a/draft/application/cms/src/kernel/form/cms_form_item.e +++ b/draft/application/cms/src/kernel/form/cms_form_item.e @@ -8,20 +8,10 @@ deferred class CMS_FORM_ITEM inherit + CMS_WIDGET + WITH_CSS_CLASS WITH_CSS_STYLE -feature -- Conversion - - append_to_html (a_theme: CMS_THEME; a_html: STRING_8) - deferred - end - - to_html (a_theme: CMS_THEME): STRING_8 - do - create Result.make_empty - append_to_html (a_theme, Result) - end - end diff --git a/draft/application/cms/src/kernel/form/cms_form_radio_input.e b/draft/application/cms/src/kernel/form/cms_form_radio_input.e index 3d928d82..78288dca 100644 --- a/draft/application/cms/src/kernel/form/cms_form_radio_input.e +++ b/draft/application/cms/src/kernel/form/cms_form_radio_input.e @@ -8,54 +8,16 @@ class CMS_FORM_RADIO_INPUT inherit - CMS_FORM_INPUT - rename - default_value as value - redefine - specific_input_attributes_string - end - - CMS_FORM_SELECTABLE_ITEM - rename - is_selected as checked, - set_is_selected as set_checked - end + CMS_FORM_SELECTABLE_INPUT create - make + make, + make_with_value feature -- Access - checked: BOOLEAN - -- Current element should be preselected when the page loads - input_type: STRING = "radio" -feature -- Status report - - is_same_value (v: READABLE_STRING_32): BOOLEAN - do - Result := attached value as l_value and then v.same_string (l_value) - end - -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/kernel/form/cms_form_raw_text.e b/draft/application/cms/src/kernel/form/cms_form_raw_text.e index 915dace7..90fa8fdc 100644 --- a/draft/application/cms/src/kernel/form/cms_form_raw_text.e +++ b/draft/application/cms/src/kernel/form/cms_form_raw_text.e @@ -8,7 +8,10 @@ class CMS_FORM_RAW_TEXT inherit - CMS_FORM_ITEM + CMS_WIDGET_TEXT + rename + set_text as set_value, + make_with_text as make redefine append_to_html end @@ -16,24 +19,6 @@ inherit 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 append_to_html (a_theme: CMS_THEME; a_html: STRING_8) diff --git a/draft/application/cms/src/kernel/form/cms_form_selectable_input.e b/draft/application/cms/src/kernel/form/cms_form_selectable_input.e new file mode 100644 index 00000000..07a711ca --- /dev/null +++ b/draft/application/cms/src/kernel/form/cms_form_selectable_input.e @@ -0,0 +1,112 @@ +note + description: "Summary description for {CMS_FORM_SELECTABLE_INPUT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_FORM_SELECTABLE_INPUT + +inherit + CMS_FORM_INPUT + rename + default_value as value, + make_with_text as make_with_value + redefine + set_value, + specific_input_attributes_string, + append_child_to_html + end + + CMS_FORM_SELECTABLE_ITEM + rename + is_selected as checked, + set_is_selected as set_checked + end + +feature -- Access + + checked: BOOLEAN + -- Current element should be preselected when the page loads + + title: detachable READABLE_STRING_32 + + raw_title: detachable READABLE_STRING_8 + +feature -- Status report + + is_same_value (v: READABLE_STRING_32): BOOLEAN + do + Result := attached value as l_value and then v.same_string (l_value) + end + +feature -- Change + + set_title (t: detachable READABLE_STRING_32) + do + title := t + end + + set_raw_title (t: detachable READABLE_STRING_8) + do + raw_title := t + end + + set_checked (b: like checked) + do + checked := b + end + + set_checked_by_value (v: detachable WSF_VALUE) + do + if attached {WSF_STRING} v as s then + if value /= Void then + set_checked (is_same_value (s.value)) + else + set_checked (s.value.same_string ("on") or s.value.same_string ("true") or s.value.same_string ("yes") or s.value.same_string ("enabled")) + end + else + set_checked (False) + end + end + + set_value (v: detachable WSF_VALUE) + -- Set value `v' if applicable to Current + do + if attached {ITERABLE [WSF_VALUE]} v as lst then + across + lst as c + loop + set_checked_by_value (c.item) + end + else + set_checked_by_value (v) + Precursor (v) + end + end + +feature {NONE} -- Implementation + + append_child_to_html (a_theme: CMS_THEME; a_html: STRING_8) + -- Specific child element if any. + --| To redefine if needed + do + if attached raw_title as t then + a_html.append (t) + elseif attached title as t then + a_html.append (a_theme.html_encoded (t)) + end + end + + 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/kernel/form/with_css_class.e b/draft/application/cms/src/kernel/form/with_css_class.e index 57921ff0..28b7fa9d 100644 --- a/draft/application/cms/src/kernel/form/with_css_class.e +++ b/draft/application/cms/src/kernel/form/with_css_class.e @@ -17,6 +17,17 @@ feature -- Change css_classes := Void end + add_css_classes (a_classes: detachable ITERABLE [READABLE_STRING_8]) + do + if a_classes /= Void then + across + a_classes as c + loop + add_css_class (c.item) + end + end + end + add_css_class (a_class: READABLE_STRING_8) require is_valid_css_class: is_valid_css_class (a_class) diff --git a/draft/application/cms/src/kernel/link/cms_local_link.e b/draft/application/cms/src/kernel/link/cms_local_link.e index 5bfd0500..e5652880 100644 --- a/draft/application/cms/src/kernel/link/cms_local_link.e +++ b/draft/application/cms/src/kernel/link/cms_local_link.e @@ -51,7 +51,7 @@ feature -- Status report Result := attached children as l_children and then not l_children.is_empty end - permission_arguments: detachable ITERABLE [STRING] + permission_arguments: detachable ITERABLE [READABLE_STRING_8] children: detachable LIST [CMS_LINK] @@ -106,14 +106,17 @@ feature -- Element change qs: STRING do create qs.make_from_string (req.path_info) - if attached req.query_string as l_query_string and then not l_query_string.is_empty then - qs.append_character ('?') - qs.append (l_query_string) - end is_active := qs.same_string (location) + if not is_active then + if attached req.query_string as l_query_string and then not l_query_string.is_empty then + qs.append_character ('?') + qs.append (l_query_string) + end + is_active := qs.same_string (location) + end end - set_permission_arguments (args: ITERABLE [STRING]) + set_permission_arguments (args: like permission_arguments) do permission_arguments := args end diff --git a/draft/application/cms/src/modules/admin/admin_cms_execution.e b/draft/application/cms/src/modules/admin/admin_cms_execution.e index 4b1e7e35..30816c59 100644 --- a/draft/application/cms/src/modules/admin/admin_cms_execution.e +++ b/draft/application/cms/src/modules/admin/admin_cms_execution.e @@ -29,6 +29,9 @@ feature -- Execution if has_permission ("administrate blocks") then b.append ("
  • " + link ("Blocks", "/admin/blocks/", Void) + "
  • ") end + if has_permission ("administrate user-roles") then + b.append ("
  • " + link ("User roles", "/admin/roles/", Void) + "
  • ") + end if has_permission ("administrate users") then b.append ("
  • " + link ("Users", "/admin/users/", Void) + "
  • ") end diff --git a/draft/application/cms/src/modules/admin/admin_module.e b/draft/application/cms/src/modules/admin/admin_module.e index 6dd4c9bb..4eed1758 100644 --- a/draft/application/cms/src/modules/admin/admin_module.e +++ b/draft/application/cms/src/modules/admin/admin_module.e @@ -9,6 +9,9 @@ class inherit CMS_MODULE + redefine + permissions + end CMS_HOOK_MENU_ALTER @@ -36,6 +39,7 @@ feature {CMS_SERVICE} -- Registration service := a_service a_service.map_uri ("/admin/", agent handle_admin (a_service, ?, ?)) a_service.map_uri ("/admin/users/", agent handle_admin_users (a_service, ?, ?)) + a_service.map_uri ("/admin/roles/", agent handle_admin_user_roles (a_service, ?, ?)) a_service.map_uri ("/admin/blocks/", agent handle_admin_blocks (a_service, ?, ?)) a_service.map_uri ("/admin/modules/", agent handle_admin_modules (a_service, ?, ?)) a_service.map_uri ("/admin/logs/", agent handle_admin_logs (a_service, ?, ?)) @@ -55,10 +59,16 @@ feature -- Hooks a_menu_system.management_menu.extend (lnk) end - links: HASH_TABLE [CMS_MODULE_LINK, STRING] - -- Link indexed by path + permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION] do - create Result.make (0) + Result := Precursor (a_service) + Result.extend ("administer") + Result.extend ("administer users") + Result.extend ("administer user roles") + Result.extend ("administer content") + Result.extend ("administer logs") + Result.extend ("administer blocks") + Result.extend ("administer modules") end feature -- Handler @@ -73,6 +83,11 @@ feature -- Handler (create {ADMIN_USERS_CMS_EXECUTION}.make (req, res, cms)).execute end + handle_admin_user_roles (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE) + do + (create {ADMIN_USER_ROLES_CMS_EXECUTION}.make (req, res, cms)).execute + end + handle_admin_blocks (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE) do (create {ADMIN_BLOCKS_CMS_EXECUTION}.make (req, res, cms)).execute diff --git a/draft/application/cms/src/modules/admin/admin_user_roles_cms_execution.e b/draft/application/cms/src/modules/admin/admin_user_roles_cms_execution.e new file mode 100644 index 00000000..84ea97c0 --- /dev/null +++ b/draft/application/cms/src/modules/admin/admin_user_roles_cms_execution.e @@ -0,0 +1,211 @@ +note + description: "Summary description for {ADMIN_USER_ROLES_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ADMIN_USER_ROLES_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + do + if request.is_post_request_method then + process_post + else + process_get + end + end + + process_get + -- Computed response message. + local + b: STRING_8 + f: CMS_FORM + l_roles: LIST [CMS_USER_ROLE] + do + set_title ("User roles") + -- check Permission !!! + create b.make_empty + if has_permission ("administrate user roles") then + l_roles := service.storage.user_roles + f := new_edit_form (url (request.path_info, Void), l_roles, True) + f.append_to_html (theme, b) + else + b.append ("
    Access denied
    ") + end + set_main_content (b) + end + + process_post + -- Computed response message. + local + b: STRING_8 + f: CMS_FORM + l_roles: LIST [CMS_USER_ROLE] + do + set_title ("User roles") + create b.make_empty + + debug ("cms") + across + request.form_parameters as c + loop + b.append ("
  • ") + b.append (html_encoded (c.item.name)) + b.append ("=") + b.append (html_encoded (c.item.string_representation)) + b.append ("
  • ") + end + end + + if has_permission ("administer user roles") then + l_roles := service.storage.user_roles + f := new_edit_form (url (request.path_info, Void), l_roles, False) + f.submit_actions.extend (agent edit_form_submit (?, l_roles)) + f.process (Current) + f.append_to_html (theme, b) + else + b.append ("
    Access denied
    ") + end + + set_main_content (b) + end + +feature -- Forms + + edit_form_submit (fd: CMS_FORM_DATA; a_roles: LIST [CMS_USER_ROLE]) + local + l_role: CMS_USER_ROLE + do + if fd.item_same_string ("op", "Apply") then + across + a_roles as r + loop + if attached fd.table_item (r.item.name) as perms then + r.item.permissions.wipe_out + across + perms as c + loop + if attached {WSF_STRING} c.item as s then + r.item.add_permission (s.value) + end + end + service.storage.save_user_role (r.item) + end + end + elseif fd.item_same_string ("op", "Add role") then + if attached fd.string_item ("new-role") as l_new_role then + create l_role.make (l_new_role) + service.storage.save_user_role (l_role) + set_redirection (url (request.path_info, Void)) + end + elseif fd.item_same_string ("op", "Add permission") then + if attached fd.string_item ("new-permission") as l_new_permission then + l_role := service.storage.authenticated_user_role + l_role.add_permission (l_new_permission) + service.storage.save_user_role (l_role) + set_redirection (url (request.path_info, Void)) + end + end + end + + new_edit_form (a_action: READABLE_STRING_8; a_roles: LIST [CMS_USER_ROLE]; a_use_data: BOOLEAN): CMS_FORM + local + perms: ARRAYED_SET [READABLE_STRING_8] + tb: CMS_WIDGET_AGENT_TABLE [READABLE_STRING_8] + i: INTEGER + tf: CMS_FORM_TEXT_INPUT + do + create perms.make (10) + perms.compare_objects + across + service.modules as m + loop + across + m.item.permissions (service) as p + loop + perms.extend (p.item.name) + end + end + across + a_roles as c + loop + across + c.item.permissions as p + loop + perms.extend (p.item) + end + end + + create tb.make + tb.set_column_count (1 + a_roles.count) + i := 1 + tb.column (i).set_title ("Permissions") + across + a_roles as r + loop + i := i + 1 + tb.column (i).set_title (r.item.name) + end + + tb.add_css_style ("border: solid 1px #999;") + tb.set_data (perms) + tb.set_compute_item_function (agent (p: READABLE_STRING_8; ia_roles: LIST [CMS_USER_ROLE]; ia_use_data: BOOLEAN): CMS_WIDGET_TABLE_ROW + local + it: CMS_WIDGET_TABLE_ITEM + cb: CMS_FORM_CHECKBOX_INPUT + do + create Result.make (1 + ia_roles.count) + create it.make_with_text (p) + Result.set_item (it, 1) + across + ia_roles as r + loop + create cb.make (r.item.name + "[" + p + "]") + cb.set_text_value (p) + + if ia_use_data then + if r.item.has_permission (p) then + cb.set_checked (True) + else + cb.set_checked (False) + end + end + create it.make_with_content (cb) + Result.add_item (it) + end + end(?, a_roles, a_use_data) + ) + + create Result.make (a_action, "edit-user-roles") + Result.set_method_post + Result.extend (tb.to_computed_table) + Result.extend (create {CMS_FORM_SUBMIT_INPUT}.make_with_text ("op", "Apply")) + + create tf.make ("new-role") + tf.add_css_class ("horizontal") + tf.set_size (24) + tf.set_label ("New user role") + Result.extend (tf) + Result.extend (create {CMS_FORM_SUBMIT_INPUT}.make_with_text ("op", "Add role")) + + create tf.make ("new-permission") + tf.add_css_class ("horizontal") + tf.set_size (24) + tf.set_label ("New permission") + Result.extend (tf) + Result.extend (create {CMS_FORM_SUBMIT_INPUT}.make_with_text ("op", "Add permission")) + + + + end + +end diff --git a/draft/application/cms/src/modules/cms_module.e b/draft/application/cms/src/modules/cms_module.e index 025e6c8a..e188c9bf 100644 --- a/draft/application/cms/src/modules/cms_module.e +++ b/draft/application/cms/src/modules/cms_module.e @@ -41,17 +41,18 @@ feature -- Hooks help_text (a_path: STRING): STRING do - Result := "" + create Result.make_empty end - permissions: LIST [TUPLE [title: detachable STRING; description: detachable STRING]] + permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION] do - create {ARRAYED_LIST [like permissions.item]} Result.make (0) + create {ARRAYED_SET [CMS_PERMISSION]} Result.make (0) end links: HASH_TABLE [CMS_MODULE_LINK, STRING] -- Link indexed by path - deferred + do + create Result.make (0) end end diff --git a/draft/application/cms/src/modules/cms_permission.e b/draft/application/cms/src/modules/cms_permission.e new file mode 100644 index 00000000..c0e23cff --- /dev/null +++ b/draft/application/cms/src/modules/cms_permission.e @@ -0,0 +1,36 @@ +note + description: "Summary description for {CMS_PERMISSION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_PERMISSION + +create + make + +convert + make ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}) + +feature {NONE} -- Initialization + + make (n: like name) + do + name := n + end + +feature -- Access + + name: READABLE_STRING_8 + + description: detachable READABLE_STRING_8 + +feature -- Change + + set_description (s: like description) + do + description := s + end + +end diff --git a/draft/application/cms/src/modules/debug/debug_module.e b/draft/application/cms/src/modules/debug/debug_module.e index c586e3bf..1c472116 100644 --- a/draft/application/cms/src/modules/debug/debug_module.e +++ b/draft/application/cms/src/modules/debug/debug_module.e @@ -36,19 +36,6 @@ feature {CMS_SERVICE} -- Registration a_service.map_uri_template ("/debug/", agent handle_debug (a_service, ?, ?)) end -feature -- Hooks - - links: HASH_TABLE [CMS_MODULE_LINK, STRING] - -- Link indexed by path - local --- lnk: CMS_MODULE_LINK - do - create Result.make (0) --- create lnk.make ("Date/time demo") --- lnk.set_callback (agent process_date_time_demo, <<"arg">>) --- Result["/demo/date/{arg}"] := lnk - end - feature -- Hooks -- block_list: ITERABLE [like {CMS_BLOCK}.name] diff --git a/draft/application/cms/src/modules/node/node_add_cms_execution.e b/draft/application/cms/src/modules/node/node_add_cms_execution.e index bfe43dba..e79252b9 100644 --- a/draft/application/cms/src/modules/node/node_add_cms_execution.e +++ b/draft/application/cms/src/modules/node/node_add_cms_execution.e @@ -6,7 +6,7 @@ class NODE_ADD_CMS_EXECUTION inherit - CMS_EXECUTION + NODE_CMS_EXECUTION create make @@ -19,71 +19,20 @@ feature -- Execution 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, url (request.path_info, Void), "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 - f.append_to_html (theme, b) + if request.is_post_request_method then + f.validation_actions.extend (agent edit_form_validate (?, b)) + f.submit_actions.extend (agent edit_form_submit (?, Void, l_type, b)) + f.process (Current) + fd := f.last_data end + f.append_to_html (theme, b) else set_title ("Access denied") end @@ -109,35 +58,4 @@ feature -- Execution 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_text ("
    ") - - 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/modules/node/node_cms_execution.e b/draft/application/cms/src/modules/node/node_cms_execution.e new file mode 100644 index 00000000..339b7fa4 --- /dev/null +++ b/draft/application/cms/src/modules/node/node_cms_execution.e @@ -0,0 +1,141 @@ +note + description: "Summary description for {NODE_CMS_EXECUTION}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + NODE_CMS_EXECUTION + +inherit + CMS_EXECUTION + +feature -- Form + + edit_form_validate (fd: CMS_FORM_DATA; b: STRING) + local + l_preview: BOOLEAN + l_format: detachable CMS_FORMAT + do + l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") + if 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 + end + + edit_form_submit (fd: CMS_FORM_DATA; a_node: detachable CMS_NODE; a_type: CMS_CONTENT_TYPE; b: STRING) + local + l_preview: BOOLEAN + l_node: detachable CMS_NODE + s: STRING + do + l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") + if not l_preview then + debug ("cms") + 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 + end + if a_node /= Void then + l_node := a_node + a_type.change_node (Current, fd, a_node) + s := "modified" + else + l_node := a_type.new_node (Current, fd, Void) + s := "created" + end + service.storage.save_node (l_node) + if attached user as u then + service.log ("node", "User %"" + user_link (u) + "%" " + s + " node " + link (a_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node)) + else + service.log ("node", "Anonymous " + s + " node " + a_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 + end + +-- edit_form_submit (fd: CMS_FORM_DATA; a_type: CMS_CONTENT_TYPE; b: STRING) +-- local +-- l_preview: BOOLEAN +-- do +-- l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") +-- if not l_preview then +-- debug ("cms") +-- 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 +-- end +-- if attached a_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 (a_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 "+ a_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 +-- end +-- 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_text ("
    ") + + 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/modules/node/node_edit_cms_execution.e b/draft/application/cms/src/modules/node/node_edit_cms_execution.e index 3153c177..0ab65038 100644 --- a/draft/application/cms/src/modules/node/node_edit_cms_execution.e +++ b/draft/application/cms/src/modules/node/node_edit_cms_execution.e @@ -6,7 +6,7 @@ class NODE_EDIT_CMS_EXECUTION inherit - CMS_EXECUTION + NODE_CMS_EXECUTION create make @@ -19,8 +19,6 @@ feature -- Execution 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 @@ -32,8 +30,10 @@ feature -- Execution if has_permission ("edit " + l_type.name) then f := edit_form (l_node, url (request.path_info, Void), "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") + f.validation_actions.extend (agent edit_form_validate (?, b)) + f.submit_actions.extend (agent edit_form_submit (?, l_node, l_type, b)) + f.process (Current) + fd := f.last_data end set_title ("Edit #" + l_node.id.out) @@ -41,54 +41,7 @@ feature -- Execution 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 - f.append_to_html (theme, b) - end + f.append_to_html (theme, b) else b.append ("

    Access denied

    ") end @@ -114,35 +67,100 @@ feature -- Execution 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) +-- edit_form_validate (fd: CMS_FORM_DATA; b: STRING) +-- local +-- l_preview: BOOLEAN +-- l_format: detachable CMS_FORMAT +-- do +-- l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") +-- if 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 +-- end - 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) +-- edit_form_submit (fd: CMS_FORM_DATA; a_node: detachable CMS_NODE; a_type: CMS_CONTENT_TYPE; b: STRING) +-- local +-- l_preview: BOOLEAN +-- l_node: detachable CMS_NODE +-- s: STRING +-- do +-- l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") +-- if not l_preview then +-- debug ("cms") +-- 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 +-- end +-- if a_node /= Void then +-- l_node := a_node +-- a_type.change_node (Current, fd, a_node) +-- s := "modified" +-- else +-- l_node := a_type.new_node (Current, fd, Void) +-- s := "created" +-- end +-- service.storage.save_node (l_node) +-- if attached user as u then +-- service.log ("node", "User %"" + user_link (u) + "%" " + s + " node " + link (a_type.name +" #" + l_node.id.out, "/node/" + l_node.id.out , Void), 0, node_local_link (l_node)) +-- else +-- service.log ("node", "Anonymous " + s + " node " + a_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 +-- end - a_type.fill_edit_form (f, a_node) +-- 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) - f.extend_text ("
    ") +-- 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) - create ts.make ("op") - ts.set_default_value ("Save") - f.extend (ts) +-- a_type.fill_edit_form (f, a_node) - create ts.make ("op") - ts.set_default_value ("Preview") - f.extend (ts) +-- f.extend_text ("
    ") - Result := f - end +-- 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/modules/node/node_module.e b/draft/application/cms/src/modules/node/node_module.e index 8dc62272..54155056 100644 --- a/draft/application/cms/src/modules/node/node_module.e +++ b/draft/application/cms/src/modules/node/node_module.e @@ -9,6 +9,9 @@ class inherit CMS_MODULE + redefine + permissions + end CMS_HOOK_MENU_ALTER @@ -29,6 +32,20 @@ feature {NONE} -- Initialization enable end +feature -- Access + + permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION] + do + Result := Precursor (a_service) + across + a_service.content_types as c + loop + Result.extend ("create " + c.item.name) + Result.extend ("edit " + c.item.name) + Result.extend ("delete " + c.item.name) + end + end + feature {CMS_SERVICE} -- Registration service: detachable CMS_SERVICE @@ -51,6 +68,7 @@ feature {CMS_SERVICE} -- Registration a_service.add_menu_alter_hook (Current) a_service.add_block_hook (Current) + end feature -- Hooks @@ -76,18 +94,19 @@ feature -- Hooks menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) local lnk: CMS_LOCAL_LINK + perms: detachable ARRAYED_LIST [READABLE_STRING_8] 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) + if attached a_execution.service.content_types as lst then + create perms.make (lst.count) + across + lst as c + loop + perms.force ("create " + c.item.name) + end end - end - - links: HASH_TABLE [CMS_MODULE_LINK, STRING] - -- Link indexed by path - do - create Result.make (0) + create lnk.make ("Add content", "/node/add/") + lnk.set_permission_arguments (perms) + a_menu_system.navigation_menu.extend (lnk) end handle_node_view (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE) diff --git a/draft/application/cms/src/modules/node/node_view_cms_execution.e b/draft/application/cms/src/modules/node/node_view_cms_execution.e index 4c67eaa7..028c5480 100644 --- a/draft/application/cms/src/modules/node/node_view_cms_execution.e +++ b/draft/application/cms/src/modules/node/node_view_cms_execution.e @@ -6,7 +6,7 @@ class NODE_VIEW_CMS_EXECUTION inherit - CMS_EXECUTION + NODE_CMS_EXECUTION create make diff --git a/draft/application/cms/src/modules/openid/openid_cms_execution.e b/draft/application/cms/src/modules/openid/openid_cms_execution.e new file mode 100644 index 00000000..e1b805cb --- /dev/null +++ b/draft/application/cms/src/modules/openid/openid_cms_execution.e @@ -0,0 +1,149 @@ +note + description: "Summary description for {OPENID_CMS_EXECUTION}." + date: "$Date$" + revision: "$Revision$" + +class + OPENID_CMS_EXECUTION + +inherit + CMS_EXECUTION + +create + make + +feature -- Execution + + process + local + b: STRING + f: CMS_FORM + tf: CMS_FORM_TEXT_INPUT + ts: CMS_FORM_SUBMIT_INPUT + o: OPENID_CONSUMER + v: OPENID_CONSUMER_VALIDATION + tb: HASH_TABLE [READABLE_STRING_8, STRING_8] + l_uid: INTEGER + do + create b.make_empty + set_title ("OpenID identities") + if attached request.string_item ("openid.mode") as l_openid_mode then + -- Callback + create o.make (request.absolute_script_url ("/openid/login")) + o.ask_email (True) + o.ask_nickname (False) +-- o.ask_all_info (False) + + create v.make_from_items (o, request.items_as_string_items) + v.validate + if v.is_valid then + if attached v.identity as l_identity then + if attached user as u then + if attached service.storage.custom_value (l_identity, "openid") as obj then + l_uid := user_id_from_custom_value (obj) + if l_uid > 0 and then l_uid = u.id then + -- Authenticated + b.append ("OpenID already associated to user %""+ user_link (u) +"%"") + else + -- Wrong USER !!! + b.append ("OpenID already associated to another user !!!") + end + else + -- New OpenID association + create tb.make (1) + tb.force (l_identity, "openid_identity") + tb.force (u.id.out, "uid") + service.storage.set_custom_value (l_identity, tb, "openid") + + b.append ("OpenID %""+ l_identity +"%" is now associated with user %""+ user_link (u) +"%"") + end + else + if + attached service.storage.custom_value (l_identity, "openid") as obj and then + attached user_id_from_custom_value (obj) as obj_uid and then + obj_uid > 0 and then + attached service.storage.user_by_id (obj_uid.to_integer) as u + then + -- Authenticated + set_user (u) + b.append ("Authenticated as %""+ user_link (u) +"%"") + set_redirection (user_url (u)) + else + -- Register new account + b.append ("Register new account associated with Openid %"" + l_identity + "%"?") + across + v.attributes as c + loop + b.append ("
  • " + c.key + "=" + c.item + "
  • ") + end + set_session_item ("openid.identity", l_identity) + if attached v.email_attribute as att_email then + set_session_item ("openid.email", att_email) + end + if attached v.nickname_attribute as att_nickname then + set_session_item ("openid.nickname", att_nickname) + end + b.append ("Create new account from your OpenID ") + b.append (link ("Register new account", "/user/register", Void)) + set_redirection (url ("/user/register", Void)) + end + end + end + else + b.append ("User authentication failed!!") + end + elseif attached request.string_item ("openid") as p_openid then + b.append ("Check openID: " + p_openid) + create o.make (request.absolute_script_url ("/openid/login")) + o.ask_email (True) + o.ask_all_info (False) + if attached o.auth_url (p_openid) as l_url then + set_redirection (l_url) + else + b.append ("Failure") + end + else + if attached user as u then + if attached service.storage.custom_value_names_where ("uid", u.id.out, "openid") as lst then + across + lst as c + loop + b.append ("
  • OpenID: " + c.item + "
  • ") + end + else + b.append ("No OpenID associated with current account") + end + end + create f.make (url ("/openid/login", Void), "openid-login") + create tf.make ("openid") + tf.set_size (50) + tf.set_text_value ("") + tf.set_label ("OpenID identifier") + f.extend (tf) + create ts.make_with_text ("op", "Validate") + f.extend (ts) + f.prepare (Current) + f.append_to_html (theme, b) + end + set_main_content (b) + end + + user_id_from_custom_value (lst: TABLE_ITERABLE [READABLE_STRING_8, STRING_8]): INTEGER + local + l_uid: detachable READABLE_STRING_8 + do + across + lst as c + until + l_uid /= Void + loop + if c.key.same_string ("uid") then + l_uid := c.item + end + end + if l_uid /= Void and then l_uid.is_integer then + Result := l_uid.to_integer + end + end + +end diff --git a/draft/application/cms/src/modules/openid/openid_module.e b/draft/application/cms/src/modules/openid/openid_module.e new file mode 100644 index 00000000..302b1b78 --- /dev/null +++ b/draft/application/cms/src/modules/openid/openid_module.e @@ -0,0 +1,141 @@ +note + description: "Summary description for {OPENID_MODULE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + OPENID_MODULE + +inherit + CMS_MODULE + + CMS_HOOK_MENU_ALTER + + CMS_HOOK_FORM_ALTER + + CMS_HOOK_AUTO_REGISTER + +create + make + +feature {NONE} -- Initialization + + make + do + name := "openid" + version := "1.0" + description := "OpenID login support" + package := "server" + end + +feature {CMS_SERVICE} -- Registration + + service: detachable CMS_SERVICE + + register (a_service: CMS_SERVICE) + do + a_service.map_uri ("/openid/login", agent handle_login) + + 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 + req: WSF_REQUEST + do + req := a_execution.request + if req.path_info.starts_with ("/user") then + if a_execution.authenticated then + create lnk.make ("Openid identities", "/openid/login") + else + create lnk.make ("Login with Openid", "/openid/login") + end + -- a_menu_system.management_menu.extend (lnk) + a_menu_system.primary_tabs.extend (lnk) + end + end + + form_alter (a_form: CMS_FORM; a_form_data: detachable CMS_FORM_DATA; a_execution: CMS_EXECUTION) + local + i: CMS_FORM_DIV + fh: CMS_FORM_HIDDEN_INPUT + do + if a_form.id.same_string ("openid-login") then + create i.make_with_text_and_css_id ( + "Login with " + a_execution.link ("OpenID", "/openid/login", Void) + + " , " + a_execution.link ("Google", "/openid/login?openid=https://www.google.com/accounts/o8/id", Void) + + " , " + a_execution.link ("Yahoo", "/openid/login?openid=https://me.yahoo.com/", Void) + , + "openid" + ) + a_form.extend (i) + elseif a_form.id.same_string ("user-login") then + create i.make_with_text_and_css_id ( + "Login with " + a_execution.link ("OpenID", "/openid/login", Void) + + " , " + a_execution.link ("Google", "/openid/login?openid=https://www.google.com/accounts/o8/id", Void) + + " , " + a_execution.link ("Yahoo", "/openid/login?openid=https://me.yahoo.com/", Void) + , + "openid" + ) + if attached a_form.items_by_type ({CMS_WIDGET_TEXT}) as lst and then not lst.is_empty then + a_form.insert_before (i, lst.last) + else + a_form.extend (i) + end + elseif a_form.id.same_string ("user-register") then + if attached {READABLE_STRING_GENERAL} a_execution.session_item ("openid.identity") as l_openid_identity then + create fh.make_with_text ("openid-identity", l_openid_identity.to_string_32) + a_execution.remove_session_item ("openid.identity") + a_form.extend (fh) + a_form.extend_text ("The new account will be associated with OpenID %""+ a_execution.html_encoded (l_openid_identity) +"%"") + if attached {READABLE_STRING_GENERAL} a_execution.session_item ("openid.nickname") as l_openid_nickname then + if attached a_form.fields_by_name ("username") as f_lst then + across + f_lst as c + loop + if attached {CMS_FORM_TEXT_INPUT} c.item as txt then + txt.set_text_value (l_openid_nickname.to_string_32) + end + end + end + a_execution.remove_session_item ("openid.nickname") + end + if attached {READABLE_STRING_GENERAL} a_execution.session_item ("openid.email") as l_openid_email then + if attached a_form.fields_by_name ("email") as f_lst then + across + f_lst as c + loop + if attached {CMS_FORM_TEXT_INPUT} c.item as txt then + txt.set_text_value (l_openid_email.to_string_32) + end + end + end + a_execution.remove_session_item ("openid.email") + end + a_form.submit_actions.extend (agent openid_user_register_submitted) + end + end + end + + openid_user_register_submitted (a_form_data: CMS_FORM_DATA) + do + + end + +feature -- Access + + handle_login (req: WSF_REQUEST; res: WSF_RESPONSE) + do + if attached service as l_service then + (create {OPENID_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/modules/user/user_cms_execution.e b/draft/application/cms/src/modules/user/user_cms_execution.e index 6f063958..76a2a39b 100644 --- a/draft/application/cms/src/modules/user/user_cms_execution.e +++ b/draft/application/cms/src/modules/user/user_cms_execution.e @@ -20,6 +20,7 @@ feature -- Execution local b: STRING_8 u: detachable CMS_USER + l_first: BOOLEAN do if attached {WSF_STRING} request.path_parameter ("uid") as p_uid then if p_uid.is_integer then @@ -43,6 +44,25 @@ feature -- Execution if attached u.email as l_email then b.append ("
  • Email: "+ l_email +"
  • ") end + if has_permission ("administer users") and attached u.roles as u_roles then + b.append ("
  • Roles:") + l_first := True + across + u_roles as r + loop + if l_first then + l_first := False + else + b.append (", ") + end + if attached service.storage.user_role_by_id (r.item) as ur then + b.append (ur.name) + else + b.append (r.item.out) + end + end + b.append ("
  • ") + 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") @@ -84,20 +104,23 @@ feature -- Execution if l_url = Void then l_url := request.script_url ("/user") end - f := login_form (url ("/user", Void), "login-form", l_url) - service.call_form_alter_hooks (f, Current) - + f := login_form (url ("/user", Void), "user-login", l_url) 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 + f.submit_actions.extend (agent on_form_submitted) + f.process (Current) + fd := f.last_data + else + f.prepare (Current) end if authenticated then + if + fd /= Void and then fd.is_valid and then + attached {WSF_STRING} fd.integer_item ("form-destination") as s_dest + then + l_url := request.script_url (s_dest.value) + end + set_redirection (l_url) set_title ("Login") create b.make_empty @@ -106,12 +129,6 @@ feature -- Execution 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 f.append_to_html (theme, b) set_main_content (b) end @@ -146,6 +163,8 @@ feature -- Execution ti: CMS_FORM_TEXT_INPUT tp: CMS_FORM_PASSWORD_INPUT ts: CMS_FORM_SUBMIT_INPUT + l_logo: CMS_FORM_RAW_TEXT + d: CMS_FORM_DIV do create Result.make (a_action, a_form_name) @@ -153,27 +172,32 @@ feature -- Execution th.set_default_value (a_destination) Result.extend (th) + create l_logo.make ("[ + + ]" + ) 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") + + create d.make_with_item (ti) + d.add_css_class ("input") + d.extend (tp) + Result.extend (l_logo) + Result.extend (d) Result.extend (ts) - Result.extend_text ("

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

    ") + Result.extend_text ("
    Need an account?
    " + link ("Sign up now!", "/user/register", Void) + "
    ") end form_username_or_email_name: STRING = "name" diff --git a/draft/application/cms/src/modules/user/user_edit_cms_execution.e b/draft/application/cms/src/modules/user/user_edit_cms_execution.e index 6b60605b..37afd19a 100644 --- a/draft/application/cms/src/modules/user/user_edit_cms_execution.e +++ b/draft/application/cms/src/modules/user/user_edit_cms_execution.e @@ -21,8 +21,7 @@ feature -- Execution b: STRING_8 f: CMS_FORM fd: detachable CMS_FORM_DATA - u, fu: detachable CMS_USER - up: detachable CMS_USER_PROFILE + u: detachable CMS_USER 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 @@ -50,67 +49,92 @@ feature -- Execution f := edit_form (u, url (request.path_info, Void), "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 and then not s_password.is_empty 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) + f.validation_actions.extend (agent edit_form_validate (?, u)) + f.submit_actions.extend (agent edit_form_submit (?, u, l_is_editing_current_user, b)) + f.process (Current) + fd := f.last_data else - if fd /= Void then - if not fd.is_valid then - report_form_errors (fd) - end - fd.apply_to_associated_form - end - f.append_to_html (theme, b) + f.prepare (Current) end + + f.append_to_html (theme, b) + end set_main_content (b) end + edit_form_validate (fd: CMS_FORM_DATA; u: CMS_USER) + local + fu: detachable CMS_USER + do + 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 + end + + edit_form_submit (fd: CMS_FORM_DATA; u: CMS_USER; a_is_editing_current_user: BOOLEAN; b: STRING) + local + up: detachable CMS_USER_PROFILE + l_roles: like {CMS_USER}.roles + do + debug + 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 + end + + if attached {WSF_STRING} fd.item ("password") as s_password and then not s_password.is_empty 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 + if has_permission ("administer users") then + l_roles := u.roles + u.clear_roles + if attached fd.table_item ("roles") as f_roles and then not f_roles.is_empty then + create {ARRAYED_LIST [INTEGER]} l_roles.make (f_roles.count) + across + f_roles as r + loop + if attached {WSF_STRING} r.item as s and then attached s.is_integer then + u.add_role_by_id (s.integer_value) + end + end + end + end + + service.storage.save_user (u) + if a_is_editing_current_user and u /= user then + set_user (u) + end + set_redirection (user_url (u)) + end + edit_form (u: CMS_USER; a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM local f: CMS_FORM @@ -118,6 +142,8 @@ feature -- Execution tp: CMS_FORM_PASSWORD_INPUT ta: CMS_FORM_TEXTAREA ts: CMS_FORM_SUBMIT_INPUT + tset: CMS_FORM_FIELD_SET + cb: CMS_FORM_CHECKBOX_INPUT do create f.make (a_url, a_name) @@ -156,6 +182,27 @@ feature -- Execution ta.set_is_required (False) f.extend (ta) + if has_permission ("administer users") then + create tset.make + tset.set_legend ("User roles") + tset.set_collapsible (True) + f.extend (tset) + across + service.storage.user_roles as r + loop + if + r.item ~ service.storage.anonymous_user_role or + r.item ~ service.storage.authenticated_user_role + then + -- Skip + else + create cb.make_with_value ("roles[]", r.item.id.out) + cb.set_title (r.item.name) + cb.set_checked (u /= Void and then u.has_role (r.item)) + tset.extend (cb) + end + end + end f.extend_text ("
    ") create ts.make ("op") diff --git a/draft/application/cms/src/modules/user/user_module.e b/draft/application/cms/src/modules/user/user_module.e index f581d030..248c8e2b 100644 --- a/draft/application/cms/src/modules/user/user_module.e +++ b/draft/application/cms/src/modules/user/user_module.e @@ -9,6 +9,9 @@ class inherit CMS_MODULE + redefine + permissions + end CMS_HOOK_MENU_ALTER @@ -55,6 +58,13 @@ feature {CMS_SERVICE} -- Registration feature -- Hooks + permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION] + do + Result := Precursor (a_service) + Result.extend ("register account") + Result.extend ("change username") + end + block_list: ITERABLE [like {CMS_BLOCK}.name] do Result := <<"user-info">> @@ -106,12 +116,6 @@ feature -- Hooks end end - links: HASH_TABLE [CMS_MODULE_LINK, STRING] - -- Link indexed by path - do - create Result.make (0) - end - feature -- Handlers handle_logout (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE) diff --git a/draft/application/cms/src/modules/user/user_new_password_cms_execution.e b/draft/application/cms/src/modules/user/user_new_password_cms_execution.e index 492b320a..25438ecf 100644 --- a/draft/application/cms/src/modules/user/user_new_password_cms_execution.e +++ b/draft/application/cms/src/modules/user/user_new_password_cms_execution.e @@ -22,8 +22,6 @@ feature -- Execution 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 @@ -45,54 +43,70 @@ feature -- Execution else f := new_password_form (url (request.path_info, Void), "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 and then u /= Void 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 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)) - else - add_success_message ("No email is associated with the requested account. Please contact the webmaster for help.") - set_redirection (url ("/user", Void)) - end - set_main_content (b) + f.validation_actions.extend (agent password_form_validate) + f.submit_actions.extend (agent password_form_submit (?, b)) + f.process (Current) + fd := f.last_data else - if fd /= Void then - if not fd.is_valid then - report_form_errors (fd) - end - fd.apply_to_associated_form - end - f.append_to_html (theme, b) + initialize_primary_tabs (Void) end + + f.append_to_html (theme, b) end set_main_content (b) end + password_form_validate (fd: CMS_FORM_DATA) + local + u: detachable CMS_USER + do + 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 + fd.add_cached_value ("user", u) + initialize_primary_tabs (u) + end + + password_form_submit (fd: CMS_FORM_DATA; b: STRING) + local + e: detachable CMS_EMAIL + l_uuid: UUID + do + debug + 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 + end + if attached {CMS_USER} fd.cached_value ("user") as u then + if 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)) + else + add_error_message ("No email is associated with the requested account. Please contact the webmaster for help.") + set_redirection (url ("/user", Void)) + end + else + add_error_message ("User not defined!") + end + 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 diff --git a/draft/application/cms/src/modules/user/user_register_cms_execution.e b/draft/application/cms/src/modules/user/user_register_cms_execution.e index b1b4d819..b82f64ca 100644 --- a/draft/application/cms/src/modules/user/user_register_cms_execution.e +++ b/draft/application/cms/src/modules/user/user_register_cms_execution.e @@ -21,11 +21,6 @@ feature -- Execution 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 @@ -34,81 +29,98 @@ feature -- Execution 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 (url (request.path_info, Void), "reg") + f := registration_form (url (request.path_info, Void), "user-register") 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 + f.validation_actions.extend (agent registration_form_validate) + f.submit_actions.extend (agent registration_form_submitted (?, b)) + + f.process (Current) + fd := f.last_data + else + f.prepare (Current) 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 f.append_to_html (theme, b) end end set_main_content (b) end + registration_form_validate (fd: CMS_FORM_DATA) + local + u: detachable CMS_USER + do + 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 + end + + registration_form_submitted (fd: CMS_FORM_DATA; buf: STRING) + local + b: STRING + u: detachable CMS_USER + up: detachable CMS_USER_PROFILE + e: detachable CMS_EMAIL + l_pass: detachable READABLE_STRING_32 + l_uuid: UUID + do + b := buf + 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 + end + registration_form (a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM local f: CMS_FORM diff --git a/draft/application/cms/src/storage/cms_sed_storage.e b/draft/application/cms/src/storage/cms_sed_storage.e index a86a49dc..f8e2e881 100644 --- a/draft/application/cms/src/storage/cms_sed_storage.e +++ b/draft/application/cms/src/storage/cms_sed_storage.e @@ -217,6 +217,46 @@ feature -- Change: user a_user.set_profile (prof) end +feature -- Access: user_role + + user_role_by_id (a_id: INTEGER): detachable CMS_USER_ROLE + do + if attached {like user_role_by_id} object_with_id (a_id, "user_roles") as ur then + Result := ur + end + end + + user_roles: LIST [CMS_USER_ROLE] + local + i: INTEGER + n: like last_sequence + do + n := last_sequence ("user_roles") + create {ARRAYED_LIST [CMS_USER_ROLE]} Result.make (n) + if n > 0 then + from + i := 1 + until + i > n + loop + if attached user_role_by_id (i) as ur then + Result.force (ur) + end + i := i + 1 + end + end + end + +feature -- Change: user_role + + save_user_role (a_role: CMS_USER_ROLE) + do + if not a_role.has_id then + a_role.set_id (next_sequence ("user_roles")) + end + save_object_with_id (a_role, a_role.id, "user_roles") + end + feature -- Email save_email (a_email: CMS_EMAIL) @@ -459,52 +499,116 @@ feature {NONE} -- Implementation 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 +feature -- Misc --- 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 + custom_type (a_type: READABLE_STRING_8): STRING + do + Result := "custom__" + a_type + end + + custom_value_id (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): INTEGER + -- Storage `id' for custom value named `a_name' if any. + -- If no such data exists, return 0 + local + i, + l_id, l_last_id: INTEGER + t: STRING + do + t := custom_type (a_type) + l_last_id := last_sequence (t) + from + i := 1 + until + i > l_last_id or l_id > 0 + loop + if + attached {TUPLE [name: READABLE_STRING_8; value: attached like custom_value]} object_with_id (i, t) as obj and then + obj.name.same_string (a_name) + then + l_id := i + end + i := i + 1 + end + end + + set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value ; a_type: READABLE_STRING_8) + -- Save data `a_name:a_value' for type `a_type' + local + t: STRING + l_id: INTEGER + do + t := custom_type (a_type) + l_id := custom_value_id (a_name, a_type) + if l_id = 0 then + l_id := next_sequence (t) + end + save_object_with_id ([a_name, a_value], l_id, t) + end + + custom_value (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable TABLE_ITERABLE [READABLE_STRING_8, STRING_8] + -- Data for name `a_name' and type `a_type'. + local + i, + l_id, l_last_id: INTEGER + t: STRING + do + t := custom_type (a_type) + l_last_id := last_sequence (t) + from + i := 1 + until + i > l_last_id or l_id > 0 + loop + if + attached {TUPLE [name: READABLE_STRING_8; value: attached like custom_value]} object_with_id (i, t) as obj and then + obj.name.same_string (a_name) + then + l_id := i + Result := obj.value + end + i := i + 1 + end + end + + custom_value_names_where (a_where_key, a_where_value: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable LIST [READABLE_STRING_8] + -- Name where custom value has item `a_where_key' same as `a_where_value' for type `a_type'. + local + i, l_last_id: INTEGER + t: STRING + l_key_found: BOOLEAN + res: ARRAYED_LIST [READABLE_STRING_8] + do + create res.make (0) + t := custom_type (a_type) + l_last_id := last_sequence (t) + from + i := 1 + until + i > l_last_id + loop + if + attached {TUPLE [name: READABLE_STRING_8; value: attached like custom_value]} object_with_id (i, t) as d + then + l_key_found := False + across + d.value as c + until + l_key_found or Result /= Void + loop + if c.key.same_string (a_where_key) then + l_key_found := True + if c.item.same_string (a_where_value) then + res.force (d.name) + end + end + end + end + i := i + 1 + end + if not res.is_empty then + Result := res + end + end feature {NONE} -- Implementation diff --git a/draft/application/cms/src/storage/cms_storage.e b/draft/application/cms/src/storage/cms_storage.e index 404b4270..bfe592be 100644 --- a/draft/application/cms/src/storage/cms_storage.e +++ b/draft/application/cms/src/storage/cms_storage.e @@ -56,17 +56,6 @@ feature -- Access: user deferred end - user_has_permission (u: detachable CMS_USER; s: detachable READABLE_STRING_8): BOOLEAN - -- Anonymous or user `u' has permission for `s' ? - --| `s' could be "create page", - do - if s = Void then - Result := True - else - Result := False - end - end - feature -- Change: user save_user (a_user: CMS_USER) @@ -76,6 +65,69 @@ feature -- Change: user a_user.has_id end +feature -- Access: roles and permissions + + user_has_permission (u: detachable CMS_USER; s: detachable READABLE_STRING_8): BOOLEAN + -- Anonymous or user `u' has permission for `s' ? + --| `s' could be "create page", + do + if s = Void then + Result := True + elseif u = Void then + Result := user_role_has_permission (anonymous_user_role, s) + else + Result := user_role_has_permission (authenticated_user_role, s) + if not Result and attached u.roles as l_roles then + across + l_roles as r + until + Result + loop + if attached user_role_by_id (r.item) as ur then + Result := user_role_has_permission (ur, s) + end + end + end + end + end + + anonymous_user_role: CMS_USER_ROLE + do + if attached user_role_by_id (1) as l_anonymous then + Result := l_anonymous + else + create Result.make ("anonymous") + end + end + + authenticated_user_role: CMS_USER_ROLE + do + if attached user_role_by_id (2) as l_authenticated then + Result := l_authenticated + else + create Result.make ("authenticated") + end + end + + user_role_has_permission (a_role: CMS_USER_ROLE; s: READABLE_STRING_8): BOOLEAN + do + Result := a_role.has_permission (s) + end + + user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE + deferred + end + + user_roles: LIST [CMS_USER_ROLE] + deferred + end + +feature -- Change: roles and permissions + + save_user_role (a_user_role: CMS_USER_ROLE) + deferred + end + feature -- Email save_email (a_email: CMS_EMAIL) @@ -114,4 +166,21 @@ feature -- Node deferred end +feature -- Misc + + set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value; a_type: READABLE_STRING_8) + -- Save data `a_name:a_value' for type `a_type' + deferred + end + + custom_value (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable TABLE_ITERABLE [READABLE_STRING_8, STRING_8] + -- Data for name `a_name' and type `a_type'. + deferred + end + + custom_value_names_where (a_where_key, a_where_value: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable LIST [READABLE_STRING_8] + -- Names where custom value has item `a_where_key' same as `a_where_value' for type `a_type'. + deferred + end + end diff --git a/draft/application/cms/src/widgets/cms_widget.e b/draft/application/cms/src/widgets/cms_widget.e index 7566ab3c..3f675a4a 100644 --- a/draft/application/cms/src/widgets/cms_widget.e +++ b/draft/application/cms/src/widgets/cms_widget.e @@ -13,4 +13,10 @@ feature -- Conversion deferred end + to_html (a_theme: CMS_THEME): STRING_8 + do + create Result.make_empty + append_to_html (a_theme, Result) + end + end diff --git a/draft/application/cms/src/widgets/cms_widget_agent_table.e b/draft/application/cms/src/widgets/cms_widget_agent_table.e new file mode 100644 index 00000000..234085df --- /dev/null +++ b/draft/application/cms/src/widgets/cms_widget_agent_table.e @@ -0,0 +1,225 @@ +note + description: "Summary description for {CMS_WIDGET_TABLE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_WIDGET_AGENT_TABLE [G] + +inherit + CMS_WIDGET + + WITH_CSS_ID + + WITH_CSS_CLASS + + WITH_CSS_STYLE + +create + make + +convert + to_computed_table: {CMS_WIDGET_TABLE} + +feature {NONE} -- Initialization + + make + do + create columns.make_empty + end + +feature -- Access + + column_count: INTEGER + do + Result := columns.count + end + + columns: ARRAY [CMS_WIDGET_TABLE_COLUMN] + + column (c: INTEGER): CMS_WIDGET_TABLE_COLUMN + do + if c > column_count then + set_column_count (c) + end + Result := columns[c] + end + + has_title: BOOLEAN + do + Result := across columns as c some c.item.title /= Void end + end + + head_data: detachable ITERABLE [G] + -- thead + + foot_data: detachable ITERABLE [G] + -- tfoot + + data: detachable ITERABLE [G] + -- tbody + + compute_item_function: detachable FUNCTION [ANY, TUPLE [data: G], CMS_WIDGET_TABLE_ROW] + +feature -- Change + + set_head_data (d: like head_data) + do + head_data := d + end + + set_foot_data (d: like foot_data) + do + foot_data := d + end + + set_data (d: like data) + do + data := d + end + + set_compute_item_function (fct: like compute_item_function) + do + compute_item_function := fct + end + + set_column_count (nb: INTEGER) + do + if nb > columns.count then +-- columns.conservative_resize_with_default (create {CMS_WIDGET_TABLE_COLUMN}, 1, nb) + from + until + columns.count = nb + loop + columns.force (create {CMS_WIDGET_TABLE_COLUMN}.make (columns.upper + 1), columns.upper + 1) + end + else + columns.remove_tail (columns.count - nb) + end + end + + set_column_title (c: INTEGER; t: READABLE_STRING_32) + do + if c > column_count then + set_column_count (c) + end + if attached column (c) as col then + col.set_title (t) + end + end + +feature -- Conversion + + to_computed_table: CMS_WIDGET_TABLE + local + col: CMS_WIDGET_TABLE_COLUMN + do + create Result.make + Result.set_column_count (column_count) + -- css classes + Result.add_css_classes (css_classes) + -- css id + Result.set_css_id (css_id) + -- css style + Result.add_css_style (css_style) + + -- columns + across + columns as c + loop + col := Result.column (c.item.index) + col.set_title (c.item.title) + col.add_css_style (c.item.css_style) + col.add_css_classes (c.item.css_classes) + end + + -- rows + if attached compute_item_function as fct then + if attached head_data as lst then + across lst as d loop + Result.add_head_row (fct.item ([d.item])) + end + end + if attached data as lst then + across lst as d loop + Result.add_row (fct.item ([d.item])) + end + end + if attached foot_data as lst then + across lst as d loop + Result.add_foot_row (fct.item ([d.item])) + end + end + end + end + +feature -- Conversion: HTML + + append_to_html (a_theme: CMS_THEME; a_html: STRING_8) + local + l_use_tbody: BOOLEAN + do + a_html.append ("") + + if has_title then + a_html.append ("") + across + columns as c + loop + c.item.append_table_header_to_html (a_theme, a_html) + end + a_html.append ("") + end + if attached head_data as l_head_data then + l_use_tbody := True + a_html.append ("") + append_data_to_html (l_head_data, a_theme, a_html) + a_html.append ("") + end + if attached foot_data as l_foot_data then + l_use_tbody := True + a_html.append ("") + append_data_to_html (l_foot_data, a_theme, a_html) + a_html.append ("") + end + + if attached data as l_data then + if l_use_tbody then + a_html.append ("") + end + append_data_to_html (l_data, a_theme, a_html) + if l_use_tbody then + a_html.append ("") + end + end + a_html.append ("") + end + + append_data_to_html (lst: ITERABLE [G]; a_theme: CMS_THEME; a_html: STRING_8) + local + fct: like compute_item_function + do + fct := compute_item_function + across + lst as d + loop + if fct /= Void and then attached fct.item ([d.item]) as r then + r.append_to_html (a_theme, a_html) + else + a_html.append ("") + a_html.append ("") + if attached d.item as g then + a_html.append (g.out) + end + a_html.append ("") + a_html.append ("") + end + end + end + +end diff --git a/draft/application/cms/src/widgets/cms_widget_composite.e b/draft/application/cms/src/widgets/cms_widget_composite.e new file mode 100644 index 00000000..ea5bfbf5 --- /dev/null +++ b/draft/application/cms/src/widgets/cms_widget_composite.e @@ -0,0 +1,250 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +deferred class + CMS_WIDGET_COMPOSITE + +inherit + ITERABLE [CMS_WIDGET] + +feature {NONE} -- Initialization + + initialize_with_count (n: INTEGER) + do + create items.make (n) + end + +feature -- Status + + is_empty: BOOLEAN + do + Result := count = 0 + end + + has_item (i: CMS_WIDGET): BOOLEAN + do + if has_immediate_item (i) then + Result := True + else + across + items as c + loop + if attached {CMS_WIDGET_COMPOSITE} c.item as comp then + Result := comp.has_item (i) + end + end + end + end + + has_immediate_item (i: CMS_WIDGET): BOOLEAN + do + Result := items.has (i) + end + +feature -- Access: cursor + + new_cursor: ITERATION_CURSOR [CMS_WIDGET] + -- Fresh cursor associated with current structure + do + Result := items.new_cursor + end + +feature -- Access + + count: INTEGER + do + Result := immediate_count + across + items as c + loop + if attached {CMS_WIDGET_COMPOSITE} c.item as comp then + Result := Result + comp.count + end + end + end + + immediate_count: INTEGER + do + Result := items.count + end + + items_by_type (a_type: TYPE [detachable ANY]): detachable LIST [CMS_WIDGET] + -- All CMS_WIDGET items conforming to a_type. + -- Warning: you should pass {detachable CMS_FORM_SUBMIT_INPUT} rather than just {CMS_FORM_SUBMIT_INPUT} + local + int: INTERNAL + tid: INTEGER + t: TYPE [detachable ANY] + do + tid := a_type.type_id + create int + tid := int.detachable_type (tid) + if tid > 0 then + t := int.type_of_type (tid) + if not a_type.conforms_to (t) then + t := a_type + end + else + t := a_type + end + Result := items_by_type_from (Current, t) + end + + items_by_css_id (a_id: READABLE_STRING_GENERAL): detachable LIST [CMS_WIDGET] + do + Result := items_by_css_id_from (Current, a_id) + end + + first_item_by_css_id (a_id: READABLE_STRING_GENERAL): detachable CMS_WIDGET + do + if attached items_by_css_id_from (Current, a_id) as lst then + if not lst.is_empty then + Result := lst.first + end + end + end + +feature -- Change + + insert_before (i: CMS_WIDGET; a_item: CMS_WIDGET) + -- Insert `i' before `a_item' + require + has_item (a_item) + local + done: BOOLEAN + do + if has_immediate_item (a_item) then + items.start + items.search (a_item) + if items.exhausted then + items.put_front (i) + else + items.put_left (i) + end + else + across + items as c + until + done + loop + if attached {CMS_WIDGET_COMPOSITE} c.item as comp and then comp.has_item (a_item) then + comp.insert_before (i, a_item) + done := True + end + end + end + end + + insert_after (i: CMS_WIDGET; a_item: CMS_WIDGET) + -- Insert `i' after `a_item' + require + has_item (a_item) + local + done: BOOLEAN + do + if has_immediate_item (a_item) then + items.start + items.search (a_item) + if items.exhausted then + items.force (i) + else + items.put_right (i) + end + else + across + items as c + until + done + loop + if attached {CMS_WIDGET_COMPOSITE} c.item as comp and then comp.has_item (a_item) then + comp.insert_after (i, a_item) + done := True + end + end + end + end + + extend (i: CMS_WIDGET) + do + items.force (i) + end + + prepend (i: CMS_WIDGET) + do + items.put_front (i) + end + + extend_text (t: READABLE_STRING_8) + do + extend (create {CMS_WIDGET_TEXT}.make_with_text (t)) + end + +feature {NONE} -- Implementation: Items + + items_by_type_from (a_container: ITERABLE [CMS_WIDGET]; a_type: TYPE [detachable ANY]): detachable ARRAYED_LIST [CMS_WIDGET] + local + res: detachable ARRAYED_LIST [CMS_WIDGET] + do + across + a_container as i + loop + if i.item.generating_type.conforms_to (a_type) then + if res = Void then + create res.make (1) + end + res.force (i.item) + elseif attached {ITERABLE [CMS_WIDGET]} i.item as l_cont then + if attached items_by_type_from (l_cont, a_type) as lst then + if res = Void then + res := lst + else + res.append (lst) + end + end + end + end + Result := res + end + + items_by_css_id_from (a_container: ITERABLE [CMS_WIDGET]; a_id: READABLE_STRING_GENERAL): detachable ARRAYED_LIST [CMS_WIDGET] + local + res: detachable ARRAYED_LIST [CMS_WIDGET] + do + across + a_container as i + loop + if + attached {WITH_CSS_ID} i.item as l_with_css_id and then + attached l_with_css_id.css_id as l_css_id and then + l_css_id.same_string_general (a_id) + then + if res = Void then + create res.make (1) + end + res.force (i.item) + elseif attached {ITERABLE [CMS_WIDGET]} i.item as l_cont then + if attached items_by_css_id_from (l_cont, a_id) as lst then + if res = Void then + res := lst + else + res.append (lst) + end + end + end + end + Result := res + end + +feature {NONE} -- Implementation + + items: ARRAYED_LIST [CMS_WIDGET] + -- name => item + +invariant + items /= Void + + +end diff --git a/draft/application/cms/src/widgets/cms_widget_table.e b/draft/application/cms/src/widgets/cms_widget_table.e index 26e8eef5..7c67d71a 100644 --- a/draft/application/cms/src/widgets/cms_widget_table.e +++ b/draft/application/cms/src/widgets/cms_widget_table.e @@ -1,11 +1,10 @@ note - description: "Summary description for {CMS_WIDGET_TABLE}." - author: "" + description: "Summary description for {CMS_WIDGET_FILLED_TABLE}." date: "$Date$" revision: "$Revision$" class - CMS_WIDGET_TABLE [G] + CMS_WIDGET_TABLE inherit CMS_WIDGET @@ -16,6 +15,8 @@ inherit WITH_CSS_STYLE + ITERABLE [CMS_WIDGET_TABLE_ITEM] + create make @@ -26,15 +27,94 @@ feature {NONE} -- Initialization create columns.make_empty end + make_from_table (tb: CMS_WIDGET_AGENT_TABLE [detachable ANY]) + local + fct: like {CMS_WIDGET_AGENT_TABLE [detachable ANY]}.compute_item_function + do + make + set_column_count (tb.column_count) + -- css classes + if attached tb.css_classes as lst then + across lst as c loop + add_css_class (c.item) + end + end + -- css id + set_css_id (tb.css_id) + + -- css style + add_css_style (tb.css_style) + + -- columns + across + tb.columns as c + loop + columns [c.item.index] := c.item.twin + end + + -- rows + fct := tb.compute_item_function + if fct /= Void then + if attached tb.head_data as lst then + across lst as d loop + add_head_row (fct.item ([d.item])) + end + end + if attached tb.data as lst then + across lst as d loop + add_row (fct.item ([d.item])) + end + end + if attached tb.foot_data as lst then + across lst as d loop + add_foot_row (fct.item ([d.item])) + end + end + end + end + feature -- Access + new_cursor: CMS_WIDGET_TABLE_ITERATION_CURSOR + -- Fresh cursor associated with current structure + do + create Result.make (Current) + end + column_count: INTEGER do Result := columns.count end + head_row_count: INTEGER + do + if attached head_rows as lst then + Result := lst.count + end + end + + body_row_count: INTEGER + do + if attached rows as lst then + Result := lst.count + end + end + + foot_row_count: INTEGER + do + if attached foot_rows as lst then + Result := lst.count + end + end + + row_count: INTEGER + do + Result := head_row_count + body_row_count + foot_row_count + end + columns: ARRAY [CMS_WIDGET_TABLE_COLUMN] + column (c: INTEGER): CMS_WIDGET_TABLE_COLUMN do if c > column_count then @@ -43,48 +123,85 @@ feature -- Access Result := columns[c] end + row (r: INTEGER): detachable CMS_WIDGET_TABLE_ROW + do + if r <= head_row_count then + if attached head_rows as lst then + Result := lst [r] + end + elseif r <= head_row_count + body_row_count then + if attached rows as lst then + Result := lst [r - head_row_count] + end + elseif r <= row_count then + if attached foot_rows as lst then + Result := lst [r - head_row_count - body_row_count] + end + end + end + has_title: BOOLEAN do Result := across columns as c some c.item.title /= Void end end - head_data: detachable ITERABLE [G] + head_rows: detachable ARRAYED_LIST [CMS_WIDGET_TABLE_ROW] -- thead - foot_data: detachable ITERABLE [G] + foot_rows: detachable ARRAYED_LIST [CMS_WIDGET_TABLE_ROW] -- tfoot - data: detachable ITERABLE [G] + rows: detachable ARRAYED_LIST [CMS_WIDGET_TABLE_ROW] -- tbody - compute_item_function: detachable FUNCTION [ANY, TUPLE [data: G], CMS_WIDGET_TABLE_ROW] - feature -- Change - set_head_data (d: like head_data) + clear_rows do - head_data := d + head_rows := Void + foot_rows := Void + rows := Void end - set_foot_data (d: like foot_data) + add_head_row (r: CMS_WIDGET_TABLE_ROW) + local + lst: like head_rows do - foot_data := d + lst := head_rows + if lst = Void then + create {ARRAYED_LIST [CMS_WIDGET_TABLE_ROW]} lst.make (1) + head_rows := lst + end + lst.force (r) end - set_data (d: like data) + add_foot_row (r: CMS_WIDGET_TABLE_ROW) + local + lst: like foot_rows do - data := d + lst := foot_rows + if lst = Void then + create {ARRAYED_LIST [CMS_WIDGET_TABLE_ROW]} lst.make (1) + foot_rows := lst + end + lst.force (r) end - set_compute_item_function (fct: like compute_item_function) + add_row (r: CMS_WIDGET_TABLE_ROW) + local + lst: like rows do - compute_item_function := fct + lst := rows + if lst = Void then + create {ARRAYED_LIST [CMS_WIDGET_TABLE_ROW]} lst.make (1) + rows := lst + end + lst.force (r) end set_column_count (nb: INTEGER) do if nb > columns.count then --- columns.conservative_resize_with_default (create {CMS_WIDGET_TABLE_COLUMN}, 1, nb) from until columns.count = nb @@ -127,24 +244,24 @@ feature -- Conversion end a_html.append ("") end - if attached head_data as l_head_data then + if attached head_rows as l_head_rows then l_use_tbody := True a_html.append ("") - append_data_to_html (l_head_data, a_theme, a_html) + append_rows_to_html (l_head_rows, a_theme, a_html) a_html.append ("") end - if attached foot_data as l_foot_data then + if attached foot_rows as l_foot_rows then l_use_tbody := True a_html.append ("") - append_data_to_html (l_foot_data, a_theme, a_html) + append_rows_to_html (l_foot_rows, a_theme, a_html) a_html.append ("") end - if attached data as l_data then + if attached rows as l_rows then if l_use_tbody then a_html.append ("") end - append_data_to_html (l_data, a_theme, a_html) + append_rows_to_html (l_rows, a_theme, a_html) if l_use_tbody then a_html.append ("") end @@ -152,25 +269,12 @@ feature -- Conversion a_html.append ("") end - append_data_to_html (lst: ITERABLE [G]; a_theme: CMS_THEME; a_html: STRING_8) - local - fct: like compute_item_function + append_rows_to_html (lst: ITERABLE [CMS_WIDGET_TABLE_ROW]; a_theme: CMS_THEME; a_html: STRING_8) do - fct := compute_item_function across - lst as d + lst as r loop - if fct /= Void and then attached fct.item ([d.item]) as r then - r.append_to_html (a_theme, a_html) - else - a_html.append ("") - a_html.append ("") - if attached d.item as g then - a_html.append (g.out) - end - a_html.append ("") - a_html.append ("") - end + r.item.append_to_html (a_theme, a_html) end end diff --git a/draft/application/cms/src/widgets/cms_widget_table_item.e b/draft/application/cms/src/widgets/cms_widget_table_item.e index db223de8..f9ae174d 100644 --- a/draft/application/cms/src/widgets/cms_widget_table_item.e +++ b/draft/application/cms/src/widgets/cms_widget_table_item.e @@ -16,6 +16,8 @@ inherit WITH_CSS_STYLE + ITERABLE [CMS_WIDGET] + create make_with_text, make_with_text_and_css, @@ -49,6 +51,18 @@ feature -- Access content: CMS_WIDGET +feature -- Access + + new_cursor: ITERATION_CURSOR [CMS_WIDGET] + -- Fresh cursor associated with current structure + local + lst: ARRAYED_LIST [CMS_WIDGET] + do + create lst.make (1) + lst.extend (content) + Result := lst.new_cursor + end + feature -- Conversion append_to_html (a_theme: CMS_THEME; a_html: STRING_8) diff --git a/draft/application/cms/src/widgets/cms_widget_table_iteration_cursor.e b/draft/application/cms/src/widgets/cms_widget_table_iteration_cursor.e new file mode 100644 index 00000000..fc1b9a88 --- /dev/null +++ b/draft/application/cms/src/widgets/cms_widget_table_iteration_cursor.e @@ -0,0 +1,96 @@ +note + description: "Summary description for {CMS_WIDGET_TABLE_ITERATION_CURSOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_WIDGET_TABLE_ITERATION_CURSOR + +inherit + ITERATION_CURSOR [CMS_WIDGET_TABLE_ITEM] + +create + make + +feature {NONE} -- Initialization + + make (a_table: CMS_WIDGET_TABLE) + do + table := a_table + start + end + + table: CMS_WIDGET_TABLE + + row_index: INTEGER + column_index: INTEGER + +feature -- Access + + start + do + row_index := 1 + column_index := 0 + forth + end + + item: CMS_WIDGET_TABLE_ITEM + -- Item at current cursor position. + do + if attached table.row (row_index) as r then + if attached r.item (column_index) as w then + Result := w + else + create Result.make_with_text ("") + end + else + create Result.make_with_text ("") + end + end + +feature -- Status report + + after: BOOLEAN + -- Are there no more items to iterate over? + do + if row_index > table.row_count then + Result := True + elseif row_index = table.row_count then + if attached table.row (row_index) as l_row then + if column_index > l_row.count then + Result := True + else + Result := False + end + else + Result := True + end + end + end + +feature -- Cursor movement + + forth + -- Move to next position. + do + if row_index <= table.row_count then + if attached table.row (row_index) as l_row then + if column_index < l_row.count then + column_index := column_index + 1 + else + from + row_index := row_index + 1 + column_index := 1 + until + row_index > table.row_count or + attached table.row (row_index) as r and then r.count > 0 + loop + row_index := row_index + 1 + end + end + end + end + end + +end diff --git a/draft/application/cms/src/widgets/cms_widget_table_row.e b/draft/application/cms/src/widgets/cms_widget_table_row.e index f01d2da2..59c2c1fe 100644 --- a/draft/application/cms/src/widgets/cms_widget_table_row.e +++ b/draft/application/cms/src/widgets/cms_widget_table_row.e @@ -49,8 +49,39 @@ feature -- Access Result := items.new_cursor end + count: INTEGER + do + Result := items.count + end + + item (c: INTEGER): CMS_WIDGET_TABLE_ITEM + do + Result := items [c] + end + feature -- Change + set_item (w: CMS_WIDGET_TABLE_ITEM; col: INTEGER) + do + if col > items.count then + items.grow (col) + from + until + items.count >= col - 1 + loop + items.force (create {CMS_WIDGET_TABLE_ITEM}.make_with_text ("")) + end + items.force (w) + else + items.put_i_th (w, col) + end + end + + add_widget (w: CMS_WIDGET) + do + add_item (create {CMS_WIDGET_TABLE_ITEM}.make_with_content (w)) + end + force, add_item (w: CMS_WIDGET_TABLE_ITEM) do items.force (w) diff --git a/draft/application/cms/www/themes/default/res/style.css b/draft/application/cms/www/themes/default/res/style.css index 8905e92e..b0615aed 100644 --- a/draft/application/cms/www/themes/default/res/style.css +++ b/draft/application/cms/www/themes/default/res/style.css @@ -150,13 +150,22 @@ div.node div.inner { border-top: dotted 1px #dddddd; } -form#login-form { +form#user-login { border: dotted 1px #099; display: inline-block; padding: 10px; margin: 10px; } +form#user-login>div { + margin-bottom: 10px; +} +form#user-login .input { + float: left; +} +form#user-login img.logo { +} + div#message { border: solid 1px #fc0; background-color: #fed; diff --git a/library/security/openid/consumer/src/openid_consumer_validation.e b/library/security/openid/consumer/src/openid_consumer_validation.e index 0abb4076..78b72c75 100644 --- a/library/security/openid/consumer/src/openid_consumer_validation.e +++ b/library/security/openid/consumer/src/openid_consumer_validation.e @@ -32,6 +32,48 @@ feature -- Access attributes: HASH_TABLE [READABLE_STRING_32, STRING_8] +feature -- Access: attributes + + email_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("contact/email") + end + + nickname_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("namePerson/friendly") + end + + fullname_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("namePerson") + end + + gender_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("person/gender") + end + + postcode_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("contact/postalCode/home") + end + + country_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("contact/country/home") + end + + language_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("pref/language") + end + + timezone_attribute: detachable READABLE_STRING_32 + do + Result := attributes.item ("pref/timezone") + end + feature -- Basic operation validate diff --git a/library/server/wsf/extension/wsf_resource_handler_helper.e b/library/server/wsf/extension/wsf_resource_handler_helper.e index cb676bb1..acf306ac 100644 --- a/library/server/wsf/extension/wsf_resource_handler_helper.e +++ b/library/server/wsf/extension/wsf_resource_handler_helper.e @@ -14,6 +14,9 @@ feature -- Execute template execute_methods (req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request and dispatch according to the request method. + require + req_attached: req /= Void + res_attached: res /= Void local m: READABLE_STRING_8 do @@ -43,6 +46,11 @@ feature -- Execute template feature -- Method Get execute_get (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + get_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_get) do do_get (req, res) end @@ -52,9 +60,9 @@ feature -- Method Get -- If the GET request is SUCCESS, we respond with -- 200 OK, and a representation of the resource. -- If the GET request is not SUCCESS, we response with - -- 404 Resource not found + -- 404 Resource not found. -- If is a Condition GET and the resource does not change we send a - -- 304, Resource not modifed + -- 304, Resource not modifed. do handle_not_implemented ("Method GET not implemented", req, res) end @@ -62,6 +70,11 @@ feature -- Method Get feature -- Method Post execute_post (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + post_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_post) do if req.is_chunked_input then do_post (req, res) @@ -90,6 +103,11 @@ feature -- Method Post feature-- Method Put execute_put (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + put_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_put) do if req.is_chunked_input then do_put (req, res) @@ -110,6 +128,11 @@ feature-- Method Put feature -- Method DELETE execute_delete (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + delete_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_delete) do do_delete (req, res) end @@ -126,6 +149,11 @@ feature -- Method DELETE feature -- Method CONNECT execute_connect (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + connect_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_connect) do do_connect (req, res) end @@ -138,6 +166,11 @@ feature -- Method CONNECT feature -- Method HEAD execute_head (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + head_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_head) do do_head (req, res) end @@ -157,6 +190,11 @@ feature -- Method HEAD feature -- Method OPTIONS execute_options (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + options_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) do do_options (req, res) end @@ -170,6 +208,11 @@ feature -- Method OPTIONS feature -- Method TRACE execute_trace (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void + trace_method: req.is_request_method ({HTTP_REQUEST_METHODS}.method_trace) do do_trace (req, res) end @@ -183,20 +226,30 @@ feature -- Method TRACE feature -- Method Extension Method execute_extension_method (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void do do_extension_method (req, res) end do_extension_method (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding into `res'. + require + req_attached: req /= Void + res_attached: res /= Void do handle_not_implemented ("Method extension-method not implemented", req, res) end feature -- Retrieve content from WGI_INPUT_STREAM - retrieve_data ( req : WSF_REQUEST) : STRING - -- retrieve the content from the input stream - -- handle differents transfers + retrieve_data (req: WSF_REQUEST): STRING + -- Retrieve the content from the input stream. + -- Handle different transfers. + require + req_attached: req /= Void do create Result.make_empty req.read_input_data_into (Result) @@ -207,15 +260,15 @@ feature -- Handle responses -- The option : Server-driven negotiation: uses request headers to select a variant -- More info : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12 --- supported_content_types: detachable ARRAY [READABLE_STRING_8] --- -- Supported content types --- -- Can be redefined --- do --- Result := Void --- end + -- TODO: review HTTP requirements on `a_description' for each individual error code. handle_error (a_description: STRING; a_status_code: INTEGER; req: WSF_REQUEST; res: WSF_RESPONSE) -- Handle an error. + require + a_description_attached: a_description /= Void + a_status_code_valid: a_status_code > 0 + req_attached: req /= Void + res_attached: res /= Void local h: HTTP_HEADER do @@ -229,55 +282,99 @@ feature -- Handle responses end handle_not_implemented (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.not_implemented. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.not_implemented, req, res) end handle_bad_request_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.bad_request. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.bad_request, req, res) end handle_resource_not_found_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.not_found. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.not_found, req, res) end handle_forbidden (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) - -- Handle forbidden. + -- Handle error {HTTP_STATUS_CODE}.forbidden. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.forbidden, req, res) end feature -- Handle responses: others - handle_precondition_fail_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE ) + handle_precondition_fail_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.precondition_failed. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.precondition_failed, req, res) end - handle_internal_server_error (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE ) + handle_internal_server_error (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.internal_server_error. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.internal_server_error, req, res) end handle_method_not_allowed_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.method_not_allowed. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.method_not_allowed, req, res) end handle_resource_not_modified_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.not_modified. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.not_modified, req, res) end handle_resource_conflict_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle error {HTTP_STATUS_CODE}.conflict. + require + a_description_attached: a_description /= Void + req_attached: req /= Void + res_attached: res /= Void do handle_error (a_description, {HTTP_STATUS_CODE}.conflict, req, res) end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/support/uri/wsf_uri_handler.e b/library/server/wsf/router/support/uri/wsf_uri_handler.e index c73a3436..efa5c53c 100644 --- a/library/server/wsf/router/support/uri/wsf_uri_handler.e +++ b/library/server/wsf/router/support/uri/wsf_uri_handler.e @@ -15,6 +15,10 @@ inherit feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute handler for `req' and respond in `res'. + require + req_attached: req /= Void + res_attached: res /= Void deferred end @@ -26,7 +30,7 @@ feature {WSF_ROUTER} -- Mapping end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e index 018f3c86..7dc8b5a6 100644 --- a/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_uri_template_routed_service.e @@ -13,11 +13,19 @@ inherit feature -- Mapping helper: uri map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) + -- Map `h' as handler for `a_tpl' + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void do map_uri_template_with_request_methods (a_tpl, h, Void) end map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `h' as handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void do router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) end @@ -25,17 +33,25 @@ feature -- Mapping helper: uri feature -- Mapping helper: uri agent map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) + -- Map `proc' as handler for `a_tpl' + require + a_tpl_attached: a_tpl /= Void + proc_attached: proc /= Void do map_uri_template_agent_with_request_methods (a_tpl, proc, Void) end map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + proc_attached: proc /= Void do map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/support/uri_template/wsf_uri_template_handler.e b/library/server/wsf/router/support/uri_template/wsf_uri_template_handler.e index e049154d..0e14102c 100644 --- a/library/server/wsf/router/support/uri_template/wsf_uri_template_handler.e +++ b/library/server/wsf/router/support/uri_template/wsf_uri_template_handler.e @@ -15,6 +15,10 @@ inherit feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute `req' responding in `res'. + require + req_attached: req /= Void + res_attached: res /= Void deferred end diff --git a/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping.e b/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping.e index 5fc830fa..31d6285d 100644 --- a/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping.e +++ b/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping.e @@ -21,17 +21,25 @@ feature -- Access feature -- Change set_handler (h: like handler) + -- do handler := h + ensure then + h_aliased: handler = h end feature {NONE} -- Execution execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE) + -- do h.execute (req, res) end +invariant + + handler_attached: handler /= Void + note copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping_i.e b/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping_i.e index 3abf5f66..0a047949 100644 --- a/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping_i.e +++ b/library/server/wsf/router/support/uri_template/wsf_uri_template_mapping_i.e @@ -15,20 +15,27 @@ inherit feature {NONE} -- Initialization make (s: READABLE_STRING_8; h: like handler) + -- do make_from_template (create {URI_TEMPLATE}.make (s), h) end make_from_template (tpl: URI_TEMPLATE; h: like handler) + -- Create with `h' as the handler for resources matching `tpl' + require + tpl_attached: tpl /= Void + h_attached: h /= Void do template := tpl set_handler (h) + ensure + tpl_aliased: template = tpl end feature -- Access associated_resource: READABLE_STRING_8 - -- Associated resource + -- URI template text of handled resource do Result := template.template end @@ -38,6 +45,9 @@ feature -- Access feature -- Change set_handler (h: like handler) + -- Set `handler' to `h'. + require + h_attached: h /= Void deferred end @@ -59,6 +69,7 @@ feature -- Status end routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER + -- local tpl: URI_TEMPLATE p: READABLE_STRING_32 @@ -88,13 +99,21 @@ feature -- Status feature {NONE} -- Execution execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute handler `h' with `req' and `res' for Current mapping + -- Run `h' to execute `req' responding in `res'. + require + h_attached: h /= Void + req_attached: req /= Void + res_attached: res /= Void deferred end feature {NONE} -- Implementation based_uri_template (a_tpl: like template; a_router: WSF_ROUTER): like template + -- Version of `a_tpl' using bas URI of `a_router' + require + a_tpl_attached: a_tpl /= Void + a_router_attached: a_router /= Void do if attached a_router.base_url as l_base_url then Result := a_tpl.duplicate @@ -102,6 +121,8 @@ feature {NONE} -- Implementation else Result := a_tpl end + ensure + based_uri_template_attached: Result /= Void end note diff --git a/library/server/wsf/router/wsf_request_methods.e b/library/server/wsf/router/wsf_request_methods.e index a2af35c3..b321240e 100644 --- a/library/server/wsf/router/wsf_request_methods.e +++ b/library/server/wsf/router/wsf_request_methods.e @@ -55,17 +55,26 @@ feature {NONE} -- Initialization end make (n: INTEGER) + -- Initialize with capacity for `n' methods. + require + valid_number_of_items: n >= 0 do create methods.make (n) end make_from_iterable (v: ITERABLE [READABLE_STRING_8]) + -- Initialize for all methods named by `v'. + require + v_all_methods_attached: v /= Void and then across v as c all c.item /= Void end do make (1) add_methods (v) end make_from_string (v: READABLE_STRING_8) + -- Initialize from comma-separated methods named in `v'. + require + v_attached: v /= Void do make_from_iterable (v.split (',')) end @@ -83,6 +92,7 @@ feature -- Status report has (a_method: READABLE_STRING_8): BOOLEAN -- Has `a_method' enabled? require + a_method_attached: a_method /= Void a_method_is_uppercase: a_method.same_string (a_method.as_upper) do -- First look for string object itself, @@ -95,67 +105,71 @@ feature -- Status report end has_some_of (a_methods: WSF_REQUEST_METHODS): BOOLEAN - -- Has any methods from `a_methods' enabled? + -- Have any methods from `a_methods' been enabled? + require + a_methods_attached: a_methods /= Void do Result := across a_methods as c some has (c.item) end end has_all_of (a_methods: WSF_REQUEST_METHODS): BOOLEAN - -- Has all methods from `a_methods' enabled? + -- Have all methods from `a_methods' been enabled? + require + a_methods_attached: a_methods /= Void do Result := across a_methods as c all has (c.item) end end has_method_get: BOOLEAN - -- Has method GET enabled? + -- Has method GET been enabled? do Result := has (method_get) end has_method_post: BOOLEAN - -- Has method POST enabled? + -- Has method POST been enabled? do Result := has (method_post) end has_method_put: BOOLEAN - -- Has method PUT enabled? + -- Has method PUT been enabled? do Result := has (method_put) end has_method_delete: BOOLEAN - -- Has method DELETE enabled? + -- Has method DELETE been enabled? do Result := has (method_delete) end has_method_options: BOOLEAN - -- Has method OPTIONS enabled? + -- Has method OPTIONS been enabled? do Result := has (method_options) end has_method_head: BOOLEAN - -- Has method HEAD enabled? + -- Has method HEAD been enabled? do Result := has (method_head) end has_method_trace: BOOLEAN - -- Has method TRACE enabled? + -- Has method TRACE been enabled? do Result := has (method_trace) end has_method_connect: BOOLEAN - -- Has method CONNECT enabled? + -- Has method CONNECT been enabled? do Result := has (method_connect) end has_method_patch: BOOLEAN - -- Has method PATCH enabled? + -- Has method PATCH been enabled? do Result := has (method_patch) end @@ -384,6 +398,7 @@ feature -- Element change disable_custom (m: READABLE_STRING_8) require is_not_locked: not is_locked + m_attached: m /= Void not_blank: not across m as mc some mc.item.is_space end custom_enabled: has (m.as_upper) do @@ -404,13 +419,17 @@ feature -- Access feature {WSF_REQUEST_METHODS} -- Implementation add_methods (lst: ITERABLE [READABLE_STRING_8]) - -- Enable methods from `lst' + -- Enable methods from `lst'. + require + lst_all_attached: lst /= Void and then across lst as c all c.item /= Void end do if not is_locked then across lst as c loop - add_method_using_constant (c.item) + if not c.item.is_empty and not has (c.item) then + add_method_using_constant (c.item) + end end end end @@ -418,7 +437,11 @@ feature {WSF_REQUEST_METHODS} -- Implementation feature {NONE} -- Implementation add_method_using_constant (v: READABLE_STRING_8) - -- Add method `v' using method_* constant + -- Add method `v' using method_* constant. + require + v_attached: v /= Void + v_not_empty: not v.is_empty + new_method: not has (v) do if v.is_case_insensitive_equal (method_get) then enable_get @@ -446,7 +469,10 @@ feature {NONE} -- Implementation end prune_method (v: READABLE_STRING_8) + -- Remove method named `v' from `Current'. + -- Does nothing if `Current' `is_locked'. require + v_attached: v /= Void is_upper_case: v.same_string (v.as_upper) local m: READABLE_STRING_8 @@ -468,10 +494,12 @@ feature {NONE} -- Implementation end invariant + + methods_attached: methods /= Void methods_are_uppercase: across methods as c all c.item.same_string (c.item.as_upper) end ;note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e index a91d45a9..5f2c3499 100644 --- a/library/server/wsf/router/wsf_routed_service.e +++ b/library/server/wsf/router/wsf_routed_service.e @@ -36,7 +36,10 @@ feature -- Execution execute (req: WSF_REQUEST; res: WSF_RESPONSE) -- Dispatch the request - -- and if you dispatch is found, execute the default procedure `execute_default' + -- and if handler is not found, execute the default procedure `execute_default'. + require + req_attached: req /= Void + res_attached: res /= Void do if attached router.dispatch_and_return_handler (req, res) as p then -- executed @@ -46,7 +49,10 @@ feature -- Execution end execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Default procedure + -- Dispatch requests without a matching handler. + require + req_attached: req /= Void + res_attached: res /= Void local msg: WSF_DEFAULT_ROUTER_RESPONSE do @@ -62,7 +68,7 @@ feature -- Access -- and associated request methods ;note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e index f25c8578..08a9c965 100644 --- a/library/server/wsf/router/wsf_router.e +++ b/library/server/wsf/router/wsf_router.e @@ -23,26 +23,40 @@ create feature {NONE} -- Initialization make (n: INTEGER) - -- Create the router with a capacity of `n' mappings + -- Create the router with a capacity of `n' mappings. + require + valid_number_of_items: n >= 0 do - create mappings.make (n) initialize (n) + ensure + no_handler_set: count = 0 end make_with_base_url (n: INTEGER; a_base_url: like base_url) -- Make router allocated for at least `n' maps, -- and use `a_base_url' as `base_url' --| This avoids prefixing all the resource string. + require + valid_number_of_items: n >= 0 + a_valid_base_url: (a_base_url /= Void and then a_base_url.is_empty) implies (a_base_url.starts_with ("/") and not a_base_url.ends_with ("/")) do make (n) + check + no_handler_set: count = 0 + -- ensured by `make' + end set_base_url (a_base_url) end initialize (n: INTEGER) - -- Initialize router + -- Initialize router. + require + valid_number_of_items: n >= 0 do create mappings.make (n) create pre_execution_actions + ensure + no_handler_set: count = 0 end mappings: ARRAYED_LIST [WSF_ROUTER_ITEM] @@ -51,13 +65,17 @@ feature {NONE} -- Initialization feature -- Mapping map (a_mapping: WSF_ROUTER_MAPPING) - -- Map `a_mapping' + -- Map `a_mapping'. + require + a_mapping_attached: a_mapping /= Void do map_with_request_methods (a_mapping, Void) end map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) - -- Map `a_mapping' for request methods `rqst_methods' + -- Map `a_mapping' for request methods `rqst_methods'. + require + a_mapping_attached: a_mapping /= Void do debug ("router") -- Display conflict in mapping @@ -76,7 +94,10 @@ feature -- Mapping feature -- Mapping handler handle (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY) - -- Map the mapping created by factory `f' for resource `a_resource' + -- Map the mapping created by factory `f' for resource `a_resource'. + require + a_resource_attached: a_resource /= Void + f_attached: f /= Void do handle_with_request_methods (a_resource, f, Void) end @@ -84,6 +105,9 @@ feature -- Mapping handler handle_with_request_methods (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map the mapping created by factory `f' for resource `a_resource' -- and only for request methods `rqst_methods' + require + a_resource_attached: a_resource /= Void + f_attached: f /= Void do map_with_request_methods (f.new_mapping (a_resource), rqst_methods) end @@ -94,9 +118,14 @@ feature -- Access -- `dispatch' set `is_dispatched' to True -- if mapping was found, and associated handler executed +feature -- Basic operations + dispatch (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Dispatch request `req' among the `mappings' - -- Set `is_dispatched' if the request were dispatched + -- Dispatch request `req' among the `mappings'. + -- Set `is_dispatched' if the request were dispatched. + require + req_attached: req /= Void + res_attached: res /= Void do if attached dispatch_and_return_handler (req, res) then check is_dispatched: is_dispatched end @@ -106,6 +135,10 @@ feature -- Access dispatch_and_return_handler (req: WSF_REQUEST; res: WSF_RESPONSE): detachable WSF_HANDLER -- Dispatch request `req' among the `mappings' -- And return the associated handler if mapping found and handler executed. + --| Violates CQS + require + req_attached: req /= Void + res_attached: res /= Void local l_req_method: READABLE_STRING_8 head_res: WSF_HEAD_RESPONSE_WRAPPER @@ -126,6 +159,11 @@ feature {NONE} -- Dispatch implementation dispatch_and_return_handler_for_request_method (req: WSF_REQUEST; res: WSF_RESPONSE; a_request_method: READABLE_STRING_8): detachable WSF_HANDLER -- Dispatch request `req' among the `mappings' -- And return the associated handler if mapping found and handler executed. + --| Violates CQS + require + req_attached: req /= Void + res_attached: res /= Void + a_request_method_attached: a_request_method /= Void local m: WSF_ROUTER_MAPPING do @@ -151,6 +189,9 @@ feature {NONE} -- Dispatch implementation feature -- Status report has_item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_REQUEST_METHODS): BOOLEAN + -- Is there a handler for `a_resource' (taking into account `rqst_methods')? + require + a_resource_attached: a_resource /= Void local m: WSF_ROUTER_MAPPING ok: BOOLEAN @@ -178,6 +219,9 @@ feature -- Status report end item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_REQUEST_METHODS): detachable WSF_ROUTER_ITEM + -- Handler and request methods for `a_resource', taking into account `rqst_methods' + require + a_resource_attached: a_resource /= Void local m: WSF_ROUTER_MAPPING ok: BOOLEAN @@ -208,6 +252,8 @@ feature -- Status report allowed_methods_for_request (req: WSF_REQUEST): WSF_REQUEST_METHODS -- Allowed methods for `req' + require + req_attched: req /= Void local m: WSF_ROUTER_MAPPING l_rqsmethods: detachable WSF_REQUEST_METHODS @@ -234,14 +280,18 @@ feature -- Status report feature -- Hook execute_before (a_mapping: WSF_ROUTER_MAPPING) - -- Execute before the handler associated with the matching mapping is executed + -- Execute before the handler associated with `a_mapping' is executed. + require + a_mapping_attached: a_mapping /= Void do pre_execution_actions.call ([a_mapping]) end execute_after (a_mapping: WSF_ROUTER_MAPPING) - -- Execute after the handler associated with the matching mapping is executed + -- Execute after the handler associated with `a_mapping' is executed. --| Could be redefined to add specific hook. + require + a_mapping_attached: a_mapping /= Void do end @@ -291,6 +341,8 @@ feature -- Request methods helper create Result Result.enable_head Result.lock + ensure + methods_head_not_void: Result /= Void end methods_options: WSF_REQUEST_METHODS @@ -298,6 +350,8 @@ feature -- Request methods helper create Result Result.enable_options Result.lock + ensure + methods_options_not_void: Result /= Void end methods_get: WSF_REQUEST_METHODS @@ -305,6 +359,8 @@ feature -- Request methods helper create Result Result.enable_get Result.lock + ensure + methods_get_not_void: Result /= Void end methods_post: WSF_REQUEST_METHODS @@ -312,6 +368,8 @@ feature -- Request methods helper create Result Result.enable_post Result.lock + ensure + methods_post_not_void: Result /= Void end methods_put: WSF_REQUEST_METHODS @@ -319,6 +377,8 @@ feature -- Request methods helper create Result Result.enable_put Result.lock + ensure + methods_put_not_void: Result /= Void end methods_delete: WSF_REQUEST_METHODS @@ -326,6 +386,8 @@ feature -- Request methods helper create Result Result.enable_delete Result.lock + ensure + methods_delete_not_void: Result /= Void end methods_head_get_post: WSF_REQUEST_METHODS @@ -335,6 +397,8 @@ feature -- Request methods helper Result.enable_get Result.enable_post Result.lock + ensure + methods_head_get_post_not_void: Result /= Void end methods_get_put_delete: WSF_REQUEST_METHODS @@ -344,6 +408,8 @@ feature -- Request methods helper Result.enable_put Result.enable_delete Result.lock + ensure + methods_get_put_not_void: Result /= Void end methods_head_get: WSF_REQUEST_METHODS @@ -352,6 +418,8 @@ feature -- Request methods helper Result.enable_head Result.enable_get Result.lock + ensure + methods_head_get_not_void: Result /= Void end methods_get_post: WSF_REQUEST_METHODS @@ -360,6 +428,8 @@ feature -- Request methods helper Result.enable_get Result.enable_post Result.lock + ensure + methods_get_post_not_void: Result /= Void end methods_put_post: WSF_REQUEST_METHODS @@ -368,12 +438,16 @@ feature -- Request methods helper Result.enable_put Result.enable_post Result.lock + ensure + methods_put_post_not_void: Result /= Void end feature {NONE} -- Access: Implementation request_method (req: WSF_REQUEST): READABLE_STRING_8 - -- Request method from `req' to be used in the router implementation. + -- Request method from `req' to be used in the router implementation + require + req_attached: req /= Void local m: READABLE_STRING_8 do @@ -403,6 +477,8 @@ feature {NONE} -- Access: Implementation is_matching_request_methods (a_request_method: READABLE_STRING_8; a_rqst_methods: detachable WSF_REQUEST_METHODS): BOOLEAN -- `a_request_method' is matching `a_rqst_methods' contents + require + a_request_method_attached: a_request_method /= Void do if a_rqst_methods /= Void and then not a_rqst_methods.is_empty then Result := a_rqst_methods.has (a_request_method) @@ -411,8 +487,13 @@ feature {NONE} -- Access: Implementation end end +invariant + + mappings_attached: mappings /= Void + pre_execution_actions_attached: pre_execution_actions /= Void + note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/wsf_router_mapping.e b/library/server/wsf/router/wsf_router_mapping.e index de7ae56e..89f53303 100644 --- a/library/server/wsf/router/wsf_router_mapping.e +++ b/library/server/wsf/router/wsf_router_mapping.e @@ -13,27 +13,36 @@ inherit feature {NONE} -- Initialization make (a_resource: READABLE_STRING_8; h: like handler) - -- Create mapping based on resource `a_resource' and handler `h' + -- Create mapping based on resource `a_resource' and handler `h'. + require + a_resource_attached: a_resource /= Void + h_attached: h /= Void deferred end feature -- Access associated_resource: READABLE_STRING_8 - -- Associated resource + -- Name (URI, or URI template or regular expression or ...) of handled resource deferred + ensure + assciated_resource_not_void: Result /= Void end handler: WSF_HANDLER - -- Handler associated with Current mapping. + -- Handler associated with `Current' mapping deferred + ensure + handler_attached: Result /= Void end feature -- Documentation description: READABLE_STRING_32 - -- Short description of associated mapping. + -- Short description of associated mapping deferred + ensure + description_attached: Result /= Void end feature -- Status report @@ -47,25 +56,36 @@ feature -- Status report feature -- Status is_mapping (req: WSF_REQUEST; a_router: WSF_ROUTER): BOOLEAN - -- Does Current accept `req'? + -- Does `Current' accept `req' when using `a_router'? + require + req_attached: req /= Void + a_router_attached: a_router /= Void deferred end routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER - -- Return the handler if Current matches the request `req'. + -- Handler when `Current' matches the request `req' + require + req_attached: req /= Void + res_attached: res /= Void + a_router_attached: a_router /= Void deferred end feature -- Helper path_from_request (req: WSF_REQUEST): READABLE_STRING_32 - -- Path used by Current to check that Current mapping matches request `req'. + -- Path used by `Current' to check that mapping matches request `req' + require + req_attached: req /= Void do Result := req.path_info + ensure + path_from_request_attached: Result /= Void end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router/wsf_router_mapping_factory.e b/library/server/wsf/router/wsf_router_mapping_factory.e index 5d4e3d4e..88eac0dd 100644 --- a/library/server/wsf/router/wsf_router_mapping_factory.e +++ b/library/server/wsf/router/wsf_router_mapping_factory.e @@ -14,6 +14,8 @@ feature {WSF_ROUTER} -- Mapping new_mapping (a_uri: READABLE_STRING_8): WSF_ROUTER_MAPPING -- New mapping object + require + a_uri_attached: a_uri /= Void deferred ensure Result_attached: Result /= Void diff --git a/library/server/wsf/session/wsf_fs_session_manager.e b/library/server/wsf/session/wsf_fs_session_manager.e index 8a00f904..260607a1 100644 --- a/library/server/wsf/session/wsf_fs_session_manager.e +++ b/library/server/wsf/session/wsf_fs_session_manager.e @@ -157,4 +157,14 @@ feature {NONE} -- Implementation Result := fn.string end +note + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/server/wsf/session/wsf_session.e b/library/server/wsf/session/wsf_session.e index eca5db08..52a7f7aa 100644 --- a/library/server/wsf/session/wsf_session.e +++ b/library/server/wsf/session/wsf_session.e @@ -78,12 +78,12 @@ feature -- Control deferred end - apply_to (h: HTTP_HEADER; a_request: WSF_REQUEST; a_path: detachable READABLE_STRING_8) + apply_to (h: HTTP_HEADER; req: WSF_REQUEST; a_path: detachable READABLE_STRING_8) deferred end note - copyright: "Copyright (c) 1984-2012, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/session/wsf_session_manager.e b/library/server/wsf/session/wsf_session_manager.e index 7d08073f..c116de1e 100644 --- a/library/server/wsf/session/wsf_session_manager.e +++ b/library/server/wsf/session/wsf_session_manager.e @@ -27,4 +27,14 @@ feature -- Persistence deferred end +note + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/server/wsf/src/request/value/wsf_table.e b/library/server/wsf/src/request/value/wsf_table.e index 8b74ff98..51d12e19 100644 --- a/library/server/wsf/src/request/value/wsf_table.e +++ b/library/server/wsf/src/request/value/wsf_table.e @@ -58,11 +58,11 @@ feature -- Access end end - values: HASH_TABLE [WSF_VALUE, READABLE_STRING_32] + values: HASH_TABLE [WSF_VALUE, STRING_32] - value (k: READABLE_STRING_32): detachable WSF_VALUE + value (k: READABLE_STRING_GENERAL): detachable WSF_VALUE do - Result := values.item (k) + Result := values.item (k.to_string_32) end count: INTEGER @@ -169,11 +169,11 @@ feature -- Conversion feature -- Element change - add_value (a_value: WSF_VALUE; k: READABLE_STRING_32) + add_value (a_value: WSF_VALUE; k: READABLE_STRING_GENERAL) require same_name: a_value.name.same_string (name) or else (a_value.name.starts_with (name) and then a_value.name.item (name.count + 1) = '[') do - values.force (a_value, k) + values.force (a_value, k.to_string_32) end feature -- Traversing @@ -217,7 +217,7 @@ feature -- Visitor end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/wsf_head_response_wrapper.e b/library/server/wsf/src/wsf_head_response_wrapper.e index 4575b317..fa894143 100644 --- a/library/server/wsf/src/wsf_head_response_wrapper.e +++ b/library/server/wsf/src/wsf_head_response_wrapper.e @@ -27,6 +27,9 @@ create feature {NONE} -- Initialization make_from_response (res: WSF_RESPONSE) + -- Initialize from `res' (assumed to be a GET response). + require + res_attached: res /= Void do wsf_response := res make_from_wgi (res.wgi_response) @@ -65,10 +68,12 @@ feature -- Output operation end invariant + transfered_content_length_is_zero: transfered_content_length = 0 + wsf_response_attached: wsf_response /= Void note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e index 0381c8a6..bc755715 100644 --- a/library/server/wsf/src/wsf_request.e +++ b/library/server/wsf/src/wsf_request.e @@ -411,6 +411,48 @@ feature -- Access: global variables Result.keep_head (n - 1) end + table_item (a_name: READABLE_STRING_GENERAL; f: detachable FUNCTION [ANY, TUPLE [READABLE_STRING_GENERAL], detachable WSF_VALUE]): detachable WSF_VALUE + -- Return value associated with table for flat name `a_name'. + -- Use function `f' to get the item, this could be agent of `form_parameter' or `query_parameter', ... + -- By default, this uses `items' + -- For instance "foo[bar]" will return item "bar" from table item "foo" if it exists. + -- Note: we could add this flexible behavior directly to `query_parameter' and related .. + local + p,q: INTEGER + n,k: READABLE_STRING_GENERAL + v: like table_item + val: detachable WSF_VALUE + do + if f /= Void then + Result := f.item ([a_name]) + else + Result := item (a_name) + end + if Result = Void then + p := a_name.index_of_code (91, 1) -- 91 '[' + if p > 0 then + q := a_name.index_of_code (93, p + 1) -- 93 ']' + if q > p then + n := a_name.substring (1, p - 1) + k := a_name.substring (p + 1, q - 1) + + if f /= Void then + val := f.item ([n]) + else + val := item (n) + end + if attached {WSF_TABLE} val as tb then + v := tb.value (k) + if q = a_name.count then + Result := v + else + end + end + end + end + end + end + feature -- Helpers: global variables items_as_string_items: ITERABLE [TUPLE [name: READABLE_STRING_32; value: detachable READABLE_STRING_32]]