Added auth_api: CMS_AUTHENTICATION_API, and for now moved registration instructions inside.

Added authentication module webapi, to provide registration via webapi.
Improved the roles display by providing table of permissions if asked.
Added various links in primary tabs to navigate back to roles or users, depending on the page.
Added datetime to-from string converters in CMS_ENCODERS.
Start removing CMS_ADMINISTRABLE.
Added permission to use simple core access token.
Added webapi for users: list, new, register.
This commit is contained in:
Jocelyn Fiat
2017-09-12 23:07:45 +02:00
parent b83a050a1d
commit e04138c89e
27 changed files with 799 additions and 208 deletions

View File

@@ -41,6 +41,18 @@ ul.cms-roles li.cms_role a::before {
content: "[role] "; content: "[role] ";
} }
table.cms-roles {
border: solid 1px black;
border-collapse: collapse;
}
table.cms-roles th, table.cms-roles td {
padding: 2px;
border: solid 1px black;
}
table.cms-roles td.cms_role_permission {
font-style: italic;
}
ul.cms-permissions { ul.cms-permissions {
list-style-type: none; list-style-type: none;
padding: 3px 3px 3px 3px; padding: 3px 3px 3px 3px;

View File

@@ -45,6 +45,14 @@ ul.cms-roles {
content: "[role] "; content: "[role] ";
} }
} }
table.cms-roles {
border: solid 1px black;
border-collapse: collapse;
th,td {padding: 2px; border: solid 1px black; }
td.cms_role_permission {
font-style: italic;
}
}
ul.cms-permissions { ul.cms-permissions {

View File

@@ -29,6 +29,8 @@ inherit
do_get do_get
end end
CMS_SHARED_SORTING_UTILITIES
REFACTORING_HELPER REFACTORING_HELPER
create create
@@ -54,26 +56,30 @@ feature -- execute
execute (req, res) execute (req, res)
end end
feature -- HTTP Methods feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE) do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
local local
l_response: CMS_RESPONSE l_response: CMS_RESPONSE
s: STRING s: STRING
u: CMS_USER_ROLE l_role: CMS_USER_ROLE
l_perm: READABLE_STRING_8
l_count: INTEGER l_count: INTEGER
user_api: CMS_USER_API user_api: CMS_USER_API
l_full: BOOLEAN
l_modname: STRING_8
l_mods: ARRAYED_LIST [STRING_8]
l_perms: LIST [READABLE_STRING_8]
do do
-- At the moment the template are hardcoded, but we can -- At the moment the template are hardcoded, but we can
-- get them from the configuration file and load them into -- get them from the configuration file and load them into
-- the setup class. -- the setup class.
user_api := api.user_api user_api := api.user_api
l_count := user_api.roles_count l_count := user_api.roles_count
l_full := attached {WSF_STRING} req.query_parameter ("full") as p and then p.is_case_insensitive_equal ("yes")
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty create s.make_empty
@@ -84,27 +90,93 @@ feature -- HTTP Methods
end end
if attached user_api.roles as lst then if attached user_api.roles as lst then
s.append ("<ul class=%"cms-roles%">%N") l_response.add_to_primary_tabs (api.local_link ("Permissions", l_response.location + "?full=yes"))
across l_response.add_to_primary_tabs (api.local_link ("Roles", l_response.location))
lst as ic
loop
u := ic.item
s.append ("<li class=%"cms_role%">")
s.append ("<a href=%"")
s.append (req.absolute_script_url (api.administration_path ("/role/") + u.id.out))
s.append ("%">")
s.append (html_encoded (u.name))
s.append ("</a>")
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
if l_full then
s.append ("<table class=%"cms-roles%"><tr><th>Permissions</th>")
across
lst as ic
loop
l_role := ic.item
s.append ("<th class=%"cms_role%">")
s.append ("<a href=%"")
s.append (req.absolute_script_url (api.administration_path ("/role/") + l_role.id.out))
s.append ("%">")
s.append (html_encoded (l_role.name))
s.append ("</a>")
s.append ("</th>%N")
end
s.append ("</tr>")
if attached user_api.role_permissions as l_role_permissions then
create l_mods.make (l_role_permissions.count)
across
l_role_permissions as m_ic
loop
l_modname := m_ic.key
l_mods.force (l_modname)
end
string_sorter.sort (l_mods)
across
l_mods as m_ic
loop
l_modname := m_ic.item
l_perms := l_role_permissions.item (l_modname)
s.append ("<tr><th colspan=%"" + (1 + lst.count).out + "%">")
if l_modname.is_whitespace then
s.append ("...")
else
s.append (html_encoded (l_modname))
end
s.append ("</th></tr>")
if l_perms /= Void then
across
l_perms as p_ic
loop
l_perm := p_ic.item
if not l_perm.is_whitespace then
s.append ("<tr><td class=%"cms_role_permission%">")
s.append (html_encoded (l_perm))
s.append ("</td>")
across
lst as ic
loop
l_role := ic.item
s.append ("<td>")
if l_role.has_permission (l_perm) then
s.append ("X")
end
s.append ("</td>")
end
s.append ("</tr>")
end
end
end
end
end
s.append ("</table>")
else
s.append ("<ul class=%"cms-roles%">%N")
across
lst as ic
loop
l_role := ic.item
s.append ("<li class=%"cms_role%">")
s.append ("<a href=%"")
s.append (req.absolute_script_url (api.administration_path ("/role/") + l_role.id.out))
s.append ("%">")
s.append (html_encoded (l_role.name))
s.append ("</a>")
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
end
s.append ("<br/>")
if l_response.has_permission ("admin roles") then if l_response.has_permission ("admin roles") then
s.append (l_response.link ("Add Role", api.administration_path_location ("add/role"), Void)) s.append (l_response.link ("Add Role", api.administration_path_location ("add/role"), Void))
end end
l_response.set_main_content (s) l_response.set_main_content (s)
l_response.execute l_response.execute
end end

View File

@@ -37,11 +37,26 @@ feature -- Process
b: STRING_8 b: STRING_8
uid: INTEGER_64 uid: INTEGER_64
user_api: CMS_USER_API user_api: CMS_USER_API
lnk: CMS_LINK
do do
user_api := api.user_api user_api := api.user_api
create b.make_empty create b.make_empty
uid := role_id_path_parameter (request) uid := role_id_path_parameter (request)
if uid > 0 and then attached user_api.user_role_by_id (uid.to_integer) as l_role then if uid > 0 and then attached user_api.user_role_by_id (uid.to_integer) as l_role then
if l_role.has_id then
lnk := api.administration_link (translation ("View", Void), "role/" + l_role.id.out)
lnk.set_weight (1)
add_to_primary_tabs (lnk)
lnk := api.administration_link (translation ("Edit", Void), "role/" + l_role.id.out + "/edit")
lnk.set_weight (2)
add_to_primary_tabs (lnk)
lnk := api.administration_link (translation ("Delete", Void), "role/" + l_role.id.out + "/delete")
lnk.set_weight (3)
add_to_primary_tabs (lnk)
end
fixme ("Issues with WSD_FORM_DATA.apply_to_associated_form") fixme ("Issues with WSD_FORM_DATA.apply_to_associated_form")
-- if we have a WSF_FORM_CHECKBOK_INPUT, cheked inputs, are not preserverd in case of error. -- if we have a WSF_FORM_CHECKBOK_INPUT, cheked inputs, are not preserverd in case of error.
if location.ends_with_general ("/edit") then if location.ends_with_general ("/edit") then
@@ -52,6 +67,10 @@ feature -- Process
else else
new_form new_form
end end
lnk := api.administration_link (translation ("<< Roles", Void), "roles")
lnk.set_weight (10)
add_to_primary_tabs (lnk)
end end
feature -- Process Edit feature -- Process Edit
@@ -71,11 +90,7 @@ feature -- Process Edit
f.process (Current) f.process (Current)
fd := f.last_data fd := f.last_data
end end
if a_role.has_id then
add_to_menu (api.administration_link (translation ("View", Void), "role/" + a_role.id.out), primary_tabs)
add_to_menu (api.administration_link (translation ("Edit", Void), "role/" + a_role.id.out + "/edit"), primary_tabs)
add_to_menu (api.administration_link (translation ("Delete", Void), "role/" + a_role.id.out + "/delete"), primary_tabs)
end
if attached redirection as l_location then if attached redirection as l_location then
-- FIXME: Hack for now -- FIXME: Hack for now
set_title (a_role.name) set_title (a_role.name)
@@ -102,11 +117,7 @@ feature -- Process Delete
f.process (Current) f.process (Current)
fd := f.last_data fd := f.last_data
end end
if a_role.has_id then
add_to_menu (api.administration_link (translation ("View", Void), "role/" + a_role.id.out), primary_tabs)
add_to_menu (api.administration_link (translation ("Edit", Void), "role/" + a_role.id.out + "/edit"), primary_tabs)
add_to_menu (api.administration_link (translation ("Delete", Void), "role/" + a_role.id.out + "/delete"), primary_tabs)
end
if attached redirection as l_location then if attached redirection as l_location then
-- FIXME: Hack for now -- FIXME: Hack for now
set_title (a_role.name) set_title (a_role.name)

View File

@@ -45,7 +45,6 @@ feature -- Execution
end end
end end
append_html_to_output (a_role: CMS_USER_ROLE; a_response: CMS_RESPONSE ) append_html_to_output (a_role: CMS_USER_ROLE; a_response: CMS_RESPONSE )
local local
lnk: CMS_LOCAL_LINK lnk: CMS_LOCAL_LINK
@@ -66,6 +65,9 @@ feature -- Execution
lnk.set_weight (3) lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk) a_response.add_to_primary_tabs (lnk)
end end
lnk := api.administration_link (translation ("<< Roles", Void), "roles")
lnk.set_weight (10)
add_to_primary_tabs (lnk)
create s.make_empty create s.make_empty
s.append ("<div class=%"info%"> ") s.append ("<div class=%"info%"> ")

View File

@@ -516,6 +516,7 @@ feature -- Form
create u.make (l_username) create u.make (l_username)
u.set_email (l_email.as_string_8) u.set_email (l_email.as_string_8)
u.set_password (new_random_password (u)) u.set_password (new_random_password (u))
u.mark_active
api.user_api.new_user (u) api.user_api.new_user (u)
if api.user_api.has_error then if api.user_api.has_error then
-- handle error -- handle error

View File

@@ -61,12 +61,18 @@ feature -- Execution
lnk.set_weight (2) lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk) a_response.add_to_primary_tabs (lnk)
if a_user /= Void and then a_user.id > 0 then if a_user /= Void and then a_user.id > 0 then
lnk := api.administration_link (a_response.translation ("Delete", Void), "user/" + a_user.id.out + "/delete") lnk := api.administration_link (a_response.translation ("Delete", Void), "user/" + a_user.id.out + "/delete")
lnk.set_weight (3) lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk) a_response.add_to_primary_tabs (lnk)
end end
lnk := api.administration_link (a_response.translation ("<< Users", Void), "users")
lnk.set_weight (10)
a_response.add_to_primary_tabs (lnk)
-- FIXME: [04/aug/2015] use a CMS_FORM rather than hardcoded html. -- FIXME: [04/aug/2015] use a CMS_FORM rather than hardcoded html.
-- So that other module may easily integrate them-selves to add information. -- So that other module may easily integrate them-selves to add information.
create s.make_empty create s.make_empty

View File

@@ -41,6 +41,18 @@ ul.cms-roles li.cms_role a::before {
content: "[role] "; content: "[role] ";
} }
table.cms-roles {
border: solid 1px black;
border-collapse: collapse;
}
table.cms-roles th, table.cms-roles td {
padding: 2px;
border: solid 1px black;
}
table.cms-roles td.cms_role_permission {
font-style: italic;
}
ul.cms-permissions { ul.cms-permissions {
list-style-type: none; list-style-type: none;
padding: 3px 3px 3px 3px; padding: 3px 3px 3px 3px;

View File

@@ -45,6 +45,14 @@ ul.cms-roles {
content: "[role] "; content: "[role] ";
} }
} }
table.cms-roles {
border: solid 1px black;
border-collapse: collapse;
th,td {padding: 2px; border: solid 1px black; }
td.cms_role_permission {
font-style: italic;
}
}
ul.cms-permissions { ul.cms-permissions {

View File

@@ -0,0 +1,68 @@
note
description: "Summary description for {CMS_AUTHENTICATION_API}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CMS_AUTHENTICATION_API
inherit
CMS_AUTH_API_I
create {CMS_AUTHENTICATION_MODULE}
make
feature -- Token Generation
register_user (u: CMS_TEMP_USER; a_email: READABLE_STRING_8; a_personal_information: READABLE_STRING_8)
local
l_user_api: CMS_USER_API
l_url_activate: STRING
l_url_reject: STRING
l_token: STRING
es: CMS_AUTHENTICATION_EMAIL_SERVICE
do
l_user_api := cms_api.user_api
l_user_api.new_temp_user (u)
-- Create activation token
l_token := new_token
l_user_api.new_activation (l_token, u.id)
l_url_activate := cms_api.absolute_url ("/account/activate/" + l_token, void)
l_url_reject := cms_api.absolute_url ("/account/reject/" + l_token, Void)
-- Send Email to webmaster
cms_api.log_debug ("registration", "send_register_email", Void)
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (cms_api))
es.send_account_evaluation (u, a_personal_information, l_url_activate, l_url_reject, cms_api.absolute_url ("", Void))
-- Send Email to user
cms_api.log_debug ("registration", "send_contact_email", Void)
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (cms_api))
es.send_contact_email (a_email, u, cms_api.absolute_url ("", Void))
cms_api.log ("registration", {STRING_32} "new user %"" + u.name + "%" <" + a_email + ">", {CMS_LOG}.level_info, Void)
end
new_token: STRING
-- Generate a new token activation token
local
l_token: STRING
l_security: SECURITY_PROVIDER
l_encode: URL_ENCODER
do
create l_security
l_token := l_security.token
create l_encode
from
until
l_token.same_string (l_encode.encoded_string (l_token))
loop
-- Loop ensure that we have a security token that does not contain characters that need encoding.
-- We cannot simply to an encode-decode because the email sent to the user will contain an encoded token
-- but the user will need to use an unencoded token if activation has to be done manually.
l_token := l_security.token
end
Result := l_token
end
end

View File

@@ -8,12 +8,18 @@ class
inherit inherit
CMS_MODULE CMS_MODULE
rename
module_api as auth_api
redefine redefine
initialize,
setup_hooks, setup_hooks,
permissions permissions,
auth_api
end end
CMS_ADMINISTRABLE CMS_WITH_MODULE_ADMINISTRATION
CMS_WITH_WEBAPI
CMS_HOOK_AUTO_REGISTER CMS_HOOK_AUTO_REGISTER
@@ -52,6 +58,15 @@ feature {NONE} -- Initialization
enable -- Is enabled by default enable -- Is enabled by default
end end
feature {CMS_API} -- Initialization
initialize (api: CMS_API)
-- <PRecursor>
do
create auth_api.make (api)
Precursor (api)
end
feature -- Access feature -- Access
name: STRING = "auth" name: STRING = "auth"
@@ -68,6 +83,8 @@ feature -- Access
Result.force ("view user") Result.force ("view user")
end end
auth_api: detachable CMS_AUTHENTICATION_API
feature {CMS_EXECUTION} -- Administration feature {CMS_EXECUTION} -- Administration
administration: CMS_AUTHENTICATION_MODULE_ADMINISTRATION administration: CMS_AUTHENTICATION_MODULE_ADMINISTRATION
@@ -75,6 +92,13 @@ feature {CMS_EXECUTION} -- Administration
create Result.make (Current) create Result.make (Current)
end end
feature -- Webapi
webapi: CMS_AUTHENTICATION_MODULE_WEBAPI
do
create Result.make (Current)
end
feature -- Access: docs feature -- Access: docs
root_dir: PATH root_dir: PATH
@@ -99,10 +123,12 @@ feature -- Router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API) setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor> -- <Precursor>
do do
configure_web (a_api, a_router) if attached auth_api as l_auth_api then
configure_web (l_auth_api, a_router)
end
end end
configure_web (a_api: CMS_API; a_router: WSF_ROUTER) configure_web (a_api: CMS_AUTHENTICATION_API; a_router: WSF_ROUTER)
local local
m: WSF_URI_MAPPING m: WSF_URI_MAPPING
do do
@@ -226,7 +252,7 @@ feature -- Handler
view_account_form_id: STRING = "roccms-user-view" view_account_form_id: STRING = "roccms-user-view"
edit_account_form_id: STRING = "roccms-user-edit" edit_account_form_id: STRING = "roccms-user-edit"
handle_account (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_account (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
l_user: detachable CMS_USER l_user: detachable CMS_USER
@@ -235,11 +261,11 @@ feature -- Handler
f: CMS_FORM f: CMS_FORM
tf: WSF_FORM_TEXT_INPUT tf: WSF_FORM_TEXT_INPUT
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
create b.make_empty create b.make_empty
l_user := r.user l_user := r.user
create f.make (r.location, view_account_form_id) create f.make (r.location, view_account_form_id)
if attached smarty_template_block (Current, "account_info", api) as l_tpl_block then if attached smarty_template_block (Current, "account_info", a_auth_api.cms_api) as l_tpl_block then
l_tpl_block.set_weight (-10) l_tpl_block.set_weight (-10)
r.add_block (l_tpl_block, "content") r.add_block (l_tpl_block, "content")
else else
@@ -260,12 +286,12 @@ feature -- Handler
tf.set_label ("Profile name") tf.set_label ("Profile name")
f.extend (tf) f.extend (tf)
end end
create tf.make_with_text ("creation", api.formatted_date_time_yyyy_mm_dd (l_user.creation_date)) create tf.make_with_text ("creation", a_auth_api.cms_api.formatted_date_time_yyyy_mm_dd (l_user.creation_date))
tf.set_label ("Creation date") tf.set_label ("Creation date")
f.extend (tf) f.extend (tf)
if attached l_user.last_login_date as dt then if attached l_user.last_login_date as dt then
create tf.make_with_text ("last_login", api.formatted_date_time_ago (dt)) create tf.make_with_text ("last_login", a_auth_api.cms_api.formatted_date_time_ago (dt))
tf.set_label ("Last login") tf.set_label ("Last login")
f.extend (tf) f.extend (tf)
end end
@@ -282,7 +308,7 @@ feature -- Handler
r.add_to_primary_tabs (lnk) r.add_to_primary_tabs (lnk)
end end
api.hooks.invoke_form_alter (f, Void, r) a_auth_api.cms_api.hooks.invoke_form_alter (f, Void, r)
f.append_to_html (r.wsf_theme, b) f.append_to_html (r.wsf_theme, b)
r.set_main_content (b) r.set_main_content (b)
@@ -293,7 +319,7 @@ feature -- Handler
r.execute r.execute
end end
handle_edit_account (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_edit_account (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
l_user: detachable CMS_USER l_user: detachable CMS_USER
@@ -301,11 +327,11 @@ feature -- Handler
lnk: CMS_LOCAL_LINK lnk: CMS_LOCAL_LINK
l_form: CMS_FORM l_form: CMS_FORM
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
create b.make_empty create b.make_empty
l_user := r.user l_user := r.user
create l_form.make (r.location, edit_account_form_id) create l_form.make (r.location, edit_account_form_id)
if attached smarty_template_block (Current, "account_edit", api) as l_tpl_block then if attached smarty_template_block (Current, "account_edit", a_auth_api.cms_api) as l_tpl_block then
l_tpl_block.set_weight (-10) l_tpl_block.set_weight (-10)
r.add_block (l_tpl_block, "content") r.add_block (l_tpl_block, "content")
else else
@@ -348,17 +374,17 @@ feature -- Handler
r.execute r.execute
end end
handle_login (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_login (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
do do
if api.user_is_authenticated then if a_auth_api.cms_api.user_is_authenticated then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
r.set_redirection ("account") r.set_redirection ("account")
r.execute r.execute
elseif attached api.module_by_name ("session_auth") then elseif attached a_auth_api.cms_api.module_by_name ("session_auth") then
-- FIXME: find better solution to support a default login system. -- FIXME: find better solution to support a default login system.
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if attached {WSF_STRING} req.item ("destination") as l_destination then if attached {WSF_STRING} req.item ("destination") as l_destination then
r.set_redirection ("account/auth/roc-session-login?destination=" + l_destination.url_encoded_value) r.set_redirection ("account/auth/roc-session-login?destination=" + l_destination.url_encoded_value)
else else
@@ -367,9 +393,9 @@ feature -- Handler
r.execute r.execute
elseif attached api.module_by_name ("basic_auth") then elseif attached a_auth_api.cms_api.module_by_name ("basic_auth") then
-- FIXME: find better solution to support a default login system. -- FIXME: find better solution to support a default login system.
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if attached {WSF_STRING} req.item ("destination") as l_destination then if attached {WSF_STRING} req.item ("destination") as l_destination then
r.set_redirection ("account/auth/roc-basic-login?destination=" + l_destination.url_encoded_value) r.set_redirection ("account/auth/roc-basic-login?destination=" + l_destination.url_encoded_value)
else else
@@ -378,17 +404,17 @@ feature -- Handler
r.execute r.execute
else else
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
r.execute r.execute
end end
end end
handle_logout (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_logout (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
loc: STRING loc: STRING
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if attached auth_strategy (req) as l_auth_strategy then if attached auth_strategy (req) as l_auth_strategy then
loc := l_auth_strategy loc := l_auth_strategy
else else
@@ -402,8 +428,9 @@ feature -- Handler
r.execute r.execute
end end
handle_register (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_register (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
f: CMS_FORM
r: CMS_RESPONSE r: CMS_RESPONSE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
u: CMS_TEMP_USER u: CMS_TEMP_USER
@@ -416,20 +443,29 @@ feature -- Handler
l_email: READABLE_STRING_8 l_email: READABLE_STRING_8
do do
if if
api.has_permission ("account register") and then a_auth_api.cms_api.has_permission ("account register") and then
req.is_post_request_method req.is_post_request_method
then then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create f.make (req.percent_encoded_path_info, "roccms-user-register")
f.extend_text_field ("name", Void)
f.extend_password_field ("password", Void)
f.extend_text_field ("email", Void)
f.extend_text_field ("personal_information", Void)
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
f.process (r)
if if
attached {WSF_STRING} req.form_parameter ("name") as l_name and then attached f.last_data as fd and then not fd.has_error and then
attached {WSF_STRING} req.form_parameter ("password") as l_password and then attached fd.string_item ("name") as l_name and then
attached {WSF_STRING} req.form_parameter ("email") as p_email and then attached fd.string_item ("password") as l_password and then
attached {WSF_STRING} req.form_parameter ("personal_information") as l_personal_information attached fd.string_item ("email") as s_email and then
attached fd.string_item ("personal_information") as l_personal_information
then then
if p_email.value.is_valid_as_string_8 then if s_email.is_valid_as_string_8 then
l_email := p_email.value.to_string_8 l_email := s_email.to_string_8
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if attached l_user_api.user_by_name (l_name.value) or else attached l_user_api.temp_user_by_name (l_name.value) then if attached l_user_api.user_by_name (l_name) or else attached l_user_api.temp_user_by_name (l_name) then
-- Username already exist. -- Username already exist.
r.set_value ("User name already exists!", "error_name") r.set_value ("User name already exists!", "error_name")
l_exist := True l_exist := True
@@ -439,7 +475,7 @@ feature -- Handler
r.set_value ("An account is already associated with that email address!", "error_email") r.set_value ("An account is already associated with that email address!", "error_email")
l_exist := True l_exist := True
end end
if attached recaptcha_secret_key (api) as l_recaptcha_key then if attached recaptcha_secret_key (a_auth_api.cms_api) as l_recaptcha_key then
if attached {WSF_STRING} req.form_parameter ("g-recaptcha-response") as l_recaptcha_response and then is_captcha_verified (l_recaptcha_key, l_recaptcha_response.url_encoded_value) then if attached {WSF_STRING} req.form_parameter ("g-recaptcha-response") as l_recaptcha_response and then is_captcha_verified (l_recaptcha_key, l_recaptcha_response.url_encoded_value) then
l_captcha_passed := True l_captcha_passed := True
else else
@@ -452,47 +488,35 @@ feature -- Handler
end end
if not l_exist then if not l_exist then
-- New temp user -- New temp user
create u.make (l_name.value) create u.make (l_name)
u.set_email (l_email) u.set_email (l_email)
u.set_password (l_password.value) u.set_password (l_password)
u.set_personal_information (l_personal_information.value) u.set_personal_information (l_personal_information)
l_user_api.new_temp_user (u) l_user_api.new_temp_user (u)
-- Create activation token
l_token := new_token
l_user_api.new_activation (l_token, u.id)
l_url_activate := req.absolute_script_url ("/account/activate/" + l_token)
l_url_reject := req.absolute_script_url ("/account/reject/" + l_token)
-- Send Email to webmaster
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_register_email")
es.send_account_evaluation (u, l_personal_information.value, l_url_activate, l_url_reject, req.absolute_script_url (""))
-- Send Email to user a_auth_api.register_user (u, l_email, l_personal_information)
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_email")
es.send_contact_email (l_email, u, req.absolute_script_url (""))
else else
r.set_value (l_name.value, "name") r.set_value (l_name, "name")
r.set_value (l_email, "email") r.set_value (l_email, "email")
r.set_value (l_personal_information.value, "personal_information") r.set_value (l_personal_information, "personal_information")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
else else
r.set_value (l_name.value, "name") r.set_value (l_name, "name")
r.set_value (p_email.value, "email") r.set_value (l_email, "email")
r.set_value (l_personal_information.value, "personal_information") r.set_value (l_personal_information, "personal_information")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
r.execute r.execute
else else
api.response_api.send_bad_request ("There were issue with your application, invalid or missing values.", req, res) a_auth_api.cms_api.response_api.send_bad_request ("There were issue with your application, invalid or missing values.", req, res)
end end
else else
api.response_api.send_permissions_access_denied ("You can also contact the webmaster to ask for an account.", Void, req, res) a_auth_api.cms_api.response_api.send_permissions_access_denied ("You can also contact the webmaster to ask for an account.", Void, req, res)
end end
end end
handle_activation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_activation (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
@@ -500,8 +524,8 @@ feature -- Handler
es: CMS_AUTHENTICATION_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_temp_id: INTEGER_64 l_temp_id: INTEGER_64
do do
if api.has_permission ("account activate") then if a_auth_api.cms_api.has_permission ("account activate") then
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if attached {WSF_STRING} req.path_parameter ("token") as l_token then if attached {WSF_STRING} req.path_parameter ("token") as l_token then
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_activation_token (l_token.value) as l_temp_user then if attached {CMS_TEMP_USER} l_user_api.temp_user_by_activation_token (l_token.value) as l_temp_user then
@@ -516,20 +540,25 @@ feature -- Handler
l_temp_user.mark_active l_temp_user.mark_active
l_user_api.new_user_from_temp_user (l_temp_user) l_user_api.new_user_from_temp_user (l_temp_user)
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if if
not l_user_api.has_error and then not l_user_api.has_error and then
attached l_user_api.user_by_name (l_temp_user.name) as l_new_user attached l_user_api.user_by_name (l_temp_user.name) as l_new_user
then then
if attached l_temp_user.personal_information as l_perso_info then
-- Keep personal information in profile item!
a_auth_api.cms_api.user_api.save_user_profile_item (l_new_user, "personal_information", l_perso_info)
end
-- Delete temporal User -- Delete temporal User
l_temp_user.set_id (l_temp_id) l_temp_user.set_id (l_temp_id)
l_user_api.delete_temp_user (l_temp_user) l_user_api.delete_temp_user (l_temp_user)
l_user_api.remove_activation (l_token.value) l_user_api.remove_activation (l_token.value)
r.set_main_content ("<p> The account <i>" + html_encoded (l_new_user.name) + "</i> has been activated</p>") r.set_main_content ("<p> The account <i>" + a_auth_api.cms_api.user_html_link (l_new_user) + "</i> has been activated</p>")
-- Send Email -- Send Email
if attached l_new_user.email as l_email then if attached l_new_user.email as l_email then
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (a_auth_api.cms_api))
write_debug_log (generator + ".handle register: send_contact_activation_confirmation_email") write_debug_log (generator + ".handle register: send_contact_activation_confirmation_email")
es.send_contact_activation_confirmation_email (l_email, l_new_user, req.absolute_script_url ("")) es.send_contact_activation_confirmation_email (l_email, l_new_user, req.absolute_script_url (""))
end end
@@ -542,38 +571,38 @@ feature -- Handler
end end
end end
else -- the token does not exist, or it was already used. else -- the token does not exist, or it was already used.
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
r.set_main_content ("<p>The token <i>" + l_token.value + "</i> is not valid " + r.link ("Reactivate Account", "account/reactivate", Void) + "</p>") r.set_main_content ("<p>The token <i>" + l_token.value + "</i> is not valid " + r.link ("Reactivate Account", "account/reactivate", Void) + "</p>")
end end
r.execute r.execute
else else
create l_ir.make (req, res, api) create l_ir.make (req, res, a_auth_api.cms_api)
l_ir.execute l_ir.execute
end end
else else
api.response_api.send_access_denied (Void, req, res) a_auth_api.cms_api.response_api.send_access_denied (Void, req, res)
end end
end end
handle_reject (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_reject (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
es: CMS_AUTHENTICATION_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if r.has_permission ("account reject") then if r.has_permission ("account reject") then
if attached {WSF_STRING} req.path_parameter ("token") as l_token then if attached {WSF_STRING} req.path_parameter ("token") as l_token then
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_activation_token (l_token.value) as l_user then if attached {CMS_TEMP_USER} l_user_api.temp_user_by_activation_token (l_token.value) as l_user then
l_user_api.delete_temp_user (l_user) l_user_api.delete_temp_user (l_user)
r.set_main_content ("<p> The temporal account for <i>" + html_encoded (l_user.name) + "</i> has been removed</p>") r.set_main_content ("<p> The temporal account for <i>" + html_encoded (l_user.name) + "</i> has been removed</p>")
-- Send Email -- Send Email
if attached l_user.email as l_email then if attached l_user.email as l_email then
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (a_auth_api.cms_api))
write_debug_log (generator + ".handle register: send_contact_activation_reject_email") write_debug_log (generator + ".handle register: send_contact_activation_reject_email")
es.send_contact_activation_reject_email (l_email, l_user, req.absolute_script_url ("")) es.send_contact_activation_reject_email (l_email, l_user, req.absolute_script_url (""))
end end
@@ -584,15 +613,15 @@ feature -- Handler
end end
r.execute r.execute
else else
create l_ir.make (req, res, api) create l_ir.make (req, res, a_auth_api.cms_api)
l_ir.execute l_ir.execute
end end
else else
api.response_api.send_access_denied (Void, req, res) a_auth_api.cms_api.response_api.send_access_denied (Void, req, res)
end end
end end
handle_reactivation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_reactivation (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
es: CMS_AUTHENTICATION_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
@@ -602,26 +631,26 @@ feature -- Handler
l_url_reject: STRING l_url_reject: STRING
l_email: READABLE_STRING_8 l_email: READABLE_STRING_8
do do
if api.has_permission ("account reactivate") then if a_auth_api.cms_api.has_permission ("account reactivate") then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if req.is_post_request_method then if req.is_post_request_method then
if attached {WSF_STRING} req.form_parameter ("email") as p_email then if attached {WSF_STRING} req.form_parameter ("email") as p_email then
if p_email.value.is_valid_as_string_8 then if p_email.value.is_valid_as_string_8 then
l_email := p_email.value.to_string_8 l_email := p_email.value.to_string_8
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_email (l_email) as l_user then if attached {CMS_TEMP_USER} l_user_api.temp_user_by_email (l_email) as l_user then
-- User exist create a new token and send a new email. -- User exist create a new token and send a new email.
if l_user.is_active then if l_user.is_active then
r.set_value ("The asociated user to the given email " + l_email + " , is already active", "is_active") r.set_value ("The asociated user to the given email " + l_email + " , is already active", "is_active")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
else else
l_token := new_token l_token := a_auth_api.new_token
l_user_api.new_activation (l_token, l_user.id) l_user_api.new_activation (l_token, l_user.id)
l_url_activate := req.absolute_script_url ("/account/activate/" + l_token) l_url_activate := req.absolute_script_url ("/account/activate/" + l_token)
l_url_reject := req.absolute_script_url ("/account/reject/" + l_token) l_url_reject := req.absolute_script_url ("/account/reject/" + l_token)
-- Send Email to webmaster -- Send Email to webmaster
if attached l_user.personal_information as l_personal_information then if attached l_user.personal_information as l_personal_information then
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (a_auth_api.cms_api))
write_debug_log (generator + ".handle register: send_register_email") write_debug_log (generator + ".handle register: send_register_email")
es.send_account_evaluation (l_user, l_personal_information, l_url_activate, l_url_reject, req.absolute_script_url ("")) es.send_account_evaluation (l_user, l_personal_information, l_url_activate, l_url_reject, req.absolute_script_url (""))
end end
@@ -640,11 +669,11 @@ feature -- Handler
end end
r.execute r.execute
else else
api.response_api.send_access_denied (Void, req, res) a_auth_api.cms_api.response_api.send_access_denied (Void, req, res)
end end
end end
handle_new_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_new_password (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
es: CMS_AUTHENTICATION_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
@@ -653,20 +682,20 @@ feature -- Handler
l_url: STRING l_url: STRING
l_email: READABLE_STRING_8 l_email: READABLE_STRING_8
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if req.is_post_request_method then if req.is_post_request_method then
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if attached {WSF_STRING} req.form_parameter ("email") as p_email then if attached {WSF_STRING} req.form_parameter ("email") as p_email then
if p_email.value.is_valid_as_string_8 then if p_email.value.is_valid_as_string_8 then
l_email := p_email.value.to_string_8 l_email := p_email.value.to_string_8
if attached {CMS_USER} l_user_api.user_by_email (l_email) as l_user then if attached {CMS_USER} l_user_api.user_by_email (l_email) as l_user then
-- User exist create a new token and send a new email. -- User exist create a new token and send a new email.
l_token := new_token l_token := a_auth_api.new_token
l_user_api.new_password (l_token, l_user.id) l_user_api.new_password (l_token, l_user.id)
l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token) l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token)
-- Send Email -- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (a_auth_api.cms_api))
write_debug_log (generator + ".handle register: send_contact_password_email") write_debug_log (generator + ".handle register: send_contact_password_email")
es.send_contact_password_email (l_email, l_user, l_url, req.absolute_script_url ("")) es.send_contact_password_email (l_email, l_user, l_url, req.absolute_script_url (""))
else else
@@ -685,12 +714,12 @@ feature -- Handler
attached l_user.email as l_user_email attached l_user.email as l_user_email
then then
-- User exist create a new token and send a new email. -- User exist create a new token and send a new email.
l_token := new_token l_token := a_auth_api.new_token
l_user_api.new_password (l_token, l_user.id) l_user_api.new_password (l_token, l_user.id)
l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token) l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token)
-- Send Email -- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (a_auth_api.cms_api))
write_debug_log (generator + ".handle register: send_contact_password_email") write_debug_log (generator + ".handle register: send_contact_password_email")
es.send_contact_password_email (l_user_email, l_user, l_url, req.absolute_script_url ("")) es.send_contact_password_email (l_user_email, l_user, l_url, req.absolute_script_url (""))
else else
@@ -703,13 +732,13 @@ feature -- Handler
r.execute r.execute
end end
handle_reset_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_reset_password (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if attached {WSF_STRING} req.query_parameter ("token") as l_token then if attached {WSF_STRING} req.query_parameter ("token") as l_token then
r.set_value (l_token.value, "token") r.set_value (l_token.value, "token")
if l_user_api.user_by_password_token (l_token.value) = Void then if l_user_api.user_by_password_token (l_token.value) = Void then
@@ -737,7 +766,7 @@ feature -- Handler
r.execute r.execute
end end
handle_change_field (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_change_field (a_auth_api: CMS_AUTHENTICATION_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
@@ -750,9 +779,9 @@ feature -- Handler
l_fieldname := p_field.url_encoded_value l_fieldname := p_field.url_encoded_value
end end
if l_fieldname = Void then if l_fieldname = Void then
api.response_api.send_bad_request (Void, req, res) a_auth_api.cms_api.response_api.send_bad_request (Void, req, res)
else else
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_auth_api.cms_api)
if r.is_authenticated then if r.is_authenticated then
create lnk.make ("View", "account/") create lnk.make ("View", "account/")
@@ -764,7 +793,7 @@ feature -- Handler
r.add_to_primary_tabs (lnk) r.add_to_primary_tabs (lnk)
end end
l_user_api := api.user_api l_user_api := a_auth_api.cms_api.user_api
if req.is_post_request_method then if req.is_post_request_method then
if attached r.user as l_user then if attached r.user as l_user then
if l_fieldname.is_case_insensitive_equal ("password") then if l_fieldname.is_case_insensitive_equal ("password") then
@@ -811,7 +840,7 @@ feature -- Handler
not fd.has_error and then not fd.has_error and then
attached fd.string_item ("new_profile_name") as l_new_profile_name attached fd.string_item ("new_profile_name") as l_new_profile_name
then then
check api.user_api.is_valid_profile_name (l_new_profile_name) end check a_auth_api.cms_api.user_api.is_valid_profile_name (l_new_profile_name) end
l_user.set_profile_name (l_new_profile_name) l_user.set_profile_name (l_new_profile_name)
l_user_api.update_user (l_user) l_user_api.update_user (l_user)
r.add_success_message ("Profile name updated.") r.add_success_message ("Profile name updated.")
@@ -822,7 +851,7 @@ feature -- Handler
r.set_main_content (f.to_html (r.wsf_theme)) r.set_main_content (f.to_html (r.wsf_theme))
end end
elseif l_fieldname.is_case_insensitive_equal ("username") then elseif l_fieldname.is_case_insensitive_equal ("username") then
if api.has_permission ("change own username") then if a_auth_api.cms_api.has_permission ("change own username") then
f := new_change_username_form (r) f := new_change_username_form (r)
f.process (r) f.process (r)
if if
@@ -830,8 +859,8 @@ feature -- Handler
not fd.has_error and then not fd.has_error and then
attached fd.string_item ("new_username") as l_new_username attached fd.string_item ("new_username") as l_new_username
then then
check api.user_api.is_valid_username (l_new_username) end check a_auth_api.cms_api.user_api.is_valid_username (l_new_username) end
check api.user_api.user_by_name (l_new_username) = Void end check a_auth_api.cms_api.user_api.user_by_name (l_new_username) = Void end
l_user_api.update_username (l_user, l_new_username) l_user_api.update_username (l_user, l_new_username)
r.add_success_message ("Username updated.") r.add_success_message ("Username updated.")
@@ -857,7 +886,7 @@ feature -- Handler
f := new_change_email_form (r) f := new_change_email_form (r)
f.append_to_html (r.wsf_theme, b) f.append_to_html (r.wsf_theme, b)
elseif l_fieldname.is_case_insensitive_equal_general ("new_username") then elseif l_fieldname.is_case_insensitive_equal_general ("new_username") then
if api.has_permission ("change own username") then if a_auth_api.cms_api.has_permission ("change own username") then
f := new_change_username_form (r) f := new_change_username_form (r)
f.append_to_html (r.wsf_theme, b) f.append_to_html (r.wsf_theme, b)
end end
@@ -996,30 +1025,6 @@ feature -- Handler
fs.extend_html_text ("<button type=%"submit%">Confirm</button>") fs.extend_html_text ("<button type=%"submit%">Confirm</button>")
end end
feature {NONE} -- Token Generation
new_token: STRING
-- Generate a new token activation token
local
l_token: STRING
l_security: SECURITY_PROVIDER
l_encode: URL_ENCODER
do
create l_security
l_token := l_security.token
create l_encode
from
until
l_token.same_string (l_encode.encoded_string (l_token))
loop
-- Loop ensure that we have a security token that does not contain characters that need encoding.
-- We cannot simply to an encode-decode because the email sent to the user will contain an encoded token
-- but the user will need to use an unencoded token if activation has to be done manually.
l_token := l_security.token
end
Result := l_token
end
feature {NONE} -- Block views feature {NONE} -- Block views
get_block_view_register (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE) get_block_view_register (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)

View File

@@ -22,7 +22,7 @@ feature -- Security
-- List of permission ids, used by this module, and declared. -- List of permission ids, used by this module, and declared.
do do
Result := Precursor Result := Precursor
Result.force ("admin users") Result.force ("account register")
end end
feature {NONE} -- Router/administration feature {NONE} -- Router/administration
@@ -30,18 +30,9 @@ feature {NONE} -- Router/administration
setup_webapi_router (a_router: WSF_ROUTER; a_api: CMS_API) setup_webapi_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor> -- <Precursor>
do do
a_router.handle ("/info", create {WSF_URI_AGENT_HANDLER}.make (agent handle_info (?, ?, a_api)), a_router.methods_get) if attached module.auth_api as l_auth_api then
end a_router.handle ("/account/register", create {CMS_USER_REGISTER_WEBAPI_HANDLER}.make_with_auth_api (l_auth_api), a_router.methods_post)
end
feature -- Request handling
handle_info (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
local
m: WSF_HTML_PAGE_RESPONSE
do
create m.make
m.set_body ("{%"info%":%"" + api.setup.site_name + "%"}")
res.send (m)
end end
end end

View File

@@ -0,0 +1,112 @@
note
description: "Summary description for {CMS_USER_REGISTER_WEBAPI_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_USER_REGISTER_WEBAPI_HANDLER
inherit
CMS_WEBAPI_HANDLER
WSF_URI_HANDLER
create
make_with_auth_api
feature {NONE} -- Initialization
make_with_auth_api (a_auth_api: CMS_AUTHENTICATION_API)
do
auth_api := a_auth_api
make (a_auth_api.cms_api)
end
auth_api: CMS_AUTHENTICATION_API
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute handler for `req' and respond in `res'.
do
if req.is_post_request_method then
register_user (req, res)
else
send_bad_request (Void, req, res)
end
end
register_user (req: WSF_REQUEST; res: WSF_RESPONSE)
local
f: CMS_FORM
rep: like new_webapi_response
l_user_api: CMS_USER_API
u: CMS_TEMP_USER
l_exist: BOOLEAN
l_url_activate: STRING
l_url_reject: STRING
l_token: STRING
l_captcha_passed: BOOLEAN
l_email: READABLE_STRING_8
do
if
api.has_permission ("account register") and then
req.is_post_request_method
then
create f.make (req.percent_encoded_path_info, "roccms-user-register")
f.extend_text_field ("name", Void)
f.extend_password_field ("password", Void)
f.extend_text_field ("email", Void)
f.extend_text_field ("personal_information", Void)
rep := new_webapi_response (req, res)
f.process (rep)
if
attached f.last_data as fd and then not fd.has_error and then
attached fd.string_item ("name") as l_name and then
attached fd.string_item ("password") as l_password and then
attached fd.string_item ("email") as s_email and then
attached fd.string_item ("personal_information") as l_personal_information
then
if s_email.is_valid_as_string_8 then
l_email := s_email.to_string_8
l_user_api := api.user_api
if attached l_user_api.user_by_name (l_name) or else attached l_user_api.temp_user_by_name (l_name) then
-- Username already exists.
fd.report_invalid_field ("name", "User name already exists!")
l_exist := True
end
if attached l_user_api.user_by_email (l_email) or else attached l_user_api.temp_user_by_email (l_email) then
-- Email already exists.
fd.report_invalid_field ("email", "An account is already associated with that email address!")
l_exist := True
end
if fd.has_error or l_exist then
send_bad_request ("User name or email is already taken!", req, res)
else
-- New temp user
create u.make (l_name)
u.set_email (l_email)
u.set_password (l_password)
u.set_personal_information (l_personal_information)
auth_api.register_user (u, l_email, l_personal_information)
-- add_user_links_to (u, rep)
rep.add_string_field ("status", "succeed")
rep.add_self (req.percent_encoded_path_info)
rep.execute
end
else
send_bad_request ("Invalid email", req, res)
end
else
send_bad_request ("There were issue with your application, invalid or missing values.", req, res)
end
else
send_access_denied ("You can also contact the webmaster to ask for an account.", req, res)
end
end
end

View File

@@ -134,6 +134,8 @@ feature -- Access
l_type_name := ic.item.name l_type_name := ic.item.name
if not l_type_name.is_whitespace then if not l_type_name.is_whitespace then
Result.force ("create " + l_type_name) Result.force ("create " + l_type_name)
Result.force ("delete " + l_type_name)
Result.force ("trash " + l_type_name)
Result.force ("view any " + l_type_name) Result.force ("view any " + l_type_name)
Result.force ("edit any " + l_type_name) Result.force ("edit any " + l_type_name)

View File

@@ -1,18 +0,0 @@
note
description: "Summary description for {NODE_MODULE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
NODE_MODULE
obsolete "Use {CMS_NODE_MODULE}"
inherit
CMS_NODE_MODULE
create
make
end

View File

@@ -52,6 +52,27 @@ feature -- Encoders
Result := percent_encoder.percent_encoded_string (a_string) Result := percent_encoder.percent_encoded_string (a_string)
end end
date_time_to_string (dt: DATE_TIME): STRING_8
-- Date time `dt` converted to standard output (using RFC1123)
local
hd: HTTP_DATE
do
create hd.make_from_date_time (dt)
Result := hd.rfc1123_string
end
date_time_from_string (s: READABLE_STRING_GENERAL): detachable DATE_TIME
-- Date time from string `s`, if valid.
local
hd: HTTP_DATE
do
create hd.make_from_string (s)
check not hd.has_error end
if not hd.has_error then
Result := hd.date_time
end
end
note note
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -74,12 +74,24 @@ feature -- Conversion
feature -- Basic operation feature -- Basic operation
process (a_response: CMS_RESPONSE_I)
do
if attached {CMS_RESPONSE} a_response as rep_cms then
process_cms_response (rep_cms)
else
-- FIXME: check webapi for hook need!
process_form (a_response.request, Void, Void)
end
end
feature -- CMS response
prepare (a_response: CMS_RESPONSE) prepare (a_response: CMS_RESPONSE)
do do
a_response.api.hooks.invoke_form_alter (Current, Void, a_response) a_response.api.hooks.invoke_form_alter (Current, Void, a_response)
end end
process (a_response: CMS_RESPONSE) process_cms_response (a_response: CMS_RESPONSE)
do do
process_form (a_response.request, agent on_prepared (a_response, ?), agent on_processed (a_response, ?)) process_form (a_response.request, agent on_prepared (a_response, ?), agent on_processed (a_response, ?))
end end
@@ -96,6 +108,41 @@ feature -- Basic operation
end end
end end
feature -- Webapi processing
process_webapi_response ()
do
end
feature -- Helpers
extend_text_field (a_name: READABLE_STRING_8; a_text: detachable READABLE_STRING_GENERAL)
-- Extend new text field `a_name` with value `a_text`.
local
tf: WSF_FORM_TEXT_INPUT
do
if a_text /= Void then
create tf.make_with_text (a_name, a_text.as_string_32)
else
create tf.make (a_name)
end
extend (tf)
end
extend_password_field (a_name: READABLE_STRING_8; a_text: detachable READABLE_STRING_GENERAL)
-- Extend new password field `a_name` with value `a_text`.
local
tf: WSF_FORM_PASSWORD_INPUT
do
if a_text /= Void then
create tf.make_with_text (a_name, a_text.as_string_32)
else
create tf.make (a_name)
end
extend (tf)
end
note note
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -85,7 +85,7 @@ feature {CMS_API} -- Module management
create u.make ("admin") create u.make ("admin")
u.set_password ("istrator#") u.set_password ("istrator#")
u.set_email (a_api.setup.site_email) u.set_email (a_api.setup.site_email)
u.set_status ({CMS_USER}.active) u.mark_active
a_api.user_api.new_user (u) a_api.user_api.new_user (u)
--| Node --| Node
@@ -130,6 +130,7 @@ feature -- Security
Result.force ("import core") Result.force ("import core")
Result.force ("admin path_alias") Result.force ("admin path_alias")
Result.force ("edit path_alias") Result.force ("edit path_alias")
Result.force ("use access_token")
end end
feature {CMS_EXECUTION} -- Administration feature {CMS_EXECUTION} -- Administration

View File

@@ -329,7 +329,7 @@ feature -- User roles.
loop loop
lst := ic.item.permissions lst := ic.item.permissions
if if
attached {CMS_ADMINISTRABLE} ic.item as adm and then attached {CMS_WITH_MODULE_ADMINISTRATION} ic.item as adm and then
attached adm.module_administration.permissions as adm_permissions and then attached adm.module_administration.permissions as adm_permissions and then
not adm_permissions.is_empty not adm_permissions.is_empty
then then

View File

@@ -119,17 +119,18 @@ feature -- Process Edit
ti.set_is_readonly (True) ti.set_is_readonly (True)
fs.extend (ti) fs.extend (ti)
end end
if api.user_has_permission (a_user, "use access_token") then
create l_new_access_token_form.make (api.webapi_path ("access_token"), Void) create l_new_access_token_form.make (api.webapi_path ("access_token"), Void)
l_new_access_token_form.set_method_post l_new_access_token_form.set_method_post
if l_access_token /= Void then if l_access_token /= Void then
l_new_access_token_form.extend (create {WSF_FORM_SUBMIT_INPUT}.make_with_text ("access_token_op", "Refresh Access Token")) l_new_access_token_form.extend (create {WSF_FORM_SUBMIT_INPUT}.make_with_text ("access_token_op", "Refresh Access Token"))
else else
l_new_access_token_form.extend (create {WSF_FORM_SUBMIT_INPUT}.make_with_text ("access_token_op", "Create Access Token")) l_new_access_token_form.extend (create {WSF_FORM_SUBMIT_INPUT}.make_with_text ("access_token_op", "Create Access Token"))
end
l_new_access_token_form.extend (create {WSF_FORM_HIDDEN_INPUT}.make_with_text ("destination", request.percent_encoded_path_info))
a_form.put_widget_after_form (l_new_access_token_form)
a_form.extend (fs)
end end
l_new_access_token_form.extend (create {WSF_FORM_HIDDEN_INPUT}.make_with_text ("destination", request.percent_encoded_path_info))
a_form.put_widget_after_form (l_new_access_token_form)
a_form.extend (fs)
end end
end end
end end

View File

@@ -18,6 +18,7 @@ feature -- Basic operations
-- Execute the filter. -- Execute the filter.
local local
tok: READABLE_STRING_GENERAL tok: READABLE_STRING_GENERAL
u: CMS_USER
do do
if if
attached req.http_authorization as l_auth and then attached req.http_authorization as l_auth and then
@@ -26,7 +27,10 @@ feature -- Basic operations
tok := l_auth.substring (8, l_auth.count) tok := l_auth.substring (8, l_auth.count)
if attached api.user_api.users_with_profile_item ("access_token", tok) as lst then if attached api.user_api.users_with_profile_item ("access_token", tok) as lst then
if lst.count = 1 then if lst.count = 1 then
api.set_user (lst.first) u := lst.first
if api.user_has_permission (u, "use access_token") then
api.set_user (u)
end
end end
end end
end end

View File

@@ -39,6 +39,7 @@ feature {NONE} -- Router/administration
a_router.handle ("/", l_root, a_router.methods_get) a_router.handle ("/", l_root, a_router.methods_get)
a_router.handle ("/user/{uid}/access_token", create {CMS_ACCESS_TOKEN_WEBAPI_HANDLER}.make (a_api), a_router.methods_get_post) a_router.handle ("/user/{uid}/access_token", create {CMS_ACCESS_TOKEN_WEBAPI_HANDLER}.make (a_api), a_router.methods_get_post)
a_router.handle ("/user/{uid}", create {CMS_USER_WEBAPI_HANDLER}.make (a_api), a_router.methods_get) a_router.handle ("/user/{uid}", create {CMS_USER_WEBAPI_HANDLER}.make (a_api), a_router.methods_get)
a_router.handle ("/user/", create {CMS_USERS_WEBAPI_HANDLER}.make (a_api), a_router.methods_get_post)
end end
feature -- Access: filter feature -- Access: filter

View File

@@ -21,6 +21,8 @@ feature -- Execution
do do
if req.is_get_request_method then if req.is_get_request_method then
execute_get (req, res) execute_get (req, res)
-- elseif req.is_post_request_method then
-- execute_post (req, res)
else else
send_bad_request (Void, req, res) send_bad_request (Void, req, res)
end end
@@ -45,16 +47,24 @@ feature -- Execution
if l_user /= Void then if l_user /= Void then
if l_user.same_as (u) or api.has_permissions (<<"admin users", "view users">>) then if l_user.same_as (u) or api.has_permissions (<<"admin users", "view users">>) then
rep := new_webapi_response (req, res) rep := new_webapi_response (req, res)
rep.add_string_field ("uid", u.id.out) rep.add_string_field ("uid", l_user.id.out)
rep.add_string_field ("name", l_user.name)
rep.add_string_field ("name", u.name) if attached l_user.email as l_email then
if attached u.email as l_email then
rep.add_string_field ("email", l_email) rep.add_string_field ("email", l_email)
end end
if attached u.profile_name as l_profile_name then if not l_user.is_active then
rep.add_boolean_field ("is_active", False)
end
if attached l_user.profile_name as l_profile_name then
rep.add_string_field ("profile_name", l_profile_name) rep.add_string_field ("profile_name", l_profile_name)
end end
add_user_links_to (u, rep) if attached l_user.creation_date as dt then
rep.add_string_field ("creation_date", date_time_to_string (dt))
end
if attached l_user.last_login_date as dt then
rep.add_string_field ("last_login_date", date_time_to_string (dt))
end
add_user_links_to (l_user, rep)
else else
rep := new_wepapi_error_response ("denied", req, res) rep := new_wepapi_error_response ("denied", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.user_access_denied) rep.set_status_code ({HTTP_STATUS_CODE}.user_access_denied)
@@ -74,6 +84,39 @@ feature -- Execution
end end
end end
-- execute_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- -- Execute handler for `req' and respond in `res'.
-- local
-- rep: HM_WEBAPI_RESPONSE
-- l_user: detachable CMS_USER
-- do
-- if attached api.user as u and then api.has_permission ("admin users") then
-- if attached {WSF_STRING} req.path_parameter ("uid") as p_uid then
-- if p_uid.is_integer then
-- l_user := api.user_api.user_by_id (p_uid.integer_value)
-- else
-- l_user := api.user_api.user_by_name (p_uid.value)
-- end
---- if l_user = Void and p_uid.is_case_insensitive_equal ("me") then
---- l_user := u
---- end
-- if l_user /= Void then
-- else
-- rep := new_wepapi_error_response ("Not found", req, res)
-- rep.set_status_code ({HTTP_STATUS_CODE}.not_found)
-- end
-- else
-- rep := new_wepapi_error_response ("Bad request", req, res)
-- rep.set_status_code ({HTTP_STATUS_CODE}.bad_request)
-- end
-- rep.execute
-- else
-- -- FIXME: use specific Web API response!
-- send_access_denied (Void, req, res)
-- end
-- end
note note
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -0,0 +1,175 @@
note
description: "Summary description for {CMS_USERS_WEBAPI_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_USERS_WEBAPI_HANDLER
inherit
CMS_WEBAPI_HANDLER
WSF_URI_HANDLER
create
make
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute handler for `req' and respond in `res'.
do
if req.is_get_request_method then
execute_get (req, res)
elseif req.is_post_request_method then
execute_post (req, res)
else
send_bad_request (Void, req, res)
end
end
execute_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute handler for `req' and respond in `res'.
local
rep: HM_WEBAPI_RESPONSE
l_user: detachable CMS_USER
l_params: CMS_DATA_QUERY_PARAMETERS
tb: STRING_TABLE [detachable ANY]
arr: ARRAYED_LIST [STRING_TABLE [detachable ANY]]
l_full: BOOLEAN
nb: INTEGER
do
if api.has_permissions (<<"admin users", "view users">>) then
if attached req.query_parameter ("full") as p and then p.is_case_insensitive_equal ("yes") then
l_full := True
end
rep := new_webapi_response (req, res)
nb := api.user_api.users_count
rep.add_integer_64_field ("users_count", nb)
create l_params.make (0, nb.to_natural_32)
create arr.make (nb)
across
api.user_api.recent_users (l_params) as ic
loop
l_user := ic.item
create tb.make_caseless (5)
tb.force (api.webapi_path ("user/" + l_user.id.out), "href")
tb.force (l_user.id.out, "uid")
tb.force (l_user.name, "name")
if attached l_user.profile_name as pn then
tb.force (pn, "profile_name")
end
if not l_user.is_active then
tb.force (False, "is_active")
end
if l_full then
if l_user.has_email then
tb.force (l_user.email, "email")
end
if attached l_user.creation_date as dt then
tb.force (date_time_to_string (dt), "creation_date")
end
if attached l_user.last_login_date as dt then
tb.force (date_time_to_string (dt), "last_login_date")
end
end
arr.force (tb)
end
rep.add_iterator_field ("users", arr)
rep.add_self (req.percent_encoded_path_info)
rep.execute
else
send_access_denied (Void, req, res)
end
end
execute_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute handler for `req' and respond in `res'.
local
rep: HM_WEBAPI_RESPONSE
l_user: detachable CMS_USER
f: WSF_FORM
tf: WSF_FORM_TEXT_INPUT
err: STRING_32
do
if api.has_permission ("admin users") then
create f.make (req.percent_encoded_path_info, "new-user")
create tf.make ("username"); f.extend (tf)
create tf.make ("password"); f.extend (tf)
create tf.make ("email"); f.extend (tf)
create tf.make ("profile_name"); f.extend (tf)
f.process (req, Void, Void)
if attached f.last_data as fd then
create err.make_empty
if not fd.has_error and then attached fd.string_item ("username") as l_name then
if api.user_api.user_by_id_or_name (l_name) /= Void then
err.append ("Username already used!%N")
fd.report_invalid_field ("username", "Username already used!")
else
create l_user.make (l_name)
if attached fd.string_item ("password") as l_passwd then
l_user.set_password (l_passwd)
else
err.append ("Missing password!%N")
fd.report_invalid_field ("username", "Missing password!")
end
if attached fd.string_item ("email") as l_email then
if l_email.is_valid_as_string_8 then
l_user.set_email (l_email.to_string_8)
else
err.append ("Invalid email address!%N")
end
end
if attached fd.string_item ("profile_name") as l_profile_name then
l_user.set_profile_name (l_profile_name)
end
end
end
if fd.has_error then
-- Error !
if attached fd.errors as lst then
create err.make_empty
across
lst as ic
loop
if attached ic.item.field as l_field then
err.append (l_field.name + ": ")
end
if attached ic.item.message as msg then
err.append (msg)
end
end
else
-- Keep `err`.
end
elseif l_user = Void then
err := "Invalid new user request!"
else
err := Void
l_user.mark_active
api.user_api.new_user (l_user)
if api.user_api.has_error then
err := "Could not create user!"
end
end
end
if l_user = Void or else err /= Void then
rep := new_wepapi_error_response (err, req, res)
else
rep := new_webapi_response (req, res)
rep.add_string_field ("uid", l_user.id.out)
add_user_links_to (l_user, rep)
end
rep.add_self (req.percent_encoded_path_info)
rep.execute
else
send_access_denied (Void, req, res)
end
end
note
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -527,7 +527,7 @@ feature -- CMS links
require require
u_with_name: not u.name.is_whitespace u_with_name: not u.name.is_whitespace
do do
Result := link (user_display_name (u), "user/" + u.id.out, Void) Result := link (real_user_display_name (u), "user/" + u.id.out, Void)
end end
feature -- Helpers: URLs feature -- Helpers: URLs
@@ -784,6 +784,11 @@ feature -- Logging
end end
end end
log_debug (a_category: READABLE_STRING_8; a_message: READABLE_STRING_8; a_link: detachable CMS_LINK)
do
log (a_category, a_message, {CMS_LOG}.level_debug, a_link)
end
feature -- Internationalization (i18n) feature -- Internationalization (i18n)
translation (a_text: READABLE_STRING_GENERAL; opts: detachable CMS_API_OPTIONS): STRING_32 translation (a_text: READABLE_STRING_GENERAL; opts: detachable CMS_API_OPTIONS): STRING_32
@@ -1059,7 +1064,7 @@ feature {CMS_EXECUTION} -- Hooks
loop loop
l_module := ic.item l_module := ic.item
if is_administration_mode then if is_administration_mode then
if attached {CMS_ADMINISTRABLE} l_module as adm then if attached {CMS_WITH_MODULE_ADMINISTRATION} l_module as adm then
l_module := adm.module_administration l_module := adm.module_administration
else else
l_module := Void l_module := Void

View File

@@ -194,6 +194,7 @@ feature -- Import
end end
else else
user_api.new_user (u) user_api.new_user (u)
-- FIXME: check what status to use...
a_import_ctx.log ("New user %"" + u.name + "%" -> " + u.id.out + " .") a_import_ctx.log ("New user %"" + u.name + "%" -> " + u.id.out + " .")
end end
end end

View File

@@ -6,7 +6,7 @@ note
deferred class deferred class
CMS_WITH_WEBAPI CMS_WITH_WEBAPI
feature -- Administration feature -- Webapi
module_webapi: like webapi module_webapi: like webapi
-- Associated web api module. -- Associated web api module.