Merge branch 'master' into es_17_01

# Conflicts:
#	examples/demo/demo.ecf
#	modules/node/node-safe.ecf
This commit is contained in:
2017-03-01 08:51:23 +01:00
38 changed files with 1188 additions and 225 deletions

View File

@@ -30,6 +30,7 @@
<library name="cms_feed_aggregator_module" location="..\..\modules\feed_aggregator\feed_aggregator.ecf" readonly="false"/> <library name="cms_feed_aggregator_module" location="..\..\modules\feed_aggregator\feed_aggregator.ecf" readonly="false"/>
<library name="cms_files_module" location="..\..\modules\files\files.ecf" readonly="false"/> <library name="cms_files_module" location="..\..\modules\files\files.ecf" readonly="false"/>
<library name="cms_google_search_module" location="..\..\modules\google_search\google_search.ecf" readonly="false" use_application_options="true"/> <library name="cms_google_search_module" location="..\..\modules\google_search\google_search.ecf" readonly="false" use_application_options="true"/>
<library name="cms_messaging_module" location="..\..\modules\messaging\messaging.ecf"/>
<library name="cms_model" location="..\..\library\model\cms_model.ecf" readonly="false"/> <library name="cms_model" location="..\..\library\model\cms_model.ecf" readonly="false"/>
<library name="cms_node_module" location="..\..\modules\node\node.ecf" readonly="false"/> <library name="cms_node_module" location="..\..\modules\node\node.ecf" readonly="false"/>
<library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20.ecf" readonly="false"/> <library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20.ecf" readonly="false"/>

View File

@@ -23,6 +23,7 @@
"files": { "location": "../../modules/files" }, "files": { "location": "../../modules/files" },
"custom_block": { "location": "../../modules/custom_block" }, "custom_block": { "location": "../../modules/custom_block" },
"wikitext": { "location": "../../modules/wikitext" }, "wikitext": { "location": "../../modules/wikitext" },
"messaging": { "location": "../../modules/messaging" },
"comments": { "location": "../../modules/comments" } "comments": { "location": "../../modules/comments" }
} }
} }

View File

@@ -10,7 +10,7 @@ ul.cms-users li:first-child {
border-top: none; border-top: none;
} }
ul.cms-users li.cms_user a::before { ul.cms-users li.cms_user a::before {
content: "[users] "; content: "[user] ";
} }
ul.cms-roles { ul.cms-roles {
@@ -25,7 +25,7 @@ ul.cms-roles li:first-child {
border-top: none; border-top: none;
} }
ul.cms-roles li.cms_role a::before { ul.cms-roles li.cms_role a::before {
content: "[roles] "; content: "[role] ";
} }
ul.cms-permissions { ul.cms-permissions {

View File

@@ -12,7 +12,7 @@ ul.cms-users {
} }
li.cms_user a::before { li.cms_user a::before {
content: "[users] "; content: "[user] ";
} }
} }
@@ -31,7 +31,7 @@ ul.cms-roles {
} }
li.cms_role a::before { li.cms_role a::before {
content: "[roles] "; content: "[role] ";
} }
} }

View File

@@ -0,0 +1,4 @@
.messaging-box fieldset {
overflow: scroll;
height: 250px;
}

View File

@@ -0,0 +1,6 @@
.messaging-box {
fieldset {
overflow:scroll;
height:250px;
}
}

View File

@@ -84,6 +84,7 @@ feature -- CMS modules
a_setup.register_module (create {FEED_AGGREGATOR_MODULE}.make) a_setup.register_module (create {FEED_AGGREGATOR_MODULE}.make)
-- Miscellanious -- Miscellanious
a_setup.register_module (create {CMS_MESSAGING_MODULE}.make)
a_setup.register_module (create {GOOGLE_CUSTOM_SEARCH_MODULE}.make) a_setup.register_module (create {GOOGLE_CUSTOM_SEARCH_MODULE}.make)
a_setup.register_module (create {CMS_CUSTOM_BLOCK_MODULE}.make) a_setup.register_module (create {CMS_CUSTOM_BLOCK_MODULE}.make)
a_setup.register_module (create {CMS_DEBUG_MODULE}.make) a_setup.register_module (create {CMS_DEBUG_MODULE}.make)

View File

@@ -124,6 +124,7 @@ feature -- Security
Result.force ("admin users") Result.force ("admin users")
Result.force ("admin roles") Result.force ("admin roles")
Result.force ("admin modules") Result.force ("admin modules")
Result.force ("admin cache")
Result.force ("admin core caches") Result.force ("admin core caches")
Result.force ("clear blocks cache") Result.force ("clear blocks cache")
Result.force ("admin export") Result.force ("admin export")
@@ -159,13 +160,16 @@ feature -- Hooks
-- Per module cache permission! -- Per module cache permission!
create lnk.make ("Cache", "admin/cache") create lnk.make ("Cache", "admin/cache")
lnk.set_permission_arguments (<<"admin cache">>)
admin_lnk.extend (lnk) admin_lnk.extend (lnk)
-- Per module export permission! -- Per module export permission!
create lnk.make ("Export", "admin/export") create lnk.make ("Export", "admin/export")
lnk.set_permission_arguments (<<"admin export">>)
admin_lnk.extend (lnk) admin_lnk.extend (lnk)
-- Per module import permission! -- Per module import permission!
create lnk.make ("Import", "admin/import") create lnk.make ("Import", "admin/import")
lnk.set_permission_arguments (<<"admin import">>)
admin_lnk.extend (lnk) admin_lnk.extend (lnk)
end end
end end

View File

@@ -41,11 +41,15 @@ feature -- Execution
s: STRING s: STRING
f: CMS_FORM f: CMS_FORM
do do
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) if api.has_permission ("admin cache") then
f := clear_cache_web_form (l_response) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty f := clear_cache_web_form (l_response)
f.append_to_html (l_response.wsf_theme, s) create s.make_empty
l_response.set_main_content (s) f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
end
l_response.execute l_response.execute
end end
@@ -55,23 +59,27 @@ feature -- Execution
s: STRING s: STRING
f: CMS_FORM f: CMS_FORM
do do
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) if api.has_permission ("admin cache") then
f := clear_cache_web_form (l_response) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
f.process (l_response) f := clear_cache_web_form (l_response)
if f.process (l_response)
attached f.last_data as fd and then if
fd.is_valid attached f.last_data as fd and then
then fd.is_valid
if attached fd.string_item ("op") as l_op and then l_op.same_string (text_clear_all_caches) then then
api.hooks.invoke_clear_cache (Void, l_response) if attached fd.string_item ("op") as l_op and then l_op.same_string (text_clear_all_caches) then
l_response.add_notice_message ("Caches cleared (if allowed)!") api.hooks.invoke_clear_cache (Void, l_response)
else l_response.add_notice_message ("Caches cleared (if allowed)!")
fd.report_error ("Invalid form data!") else
fd.report_error ("Invalid form data!")
end
end end
create s.make_empty
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
end end
create s.make_empty
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute l_response.execute
end end

View File

@@ -41,11 +41,15 @@ feature -- Execution
s: STRING s: STRING
f: CMS_FORM f: CMS_FORM
do do
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) if api.has_permission ("admin export") then
f := exportation_web_form (l_response) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty f := exportation_web_form (l_response)
f.append_to_html (l_response.wsf_theme, s) create s.make_empty
l_response.set_main_content (s) f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
end
l_response.execute l_response.execute
end end
@@ -56,37 +60,41 @@ feature -- Execution
f: CMS_FORM f: CMS_FORM
l_exportation: CMS_EXPORT_CONTEXT l_exportation: CMS_EXPORT_CONTEXT
do do
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) if api.has_permission ("admin export") then
f := exportation_web_form (l_response) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
f.process (l_response) f := exportation_web_form (l_response)
if f.process (l_response)
attached f.last_data as fd and then if
fd.is_valid attached f.last_data as fd and then
then fd.is_valid
if attached fd.string_item ("op") as l_op and then l_op.same_string (text_export_all_data) then then
if attached fd.string_item ("folder") as l_folder then if attached fd.string_item ("op") as l_op and then l_op.same_string (text_export_all_data) then
create l_exportation.make (api.site_location.extended ("export").extended (l_folder)) if attached fd.string_item ("folder") as l_folder then
create l_exportation.make (api.site_location.extended ("export").extended (l_folder))
else
create l_exportation.make (api.site_location.extended ("export").extended ((create {DATE_TIME}.make_now_utc).formatted_out ("yyyy-[0]mm-[0]dd---hh24-[0]mi-[0]ss")))
end
api.hooks.invoke_export_to (Void, l_exportation, l_response)
l_response.add_notice_message ("All data exported (if allowed)!")
create s.make_empty
across
l_exportation.logs as ic
loop
s.append (ic.item)
s.append ("<br/>")
s.append_character ('%N')
end
l_response.add_notice_message (s)
else else
create l_exportation.make (api.site_location.extended ("export").extended ((create {DATE_TIME}.make_now_utc).formatted_out ("yyyy-[0]mm-[0]dd---hh24-[0]mi-[0]ss"))) fd.report_error ("Invalid form data!")
end end
api.hooks.invoke_export_to (Void, l_exportation, l_response)
l_response.add_notice_message ("All data exported (if allowed)!")
create s.make_empty
across
l_exportation.logs as ic
loop
s.append (ic.item)
s.append ("<br/>")
s.append_character ('%N')
end
l_response.add_notice_message (s)
else
fd.report_error ("Invalid form data!")
end end
create s.make_empty
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
end end
create s.make_empty
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute l_response.execute
end end

View File

@@ -41,11 +41,15 @@ feature -- Execution
s: STRING s: STRING
f: CMS_FORM f: CMS_FORM
do do
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) if api.has_permission ("admin import") then
f := importation_web_form (l_response) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty f := importation_web_form (l_response)
f.append_to_html (l_response.wsf_theme, s) create s.make_empty
l_response.set_main_content (s) f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
end
l_response.execute l_response.execute
end end
@@ -57,43 +61,48 @@ feature -- Execution
l_importation: CMS_IMPORT_CONTEXT l_importation: CMS_IMPORT_CONTEXT
p: PATH p: PATH
do do
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api) if api.has_permission ("admin import") then
f := importation_web_form (l_response) create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
f.process (l_response) f := importation_web_form (l_response)
if f.process (l_response)
attached f.last_data as fd and then if
fd.is_valid attached f.last_data as fd and then
then fd.is_valid
if attached fd.string_item ("op") as l_op and then l_op.same_string (text_import_all_data) then then
if attached fd.string_item ("folder") as l_folder then if attached fd.string_item ("op") as l_op and then l_op.same_string (text_import_all_data) then
create p.make_from_string (l_folder) if attached fd.string_item ("folder") as l_folder then
create l_importation.make (api.site_location.extended (import_folder_name).extended (l_folder)) create p.make_from_string (l_folder)
if l_importation.location_exists then create l_importation.make (api.site_location.extended (import_folder_name).extended (l_folder))
l_response.add_notice_message ("Import all data (if permitted)!") if l_importation.location_exists then
api.hooks.invoke_import_from (Void, l_importation, l_response) l_response.add_notice_message ("Import all data (if permitted)!")
create s.make_empty api.hooks.invoke_import_from (Void, l_importation, l_response)
across create s.make_empty
l_importation.logs as ic across
loop l_importation.logs as ic
s.append (ic.item) loop
s.append ("<br/>") s.append (ic.item)
s.append_character ('%N') s.append ("<br/>")
s.append_character ('%N')
end
l_response.add_notice_message (s)
else
l_response.add_error_message ("Specified import folder is not found!")
fd.report_invalid_field ("folder", "Folder not found!")
end end
l_response.add_notice_message (s)
else else
l_response.add_error_message ("Specified import folder is not found!") fd.report_error ("Invalid form data!")
fd.report_invalid_field ("folder", "Folder not found!")
end end
else else
fd.report_error ("Invalid form data!") fd.report_error ("Invalid form data!")
end end
else
fd.report_error ("Invalid form data!")
end end
create s.make_empty
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
end end
create s.make_empty
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute l_response.execute
end end

View File

@@ -66,6 +66,7 @@ feature -- HTTP Methods
s_pager: STRING s_pager: STRING
l_count: INTEGER l_count: INTEGER
user_api: CMS_USER_API user_api: CMS_USER_API
l_display_name: READABLE_STRING_32
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
@@ -81,9 +82,9 @@ feature -- HTTP Methods
create s.make_empty create s.make_empty
if l_count > 1 then if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " Users") l_response.set_title ("Listing " + l_count.out + " users")
else else
l_response.set_title ("Listing " + l_count.out + " User") l_response.set_title ("A single user")
end end
create s_pager.make_empty create s_pager.make_empty
@@ -106,7 +107,13 @@ feature -- HTTP Methods
s.append ("<a href=%"") s.append ("<a href=%"")
s.append (req.absolute_script_url ("/admin/user/"+u.id.out)) s.append (req.absolute_script_url ("/admin/user/"+u.id.out))
s.append ("%">") s.append ("%">")
s.append (html_encoded (u.name)) l_display_name := user_api.user_display_name (u)
s.append (html_encoded (l_display_name))
if not l_display_name.same_string (u.name) then
s.append (" [")
s.append (html_encoded (u.name))
s.append ("]")
end
s.append ("</a>") s.append ("</a>")
if attached user_api.user_roles (u) as l_roles and then not l_roles.is_empty then if attached user_api.user_roles (u) as l_roles and then not l_roles.is_empty then
s.append (" <span class=%"cms_roles%">(") s.append (" <span class=%"cms_roles%">(")

View File

@@ -10,7 +10,7 @@ ul.cms-users li:first-child {
border-top: none; border-top: none;
} }
ul.cms-users li.cms_user a::before { ul.cms-users li.cms_user a::before {
content: "[users] "; content: "[user] ";
} }
ul.cms-roles { ul.cms-roles {
@@ -25,7 +25,7 @@ ul.cms-roles li:first-child {
border-top: none; border-top: none;
} }
ul.cms-roles li.cms_role a::before { ul.cms-roles li.cms_role a::before {
content: "[roles] "; content: "[role] ";
} }
ul.cms-permissions { ul.cms-permissions {

View File

@@ -12,7 +12,7 @@ ul.cms-users {
} }
li.cms_user a::before { li.cms_user a::before {
content: "[users] "; content: "[user] ";
} }
} }
@@ -31,7 +31,7 @@ ul.cms-roles {
} }
li.cms_role a::before { li.cms_role a::before {
content: "[roles] "; content: "[role] ";
} }
} }

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="messaging" uuid="939C9362-FD46-4B4F-BB36-A593089430AB" library_target="messaging">
<target name="messaging">
<root all_classes="true"/>
<option>
</option>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf"/>
<cluster name="src" location="src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,4 @@
.messaging-box fieldset {
overflow: scroll;
height: 250px;
}

View File

@@ -0,0 +1,6 @@
.messaging-box {
fieldset {
overflow:scroll;
height:250px;
}
}

View File

@@ -0,0 +1,17 @@
note
description: "API for the contact module."
date: "$Date$"
revision: "$Revision$"
class
CMS_MESSAGING_API
inherit
CMS_MODULE_API
REFACTORING_HELPER
create
make
end

View File

@@ -0,0 +1,381 @@
note
description: "[
Module that provides messenger functionality.
]"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
CMS_MESSAGING_MODULE
inherit
CMS_MODULE
rename
module_api as messaging_api
redefine
setup_hooks,
-- install,
initialize,
permissions,
messaging_api
end
CMS_HOOK_AUTO_REGISTER
CMS_HOOK_MENU_SYSTEM_ALTER
REFACTORING_HELPER
SHARED_LOGGER
create
make
feature {NONE} -- Initialization
make
-- Create current module
do
version := "1.0"
description := "Messaging module"
package := "messaging"
end
feature -- Access
name: STRING = "messaging"
-- <Precursor>
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
-- <Precursor>
local
l_messaging_api: like messaging_api
do
Precursor (api)
create l_messaging_api.make (api)
messaging_api := l_messaging_api
end
feature {CMS_API} -- Access: API
messaging_api: detachable CMS_MESSAGING_API
feature -- Router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- Router configuration.
local
m: WSF_URI_MAPPING
do
create m.make_trailing_slash_ignored ("/messaging", create {WSF_URI_AGENT_HANDLER}.make (agent handle_get_messaging (a_api, ?, ?)))
a_router.map (m, a_router.methods_head_get)
a_router.handle ("/messaging", create {WSF_URI_AGENT_HANDLER}.make (agent handle_post_messaging (a_api, ?, ?)), a_router.methods_put_post)
end
feature -- Security
permissions: LIST [READABLE_STRING_8]
-- List of permission ids, used by this module, and declared.
do
Result := Precursor
Result.force ("admin messaging")
Result.force ("message any user")
Result.force ("use messaging")
end
feature -- Hooks configuration
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
-- Module hooks configuration.
do
auto_subscribe_to_hooks (a_hooks)
end
feature -- Hooks
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
-- Hook execution on collection of menu contained by `a_menu_system'
-- for related response `a_response'.
do
debug ("refactor_fixme")
fixme ("add messaging to menu")
end
end
new_html_messaging_form (a_response: CMS_RESPONSE; api: CMS_API): STRING
local
f: CMS_FORM
do
a_response.add_style (a_response.url ("/module/" + name + "/files/css/messaging.css", Void), Void)
-- TODO: use template to overwrite/customize
-- if attached smarty_template_block (Current, "messaging", api) as l_tpl_block then
-- across
-- a_response.values as tb
-- loop
-- l_tpl_block.set_value (tb.item, tb.key)
-- end
-- Result := l_tpl_block.to_html (a_response.theme)
-- else
f := new_messaging_form (a_response, api)
api.hooks.invoke_form_alter (f, f.last_data, a_response)
Result := "<div class=%"messaging-box%"><h1>Send message to ...</h1>" + f.to_html (a_response.wsf_theme) + "<br/></div>"
-- end
end
new_messaging_form (a_response: CMS_RESPONSE; api: CMS_API): CMS_FORM
local
f: CMS_FORM
f_name: WSF_FORM_TEXT_INPUT
f_msg: WSF_FORM_TEXTAREA
f_submit: WSF_FORM_SUBMIT_INPUT
f_user: WSF_FORM_CHECKBOX_INPUT
f_set: WSF_FORM_FIELD_SET
l_params: CMS_DATA_QUERY_PARAMETERS
nb: INTEGER
i: INTEGER
do
create f.make (a_response.url ("messaging", Void), "messaging-form")
if attached api.user as l_current_user then
nb := api.user_api.users_count
from
create f_set.make
f_set.set_legend ("Select users")
f.extend (f_set)
i := 0
until
i > nb
loop
create l_params.make (i.to_natural_64, 25)
if attached api.user_api.recent_users (l_params) as l_users then
across
l_users as ic
loop
if l_current_user.id = ic.item.id then
else
create f_user.make_with_value ("users[]", ic.item.id.out)
f_user.set_title (api.user_api.user_display_name (ic.item))
f_set.extend (f_user)
end
end
end
i := i + 25
end
create f_name.make ("title")
f_name.set_size (80)
f_name.set_label ("Title")
f_name.set_is_required (True)
f.extend (f_name)
create f_msg.make ("message")
f_msg.set_cols (80)
f_msg.set_rows (75)
f_msg.set_label ("Message")
f_msg.set_rows (5)
f_msg.set_is_required (True)
f.extend (f_msg)
create f_submit.make_with_text ("submit-op", "Send")
f.extend (f_submit)
end
Result := f
end
handle_get_messaging (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
do
if api.has_permission ("use messaging") or api.has_permission ("message any user") then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.values.force ("messaging", "messaging")
r.set_main_content (new_html_messaging_form (r, api))
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
end
r.execute
end
handle_post_messaging (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
e: CMS_EMAIL
l_emails: ARRAYED_LIST [CMS_EMAIL]
vars: STRING_TABLE [READABLE_STRING_8]
l_messaging_email_address: READABLE_STRING_8
s: STRING
l_uid: READABLE_STRING_32
f: like new_messaging_form
l_user: detachable CMS_USER
l_email_title: READABLE_STRING_8
l_email_messg: READABLE_STRING_8
do
if api.has_permission ("message any user") then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.add_style (r.url ("/module/" + name + "/files/css/messaging.css", Void), Void)
create s.make_empty
f := new_messaging_form (r, api)
f.process (r)
if attached f.last_data as fd then
if
not fd.has_error and then
attached fd.string_item ("title") as l_title and then
attached fd.string_item ("message") as l_message and then
attached fd.table_item ("users") as l_users
then
create l_emails.make (l_users.count)
s.append ("Send message %"")
s.append (r.html_encoded (l_title))
s.append ("%"")
s.append (" to users: <ul>")
across
l_users as ic
loop
if attached {WSF_STRING} ic.item as p_uid then
l_uid := p_uid.value
if l_uid.is_integer_64 then
l_user := api.user_api.user_by_id (l_uid.to_integer_64)
else
l_user := api.user_api.user_by_name (l_uid)
end
s.append ("<li>")
if l_user /= Void and then attached l_user.email as l_user_email then
s.append (r.html_encoded (api.user_api.user_display_name (l_user)))
s.append (" &lt;")
s.append (r.html_encoded (l_user_email))
s.append ("&gt;")
l_email_title := resolved_template_text (api, l_title, l_user)
l_email_messg := resolved_template_text (api, l_message, l_user)
e := api.new_email (l_user_email, l_email_title, l_email_messg)
s.append (" <pre>")
s.append (e.message)
s.append ("</pre>")
l_emails.force (e)
api.process_email (e)
if e.is_sent then
s.append (" successfully sent.")
else
s.append (" failure, not sent!")
end
else
s.append (r.html_encoded (p_uid.value))
s.append (" skipped!")
end
s.append ("</li>%N")
end
end
else
f.append_to_html (r.wsf_theme, s)
end
end
r.set_main_content (s)
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
end
r.execute
end
feature {NONE} -- Helpers
form_parameters_as_string (req: WSF_REQUEST): STRING
do
create Result.make_empty
across req.form_parameters as ic loop
Result.append (ic.item.key)
Result.append_character ('=')
Result.append_string (ic.item.string_representation)
Result.append_character ('%N')
end
end
feature {NONE} -- Contact Message
resolved_template_text (api: CMS_API; a_text: READABLE_STRING_GENERAL; a_target_user: detachable CMS_USER): STRING_8
local
smt: CMS_SMARTY_TEMPLATE_TEXT
utf: UTF_CONVERTER
do
create smt.make (utf.utf_32_string_to_utf_8_string_8 (a_text))
across
api.builtin_variables as vars_ic
loop
smt.set_value (vars_ic.item, vars_ic.key)
end
if a_target_user /= Void then
smt.set_value (a_target_user.name, "target_user_name")
smt.set_value (api.user_api.user_display_name (a_target_user), "target_user_profile_name")
smt.set_value (a_target_user.id.out, "target_user_id")
if attached a_target_user.email as l_email then
smt.set_value (l_email, "target_user_email")
end
end
Result := smt.string
end
-- email_html_message (a_message_id: READABLE_STRING_8; a_response: CMS_RESPONSE; a_html_encoded_values: STRING_TABLE [READABLE_STRING_8]): STRING
-- -- html message related to `a_message_id'.
-- local
-- res: PATH
-- p: detachable PATH
-- tpl: CMS_SMARTY_TEMPLATE_BLOCK
-- exp: CMS_STRING_EXPANDER [STRING_8]
-- do
-- write_debug_log (generator + ".email_html_message for [" + a_message_id + " ]")
-- create res.make_from_string ("templates")
-- res := res.extended ("email_").appended (a_message_id).appended_with_extension ("tpl")
-- p := a_response.api.module_theme_resource_location (Current, res)
-- if p /= Void then
-- if attached p.entry as e then
-- create tpl.make (a_message_id, Void, p.parent, e)
-- write_debug_log (generator + ".email_html_message from smarty template:" + tpl.out)
-- else
-- create tpl.make (a_message_id, Void, p.parent, p)
-- write_debug_log (generator + ".email_html_message from smarty template:" + tpl.out)
-- end
-- across
-- a_html_encoded_values as ic
-- loop
-- tpl.set_value (ic.item, ic.key)
-- end
-- Result := tpl.to_html (a_response.theme)
-- else
-- if a_message_id.is_case_insensitive_equal_general ("message") then
-- create Result.make_from_string (messaging_message_template)
-- elseif a_message_id.is_case_insensitive_equal_general ("notification") then
-- create Result.make_from_string (messaging_notification_message_template)
-- else
-- create Result.make_from_string (a_message_id)
-- across
-- a_html_encoded_values as ic
-- loop
-- Result.append ("<li>")
-- Result.append (html_encoded (ic.key))
-- Result.append (": ")
-- Result.append (ic.item) -- Already html encoded.
-- Result.append ("</li>%N")
-- end
-- end
-- create exp.make
-- across
-- a_html_encoded_values as ic
-- loop
-- exp.put (ic.item, ic.key)
-- end
-- exp.expand_string (Result)
-- write_debug_log (generator + ".email_html_message using built-in message:" + Result)
-- end
-- end
end

View File

@@ -153,6 +153,11 @@ feature -- Access: Node
Result := node_storage.nodes_count Result := node_storage.nodes_count
end end
nodes_of_type_count (a_content_type: CMS_CONTENT_TYPE): NATURAL_64
do
Result := node_storage.nodes_of_type_count (a_content_type)
end
nodes: LIST [CMS_NODE] nodes: LIST [CMS_NODE]
-- List of nodes. -- List of nodes.
do do
@@ -179,6 +184,12 @@ feature -- Access: Node
Result := node_storage.recent_nodes (params.offset.to_integer_32, params.size.to_integer_32) Result := node_storage.recent_nodes (params.offset.to_integer_32, params.size.to_integer_32)
end end
recent_nodes_of_type (a_content_type: CMS_CONTENT_TYPE; params: CMS_DATA_QUERY_PARAMETERS): ITERABLE [CMS_NODE]
-- Most recent `a_content_type` nodes according to `params.offset' and `params.size'.
do
Result := node_storage.recent_nodes_of_type (a_content_type, params.offset.to_integer_32, params.size.to_integer_32)
end
recent_node_changes_before (params: CMS_DATA_QUERY_PARAMETERS; a_date: DATE_TIME): ITERABLE [CMS_NODE] recent_node_changes_before (params: CMS_DATA_QUERY_PARAMETERS; a_date: DATE_TIME): ITERABLE [CMS_NODE]
-- List of recent changes, before `a_date', according to `params' settings. -- List of recent changes, before `a_date', according to `params' settings.
do do
@@ -356,6 +367,85 @@ feature -- Change: Node
error_handler.append (node_storage.error_handler) error_handler.append (node_storage.error_handler)
end end
feature -- path_alias suggestion
path_alias_uri_suggestion (a_node: detachable CMS_NODE; a_content_type: CMS_CONTENT_TYPE): STRING
local
dt: DATE_TIME
uri: URI
do
create uri.make_from_string ("/")
uri.add_unencoded_path_segment (a_content_type.name)
if a_node /= Void then
dt := a_node.creation_date
else
create dt.make_now_utc
end
if attached cms_api.user as u and then not cms_api.user_api.is_admin_user (u) then
uri.add_unencoded_path_segment (cms_api.user_api.user_display_name (u))
end
uri.add_unencoded_path_segment (dt.year.out)
if dt.month <= 9 then
uri.add_unencoded_path_segment ("0" + dt.month.out)
else
uri.add_unencoded_path_segment (dt.month.out)
end
if a_node /= Void and then attached a_node.title as l_title then
uri.add_unencoded_path_segment (safe_path_alias_uri_segment_text (l_title))
else
uri.add_unencoded_path_segment ("")
end
Result := uri.string
end
safe_path_alias_uri_segment_text (s: READABLE_STRING_GENERAL): STRING_32
local
i,n: INTEGER
c, prev: CHARACTER_32
l_words: ITERABLE [READABLE_STRING_GENERAL]
w: STRING_32
do
l_words := << "a", "an", "as", "at", "before", "but", "by", "for", "from", "is", "in", "into", "like", "of", "off", "on", "onto", "per", "since", "than", "the", "this", "that", "to", "up", "via", "with" >>
from
i := 1
n := s.count
create Result.make (n)
create w.make_empty
until
i > n
loop
c := s[i].as_lower
if c.is_alpha_numeric then
w.append_character (c)
prev := c
else
if w.is_empty then
-- Ignore
else
if across l_words as ic some w.same_string_general (ic.item) end then
-- Ignore
w.wipe_out
else
if not Result.is_empty then
Result.append_character ('-')
end
Result.append (w)
w.wipe_out
end
end
end
i := i + 1
end
if not w.is_empty then
if not Result.is_empty then
Result.append_character ('-')
end
Result.append (w)
w.wipe_out
end
end
feature -- Node status feature -- Node status
Not_published: INTEGER = 0 Not_published: INTEGER = 0

View File

@@ -150,13 +150,13 @@ feature -- Access
Result.force ("restore own " + l_type_name) Result.force ("restore own " + l_type_name)
Result.force ("view unpublished " + l_type_name) Result.force ("view unpublished " + l_type_name)
Result.force ("view revisions own " + l_type_name) Result.force ("view revisions own " + l_type_name)
Result.force ("export " + l_type_name) Result.force ("export " + l_type_name)
end end
end end
Result.force ("view trash") Result.force ("view trash")
Result.force ("view own trash")
end end
end end
@@ -195,6 +195,7 @@ feature -- Access: router
create l_nodes_handler.make (a_api, a_node_api) create l_nodes_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/nodes", l_nodes_handler) create l_uri_mapping.make_trailing_slash_ignored ("/nodes", l_nodes_handler)
a_router.map (l_uri_mapping, a_router.methods_get) a_router.map (l_uri_mapping, a_router.methods_get)
a_router.handle ("/nodes/{type}", l_nodes_handler, a_router.methods_get)
-- Trash -- Trash
create l_trash_handler.make (a_api, a_node_api) create l_trash_handler.make (a_api, a_node_api)

View File

@@ -92,7 +92,15 @@ feature -- Status reports
do do
Result := status = {CMS_NODE_API}.published Result := status = {CMS_NODE_API}.published
ensure ensure
Result implies not is_trashed Result implies not is_trashed and not is_not_published
end
is_not_published: BOOLEAN
-- Is Current not published?
do
Result := status = {CMS_NODE_API}.not_published
ensure
Result implies not is_published
end end
is_trashed: BOOLEAN is_trashed: BOOLEAN

View File

@@ -107,10 +107,14 @@ feature -- Forms ...
populate_form_with_path_alias (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE) populate_form_with_path_alias (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
local local
ti: WSF_FORM_TEXT_INPUT ti: WSF_FORM_TEXT_INPUT
thi: WSF_FORM_HIDDEN_INPUT
l_uri: detachable READABLE_STRING_8 l_uri: detachable READABLE_STRING_8
l_iri: detachable READABLE_STRING_32 l_iri: detachable READABLE_STRING_32
l_auto_path_alias: READABLE_STRING_8
do do
-- Path alias -- Path alias
l_auto_path_alias := node_api.path_alias_uri_suggestion (a_node, content_type)
create ti.make ("path_alias") create ti.make ("path_alias")
ti.set_label ("Path") ti.set_label ("Path")
ti.set_pattern ("^([A-Za-z0-9-_+ ]).+") ti.set_pattern ("^([A-Za-z0-9-_+ ]).+")
@@ -119,13 +123,19 @@ feature -- Forms ...
if a_node /= Void and then a_node.has_id then if a_node /= Void and then a_node.has_id then
if attached a_node.link as lnk then if attached a_node.link as lnk then
l_uri := lnk.location l_uri := lnk.location
if l_uri.same_string (node_api.node_path (a_node)) then
l_uri := ""
end
else else
l_iri := percent_encoder.percent_decoded_string (response.api.location_alias (response.node_api.node_path (a_node))) l_iri := percent_encoder.percent_decoded_string (response.api.location_alias (response.node_api.node_path (a_node)))
l_uri := l_iri.to_string_8 l_uri := l_iri.to_string_8
end end
ti.set_text_value (l_uri) ti.set_description ("Optionally specify an alternative URL path by which this content can be accessed.<br/>%NFor example, type 'about' when writing an about page. Use a relative path or the URL alias won't work.")
ti.set_description ("Optionally specify an alternative URL path by which this content can be accessed. For example, type 'about' when writing an about page. Use a relative path or the URL alias won't work.") else
l_uri := ""
end end
ti.set_text_value (l_uri)
ti.set_placeholder (l_auto_path_alias)
ti.set_validation_action (agent (fd: WSF_FORM_DATA; ia_response: NODE_RESPONSE; ia_node: detachable CMS_NODE) ti.set_validation_action (agent (fd: WSF_FORM_DATA; ia_response: NODE_RESPONSE; ia_node: detachable CMS_NODE)
do do
if if
@@ -163,6 +173,11 @@ feature -- Forms ...
else else
f.extend (ti) f.extend (ti)
end end
-- Auto path alias / suggestion
create thi.make ("auto_path_alias")
thi.set_text_value (l_auto_path_alias)
thi.set_is_readonly (True)
f.insert_after (thi, ti)
end end
update_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: CMS_NODE) update_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: CMS_NODE)
@@ -291,9 +306,12 @@ feature -- Output
a_response.add_to_primary_tabs (lnk) a_response.add_to_primary_tabs (lnk)
if a_node.status = {CMS_NODE_API}.trashed then if a_node.status = {CMS_NODE_API}.trashed then
create lnk.make ("Delete", l_node_api.node_path (a_node) + "/delete") create lnk.make ("Restore", l_node_api.node_path (a_node) + "/trash")
lnk.set_weight (2) lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk) a_response.add_to_primary_tabs (lnk)
create lnk.make ("Delete", l_node_api.node_path (a_node) + "/delete")
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
elseif a_node.has_id then elseif a_node.has_id then
-- Node in {{CMS_NODE_API}.published} or {CMS_NODE_API}.not_published} status. -- Node in {{CMS_NODE_API}.published} or {CMS_NODE_API}.not_published} status.
create lnk.make ("Edit", l_node_api.node_path (a_node) + "/edit") create lnk.make ("Edit", l_node_api.node_path (a_node) + "/edit")
@@ -320,7 +338,17 @@ feature -- Output
if is_teaser then if is_teaser then
a_output.append (" cms-teaser") a_output.append (" cms-teaser")
end end
a_output.append ("cms-node node-" + a_node.content_type + "%">") a_output.append ("cms-node node-" + a_node.content_type)
if a_node.is_published then
a_output.append (" cms-status-published")
elseif a_node.is_trashed then
a_output.append (" cms-status-trashed")
elseif a_node.is_not_published then
a_output.append (" cms-status-unpublished")
else
a_output.append (" cms-status-" + a_node.status.out)
end
a_output.append ("%">")
a_output.append ("<div class=%"info%"> ") a_output.append ("<div class=%"info%"> ")
if attached a_node.author as l_author then if attached a_node.author as l_author then
@@ -430,6 +458,4 @@ feature -- Output
end end
a_output.append ("</li>") a_output.append ("</li>")
end end
end end

View File

@@ -159,7 +159,6 @@ feature {NONE} -- Create a new node
end end
end end
delete_node (a_node: CMS_NODE; a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING_8) delete_node (a_node: CMS_NODE; a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING_8)
local local
f: like new_edit_form f: like new_edit_form
@@ -187,7 +186,7 @@ feature {NONE} -- Create a new node
f.append_to_html (wsf_theme, b) f.append_to_html (wsf_theme, b)
end end
else else
-- b.append ("ERROR: node is not in the trash!")
end end
end end
@@ -254,7 +253,7 @@ feature -- Form
l_node: detachable CMS_NODE l_node: detachable CMS_NODE
s: STRING s: STRING
l_node_path: READABLE_STRING_8 l_node_path: READABLE_STRING_8
l_path_alias, l_existing_path_alias: detachable READABLE_STRING_8 l_path_alias, l_existing_path_alias, l_auto_path_alias: detachable READABLE_STRING_8
do do
fixme ("Refactor code per operacion: Preview, Save") fixme ("Refactor code per operacion: Preview, Save")
l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview") l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview")
@@ -302,10 +301,13 @@ feature -- Form
add_success_message ("Node #" + l_node.id.out + " saved.") add_success_message ("Node #" + l_node.id.out + " saved.")
end end
-- Path aliase
l_node_path := node_api.node_path (l_node)
l_existing_path_alias := api.location_alias (l_node_path)
l_auto_path_alias := node_api.path_alias_uri_suggestion (l_node, a_type)
if attached fd.string_item ("path_alias") as f_path_alias then if attached fd.string_item ("path_alias") as f_path_alias then
l_node_path := node_api.node_path (l_node)
l_path_alias := percent_encoder.partial_encoded_string (f_path_alias, <<'/'>>) l_path_alias := percent_encoder.partial_encoded_string (f_path_alias, <<'/'>>)
l_existing_path_alias := api.location_alias (l_node_path)
if if
l_existing_path_alias /= Void and then l_existing_path_alias /= Void and then
l_path_alias.same_string (l_existing_path_alias) l_path_alias.same_string (l_existing_path_alias)
@@ -315,7 +317,10 @@ feature -- Form
elseif l_existing_path_alias /= Void and then l_path_alias.is_whitespace then elseif l_existing_path_alias /= Void and then l_path_alias.is_whitespace then
-- Reset to builtin alias. -- Reset to builtin alias.
if api.has_permission ("edit path_alias") then if api.has_permission ("edit path_alias") then
api.set_path_alias (l_node_path, l_node_path, True) api.set_path_alias (l_node_path, l_auto_path_alias, True)
elseif l_existing_path_alias.same_string (l_node_path) then
-- not aliased! Use default.
api.set_path_alias (l_node_path, l_auto_path_alias, True)
else else
add_error_message ("Permission denied to reset path alias on node #" + l_node.id.out + "!") add_error_message ("Permission denied to reset path alias on node #" + l_node.id.out + "!")
end end
@@ -330,6 +335,12 @@ feature -- Form
l_node.set_link (node_api.node_link (l_node)) l_node.set_link (node_api.node_link (l_node))
end end
end end
elseif l_existing_path_alias /= Void then
l_node.set_link (create {CMS_LOCAL_LINK}.make (l_node.title, l_existing_path_alias))
elseif l_auto_path_alias /= Void then
-- Use auto path alias
api.set_path_alias (l_node_path, l_auto_path_alias, True)
l_node.set_link (create {CMS_LOCAL_LINK}.make (l_node.title, l_auto_path_alias))
else else
l_node.set_link (node_api.node_link (l_node)) l_node.set_link (node_api.node_link (l_node))
end end
@@ -381,7 +392,7 @@ feature -- Form
create f.make (a_url, a_name) create f.make (a_url, a_name)
f.extend_html_text ("<br/>") f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Are you sure you want to delete?</legend>") f.extend_html_text ("<legend>Are you sure you want to delete? (impossible to undo)</legend>")
-- TODO check if we need to check for has_permissions!! -- TODO check if we need to check for has_permissions!!
if if
@@ -400,46 +411,42 @@ feature -- Form
ts.set_formmethod ("GET") ts.set_formmethod ("GET")
f.extend (ts) f.extend (ts)
end end
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Do you want to restore the current node?</legend>")
if
a_node /= Void and then
a_node.id > 0
then
create ts.make ("op")
ts.set_default_value ("Restore")
ts.set_formaction ("/node/"+a_node.id.out+"/delete")
ts.set_formmethod ("POST")
fixme ("[
ts.set_default_value (translation ("Restore"))
]")
f.extend (ts)
end
Result := f Result := f
end end
new_trash_form (a_node: CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_node_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM
new_trash_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_node_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM -- Create a web form named `a_name' for node `a_node', using form action url `a_url', and for type of node `a_node_type'.
-- Create a web form named `a_name' for node `a_node' (if set), using form action url `a_url', and for type of node `a_node_type'.
local local
f: CMS_FORM f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT ts: WSF_FORM_SUBMIT_INPUT
do do
create f.make (a_url, a_name) create f.make (a_url, a_name)
f.set_method_post
f.extend_html_text ("<br/>") f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Are you sure you want to trash the current node?</legend>") if a_node.is_trashed then
if f.extend_html_text ("<legend>Are you sure you want to restore the current node?</legend>")
a_node /= Void and then
a_node.id > 0
then
create ts.make ("op") create ts.make ("op")
ts.set_default_value ("Trash") ts.set_default_value ("Restore")
ts.set_formaction ("/node/" + a_node.id.out + "/trash")
ts.set_formmethod ("POST")
fixme ("[ fixme ("[
ts.set_default_value (translation ("Trash")) ts.set_default_value (translation ("Trash"))
]") ]")
f.extend (ts) else
f.extend_html_text ("<legend>Are you sure you want to trash the current node?</legend>")
create ts.make ("op")
ts.set_default_value ("Trash")
ts.set_formaction ("/node/" + a_node.id.out + "/trash")
ts.set_formmethod ("POST")
fixme ("[
ts.set_default_value (translation ("Trash"))
]")
end end
f.extend (ts)
Result := f Result := f
end end

View File

@@ -174,18 +174,20 @@ feature -- HTTP Methods
l_op.value.same_string ("Delete") l_op.value.same_string ("Delete")
then then
do_delete (req, res) do_delete (req, res)
elseif else
attached {WSF_STRING} req.form_parameter ("op") as l_op and then send_bad_request (req, res)
l_op.value.same_string ("Restore")
then
do_restore (req, res)
end end
elseif req.percent_encoded_path_info.ends_with ("/trash") then elseif req.percent_encoded_path_info.ends_with ("/trash") then
if if attached {WSF_STRING} req.form_parameter ("op") as l_op then
attached {WSF_STRING} req.form_parameter ("op") as l_op and then if l_op.is_case_insensitive_equal ("Trash") then
l_op.value.same_string ("Trash") do_trash (req, res)
then elseif l_op.is_case_insensitive_equal ("Restore") then
do_trash (req, res) do_restore (req, res)
else
send_bad_request (req, res)
end
else
send_bad_request (req, res)
end end
elseif req.percent_encoded_path_info.starts_with ("/node/add/") then elseif req.percent_encoded_path_info.starts_with ("/node/add/") then
create edit_response.make (req, res, api, node_api) create edit_response.make (req, res, api, node_api)
@@ -206,6 +208,14 @@ feature -- HTTP Methods
send_not_implemented ("REST API not yet implemented", req, res) send_not_implemented ("REST API not yet implemented", req, res)
end end
process_node_creation (req: WSF_REQUEST; res: WSF_RESPONSE; a_user: CMS_USER)
do
to_implement ("REST API")
send_not_implemented ("REST API not yet implemented", req, res)
end
feature {NONE} -- Trash:Restore
do_trash (req: WSF_REQUEST; res: WSF_RESPONSE) do_trash (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Trash a node, soft delete. -- Trash a node, soft delete.
do do
@@ -233,14 +243,6 @@ feature -- HTTP Methods
end end
end end
process_node_creation (req: WSF_REQUEST; res: WSF_RESPONSE; a_user: CMS_USER)
do
to_implement ("REST API")
send_not_implemented ("REST API not yet implemented", req, res)
end
feature {NONE} -- Trash:Restore
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE) do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Delete a node from the database. -- Delete a node from the database.
local local
@@ -283,7 +285,7 @@ feature {NONE} -- Trash:Restore
then then
if node_api.has_permission_for_action_on_node ("restore", l_node, l_user) then if node_api.has_permission_for_action_on_node ("restore", l_node, l_user) then
node_api.restore_node (l_node) node_api.restore_node (l_node)
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url (""))) res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("/" + node_api.node_path (l_node))))
else else
send_access_denied (req, res) send_access_denied (req, res)
-- send_not_authorized ? -- send_not_authorized ?

View File

@@ -11,7 +11,16 @@ inherit
WSF_URI_HANDLER WSF_URI_HANDLER
rename rename
new_mapping as new_uri_mapping new_mapping as new_uri_mapping,
execute as execute_uri
end
WSF_URI_TEMPLATE_HANDLER
rename
new_mapping as new_uri_template_mapping,
execute as execute_uri_template
select
new_uri_template_mapping
end end
WSF_RESOURCE_HANDLER_HELPER WSF_RESOURCE_HANDLER_HELPER
@@ -26,6 +35,16 @@ create
feature -- execute feature -- execute
execute_uri (req: WSF_REQUEST; res: WSF_RESPONSE)
do
execute (req, res)
end
execute_uri_template (req: WSF_REQUEST; res: WSF_RESPONSE)
do
execute (req, res)
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE) execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler -- Execute request handler
do do
@@ -39,30 +58,57 @@ feature -- HTTP Methods
local local
l_response: CMS_RESPONSE l_response: CMS_RESPONSE
s: STRING s: STRING
l_content_type: detachable CMS_CONTENT_TYPE
n: CMS_NODE n: CMS_NODE
lnk: CMS_LOCAL_LINK lnk: CMS_LOCAL_LINK
l_page_helper: CMS_PAGINATION_GENERATOR l_page_helper: CMS_PAGINATION_GENERATOR
s_pager: STRING s_pager: STRING
l_count: NATURAL_64 l_count: NATURAL_64
inc: BOOLEAN
l_include_trashed: BOOLEAN l_include_trashed: BOOLEAN
lst: detachable ITERABLE [CMS_NODE]
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.
if attached {WSF_STRING} req.path_parameter ("type") as p_node_type and then attached api.content_type (p_node_type.value) as ct then
l_count := node_api.nodes_count l_content_type := api.content_type (p_node_type.value)
end
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
if l_count > 1 then across
l_response.set_title ("Listing " + l_count.out + " nodes") api.content_types as ic
else loop
l_response.set_title ("Listing " + l_count.out + " node") if attached {CMS_NODE_TYPE [CMS_NODE]} ic.item as l_note_type then
create lnk.make (l_note_type.name, "nodes/" + l_note_type.name)
if l_note_type = l_content_type then
lnk.set_is_active (True)
end
l_response.add_to_primary_tabs (lnk)
end
end end
create s_pager.make_empty create s_pager.make_empty
create l_page_helper.make ("nodes/?page={page}&size={size}", node_api.nodes_count, 25) -- FIXME: Make this default page size a global CMS settings if l_content_type /= Void then
l_count := node_api.nodes_of_type_count (l_content_type)
if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " " + l_content_type.name + " nodes")
else
l_response.set_title ("Listing " + l_count.out + " " + l_content_type.name + " node")
end
create l_page_helper.make ("nodes/" + l_content_type.name + "/?page={page}&size={size}", l_count, 25) -- FIXME: Make this default page size a global CMS settings
else
l_count := node_api.nodes_count
if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " nodes")
else
l_response.set_title ("Listing " + l_count.out + " node")
end
create l_page_helper.make ("nodes/?page={page}&size={size}", l_count, 25) -- FIXME: Make this default page size a global CMS settings
end
l_page_helper.get_setting_from_request (req) l_page_helper.get_setting_from_request (req)
if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then
l_page_helper.append_to_html (l_response, s_pager) l_page_helper.append_to_html (l_response, s_pager)
@@ -71,7 +117,12 @@ feature -- HTTP Methods
end end
end end
if attached node_api.recent_nodes (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size)) as lst then if l_content_type /= Void then
lst := node_api.recent_nodes_of_type (l_content_type, create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size))
else
lst := node_api.recent_nodes (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size))
end
if lst /= Void then
if attached {WSF_STRING} req.query_parameter ("include_trash") as v and then v.is_case_insensitive_equal ("yes") then if attached {WSF_STRING} req.query_parameter ("include_trash") as v and then v.is_case_insensitive_equal ("yes") then
l_include_trashed := l_response.has_permissions (<<"view trash", "view any trash">>) l_include_trashed := l_response.has_permissions (<<"view trash", "view any trash">>)
end end
@@ -80,7 +131,14 @@ feature -- HTTP Methods
lst as ic lst as ic
loop loop
n := ic.item n := ic.item
if not n.is_trashed or else l_include_trashed then inc := True
if not n.is_published then
inc := view_unpublished_node_permitted (n)
end
if inc and n.is_trashed then
inc := l_include_trashed
end
if inc then
lnk := node_api.node_link (n) lnk := node_api.node_link (n)
s.append ("<li class=%"cms_type_"+ n.content_type) s.append ("<li class=%"cms_type_"+ n.content_type)
if not n.is_published then if not n.is_published then
@@ -131,4 +189,15 @@ feature -- HTTP Methods
l_response.execute l_response.execute
end end
feature -- Helper
view_unpublished_node_permitted (n: CMS_NODE): BOOLEAN
do
if api.has_permission ("view unpublished " + n.content_type) then
Result := True
elseif attached api.user as u then
Result := u.same_as (n.author)
end
end
end end

View File

@@ -22,6 +22,7 @@
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf"/> <library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf"/>
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter.ecf"/> <library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/> <library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/> <library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension.ecf" readonly="false"/> <library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension.ecf" readonly="false"/>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html.ecf" readonly="false"/> <library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html.ecf" readonly="false"/>

View File

@@ -100,6 +100,13 @@ feature -- Access
deferred deferred
end end
recent_nodes_of_type (a_node_type: CMS_CONTENT_TYPE; a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- Recent `a_count` nodes of type `a_node_type` with an offset of `lower`.
deferred
ensure
across Result as ic all ic.item.is_typed_as (a_node_type.name) end
end
recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE] recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE]
-- List of recent changes, before `a_date', according to `params' settings. -- List of recent changes, before `a_date', according to `params' settings.
deferred deferred
@@ -120,6 +127,12 @@ feature -- Access
deferred deferred
end end
nodes_of_type_count (a_node_type: CMS_CONTENT_TYPE): NATURAL_64
-- Count of nodes of type `a_node_type`.
do
Result := nodes_of_type (a_node_type).count.to_natural_64
end
nodes_of_type (a_node_type: CMS_CONTENT_TYPE): LIST [CMS_NODE] nodes_of_type (a_node_type: CMS_CONTENT_TYPE): LIST [CMS_NODE]
-- List of nodes of type `a_node_type'. -- List of nodes of type `a_node_type'.
--| Redefine to optimize! --| Redefine to optimize!
@@ -137,7 +150,7 @@ feature -- Access
end end
end end
ensure ensure
expected_type: across Result as ic all ic.item.content_type.same_string (a_node_type.name) end expected_type: across Result as ic all ic.item.is_typed_as (a_node_type.name) end
end end
nodes_of_type_with_title (a_node_type: CMS_CONTENT_TYPE; a_title: READABLE_STRING_GENERAL): LIST [CMS_NODE] nodes_of_type_with_title (a_node_type: CMS_CONTENT_TYPE; a_title: READABLE_STRING_GENERAL): LIST [CMS_NODE]

View File

@@ -59,6 +59,12 @@ feature -- Access: node
create {ARRAYED_LIST [CMS_NODE]} Result.make (0) create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
end end
recent_nodes_of_type (a_node_type: CMS_CONTENT_TYPE; a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- Recent `a_count` nodes of type `a_node_type` with an offset of `lower`.
do
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
end
recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE] recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE]
-- List of recent changes, before `a_date', according to `params' settings. -- List of recent changes, before `a_date', according to `params' settings.
do do

View File

@@ -13,6 +13,7 @@ inherit
CMS_NODE_STORAGE_I CMS_NODE_STORAGE_I
redefine redefine
nodes_of_type_count,
nodes_of_type, nodes_of_type,
nodes_of_type_with_title nodes_of_type_with_title
end end
@@ -38,6 +39,22 @@ feature -- Access
sql_finalize sql_finalize
end end
nodes_of_type_count (a_node_type: CMS_CONTENT_TYPE): NATURAL_64
-- Count of nodes of type `a_node_type`.
local
l_parameters: STRING_TABLE [ANY]
do
error_handler.reset
create l_parameters.make (1)
l_parameters.force (a_node_type.name, "node_type")
sql_query (sql_select_nodes_of_type_count, l_parameters)
if not has_error and not sql_after then
Result := sql_read_natural_64 (1)
end
sql_finalize
end
nodes: LIST [CMS_NODE] nodes: LIST [CMS_NODE]
-- List of nodes. -- List of nodes.
do do
@@ -145,6 +162,31 @@ feature -- Access
sql_finalize sql_finalize
end end
recent_nodes_of_type (a_node_type: CMS_CONTENT_TYPE; a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- Recent `a_count` nodes of type `a_node_type` with an offset of `lower`.
local
l_parameters: STRING_TABLE [detachable ANY]
do
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
error_handler.reset
from
create l_parameters.make (3)
l_parameters.put (a_node_type.name, "node_type")
l_parameters.put (a_count, "size")
l_parameters.put (a_lower, "offset")
sql_query (sql_select_recent_nodes_of_type, l_parameters)
sql_start
until
sql_after
loop
if attached fetch_node as l_node then
Result.force (l_node)
end
sql_forth
end
sql_finalize
end
recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE] recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE]
-- List of recent changes, before `a_date', according to `params' settings. -- List of recent changes, before `a_date', according to `params' settings.
local local
@@ -270,7 +312,7 @@ feature -- Access
sql_after sql_after
loop loop
if attached fetch_node as l_node then if attached fetch_node as l_node then
check expected_node_type: l_node.content_type.same_string (a_node_type.name) end check expected_node_type: l_node.is_typed_as (a_node_type.name) end
Result.force (l_node) Result.force (l_node)
end end
sql_forth sql_forth
@@ -474,6 +516,10 @@ feature {NONE} -- Queries
-- Nodes count (Published and not Published) -- Nodes count (Published and not Published)
--| note: {CMS_NODE_API}.trashed = -1 --| note: {CMS_NODE_API}.trashed = -1
sql_select_nodes_of_type_count: STRING = "SELECT count(*) FROM nodes WHERE type=:node_type AND status != -1 ;"
-- Nodes of type `:node_type` count (Published and not Published)
--| note: {CMS_NODE_API}.trashed = -1
sql_select_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE status != -1 ;" sql_select_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE status != -1 ;"
-- SQL Query to retrieve all nodes. -- SQL Query to retrieve all nodes.
--| note: {CMS_NODE_API}.trashed = -1 --| note: {CMS_NODE_API}.trashed = -1
@@ -503,6 +549,8 @@ feature {NONE} -- Queries
sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes ORDER BY changed DESC, publish DESC LIMIT :size OFFSET :offset ;" sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes ORDER BY changed DESC, publish DESC LIMIT :size OFFSET :offset ;"
sql_select_recent_nodes_of_type: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE type=:node_type ORDER BY changed DESC, publish DESC LIMIT :size OFFSET :offset ;"
sql_select_recent_node_changes_before: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE changed <= :date ORDER BY changed DESC, nid DESC LIMIT :size OFFSET :offset ;" sql_select_recent_node_changes_before: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE changed <= :date ORDER BY changed DESC, nid DESC LIMIT :size OFFSET :offset ;"
sql_insert_node: STRING = "INSERT INTO nodes (revision, type, title, summary, content, format, publish, created, changed, status, author) VALUES (:revision, :type, :title, :summary, :content, :format, :publish, :created, :changed, :status, :author);" sql_insert_node: STRING = "INSERT INTO nodes (revision, type, title, summary, content, format, publish, created, changed, status, author) VALUES (:revision, :type, :title, :summary, :content, :format, :publish, :created, :changed, :status, :author);"

View File

@@ -318,7 +318,7 @@ feature -- Web forms
s.append_character (',') s.append_character (',')
s.append_character (' ') s.append_character (' ')
end end
if ic.item.text.has (' ') then if ic.item.text.has (',') then
s.append_character ('"') s.append_character ('"')
s.append (t.text) s.append (t.text)
s.append_character ('"') s.append_character ('"')

View File

@@ -0,0 +1,98 @@
note
description: "[
CMS text with smarty template text content.
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_SMARTY_TEMPLATE_TEXT
inherit
ANY
SHARED_TEMPLATE_CONTEXT
undefine
is_equal
end
create
make
feature {NONE} -- Initialization
make (a_source: like source)
-- Create template text from `a_source`.
do
source := a_source
create values.make (0)
end
feature -- Access
source: READABLE_STRING_8
-- Template source.
values: STRING_TABLE [detachable ANY]
-- Additional value used during template output processing.
value (k: READABLE_STRING_GENERAL): detachable ANY assign set_value
do
Result := values.item (k)
end
feature -- Element change
set_value (v: detachable ANY; k: READABLE_STRING_GENERAL)
-- Associate value `v' with key `k'.
do
values.force (v, k)
end
unset_value (k: READABLE_STRING_GENERAL)
-- Remove value indexed by key `k'.
do
values.remove (k)
end
feature -- Conversion
string: STRING_8
-- <Precursor>
local
tpl: detachable TEMPLATE_TEXT
l_table_inspector: detachable STRING_TABLE_OF_STRING_INSPECTOR
do
template_context.disable_verbose
debug ("cms")
template_context.enable_verbose
end
create tpl.make_from_text (source)
across
values as ic
loop
tpl.add_value (ic.item, ic.key)
end
create l_table_inspector.register (({detachable STRING_TABLE [STRING_8]}).name)
create l_table_inspector.register (({detachable STRING_TABLE [STRING_32]}).name)
create l_table_inspector.register (({detachable STRING_TABLE [READABLE_STRING_8]}).name)
create l_table_inspector.register (({detachable STRING_TABLE [READABLE_STRING_32]}).name)
tpl.get_structure
tpl.get_output
l_table_inspector.unregister
-- l_table32_inspector.unregister
if attached tpl.output as l_output then
Result := l_output
else
Result := source
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

@@ -24,19 +24,34 @@ feature -- URL aliases
-- <Precursor> -- <Precursor>
local local
l_parameters: STRING_TABLE [detachable ANY] l_parameters: STRING_TABLE [detachable ANY]
l_source: like source_of_path_alias
l_continue: BOOLEAN
do do
error_handler.reset error_handler.reset
create l_parameters.make (2) create l_parameters.make (2)
l_parameters.put (a_source, "source") l_parameters.put (a_source, "source")
l_parameters.put (a_alias, "alias") l_parameters.put (a_alias, "alias")
if attached source_of_path_alias (a_alias) as l_path then l_source := source_of_path_alias (a_alias)
if a_source.same_string (l_path) then l_continue := True
-- already up to date if
l_source /= Void -- Alias exists!
then
if a_source.same_string (l_source) then
if attached path_alias (l_source) as l_alias and then l_alias.same_string (a_alias) then
-- already up to date
l_continue := False
else
-- multiple alias and a_alias is not the default alias
-- then unset, and set again !
unset_path_alias (a_source, a_alias)
end
else else
l_continue := False
error_handler.add_custom_error (0, "alias exists", "Path alias %"" + a_alias + "%" already exists!") error_handler.add_custom_error (0, "alias exists", "Path alias %"" + a_alias + "%" already exists!")
end end
else end
if l_continue then
sql_insert (sql_insert_path_alias, l_parameters) sql_insert (sql_insert_path_alias, l_parameters)
sql_finalize sql_finalize
end end

View File

@@ -44,6 +44,9 @@ feature {NONE} -- Initialize
l_enabled_modules: CMS_MODULE_COLLECTION l_enabled_modules: CMS_MODULE_COLLECTION
l_uninstalled_mods: detachable ARRAYED_LIST [CMS_MODULE] l_uninstalled_mods: detachable ARRAYED_LIST [CMS_MODULE]
do do
-- Initialize site_url
initialize_site_url
-- Initialize formats. -- Initialize formats.
initialize_formats initialize_formats
-- Initialize contents. -- Initialize contents.
@@ -101,6 +104,35 @@ feature {NONE} -- Initialize
setup_hooks setup_hooks
end end
initialize_site_url
-- Initialize site and base url.
local
l_url: detachable STRING_8
i,j: INTEGER
do
--| WARNING: do not use `absolute_url' and `url', since it relies on site_url and base_url.
if attached setup.site_url as l_site_url and then not l_site_url.is_empty then
create l_url.make_from_string (l_site_url)
else
l_url := request.absolute_script_url ("/")
end
check is_not_empty: not l_url.is_empty end
if l_url [l_url.count] /= '/' then
l_url.append_character ('/')
end
site_url := l_url
i := l_url.substring_index ("://", 1)
if i > 0 then
j := l_url.index_of ('/', i + 3)
if j > 0 then
base_url := l_url.substring (j, l_url.count)
end
end
ensure
site_url_set: site_url /= Void
site_url_ends_with_slash: site_url.ends_with_general ("/")
end
initialize_content_types initialize_content_types
-- Initialize content types. -- Initialize content types.
do do
@@ -199,6 +231,16 @@ feature -- Access
storage: CMS_STORAGE storage: CMS_STORAGE
-- Default persistence storage. -- Default persistence storage.
feature -- Access: url
site_url: IMMUTABLE_STRING_8
-- Site url
base_url: detachable IMMUTABLE_STRING_8
-- Base url if any.
--| Usually it is Void, but it could be
--| /project/demo/
feature -- Settings feature -- Settings
is_debug: BOOLEAN is_debug: BOOLEAN
@@ -400,6 +442,8 @@ feature -- Emails
setup.mailer.safe_process_email (e) setup.mailer.safe_process_email (e)
if setup.mailer.has_error then if setup.mailer.has_error then
error_handler.add_custom_error (0, "Mailer error", "Error occurred while processing email.") error_handler.add_custom_error (0, "Mailer error", "Error occurred while processing email.")
else
e.set_is_sent (True)
end end
end end
@@ -442,7 +486,13 @@ feature -- Permissions system
-- Anonymous or user `user' has permission for `a_permission'? -- Anonymous or user `user' has permission for `a_permission'?
--| `a_permission' could be for instance "create page". --| `a_permission' could be for instance "create page".
do do
Result := user_api.user_has_permission (user, a_permission) Result := user_has_permission (user, a_permission)
end
has_permissions (a_permission_list: ITERABLE [READABLE_STRING_GENERAL]): BOOLEAN
-- Anonymous or user `user' has any of the permissions `a_permission_list`?
do
Result := user_has_permissions (user, a_permission_list)
end end
user_has_permission (a_user: detachable CMS_USER; a_permission: detachable READABLE_STRING_GENERAL): BOOLEAN user_has_permission (a_user: detachable CMS_USER; a_permission: detachable READABLE_STRING_GENERAL): BOOLEAN
@@ -452,6 +502,18 @@ feature -- Permissions system
Result := user_api.user_has_permission (a_user, a_permission) Result := user_api.user_has_permission (a_user, a_permission)
end end
user_has_permissions (a_user: detachable CMS_USER; a_permission_list: ITERABLE [READABLE_STRING_GENERAL]): BOOLEAN
-- Does `a_user' has any of the permissions `a_permission_list' ?
do
across
a_permission_list as ic
until
Result
loop
Result := user_has_permission (a_user, ic.item)
end
end
feature -- Query: module feature -- Query: module
is_module_installed (a_module: CMS_MODULE): BOOLEAN is_module_installed (a_module: CMS_MODULE): BOOLEAN
@@ -905,6 +967,24 @@ feature -- Access: active user
user_api.update_user (a_user) user_api.update_user (a_user)
end end
feature -- Site builtin variables
builtin_variables: STRING_TABLE [detachable ANY]
-- Builtin variables , value indexed by name.
do
create Result.make (7)
Result["site_url"] := site_url
Result["site_email"] := setup.site_email
Result["site_name"] := setup.site_name
if attached user as l_user then
Result["active_user"] := l_user
Result["user"] := l_user.name
Result["user_id"] := l_user.id
Result["user_profile_name"] := user_api.user_display_name (l_user)
end
end
feature -- Request utilities feature -- Request utilities
execution_variable (a_name: READABLE_STRING_GENERAL): detachable ANY execution_variable (a_name: READABLE_STRING_GENERAL): detachable ANY

View File

@@ -160,7 +160,7 @@ feature -- Import
import_json_user (j_user: JSON_OBJECT; a_import_ctx: CMS_IMPORT_CONTEXT) import_json_user (j_user: JSON_OBJECT; a_import_ctx: CMS_IMPORT_CONTEXT)
local local
l_user_by_name, l_user_by_email: detachable CMS_USER l_user_by_name, l_user_by_email, l_user: detachable CMS_USER
do do
if attached json_to_user (j_user) as u then if attached json_to_user (j_user) as u then
l_user_by_name := user_api.user_by_name (u.name) l_user_by_name := user_api.user_by_name (u.name)
@@ -170,6 +170,28 @@ feature -- Import
if l_user_by_name /= Void or l_user_by_email /= Void then if l_user_by_name /= Void or l_user_by_email /= Void then
a_import_ctx.log ("Skip user %"" + u.name + "%": already exists!") a_import_ctx.log ("Skip user %"" + u.name + "%": already exists!")
-- Already exists! -- Already exists!
if l_user_by_email /= Void then
l_user := l_user_by_email
if
l_user_by_name /= Void and then
l_user_by_name.same_as (l_user)
then
-- Two different accounts exists!
a_import_ctx.log ("Two different accounts already exists for username %"" + u.name + "%" !")
end
else
l_user := l_user_by_name
end
-- Check if new information are now available.
if
l_user /= Void and then
l_user.profile_name = Void and then
attached u.profile_name as l_new_prof_name and then
not l_new_prof_name.is_whitespace
then
l_user.set_profile_name (l_new_prof_name)
user_api.update_user (l_user)
end
else else
user_api.new_user (u) user_api.new_user (u)
a_import_ctx.log ("New user %"" + u.name + "%" -> " + u.id.out + " .") a_import_ctx.log ("New user %"" + u.name + "%" -> " + u.id.out + " .")

View File

@@ -12,7 +12,19 @@ inherit
create create
make make
feature -- Status report
is_sent: BOOLEAN
-- Current Email is sent.
feature -- Element change
set_is_sent (b: BOOLEAN)
do
is_sent := b
end
note note
copyright: "2011-2015, 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)"
end end

View File

@@ -24,46 +24,18 @@ feature {NONE} -- Initialization
response := res response := res
create header.make create header.make
create values.make (3) create values.make (3)
site_url := a_api.site_url
base_url := a_api.base_url
initialize initialize
end end
initialize initialize
do do
initialize_site_url
get_theme get_theme
create menu_system.make create menu_system.make
initialize_block_region_settings initialize_block_region_settings
end end
initialize_site_url
-- Initialize site and base url.
local
l_url: detachable STRING_8
i,j: INTEGER
do
--| WARNING: do not use `absolute_url' and `url', since it relies on site_url and base_url.
if attached setup.site_url as l_site_url and then not l_site_url.is_empty then
create l_url.make_from_string (l_site_url)
else
l_url := request.absolute_script_url ("/")
end
check is_not_empty: not l_url.is_empty end
if l_url [l_url.count] /= '/' then
l_url.append_character ('/')
end
site_url := l_url
i := l_url.substring_index ("://", 1)
if i > 0 then
j := l_url.index_of ('/', i + 3)
if j > 0 then
base_url := l_url.substring (j, l_url.count)
end
end
ensure
site_url_set: site_url /= Void
site_url_ends_with_slash: site_url.ends_with_general ("/")
end
feature -- Access feature -- Access
request: WSF_REQUEST request: WSF_REQUEST
@@ -236,13 +208,7 @@ feature -- Permission
user_has_permissions (a_user: detachable CMS_USER; a_permission_list: ITERABLE [READABLE_STRING_GENERAL]): BOOLEAN user_has_permissions (a_user: detachable CMS_USER; a_permission_list: ITERABLE [READABLE_STRING_GENERAL]): BOOLEAN
-- Does `a_user' has any of the permissions `a_permission_list' ? -- Does `a_user' has any of the permissions `a_permission_list' ?
do do
across Result := api.user_has_permissions (a_user, a_permission_list)
a_permission_list as ic
until
Result
loop
Result := user_has_permission (a_user, ic.item)
end
end end
feature -- Head customization feature -- Head customization
@@ -1088,6 +1054,17 @@ feature -- Cache managment
end end
end end
feature -- Response builtin variables
builtin_variables: STRING_TABLE [detachable ANY]
-- builtin variables value indexed by name.
do
Result := api.builtin_variables
Result ["site_url"] := site_url
Result ["host"] := site_url -- FIXME: check and remove if unused.
Result ["is_https"] := request.is_https
end
feature -- Generation feature -- Generation
prepare (page: CMS_HTML_PAGE) prepare (page: CMS_HTML_PAGE)
@@ -1233,14 +1210,17 @@ feature -- Generation
end end
end end
-- Fill with CMS builtin variables.
across
builtin_variables as ic
loop
page.register_variable (ic.item, ic.key)
end
-- Variables -- Variables
page.register_variable (absolute_url ("", Void), "site_url") page.register_variable (absolute_url ("", Void), "site_url")
page.register_variable (absolute_url ("", Void), "host") -- Same as `site_url'. page.register_variable (absolute_url ("", Void), "host") -- Same as `site_url'.
page.register_variable (request.is_https, "is_https") page.register_variable (request.is_https, "is_https")
if attached user as l_user then
page.register_variable (l_user.name, "user")
page.register_variable (user_profile_name (l_user), "user_profile_name")
end
if attached title as l_title then if attached title as l_title then
page.register_variable (l_title, "site_title") page.register_variable (l_title, "site_title")
else else
@@ -1358,15 +1338,9 @@ feature -- Helpers: cms link
feature -- Helpers: html links feature -- Helpers: html links
user_profile_name (u: CMS_USER): READABLE_STRING_32 user_profile_name, user_display_name (u: CMS_USER): READABLE_STRING_32
do do
if attached u.profile_name as pn and then not pn.is_whitespace then Result := api.user_api.user_display_name (u)
Result := pn
elseif not u.name.is_whitespace then
Result := u.name
else
Result := {STRING_32} "user #" + u.id.out
end
end end
user_html_link (u: CMS_USER): STRING user_html_link (u: CMS_USER): STRING

View File

@@ -68,6 +68,20 @@ feature -- Validation
end end
end end
feature -- Query
user_display_name (u: CMS_USER): READABLE_STRING_32
-- Display name for user `u`.
do
if attached u.profile_name as pn and then not pn.is_whitespace then
Result := pn
elseif not u.name.is_whitespace then
Result := u.name
else
Result := {STRING_32} "user #" + u.id.out
end
end
feature -- Access: user feature -- Access: user
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER