Merge remote-tracking branch 'upstream/master' into cors

This commit is contained in:
Olivier Ligot
2013-03-15 14:54:43 +01:00
73 changed files with 3203 additions and 1023 deletions

View File

@@ -13,13 +13,12 @@
<setting name="exception_trace" value="true"/> <setting name="exception_trace" value="true"/>
<setting name="concurrency" value="thread"/> <setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="default_nino" location="..\..\..\library\server\wsf\default\nino-safe.ecf"/>
<library name="encoder" location="..\..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/> <library name="encoder" location="..\..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="http" location="..\..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/> <library name="http" location="..\..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
<library name="nino" location="..\..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/> <library name="openid" location="..\..\..\library\security\openid\consumer\openid-safe.ecf" readonly="false"/>
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/> <library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/> <library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="uri_template" location="..\..\..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/> <library name="uri_template" location="..\..\..\library\text\parser\uri_template\uri_template-safe.ecf"/>
<library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid-safe.ecf"/> <library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid-safe.ecf"/>
<library name="wsf" location="..\..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/> <library name="wsf" location="..\..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_session" location="..\..\..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/> <library name="wsf_session" location="..\..\..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/>

View File

@@ -14,14 +14,13 @@
<setting name="exception_trace" value="true"/> <setting name="exception_trace" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/> <library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="default_nino" location="..\..\..\library\server\wsf\default\nino.ecf"/>
<library name="encoder" location="..\..\..\library\text\encoder\encoder.ecf" readonly="false"/> <library name="encoder" location="..\..\..\library\text\encoder\encoder.ecf" readonly="false"/>
<library name="http" location="..\..\..\library\network\protocol\http\http.ecf" readonly="false"/> <library name="http" location="..\..\..\library\network\protocol\http\http.ecf" readonly="false"/>
<library name="nino" location="..\..\..\library\server\ewsgi\connectors\nino\nino.ecf"/> <library name="openid" location="..\..\..\library\security\openid\consumer\openid.ecf" />
<library name="process" location="$ISE_LIBRARY\library\process\process.ecf"/> <library name="process" location="$ISE_LIBRARY\library\process\process.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/> <library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<library name="uri_template" location="..\..\..\library\text\parser\uri_template\uri_template.ecf" readonly="false"/>
<library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid.ecf"/> <library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid.ecf"/>
<library name="uri_template" location="..\..\..\library\text\parser\uri_template\uri_template.ecf"/>
<library name="wsf" location="..\..\..\library\server\wsf\wsf.ecf" readonly="false"/> <library name="wsf" location="..\..\..\library\server\wsf\wsf.ecf" readonly="false"/>
<library name="wsf_session" location="..\..\..\library\server\wsf\wsf_session.ecf" readonly="false"/> <library name="wsf_session" location="..\..\..\library\server\wsf\wsf_session.ecf" readonly="false"/>
<cluster name="src" location=".\src\" recursive="true"> <cluster name="src" location=".\src\" recursive="true">

View File

@@ -9,6 +9,9 @@ class
inherit inherit
CMS_MODULE CMS_MODULE
redefine
links
end
CMS_HOOK_MENU_ALTER CMS_HOOK_MENU_ALTER
@@ -55,7 +58,7 @@ feature -- Hooks
local local
lnk: CMS_MODULE_LINK lnk: CMS_MODULE_LINK
do do
create Result.make (0) Result := Precursor
create lnk.make ("Date/time demo") create lnk.make ("Date/time demo")
-- lnk.set_callback (agent process_date_time_demo, <<"arg">>) -- lnk.set_callback (agent process_date_time_demo, <<"arg">>)
-- Result["/demo/date/{arg}"] := lnk -- Result["/demo/date/{arg}"] := lnk

View File

@@ -35,9 +35,9 @@ feature -- Execution
set_main_content (s) set_main_content (s)
end end
new_table: CMS_WIDGET_TABLE [READABLE_STRING_8] new_table: CMS_WIDGET_AGENT_TABLE [READABLE_STRING_8]
local local
l_table: CMS_WIDGET_TABLE [READABLE_STRING_8] l_table: CMS_WIDGET_AGENT_TABLE [READABLE_STRING_8]
do do
create l_table.make create l_table.make
l_table.add_css_style ("width: 85%%; border: solid 1px #999; padding: 2px;") l_table.add_css_style ("width: 85%%; border: solid 1px #999; padding: 2px;")

View File

@@ -9,6 +9,9 @@ class
inherit inherit
CMS_MODULE CMS_MODULE
redefine
permissions
end
CMS_HOOK_MENU_ALTER CMS_HOOK_MENU_ALTER
@@ -39,25 +42,19 @@ feature {CMS_SERVICE} -- Registration
feature -- Hooks 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) menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION)
local local
lnk: CMS_LOCAL_LINK lnk: CMS_LOCAL_LINK
do do
create lnk.make ("Shutdown", "/admin/shutdown/") create lnk.make ("Shutdown", "/admin/shutdown/")
lnk.set_permission_arguments (<<"admin shutdown">>) lnk.set_permission_arguments (<<"shutdown">>)
a_menu_system.management_menu.extend (lnk) 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 end
handle_shutdown (req: WSF_REQUEST; res: WSF_RESPONSE) handle_shutdown (req: WSF_REQUEST; res: WSF_RESPONSE)

View File

@@ -101,6 +101,10 @@ feature -- Access
create {DEBUG_MODULE} m.make create {DEBUG_MODULE} m.make
m.enable m.enable
a_setup.add_module (m) a_setup.add_module (m)
create {OPENID_MODULE} m.make
m.enable
a_setup.add_module (m)
end end
setup_storage (a_setup: CMS_SETUP) setup_storage (a_setup: CMS_SETUP)

View File

@@ -25,20 +25,9 @@ feature {NONE} -- Initialization
make make
configuration_location := a_filename configuration_location := a_filename
import (a_filename) import (a_filename)
resolve
analyze analyze
end end
resolve
-- Resolve options related to variable ${..}
do
across
options as c
loop
options.replace (resolved_string (c.item), c.key)
end
end
analyze analyze
do do
get_root_location get_root_location
@@ -239,15 +228,24 @@ feature {NONE} -- Implementation
loop loop
l := f.last_string l := f.last_string
l.left_adjust l.left_adjust
if not l.is_empty and then l[1] /= '#' then if not l.is_empty then
p := l.index_of ('=', 1) if l[1] = '#' then
if p > 1 then -- commented line
v := l.substring (p + 1, l.count) else
l.keep_head (p - 1) p := l.index_of ('=', 1)
v.left_adjust if p > 1 then
v.right_adjust v := l.substring (p + 1, l.count)
l.right_adjust l.keep_head (p - 1)
set_option (l.as_lower, v) 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
end end
f.read_line f.read_line

View File

@@ -637,6 +637,8 @@ feature {NONE} -- Implementation
set_session_item ("last_access", (create {DATE_TIME}.make_now_utc)) set_session_item ("last_access", (create {DATE_TIME}.make_now_utc))
end end
feature -- Access: Session
session_item (k: READABLE_STRING_GENERAL): detachable ANY session_item (k: READABLE_STRING_GENERAL): detachable ANY
do do
Result := controller.session.item (k) Result := controller.session.item (k)

View File

@@ -81,10 +81,18 @@ feature {NONE} -- Initialization
has_no_user: not storage.has_user has_no_user: not storage.has_user
local local
u: CMS_USER u: CMS_USER
ur: CMS_USER_ROLE
do do
create u.make_new ("admin") create u.make_new ("admin")
u.set_password ("istrator") u.set_password ("istrator")
storage.save_user (u) 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 end
initialize_mailer initialize_mailer
@@ -159,7 +167,9 @@ feature -- Hook: menu_alter
create lst.make (1) create lst.make (1)
menu_alter_hooks := lst menu_alter_hooks := lst
end end
lst.force (h) if not lst.has (h) then
lst.force (h)
end
end end
menu_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_MENU_ALTER] menu_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_MENU_ALTER]
@@ -186,18 +196,20 @@ feature -- Hook: form_alter
create lst.make (1) create lst.make (1)
form_alter_hooks := lst form_alter_hooks := lst
end end
lst.force (h) if not lst.has (h) then
lst.force (h)
end
end end
form_alter_hooks: detachable ARRAYED_LIST [CMS_HOOK_FORM_ALTER] 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 do
if attached form_alter_hooks as lst then if attached form_alter_hooks as lst then
across across
lst as c lst as c
loop loop
c.item.form_alter (f, a_execution) c.item.form_alter (f, a_form_data, a_execution)
end end
end end
end end
@@ -213,7 +225,9 @@ feature -- Hook: block
create lst.make (1) create lst.make (1)
block_hooks := lst block_hooks := lst
end end
lst.force (h) if not lst.has (h) then
lst.force (h)
end
end end
block_hooks: detachable ARRAYED_LIST [CMS_HOOK_BLOCK] block_hooks: detachable ARRAYED_LIST [CMS_HOOK_BLOCK]

View File

@@ -3,7 +3,7 @@ note
Summary description for {CMS_HOOK_AUTO_REGISTER}. Summary description for {CMS_HOOK_AUTO_REGISTER}.
When inheriting from this class, the declared hooks are automatically When inheriting from this class, the declared hooks are automatically
registered, otherwise, each descendant has to add it to the cms service registered, otherwise, each descendant has to add it to the cms service
itself. itself.
]" ]"
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
@@ -24,6 +24,10 @@ feature -- Hook
if attached {CMS_HOOK_BLOCK} Current as h_block then if attached {CMS_HOOK_BLOCK} Current as h_block then
a_service.add_block_hook (h_block) a_service.add_block_hook (h_block)
end end
if attached {CMS_HOOK_FORM_ALTER} Current as h_block then
a_service.add_form_alter_hook (h_block)
end
end end
end end

View File

@@ -12,7 +12,7 @@ inherit
feature -- Hook 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 deferred
end end

View File

@@ -16,7 +16,8 @@ create
convert convert
make_from_manifest ({ ARRAY [TUPLE [key: STRING; value: detachable ANY]], 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 feature {NONE} -- Initialization

View File

@@ -63,6 +63,41 @@ feature -- Access
end end
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 feature -- Status report
has_id: BOOLEAN has_id: BOOLEAN

View File

@@ -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

View File

@@ -45,6 +45,7 @@ feature -- Conversion
i: INTEGER i: INTEGER
n: INTEGER n: INTEGER
in_tag: BOOLEAN in_tag: BOOLEAN
t: READABLE_STRING_8
p1, p2: INTEGER p1, p2: INTEGER
do do
create l_new.make (a_text.count) create l_new.make (a_text.count)
@@ -75,7 +76,9 @@ feature -- Conversion
else else
i := a_text.index_of ('<', p2 + 1) i := a_text.index_of ('<', p2 + 1)
end end
if i > 0 then if i = 0 then
p1 := p2 + 1
else
l_new.append (a_text.substring (p2 + 1, i - 1)) l_new.append (a_text.substring (p2 + 1, i - 1))
end end
end end

View File

@@ -8,7 +8,7 @@ class
CMS_FORM CMS_FORM
inherit inherit
ITERABLE [CMS_FORM_ITEM] CMS_FORM_COMPOSITE
create create
make make
@@ -19,10 +19,11 @@ feature {NONE} -- Initialization
do do
action := a_action action := a_action
id := a_id id := a_id
initialize_with_count (10)
create html_classes.make (2) create html_classes.make (2)
create items.make (10)
set_method_post set_method_post
create validation_actions
create submit_actions
end end
feature -- Access feature -- Access
@@ -33,11 +34,6 @@ feature -- Access
id: READABLE_STRING_8 id: READABLE_STRING_8
-- Id of the form -- Id of the form
count: INTEGER
do
Result := items.count
end
is_get_method: BOOLEAN is_get_method: BOOLEAN
do do
Result := method.same_string ("GET") Result := method.same_string ("GET")
@@ -52,14 +48,42 @@ feature -- Access
-- Form's method -- Form's method
--| GET or POST --| 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 feature -- Validation
validation_action: detachable PROCEDURE [ANY, TUPLE [CMS_FORM_DATA]] validation_actions: ACTION_SEQUENCE [TUPLE [CMS_FORM_DATA]]
-- Procedure to validate the data -- Procedure to validate the data
-- report error if not valid -- report error if not valid
-- submit_callbacks_actions: HASH_TABLE [PROCEDURE [ANY, TUPLE [CMS_FORM_DATA]], STRING] submit_actions: ACTION_SEQUENCE [TUPLE [CMS_FORM_DATA]]
-- -- Submit callbacks indexed by submit names -- Submit actions
feature -- Element change feature -- Element change
@@ -73,141 +97,10 @@ feature -- Element change
method := "POST" method := "POST"
end 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 feature -- Optional
html_classes: ARRAYED_LIST [STRING_8] 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 feature -- Conversion
append_to_html (a_theme: CMS_THEME; a_html: STRING_8) append_to_html (a_theme: CMS_THEME; a_html: STRING_8)
@@ -242,11 +135,4 @@ feature -- Conversion
append_to_html (a_theme, Result) append_to_html (a_theme, Result)
end end
feature {NONE} -- Implementation
items: ARRAYED_LIST [CMS_FORM_ITEM]
-- name => item
invariant
end end

View File

@@ -8,103 +8,16 @@ class
CMS_FORM_CHECKBOX_INPUT CMS_FORM_CHECKBOX_INPUT
inherit inherit
CMS_FORM_INPUT CMS_FORM_SELECTABLE_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
create create
make, make,
make_with_text make_with_value
feature -- Access feature -- Access
checked: BOOLEAN
-- Current <input> element should be preselected when the page loads
input_type: STRING = "checkbox" 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 invariant
end end

View File

@@ -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

View File

@@ -10,7 +10,7 @@ class
inherit inherit
TABLE_ITERABLE [detachable WSF_VALUE, READABLE_STRING_8] TABLE_ITERABLE [detachable WSF_VALUE, READABLE_STRING_8]
create create {CMS_FORM}
make make
feature {NONE} -- Initialization feature {NONE} -- Initialization
@@ -21,7 +21,6 @@ feature {NONE} -- Initialization
form := a_form form := a_form
create items.make (a_form.count) create items.make (a_form.count)
get_items (req) get_items (req)
validate
end end
feature -- Access feature -- Access
@@ -37,6 +36,14 @@ feature -- Status
feature -- Access 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 item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
do do
Result := items.item (a_name.as_string_8) Result := items.item (a_name.as_string_8)
@@ -49,11 +56,49 @@ feature -- Access
end end
end end
-- table_item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE table_item (a_name: READABLE_STRING_GENERAL): detachable WSF_TABLE
-- do local
-- FIXME s,k: READABLE_STRING_GENERAL
-- Result := items.item (a_name.as_string_8 + "[]") p,q: INTEGER
-- end 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 integer_item (a_name: READABLE_STRING_GENERAL): INTEGER
do do
@@ -70,17 +115,33 @@ feature -- Access
feature -- Basic operation feature -- Basic operation
submit
require
is_valid: is_valid
do
form.submit_actions.call ([Current])
end
validate validate
do do
across across
form as f form as f
loop loop
if attached {CMS_FORM_FIELD} f.item as l_field then validate_item (f.item)
l_field.validate (Current)
end
end end
if attached form.validation_action as act then form.validation_actions.call ([Current])
act.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
end end
@@ -121,7 +182,7 @@ feature -- Basic operation
feature {NONE} -- Implementation: apply 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 local
do do
if attached {CMS_FORM_FIELD} i as l_field then if attached {CMS_FORM_FIELD} i as l_field then
@@ -130,7 +191,7 @@ feature {NONE} -- Implementation: apply
l_field.set_value (a_value) l_field.set_value (a_value)
end end
end end
elseif attached {ITERABLE [CMS_FORM_ITEM]} i as l_set then elseif attached {ITERABLE [CMS_WIDGET]} i as l_set then
across across
l_set as c l_set as c
loop loop
@@ -170,14 +231,14 @@ feature {NONE} -- Implementation
get_form_items (req, form) get_form_items (req, form)
end end
get_form_items (req: WSF_REQUEST; lst: ITERABLE [CMS_FORM_ITEM]) get_form_items (req: WSF_REQUEST; lst: ITERABLE [CMS_WIDGET])
do do
across across
lst as c lst as c
loop loop
if attached {CMS_FORM_FIELD} c.item as l_field then if attached {CMS_FORM_FIELD} c.item as l_field then
get_form_field_item (req, l_field, l_field.name) 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) get_form_items (req, l_set)
end end
end end
@@ -186,49 +247,24 @@ feature {NONE} -- Implementation
get_form_field_item (req: WSF_REQUEST; i: CMS_FORM_FIELD; n: READABLE_STRING_8) get_form_field_item (req: WSF_REQUEST; i: CMS_FORM_FIELD; n: READABLE_STRING_8)
local local
v: detachable WSF_VALUE v: detachable WSF_VALUE
-- tb: detachable WSF_TABLE
do do
if form.is_post_method then if form.is_post_method then
v := req.form_parameter (n) v := req.table_item (n, agent req.form_parameter)
else else
v := req.query_parameter (n) v := req.table_item (n, agent req.query_parameter)
end end
if v = Void and then n.ends_with_general ("[]") then if v = Void then
if form.is_post_method then if n.ends_with_general ("[]") then
v := req.form_parameter (n.substring (1, n.count - 2)) if form.is_post_method then
else v := req.form_parameter (n.substring (1, n.count - 2))
v := req.query_parameter (n.substring (1, n.count - 2)) else
v := req.query_parameter (n.substring (1, n.count - 2))
end
end end
end end
if i.is_required and (v = Void or else v.is_empty) then if i.is_required and (v = Void or else v.is_empty) then
add_error (i, "Field %"<em>" + n + "</em>%" is required") add_error (i, "Field %"<em>" + n + "</em>%" is required")
else 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) items.force (v, n)
end end
end end
@@ -247,8 +283,45 @@ feature {NONE} -- Implementation
items: HASH_TABLE [detachable WSF_VALUE, READABLE_STRING_8] 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 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]] errors: detachable ARRAYED_LIST [TUPLE [field: detachable CMS_FORM_FIELD; message: detachable READABLE_STRING_8]]
invariant invariant

View File

@@ -10,7 +10,7 @@ class
inherit inherit
CMS_FORM_ITEM CMS_FORM_ITEM
ITERABLE [CMS_FORM_ITEM] CMS_FORM_COMPOSITE
WITH_CSS_ID WITH_CSS_ID
@@ -18,14 +18,16 @@ create
make, make,
make_with_item, make_with_item,
make_with_items, make_with_items,
make_with_text make_with_text,
make_with_text_and_css_id,
make_with_item_and_css_id
feature {NONE} -- Initialization feature {NONE} -- Initialization
make make
-- Initialize `Current'. -- Initialize `Current'.
do do
create items.make (0) initialize_with_count (0)
end end
make_with_text (s: READABLE_STRING_8) make_with_text (s: READABLE_STRING_8)
@@ -33,15 +35,15 @@ feature {NONE} -- Initialization
make_with_item (create {CMS_FORM_RAW_TEXT}.make (s)) make_with_item (create {CMS_FORM_RAW_TEXT}.make (s))
end end
make_with_item (i: CMS_FORM_ITEM) make_with_item (i: CMS_WIDGET)
do do
create items.make (1) initialize_with_count (1)
extend (i) extend (i)
end end
make_with_items (it: ITERABLE [CMS_FORM_ITEM]) make_with_items (it: ITERABLE [CMS_WIDGET])
do do
create items.make (2) initialize_with_count (2)
across across
it as c it as c
loop loop
@@ -49,19 +51,16 @@ feature {NONE} -- Initialization
end end
end end
feature -- Access make_with_item_and_css_id (i: CMS_WIDGET; a_css_id: READABLE_STRING_8)
new_cursor: ITERATION_CURSOR [CMS_FORM_ITEM]
-- Fresh cursor associated with current structure
do do
Result := items.new_cursor make_with_item (i)
set_css_id (a_css_id)
end end
feature -- Change make_with_text_and_css_id (s: READABLE_STRING_8; a_css_id: READABLE_STRING_8)
extend (i: CMS_FORM_ITEM)
do do
items.force (i) make_with_text (s)
set_css_id (a_css_id)
end end
feature -- Conversion feature -- Conversion
@@ -82,8 +81,4 @@ feature -- Conversion
a_html.append ("%N</div>%N") a_html.append ("%N</div>%N")
end end
feature {NONE} -- Implementation
items: ARRAYED_LIST [CMS_FORM_ITEM]
end end

View File

@@ -10,7 +10,7 @@ class
inherit inherit
CMS_FORM_ITEM CMS_FORM_ITEM
ITERABLE [CMS_FORM_ITEM] CMS_FORM_COMPOSITE
WITH_CSS_ID WITH_CSS_ID
@@ -22,7 +22,7 @@ feature {NONE} -- Initialization
make make
-- Initialize `Current'. -- Initialize `Current'.
do do
create items.make (0) initialize_with_count (0)
end end
feature -- Access feature -- Access
@@ -31,14 +31,6 @@ feature -- Access
is_collapsible: BOOLEAN 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 feature -- Change
set_legend (v: like legend) set_legend (v: like legend)
@@ -46,21 +38,6 @@ feature -- Change
legend := v legend := v
end 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) set_collapsible (b: BOOLEAN)
do do
is_collapsible := b is_collapsible := b
@@ -101,8 +78,4 @@ feature -- Conversion
a_html.append ("%N</fieldset>%N") a_html.append ("%N</fieldset>%N")
end end
feature {NONE} -- Implementation
items: ARRAYED_LIST [CMS_FORM_ITEM]
end end

View File

@@ -8,20 +8,10 @@ deferred class
CMS_FORM_ITEM CMS_FORM_ITEM
inherit inherit
CMS_WIDGET
WITH_CSS_CLASS WITH_CSS_CLASS
WITH_CSS_STYLE 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 end

View File

@@ -8,54 +8,16 @@ class
CMS_FORM_RADIO_INPUT CMS_FORM_RADIO_INPUT
inherit inherit
CMS_FORM_INPUT CMS_FORM_SELECTABLE_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
create create
make make,
make_with_value
feature -- Access feature -- Access
checked: BOOLEAN
-- Current <input> element should be preselected when the page loads
input_type: STRING = "radio" 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 invariant
end end

View File

@@ -8,7 +8,10 @@ class
CMS_FORM_RAW_TEXT CMS_FORM_RAW_TEXT
inherit inherit
CMS_FORM_ITEM CMS_WIDGET_TEXT
rename
set_text as set_value,
make_with_text as make
redefine redefine
append_to_html append_to_html
end end
@@ -16,24 +19,6 @@ inherit
create create
make 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 feature -- Conversion
append_to_html (a_theme: CMS_THEME; a_html: STRING_8) append_to_html (a_theme: CMS_THEME; a_html: STRING_8)

View File

@@ -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 <input> 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

View File

@@ -17,6 +17,17 @@ feature -- Change
css_classes := Void css_classes := Void
end 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) add_css_class (a_class: READABLE_STRING_8)
require require
is_valid_css_class: is_valid_css_class (a_class) is_valid_css_class: is_valid_css_class (a_class)

View File

@@ -51,7 +51,7 @@ feature -- Status report
Result := attached children as l_children and then not l_children.is_empty Result := attached children as l_children and then not l_children.is_empty
end end
permission_arguments: detachable ITERABLE [STRING] permission_arguments: detachable ITERABLE [READABLE_STRING_8]
children: detachable LIST [CMS_LINK] children: detachable LIST [CMS_LINK]
@@ -106,14 +106,17 @@ feature -- Element change
qs: STRING qs: STRING
do do
create qs.make_from_string (req.path_info) 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) 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 end
set_permission_arguments (args: ITERABLE [STRING]) set_permission_arguments (args: like permission_arguments)
do do
permission_arguments := args permission_arguments := args
end end

View File

@@ -29,6 +29,9 @@ feature -- Execution
if has_permission ("administrate blocks") then if has_permission ("administrate blocks") then
b.append ("<li>" + link ("Blocks", "/admin/blocks/", Void) + "</li>") b.append ("<li>" + link ("Blocks", "/admin/blocks/", Void) + "</li>")
end end
if has_permission ("administrate user-roles") then
b.append ("<li>" + link ("User roles", "/admin/roles/", Void) + "</li>")
end
if has_permission ("administrate users") then if has_permission ("administrate users") then
b.append ("<li>" + link ("Users", "/admin/users/", Void) + "</li>") b.append ("<li>" + link ("Users", "/admin/users/", Void) + "</li>")
end end

View File

@@ -9,6 +9,9 @@ class
inherit inherit
CMS_MODULE CMS_MODULE
redefine
permissions
end
CMS_HOOK_MENU_ALTER CMS_HOOK_MENU_ALTER
@@ -36,6 +39,7 @@ feature {CMS_SERVICE} -- Registration
service := a_service service := a_service
a_service.map_uri ("/admin/", agent handle_admin (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/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/blocks/", agent handle_admin_blocks (a_service, ?, ?))
a_service.map_uri ("/admin/modules/", agent handle_admin_modules (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, ?, ?)) 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) a_menu_system.management_menu.extend (lnk)
end end
links: HASH_TABLE [CMS_MODULE_LINK, STRING] permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION]
-- Link indexed by path
do 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 end
feature -- Handler feature -- Handler
@@ -73,6 +83,11 @@ feature -- Handler
(create {ADMIN_USERS_CMS_EXECUTION}.make (req, res, cms)).execute (create {ADMIN_USERS_CMS_EXECUTION}.make (req, res, cms)).execute
end 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) handle_admin_blocks (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE)
do do
(create {ADMIN_BLOCKS_CMS_EXECUTION}.make (req, res, cms)).execute (create {ADMIN_BLOCKS_CMS_EXECUTION}.make (req, res, cms)).execute

View File

@@ -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 ("<div class=%"denied%">Access denied</div>")
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 ("<li>")
b.append (html_encoded (c.item.name))
b.append ("=")
b.append (html_encoded (c.item.string_representation))
b.append ("</li>")
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 ("<div class=%"denied%">Access denied</div>")
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

View File

@@ -41,17 +41,18 @@ feature -- Hooks
help_text (a_path: STRING): STRING help_text (a_path: STRING): STRING
do do
Result := "" create Result.make_empty
end end
permissions: LIST [TUPLE [title: detachable STRING; description: detachable STRING]] permissions (a_service: CMS_SERVICE): LIST [CMS_PERMISSION]
do do
create {ARRAYED_LIST [like permissions.item]} Result.make (0) create {ARRAYED_SET [CMS_PERMISSION]} Result.make (0)
end end
links: HASH_TABLE [CMS_MODULE_LINK, STRING] links: HASH_TABLE [CMS_MODULE_LINK, STRING]
-- Link indexed by path -- Link indexed by path
deferred do
create Result.make (0)
end end
end end

View File

@@ -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

View File

@@ -36,19 +36,6 @@ feature {CMS_SERVICE} -- Registration
a_service.map_uri_template ("/debug/", agent handle_debug (a_service, ?, ?)) a_service.map_uri_template ("/debug/", agent handle_debug (a_service, ?, ?))
end 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 feature -- Hooks
-- block_list: ITERABLE [like {CMS_BLOCK}.name] -- block_list: ITERABLE [like {CMS_BLOCK}.name]

View File

@@ -6,7 +6,7 @@ class
NODE_ADD_CMS_EXECUTION NODE_ADD_CMS_EXECUTION
inherit inherit
CMS_EXECUTION NODE_CMS_EXECUTION
create create
make make
@@ -19,71 +19,20 @@ feature -- Execution
b: STRING_8 b: STRING_8
f: like edit_form f: like edit_form
fd: detachable CMS_FORM_DATA fd: detachable CMS_FORM_DATA
l_preview: BOOLEAN
l_format: detachable CMS_FORMAT
do do
create b.make_empty create b.make_empty
if attached non_empty_string_path_parameter ("type") as s_type then if attached non_empty_string_path_parameter ("type") as s_type then
if attached service.content_type (s_type) as l_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) 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) set_title ("Create " + l_type.title)
if has_permission ("create " + l_type.name) then if has_permission ("create " + l_type.name) then
if request.is_post_request_method then
if fd /= Void and l_preview then f.validation_actions.extend (agent edit_form_validate (?, b))
b.append ("<strong>Preview</strong><div class=%"preview%">") f.submit_actions.extend (agent edit_form_submit (?, Void, l_type, b))
if attached fd.string_item ("format") as s_format and then attached formats.format (s_format) as f_format then f.process (Current)
l_format := f_format fd := f.last_data
end
if attached fd.string_item ("title") as l_title then
b.append ("<strong>Title:</strong><div class=%"title%">" + html_encoded (l_title) + "</div>")
end
if attached fd.string_item ("body") as l_body then
b.append ("<strong>Body:</strong><div class=%"body%">")
if l_format /= Void then
b.append (l_format.to_html (l_body))
else
b.append (html_encoded (l_body))
end
b.append ("</div>")
end
b.append ("</div>")
end
if fd /= Void and then fd.is_valid and not l_preview then
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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)
end end
f.append_to_html (theme, b)
else else
set_title ("Access denied") set_title ("Access denied")
end end
@@ -109,35 +58,4 @@ feature -- Execution
set_main_content (b) set_main_content (b)
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 ("<br/>")
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 end

View File

@@ -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 ("<strong>Preview</strong><div class=%"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 ("<strong>Title:</strong><div class=%"title%">" + html_encoded (l_title) + "</div>")
end
if attached fd.string_item ("body") as l_body then
b.append ("<strong>Body:</strong><div class=%"body%">")
if l_format /= Void then
b.append (l_format.to_html (l_body))
else
b.append (html_encoded (l_body))
end
b.append ("</div>")
end
b.append ("</div>")
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 ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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 ("<li>" + html_encoded (c.key) + "=")
-- if attached c.item as v then
-- b.append (html_encoded (v.string_representation))
-- end
-- b.append ("</li>")
-- 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 ("<br/>")
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

View File

@@ -6,7 +6,7 @@ class
NODE_EDIT_CMS_EXECUTION NODE_EDIT_CMS_EXECUTION
inherit inherit
CMS_EXECUTION NODE_CMS_EXECUTION
create create
make make
@@ -19,8 +19,6 @@ feature -- Execution
b: STRING_8 b: STRING_8
f: like edit_form f: like edit_form
fd: detachable CMS_FORM_DATA fd: detachable CMS_FORM_DATA
l_preview: BOOLEAN
l_format: detachable CMS_FORMAT
do do
create b.make_empty create b.make_empty
if if
@@ -32,8 +30,10 @@ feature -- Execution
if has_permission ("edit " + l_type.name) then if has_permission ("edit " + l_type.name) then
f := edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type) f := edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
if request.is_post_request_method then if request.is_post_request_method then
create fd.make (request, f) f.validation_actions.extend (agent edit_form_validate (?, b))
l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") f.submit_actions.extend (agent edit_form_submit (?, l_node, l_type, b))
f.process (Current)
fd := f.last_data
end end
set_title ("Edit #" + l_node.id.out) 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 ("View", node_url (l_node)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), 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 f.append_to_html (theme, b)
b.append ("<strong>Preview</strong><div class=%"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 ("<strong>Title:</strong><div class=%"title%">" + html_encoded (l_title) + "</div>")
end
if attached fd.string_item ("body") as l_body then
b.append ("<strong>Body:</strong><div class=%"body%">")
if l_format /= Void then
b.append (l_format.to_html (l_body))
else
b.append (html_encoded (l_body))
end
b.append ("</div>")
end
b.append ("</div>")
end
if fd /= Void and then fd.is_valid and not l_preview then
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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
else else
b.append ("<h1>Access denied</h1>") b.append ("<h1>Access denied</h1>")
end end
@@ -114,35 +67,100 @@ feature -- Execution
set_main_content (b) set_main_content (b)
end end
edit_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_type: CMS_CONTENT_TYPE): CMS_FORM -- edit_form_validate (fd: CMS_FORM_DATA; b: STRING)
local -- local
f: CMS_FORM -- l_preview: BOOLEAN
ts: CMS_FORM_SUBMIT_INPUT -- l_format: detachable CMS_FORMAT
th: CMS_FORM_HIDDEN_INPUT -- do
do -- l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview")
create f.make (a_url, a_name) -- if l_preview then
-- b.append ("<strong>Preview</strong><div class=%"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 ("<strong>Title:</strong><div class=%"title%">" + html_encoded (l_title) + "</div>")
-- end
-- if attached fd.string_item ("body") as l_body then
-- b.append ("<strong>Body:</strong><div class=%"body%">")
-- if l_format /= Void then
-- b.append (l_format.to_html (l_body))
-- else
-- b.append (html_encoded (l_body))
-- end
-- b.append ("</div>")
-- end
-- b.append ("</div>")
-- end
-- end
create th.make ("node-id") -- edit_form_submit (fd: CMS_FORM_DATA; a_node: detachable CMS_NODE; a_type: CMS_CONTENT_TYPE; b: STRING)
if a_node /= Void then -- local
th.set_text_value (a_node.id.out) -- l_preview: BOOLEAN
else -- l_node: detachable CMS_NODE
th.set_text_value ("0") -- s: STRING
end -- do
f.extend (th) -- 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 ("<li>" + html_encoded (c.key) + "=")
-- if attached c.item as v then
-- b.append (html_encoded (v.string_representation))
-- end
-- b.append ("</li>")
-- 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 ("<br/>") -- 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") -- a_type.fill_edit_form (f, a_node)
ts.set_default_value ("Save")
f.extend (ts)
create ts.make ("op") -- f.extend_text ("<br/>")
ts.set_default_value ("Preview")
f.extend (ts)
Result := f -- create ts.make ("op")
end -- ts.set_default_value ("Save")
-- f.extend (ts)
-- create ts.make ("op")
-- ts.set_default_value ("Preview")
-- f.extend (ts)
-- Result := f
-- end
end end

View File

@@ -9,6 +9,9 @@ class
inherit inherit
CMS_MODULE CMS_MODULE
redefine
permissions
end
CMS_HOOK_MENU_ALTER CMS_HOOK_MENU_ALTER
@@ -29,6 +32,20 @@ feature {NONE} -- Initialization
enable enable
end 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 feature {CMS_SERVICE} -- Registration
service: detachable CMS_SERVICE service: detachable CMS_SERVICE
@@ -51,6 +68,7 @@ feature {CMS_SERVICE} -- Registration
a_service.add_menu_alter_hook (Current) a_service.add_menu_alter_hook (Current)
a_service.add_block_hook (Current) a_service.add_block_hook (Current)
end end
feature -- Hooks feature -- Hooks
@@ -76,18 +94,19 @@ feature -- Hooks
menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION) menu_alter (a_menu_system: CMS_MENU_SYSTEM; a_execution: CMS_EXECUTION)
local local
lnk: CMS_LOCAL_LINK lnk: CMS_LOCAL_LINK
perms: detachable ARRAYED_LIST [READABLE_STRING_8]
do do
if a_execution.authenticated then if attached a_execution.service.content_types as lst then
create lnk.make ("Add content", "/node/add/") create perms.make (lst.count)
lnk.set_permission_arguments (<<"authenticated">>) across
a_menu_system.navigation_menu.extend (lnk) lst as c
loop
perms.force ("create " + c.item.name)
end
end end
end create lnk.make ("Add content", "/node/add/")
lnk.set_permission_arguments (perms)
links: HASH_TABLE [CMS_MODULE_LINK, STRING] a_menu_system.navigation_menu.extend (lnk)
-- Link indexed by path
do
create Result.make (0)
end end
handle_node_view (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE) handle_node_view (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE)

View File

@@ -6,7 +6,7 @@ class
NODE_VIEW_CMS_EXECUTION NODE_VIEW_CMS_EXECUTION
inherit inherit
CMS_EXECUTION NODE_CMS_EXECUTION
create create
make make

View File

@@ -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 ("<li>" + c.key + "=" + c.item + "</li>")
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 ("<li>OpenID: " + c.item + "</li>")
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

View File

@@ -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

View File

@@ -20,6 +20,7 @@ feature -- Execution
local local
b: STRING_8 b: STRING_8
u: detachable CMS_USER u: detachable CMS_USER
l_first: BOOLEAN
do do
if attached {WSF_STRING} request.path_parameter ("uid") as p_uid then if attached {WSF_STRING} request.path_parameter ("uid") as p_uid then
if p_uid.is_integer then if p_uid.is_integer then
@@ -43,6 +44,25 @@ feature -- Execution
if attached u.email as l_email then if attached u.email as l_email then
b.append ("<li>Email: <a mailto=%""+ l_email +"%">"+ l_email +"</a></li>") b.append ("<li>Email: <a mailto=%""+ l_email +"%">"+ l_email +"</a></li>")
end end
if has_permission ("administer users") and attached u.roles as u_roles then
b.append ("<li>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 ("</li>")
end
b.append ("<li>Created: "+ u.creation_date.out +"</li>%N") b.append ("<li>Created: "+ u.creation_date.out +"</li>%N")
if attached u.last_login_date as dt then if attached u.last_login_date as dt then
b.append ("<li>Last signed: "+ dt.out +"</li>%N") b.append ("<li>Last signed: "+ dt.out +"</li>%N")
@@ -84,20 +104,23 @@ feature -- Execution
if l_url = Void then if l_url = Void then
l_url := request.script_url ("/user") l_url := request.script_url ("/user")
end end
f := login_form (url ("/user", Void), "login-form", l_url) f := login_form (url ("/user", Void), "user-login", l_url)
service.call_form_alter_hooks (f, Current)
if request.is_request_method ("post") then if request.is_request_method ("post") then
create fd.make (request, f) f.submit_actions.extend (agent on_form_submitted)
if fd.is_valid then f.process (Current)
on_form_submitted (fd) fd := f.last_data
if attached {WSF_STRING} fd.integer_item ("form-destination") as s_dest then else
l_url := request.script_url (s_dest.value) f.prepare (Current)
end
end
end end
if authenticated then 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_redirection (l_url)
set_title ("Login") set_title ("Login")
create b.make_empty create b.make_empty
@@ -106,12 +129,6 @@ feature -- Execution
else else
set_title ("Login") set_title ("Login")
create b.make_empty 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) f.append_to_html (theme, b)
set_main_content (b) set_main_content (b)
end end
@@ -146,6 +163,8 @@ feature -- Execution
ti: CMS_FORM_TEXT_INPUT ti: CMS_FORM_TEXT_INPUT
tp: CMS_FORM_PASSWORD_INPUT tp: CMS_FORM_PASSWORD_INPUT
ts: CMS_FORM_SUBMIT_INPUT ts: CMS_FORM_SUBMIT_INPUT
l_logo: CMS_FORM_RAW_TEXT
d: CMS_FORM_DIV
do do
create Result.make (a_action, a_form_name) create Result.make (a_action, a_form_name)
@@ -153,27 +172,32 @@ feature -- Execution
th.set_default_value (a_destination) th.set_default_value (a_destination)
Result.extend (th) Result.extend (th)
create l_logo.make ("[
<img class="logo" alt="login"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAHiQAAB4kB+XNYvQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAASmSURBVGiB1ZpbaBxVGMd/Mzu5bSRJY6LubmKJl4J9qShdwdpGGxGlharJSwpVVFrUUF+iT1VEUYRgaEGqsa2FGtu8xNtDsBQi5EFBS8UnsYWUtpsmaqppIdkkm+4eH77ZzWazl7lllv7gPOycmXP+/9kzM+d839GUUnjEOqAL2A7cCdSYJWjWx4F5s/wN/AgMAzNedK65NHI38CKwAwiZpcLitUvAlFlGgBPAFadCnBppAQ4DDwNhQHMqwEQBk8A5oAeYsNuAXSP1QD/wFNBqtzOLxIAzQC9ww/JVSimrZbdSalwplVJrT8rsa7dVfVZNHFRKTftgIJdps++SGksNrSDwLbAFqHUxXNwwB/wEPIe8+fJSzEi12cCDgO61OpukgN+RG7qQ74RiRkaApylg4sj4YZLqpgcalwloBvvu7SlUnQJOI6/6VRQy8jHwKkWG04aRMIlUwp7SElTqlVzYMVnslDlgAHgztyLf3e5GPnLleiaKUYto686tyDXSCHwANPkgyilNiMbG7INGzkn9QJvdltdVNnJg43uOVH34x7vMJP6ze1kbovWl9IFsI+uBJ3Ew3QgGaulqXfVvW+Lg+T5msG1EQ7SuBy7DyqH1GTKHulVoQTQDy0YiwKayyHHHJkR7xsgLyBTcFYupRbdN2CWEaM8Y2Yn7qTjHLw4w9s+o22bsoCHa0YEGZE3hmsXkInvP7vHbTBhoMJDlacTu1fs39JJMJQGoq6jLHE+kEuw9u4ejmwdpv6PDI61FiQBdBtCB9eVphv339xas89lMBdCh48FDno+0GZ+GWchAIh0F+f7q15y6fMJSaxPx2IrfPv4zNQbL4Zq8TM5P8Mu/PzvuwSczQZ0SRrzAh2EW9G3lp6Ghaa4/VQXRKbIO9ooqvYqj0UG2NW9fqy7iBiWMhGtaeOT2Ry21NhGPcXV+5QNfpVdxLPoVW5ufcKzSAnEDicUWZFekk12RTkutHTrfx6ELfZnfYuIkW5sfdyPSCvMGEnv1nOpANcc2n+Sx5va1aD6XKQMYBTqx+XXv//MjbqolAOoqGnjtvjcydT6bWAJGDSS0/w4SWbfM5+OfZKIokZrWjJHqQDVfRE+xpWmbt3ILMwUM68B1PBpeNUaQ49EhP02AaL+eXrN/A0RxuSZ5uW0fFXqlW2F2UIj2zMJqEMlPuMJnEyCaB2HZyBSSZLnVOIf5WGRPUXpwkfoqA1cQzcDKuNYEkil6BZvPSjw5x3BsyJGaeHLOyWUK0ZpJ0eUGseuB34B7SrVUpiB2movAQ2Sl5nJnvzeAt4Fpz9R5zzSicUV+Md80fghJFc/6IMous4i2VeM4N4id5i3gASTRE8h3woGN769JoqcISWDM1LaKUqm3MSSXnteMjySRV207BVJvxVaIC+aFpynvMJs1NRQ0AaWTnAtISHIAuOaZNOtcM/veSRETgK0NA91KqUvKvw0Dl8w+Pd0wkC71SqkjSqnYGpqImX3U29HmdFNNCPgUmTGH8GZTzRTwK/A6DpYVbrc53YXkJ55FouJh7G1zmjTLd8CXwF9Ohbg1ks1twPPAM8i/FCT/xrM4csd/QNYSnrwR/wfI5AekDWyX2QAAAABJRU5ErkJggg=="
/>
]"
)
create ti.make (form_username_or_email_name) create ti.make (form_username_or_email_name)
ti.set_label ("Username or email") ti.set_label ("Username or email")
ti.set_is_required (True) ti.set_is_required (True)
Result.extend (ti)
create tp.make (form_password_name) create tp.make (form_password_name)
tp.set_label ("Password") tp.set_label ("Password")
tp.set_is_required (True) tp.set_is_required (True)
tp.set_description (link ("Reset password", "/user/password", Void)) tp.set_description (link ("Reset password", "/user/password", Void))
Result.extend (tp)
Result.extend_text ("[
<img alt="login" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAHiQAAB4kB+XNYvQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAASmSURBVGiB1ZpbaBxVGMd/Mzu5bSRJY6LubmKJl4J9qShdwdpGGxGlharJSwpVVFrUUF+iT1VEUYRgaEGqsa2FGtu8xNtDsBQi5EFBS8UnsYWUtpsmaqppIdkkm+4eH77ZzWazl7lllv7gPOycmXP+/9kzM+d839GUUnjEOqAL2A7cCdSYJWjWx4F5s/wN/AgMAzNedK65NHI38CKwAwiZpcLitUvAlFlGgBPAFadCnBppAQ4DDwNhQHMqwEQBk8A5oAeYsNuAXSP1QD/wFNBqtzOLxIAzQC9ww/JVSimrZbdSalwplVJrT8rsa7dVfVZNHFRKTftgIJdps++SGksNrSDwLbAFqHUxXNwwB/wEPIe8+fJSzEi12cCDgO61OpukgN+RG7qQ74RiRkaApylg4sj4YZLqpgcalwloBvvu7SlUnQJOI6/6VRQy8jHwKkWG04aRMIlUwp7SElTqlVzYMVnslDlgAHgztyLf3e5GPnLleiaKUYto686tyDXSCHwANPkgyilNiMbG7INGzkn9QJvdltdVNnJg43uOVH34x7vMJP6ze1kbovWl9IFsI+uBJ3Ew3QgGaulqXfVvW+Lg+T5msG1EQ7SuBy7DyqH1GTKHulVoQTQDy0YiwKayyHHHJkR7xsgLyBTcFYupRbdN2CWEaM8Y2Yn7qTjHLw4w9s+o22bsoCHa0YEGZE3hmsXkInvP7vHbTBhoMJDlacTu1fs39JJMJQGoq6jLHE+kEuw9u4ejmwdpv6PDI61FiQBdBtCB9eVphv339xas89lMBdCh48FDno+0GZ+GWchAIh0F+f7q15y6fMJSaxPx2IrfPv4zNQbL4Zq8TM5P8Mu/PzvuwSczQZ0SRrzAh2EW9G3lp6Ghaa4/VQXRKbIO9ooqvYqj0UG2NW9fqy7iBiWMhGtaeOT2Ry21NhGPcXV+5QNfpVdxLPoVW5ufcKzSAnEDicUWZFekk12RTkutHTrfx6ELfZnfYuIkW5sfdyPSCvMGEnv1nOpANcc2n+Sx5va1aD6XKQMYBTqx+XXv//MjbqolAOoqGnjtvjcydT6bWAJGDSS0/w4SWbfM5+OfZKIokZrWjJHqQDVfRE+xpWmbt3ILMwUM68B1PBpeNUaQ49EhP02AaL+eXrN/A0RxuSZ5uW0fFXqlW2F2UIj2zMJqEMlPuMJnEyCaB2HZyBSSZLnVOIf5WGRPUXpwkfoqA1cQzcDKuNYEkil6BZvPSjw5x3BsyJGaeHLOyWUK0ZpJ0eUGseuB34B7SrVUpiB2movAQ2Sl5nJnvzeAt4Fpz9R5zzSicUV+Md80fghJFc/6IMous4i2VeM4N4id5i3gASTRE8h3woGN769JoqcISWDM1LaKUqm3MSSXnteMjySRV207BVJvxVaIC+aFpynvMJs1NRQ0AaWTnAtISHIAuOaZNOtcM/veSRETgK0NA91KqUvKvw0Dl8w+Pd0wkC71SqkjSqnYGpqImX3U29HmdFNNCPgUmTGH8GZTzRTwK/A6DpYVbrc53YXkJ55FouJh7G1zmjTLd8CXwF9Ohbg1ks1twPPAM8i/FCT/xrM4csd/QNYSnrwR/wfI5AekDWyX2QAAAABJRU5ErkJggg=="
style="float:right; margin: 5px;"/>
]")
create ts.make ("op") create ts.make ("op")
ts.set_default_value ("Log in") 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 (ts)
Result.extend_text ("<p>Need an account?<br/>" + link ("Sign up now!", "/user/register", Void) + "</p>") Result.extend_text ("<div>Need an account?<br/>" + link ("Sign up now!", "/user/register", Void) + "</div>")
end end
form_username_or_email_name: STRING = "name" form_username_or_email_name: STRING = "name"

View File

@@ -21,8 +21,7 @@ feature -- Execution
b: STRING_8 b: STRING_8
f: CMS_FORM f: CMS_FORM
fd: detachable CMS_FORM_DATA fd: detachable CMS_FORM_DATA
u, fu: detachable CMS_USER u: detachable CMS_USER
up: detachable CMS_USER_PROFILE
l_is_editing_current_user: BOOLEAN l_is_editing_current_user: BOOLEAN
do do
if attached {WSF_STRING} request.path_parameter ("uid") as p_uid and then p_uid.is_integer then 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") f := edit_form (u, url (request.path_info, Void), "user-edit")
if request.is_post_request_method then if request.is_post_request_method then
create fd.make (request, f) f.validation_actions.extend (agent edit_form_validate (?, u))
if attached {WSF_STRING} fd.item ("username") as s_username then f.submit_actions.extend (agent edit_form_submit (?, u, l_is_editing_current_user, b))
fu := service.storage.user_by_name (s_username.value) f.process (Current)
if fu = Void then fd := f.last_data
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 ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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)
else else
if fd /= Void then f.prepare (Current)
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
f.append_to_html (theme, b)
end end
set_main_content (b) set_main_content (b)
end 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 ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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 edit_form (u: CMS_USER; a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM
local local
f: CMS_FORM f: CMS_FORM
@@ -118,6 +142,8 @@ feature -- Execution
tp: CMS_FORM_PASSWORD_INPUT tp: CMS_FORM_PASSWORD_INPUT
ta: CMS_FORM_TEXTAREA ta: CMS_FORM_TEXTAREA
ts: CMS_FORM_SUBMIT_INPUT ts: CMS_FORM_SUBMIT_INPUT
tset: CMS_FORM_FIELD_SET
cb: CMS_FORM_CHECKBOX_INPUT
do do
create f.make (a_url, a_name) create f.make (a_url, a_name)
@@ -156,6 +182,27 @@ feature -- Execution
ta.set_is_required (False) ta.set_is_required (False)
f.extend (ta) 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 ("<br/>") f.extend_text ("<br/>")
create ts.make ("op") create ts.make ("op")

View File

@@ -9,6 +9,9 @@ class
inherit inherit
CMS_MODULE CMS_MODULE
redefine
permissions
end
CMS_HOOK_MENU_ALTER CMS_HOOK_MENU_ALTER
@@ -55,6 +58,13 @@ feature {CMS_SERVICE} -- Registration
feature -- Hooks 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] block_list: ITERABLE [like {CMS_BLOCK}.name]
do do
Result := <<"user-info">> Result := <<"user-info">>
@@ -106,12 +116,6 @@ feature -- Hooks
end end
end end
links: HASH_TABLE [CMS_MODULE_LINK, STRING]
-- Link indexed by path
do
create Result.make (0)
end
feature -- Handlers feature -- Handlers
handle_logout (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE) handle_logout (cms: CMS_SERVICE; req: WSF_REQUEST; res: WSF_RESPONSE)

View File

@@ -22,8 +22,6 @@ feature -- Execution
f: CMS_FORM f: CMS_FORM
u: detachable CMS_USER u: detachable CMS_USER
fd: detachable CMS_FORM_DATA fd: detachable CMS_FORM_DATA
e: detachable CMS_EMAIL
l_uuid: UUID
do do
set_title ("Request new password") set_title ("Request new password")
create b.make_empty create b.make_empty
@@ -45,54 +43,70 @@ feature -- Execution
else else
f := new_password_form (url (request.path_info, Void), "new-password") f := new_password_form (url (request.path_info, Void), "new-password")
if request.is_post_request_method then if request.is_post_request_method then
create fd.make (request, f) f.validation_actions.extend (agent password_form_validate)
if attached {WSF_STRING} fd.item ("name") as s_name then f.submit_actions.extend (agent password_form_submit (?, b))
u := service.storage.user_by_name (s_name.value) f.process (Current)
if u = Void then fd := f.last_data
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 ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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)
else else
if fd /= Void then initialize_primary_tabs (Void)
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
f.append_to_html (theme, b)
end end
set_main_content (b) set_main_content (b)
end 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 ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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 new_password_form (a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM
require require
attached user as l_auth_user implies l_auth_user.has_email attached user as l_auth_user implies l_auth_user.has_email

View File

@@ -21,11 +21,6 @@ feature -- Execution
b: STRING_8 b: STRING_8
f: CMS_FORM f: CMS_FORM
fd: detachable CMS_FORM_DATA 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 do
set_title ("Create new account") set_title ("Create new account")
create b.make_empty 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) + ".") 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)) set_redirection (url ("/user", Void))
else 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 if request.is_post_request_method then
create fd.make (request, f) f.validation_actions.extend (agent registration_form_validate)
if attached {WSF_STRING} fd.item ("username") as s_username then f.submit_actions.extend (agent registration_form_submitted (?, b))
u := service.storage.user_by_name (s_username.value)
if u /= Void then f.process (Current)
fd.report_invalid_field ("username", "User already exists!") fd := f.last_data
end else
end f.prepare (Current)
if attached {WSF_STRING} fd.item ("email") as s_email then
u := service.storage.user_by_email (s_email.value)
if u /= Void then
fd.report_invalid_field ("email", "Email is already used!")
end
end
u := Void
end end
if fd /= Void and then fd.is_valid then if fd /= Void and then fd.is_valid then
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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) set_main_content (b)
else else
initialize_primary_tabs (user) 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) f.append_to_html (theme, b)
end end
end end
set_main_content (b) set_main_content (b)
end 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 ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
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 registration_form (a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM
local local
f: CMS_FORM f: CMS_FORM

View File

@@ -217,6 +217,46 @@ feature -- Change: user
a_user.set_profile (prof) a_user.set_profile (prof)
end 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 feature -- Email
save_email (a_email: CMS_EMAIL) save_email (a_email: CMS_EMAIL)
@@ -459,52 +499,116 @@ feature {NONE} -- Implementation
save_object_with_id (a_prof, l_id, "user_profile") save_object_with_id (a_prof, l_id, "user_profile")
end end
-- user_profiles: TUPLE [by_username: HASH_TABLE [CMS_USER_PROFILE, like {CMS_USER}.name]] feature -- Misc
-- local
-- f: RAW_FILE
-- fn: FILE_NAME
-- res: detachable like user_profiles
-- retried: INTEGER
-- do
-- if retried = 0 then
-- create fn.make_from_string (directory_name)
-- fn.set_file_name ("user_profiles.db")
-- create f.make (fn.string)
-- if f.exists and then f.is_readable then
-- f.open_read
-- if attached {like user_profiles} sed_file_retrieved (f) as r then
-- res := r
-- end
-- f.close
-- else
-- end
-- end
-- if res = Void then
-- res := [create {HASH_TABLE [CMS_USER_PROFILE, like {CMS_USER}.name]}.make (1)]
-- if retried <= 1 then
-- store_user_profiles (res)
-- end
-- end
-- Result := res
-- rescue
-- retried := retried + 1
-- retry
-- end
-- store_user_profiles (a_user_profiles: like user_profiles) custom_type (a_type: READABLE_STRING_8): STRING
-- local do
-- f: RAW_FILE Result := "custom__" + a_type
-- fn: FILE_NAME end
-- do
-- create fn.make_from_string (directory_name) custom_value_id (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): INTEGER
-- fn.set_file_name ("user_profiles.db") -- Storage `id' for custom value named `a_name' if any.
-- create f.make (fn.string) -- If no such data exists, return 0
-- if not f.exists or else f.is_writable then local
-- f.open_write i,
-- sed_file_store (a_user_profiles, f) l_id, l_last_id: INTEGER
-- f.close t: STRING
-- end do
-- end 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 feature {NONE} -- Implementation

View File

@@ -56,17 +56,6 @@ feature -- Access: user
deferred deferred
end 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 feature -- Change: user
save_user (a_user: CMS_USER) save_user (a_user: CMS_USER)
@@ -76,6 +65,69 @@ feature -- Change: user
a_user.has_id a_user.has_id
end 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 feature -- Email
save_email (a_email: CMS_EMAIL) save_email (a_email: CMS_EMAIL)
@@ -114,4 +166,21 @@ feature -- Node
deferred deferred
end 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 end

View File

@@ -13,4 +13,10 @@ feature -- Conversion
deferred deferred
end end
to_html (a_theme: CMS_THEME): STRING_8
do
create Result.make_empty
append_to_html (a_theme, Result)
end
end end

View File

@@ -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 ("<table")
append_css_id_to (a_html)
append_css_class_to (a_html, Void)
append_css_style_to (a_html)
a_html.append (">")
if has_title then
a_html.append ("<tr>")
across
columns as c
loop
c.item.append_table_header_to_html (a_theme, a_html)
end
a_html.append ("</tr>")
end
if attached head_data as l_head_data then
l_use_tbody := True
a_html.append ("<thead>")
append_data_to_html (l_head_data, a_theme, a_html)
a_html.append ("</thead>")
end
if attached foot_data as l_foot_data then
l_use_tbody := True
a_html.append ("<tfoot>")
append_data_to_html (l_foot_data, a_theme, a_html)
a_html.append ("</tfoot>")
end
if attached data as l_data then
if l_use_tbody then
a_html.append ("<tbody>")
end
append_data_to_html (l_data, a_theme, a_html)
if l_use_tbody then
a_html.append ("</tbody>")
end
end
a_html.append ("</table>")
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 ("<tr>")
a_html.append ("<td>")
if attached d.item as g then
a_html.append (g.out)
end
a_html.append ("</td>")
a_html.append ("</tr>")
end
end
end
end

View File

@@ -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

View File

@@ -1,11 +1,10 @@
note note
description: "Summary description for {CMS_WIDGET_TABLE}." description: "Summary description for {CMS_WIDGET_FILLED_TABLE}."
author: ""
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
class class
CMS_WIDGET_TABLE [G] CMS_WIDGET_TABLE
inherit inherit
CMS_WIDGET CMS_WIDGET
@@ -16,6 +15,8 @@ inherit
WITH_CSS_STYLE WITH_CSS_STYLE
ITERABLE [CMS_WIDGET_TABLE_ITEM]
create create
make make
@@ -26,15 +27,94 @@ feature {NONE} -- Initialization
create columns.make_empty create columns.make_empty
end 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 feature -- Access
new_cursor: CMS_WIDGET_TABLE_ITERATION_CURSOR
-- Fresh cursor associated with current structure
do
create Result.make (Current)
end
column_count: INTEGER column_count: INTEGER
do do
Result := columns.count Result := columns.count
end 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] columns: ARRAY [CMS_WIDGET_TABLE_COLUMN]
column (c: INTEGER): CMS_WIDGET_TABLE_COLUMN column (c: INTEGER): CMS_WIDGET_TABLE_COLUMN
do do
if c > column_count then if c > column_count then
@@ -43,48 +123,85 @@ feature -- Access
Result := columns[c] Result := columns[c]
end 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 has_title: BOOLEAN
do do
Result := across columns as c some c.item.title /= Void end Result := across columns as c some c.item.title /= Void end
end end
head_data: detachable ITERABLE [G] head_rows: detachable ARRAYED_LIST [CMS_WIDGET_TABLE_ROW]
-- thead -- thead
foot_data: detachable ITERABLE [G] foot_rows: detachable ARRAYED_LIST [CMS_WIDGET_TABLE_ROW]
-- tfoot -- tfoot
data: detachable ITERABLE [G] rows: detachable ARRAYED_LIST [CMS_WIDGET_TABLE_ROW]
-- tbody -- tbody
compute_item_function: detachable FUNCTION [ANY, TUPLE [data: G], CMS_WIDGET_TABLE_ROW]
feature -- Change feature -- Change
set_head_data (d: like head_data) clear_rows
do do
head_data := d head_rows := Void
foot_rows := Void
rows := Void
end end
set_foot_data (d: like foot_data) add_head_row (r: CMS_WIDGET_TABLE_ROW)
local
lst: like head_rows
do 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 end
set_data (d: like data) add_foot_row (r: CMS_WIDGET_TABLE_ROW)
local
lst: like foot_rows
do 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 end
set_compute_item_function (fct: like compute_item_function) add_row (r: CMS_WIDGET_TABLE_ROW)
local
lst: like rows
do 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 end
set_column_count (nb: INTEGER) set_column_count (nb: INTEGER)
do do
if nb > columns.count then if nb > columns.count then
-- columns.conservative_resize_with_default (create {CMS_WIDGET_TABLE_COLUMN}, 1, nb)
from from
until until
columns.count = nb columns.count = nb
@@ -127,24 +244,24 @@ feature -- Conversion
end end
a_html.append ("</tr>") a_html.append ("</tr>")
end end
if attached head_data as l_head_data then if attached head_rows as l_head_rows then
l_use_tbody := True l_use_tbody := True
a_html.append ("<thead>") a_html.append ("<thead>")
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 ("</thead>") a_html.append ("</thead>")
end end
if attached foot_data as l_foot_data then if attached foot_rows as l_foot_rows then
l_use_tbody := True l_use_tbody := True
a_html.append ("<tfoot>") a_html.append ("<tfoot>")
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 ("</tfoot>") a_html.append ("</tfoot>")
end end
if attached data as l_data then if attached rows as l_rows then
if l_use_tbody then if l_use_tbody then
a_html.append ("<tbody>") a_html.append ("<tbody>")
end 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 if l_use_tbody then
a_html.append ("</tbody>") a_html.append ("</tbody>")
end end
@@ -152,25 +269,12 @@ feature -- Conversion
a_html.append ("</table>") a_html.append ("</table>")
end end
append_data_to_html (lst: ITERABLE [G]; a_theme: CMS_THEME; a_html: STRING_8) append_rows_to_html (lst: ITERABLE [CMS_WIDGET_TABLE_ROW]; a_theme: CMS_THEME; a_html: STRING_8)
local
fct: like compute_item_function
do do
fct := compute_item_function
across across
lst as d lst as r
loop loop
if fct /= Void and then attached fct.item ([d.item]) as r then r.item.append_to_html (a_theme, a_html)
r.append_to_html (a_theme, a_html)
else
a_html.append ("<tr>")
a_html.append ("<td>")
if attached d.item as g then
a_html.append (g.out)
end
a_html.append ("</td>")
a_html.append ("</tr>")
end
end end
end end

View File

@@ -16,6 +16,8 @@ inherit
WITH_CSS_STYLE WITH_CSS_STYLE
ITERABLE [CMS_WIDGET]
create create
make_with_text, make_with_text,
make_with_text_and_css, make_with_text_and_css,
@@ -49,6 +51,18 @@ feature -- Access
content: CMS_WIDGET 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 feature -- Conversion
append_to_html (a_theme: CMS_THEME; a_html: STRING_8) append_to_html (a_theme: CMS_THEME; a_html: STRING_8)

View File

@@ -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

View File

@@ -49,8 +49,39 @@ feature -- Access
Result := items.new_cursor Result := items.new_cursor
end end
count: INTEGER
do
Result := items.count
end
item (c: INTEGER): CMS_WIDGET_TABLE_ITEM
do
Result := items [c]
end
feature -- Change 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) force, add_item (w: CMS_WIDGET_TABLE_ITEM)
do do
items.force (w) items.force (w)

View File

@@ -150,13 +150,22 @@ div.node div.inner {
border-top: dotted 1px #dddddd; border-top: dotted 1px #dddddd;
} }
form#login-form { form#user-login {
border: dotted 1px #099; border: dotted 1px #099;
display: inline-block; display: inline-block;
padding: 10px; padding: 10px;
margin: 10px; margin: 10px;
} }
form#user-login>div {
margin-bottom: 10px;
}
form#user-login .input {
float: left;
}
form#user-login img.logo {
}
div#message { div#message {
border: solid 1px #fc0; border: solid 1px #fc0;
background-color: #fed; background-color: #fed;

View File

@@ -32,6 +32,48 @@ feature -- Access
attributes: HASH_TABLE [READABLE_STRING_32, STRING_8] 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 feature -- Basic operation
validate validate

View File

@@ -14,6 +14,9 @@ feature -- Execute template
execute_methods (req: WSF_REQUEST; res: WSF_RESPONSE) execute_methods (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request and dispatch according to the request method. -- Execute request and dispatch according to the request method.
require
req_attached: req /= Void
res_attached: res /= Void
local local
m: READABLE_STRING_8 m: READABLE_STRING_8
do do
@@ -43,6 +46,11 @@ feature -- Execute template
feature -- Method Get feature -- Method Get
execute_get (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_get (req, res) do_get (req, res)
end end
@@ -52,9 +60,9 @@ feature -- Method Get
-- If the GET request is SUCCESS, we respond with -- If the GET request is SUCCESS, we respond with
-- 200 OK, and a representation of the resource. -- 200 OK, and a representation of the resource.
-- If the GET request is not SUCCESS, we response with -- 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 -- If is a Condition GET and the resource does not change we send a
-- 304, Resource not modifed -- 304, Resource not modifed.
do do
handle_not_implemented ("Method GET not implemented", req, res) handle_not_implemented ("Method GET not implemented", req, res)
end end
@@ -62,6 +70,11 @@ feature -- Method Get
feature -- Method Post feature -- Method Post
execute_post (req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
if req.is_chunked_input then if req.is_chunked_input then
do_post (req, res) do_post (req, res)
@@ -90,6 +103,11 @@ feature -- Method Post
feature-- Method Put feature-- Method Put
execute_put (req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
if req.is_chunked_input then if req.is_chunked_input then
do_put (req, res) do_put (req, res)
@@ -110,6 +128,11 @@ feature-- Method Put
feature -- Method DELETE feature -- Method DELETE
execute_delete (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_delete (req, res) do_delete (req, res)
end end
@@ -126,6 +149,11 @@ feature -- Method DELETE
feature -- Method CONNECT feature -- Method CONNECT
execute_connect (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_connect (req, res) do_connect (req, res)
end end
@@ -138,6 +166,11 @@ feature -- Method CONNECT
feature -- Method HEAD feature -- Method HEAD
execute_head (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_head (req, res) do_head (req, res)
end end
@@ -157,6 +190,11 @@ feature -- Method HEAD
feature -- Method OPTIONS feature -- Method OPTIONS
execute_options (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_options (req, res) do_options (req, res)
end end
@@ -170,6 +208,11 @@ feature -- Method OPTIONS
feature -- Method TRACE feature -- Method TRACE
execute_trace (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_trace (req, res) do_trace (req, res)
end end
@@ -183,20 +226,30 @@ feature -- Method TRACE
feature -- Method Extension Method feature -- Method Extension Method
execute_extension_method (req: WSF_REQUEST; res: WSF_RESPONSE) 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
do_extension_method (req, res) do_extension_method (req, res)
end end
do_extension_method (req: WSF_REQUEST; res: WSF_RESPONSE) do_extension_method (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute `req' responding into `res'.
require
req_attached: req /= Void
res_attached: res /= Void
do do
handle_not_implemented ("Method extension-method not implemented", req, res) handle_not_implemented ("Method extension-method not implemented", req, res)
end end
feature -- Retrieve content from WGI_INPUT_STREAM feature -- Retrieve content from WGI_INPUT_STREAM
retrieve_data ( req : WSF_REQUEST) : STRING retrieve_data (req: WSF_REQUEST): STRING
-- retrieve the content from the input stream -- Retrieve the content from the input stream.
-- handle differents transfers -- Handle different transfers.
require
req_attached: req /= Void
do do
create Result.make_empty create Result.make_empty
req.read_input_data_into (Result) 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 -- The option : Server-driven negotiation: uses request headers to select a variant
-- More info : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12 -- More info : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12
-- supported_content_types: detachable ARRAY [READABLE_STRING_8] -- TODO: review HTTP requirements on `a_description' for each individual error code.
-- -- Supported content types
-- -- Can be redefined
-- do
-- Result := Void
-- end
handle_error (a_description: STRING; a_status_code: INTEGER; req: WSF_REQUEST; res: WSF_RESPONSE) handle_error (a_description: STRING; a_status_code: INTEGER; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle an error. -- 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 local
h: HTTP_HEADER h: HTTP_HEADER
do do
@@ -229,55 +282,99 @@ feature -- Handle responses
end end
handle_not_implemented (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.not_implemented, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.not_implemented, req, res)
end end
handle_bad_request_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.bad_request, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.bad_request, req, res)
end end
handle_resource_not_found_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.not_found, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.not_found, req, res)
end end
handle_forbidden (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.forbidden, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.forbidden, req, res)
end end
feature -- Handle responses: others 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.precondition_failed, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.precondition_failed, req, res)
end 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.internal_server_error, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.internal_server_error, req, res)
end end
handle_method_not_allowed_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.method_not_allowed, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.method_not_allowed, req, res)
end end
handle_resource_not_modified_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.not_modified, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.not_modified, req, res)
end end
handle_resource_conflict_response (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) 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 do
handle_error (a_description, {HTTP_STATUS_CODE}.conflict, req, res) handle_error (a_description, {HTTP_STATUS_CODE}.conflict, req, res)
end end
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -15,6 +15,10 @@ inherit
feature -- Execution feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE) 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 deferred
end end
@@ -26,7 +30,7 @@ feature {WSF_ROUTER} -- Mapping
end end
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -13,11 +13,19 @@ inherit
feature -- Mapping helper: uri feature -- Mapping helper: uri
map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) 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 do
map_uri_template_with_request_methods (a_tpl, h, Void) map_uri_template_with_request_methods (a_tpl, h, Void)
end end
map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) 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 do
router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods)
end end
@@ -25,17 +33,25 @@ feature -- Mapping helper: uri
feature -- Mapping helper: uri agent 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_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 do
map_uri_template_agent_with_request_methods (a_tpl, proc, Void) map_uri_template_agent_with_request_methods (a_tpl, proc, Void)
end 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_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 do
map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods)
end end
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -15,6 +15,10 @@ inherit
feature -- Execution feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE) execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute `req' responding in `res'.
require
req_attached: req /= Void
res_attached: res /= Void
deferred deferred
end end

View File

@@ -21,17 +21,25 @@ feature -- Access
feature -- Change feature -- Change
set_handler (h: like handler) set_handler (h: like handler)
-- <Precursor>
do do
handler := h handler := h
ensure then
h_aliased: handler = h
end end
feature {NONE} -- Execution feature {NONE} -- Execution
execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE) execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do do
h.execute (req, res) h.execute (req, res)
end end
invariant
handler_attached: handler /= Void
note note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -15,20 +15,27 @@ inherit
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (s: READABLE_STRING_8; h: like handler) make (s: READABLE_STRING_8; h: like handler)
-- <Precursor>
do do
make_from_template (create {URI_TEMPLATE}.make (s), h) make_from_template (create {URI_TEMPLATE}.make (s), h)
end end
make_from_template (tpl: URI_TEMPLATE; h: like handler) 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 do
template := tpl template := tpl
set_handler (h) set_handler (h)
ensure
tpl_aliased: template = tpl
end end
feature -- Access feature -- Access
associated_resource: READABLE_STRING_8 associated_resource: READABLE_STRING_8
-- Associated resource -- URI template text of handled resource
do do
Result := template.template Result := template.template
end end
@@ -38,6 +45,9 @@ feature -- Access
feature -- Change feature -- Change
set_handler (h: like handler) set_handler (h: like handler)
-- Set `handler' to `h'.
require
h_attached: h /= Void
deferred deferred
end end
@@ -59,6 +69,7 @@ feature -- Status
end end
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER
-- <Precursor>
local local
tpl: URI_TEMPLATE tpl: URI_TEMPLATE
p: READABLE_STRING_32 p: READABLE_STRING_32
@@ -88,13 +99,21 @@ feature -- Status
feature {NONE} -- Execution feature {NONE} -- Execution
execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE) 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 deferred
end end
feature {NONE} -- Implementation feature {NONE} -- Implementation
based_uri_template (a_tpl: like template; a_router: WSF_ROUTER): like template 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 do
if attached a_router.base_url as l_base_url then if attached a_router.base_url as l_base_url then
Result := a_tpl.duplicate Result := a_tpl.duplicate
@@ -102,6 +121,8 @@ feature {NONE} -- Implementation
else else
Result := a_tpl Result := a_tpl
end end
ensure
based_uri_template_attached: Result /= Void
end end
note note

View File

@@ -55,17 +55,26 @@ feature {NONE} -- Initialization
end end
make (n: INTEGER) make (n: INTEGER)
-- Initialize with capacity for `n' methods.
require
valid_number_of_items: n >= 0
do do
create methods.make (n) create methods.make (n)
end end
make_from_iterable (v: ITERABLE [READABLE_STRING_8]) 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 do
make (1) make (1)
add_methods (v) add_methods (v)
end end
make_from_string (v: READABLE_STRING_8) make_from_string (v: READABLE_STRING_8)
-- Initialize from comma-separated methods named in `v'.
require
v_attached: v /= Void
do do
make_from_iterable (v.split (',')) make_from_iterable (v.split (','))
end end
@@ -83,6 +92,7 @@ feature -- Status report
has (a_method: READABLE_STRING_8): BOOLEAN has (a_method: READABLE_STRING_8): BOOLEAN
-- Has `a_method' enabled? -- Has `a_method' enabled?
require require
a_method_attached: a_method /= Void
a_method_is_uppercase: a_method.same_string (a_method.as_upper) a_method_is_uppercase: a_method.same_string (a_method.as_upper)
do do
-- First look for string object itself, -- First look for string object itself,
@@ -95,67 +105,71 @@ feature -- Status report
end end
has_some_of (a_methods: WSF_REQUEST_METHODS): BOOLEAN 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 do
Result := across a_methods as c some has (c.item) end Result := across a_methods as c some has (c.item) end
end end
has_all_of (a_methods: WSF_REQUEST_METHODS): BOOLEAN 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 do
Result := across a_methods as c all has (c.item) end Result := across a_methods as c all has (c.item) end
end end
has_method_get: BOOLEAN has_method_get: BOOLEAN
-- Has method GET enabled? -- Has method GET been enabled?
do do
Result := has (method_get) Result := has (method_get)
end end
has_method_post: BOOLEAN has_method_post: BOOLEAN
-- Has method POST enabled? -- Has method POST been enabled?
do do
Result := has (method_post) Result := has (method_post)
end end
has_method_put: BOOLEAN has_method_put: BOOLEAN
-- Has method PUT enabled? -- Has method PUT been enabled?
do do
Result := has (method_put) Result := has (method_put)
end end
has_method_delete: BOOLEAN has_method_delete: BOOLEAN
-- Has method DELETE enabled? -- Has method DELETE been enabled?
do do
Result := has (method_delete) Result := has (method_delete)
end end
has_method_options: BOOLEAN has_method_options: BOOLEAN
-- Has method OPTIONS enabled? -- Has method OPTIONS been enabled?
do do
Result := has (method_options) Result := has (method_options)
end end
has_method_head: BOOLEAN has_method_head: BOOLEAN
-- Has method HEAD enabled? -- Has method HEAD been enabled?
do do
Result := has (method_head) Result := has (method_head)
end end
has_method_trace: BOOLEAN has_method_trace: BOOLEAN
-- Has method TRACE enabled? -- Has method TRACE been enabled?
do do
Result := has (method_trace) Result := has (method_trace)
end end
has_method_connect: BOOLEAN has_method_connect: BOOLEAN
-- Has method CONNECT enabled? -- Has method CONNECT been enabled?
do do
Result := has (method_connect) Result := has (method_connect)
end end
has_method_patch: BOOLEAN has_method_patch: BOOLEAN
-- Has method PATCH enabled? -- Has method PATCH been enabled?
do do
Result := has (method_patch) Result := has (method_patch)
end end
@@ -384,6 +398,7 @@ feature -- Element change
disable_custom (m: READABLE_STRING_8) disable_custom (m: READABLE_STRING_8)
require require
is_not_locked: not is_locked is_not_locked: not is_locked
m_attached: m /= Void
not_blank: not across m as mc some mc.item.is_space end not_blank: not across m as mc some mc.item.is_space end
custom_enabled: has (m.as_upper) custom_enabled: has (m.as_upper)
do do
@@ -404,13 +419,17 @@ feature -- Access
feature {WSF_REQUEST_METHODS} -- Implementation feature {WSF_REQUEST_METHODS} -- Implementation
add_methods (lst: ITERABLE [READABLE_STRING_8]) 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 do
if not is_locked then if not is_locked then
across across
lst as c lst as c
loop 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 end
end end
@@ -418,7 +437,11 @@ feature {WSF_REQUEST_METHODS} -- Implementation
feature {NONE} -- Implementation feature {NONE} -- Implementation
add_method_using_constant (v: READABLE_STRING_8) 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 do
if v.is_case_insensitive_equal (method_get) then if v.is_case_insensitive_equal (method_get) then
enable_get enable_get
@@ -446,7 +469,10 @@ feature {NONE} -- Implementation
end end
prune_method (v: READABLE_STRING_8) prune_method (v: READABLE_STRING_8)
-- Remove method named `v' from `Current'.
-- Does nothing if `Current' `is_locked'.
require require
v_attached: v /= Void
is_upper_case: v.same_string (v.as_upper) is_upper_case: v.same_string (v.as_upper)
local local
m: READABLE_STRING_8 m: READABLE_STRING_8
@@ -468,10 +494,12 @@ feature {NONE} -- Implementation
end end
invariant invariant
methods_attached: methods /= Void
methods_are_uppercase: across methods as c all c.item.same_string (c.item.as_upper) end methods_are_uppercase: across methods as c all c.item.same_string (c.item.as_upper) end
;note ;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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -36,7 +36,10 @@ feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE) execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Dispatch the request -- 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 do
if attached router.dispatch_and_return_handler (req, res) as p then if attached router.dispatch_and_return_handler (req, res) as p then
-- executed -- executed
@@ -46,7 +49,10 @@ feature -- Execution
end end
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) 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 local
msg: WSF_DEFAULT_ROUTER_RESPONSE msg: WSF_DEFAULT_ROUTER_RESPONSE
do do
@@ -62,7 +68,7 @@ feature -- Access
-- and associated request methods -- and associated request methods
;note ;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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -23,26 +23,40 @@ create
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (n: INTEGER) 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 do
create mappings.make (n)
initialize (n) initialize (n)
ensure
no_handler_set: count = 0
end end
make_with_base_url (n: INTEGER; a_base_url: like base_url) make_with_base_url (n: INTEGER; a_base_url: like base_url)
-- Make router allocated for at least `n' maps, -- Make router allocated for at least `n' maps,
-- and use `a_base_url' as `base_url' -- and use `a_base_url' as `base_url'
--| This avoids prefixing all the resource string. --| 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 do
make (n) make (n)
check
no_handler_set: count = 0
-- ensured by `make'
end
set_base_url (a_base_url) set_base_url (a_base_url)
end end
initialize (n: INTEGER) initialize (n: INTEGER)
-- Initialize router -- Initialize router.
require
valid_number_of_items: n >= 0
do do
create mappings.make (n) create mappings.make (n)
create pre_execution_actions create pre_execution_actions
ensure
no_handler_set: count = 0
end end
mappings: ARRAYED_LIST [WSF_ROUTER_ITEM] mappings: ARRAYED_LIST [WSF_ROUTER_ITEM]
@@ -51,13 +65,17 @@ feature {NONE} -- Initialization
feature -- Mapping feature -- Mapping
map (a_mapping: WSF_ROUTER_MAPPING) map (a_mapping: WSF_ROUTER_MAPPING)
-- Map `a_mapping' -- Map `a_mapping'.
require
a_mapping_attached: a_mapping /= Void
do do
map_with_request_methods (a_mapping, Void) map_with_request_methods (a_mapping, Void)
end end
map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) 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 do
debug ("router") debug ("router")
-- Display conflict in mapping -- Display conflict in mapping
@@ -76,7 +94,10 @@ feature -- Mapping
feature -- Mapping handler feature -- Mapping handler
handle (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY) 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 do
handle_with_request_methods (a_resource, f, Void) handle_with_request_methods (a_resource, f, Void)
end 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) 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' -- Map the mapping created by factory `f' for resource `a_resource'
-- and only for request methods `rqst_methods' -- and only for request methods `rqst_methods'
require
a_resource_attached: a_resource /= Void
f_attached: f /= Void
do do
map_with_request_methods (f.new_mapping (a_resource), rqst_methods) map_with_request_methods (f.new_mapping (a_resource), rqst_methods)
end end
@@ -94,9 +118,14 @@ feature -- Access
-- `dispatch' set `is_dispatched' to True -- `dispatch' set `is_dispatched' to True
-- if mapping was found, and associated handler executed -- if mapping was found, and associated handler executed
feature -- Basic operations
dispatch (req: WSF_REQUEST; res: WSF_RESPONSE) dispatch (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Dispatch request `req' among the `mappings' -- Dispatch request `req' among the `mappings'.
-- Set `is_dispatched' if the request were dispatched -- Set `is_dispatched' if the request were dispatched.
require
req_attached: req /= Void
res_attached: res /= Void
do do
if attached dispatch_and_return_handler (req, res) then if attached dispatch_and_return_handler (req, res) then
check is_dispatched: is_dispatched end 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_and_return_handler (req: WSF_REQUEST; res: WSF_RESPONSE): detachable WSF_HANDLER
-- Dispatch request `req' among the `mappings' -- Dispatch request `req' among the `mappings'
-- And return the associated handler if mapping found and handler executed. -- And return the associated handler if mapping found and handler executed.
--| Violates CQS
require
req_attached: req /= Void
res_attached: res /= Void
local local
l_req_method: READABLE_STRING_8 l_req_method: READABLE_STRING_8
head_res: WSF_HEAD_RESPONSE_WRAPPER 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_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' -- Dispatch request `req' among the `mappings'
-- And return the associated handler if mapping found and handler executed. -- 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 local
m: WSF_ROUTER_MAPPING m: WSF_ROUTER_MAPPING
do do
@@ -151,6 +189,9 @@ feature {NONE} -- Dispatch implementation
feature -- Status report feature -- Status report
has_item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_REQUEST_METHODS): BOOLEAN 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 local
m: WSF_ROUTER_MAPPING m: WSF_ROUTER_MAPPING
ok: BOOLEAN ok: BOOLEAN
@@ -178,6 +219,9 @@ feature -- Status report
end end
item_associated_with_resource (a_resource: READABLE_STRING_8; rqst_methods: detachable WSF_REQUEST_METHODS): detachable WSF_ROUTER_ITEM 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 local
m: WSF_ROUTER_MAPPING m: WSF_ROUTER_MAPPING
ok: BOOLEAN ok: BOOLEAN
@@ -208,6 +252,8 @@ feature -- Status report
allowed_methods_for_request (req: WSF_REQUEST): WSF_REQUEST_METHODS allowed_methods_for_request (req: WSF_REQUEST): WSF_REQUEST_METHODS
-- Allowed methods for `req' -- Allowed methods for `req'
require
req_attched: req /= Void
local local
m: WSF_ROUTER_MAPPING m: WSF_ROUTER_MAPPING
l_rqsmethods: detachable WSF_REQUEST_METHODS l_rqsmethods: detachable WSF_REQUEST_METHODS
@@ -234,14 +280,18 @@ feature -- Status report
feature -- Hook feature -- Hook
execute_before (a_mapping: WSF_ROUTER_MAPPING) 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 do
pre_execution_actions.call ([a_mapping]) pre_execution_actions.call ([a_mapping])
end end
execute_after (a_mapping: WSF_ROUTER_MAPPING) 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. --| Could be redefined to add specific hook.
require
a_mapping_attached: a_mapping /= Void
do do
end end
@@ -291,6 +341,8 @@ feature -- Request methods helper
create Result create Result
Result.enable_head Result.enable_head
Result.lock Result.lock
ensure
methods_head_not_void: Result /= Void
end end
methods_options: WSF_REQUEST_METHODS methods_options: WSF_REQUEST_METHODS
@@ -298,6 +350,8 @@ feature -- Request methods helper
create Result create Result
Result.enable_options Result.enable_options
Result.lock Result.lock
ensure
methods_options_not_void: Result /= Void
end end
methods_get: WSF_REQUEST_METHODS methods_get: WSF_REQUEST_METHODS
@@ -305,6 +359,8 @@ feature -- Request methods helper
create Result create Result
Result.enable_get Result.enable_get
Result.lock Result.lock
ensure
methods_get_not_void: Result /= Void
end end
methods_post: WSF_REQUEST_METHODS methods_post: WSF_REQUEST_METHODS
@@ -312,6 +368,8 @@ feature -- Request methods helper
create Result create Result
Result.enable_post Result.enable_post
Result.lock Result.lock
ensure
methods_post_not_void: Result /= Void
end end
methods_put: WSF_REQUEST_METHODS methods_put: WSF_REQUEST_METHODS
@@ -319,6 +377,8 @@ feature -- Request methods helper
create Result create Result
Result.enable_put Result.enable_put
Result.lock Result.lock
ensure
methods_put_not_void: Result /= Void
end end
methods_delete: WSF_REQUEST_METHODS methods_delete: WSF_REQUEST_METHODS
@@ -326,6 +386,8 @@ feature -- Request methods helper
create Result create Result
Result.enable_delete Result.enable_delete
Result.lock Result.lock
ensure
methods_delete_not_void: Result /= Void
end end
methods_head_get_post: WSF_REQUEST_METHODS methods_head_get_post: WSF_REQUEST_METHODS
@@ -335,6 +397,8 @@ feature -- Request methods helper
Result.enable_get Result.enable_get
Result.enable_post Result.enable_post
Result.lock Result.lock
ensure
methods_head_get_post_not_void: Result /= Void
end end
methods_get_put_delete: WSF_REQUEST_METHODS methods_get_put_delete: WSF_REQUEST_METHODS
@@ -344,6 +408,8 @@ feature -- Request methods helper
Result.enable_put Result.enable_put
Result.enable_delete Result.enable_delete
Result.lock Result.lock
ensure
methods_get_put_not_void: Result /= Void
end end
methods_head_get: WSF_REQUEST_METHODS methods_head_get: WSF_REQUEST_METHODS
@@ -352,6 +418,8 @@ feature -- Request methods helper
Result.enable_head Result.enable_head
Result.enable_get Result.enable_get
Result.lock Result.lock
ensure
methods_head_get_not_void: Result /= Void
end end
methods_get_post: WSF_REQUEST_METHODS methods_get_post: WSF_REQUEST_METHODS
@@ -360,6 +428,8 @@ feature -- Request methods helper
Result.enable_get Result.enable_get
Result.enable_post Result.enable_post
Result.lock Result.lock
ensure
methods_get_post_not_void: Result /= Void
end end
methods_put_post: WSF_REQUEST_METHODS methods_put_post: WSF_REQUEST_METHODS
@@ -368,12 +438,16 @@ feature -- Request methods helper
Result.enable_put Result.enable_put
Result.enable_post Result.enable_post
Result.lock Result.lock
ensure
methods_put_post_not_void: Result /= Void
end end
feature {NONE} -- Access: Implementation feature {NONE} -- Access: Implementation
request_method (req: WSF_REQUEST): READABLE_STRING_8 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 local
m: READABLE_STRING_8 m: READABLE_STRING_8
do 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 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 -- `a_request_method' is matching `a_rqst_methods' contents
require
a_request_method_attached: a_request_method /= Void
do do
if a_rqst_methods /= Void and then not a_rqst_methods.is_empty then if a_rqst_methods /= Void and then not a_rqst_methods.is_empty then
Result := a_rqst_methods.has (a_request_method) Result := a_rqst_methods.has (a_request_method)
@@ -411,8 +487,13 @@ feature {NONE} -- Access: Implementation
end end
end end
invariant
mappings_attached: mappings /= Void
pre_execution_actions_attached: pre_execution_actions /= Void
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -13,27 +13,36 @@ inherit
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (a_resource: READABLE_STRING_8; h: like handler) 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 deferred
end end
feature -- Access feature -- Access
associated_resource: READABLE_STRING_8 associated_resource: READABLE_STRING_8
-- Associated resource -- Name (URI, or URI template or regular expression or ...) of handled resource
deferred deferred
ensure
assciated_resource_not_void: Result /= Void
end end
handler: WSF_HANDLER handler: WSF_HANDLER
-- Handler associated with Current mapping. -- Handler associated with `Current' mapping
deferred deferred
ensure
handler_attached: Result /= Void
end end
feature -- Documentation feature -- Documentation
description: READABLE_STRING_32 description: READABLE_STRING_32
-- Short description of associated mapping. -- Short description of associated mapping
deferred deferred
ensure
description_attached: Result /= Void
end end
feature -- Status report feature -- Status report
@@ -47,25 +56,36 @@ feature -- Status report
feature -- Status feature -- Status
is_mapping (req: WSF_REQUEST; a_router: WSF_ROUTER): BOOLEAN 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 deferred
end end
routed_handler (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER): detachable WSF_HANDLER 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 deferred
end end
feature -- Helper feature -- Helper
path_from_request (req: WSF_REQUEST): READABLE_STRING_32 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 do
Result := req.path_info Result := req.path_info
ensure
path_from_request_attached: Result /= Void
end end
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -14,6 +14,8 @@ feature {WSF_ROUTER} -- Mapping
new_mapping (a_uri: READABLE_STRING_8): WSF_ROUTER_MAPPING new_mapping (a_uri: READABLE_STRING_8): WSF_ROUTER_MAPPING
-- New mapping object -- New mapping object
require
a_uri_attached: a_uri /= Void
deferred deferred
ensure ensure
Result_attached: Result /= Void Result_attached: Result /= Void

View File

@@ -157,4 +157,14 @@ feature {NONE} -- Implementation
Result := fn.string Result := fn.string
end 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 end

View File

@@ -78,12 +78,12 @@ feature -- Control
deferred deferred
end 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 deferred
end end
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -27,4 +27,14 @@ feature -- Persistence
deferred deferred
end 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 end

View File

@@ -58,11 +58,11 @@ feature -- Access
end end
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 do
Result := values.item (k) Result := values.item (k.to_string_32)
end end
count: INTEGER count: INTEGER
@@ -169,11 +169,11 @@ feature -- Conversion
feature -- Element change feature -- Element change
add_value (a_value: WSF_VALUE; k: READABLE_STRING_32) add_value (a_value: WSF_VALUE; k: READABLE_STRING_GENERAL)
require 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) = '[') 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 do
values.force (a_value, k) values.force (a_value, k.to_string_32)
end end
feature -- Traversing feature -- Traversing
@@ -217,7 +217,7 @@ feature -- Visitor
end end
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -27,6 +27,9 @@ create
feature {NONE} -- Initialization feature {NONE} -- Initialization
make_from_response (res: WSF_RESPONSE) make_from_response (res: WSF_RESPONSE)
-- Initialize from `res' (assumed to be a GET response).
require
res_attached: res /= Void
do do
wsf_response := res wsf_response := res
make_from_wgi (res.wgi_response) make_from_wgi (res.wgi_response)
@@ -65,10 +68,12 @@ feature -- Output operation
end end
invariant invariant
transfered_content_length_is_zero: transfered_content_length = 0 transfered_content_length_is_zero: transfered_content_length = 0
wsf_response_attached: wsf_response /= Void
note 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)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -411,6 +411,48 @@ feature -- Access: global variables
Result.keep_head (n - 1) Result.keep_head (n - 1)
end 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 feature -- Helpers: global variables
items_as_string_items: ITERABLE [TUPLE [name: READABLE_STRING_32; value: detachable READABLE_STRING_32]] items_as_string_items: ITERABLE [TUPLE [name: READABLE_STRING_32; value: detachable READABLE_STRING_32]]