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 ("
")
+ 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 ("
")
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 ("[
-
- ]")
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]]