Added support for OpenID identity

Added user roles management
Improvement CMS_HOOK_FORM_ALTER design.
Factorized code into CMS_WIDGET_COMPOSITE
Use general notion of CMS_WIDGET (and CMS_FORM allows CMS_WIDGET, and not just CMS_FORM_ITEM)
Fixed various CMS_WIDGET traversal, and fixed related issue for CMS forms
Fixed CMS_FORM_CHECKBOX_INPUT when no value was set.
Added CMS_FORM_DATA.cached_value .. to pass computed values during validation to submit actions (mainly for optimization)
Added support for @include=filename  in CMS_CONFIGURATION
Added CMS_WIDGET_TABLE as filled version of CMS_WIDGET_AGENT_TABLE (renamed from previous CMS_WIDGET_TABLE)
Many improvements to the CMS_FORM design
Some improvements to CMS_MODULE
...
This commit is contained in:
Jocelyn Fiat
2013-03-08 15:48:39 +01:00
parent 231b263a82
commit 617c48adcb
52 changed files with 2635 additions and 834 deletions

View File

@@ -13,13 +13,11 @@
<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="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,13 +14,11 @@
<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="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"/>

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

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

@@ -62,6 +62,19 @@ feature -- Change
checked := b checked := b
end 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: detachable WSF_VALUE)
-- Set value `v' if applicable to Current -- Set value `v' if applicable to Current
do do
@@ -69,14 +82,10 @@ feature -- Change
across across
lst as c lst as c
loop loop
if set_checked_by_value (c.item)
attached {WSF_STRING} c.item as s and then
is_same_value (s.value)
then
set_checked (True)
end
end end
else else
set_checked_by_value (v)
Precursor (v) Precursor (v)
end end
end end
@@ -91,8 +100,8 @@ feature {NONE} -- Implementation
a_html.append (t) a_html.append (t)
elseif attached text as t then elseif attached text as t then
a_html.append (a_theme.html_encoded (t)) a_html.append (a_theme.html_encoded (t))
elseif attached value as v then -- elseif attached value as v then
a_html.append (a_theme.html_encoded (v)) -- a_html.append (a_theme.html_encoded (v))
end end
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 ('[', 1)
if p > 0 then
q := k.index_of (']', p + 1)
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,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

@@ -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 %""+ 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_text ("roles[]", r.item.id.out)
cb.set_text (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;