Compare commits

...

17 Commits

Author SHA1 Message Date
db697cec3e Fixed auth mail template text and code. 2016-02-03 23:33:52 +01:00
892f2331de Do not set destination query parameter to any account/auth url.
Set "site_sign_in_url" and "site_sign_out_url" as variables (so it could be used by template).
2016-02-03 23:16:05 +01:00
3496536751 Added CMS_API.request: WSF_REQUEST to ease dev of ROC CMS code.
- Removed CMS_REQUEST_UTIL
  - centralize a few request related code into CMS_API
Added CMS_API.user, CMS_API.set_user (CMS_USER), ... and user related routines.

Refactored Auth related code
  - added various abstractions to factorize implementation and harmonize solutions.
  - revisited the logout strategy.
  - updated the account info page, and remove info user should not care about.
  - simplified the process, and encourage auth module to follow same design.

Added CMS_LINK helper routines to modify the related query string.
Removed CMS_USER.profile (and related routines)
   - It was not used so far.
   - it will probably a specific module later, if needed.

Update various module to avoid fetching user from sql directly, and let this task to CMS_USER_API.

Removed CMS_NODE_API.node_author (a_node: CMS_NODE): detachable CMS_USER,
   - as the info is already in CMS_NODE.author

Added CMS_RESPONSE.redirection_delay, if ever one code want to redirect after a few seconds.
Added the request uri info to the not found cms response.
2016-01-29 21:58:49 +01:00
41ac45d07b Fixed various CMS_MODULE.install, by not marked module installed if an error occurred!
Improved Auth related module implementation by having a way to change settings like token, max age.
  - use CMS_SETUP.site_id and related "auth.$module.token" ... configuration values.
  - removed related CMS_..._CONSTANTS classes.

For auth session module, use auth_session as table name, and use VARCHAR(64).
Extracted sql from blog module, and store it under site/scripts/install.sql .
Renamed a few $modulename.sql as install.sql
2016-01-27 18:22:20 +01:00
d3b485f4d3 Removed unused local variable. 2016-01-22 22:19:24 +01:00
2b1d5f9693 Updated to new routine type. 2016-01-22 21:41:56 +01:00
59c03c5f4d Added CMS_STRING_EXPANDER.
For now with basic implementation.
  It will be improved later

Added SEO related attribute in CMS_RESPONSE.
Added improved Contact module.
Added basic SEO module.
2016-01-22 21:33:06 +01:00
39ab19d20e Eiffel code and ECFs update to support new agent notations.
Accepts /account and /account/ .
2016-01-19 16:15:13 +01:00
fd5e396b72 Code cleaning. 2016-01-15 18:35:53 +01:00
5bd28326c2 Added source for sql scripts. 2016-01-15 17:59:21 +01:00
eef2a52f48 Integrated new registration workflow.
Added optional "mailer.subject_prefix" configuration item.
Added CMS_SETUP.utf_8_site_name for convenience.
Fixed a few potential unicode issues.
Fixed various typos.
2016-01-15 17:46:56 +01:00
a013efd6f7 Cosmetic in DEMO_CMS_EXECUTION
Removed persistence/mysql which is not used.
2016-01-15 13:30:07 +01:00
f6885ff581 remove roc.exe 2016-01-13 22:05:49 +01:00
a179ee3239 Reverted executable name to "demo" 2016-01-13 10:38:27 +01:00
ed0d9c8d07 Use {CMS_LOG}.level_notice and related constant when using api.log(..) 2016-01-12 16:14:54 +01:00
67fbee737d Keep only sqlite3 persistence as default.
To include mysql and other, uncomment related code in demo-safe.ecf and demo_cms_execution.
2016-01-12 16:14:18 +01:00
56b9355f3c Updated email messaging of Auth modules to use the CMS_API.process_email (..) system.
as a consequence, removed usage of email_service library.
Updated the meaning for site.email to be sender email addressed.
Added notification.email to set the email address that will received system email notification.
2016-01-08 22:24:52 +01:00
155 changed files with 4824 additions and 2869 deletions

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms"> <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="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms">
<target name="cms"> <target name="cms">
<root all_classes="true"/> <root all_classes="true"/>
<file_rule> <file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule> </file_rule>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional"> <option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/> <assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms"> <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="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms">
<description>ROC CMS library</description> <description>ROC CMS library</description>
<target name="cms"> <target name="cms">
<root all_classes="true"/> <root all_classes="true"/>
<file_rule> <file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule> </file_rule>
<option warning="true" full_class_checking="false" void_safety="none" syntax="transitional"> <option warning="true" full_class_checking="false" void_safety="none" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/> <assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>

View File

@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="demo" uuid="3643E657-BCBE-46AA-931B-71EAEA877A18" library_target="demo"> <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="demo" uuid="3643E657-BCBE-46AA-931B-71EAEA877A18" library_target="demo">
<description>Example/demo for Eiffel ROC CMS library</description> <description>Example/demo for Eiffel ROC CMS library</description>
<target name="common" abstract="true"> <target name="common" abstract="true">
<root class="DEMO_CMS_SERVER" feature="make_and_launch"/> <root class="DEMO_CMS_SERVER" feature="make_and_launch"/>
<file_rule> <file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule> </file_rule>
<option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional"> <option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
<debug name="dbglog" enabled="true"/> <debug name="dbglog" enabled="true"/>
</option> </option>
<setting name="executable_name" value="demo"/>
<setting name="concurrency" value="thread"/> <setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"> <library name="cms" location="..\..\cms-safe.ecf" readonly="false">
@@ -23,17 +24,19 @@
<library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/> <library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/>
<library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/> <library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/>
<library name="cms_blog_module" location="..\..\modules\blog\cms_blog_module-safe.ecf" readonly="false"/> <library name="cms_blog_module" location="..\..\modules\blog\cms_blog_module-safe.ecf" readonly="false"/>
<library name="cms_contact_module" location="..\..\modules\contact\contact-safe.ecf" readonly="false"/>
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/> <library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
<library name="cms_email_service" location="..\..\library\email\email-safe.ecf" readonly="false"/> <library name="cms_email_service" location="..\..\library\email\email-safe.ecf" readonly="false"/>
<library name="cms_feed_aggregator_module" location="..\..\modules\feed_aggregator\feed_aggregator-safe.ecf" readonly="false"/> <library name="cms_feed_aggregator_module" location="..\..\modules\feed_aggregator\feed_aggregator-safe.ecf" readonly="false"/>
<library name="cms_google_search_module" location="..\..\modules\google_search\google_search-safe.ecf" readonly="false" use_application_options="true"/> <library name="cms_google_search_module" location="..\..\modules\google_search\google_search-safe.ecf" readonly="false" use_application_options="true"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/> <library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/> <library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
<library name="cms_taxnomy_module" location="..\..\modules\taxonomy\taxonomy-safe.ecf" readonly="false"/>
<library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/> <library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/>
<library name="cms_session_auth_module" location="..\..\modules\session_auth\cms_session_auth-safe.ecf" readonly="false"/>
<library name="cms_openid_module" location="..\..\modules\openid\openid-safe.ecf" readonly="false"/> <library name="cms_openid_module" location="..\..\modules\openid\openid-safe.ecf" readonly="false"/>
<library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes-safe.ecf" readonly="false"/> <library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes-safe.ecf" readonly="false"/>
<library name="cms_seo_module" location="..\..\modules\seo\seo-safe.ecf" readonly="false"/>
<library name="cms_session_auth_module" location="..\..\modules\session_auth\cms_session_auth-safe.ecf" readonly="false"/>
<library name="cms_taxnomy_module" location="..\..\modules\taxonomy\taxonomy-safe.ecf" readonly="false"/>
<library name="persistence_sqlite3" location="..\..\library\persistence\sqlite3\sqlite3-safe.ecf" readonly="false"> <library name="persistence_sqlite3" location="..\..\library\persistence\sqlite3\sqlite3-safe.ecf" readonly="false">
<option> <option>
<assertions/> <assertions/>
@@ -41,13 +44,13 @@
</library> </library>
<!-- <!--
<library name="persistence_store_odbc" location="..\..\library\persistence\store_odbc\store_odbc-safe.ecf"/> <library name="persistence_store_odbc" location="..\..\library\persistence\store_odbc\store_odbc-safe.ecf"/>
-->
<library name="persistence_store_mysql" location="..\..\library\persistence\store_mysql\store_mysql-safe.ecf" /> <library name="persistence_store_mysql" location="..\..\library\persistence\store_mysql\store_mysql-safe.ecf" />
-->
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/> <library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/> <library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
</target> </target>
<target name="demo_any" extends="common"> <target name="demo_any" extends="common">
<setting name="concurrency" value="thread"/> <setting name="concurrency" value="scoop"/>
<library name="any_launcher" location="..\..\launcher\any-safe.ecf" readonly="false"/> <library name="any_launcher" location="..\..\launcher\any-safe.ecf" readonly="false"/>
<cluster name="src" location=".\src\" recursive="true"/> <cluster name="src" location=".\src\" recursive="true"/>
</target> </target>

View File

@@ -6,10 +6,13 @@ set ROC_CMS_DIR=%~dp0
%ROC_CMD% install --module ..\..\modules\auth --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\auth --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\basic_auth --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\basic_auth --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\blog --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\blog --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\contact --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\feed_aggregator --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\google_search --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\node --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\node --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\oauth20 --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\oauth20 --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\openid --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\openid --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\recent_changes --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\recent_changes --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\feed_aggregator --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\seo --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\google_search --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\session_auth --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\taxonomy --dir %ROC_CMS_DIR% %ROC_CMD% install --module ..\..\modules\taxonomy --dir %ROC_CMS_DIR%

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="cms_demo_module" uuid="4BB59A54-2544-4C10-BFA6-01D12E541A30" library_target="cms_demo_module"> <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="cms_demo_module" uuid="4BB59A54-2544-4C10-BFA6-01D12E541A30" library_target="cms_demo_module">
<target name="cms_demo_module"> <target name="cms_demo_module">
<root all_classes="true"/> <root all_classes="true"/>
<file_rule> <file_rule>
<exclude>/.git$</exclude> <exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule> </file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard"> <option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
</option> </option>
@@ -21,4 +21,3 @@
<cluster name="src" location=".\" recursive="true"/> <cluster name="src" location=".\" recursive="true"/>
</target> </target>
</system> </system>

View File

@@ -70,8 +70,9 @@ CREATE TABLE tb_demo(
api.logger.put_error ("Could not initialize database for demo module", generating_type) api.logger.put_error ("Could not initialize database for demo module", generating_type)
end end
end end
Precursor {CMS_MODULE}(api)
end end
-- For this demo, be flexible, and do not required sql.
Precursor {CMS_MODULE}(api)
end end
feature -- Access: router feature -- Access: router
@@ -151,7 +152,7 @@ feature -- Mapping helper: uri template
feature -- Mapping helper: uri template agent feature -- Mapping helper: uri template agent
map_uri_template_agent (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) map_uri_template_agent (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [WSF_REQUEST, WSF_RESPONSE]; rqst_methods: detachable WSF_REQUEST_METHODS)
-- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'.
require require
a_tpl_attached: a_tpl /= Void a_tpl_attached: a_tpl /= Void

View File

@@ -4,14 +4,36 @@ root-dir=site/www
#modules-dir=site/modules #modules-dir=site/modules
[site] [site]
# General token that could be use for cookies, and related.
id=_EIFFEL_CMS_
# Name of the site, for the title, and eventual message.
name=Eiffel CMS name=Eiffel CMS
email=your@email.com
# Properties used for SEO.
property[headline]=Eiffel CMS -- the demo
property[description]=Demo for Eiffel ROC CMS.
property[keywords]=eiffel,cms,demo
# Email used for notification
email=noreply@example.com
# Name of website theme.
theme=bootstrap theme=bootstrap
[notification]
# By default, notification.email = site.email
# you can change here the email that will receive internal messages.
email=webmaster@example.com
[mailer] [mailer]
#smtp=localhost:25 #The mailer is used mostly used by the CMS to send email messages.
#sendmail=/usr/bin/sendmail # you can change the "From:" by setting mailer.from value"
output=@stderr subject_prefix=[Eiffel CMS]
#from=...
smtp=localhost:25
#sendmail=site\bin\roc_sendmail.bat
output=site\db\mailer.log
[modules] [modules]
# Module status # Module status
@@ -25,6 +47,14 @@ output=@stderr
[blocks] [blocks]
@include=blocks.ini @include=blocks.ini
[auth]
# token, default is $site.id or built-in.
#token=_ROC_AUTH_TOKEN_
#session.token=
#session.max_age=86400
#openid.token=
#oauth.token=
[admin] [admin]
# CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none) # CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none)
installation_access=all installation_access=all

View File

@@ -1,8 +1,7 @@
{ {
"email": "webmaster@eiffel.org",
"subject": "Thank you for contacting us", "subject": "Thank you for contacting us",
"recaptcha": { "recaptcha": {
"site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD", "site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD",
"secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx" "secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx"
} }
} }

View File

@@ -1,22 +1,28 @@
ul.cms-temp-users { ul.cms-temp-users {
list-style-type: none; list-style-type: none;
padding: 3px 3px 3px 3px; padding: 3px 3px 3px 3px;
border: solid 1px #ccc; } border: solid 1px #ccc;
ul.cms-temp-users li { }
border-top: dotted 1px #ccc; } ul.cms-temp-users li {
ul.cms-temp-users li:first-child { border-top: dotted 1px #ccc;
border-top: none; } }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details { ul.cms-temp-users li:first-child {
list-style-type: none; border-top: none;
padding: 3px 3px 3px 3px; }
border: solid 1px #ccc; } ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details {
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li { list-style-type: none;
border-top: dotted 1px #ccc; } padding: 3px 3px 3px 3px;
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child { border: solid 1px #ccc;
border-top: none; } }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before { ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li {
content: "[personal information] "; } border-top: dotted 1px #ccc;
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before { }
content: "[email] "; } ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child {
border-top: none;
/*# sourceMappingURL=auth.css.map */ }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before {
content: "[personal information] ";
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before {
content: "[email] ";
}

View File

@@ -0,0 +1,37 @@
ul.cms-temp-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_temp_user {
ul.cms_temp_user_details {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_temp_user_detail_information::before{
content: "[personal information] "
}
li.cms_temp_user_detail_email::before{
content: "[email] "
}
}
}
}

View File

@@ -1,14 +1,13 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Activation</title> <title>Activation</title>
<meta name="description" content="Activation"> <meta name="description" content="Activation">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>Thank you for applying to <a href="$host">$sitename</a> $user</p> <p>"$user ($email)", thank you for applying to <a href="$host">$sitename</a>.</p>
<p>We will review your application and send you a resolution<p> <p>We will review your application and send you a resolution.<p>
</body> </body>
</html> </html>

View File

@@ -6,9 +6,8 @@
<meta name="description" content="Activation Confirmation"> <meta name="description" content="Activation Confirmation">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>Your account has been confirmed <a href="$host">$sitename</a> $email</p> <p>Your account "$user ($email)" is confirmed at <a href="$host">$sitename</a>.</p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -6,12 +6,10 @@
<meta name="description" content="New Password"> <meta name="description" content="New Password">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>You have required a new password at <a href="$host">$sitename</a></p> <p>You have requested a new password at <a href="$host">$sitename</a>.</p>
<p>To complete your request, please click on the following link to generate a new password:
<p>To complete your request, please click on this link to generate a new password:<p> <ul><a href="$link">$link</a></ul>
</p>
<p><a href="$link">$link</a></p>
</body> </body>
</html> </html>

View File

@@ -6,13 +6,12 @@
<meta name="description" content="New Activation token"> <meta name="description" content="New Activation token">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>You have request a new activation token at <a href="$host">$sitename</a></p> <p>You have requested a new activation token at <a href="$host">$sitename</a>.</p>
<p>To complete your registration, please click on this link to activate your account:<p> <p>To complete your registration, please click on the following link to re-activate your account:
<ul><a href="$link">$link</a></ul>
<p><a href="$link">$link</a></p> </p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -6,8 +6,7 @@
<meta name="description" content="Application Rejected"> <meta name="description" content="Application Rejected">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>You requested has been rejected, your application does not conform our rules <a href="$host">$sitename</a></p> <p>Your account application is rejected, it was not respecting the requirements from <a href="$host">$sitename</a>.</p>
</body> </body>
</html> </html>

View File

@@ -7,7 +7,13 @@
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>Welcome to <a href="$host">$sitename</a></p> <p>Welcome to <a href="$host">$sitename</a>.</p>
<p>Your account information:
<ul>
<li>Email address: "$email" .</li>
<li>User name: "$user" .</li>
</ul>
</p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -1,13 +0,0 @@
CREATE TABLE `auth_temp_users` (
`uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
`name` VARCHAR(100) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`salt` VARCHAR(100) NOT NULL,
`email` VARCHAR(250) NOT NULL,
`application` TEXT NOT NULL,
CONSTRAINT `name`
UNIQUE(`name`)
);

View File

@@ -0,0 +1 @@
{include file="block_account_info.tpl" /}

View File

@@ -1,62 +1,34 @@
<div class="primary-tabs"> <div class="primary-tabs">
{if isset="$user"} {if isset="$user"}
<h3>Account Information</h3> <h3>Account Information</h3>
<div> <ul class="user-information">
<div> <div>
<div> <label>Username:</label> {$user.name/}
<label>Username:</label> {$user.name/}
</div>
<div>
<label>Email:</label> {$user.email/}
</div>
<div>
<label>Creation Date:</label> {$user.creation_date/}
</div>
<div>
<label>Last login:</label> {$user.last_login_date/}
</div>
<div>
<form method="get" action="{$site_url/}{$auth_login_strategy/}">
<button type="submit">Logout</button>
</form>
</div>
</div> </div>
</div> <div>
<hr> <label>Email:</label> {$user.email/}
{include file="block_change_password.tpl" /} </div>
<hr> <div>
<h4>Roles</h4> <label>Creation Date:</label> {$user.creation_date/} (UTC)
<div> </div>
{foreach item="ic" from="$roles"} <div>
<div> <label>Last login:</label> {$user.last_login_date/} (UTC)
<ul> </div>
<li> <div>
<strong>{$ic.name/}</strong> <form method="get" action="{$site_url/}account/roc-logout">
<ul> <button type="submit">Logout</button>
<li> <i>permissions</i> </form>
<ul> </div>
{foreach item="ip" from="$ic.permissions"} </ul>
<li>{$ip/}</li>
{/foreach}
</ul>
</li>
</ul>
</li>
</ul>
</div>
{/foreach}
</div>
<hr> <hr>
<h4>Profile</h4> <h4>Profile</h4>
<div> <ul class="user-profile">
{foreach item="the_value" key="the_name" from="$user.profile"} {foreach item="the_value" key="the_name" from="$user.profile"}
<div> <li>
<label>{$the_name/}:</label> {$the_value/} <label>{$the_name/}:</label><div>{$the_value/}</div>
</div> </li>
{/foreach} {/foreach}
</div> </ul>
{/if} {/if}
{unless isset="$user"} {unless isset="$user"}
<div> <div>

View File

@@ -1,7 +1,7 @@
<div> <div>
<form action="{$site_url/}account/change-password" method="post"> <form action="{$site_url/}account/change-password" method="post">
<fieldset> <fieldset>
<legend>Change Password Form</legend> <legend>Change Password</legend>
<div> <div>
<input type="password" id="password" name="password" value="" required/> <input type="password" id="password" name="password" value="" required/>
<label for="password">Password</label> <label for="password">Password</label>

View File

@@ -1,29 +0,0 @@
<div class="primary-tabs">
{unless isset="$user"}
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div>
<div>
<form action method="POST">
<div>
<input type="text" name="username" required>
<label>Username</label>
</div>
<div>
<input type="password" name="password" required>
<label>Password</label>
</div>
<button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
</div>
</div>
<div>
<div>
<p>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div>
{/unless}
</div>

View File

@@ -1,307 +1,291 @@
var ROC_AUTH = ROC_AUTH || { }; var ROC_AUTH = ROC_AUTH || { };
var loginURL = "/basic_auth_login"; var loginURL = "/roc-basic-login";
var logoutURL = "/basic_auth_logoff"; var logoutURL = "/roc-basic-logoff";
var userAgent = navigator.userAgent.toLowerCase(); var userAgent = navigator.userAgent.toLowerCase();
var firstLogIn = true; var firstLogIn = true;
ROC_AUTH.login = function() { ROC_AUTH.login = function() {
var form = document.forms['cms_basic_auth']; var form = document.forms['cms_basic_auth'];
var username = form.username.value; var username = form.username.value;
var password = form.password.value; var password = form.password.value;
//var host = form.host.value; //var host = form.host.value;
var origin = window.location.origin + window.location.pathname; var origin = window.location.origin + window.location.pathname;
var _login = function(){ var _login = function(){
if (document.getElementById('myModalFormId') !== null ) {
ROC_AUTH.remove ('myModalFormId');
}
if (username === "" || password === "") {
if (document.getElementById('myModalFormId') !== null ) { if (document.getElementById('myModalFormId') === null ) {
ROC_AUTH.remove ('myModalFormId'); var newdiv = document.createElement('div');
} newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
}
}else{
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
delete form;
window.location=window.location.origin;
} else {
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
// .. ?
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
}
}
}
}
}
}
if (username === "" || password === "") { var userAgent = navigator.userAgent.toLowerCase();
if (document.getElementById('myModalFormId') === null ) { if (userAgent.indexOf("firefox") != -1) { //TODO: check version number
var newdiv = document.createElement('div'); if (firstLogIn) {
newdiv.innerHTML = "<br>Invalid Credentials</br>"; _login();
newdiv.id = 'myModalFormId'; } else {
$(".primary-tabs").append(newdiv); ROC_AUTH.logoff(_login);
} }
}else{ } else {
_login();
//Instantiate HTTP Request }
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
delete form;
window.location=window.location.origin;
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".primary-tabs").append(newdiv);
}
} if (firstLogIn) {
} firstLogIn = false;
} }
}
}
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (firstLogIn) _login();
else logoff(_login);
}
else{
_login();
}
if (firstLogIn) firstLogIn = false;
}; };
ROC_AUTH.login_with_redirect = function() { ROC_AUTH.login_with_redirect = function() {
var form = document.forms[2]; var form = document.forms[2];
var username = form.username.value; var username = form.username.value;
var password = form.password.value; var password = form.password.value;
var host = form.host.value; var host = form.host.value;
var _login = function(){ var _login = function(){
var redirectURL = form.redirect && form.redirect.value || "";
$("#imgProgressRedirect").show();
var redirectURL = form.redirect && form.redirect.value || ""; if (document.getElementById('myModalFormId') !== null ) {
ROC_AUTH.remove ('myModalFormId');
}
if (username === "" || password === "") {
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
$("#imgProgressRedirect").hide();
}
} else {
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", host + loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status==200) {
if (redirectURL === "") {
window.location=host + "/";
} else {
window.location=host + redirectURL;
}
} else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
$("#imgProgressRedirect").hide();
}
}
}
}
}
}
$("#imgProgressRedirect").show(); var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (document.getElementById('myModalFormId') !== null ) { if (firstLogIn) {
ROC_AUTH.remove ('myModalFormId'); _login();
} } else {
ROC_AUTH.logoff(_login);
}
if (username === "" || password === "") { } else{
if (document.getElementById('myModalFormId') === null ) { _login();
var newdiv = document.createElement('div'); }
newdiv.innerHTML = "<br>Invalid Credentials</br>"; if (firstLogIn) {
newdiv.id = 'myModalFormId'; firstLogIn = false;
$(".primary-tabs").append(newdiv); }
$("#imgProgressRedirect").hide();
}
}else{
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", host.concat(loginURL), true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
if (redirectURL === "") {
window.location=host.concat("/");
} else {
window.location=host.concat(redirectURL);
}
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".primary-tabs").append(newdiv);
$("#imgProgressRedirect").hide();
}
}
}
}
}
}
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (firstLogIn) _login();
else logoff(_login);
}
else{
_login();
}
if (firstLogIn) firstLogIn = false;
}; };
ROC_AUTH.getQueryParameterByName = function (name) { ROC_AUTH.getQueryParameterByName = function (name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search);
results = regex.exec(location.search); return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
} }
ROC_AUTH.logoff = function(callback){ ROC_AUTH.logoff = function(callback){
var form = document.forms[0]; var form = document.forms[0];
var host = form.host.value; var host = form.host.value;
if (userAgent.indexOf("msie") != -1) { if (userAgent.indexOf("msie") != -1) {
document.execCommand("ClearAuthenticationCache"); document.execCommand("ClearAuthenticationCache");
} } else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number var request1 = new XMLHttpRequest();
var request2 = new XMLHttpRequest();
var request1 = new XMLHttpRequest();
var request2 = new XMLHttpRequest(); //Logout. Tell the server not to return the "WWW-Authenticate" header
request1.open("GET", host + logoutURL + "?prompt=false", true);
//Logout. Tell the server not to return the "WWW-Authenticate" header request1.send("");
request1.open("GET", host.concat(logoutURL) + "?prompt=false", true); request1.onreadystatechange = function(){
request1.send(""); if (request1.readyState == 4) {
request1.onreadystatechange = function(){ //Sign in with dummy credentials to clear the auth cache
if (request1.readyState == 4) { request2.open("GET", host + logoutURL, true, "logout", "logout");
request2.send("");
//Sign in with dummy credentials to clear the auth cache request2.onreadystatechange = function(){
request2.open("GET", host.concat(logoutURL), true, "logout", "logout"); if (request2.readyState == 4) {
request2.send(""); if (callback!=null) {
callback.call();
request2.onreadystatechange = function(){ } else {
if (request2.readyState == 4) { window.location=host + logoutURL;
if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);} }
} }
} }
}
} }
} } else {
} var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
else { request.open("GET", host + logoutURL, true, "logout", "logout");
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); request.send("");
request.open("GET", host.concat(logoutURL), true, "logout", "logout"); request.onreadystatechange = function(){
request.send(""); if (request.status==401 || request.status==403 ) {
request.onreadystatechange = function(){ window.location=host + logoutURL;
if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL); }
} }
} }
}
}; };
ROC_AUTH.remove = function (id) ROC_AUTH.remove = function (id) {
{ var element = document.getElementById(id);
var element = document.getElementById(id); element.outerHTML = "";
element.outerHTML = ""; delete element;
delete element; return;
return;
}; };
$(document).ready(function() { $(document).ready(function() {
if (typeof String.prototype.contains != 'function') {
if (typeof String.prototype.contains != 'function') { String.prototype.contains = function (str){
String.prototype.contains = function (str){ return this.indexOf(str) != -1;
return this.indexOf(str) != -1; };
}; }
} ROC_AUTH.progressive_loging();
ROC_AUTH.progressive_loging();
}); });
ROC_AUTH.progressive_loging = function () { ROC_AUTH.progressive_loging = function () {
ROC_AUTH.login_href();
ROC_AUTH.login_href();
}; };
$(document).keypress(function(e) { $(document).keypress(function(e) {
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) { if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
ROC_AUTH.login(); ROC_AUTH.login();
} }
}); });
ROC_AUTH.OnOneClick = function(event) { ROC_AUTH.OnOneClick = function(event) {
event.preventDefault(); event.preventDefault();
if ( document.forms[0] === undefined ) { if ( document.forms[0] === undefined ) {
ROC_AUTH.create_form(); ROC_AUTH.create_form();
} }
return false; return false;
}; };
ROC_AUTH.login_href = function() { ROC_AUTH.login_href = function() {
var els = document.getElementsByTagName("a"); var els = document.getElementsByTagName("a");
for (var i = 0, l = els.length; i < l; i++) { for (var i = 0, l = els.length; i < l; i++) {
var el = els[i]; var el = els[i];
if (el.href.contains("/basic_auth_login?destination")) { if (el.href.contains(loginURL + "?destination")) {
loginURL = el.href; // loginURL = el.href;
var OneClick = el; var OneClick = el;
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false); OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
} }
} }
}; };
ROC_AUTH.create_form = function() { ROC_AUTH.create_form = function() {
// Fetching HTML Elements in Variables by ID. // Fetching HTML Elements in Variables by ID.
var createform = document.createElement('form'); // Create New Element Form var createform = document.createElement('form'); // Create New Element Form
createform.setAttribute("action", ""); // Setting Action Attribute on Form createform.setAttribute("action", ""); // Setting Action Attribute on Form
createform.setAttribute("method", "post"); // Setting Method Attribute on Form createform.setAttribute("method", "post"); // Setting Method Attribute on Form
$("body").append(createform); $("body").append(createform);
var heading = document.createElement('h2'); // Heading of Form var heading = document.createElement('h2'); // Heading of Form
heading.innerHTML = "Login Form "; heading.innerHTML = "Login Form ";
createform.appendChild(heading); createform.appendChild(heading);
var line = document.createElement('hr'); // Giving Horizontal Row After Heading var line = document.createElement('hr'); // Giving Horizontal Row After Heading
createform.appendChild(line); createform.appendChild(line);
var linebreak = document.createElement('br'); var linebreak = document.createElement('br');
createform.appendChild(linebreak); createform.appendChild(linebreak);
var namelabel = document.createElement('label'); // Create Label for Name Field var namelabel = document.createElement('label'); // Create Label for Name Field
namelabel.innerHTML = "Username : "; // Set Field Labels namelabel.innerHTML = "Username : "; // Set Field Labels
createform.appendChild(namelabel); createform.appendChild(namelabel);
var inputelement = document.createElement('input'); // Create Input Field for UserName var inputelement = document.createElement('input'); // Create Input Field for UserName
inputelement.setAttribute("type", "text"); inputelement.setAttribute("type", "text");
inputelement.setAttribute("name", "username"); inputelement.setAttribute("name", "username");
inputelement.setAttribute("required","required"); inputelement.setAttribute("required","required");
createform.appendChild(inputelement); createform.appendChild(inputelement);
var linebreak = document.createElement('br'); var linebreak = document.createElement('br');
createform.appendChild(linebreak); createform.appendChild(linebreak);
var passwordlabel = document.createElement('label'); // Create Label for Password Field var passwordlabel = document.createElement('label'); // Create Label for Password Field
passwordlabel.innerHTML = "Password : "; passwordlabel.innerHTML = "Password : ";
createform.appendChild(passwordlabel); createform.appendChild(passwordlabel);
var passwordelement = document.createElement('input'); // Create Input Field for Password. var passwordelement = document.createElement('input'); // Create Input Field for Password.
passwordelement.setAttribute("type", "password"); passwordelement.setAttribute("type", "password");
passwordelement.setAttribute("name", "password"); passwordelement.setAttribute("name", "password");
passwordelement.setAttribute("id", "password"); passwordelement.setAttribute("id", "password");
passwordelement.setAttribute("required","required"); passwordelement.setAttribute("required","required");
createform.appendChild(passwordelement); createform.appendChild(passwordelement);
var passwordbreak = document.createElement('br'); var passwordbreak = document.createElement('br');
createform.appendChild(passwordbreak); createform.appendChild(passwordbreak);
var submitelement = document.createElement('button'); // Append Submit Button var submitelement = document.createElement('button'); // Append Submit Button
submitelement.setAttribute("type", "button"); submitelement.setAttribute("type", "button");
submitelement.setAttribute("onclick", "ROC_AUTH.login();"); submitelement.setAttribute("onclick", "ROC_AUTH.login();");
submitelement.innerHTML = "Sign In "; submitelement.innerHTML = "Sign In ";
createform.appendChild(submitelement); createform.appendChild(submitelement);
}; };
@@ -310,16 +294,16 @@ var password = document.getElementById("password");
var confirm_password = document.getElementById("confirm_password"); var confirm_password = document.getElementById("confirm_password");
ROC_AUTH.validatePassword =function(){ ROC_AUTH.validatePassword =function(){
if ((password != null) && (confirm_password != null)) { if ((password != null) && (confirm_password != null)) {
if(password.value != confirm_password.value) { if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match"); confirm_password.setCustomValidity("Passwords Don't Match");
} else { } else {
confirm_password.setCustomValidity(''); confirm_password.setCustomValidity('');
} }
} }
} }
if ((password != null) && (confirm_password != null)) { if ((password != null) && (confirm_password != null)) {
password.onchange = ROC_AUTH.validatePassword(); password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword; confirm_password.onkeyup = ROC_AUTH.validatePassword;
} }

View File

@@ -1,29 +1,23 @@
<div class="primary-tabs"> {unless isset="$user"}
{unless isset="$user"} <div class="login-box">
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3> <div class="description">The "Basic Auth" relies on the HTTP basic acces authentication.<br/>(see also: <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">https://en.wikipedia.org/wiki/Basic_access_authentication</a> )</div>
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div> <div>
<div> <form name="cms_basic_auth" action="{$site_url/}roc-basic-login" method="POST">
<form name="cms_basic_auth" action method="POST"> <input type="hidden" name="host" id="host" value="{$site_url/}">
<div> <div>
<input type="text" name="username" id="username" required> <input type="text" name="username" id="username" required>
<label>Username</label> <label>Username</label>
</div> </div>
<div>
<div> <input type="password" name="password" id="password" required>
<input type="password" name="password" id="password" required> <label>Password</label>
<label>Password</label> </div>
</div> <button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
<button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
</div>
</div> </div>
<div> <div>
<div> <a href="{$site_url/}account/new-password">Forgot password?</a>
<p>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div> </div>
{/unless}
</div> </div>
{/unless}

View File

@@ -0,0 +1,6 @@
CREATE TABLE blog_post_nodes(
`nid` INTEGER NOT NULL CHECK("nid">=0),
`revision` INTEGER NOT NULL,
`tags` VARCHAR(255),
CONSTRAINT PK_nid_revision PRIMARY KEY (nid,revision)
);

View File

@@ -0,0 +1,8 @@
{
"--email": "webmaster@example.com",
"subjet": "Thank you for contacting us",
"recaptcha": {
"site_key":"",
"secret_key":""
}
}

View File

@@ -0,0 +1,124 @@
.contact-box {
background-color: #F2F7F9;
width: 465px;
padding: 20px;
border: 6px solid #8FB5C1;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
border-radius: 15px;
position: relative;
/* Remove box shadow firefox, chrome and opera put around required fields.
* It looks rubbish.
*/
/* Normalize placeholder styles */
/* chrome, safari */
/* mozilla */
/* ie (faux placeholder) */
}
.contact-box h1 {
font-size: 42px;
}
.contact-box h2 {
margin-bottom: 15px;
font-style: italic;
font-weight: normal;
}
.contact-box label {
font-size: 15px;
margin-bottom: 2px;
display: block;
}
.contact-box input, .contact-box select, .contact-box textarea {
width: 100%;
font-size: 15px;
border: 1px solid #CEE1E8;
margin-bottom: 20px;
padding: 4px;
}
.contact-box input:focus, .contact-box select:focus, .contact-box textarea:focus {
border: 1px solid #AFCDD8;
background-color: #EBF2F4;
}
.contact-box textarea {
height: 150px;
resize: none;
}
.contact-box span.required {
font-weight: bold;
color: #F00;
}
.contact-box input[type=submit] {
width: 100px;
background-color: #333;
color: #FFF;
border: none;
display: block;
float: right;
margin-bottom: 0px;
margin-right: 6px;
background-color: #8FB5C1;
-moz-border-radius: 8px;
}
.contact-box input[type=submit]:hover {
background-color: #A6CFDD;
}
.contact-box input[type=submit]:active {
position: relative;
top: 1px;
}
.contact-box .message {
width: 95%;
margin: 25px 0px;
padding: 10px;
display: block;
border: solid 1px #ccc;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
}
.contact-box .message.hidden {
display: none;
}
.contact-box .message.error {
border-color: #E58E8E;
background-color: #FFE6E6;
}
.contact-box .message.error li {
padding: 2px;
list-style: none;
}
.contact-box .message.error li:before {
content: ' - ';
}
.contact-box .message.error #info {
font-weight: bold;
}
.contact-box .message.error #info:before {
content: '';
}
.contact-box .message.success {
border-color: #83D186;
padding-top: 25px;
background-color: #D3EDD3;
}
.contact-box .req-field-desc {
font-style: italic;
}
.contact-box input:required, .contact-box textarea:required {
-moz-box-shadow: none;
-webkit-box-shadow: none;
-o-box-shadow: none;
box-shadow: none;
}
.contact-box ::-webkit-input-placeholder {
color: #CCC;
font-style: italic;
}
.contact-box input:-moz-placeholder, .contact-box textarea:-moz-placeholder {
color: #CCC;
font-style: italic;
}
.contact-box input.placeholder-text, .contact-box textarea.placeholder-text {
color: #CCC;
font-style: italic;
}

View File

@@ -0,0 +1,140 @@
.contact-box {
background-color:#F2F7F9;
width:465px;
padding:20px;
border: 6px solid #8FB5C1;
-moz-border-radius:15px;
-webkit-border-radius:15px;
border-radius:15px;
position:relative;
h1 {
font-size:42px;
}
h2 {
margin-bottom:15px;
font-style:italic;
font-weight:normal;
}
label {
font-size:15px;
margin-bottom:2px;
display:block;
}
input, select, textarea {
width:100%;
font-size:15px;
border: 1px solid #CEE1E8;
margin-bottom:20px;
padding:4px;
&:focus {
border: 1px solid #AFCDD8;
background-color: #EBF2F4;
}
}
textarea {
height:150px;
resize: none;
}
span.required {
font-weight:bold;
color:#F00;
}
input[type=submit] {
width: 100px;
background-color:#333;
color:#FFF;
border:none;
display:block;
float:right;
margin-bottom:0px;
margin-right:6px;
background-color:#8FB5C1;
-moz-border-radius:8px;
&:hover {
background-color: #A6CFDD;
}
&:active {
position:relative;
top:1px;
}
}
.message {
width:95%;
margin:25px 0px;
padding:10px;
display:block;
border:solid 1px #ccc;
border-radius:8px;
-webkit-border-radius:8px;
-moz-border-radius:8px;
&.hidden {
display: none;
}
&.error {
border-color: #E58E8E;
background-color:#FFE6E6;
li {
padding:2px;
list-style:none;
&:before { content: ' - '; }
}
#info {
font-weight:bold;
&:before { content: ''; }
}
}
&.success {
border-color: #83D186;
padding-top: 25px;
background-color:#D3EDD3;
}
}
.req-field-desc {
font-style:italic;
}
/* Remove box shadow firefox, chrome and opera put around required fields.
* It looks rubbish.
*/
input:required, textarea:required {
-moz-box-shadow:none;
-webkit-box-shadow:none;
-o-box-shadow:none;
box-shadow:none;
}
/* Normalize placeholder styles */
/* chrome, safari */
::-webkit-input-placeholder {
color:#CCC;
font-style:italic;
}
/* mozilla */
input:-moz-placeholder, textarea:-moz-placeholder {
color:#CCC;
font-style:italic;
}
/* ie (faux placeholder) */
input.placeholder-text, textarea.placeholder-text {
color:#CCC;
font-style:italic;
}
}

View File

@@ -0,0 +1,25 @@
<div class="contact-box clearfix">
<h1>Contact us!</h1>
<form method="post" action="{$site_url/}contact" id="contact-form">
<label for="name">Name: <span class="required">*</span></label>
<input type="text" id="name" name="name" value="{$name/}" required="required" autofocus="autofocus" />
<label for="email">Email Address: <span class="required">*</span></label>
<input type="email" id="email" name="email" value="{$email/}" required="required" />
<label for="message">Message: <span class="required">*</span></label>
<textarea id="message" name="message" required="required" data-minlength="20" minlength="20" >{$message/}</textarea>
{unless isempty="$recaptcha_site_key"}
<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div>
<br/>
{/unless}
<input type="submit" value="Send" class="submit-button" />
<p class="req-field-desc"><span class="required">*</span> indicates a required field</p>
</form>
{unless isempty="$error_response"}
<ul class="message error">
{foreach item="item" from="$error_response"}<li class="info">{$item/}</li>{/foreach}
</ul>
<div class="notice"> Try again later </div>
{/unless}
</div>

View File

@@ -0,0 +1,15 @@
<div class="contact-box">
{if condition="$has_error"}
<div class="message error">
<strong>Internal Server Error <small>Error 500</small></strong>
<p>The page you requested could not be served because the server is down,
either contact the webmaster or try again.
Use your browser's <strong>Back</strong> button to navigate to the page you came from.</p>
<p><strong>Or you could just press this link:</strong> <a href="{$site_url/}" itemprop="home" rel="home">Take Me Home</a></p>
</div>
{/if}
{unless condition="$has_error"}
<p class="message success">Thank you for contacting the Eiffel Programming Language community.<br/>
We will get back to you promptly on your contact request.</p>
{/unless}
</div>

View File

@@ -0,0 +1,10 @@
<p>
Thank you for contacting {$sitename/}.<br/>
We will get back to you promptly about your contact message.
</p>
<h2>Your contact information:</h2>
<div>
<strong>Name<strong>: {$name/} <br/>
<strong>Email<strong>: {$email/} <br/>
<strong>Message<strong>: {$message/} <br/>
</div>

View File

@@ -0,0 +1,6 @@
<h2>Contact information:</h2>
<div>
<strong>Name<strong>: {$name/}<br/>
<strong>Email<strong>: {$email/} <br/>
<strong>Message<strong>: {$message/} <br/>
</div>

View File

@@ -3,22 +3,17 @@ ul.cms-nodes {
list-style-type: none; list-style-type: none;
padding: 3px 3px 3px 3px; padding: 3px 3px 3px 3px;
border: solid 1px #ccc; border: solid 1px #ccc;
li{ li{
border-top: dotted 1px #ccc; border-top: dotted 1px #ccc;
&:first-child { &:first-child {
border-top: none; border-top: none;
} }
} }
li.cms_type_page a::before { li.cms_type_page a::before {
content: "[page] "; content: "[page] ";
} }
li.cms_type_blog a::before { li.cms_type_blog a::before {
content: "[blog] "; content: "[blog] ";
} }
} }

View File

@@ -0,0 +1,9 @@
CREATE TABLE auth_session (
`uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0),
`access_token` VARCHAR(64) NOT NULL,
`created` DATETIME NOT NULL,
CONSTRAINT `uid` UNIQUE(`uid`),
CONSTRAINT `access_token` UNIQUE(`access_token`)
);

View File

@@ -1,11 +0,0 @@
CREATE TABLE session_auth (
`uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0),
`access_token` TEXT NOT NULL,
`created` DATETIME NOT NULL,
CONSTRAINT `uid`
UNIQUE(`uid`),
CONSTRAINT `access_token`
UNIQUE(`access_token`)
);

View File

@@ -1,37 +1,23 @@
<div class="primary-tabs"> {unless isset="$user"}
{unless isset="$user"} <div class="login-box">
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3> <div class="description">The "Session" is the standard authentication system. (based on cookie)</div>
<div> <h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div> <div>
<form name="cms_session_auth" action="{$site_url/}account/login-with-session" method="POST"> <form name="cms_session_auth" action="{$site_url/}account/auth/roc-session-login" method="POST">
<div>
<input type="text" name="username" id="username" required value="{$username/}">
<label>Username</label>
</div>
<div>
<input type="password" name="password" id="password" required >
<label>Password</label>
</div>
<button type="submit">Login</button>
</form>
</div>
</div>
<div>
<div> <div>
<p> <input type="text" name="username" id="username" required value="{$username/}">
<a href="{$site_url/}account/new-password">Forgot password?</a> <label>Username</label>
</p>
</div> </div>
</div>
{/unless}
{if isset=$error}
<div> <div>
<div> <input type="password" name="password" id="password" required >
<p> <label>Password</label>
<strong>{$error/}
</p>
</div> </div>
</div> <button type="submit">Login</button>
{/if} </form>
</div> </div>
<div>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</div>
{if isset="$error"}<div class="error">{$error/}</div>{/if}
</div>
{/unless}

View File

@@ -34,64 +34,48 @@ feature -- CMS storage
setup_storage (a_setup: CMS_SETUP) setup_storage (a_setup: CMS_SETUP)
do do
a_setup.storage_drivers.force (create {CMS_STORAGE_SQLITE3_BUILDER}.make, "sqlite3") a_setup.storage_drivers.force (create {CMS_STORAGE_SQLITE3_BUILDER}.make, "sqlite3")
a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_MYSQL_BUILDER}.make, "mysql") -- a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_MYSQL_BUILDER}.make, "mysql")
--a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_ODBC_BUILDER}.make, "odbc") -- a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_ODBC_BUILDER}.make, "odbc")
end end
feature -- CMS modules feature -- CMS modules
setup_modules (a_setup: CMS_SETUP) setup_modules (a_setup: CMS_SETUP)
-- Setup additional modules. -- Setup additional modules.
local
m: CMS_MODULE
do do
create {CMS_ADMIN_MODULE} m.make -- Admin
a_setup.register_module (m) a_setup.register_module (create {CMS_ADMIN_MODULE}.make)
-- Auth -- Auth
create {CMS_AUTHENTICATION_MODULE} m.make a_setup.register_module (create {CMS_AUTHENTICATION_MODULE}.make)
a_setup.register_module (m) a_setup.register_module (create {CMS_BASIC_AUTH_MODULE}.make)
a_setup.register_module (create {CMS_OAUTH_20_MODULE}.make)
create {CMS_BASIC_AUTH_MODULE} m.make a_setup.register_module (create {CMS_OPENID_MODULE}.make)
a_setup.register_module (m) a_setup.register_module (create {CMS_SESSION_AUTH_MODULE}.make)
create {CMS_OAUTH_20_MODULE} m.make
a_setup.register_module (m)
create {CMS_OPENID_MODULE} m.make
a_setup.register_module (m)
-- Nodes -- Nodes
create {CMS_NODE_MODULE} m.make (a_setup) a_setup.register_module (create {CMS_NODE_MODULE}.make (a_setup))
a_setup.register_module (m) a_setup.register_module (create {CMS_BLOG_MODULE}.make)
create {CMS_BLOG_MODULE} m.make -- Contact
a_setup.register_module (m) a_setup.register_module (create {CMS_CONTACT_MODULE}.make)
-- Misc
a_setup.register_module (create {CMS_SEO_MODULE}.make)
-- Taxonomy -- Taxonomy
create {CMS_TAXONOMY_MODULE} m.make a_setup.register_module (create {CMS_TAXONOMY_MODULE}.make)
a_setup.register_module (m)
-- Recent changes -- Recent changes
create {CMS_RECENT_CHANGES_MODULE} m.make a_setup.register_module (create {CMS_RECENT_CHANGES_MODULE}.make)
a_setup.register_module (m)
-- Recent changes -- Feed aggregator
create {FEED_AGGREGATOR_MODULE} m.make a_setup.register_module (create {FEED_AGGREGATOR_MODULE}.make)
a_setup.register_module (m)
-- Miscellanious -- Miscellanious
create {CMS_DEBUG_MODULE} m.make a_setup.register_module (create {GOOGLE_CUSTOM_SEARCH_MODULE}.make)
a_setup.register_module (m) a_setup.register_module (create {CMS_DEBUG_MODULE}.make)
a_setup.register_module (create {CMS_DEMO_MODULE}.make)
create {CMS_DEMO_MODULE} m.make
a_setup.register_module (m)
create {GOOGLE_CUSTOM_SEARCH_MODULE} m.make
a_setup.register_module (m)
create {CMS_SESSION_AUTH_MODULE} m.make
a_setup.register_module (m)
end end
end end

View File

@@ -37,6 +37,80 @@ feature -- Access
weight: INTEGER weight: INTEGER
-- Optional weight used for order. -- Optional weight used for order.
query_string: detachable STRING
-- Query string from `location'.
local
i: INTEGER
loc: like location
do
loc := location
i := loc.index_of ('?', 1)
if i > 0 then
Result := loc.substring (i + 1, loc.count)
i := loc.last_index_of ('#', loc.count)
if i > 0 then
Result.keep_head (i - 1)
end
end
end
fragment_string: detachable STRING
-- Query string from `location'.
local
i: INTEGER
loc: like location
do
loc := location
i := loc.last_index_of ('#', loc.count)
if i > 0 then
Result := loc.substring (i + 1, loc.count)
end
end
feature -- Element change
add_query_parameter (a_encoded_name: READABLE_STRING_8; a_encoded_value: detachable READABLE_STRING_8)
-- Add query parameter "$a_encoded_name=$a_encoded_value" to `location'.
-- note: the argument must already be url encoded!
local
q: STRING_8
f: detachable READABLE_STRING_8
i,j: INTEGER
loc: STRING_8
do
create loc.make_from_string (location)
j := loc.last_index_of ('#', loc.count)
if j > 0 then
f := loc.substring (j, loc.count)
loc.keep_head (j - 1)
end
i := loc.index_of ('?', 1)
if i > 0 then
q := loc.substring (i + 1, loc.count)
loc.keep_head (i)
else
create q.make_empty
end
if not q.is_empty then
q.append_character ('&')
end
q.append (a_encoded_name)
if a_encoded_value /= Void then
q.append_character ('=')
q.append (a_encoded_value)
end
loc.append_character ('?')
loc.append (q)
if f /= Void then
loc.append (f)
end
location := loc
end
feature -- Comparison feature -- Comparison
is_less alias "<" (other: like Current): BOOLEAN is_less alias "<" (other: like Current): BOOLEAN
@@ -134,6 +208,6 @@ feature -- Status report
end end
note note
copyright: "2011-2015, Javier Velilla, Jocelyn Fiat, Eiffel Software and others" copyright: "2011-2016, Javier Velilla, Jocelyn Fiat, 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

@@ -1,5 +1,5 @@
note note
description: "Summary description for {CMS_TEMP_USER}." description: "User for temporary account."
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
@@ -7,7 +7,6 @@ class
CMS_TEMP_USER CMS_TEMP_USER
inherit inherit
CMS_USER CMS_USER
create create
@@ -20,17 +19,16 @@ feature -- Access
-- User personal information. -- User personal information.
salt: detachable STRING_32 salt: detachable STRING_32
-- User's password salt. -- User's password salt.
feature -- Element change feature -- Element change
set_personal_information (an_personal_information: like personal_information) set_personal_information (a_personal_information: like personal_information)
-- Assign `personal_information' with `an_personal_information'. -- Assign `personal_information' with `a_personal_information'.
do do
personal_information := an_personal_information personal_information := a_personal_information
ensure ensure
personal_information_assigned: personal_information = an_personal_information personal_information_assigned: personal_information = a_personal_information
end end
set_salt (a_salt: like salt) set_salt (a_salt: like salt)
@@ -41,4 +39,7 @@ feature -- Element change
salt_assigned: salt = a_salt salt_assigned: salt = a_salt
end end
note
copyright: "2011-2016, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -62,12 +62,9 @@ feature -- Access
hashed_password: detachable READABLE_STRING_8 hashed_password: detachable READABLE_STRING_8
-- Hashed user password. -- Hashed user password.
email: detachable READABLE_STRING_32 email: detachable READABLE_STRING_8
-- User email. -- User email.
profile: detachable CMS_USER_PROFILE
-- User profile.
creation_date: DATE_TIME creation_date: DATE_TIME
-- Creation date. -- Creation date.
@@ -189,26 +186,6 @@ feature -- Change element
email_set: email = a_email email_set: email = a_email
end end
set_profile (prof: like profile)
-- Set `profile' with `prof'.
do
profile := prof
ensure
profile_set: profile = prof
end
set_profile_item (k: READABLE_STRING_8; v: READABLE_STRING_8)
local
prof: like profile
do
prof := profile
if prof = Void then
create prof.make
profile := prof
end
prof.force (v, k)
end
set_last_login_date (dt: like last_login_date) set_last_login_date (dt: like last_login_date)
do do
last_login_date := dt last_login_date := dt
@@ -284,7 +261,6 @@ feature -- Status change
status_set: status = a_status status_set: status = a_status
end end
feature -- User status feature -- User status
not_active: INTEGER = 0 not_active: INTEGER = 0

View File

@@ -1,56 +0,0 @@
note
description: "[
User profile used to extend information associated with a {CMS_USER}.
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_USER_PROFILE
inherit
TABLE_ITERABLE [READABLE_STRING_8, READABLE_STRING_GENERAL]
create
make
feature {NONE} -- Initialization
make
-- Create Current profile.
do
create items.make (0)
end
feature -- Access
item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
-- Profile item associated with key `k'.
do
Result := items.item (k)
end
feature -- Change
force (v: READABLE_STRING_8; k: READABLE_STRING_GENERAL)
-- Associated value `v' with key `k'.
do
items.force (v, k)
end
feature -- Access
new_cursor: TABLE_ITERATION_CURSOR [READABLE_STRING_8, READABLE_STRING_GENERAL]
-- Fresh cursor associated with current structure
do
Result := items.new_cursor
end
feature {NONE} -- Implementation
items: STRING_TABLE [READABLE_STRING_8]
;note
copyright: "2011-2014, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -80,7 +80,7 @@ feature -- Cursor
feature -- Action feature -- Action
action: FUNCTION [ANY, detachable TUPLE, G] action: FUNCTION [DB_TUPLE, G]
-- Agent to create a new item of type G. -- Agent to create a new item of type G.
feature {NONE} -- Implementation feature {NONE} -- Implementation

View File

@@ -1,30 +0,0 @@
BEGIN;
CREATE TABLE `logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category` VARCHAR(255) NOT NULL,
`level` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`message` text NOT NULL,
`info` text,
`link` text,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `custom_values` (
`type` VARCHAR(255) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`value` VARCHAR(255) NOT NULL
);
CREATE TABLE `path_aliases` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`source` varchar(255) NOT NULL,
`alias` varchar(255) NOT NULL,
`lang` varchar(12) DEFAULT NULL,
PRIMARY KEY (`pid`)
);
COMMIT;

View File

@@ -1,24 +0,0 @@
BEGIN;
CREATE TABLE nodes (
nid INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK( nid >=0),
revision INTEGER,
type TEXT NOT NULL,
title VARCHAR(255) NOT NULL,
summary TEXT,
content MEDIUMTEXT NOT NULL,
format VARCHAR(255),
author INTEGER,
publish DATETIME,
created DATETIME NOT NULL,
changed DATETIME NOT NULL,
status INTEGER
);
CREATE TABLE page_nodes(
nid INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK( nid >=0),
revision INTEGER,
parent INTEGER
);
COMMIT;

View File

@@ -1,76 +0,0 @@
BEGIN;
CREATE TABLE `users` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`password` varchar(100) NOT NULL,
`salt` varchar(100) NOT NULL,
`email` varchar(250) NOT NULL,
`status` int(11) DEFAULT NULL,
`created` datetime NOT NULL,
`signed` datetime DEFAULT NULL,
CHECK (`uid` >= 0),
PRIMARY KEY (`uid`),
UNIQUE KEY `name` (`name`)
);
CREATE TABLE `roles` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
CHECK (`rid` >= 0),
PRIMARY KEY (`rid`),
UNIQUE KEY `name` (`name`)
);
CREATE TABLE `users_roles` (
`uid` int(11) NOT NULL,
`rid` int(11) NOT NULL,
CHECK (`uid` >= 0),
CHECK (`rid` >= 0)
);
CREATE TABLE `role_permissions` (
`rid` int(11) NOT NULL,
`permission` varchar(255) NOT NULL,
`module` varchar(255) DEFAULT NULL,
CHECK (`rid` >= 0)
);
CREATE TABLE `users_activations` (
`aid` int(11) NOT NULL AUTO_INCREMENT,
`token` varchar(255) NOT NULL,
`uid` int(11) NOT NULL,
`created` datetime NOT NULL,
CHECK (`aid` >= 0),
CHECK (`uid` >= 0),
PRIMARY KEY (`aid`),
UNIQUE KEY `token` (`token`)
);
CREATE TABLE `users_password_recovery` (
`aid` int(11) NOT NULL AUTO_INCREMENT,
`token` varchar(255) NOT NULL,
`uid` int(11) NOT NULL,
`created` datetime NOT NULL,
CHECK (`aid` >= 0),
CHECK (`uid` >= 0),
PRIMARY KEY (`aid`),
UNIQUE KEY `token` (`token`)
);
CREATE TABLE `auth_temp_users` (
`uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
`name` VARCHAR(100) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`salt` VARCHAR(100) NOT NULL,
`email` VARCHAR(250) NOT NULL,
`application` TEXT NOT NULL,
CONSTRAINT `name`
UNIQUE(`name`)
);
COMMIT;

View File

@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="store_mysql" uuid="DC757CBD-D8C4-44D6-A07F-C1148D8D233E" library_target="store_mysql"> <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="store_mysql" uuid="DC757CBD-D8C4-44D6-A07F-C1148D8D233E" library_target="store_mysql">
<description>CMS Eiffel Store MySQL persistence solution</description>
<target name="store_mysql"> <target name="store_mysql">
<root all_classes="true"/> <root all_classes="true"/>
<option warning="true" void_safety="all"> <option warning="true" is_obsolete_routine_type="false" void_safety="all">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/> <assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option> </option>
<setting name="console_application" value="true"/> <setting name="console_application" value="true"/>
@@ -26,9 +27,9 @@
</cluster> </cluster>
<cluster name="persistence_store_mysql" location=".\src\" recursive="true"> <cluster name="persistence_store_mysql" location=".\src\" recursive="true">
<file_rule> <file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule> </file_rule>
</cluster> </cluster>
</target> </target>

View File

@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="persistence_store_odbc" uuid="8FD9D3B3-5FC1-495F-A05D-0205EC966841" library_target="persistence_store_odbc"> <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="persistence_store_odbc" uuid="8FD9D3B3-5FC1-495F-A05D-0205EC966841" library_target="persistence_store_odbc">
<target name="persistence_store_odbc"> <target name="persistence_store_odbc">
<description>CMS Eiffel Store ODBC persistence solution</description>
<root all_classes="true"/> <root all_classes="true"/>
<option warning="true" void_safety="all"> <option warning="true" is_obsolete_routine_type="false" void_safety="all">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/> <assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option> </option>
<setting name="console_application" value="true"/> <setting name="console_application" value="true"/>
@@ -22,9 +23,9 @@
<cluster name="common" location="..\implementation\store\" recursive="true"/> <cluster name="common" location="..\implementation\store\" recursive="true"/>
<cluster name="persistence_store_odbc" location=".\src\" recursive="true"> <cluster name="persistence_store_odbc" location=".\src\" recursive="true">
<file_rule> <file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule> </file_rule>
</cluster> </cluster>
</target> </target>

View File

@@ -166,7 +166,7 @@ feature -- Error
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE) do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor> -- <Precursor>
do do
if attached current_user (req) as l_user then if attached api.user as l_user then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if if
l_id.is_integer and then l_id.is_integer and then

View File

@@ -166,7 +166,7 @@ feature -- Error
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE) do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor> -- <Precursor>
do do
if attached current_user (req) as l_user then if attached api.user as l_user then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if if
l_id.is_integer and then l_id.is_integer and then

View File

@@ -73,7 +73,7 @@ feature -- Execution
s.append ("<div class=%"info%"> ") s.append ("<div class=%"info%"> ")
s.append ("<h4>Account Information</h4>") s.append ("<h4>Account Information</h4>")
s.append ("<p>Username: ") s.append ("<p>Username: ")
s.append (a_user.name) s.append (html_encoded (a_user.name))
s.append ("</p>") s.append ("</p>")
if attached a_user.email as l_email then if attached a_user.email as l_email then
s.append ("<p>Email: ") s.append ("<p>Email: ")
@@ -86,12 +86,13 @@ feature -- Execution
not l_roles.is_empty not l_roles.is_empty
then then
s.append ("<h4>Role(s):</h4>") s.append ("<h4>Role(s):</h4>")
s.append ("<ul class=%"user-roles%">")
across l_roles as ic loop across l_roles as ic loop
l_role := ic.item l_role := ic.item
s.append ("<i>") s.append ("<li>")
s.append (link (l_role.name, "admin/role/" + l_role.id.out, Void)) s.append (link (l_role.name, "admin/role/" + l_role.id.out, Void))
s.append ("</i>") s.append ("</li>")
debug if request.query_parameter ("debug") /= Void then
s.append ("<h5>Permissions:</h5>") s.append ("<h5>Permissions:</h5>")
s.append ("<ul class=%"cms-permissions%">%N") s.append ("<ul class=%"cms-permissions%">%N")
across l_role.permissions as perms_ic loop across l_role.permissions as perms_ic loop
@@ -100,6 +101,7 @@ feature -- Execution
s.append ("</ul>%N") s.append ("</ul>%N")
end end
end end
s.append ("</ul>%N")
end end
s.append ("</div>") s.append ("</div>")

View File

@@ -26,10 +26,6 @@
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/> <library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/> <library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf" readonly="false"/> <library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf" readonly="false"/>
<cluster name="src" location=".\" recursive="true"> <cluster name="src" location=".\" recursive="true"/>
<file_rule>
<exclude>^persistence$</exclude>
</file_rule>
</cluster>
</target> </target>
</system> </system>

View File

@@ -0,0 +1,17 @@
note
description: "[
Common interface for Auth module API.
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_AUTH_API_I
inherit
CMS_MODULE_API
create
make
end

View File

@@ -0,0 +1,44 @@
note
description: "[
Processes a HTTP request, and depending on header, authenticate a current user or not.
]"
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_AUTH_FILTER_I
inherit
WSF_FILTER
feature {NONE} -- Initialization
make (a_api: CMS_API)
-- Initialize Current handler with `a_api'.
do
api := a_api
end
feature -- API Service
api: CMS_API
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
deferred
end
auth_strategy: STRING
deferred
end
set_current_user (u: CMS_USER)
do
api.set_user (u)
-- Record auth strategy:
api.set_execution_variable ("auth_strategy", auth_strategy)
end
end

View File

@@ -0,0 +1,108 @@
note
description: "Common ancestor for Authentication modules."
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_AUTH_MODULE_I
inherit
CMS_MODULE
redefine
setup_hooks
end
CMS_HOOK_AUTO_REGISTER
CMS_HOOK_MENU_SYSTEM_ALTER
SHARED_LOGGER
feature {NONE} -- Initialization
make
do
package := "authentication"
add_dependency ({CMS_AUTHENTICATION_MODULE})
end
feature -- Access: auth strategy
login_title: READABLE_STRING_GENERAL
-- Module specific login title.
deferred
end
login_location: STRING
-- Login cms location for Current module.
deferred
end
logout_location: STRING
-- Logout cms location for Current module.
deferred
end
is_authenticating (a_response: CMS_RESPONSE): BOOLEAN
-- Is Current module strategy currently authenticating active user?
deferred
ensure
Result implies a_response.is_authenticated
end
feature -- Hooks configuration
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
-- Module hooks configuration.
do
auto_subscribe_to_hooks (a_hooks)
a_hooks.subscribe_to_menu_system_alter_hook (Current)
end
feature -- Hooks
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
-- <Precursor>
local
lnk: CMS_LOCAL_LINK
l_destination: READABLE_STRING_8
do
if attached {WSF_STRING} a_response.request.query_parameter ("destination") as p_destination then
l_destination := p_destination.value
else
l_destination := a_response.location
end
if is_authenticating (a_response) then
else
if a_response.location.starts_with ("account/auth/") then
create lnk.make (login_title, login_location)
if not l_destination.starts_with ("account/auth/") then
lnk.add_query_parameter ("destination", l_destination)
end
lnk.set_expandable (True)
a_response.add_to_primary_tabs (lnk)
end
end
end
feature {NONE} -- Helpers
template_block (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE): detachable CMS_SMARTY_TEMPLATE_BLOCK
-- Smarty content block for `a_block_id'
local
p: detachable PATH
do
create p.make_from_string ("templates")
p := p.extended ("block_").appended (a_block_id).appended_with_extension ("tpl")
p := a_response.api.module_theme_resource_location (Current, p)
if p /= Void then
if attached p.entry as e then
create Result.make (a_block_id, Void, p.parent, e)
else
create Result.make (a_block_id, Void, p.parent, p)
end
end
end
end

View File

@@ -0,0 +1,209 @@
note
description: "Summary description for {CMS_AUTHENTICATION_EMAIL_SERVICE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_AUTHENTICATION_EMAIL_SERVICE
create
make
feature {NONE} -- Initialization
make (a_params: like parameters)
-- Create instance of email service with `a_params' data.
do
parameters := a_params
initialize
end
initialize
-- Initialize service.
do
create error_handler.make
reset_error
end
feature -- Access
parameters: CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS
-- Associated parameters.
cms_api: CMS_API
do
Result := parameters.cms_api
end
contact_email_address: IMMUTABLE_STRING_8
-- contact email.
do
Result := parameters.contact_email_address
end
notif_email_address: IMMUTABLE_STRING_8
-- Site admin's email.
do
Result := parameters.notif_email_address
end
sender_email_address: IMMUTABLE_STRING_8
-- Site sender's email.
do
Result := parameters.sender_email_address
end
feature -- Error
error_handler: ERROR_HANDLER
has_error: BOOLEAN
do
Result := error_handler.has_error
end
reset_error
do
error_handler.reset
end
feature -- Basic Operations / Internal
send_internal_email (a_content: READABLE_STRING_GENERAL)
do
send_message (sender_email_address, notif_email_address, "Notification Contact", a_content)
end
send_email_internal_server_error (a_content: READABLE_STRING_GENERAL)
do
send_message (sender_email_address, notif_email_address, "Internal Server Error", a_content)
end
feature -- Basic Operations / Contact
send_account_evaluation (a_user: CMS_USER; a_application, a_url_activate, a_url_reject, a_host: READABLE_STRING_8)
-- Send new user register to webmaster to confirm or reject itt.
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_evaluation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
if attached a_user.email as l_email then
l_message.replace_substring_all ("$email", l_email)
else
l_message.replace_substring_all ("$email", "unknown email")
end
l_message.replace_substring_all ("$application", a_application)
l_message.replace_substring_all ("$activation_url", a_url_activate)
l_message.replace_substring_all ("$rejection_url", a_url_reject)
send_message (contact_email_address, contact_email_address, parameters.contact_subject_account_evaluation, l_message)
end
send_contact_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful contact message for user `a_user' to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
send_message (contact_email_address, a_to, parameters.contact_subject_register, l_message)
end
send_contact_activation_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_link, a_host: READABLE_STRING_8)
-- Send successful message activation to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_re_activation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$link", a_link)
send_message (contact_email_address, a_to, parameters.contact_subject_activate, l_message)
end
send_contact_activation_confirmation_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful message activation to a_to.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation_confirmation)
l_message.replace_substring_all ("$hot", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
l_message.replace_substring_all ("$email", a_to)
send_message (contact_email_address, a_to, parameters.contact_subject_activated, l_message)
end
send_contact_activation_reject_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful contact activation reject message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_rejected)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$email", a_to)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
send_message (contact_email_address, a_to, parameters.contact_subject_rejected, l_message)
end
send_contact_password_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_link, a_host: READABLE_STRING_8)
-- Send successful new account password message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_password)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$link", a_link)
send_message (contact_email_address, a_to, parameters.contact_subject_password, l_message)
end
send_contact_welcome_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful welcome message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_welcome)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$email", a_to)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
send_message (contact_email_address, a_to, parameters.contact_subject_oauth, l_message)
end
feature {NONE} -- Implementation
send_message (a_from_address, a_to_address: READABLE_STRING_8; a_subjet: READABLE_STRING_GENERAL; a_content: READABLE_STRING_GENERAL)
local
l_email: CMS_EMAIL
utf: UTF_CONVERTER
do
reset_error
l_email := cms_api.new_email (a_to_address, utf.escaped_utf_32_string_to_utf_8_string_8 (a_subjet), utf.escaped_utf_32_string_to_utf_8_string_8 (a_content))
l_email.set_from_address (a_from_address)
l_email.add_header_line ("MIME-Version:1.0")
l_email.add_header_line ("Content-Type: text/html; charset=utf-8")
cms_api.process_email (l_email)
if cms_api.has_error then
error_handler.add_custom_error (-1, generator + "send_message failed", cms_api.string_representation_of_errors)
end
end
end

View File

@@ -6,9 +6,6 @@ note
class class
CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS
inherit
EMAIL_SERVICE_PARAMETERS
create create
make make
@@ -18,23 +15,20 @@ feature {NONE} -- Initialization
local local
utf: UTF_CONVERTER utf: UTF_CONVERTER
s: detachable READABLE_STRING_32 s: detachable READABLE_STRING_32
l_utf8_site_name: IMMUTABLE_STRING_8
l_contact_email, l_subject_register, l_subject_activate, l_subject_password, l_subject_oauth: detachable READABLE_STRING_8 l_contact_email, l_subject_register, l_subject_activate, l_subject_password, l_subject_oauth: detachable READABLE_STRING_8
do do
cms_api := a_cms_api cms_api := a_cms_api
-- Use global smtp setting if any, otherwise "localhost" create l_utf8_site_name.make_from_string (a_cms_api.setup.utf_8_site_name)
smtp_server := utf.escaped_utf_32_string_to_utf_8_string_8 (a_cms_api.setup.text_item_or_default ("smtp", "localhost")) utf_8_site_name := l_utf8_site_name
site_name := utf.escaped_utf_32_string_to_utf_8_string_8 (a_cms_api.setup.site_name) notif_email_address := a_cms_api.setup.site_notification_email
admin_email := a_cms_api.setup.site_email sender_email_address := a_cms_api.setup.site_email
if not admin_email.has ('<') then if not notif_email_address.has ('<') then
admin_email := site_name + " <" + admin_email +">" notif_email_address := l_utf8_site_name + " <" + notif_email_address + ">"
end end
if attached {CONFIG_READER} a_cms_api.module_configuration_by_name ({CMS_AUTHENTICATION_MODULE}.name, Void) as cfg then if attached a_cms_api.module_configuration_by_name ({CMS_AUTHENTICATION_MODULE}.name, Void) as cfg then
if attached cfg.text_item ("smtp") as l_smtp then
-- Overwrite global smtp setting if any.
smtp_server := utf.utf_32_string_to_utf_8_string_8 (l_smtp)
end
s := cfg.text_item ("email") s := cfg.text_item ("email")
if s /= Void then if s /= Void then
l_contact_email := utf.utf_32_string_to_utf_8_string_8 (s) l_contact_email := utf.utf_32_string_to_utf_8_string_8 (s)
@@ -55,16 +49,15 @@ feature {NONE} -- Initialization
if s /= Void then if s /= Void then
l_subject_oauth := utf.utf_32_string_to_utf_8_string_8 (s) l_subject_oauth := utf.utf_32_string_to_utf_8_string_8 (s)
end end
end
if l_contact_email = Void then
l_contact_email := notif_email_address
end
if not l_contact_email.has ('<') then
l_contact_email := l_utf8_site_name + " <" + l_contact_email + ">"
end
contact_email_address := l_contact_email
end
if l_contact_email /= Void then
if not l_contact_email.has ('<') then
l_contact_email := site_name + " <" + l_contact_email + ">"
end
contact_email := l_contact_email
else
contact_email := admin_email
end
if l_subject_register /= Void then if l_subject_register /= Void then
contact_subject_register := l_subject_register contact_subject_register := l_subject_register
else else
@@ -87,11 +80,9 @@ feature {NONE} -- Initialization
contact_subject_oauth := "Welcome." contact_subject_oauth := "Welcome."
end end
contact_subject_account_evaluation := "New register, account evalution" contact_subject_account_evaluation := "New register, account evalution."
contact_subject_rejected := "Your account was rejected."
contact_subject_rejected := "Your account was rejected" contact_subject_activated := "Your account was activated."
contact_subject_activated := "Your account was activated"
end end
@@ -100,14 +91,14 @@ feature -- Access
cms_api: CMS_API cms_api: CMS_API
smtp_server: IMMUTABLE_STRING_8 notif_email_address: IMMUTABLE_STRING_8
admin_email: IMMUTABLE_STRING_8 sender_email_address: IMMUTABLE_STRING_8
contact_email: IMMUTABLE_STRING_8 contact_email_address: IMMUTABLE_STRING_8
-- Contact email. -- Contact email.
site_name: IMMUTABLE_STRING_8 utf_8_site_name: IMMUTABLE_STRING_8
-- UTF-8 encoded Site name. -- UTF-8 encoded Site name.
contact_subject_account_evaluation: IMMUTABLE_STRING_8 contact_subject_account_evaluation: IMMUTABLE_STRING_8
@@ -118,7 +109,6 @@ feature -- Access
contact_subject_rejected: IMMUTABLE_STRING_8 contact_subject_rejected: IMMUTABLE_STRING_8
contact_subject_activated: IMMUTABLE_STRING_8 contact_subject_activated: IMMUTABLE_STRING_8
account_evaluation: STRING account_evaluation: STRING
-- Account evaluation template email message. -- Account evaluation template email message.
do do
@@ -140,13 +130,13 @@ feature -- Access
account_re_activation: STRING account_re_activation: STRING
-- Account re_activation template email message. -- Account re_activation template email message.
do do
Result := template_string ("accunt_re_activation.html", default_template_account_re_activation) Result := template_string ("account_re_activation.html", default_template_account_re_activation)
end end
account_rejected: STRING account_rejected: STRING
-- Account rejected template email message. -- Account rejected template email message.
do do
Result := template_string ("accunt_rejected.html", default_template_account_rejected) Result := template_string ("account_rejected.html", default_template_account_rejected)
end end
account_password: STRING account_password: STRING
@@ -287,7 +277,7 @@ feature {NONE} -- Message email
</head> </head>
<body> <body>
<p>You requested has been rejected, your application does not conform our rules <a href="$host">$sitename</a></p> <p>Your account application is rejected, it does not conform our rules <a href="$host">$sitename</a></p>
</body> </body>
</html> </html>
]" ]"
@@ -326,7 +316,7 @@ feature {NONE} -- Message email
</head> </head>
<body> <body>
<p>You have required a new password at <a href="$host">$sitename</a></p> <p>You have requested a new password at <a href="$host">$sitename</a></p>
<p>To complete your request, please click on this link to generate a new password:<p> <p>To complete your request, please click on this link to generate a new password:<p>
@@ -347,7 +337,7 @@ feature {NONE} -- Message email
</head> </head>
<body> <body>
<p>Welcome to<a href="...">$sitename</a></p> <p>Welcome to <a href="$host">$sitename</a>.</p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -1,13 +1,12 @@
note note
description: "Module Auth" description: "Module Auth"
date: "$Date: 2015-05-20 06:50:50 -0300 (mi. 20 de may. de 2015) $" date: "$Date$"
revision: "$Revision: 97328 $" revision: "$Revision$"
class class
CMS_AUTHENTICATION_MODULE CMS_AUTHENTICATION_MODULE
inherit inherit
CMS_MODULE CMS_MODULE
redefine redefine
setup_hooks, setup_hooks,
@@ -33,8 +32,6 @@ inherit
SHARED_LOGGER SHARED_LOGGER
CMS_REQUEST_UTIL
create create
make make
@@ -82,6 +79,10 @@ feature -- Access: docs
feature -- Router feature -- Router
roc_login_location: STRING = "account/roc-login"
roc_logout_location: STRING = "account/roc-logout"
setup_router (a_router: WSF_ROUTER; a_api: CMS_API) setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor> -- <Precursor>
do do
@@ -90,18 +91,25 @@ feature -- Router
end end
configure_web (a_api: CMS_API; a_router: WSF_ROUTER) configure_web (a_api: CMS_API; a_router: WSF_ROUTER)
local
m: WSF_URI_MAPPING
do do
a_router.handle ("/account", create {WSF_URI_AGENT_HANDLER}.make (agent handle_account(a_api, ?, ?)), a_router.methods_head_get) create m.make_trailing_slash_ignored ("/account", create {WSF_URI_AGENT_HANDLER}.make (agent handle_account (a_api, ?, ?)))
a_router.handle ("/account/roc-login", create {WSF_URI_AGENT_HANDLER}.make (agent handle_login(a_api, ?, ?)), a_router.methods_head_get) a_router.map (m, a_router.methods_head_get)
a_router.handle ("/account/roc-logout", create {WSF_URI_AGENT_HANDLER}.make (agent handle_logout(a_api, ?, ?)), a_router.methods_head_get)
create m.make_trailing_slash_ignored ("/account/edit", create {WSF_URI_AGENT_HANDLER}.make (agent handle_edit_account (a_api, ?, ?)))
a_router.map (m, a_router.methods_head_get)
a_router.handle ("/" + roc_login_location, create {WSF_URI_AGENT_HANDLER}.make (agent handle_login(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/" + roc_logout_location, create {WSF_URI_AGENT_HANDLER}.make (agent handle_logout(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-register", create {WSF_URI_AGENT_HANDLER}.make (agent handle_register(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/roc-register", create {WSF_URI_AGENT_HANDLER}.make (agent handle_register(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/activate/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_activation(a_api, ?, ?)), a_router.methods_head_get) a_router.handle ("/account/activate/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_activation(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/reject/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_reject(a_api, ?, ?)), a_router.methods_head_get) a_router.handle ("/account/reject/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_reject(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/reactivate", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reactivation(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/reactivate", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reactivation(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/new-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_new_password(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/new-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_new_password(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/reset-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reset_password(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/reset-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reset_password(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_change_password(a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/change/{field}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_change_field (a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/post-change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_post_change_password(a_api, ?, ?)), a_router.methods_get)
end end
@@ -124,8 +132,35 @@ feature -- Hooks configuration
value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE) value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE)
-- <Precursor> -- <Precursor>
local
l_destination: detachable READABLE_STRING_GENERAL
l_url: STRING
l_url_name: READABLE_STRING_GENERAL
do do
a_value.force (a_response.user, "user") if attached {WSF_STRING} a_response.request.query_parameter ("destination") as p_destination then
l_destination := p_destination.value
else
l_destination := a_response.location
end
if l_destination.starts_with ("account/auth/") then
l_destination := Void
end
if attached a_response.user as u then
a_value.force (u, "user")
l_url_name := "site_sign_out_url"
l_url := a_response.url (roc_logout_location, Void)
else
a_value.force (Void, "user")
l_url_name := "site_sign_in_url"
l_url := a_response.url (roc_login_location, Void)
end
if l_destination /= Void then
l_url.append ("?destination=" + percent_encoded (l_destination))
end
a_value.force (l_url, l_url_name)
end end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
@@ -138,14 +173,22 @@ feature -- Hooks configuration
create lnk.make (u.name, "account") create lnk.make (u.name, "account")
lnk.set_weight (97) lnk.set_weight (97)
a_menu_system.primary_menu.extend (lnk) a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Logout", "account/roc-logout")
lnk.set_weight (98) create lnk.make ("Logout", roc_logout_location)
a_menu_system.primary_menu.extend (lnk)
else else
create lnk.make ("Login", "account/roc-login") create lnk.make ("Login", roc_login_location)
lnk.set_weight (98)
a_menu_system.primary_menu.extend (lnk)
end end
lnk.set_weight (98)
if
a_response.location.starts_with_general ("account/auth/")
or a_response.location.starts_with_general ("account/roc-log") -- in ou out
then
-- ignore destination
else
lnk.add_query_parameter ("destination", percent_encoded (a_response.location))
end
a_menu_system.primary_menu.extend (lnk)
-- Add the link to the taxonomy to the main menu -- Add the link to the taxonomy to the main menu
if a_response.has_permission ("admin registration") then if a_response.has_permission ("admin registration") then
create lnk.make ("Registration", "admin/pending-registrations/") create lnk.make ("Registration", "admin/pending-registrations/")
@@ -158,18 +201,78 @@ feature -- Handler
handle_account (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_account (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
l_user: detachable CMS_USER
b: STRING
lnk: CMS_LOCAL_LINK
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
create b.make_empty
l_user := r.user
if attached template_block ("account_info", r) as l_tpl_block then if attached template_block ("account_info", r) as l_tpl_block then
if attached r.user as l_user then l_tpl_block.set_weight (-10)
r.set_value (api.user_api.user_roles (l_user), "roles")
end
r.add_block (l_tpl_block, "content") r.add_block (l_tpl_block, "content")
else else
debug ("cms") debug ("cms")
r.add_warning_message ("Error with block [resources_page]") r.add_warning_message ("Error with block [resources_page]")
end end
end end
if r.is_authenticated then
create lnk.make ("View", "account/")
lnk.set_weight (1)
r.add_to_primary_tabs (lnk)
create lnk.make ("Edit", "account/edit")
lnk.set_weight (2)
r.add_to_primary_tabs (lnk)
end
r.set_main_content (b)
if l_user = Void then
r.set_redirection (roc_login_location)
end
r.execute
end
handle_edit_account (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
l_user: detachable CMS_USER
b: STRING
f: CMS_FORM
lnk: CMS_LOCAL_LINK
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
create b.make_empty
l_user := r.user
if attached template_block ("account_edit", r) as l_tpl_block then
l_tpl_block.set_weight (-10)
r.add_block (l_tpl_block, "content")
else
debug ("cms")
r.add_warning_message ("Error with block [resources_page]")
end
end
create lnk.make ("View", "account/")
lnk.set_weight (1)
r.add_to_primary_tabs (lnk)
create lnk.make ("Edit", "account/edit")
lnk.set_weight (2)
r.add_to_primary_tabs (lnk)
f := new_change_password_form (r)
f.append_to_html (r.wsf_theme, b)
f := new_change_email_form (r)
f.append_to_html (r.wsf_theme, b)
r.set_main_content (b)
if l_user = Void then
r.set_redirection ("account")
end
r.execute r.execute
end end
@@ -177,10 +280,30 @@ feature -- Handler
local local
r: CMS_RESPONSE r: CMS_RESPONSE
do do
if attached api.module_by_name ("basic_auth") then if api.user_is_authenticated then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.set_redirection ("account")
r.execute
elseif attached 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, api)
r.set_redirection (r.absolute_url ("/account/roc-basic-auth", Void)) if attached {WSF_STRING} req.query_parameter ("destination") as l_destination then
r.set_redirection ("account/auth/roc-session-login?destination=" + l_destination.url_encoded_value)
else
r.set_redirection ("account/auth/roc-session-login")
end
r.execute
elseif attached api.module_by_name ("basic_auth") then
-- FIXME: find better solution to support a default login system.
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if attached {WSF_STRING} req.query_parameter ("destination") as l_destination then
r.set_redirection ("account/auth/roc-basic-login?destination=" + l_destination.url_encoded_value)
else
r.set_redirection ("account/auth/roc-basic-login")
end
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, api)
@@ -191,9 +314,19 @@ feature -- Handler
handle_logout (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_logout (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
loc: STRING
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.set_redirection (r.absolute_url ("", Void)) if attached {READABLE_STRING_8} api.execution_variable ("auth_strategy") as l_auth_strategy then
loc := l_auth_strategy
else
loc := ""
end
if attached {WSF_STRING} req.query_parameter ("destination") as l_destination then
loc.append ("?destination=" + l_destination.url_encoded_value)
end
r.set_redirection (loc)
r.execute r.execute
end end
@@ -203,68 +336,84 @@ feature -- Handler
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
u: CMS_TEMP_USER u: CMS_TEMP_USER
l_exist: BOOLEAN l_exist: BOOLEAN
es: CMS_AUTHENTICATON_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_url_activate: STRING l_url_activate: STRING
l_url_reject: STRING l_url_reject: STRING
l_token: STRING l_token: STRING
l_captcha_passed: BOOLEAN l_captcha_passed: BOOLEAN
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, api)
if r.has_permission ("account register") then if r.has_permission ("account register") then
if req.is_post_request_method then if req.is_post_request_method then
if attached {WSF_STRING} req.form_parameter ("name") as l_name and then attached {WSF_STRING} req.form_parameter ("password") as l_password and then attached {WSF_STRING} req.form_parameter ("email") as l_email and then attached {WSF_STRING} req.form_parameter ("personal_information") as l_personal_information then if
l_user_api := api.user_api attached {WSF_STRING} req.form_parameter ("name") as l_name and then
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 attached {WSF_STRING} req.form_parameter ("password") as l_password and then
-- Username already exist. attached {WSF_STRING} req.form_parameter ("email") as p_email and then
r.set_value ("User name already exists!", "error_name") attached {WSF_STRING} req.form_parameter ("personal_information") as l_personal_information
l_exist := True then
end if p_email.value.is_valid_as_string_8 then
if attached l_user_api.user_by_email (l_email.value) or else attached l_user_api.temp_user_by_email (l_email.value) then l_email := p_email.value.to_string_8
-- Emails already exist. l_user_api := api.user_api
r.set_value ("An account is already associated with that email address!", "error_email") 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
l_exist := True -- Username already exist.
end r.set_value ("User name already exists!", "error_name")
if attached recaptcha_secret_key (api) as l_recaptcha_key then l_exist := True
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.value) then end
l_captcha_passed := True 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.
r.set_value ("An account is already associated with that email address!", "error_email")
l_exist := True
end
if attached recaptcha_secret_key (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.value) then
l_captcha_passed := True
else
--| Bad or missing captcha
l_captcha_passed := False
end
else else
--| Bad or missing captcha --| reCaptcha is not setup, so no verification
l_captcha_passed := False l_captcha_passed := True
end
if not l_exist then
-- New temp user
create u.make (l_name.value)
u.set_email (l_email)
u.set_password (l_password.value)
u.set_personal_information (l_personal_information.value)
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
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
r.set_value (l_name.value, "name")
r.set_value (l_email, "email")
r.set_value (l_personal_information.value, "personal_information")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
else
--| reCaptcha is not setup, so no verification
l_captcha_passed := True
end
if not l_exist then
-- New temp user
create u.make (l_name.value)
u.set_email (l_email.value)
u.set_password (l_password.value)
u.set_personal_information (l_personal_information.value)
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
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.value, l_name.value, req.absolute_script_url (""))
else else
r.set_value (l_name.value, "name") r.set_value (l_name.value, "name")
r.set_value (l_email.value, "email") r.set_value (p_email.value, "email")
r.set_value (l_personal_information.value, "personal_information") r.set_value (l_personal_information.value, "personal_information")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
else
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.set_main_content ("There were issue with your application, invalid or missing values.")
end end
end end
else else
@@ -279,7 +428,7 @@ feature -- Handler
r: CMS_RESPONSE r: CMS_RESPONSE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE
es: CMS_AUTHENTICATON_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
do do
l_user_api := api.user_api l_user_api := api.user_api
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
@@ -299,12 +448,12 @@ feature -- Handler
l_user.mark_active l_user.mark_active
l_user_api.new_user_from_temp_user (l_user) l_user_api.new_user_from_temp_user (l_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>" + l_user.name + "</i> has been activated</p>") r.set_main_content ("<p> The account <i>" + html_encoded (l_user.name) + "</i> has been activated</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 (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, "", req.absolute_script_url ("")) es.send_contact_activation_confirmation_email (l_email, l_user, req.absolute_script_url (""))
end end
else else
-- the token does not exist, or it was already used. -- the token does not exist, or it was already used.
@@ -325,8 +474,8 @@ feature -- Handler
handle_reject (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_reject (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE
es: CMS_AUTHENTICATON_EMAIL_SERVICE
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, api)
@@ -335,12 +484,12 @@ feature -- Handler
l_user_api := api.user_api l_user_api := 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>" + 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 (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, "", req.absolute_script_url ("")) es.send_contact_activation_reject_email (l_email, l_user, req.absolute_script_url (""))
end end
else else
-- the token does not exist, or it was already used. -- the token does not exist, or it was already used.
@@ -361,37 +510,45 @@ feature -- Handler
handle_reactivation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_reactivation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
es: CMS_AUTHENTICATON_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
l_token: STRING l_token: STRING
l_url_activate: STRING l_url_activate: STRING
l_url_reject: STRING l_url_reject: STRING
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, api)
if r.has_permission ("account reactivate") then if r.has_permission ("account reactivate") then
if req.is_post_request_method then if req.is_post_request_method then
if attached {WSF_STRING} req.form_parameter ("email") as l_email then if attached {WSF_STRING} req.form_parameter ("email") as p_email then
l_user_api := api.user_api if p_email.value.is_valid_as_string_8 then
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_email (l_email.value) as l_user then l_email := p_email.value.to_string_8
-- User exist create a new token and send a new email. l_user_api := api.user_api
if l_user.is_active then if attached {CMS_TEMP_USER} l_user_api.temp_user_by_email (l_email) as l_user then
r.set_value ("The asociated user to the given email " + l_email.value + " , is already active", "is_active") -- User exist create a new token and send a new email.
r.set_status_code ({HTTP_CONSTANTS}.bad_request) if l_user.is_active then
else r.set_value ("The asociated user to the given email " + l_email + " , is already active", "is_active")
l_token := new_token r.set_status_code ({HTTP_CONSTANTS}.bad_request)
l_user_api.new_activation (l_token, l_user.id) else
l_url_activate := req.absolute_script_url ("/account/activate/" + l_token) l_token := new_token
l_url_reject := req.absolute_script_url ("/account/reject/" + l_token) l_user_api.new_activation (l_token, l_user.id)
-- Send Email to webmaster l_url_activate := req.absolute_script_url ("/account/activate/" + l_token)
if attached l_user.personal_information as l_personal_information then l_url_reject := req.absolute_script_url ("/account/reject/" + l_token)
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) -- Send Email to webmaster
write_debug_log (generator + ".handle register: send_register_email") if attached l_user.personal_information as l_personal_information then
es.send_account_evaluation (l_user, l_personal_information, l_url_activate, l_url_reject, req.absolute_script_url ("")) create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
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 (""))
end
end end
else
r.set_value ("The email does not exist !", "error_email")
r.set_value (l_email, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
else else
r.set_value ("The email does not exist or !", "error_email") r.set_value ("The email is not valid!", "error_email")
r.set_value (l_email.value, "email") r.set_value (p_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
end end
@@ -406,32 +563,43 @@ feature -- Handler
handle_new_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_new_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
es: CMS_AUTHENTICATON_EMAIL_SERVICE es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_user_api: CMS_USER_API l_user_api: CMS_USER_API
l_token: STRING l_token: STRING
l_url: STRING l_url: STRING
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, api)
if req.is_post_request_method then if req.is_post_request_method then
l_user_api := api.user_api l_user_api := api.user_api
if attached {WSF_STRING} req.form_parameter ("email") as l_email then if attached {WSF_STRING} req.form_parameter ("email") as p_email then
if attached {CMS_USER} l_user_api.user_by_email (l_email.value) as l_user then if p_email.value.is_valid_as_string_8 then
-- User exist create a new token and send a new email. l_email := p_email.value.to_string_8
l_token := new_token if attached {CMS_USER} l_user_api.user_by_email (l_email) as l_user then
l_user_api.new_password (l_token, l_user.id) -- User exist create a new token and send a new email.
l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token) l_token := new_token
l_user_api.new_password (l_token, l_user.id)
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 (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.value, l_url, req.absolute_script_url ("")) es.send_contact_password_email (l_email, l_user, l_url, req.absolute_script_url (""))
else
r.set_value ("The email does not exist !", "error_email")
r.set_value (p_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
else else
r.set_value ("The email does not exist !", "error_email") r.set_value ("The email is not valid!", "error_email")
r.set_value (l_email.value, "email") r.set_value (p_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end end
elseif attached {WSF_STRING} req.form_parameter ("username") as l_username then elseif attached {WSF_STRING} req.form_parameter ("username") as l_username then
if attached {CMS_USER} l_user_api.user_by_name (l_username) as l_user and then attached l_user.email as l_email then if
attached {CMS_USER} l_user_api.user_by_name (l_username) as l_user and then
attached l_user.email as l_user_email
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 := new_token
l_user_api.new_password (l_token, l_user.id) l_user_api.new_password (l_token, l_user.id)
@@ -440,7 +608,7 @@ feature -- Handler
-- 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 (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_url, req.absolute_script_url ("")) es.send_contact_password_email (l_user_email, l_user, l_url, req.absolute_script_url (""))
else else
r.set_value ("The username does not exist !", "error_username") r.set_value ("The username does not exist !", "error_username")
r.set_value (l_username.value, "username") r.set_value (l_username.value, "username")
@@ -485,46 +653,91 @@ feature -- Handler
r.execute r.execute
end end
handle_change_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_change_field (api: CMS_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
f: CMS_FORM
l_fieldname: detachable READABLE_STRING_8
b: STRING
lnk: CMS_LOCAL_LINK
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) if attached {WSF_STRING} req.path_parameter ("field") as p_field then
l_user_api := api.user_api l_fieldname := p_field.url_encoded_value
if req.is_post_request_method then end
if attached r.user as l_user then if l_fieldname = Void then
r.set_value (api.user_api.user_roles (l_user), "roles") create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
if attached {WSF_STRING} req.form_parameter ("password") as l_password and then attached {WSF_STRING} req.form_parameter ("confirm_password") as l_confirm_password and then l_password.value.same_string (l_confirm_password.value) then else
-- Does the passwords match? create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
l_user.set_password (l_password.value)
l_user_api.update_user (l_user) if r.is_authenticated then
r.set_redirection (req.absolute_script_url ("/account/post-change-password")) create lnk.make ("View", "account/")
else lnk.set_weight (1)
if attached template_block ("account_info", r) as l_tpl_block then r.add_to_primary_tabs (lnk)
-- r.set_value (l_user, "user")
r.set_value ("Passwords Don't Match", "error_password") create lnk.make ("Edit", "account/edit")
r.set_status_code ({HTTP_CONSTANTS}.bad_request) lnk.set_weight (2)
r.add_block (l_tpl_block, "content") r.add_to_primary_tabs (lnk)
end
l_user_api := api.user_api
if req.is_post_request_method then
if attached r.user as l_user then
if l_fieldname.is_case_insensitive_equal ("password") then
if
attached {WSF_STRING} req.form_parameter ("password") as l_password and then
attached {WSF_STRING} req.form_parameter ("confirm_password") as l_confirm_password and then
l_password.value.same_string (l_confirm_password.value)
then
-- passwords matched?
l_user.set_password (l_password.value)
l_user_api.update_user (l_user)
r.add_success_message ("Password updated.")
r.set_redirection ("account/")
r.set_redirection_delay (3)
else
r.add_error_message ("Passwords do not match!")
f := new_change_password_form (r)
r.set_main_content (f.to_html (r.wsf_theme))
end
elseif l_fieldname.is_case_insensitive_equal ("email") then
-- FIXME: find a safer workflow .. allow multiple emails, and have a primary email?
if
attached {WSF_STRING} req.form_parameter ("email") as l_email and then
attached {WSF_STRING} req.form_parameter ("confirm_email") as l_confirm_email and then
l_email.value.same_string (l_confirm_email.value) and then
l_email.value.is_valid_as_string_8
then
-- emails matched?
l_user.set_email (l_email.value.to_string_8)
l_user_api.update_user (l_user)
r.add_success_message ("Email updated.")
r.set_redirection ("account/")
r.set_redirection_delay (3)
else
r.add_error_message ("Emails do not match!")
f := new_change_email_form (r)
r.set_main_content (f.to_html (r.wsf_theme))
end
else
r.add_error_message ("You can not change %"" + l_fieldname + "%" information!")
end end
end end
else
create b.make_empty
if l_fieldname.is_case_insensitive_equal_general ("password") then
f := new_change_password_form (r)
f.append_to_html (r.wsf_theme, b)
elseif l_fieldname.is_case_insensitive_equal_general ("email") then
f := new_change_email_form (r)
f.append_to_html (r.wsf_theme, b)
end
r.set_main_content (b)
end end
end end
r.execute r.execute
end end
handle_post_change_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if attached template_block ("post_change", r) as l_tpl_block then
r.add_block (l_tpl_block, "content")
end
r.execute
end
handle_admin_pending_registrations (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API) handle_admin_pending_registrations (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
local local
l_response: CMS_RESPONSE l_response: CMS_RESPONSE
@@ -573,11 +786,11 @@ feature -- Handler
loop loop
u := ic.item u := ic.item
s.append ("<li class=%"cms_temp_user%">") s.append ("<li class=%"cms_temp_user%">")
s.append ("User:" + u.name) s.append ("User:" + html_encoded (u.name))
s.append ("<ul class=%"cms_temp_user_details%">") s.append ("<ul class=%"cms_temp_user_details%">")
if attached u.personal_information as l_information then if attached u.personal_information as l_information then
s.append ("<li class=%"cms_temp_user_detail_information%">") s.append ("<li class=%"cms_temp_user_detail_information%">")
s.append (l_information) s.append (html_encoded (l_information))
s.append ("</li>%N") s.append ("</li>%N")
end end
if attached u.email as l_email then if attached u.email as l_email then
@@ -616,39 +829,76 @@ feature -- Handler
end end
end end
block_list: ITERABLE [like {CMS_BLOCK}.name] block_list: ITERABLE [like {CMS_BLOCK}.name]
local
l_string: STRING
do do
Result := <<"register", "reactivate", "new_password", "reset_password", "registration">> Result := <<"register", "reactivate", "new_password", "reset_password", "registration">>
debug ("roc")
create l_string.make_empty
across
Result as ic
loop
l_string.append (ic.item)
l_string.append_character (' ')
end
write_debug_log (generator + ".block_list:" + l_string)
end
end end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE) get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
local
loc: READABLE_STRING_8
do do
if a_block_id.is_case_insensitive_equal_general ("register") and then a_response.location.starts_with ("account/roc-register") then loc := a_response.location
if a_block_id.is_case_insensitive_equal_general ("register") and then loc.starts_with ("account/roc-register") then
get_block_view_register (a_block_id, a_response) get_block_view_register (a_block_id, a_response)
elseif a_block_id.is_case_insensitive_equal_general ("reactivate") and then a_response.location.starts_with ("account/reactivate") then elseif a_block_id.is_case_insensitive_equal_general ("reactivate") and then loc.starts_with ("account/reactivate") then
get_block_view_reactivate (a_block_id, a_response) get_block_view_reactivate (a_block_id, a_response)
elseif a_block_id.is_case_insensitive_equal_general ("new_password") and then a_response.location.starts_with ("account/new-password") then elseif a_block_id.is_case_insensitive_equal_general ("new_password") and then loc.starts_with ("account/new-password") then
get_block_view_new_password (a_block_id, a_response) get_block_view_new_password (a_block_id, a_response)
elseif a_block_id.is_case_insensitive_equal_general ("reset_password") and then a_response.location.starts_with ("account/reset-password") then elseif a_block_id.is_case_insensitive_equal_general ("reset_password") and then loc.starts_with ("account/reset-password") then
get_block_view_reset_password (a_block_id, a_response) get_block_view_reset_password (a_block_id, a_response)
elseif a_block_id.is_case_insensitive_equal_general ("registration") and then a_response.location.starts_with ("admin/pending-registrations") then elseif a_block_id.is_case_insensitive_equal_general ("registration") and then loc.starts_with ("admin/pending-registrations") then
get_block_view_registration (a_block_id, a_response) get_block_view_registration (a_block_id, a_response)
end end
end end
new_change_password_form (a_response: CMS_RESPONSE): CMS_FORM
local
fs: WSF_FORM_FIELD_SET
pwd: WSF_FORM_PASSWORD_INPUT
do
create Result.make (a_response.url ("account/change/password", Void), "change-password-form")
create fs.make
fs.set_legend ("Change password")
Result.extend (fs)
create pwd.make ("password")
pwd.set_label ("Password")
pwd.enable_required
fs.extend (pwd)
create pwd.make ("confirm_password")
pwd.set_label ("Confirm password")
pwd.enable_required
fs.extend (pwd)
-- create but.make_with_text ("op", "Confirm")
-- fs.extend (but)
fs.extend_html_text ("<button type=%"submit%">Confirm</button>")
end
new_change_email_form (a_response: CMS_RESPONSE): CMS_FORM
local
fs: WSF_FORM_FIELD_SET
tf: WSF_FORM_EMAIL_INPUT
do
create Result.make (a_response.url ("account/change/email", Void), "change-email-form")
create fs.make
fs.set_legend ("Change email")
Result.extend (fs)
create tf.make ("email")
tf.set_label ("Email")
tf.enable_required
fs.extend (tf)
create tf.make ("confirm_email")
tf.set_label ("Confirm email")
tf.enable_required
fs.extend (tf)
fs.extend_html_text ("<button type=%"submit%">Confirm</button>")
end
feature {NONE} -- Token Generation feature {NONE} -- Token Generation
new_token: STRING new_token: STRING

View File

@@ -1,148 +0,0 @@
note
description: "Summary description for {CMS_AUTHENTICATON_EMAIL_SERVICE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_AUTHENTICATON_EMAIL_SERVICE
inherit
EMAIL_SERVICE
redefine
initialize,
parameters
end
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
contact_email := parameters.contact_email
end
parameters: CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS
-- Associated parameters.
feature -- Access
contact_email: IMMUTABLE_STRING_8
-- contact email.
feature -- Basic Operations
send_account_evaluation (a_user: CMS_USER; a_application, a_url_activate, a_url_reject, a_host: READABLE_STRING_8)
-- Send new user register to webmaster to confirm or reject itt.
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_evaluation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.site_name)
l_message.replace_substring_all ("$user", a_user.name)
if attached a_user.email as l_email then
l_message.replace_substring_all ("$email", l_email)
else
l_message.replace_substring_all ("$email", "unknown email")
end
l_message.replace_substring_all ("$application", a_application)
l_message.replace_substring_all ("$activation_url", a_url_activate)
l_message.replace_substring_all ("$rejection_url", a_url_reject)
send_message (contact_email, contact_email, parameters.contact_subject_account_evaluation, l_message)
end
send_contact_email (a_to, a_user, a_host: READABLE_STRING_8)
-- Send successful contact message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.site_name)
l_message.replace_substring_all ("$user", a_user)
send_message (contact_email, a_to, parameters.contact_subject_register, l_message)
end
send_contact_activation_email (a_to, a_content, a_host: READABLE_STRING_8)
-- Send successful contact activation message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_re_activation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.site_name)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_activate, l_message)
end
send_contact_activation_confirmation_email (a_to, a_content, a_host: READABLE_STRING_8)
-- Send successful message activation to a_to.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation_confirmation)
l_message.replace_substring_all ("$hot", a_host)
l_message.replace_substring_all ("$sitename", parameters.site_name)
l_message.replace_substring_all ("$email", a_content)
send_message (contact_email, a_to, parameters.contact_subject_activated, l_message)
end
send_contact_activation_reject_email (a_to, a_content, a_host: READABLE_STRING_8)
-- Send successful contact activation reject message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_rejected)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.site_name)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_rejected, l_message)
end
send_contact_password_email (a_to, a_content, a_host: READABLE_STRING_8)
-- Send successful new account password message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_password)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.site_name)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_password, l_message)
end
send_contact_welcome_email (a_to, a_content, a_host: READABLE_STRING_8)
-- Send successful welcome message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_welcome)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitenme", parameters.site_name)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_oauth, l_message)
end
end

View File

@@ -1,8 +1,7 @@
{ {
"email": "webmaster@eiffel.org",
"subject": "Thank you for contacting us", "subject": "Thank you for contacting us",
"recaptcha": { "recaptcha": {
"site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD", "site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD",
"secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx" "secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx"
} }
} }

View File

@@ -1,22 +1,28 @@
ul.cms-temp-users { ul.cms-temp-users {
list-style-type: none; list-style-type: none;
padding: 3px 3px 3px 3px; padding: 3px 3px 3px 3px;
border: solid 1px #ccc; } border: solid 1px #ccc;
ul.cms-temp-users li { }
border-top: dotted 1px #ccc; } ul.cms-temp-users li {
ul.cms-temp-users li:first-child { border-top: dotted 1px #ccc;
border-top: none; } }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details { ul.cms-temp-users li:first-child {
list-style-type: none; border-top: none;
padding: 3px 3px 3px 3px; }
border: solid 1px #ccc; } ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details {
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li { list-style-type: none;
border-top: dotted 1px #ccc; } padding: 3px 3px 3px 3px;
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child { border: solid 1px #ccc;
border-top: none; } }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before { ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li {
content: "[personal information] "; } border-top: dotted 1px #ccc;
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before { }
content: "[email] "; } ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child {
border-top: none;
/*# sourceMappingURL=auth.css.map */ }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before {
content: "[personal information] ";
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before {
content: "[email] ";
}

View File

@@ -1,22 +0,0 @@
ul.cms-temp-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc; }
ul.cms-temp-users li {
border-top: dotted 1px #ccc; }
ul.cms-temp-users li:first-child {
border-top: none; }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc; }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li {
border-top: dotted 1px #ccc; }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child {
border-top: none; }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before {
content: "[personal information] "; }
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before {
content: "[email] "; }
/*# sourceMappingURL=auth.css.map */

View File

@@ -1,7 +0,0 @@
{
"version": 3,
"mappings": "AAAA,iBAAkB;EAEjB,eAAe,EAAE,IAAI;EACrB,OAAO,EAAE,eAAe;EACxB,MAAM,EAAE,cAAc;EAEtB,oBAAE;IACD,UAAU,EAAE,eAAe;IAC3B,gCAAc;MACb,UAAU,EAAE,IAAI;EAMjB,2DAAyB;IACxB,eAAe,EAAE,IAAI;IACrB,OAAO,EAAE,eAAe;IACxB,MAAM,EAAE,cAAc;IAEtB,8DAAE;MACD,UAAU,EAAE,eAAe;MAC3B,0EAAc;QACb,UAAU,EAAE,IAAI;IAGlB,uGAA2C;MAC1C,OAAO,EAAE,yBAAyB;IAEnC,iGAAqC;MACpC,OAAO,EAAE,UAAU",
"sources": ["auth.scss"],
"names": [],
"file": "auth.css"
}

View File

@@ -1,14 +1,13 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Activation</title> <title>Activation</title>
<meta name="description" content="Activation"> <meta name="description" content="Activation">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>Thank you for applying to <a href="$host">$sitename</a> $user</p> <p>"$user ($email)", thank you for applying to <a href="$host">$sitename</a>.</p>
<p>We will review your application and send you a resolution<p> <p>We will review your application and send you a resolution.<p>
</body> </body>
</html> </html>

View File

@@ -6,9 +6,8 @@
<meta name="description" content="Activation Confirmation"> <meta name="description" content="Activation Confirmation">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>Your account has been confirmed <a href="$host">$sitename</a> $email</p> <p>Your account "$user ($email)" is confirmed at <a href="$host">$sitename</a>.</p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -6,12 +6,10 @@
<meta name="description" content="New Password"> <meta name="description" content="New Password">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>You have required a new password at <a href="$host">$sitename</a></p> <p>You have requested a new password at <a href="$host">$sitename</a>.</p>
<p>To complete your request, please click on the following link to generate a new password:
<p>To complete your request, please click on this link to generate a new password:<p> <ul><a href="$link">$link</a></ul>
</p>
<p><a href="$link">$link</a></p>
</body> </body>
</html> </html>

View File

@@ -6,13 +6,12 @@
<meta name="description" content="New Activation token"> <meta name="description" content="New Activation token">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>You have request a new activation token at <a href="$host">$sitename</a></p> <p>You have requested a new activation token at <a href="$host">$sitename</a>.</p>
<p>To complete your registration, please click on this link to activate your account:<p> <p>To complete your registration, please click on the following link to re-activate your account:
<ul><a href="$link">$link</a></ul>
<p><a href="$link">$link</a></p> </p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -6,8 +6,7 @@
<meta name="description" content="Application Rejected"> <meta name="description" content="Application Rejected">
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>You requested has been rejected, your application does not conform our rules <a href="$host">$sitename</a></p> <p>Your account application is rejected, it was not respecting the requirements from <a href="$host">$sitename</a>.</p>
</body> </body>
</html> </html>

View File

@@ -7,7 +7,13 @@
<meta name="author" content="$sitename"> <meta name="author" content="$sitename">
</head> </head>
<body> <body>
<p>Welcome to <a href="$host">$sitename</a></p> <p>Welcome to <a href="$host">$sitename</a>.</p>
<p>Your account information:
<ul>
<li>Email address: "$email" .</li>
<li>User name: "$user" .</li>
</ul>
</p>
<p>Thank you for joining us.</p> <p>Thank you for joining us.</p>
</body> </body>
</html> </html>

View File

@@ -1,13 +0,0 @@
CREATE TABLE `auth_temp_users` (
`uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
`name` VARCHAR(100) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`salt` VARCHAR(100) NOT NULL,
`email` VARCHAR(250) NOT NULL,
`application` TEXT NOT NULL,
CONSTRAINT `name`
UNIQUE(`name`)
);

View File

@@ -0,0 +1 @@
{include file="block_account_info.tpl" /}

View File

@@ -1,62 +1,34 @@
<div class="primary-tabs"> <div class="primary-tabs">
{if isset="$user"} {if isset="$user"}
<h3>Account Information</h3> <h3>Account Information</h3>
<div> <ul class="user-information">
<div> <div>
<div> <label>Username:</label> {$user.name/}
<label>Username:</label> {$user.name/}
</div>
<div>
<label>Email:</label> {$user.email/}
</div>
<div>
<label>Creation Date:</label> {$user.creation_date/}
</div>
<div>
<label>Last login:</label> {$user.last_login_date/}
</div>
<div>
<form method="get" action="{$site_url/}{$auth_login_strategy/}">
<button type="submit">Logout</button>
</form>
</div>
</div> </div>
</div> <div>
<hr> <label>Email:</label> {$user.email/}
{include file="block_change_password.tpl" /} </div>
<hr> <div>
<h4>Roles</h4> <label>Creation Date:</label> {$user.creation_date/} (UTC)
<div> </div>
{foreach item="ic" from="$roles"} <div>
<div> <label>Last login:</label> {$user.last_login_date/} (UTC)
<ul> </div>
<li> <div>
<strong>{$ic.name/}</strong> <form method="get" action="{$site_url/}account/roc-logout">
<ul> <button type="submit">Logout</button>
<li> <i>permissions</i> </form>
<ul> </div>
{foreach item="ip" from="$ic.permissions"} </ul>
<li>{$ip/}</li>
{/foreach}
</ul>
</li>
</ul>
</li>
</ul>
</div>
{/foreach}
</div>
<hr> <hr>
<h4>Profile</h4> <h4>Profile</h4>
<div> <ul class="user-profile">
{foreach item="the_value" key="the_name" from="$user.profile"} {foreach item="the_value" key="the_name" from="$user.profile"}
<div> <li>
<label>{$the_name/}:</label> {$the_value/} <label>{$the_name/}:</label><div>{$the_value/}</div>
</div> </li>
{/foreach} {/foreach}
</div> </ul>
{/if} {/if}
{unless isset="$user"} {unless isset="$user"}
<div> <div>

View File

@@ -1,7 +1,7 @@
<div> <div>
<form action="{$site_url/}account/change-password" method="post"> <form action="{$site_url/}account/change-password" method="post">
<fieldset> <fieldset>
<legend>Change Password Form</legend> <legend>Change Password</legend>
<div> <div>
<input type="password" id="password" name="password" value="" required/> <input type="password" id="password" name="password" value="" required/>
<label for="password">Password</label> <label for="password">Password</label>

View File

@@ -1,29 +0,0 @@
<div class="primary-tabs">
{unless isset="$user"}
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div>
<div>
<form action method="POST">
<div>
<input type="text" name="username" required>
<label>Username</label>
</div>
<div>
<input type="password" name="password" required>
<label>Password</label>
</div>
<button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
</div>
</div>
<div>
<div>
<p>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div>
{/unless}
</div>

View File

@@ -10,24 +10,17 @@ class
CMS_BASIC_AUTH_MODULE CMS_BASIC_AUTH_MODULE
inherit inherit
CMS_MODULE CMS_AUTH_MODULE_I
rename
module_api as basic_auth_api
redefine redefine
make,
filters, filters,
setup_hooks setup_hooks
end end
CMS_HOOK_AUTO_REGISTER
CMS_HOOK_BLOCK CMS_HOOK_BLOCK
CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_VALUE_TABLE_ALTER
SHARED_LOGGER
CMS_REQUEST_UTIL
create create
make make
@@ -35,26 +28,42 @@ feature {NONE} -- Initialization
make make
do do
Precursor
version := "1.0" version := "1.0"
description := "Service to manage basic authentication" description := "Service to manage basic authentication"
package := "authentication"
add_dependency ({CMS_AUTHENTICATION_MODULE})
end end
feature -- Access feature -- Access
name: STRING = "basic_auth" name: STRING = "basic_auth"
feature -- Access: router feature -- Access: auth strategy
setup_router (a_router: WSF_ROUTER; a_api: CMS_API) login_title: STRING = "Basic Auth"
-- Module specific login title.
login_location: STRING = "account/auth/roc-basic-login"
do_login_location: STRING = "roc-basic-login" -- IMPORTANT: it has to be at the root !
logout_location: STRING = "roc-basic-logoff" -- IMPORTANT: it has to be at the root !
is_authenticating (a_response: CMS_RESPONSE): BOOLEAN
-- <Precursor> -- <Precursor>
do do
configure_api_login (a_api, a_router) if
configure_api_logoff (a_api, a_router) a_response.is_authenticated and then
a_router.handle ("/account/roc-basic-auth", create {WSF_URI_AGENT_HANDLER}.make (agent handle_login_basic_auth (a_api, ?, ?)), a_router.methods_head_get) a_response.request.http_authorization /= Void
then
Result := True
end
end end
feature {CMS_API} -- Access: API
oauth20_api: detachable CMS_AUTH_API_I
-- <Precursor>
feature -- Access: filter feature -- Access: filter
filters (a_api: CMS_API): detachable LIST [WSF_FILTER] filters (a_api: CMS_API): detachable LIST [WSF_FILTER]
@@ -65,6 +74,16 @@ feature -- Access: filter
Result.extend (create {CMS_BASIC_AUTH_FILTER}.make (a_api)) Result.extend (create {CMS_BASIC_AUTH_FILTER}.make (a_api))
end end
feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
configure_api_login (a_api, a_router)
configure_api_logoff (a_api, a_router)
a_router.handle ("/" + login_location, create {WSF_URI_AGENT_HANDLER}.make (agent handle_login_basic_auth (a_api, ?, ?)), a_router.methods_head_get)
end
feature {NONE} -- Implementation: routes feature {NONE} -- Implementation: routes
configure_api_login (api: CMS_API; a_router: WSF_ROUTER) configure_api_login (api: CMS_API; a_router: WSF_ROUTER)
@@ -75,7 +94,7 @@ feature {NONE} -- Implementation: routes
create l_bal_handler.make (api) create l_bal_handler.make (api)
create l_methods create l_methods
l_methods.enable_get l_methods.enable_get
a_router.handle ("/basic_auth_login", l_bal_handler, l_methods) a_router.handle ("/" + do_login_location, l_bal_handler, l_methods)
end end
configure_api_logoff (api: CMS_API; a_router: WSF_ROUTER) configure_api_logoff (api: CMS_API; a_router: WSF_ROUTER)
@@ -86,16 +105,38 @@ feature {NONE} -- Implementation: routes
create l_bal_handler.make (api) create l_bal_handler.make (api)
create l_methods create l_methods
l_methods.enable_get l_methods.enable_get
a_router.handle ("/basic_auth_logoff", l_bal_handler, l_methods) a_router.handle ("/" + logout_location, l_bal_handler, l_methods)
end end
handle_login_basic_auth (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_login_basic_auth (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
r: CMS_RESPONSE r: CMS_RESPONSE
vals: CMS_VALUE_TABLE
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.set_value ("Basic Auth", "optional_content_type") if api.user_is_authenticated then
r.add_error_message ("You are already signed in!")
r.set_main_content (r.link ("Logout", "account/roc-logout", Void))
else
if attached template_block ("login", r) as l_tpl_block then
r.add_javascript_url (r.url ("module/" + name + "/files/js/roc_basic_auth.js", Void))
create vals.make (1)
-- add the variable to the block
api.hooks.invoke_value_table_alter (vals, r)
across
vals as ic
loop
l_tpl_block.set_value (ic.item, ic.key)
end
r.add_block (l_tpl_block, "content")
else
debug ("cms")
r.add_warning_message ("Error with block [login]")
end
end
r.set_value ("Basic Auth", "optional_content_type")
end
r.execute r.execute
end end
@@ -104,103 +145,25 @@ feature -- Hooks configuration
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER) setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
-- Module hooks configuration. -- Module hooks configuration.
do do
auto_subscribe_to_hooks (a_hooks) Precursor (a_hooks)
a_hooks.subscribe_to_block_hook (Current) a_hooks.subscribe_to_block_hook (Current)
a_hooks.subscribe_to_value_table_alter_hook (Current)
end end
feature -- Hooks feature -- Hooks
value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE)
-- <Precursor>
do
if a_response.is_authenticated then
a_value.force ("basic_auth_logoff", "auth_login_strategy")
end
end
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'.
local
lnk: CMS_LOCAL_LINK
lnk2: detachable CMS_LINK
do
if attached a_response.user as u then
across
a_menu_system.primary_menu.items as ic
until
lnk2 /= Void
loop
if ic.item.location.same_string ("account/roc-logout") then
lnk2 := ic.item
end
end
if lnk2 /= Void then
a_menu_system.primary_menu.remove (lnk2)
end
create lnk.make ("Logout", "basic_auth_logoff")
lnk.set_weight (98)
a_menu_system.primary_menu.extend (lnk)
else
if a_response.location.starts_with ("account/") then
create lnk.make ("Basic Auth", "account/roc-basic-auth")
lnk.set_expandable (True)
a_response.add_to_primary_tabs (lnk)
end
end
end
block_list: ITERABLE [like {CMS_BLOCK}.name] block_list: ITERABLE [like {CMS_BLOCK}.name]
local
l_string: STRING
do do
Result := <<"login">> Result := <<"?login">>
debug ("roc")
create l_string.make_empty
across
Result as ic
loop
l_string.append (ic.item)
l_string.append_character (' ')
end
write_debug_log (generator + ".block_list:" + l_string )
end
end end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE) get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
do do
if if a_block_id.is_case_insensitive_equal_general ("login") then
a_block_id.is_case_insensitive_equal_general ("login") and then
a_response.location.starts_with ("account/roc-basic-auth")
then
a_response.add_javascript_url (a_response.url ("module/" + name + "/files/js/roc_basic_auth.js", Void)) a_response.add_javascript_url (a_response.url ("module/" + name + "/files/js/roc_basic_auth.js", Void))
get_block_view_login (a_block_id, a_response) get_block_view_login (a_block_id, a_response)
end end
end end
feature {NONE} -- Helpers
template_block (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE): detachable CMS_SMARTY_TEMPLATE_BLOCK
-- Smarty content block for `a_block_id'
local
p: detachable PATH
do
create p.make_from_string ("templates")
p := p.extended ("block_").appended (a_block_id).appended_with_extension ("tpl")
p := a_response.api.module_theme_resource_location (Current, p)
if p /= Void then
if attached p.entry as e then
create Result.make (a_block_id, Void, p.parent, e)
else
create Result.make (a_block_id, Void, p.parent, p)
end
end
end
feature {NONE} -- Block views feature {NONE} -- Block views
get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE) get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
@@ -210,7 +173,7 @@ feature {NONE} -- Block views
if attached template_block (a_block_id, a_response) as l_tpl_block then if attached template_block (a_block_id, a_response) as l_tpl_block then
create vals.make (1) create vals.make (1)
-- add the variable to the block -- add the variable to the block
value_table_alter (vals, a_response) a_response.api.hooks.invoke_value_table_alter (vals, a_response)
across across
vals as ic vals as ic
loop loop

View File

@@ -9,54 +9,46 @@ class
CMS_BASIC_AUTH_FILTER CMS_BASIC_AUTH_FILTER
inherit inherit
WSF_URI_TEMPLATE_HANDLER CMS_AUTH_FILTER_I
CMS_HANDLER
WSF_FILTER REFACTORING_HELPER
create create
make make
feature -- Basic operations feature -- Basic operations
auth_strategy: STRING
do
Result := {CMS_BASIC_AUTH_MODULE}.logout_location
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE) execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter. -- Execute the filter.
local local
l_auth: HTTP_AUTHORIZATION l_auth: HTTP_AUTHORIZATION
do do
api.logger.put_debug (generator + ".execute ", Void)
create l_auth.make (req.http_authorization) create l_auth.make (req.http_authorization)
debug
if attached req.raw_header_data as l_raw_data then
api.logger.put_debug (generator + ".execute " + (create {UTF_CONVERTER}).escaped_utf_32_string_to_utf_8_string_8 (l_raw_data), Void)
end
end
-- A valid user
if if
(attached l_auth.type as l_auth_type and then l_auth_type.is_case_insensitive_equal_general ("basic")) and then l_auth.is_basic and then
attached l_auth.login as l_auth_login and then attached l_auth.password as l_auth_password attached l_auth.login as l_auth_login and then
attached l_auth.password as l_auth_password
then then
if api.user_api.is_valid_credential (l_auth_login, l_auth_password) then if
if attached api.user_api.user_by_name (l_auth_login) as l_user then api.user_api.is_valid_credential (l_auth_login, l_auth_password) and then
debug ("refactor_fixme") attached api.user_api.user_by_name (l_auth_login) as l_user
fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT") then
-- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user)) debug ("refactor_fixme")
-- other authentication filters (OpenID, etc) should implement the same approach. fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT")
end -- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user))
set_current_user (req, l_user) -- other authentication filters (OpenID, etc) should implement the same approach.
execute_next (req, res)
else
debug ("refactor_fixme")
to_implement ("Internal server error")
end
end end
set_current_user (l_user)
else else
api.logger.put_error (generator + ".execute login_valid failed for: " + l_auth_login, Void) api.logger.put_error (generator + ".execute login_valid failed for: " + l_auth_login, Void)
execute_next (req, res)
end end
else
api.logger.put_debug (generator + ".execute without authentication", Void)
execute_next (req, res)
end end
execute_next (req, res)
end end
end end

View File

@@ -49,9 +49,9 @@ feature -- HTTP Methods
-- <Precursor> -- <Precursor>
do do
api.logger.put_information (generator + ".do_get Processing basic auth login", Void) api.logger.put_information (generator + ".do_get Processing basic auth login", Void)
if attached {STRING_32} current_user_name (req) as l_user then if api.user_is_authenticated then
if attached {WSF_STRING} req.query_parameter ("destination") as l_uri then if attached {WSF_STRING} req.query_parameter ("destination") as l_uri then
redirect_to (req.absolute_script_url (l_uri.url_encoded_value), res) redirect_to (req.absolute_script_url (l_uri.url_encoded_value), res)
else else
redirect_to (req.absolute_script_url ("/"), res) redirect_to (req.absolute_script_url ("/"), res)
end end

View File

@@ -51,11 +51,11 @@ feature -- HTTP Methods
do do
api.logger.put_information (generator + ".do_get Processing basic auth logoff", Void) api.logger.put_information (generator + ".do_get Processing basic auth logoff", Void)
if attached req.query_parameter ("prompt") as l_prompt then if attached req.query_parameter ("prompt") as l_prompt then
unset_current_user (req) api.unset_current_user (req)
send_access_denied_message (res) send_access_denied_message (res)
else else
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
unset_current_user (req) api.unset_current_user (req)
l_page.set_status_code ({HTTP_STATUS_CODE}.unauthorized) -- Note: can not use {HTTP_STATUS_CODE}.unauthorized for redirection l_page.set_status_code ({HTTP_STATUS_CODE}.unauthorized) -- Note: can not use {HTTP_STATUS_CODE}.unauthorized for redirection
l_url := req.absolute_script_url ("") l_url := req.absolute_script_url ("")
i := l_url.substring_index ("://", 1) i := l_url.substring_index ("://", 1)

View File

@@ -1,307 +1,291 @@
var ROC_AUTH = ROC_AUTH || { }; var ROC_AUTH = ROC_AUTH || { };
var loginURL = "/basic_auth_login"; var loginURL = "/roc-basic-login";
var logoutURL = "/basic_auth_logoff"; var logoutURL = "/roc-basic-logoff";
var userAgent = navigator.userAgent.toLowerCase(); var userAgent = navigator.userAgent.toLowerCase();
var firstLogIn = true; var firstLogIn = true;
ROC_AUTH.login = function() { ROC_AUTH.login = function() {
var form = document.forms['cms_basic_auth']; var form = document.forms['cms_basic_auth'];
var username = form.username.value; var username = form.username.value;
var password = form.password.value; var password = form.password.value;
//var host = form.host.value; //var host = form.host.value;
var origin = window.location.origin + window.location.pathname; var origin = window.location.origin + window.location.pathname;
var _login = function(){ var _login = function(){
if (document.getElementById('myModalFormId') !== null ) {
ROC_AUTH.remove ('myModalFormId');
}
if (username === "" || password === "") {
if (document.getElementById('myModalFormId') !== null ) { if (document.getElementById('myModalFormId') === null ) {
ROC_AUTH.remove ('myModalFormId'); var newdiv = document.createElement('div');
} newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
}
}else{
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
delete form;
window.location=window.location.origin;
} else {
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
// .. ?
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
}
}
}
}
}
}
if (username === "" || password === "") { var userAgent = navigator.userAgent.toLowerCase();
if (document.getElementById('myModalFormId') === null ) { if (userAgent.indexOf("firefox") != -1) { //TODO: check version number
var newdiv = document.createElement('div'); if (firstLogIn) {
newdiv.innerHTML = "<br>Invalid Credentials</br>"; _login();
newdiv.id = 'myModalFormId'; } else {
$(".primary-tabs").append(newdiv); ROC_AUTH.logoff(_login);
} }
}else{ } else {
_login();
//Instantiate HTTP Request }
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
delete form;
window.location=window.location.origin;
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".primary-tabs").append(newdiv);
}
} if (firstLogIn) {
} firstLogIn = false;
} }
}
}
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (firstLogIn) _login();
else logoff(_login);
}
else{
_login();
}
if (firstLogIn) firstLogIn = false;
}; };
ROC_AUTH.login_with_redirect = function() { ROC_AUTH.login_with_redirect = function() {
var form = document.forms[2]; var form = document.forms[2];
var username = form.username.value; var username = form.username.value;
var password = form.password.value; var password = form.password.value;
var host = form.host.value; var host = form.host.value;
var _login = function(){ var _login = function(){
var redirectURL = form.redirect && form.redirect.value || "";
$("#imgProgressRedirect").show();
var redirectURL = form.redirect && form.redirect.value || ""; if (document.getElementById('myModalFormId') !== null ) {
ROC_AUTH.remove ('myModalFormId');
}
if (username === "" || password === "") {
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
$("#imgProgressRedirect").hide();
}
} else {
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", host + loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status==200) {
if (redirectURL === "") {
window.location=host + "/";
} else {
window.location=host + redirectURL;
}
} else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".login-box").append(newdiv);
$("#imgProgressRedirect").hide();
}
}
}
}
}
}
$("#imgProgressRedirect").show(); var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (document.getElementById('myModalFormId') !== null ) { if (firstLogIn) {
ROC_AUTH.remove ('myModalFormId'); _login();
} } else {
ROC_AUTH.logoff(_login);
}
if (username === "" || password === "") { } else{
if (document.getElementById('myModalFormId') === null ) { _login();
var newdiv = document.createElement('div'); }
newdiv.innerHTML = "<br>Invalid Credentials</br>"; if (firstLogIn) {
newdiv.id = 'myModalFormId'; firstLogIn = false;
$(".primary-tabs").append(newdiv); }
$("#imgProgressRedirect").hide();
}
}else{
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", host.concat(loginURL), true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
if (redirectURL === "") {
window.location=host.concat("/");
} else {
window.location=host.concat(redirectURL);
}
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$(".primary-tabs").append(newdiv);
$("#imgProgressRedirect").hide();
}
}
}
}
}
}
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (firstLogIn) _login();
else logoff(_login);
}
else{
_login();
}
if (firstLogIn) firstLogIn = false;
}; };
ROC_AUTH.getQueryParameterByName = function (name) { ROC_AUTH.getQueryParameterByName = function (name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search);
results = regex.exec(location.search); return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
} }
ROC_AUTH.logoff = function(callback){ ROC_AUTH.logoff = function(callback){
var form = document.forms[0]; var form = document.forms[0];
var host = form.host.value; var host = form.host.value;
if (userAgent.indexOf("msie") != -1) { if (userAgent.indexOf("msie") != -1) {
document.execCommand("ClearAuthenticationCache"); document.execCommand("ClearAuthenticationCache");
} } else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number var request1 = new XMLHttpRequest();
var request2 = new XMLHttpRequest();
var request1 = new XMLHttpRequest();
var request2 = new XMLHttpRequest(); //Logout. Tell the server not to return the "WWW-Authenticate" header
request1.open("GET", host + logoutURL + "?prompt=false", true);
//Logout. Tell the server not to return the "WWW-Authenticate" header request1.send("");
request1.open("GET", host.concat(logoutURL) + "?prompt=false", true); request1.onreadystatechange = function(){
request1.send(""); if (request1.readyState == 4) {
request1.onreadystatechange = function(){ //Sign in with dummy credentials to clear the auth cache
if (request1.readyState == 4) { request2.open("GET", host + logoutURL, true, "logout", "logout");
request2.send("");
//Sign in with dummy credentials to clear the auth cache request2.onreadystatechange = function(){
request2.open("GET", host.concat(logoutURL), true, "logout", "logout"); if (request2.readyState == 4) {
request2.send(""); if (callback!=null) {
callback.call();
request2.onreadystatechange = function(){ } else {
if (request2.readyState == 4) { window.location=host + logoutURL;
if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);} }
} }
} }
}
} }
} } else {
} var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
else { request.open("GET", host + logoutURL, true, "logout", "logout");
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); request.send("");
request.open("GET", host.concat(logoutURL), true, "logout", "logout"); request.onreadystatechange = function(){
request.send(""); if (request.status==401 || request.status==403 ) {
request.onreadystatechange = function(){ window.location=host + logoutURL;
if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL); }
} }
} }
}
}; };
ROC_AUTH.remove = function (id) ROC_AUTH.remove = function (id) {
{ var element = document.getElementById(id);
var element = document.getElementById(id); element.outerHTML = "";
element.outerHTML = ""; delete element;
delete element; return;
return;
}; };
$(document).ready(function() { $(document).ready(function() {
if (typeof String.prototype.contains != 'function') {
if (typeof String.prototype.contains != 'function') { String.prototype.contains = function (str){
String.prototype.contains = function (str){ return this.indexOf(str) != -1;
return this.indexOf(str) != -1; };
}; }
} ROC_AUTH.progressive_loging();
ROC_AUTH.progressive_loging();
}); });
ROC_AUTH.progressive_loging = function () { ROC_AUTH.progressive_loging = function () {
ROC_AUTH.login_href();
ROC_AUTH.login_href();
}; };
$(document).keypress(function(e) { $(document).keypress(function(e) {
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) { if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
ROC_AUTH.login(); ROC_AUTH.login();
} }
}); });
ROC_AUTH.OnOneClick = function(event) { ROC_AUTH.OnOneClick = function(event) {
event.preventDefault(); event.preventDefault();
if ( document.forms[0] === undefined ) { if ( document.forms[0] === undefined ) {
ROC_AUTH.create_form(); ROC_AUTH.create_form();
} }
return false; return false;
}; };
ROC_AUTH.login_href = function() { ROC_AUTH.login_href = function() {
var els = document.getElementsByTagName("a"); var els = document.getElementsByTagName("a");
for (var i = 0, l = els.length; i < l; i++) { for (var i = 0, l = els.length; i < l; i++) {
var el = els[i]; var el = els[i];
if (el.href.contains("/basic_auth_login?destination")) { if (el.href.contains(loginURL + "?destination")) {
loginURL = el.href; // loginURL = el.href;
var OneClick = el; var OneClick = el;
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false); OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
} }
} }
}; };
ROC_AUTH.create_form = function() { ROC_AUTH.create_form = function() {
// Fetching HTML Elements in Variables by ID. // Fetching HTML Elements in Variables by ID.
var createform = document.createElement('form'); // Create New Element Form var createform = document.createElement('form'); // Create New Element Form
createform.setAttribute("action", ""); // Setting Action Attribute on Form createform.setAttribute("action", ""); // Setting Action Attribute on Form
createform.setAttribute("method", "post"); // Setting Method Attribute on Form createform.setAttribute("method", "post"); // Setting Method Attribute on Form
$("body").append(createform); $("body").append(createform);
var heading = document.createElement('h2'); // Heading of Form var heading = document.createElement('h2'); // Heading of Form
heading.innerHTML = "Login Form "; heading.innerHTML = "Login Form ";
createform.appendChild(heading); createform.appendChild(heading);
var line = document.createElement('hr'); // Giving Horizontal Row After Heading var line = document.createElement('hr'); // Giving Horizontal Row After Heading
createform.appendChild(line); createform.appendChild(line);
var linebreak = document.createElement('br'); var linebreak = document.createElement('br');
createform.appendChild(linebreak); createform.appendChild(linebreak);
var namelabel = document.createElement('label'); // Create Label for Name Field var namelabel = document.createElement('label'); // Create Label for Name Field
namelabel.innerHTML = "Username : "; // Set Field Labels namelabel.innerHTML = "Username : "; // Set Field Labels
createform.appendChild(namelabel); createform.appendChild(namelabel);
var inputelement = document.createElement('input'); // Create Input Field for UserName var inputelement = document.createElement('input'); // Create Input Field for UserName
inputelement.setAttribute("type", "text"); inputelement.setAttribute("type", "text");
inputelement.setAttribute("name", "username"); inputelement.setAttribute("name", "username");
inputelement.setAttribute("required","required"); inputelement.setAttribute("required","required");
createform.appendChild(inputelement); createform.appendChild(inputelement);
var linebreak = document.createElement('br'); var linebreak = document.createElement('br');
createform.appendChild(linebreak); createform.appendChild(linebreak);
var passwordlabel = document.createElement('label'); // Create Label for Password Field var passwordlabel = document.createElement('label'); // Create Label for Password Field
passwordlabel.innerHTML = "Password : "; passwordlabel.innerHTML = "Password : ";
createform.appendChild(passwordlabel); createform.appendChild(passwordlabel);
var passwordelement = document.createElement('input'); // Create Input Field for Password. var passwordelement = document.createElement('input'); // Create Input Field for Password.
passwordelement.setAttribute("type", "password"); passwordelement.setAttribute("type", "password");
passwordelement.setAttribute("name", "password"); passwordelement.setAttribute("name", "password");
passwordelement.setAttribute("id", "password"); passwordelement.setAttribute("id", "password");
passwordelement.setAttribute("required","required"); passwordelement.setAttribute("required","required");
createform.appendChild(passwordelement); createform.appendChild(passwordelement);
var passwordbreak = document.createElement('br'); var passwordbreak = document.createElement('br');
createform.appendChild(passwordbreak); createform.appendChild(passwordbreak);
var submitelement = document.createElement('button'); // Append Submit Button var submitelement = document.createElement('button'); // Append Submit Button
submitelement.setAttribute("type", "button"); submitelement.setAttribute("type", "button");
submitelement.setAttribute("onclick", "ROC_AUTH.login();"); submitelement.setAttribute("onclick", "ROC_AUTH.login();");
submitelement.innerHTML = "Sign In "; submitelement.innerHTML = "Sign In ";
createform.appendChild(submitelement); createform.appendChild(submitelement);
}; };
@@ -310,16 +294,16 @@ var password = document.getElementById("password");
var confirm_password = document.getElementById("confirm_password"); var confirm_password = document.getElementById("confirm_password");
ROC_AUTH.validatePassword =function(){ ROC_AUTH.validatePassword =function(){
if ((password != null) && (confirm_password != null)) { if ((password != null) && (confirm_password != null)) {
if(password.value != confirm_password.value) { if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match"); confirm_password.setCustomValidity("Passwords Don't Match");
} else { } else {
confirm_password.setCustomValidity(''); confirm_password.setCustomValidity('');
} }
} }
} }
if ((password != null) && (confirm_password != null)) { if ((password != null) && (confirm_password != null)) {
password.onchange = ROC_AUTH.validatePassword(); password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword; confirm_password.onkeyup = ROC_AUTH.validatePassword;
} }

View File

@@ -1,29 +1,23 @@
<div class="primary-tabs"> {unless isset="$user"}
{unless isset="$user"} <div class="login-box">
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3> <div class="description">The "Basic Auth" relies on the HTTP basic acces authentication.<br/>(see also: <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">https://en.wikipedia.org/wiki/Basic_access_authentication</a> )</div>
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div> <div>
<div> <form name="cms_basic_auth" action="{$site_url/}roc-basic-login" method="POST">
<form name="cms_basic_auth" action method="POST"> <input type="hidden" name="host" id="host" value="{$site_url/}">
<div> <div>
<input type="text" name="username" id="username" required> <input type="text" name="username" id="username" required>
<label>Username</label> <label>Username</label>
</div> </div>
<div>
<div> <input type="password" name="password" id="password" required>
<input type="password" name="password" id="password" required> <label>Password</label>
<label>Password</label> </div>
</div> <button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
<button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
</div>
</div> </div>
<div> <div>
<div> <a href="{$site_url/}account/new-password">Forgot password?</a>
<p>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div> </div>
{/unless}
</div> </div>
{/unless}

View File

@@ -78,27 +78,17 @@ feature {CMS_API} -- Module Initialization
feature {CMS_API} -- Module management feature {CMS_API} -- Module management
install (api: CMS_API) install (a_api: CMS_API)
local
sql: STRING
do do
-- Schema -- Schema
if attached api.storage.as_sql_storage as l_sql_storage then if attached a_api.storage.as_sql_storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("blog_post_nodes") then l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("install.sql")), Void)
sql := "[
CREATE TABLE blog_post_nodes( if l_sql_storage.has_error then
`nid` INTEGER NOT NULL CHECK("nid">=0), a_api.logger.put_error ("Could not initialize database for module [" + name + "]", generating_type)
`revision` INTEGER NOT NULL, else
`tags` VARCHAR(255), Precursor {CMS_MODULE} (a_api)
CONSTRAINT PK_nid_revision PRIMARY KEY (nid,revision)
);
]"
l_sql_storage.sql_execute_script (sql, Void)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for blog module", generating_type)
end
end end
Precursor (api)
end end
end end

View File

@@ -206,7 +206,7 @@ feature -- HTML Output
do do
if attached n.author as l_author then if attached n.author as l_author then
a_output.append ("by ") a_output.append ("by ")
a_output.append ("<a class=%"blog_user_link%" href=%"/blogs/user/" + l_author.id.out + "%">" + l_author.name + "</a>") a_output.append ("<a class=%"blog_user_link%" href=%"/blogs/user/" + l_author.id.out + "%">" + html_encoded (l_author.name) + "</a>")
end end
end end

View File

@@ -0,0 +1,6 @@
CREATE TABLE blog_post_nodes(
`nid` INTEGER NOT NULL CHECK("nid">=0),
`revision` INTEGER NOT NULL,
`tags` VARCHAR(255),
CONSTRAINT PK_nid_revision PRIMARY KEY (nid,revision)
);

View File

@@ -0,0 +1,21 @@
<?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="contact" uuid="5F9BB4AA-FB62-4550-B314-DED374843DC0" library_target="contact">
<target name="contact">
<root all_classes="true"/>
<option is_obsolete_routine_type="true">
</option>
<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_config" location="..\..\library\configuration\config-safe.ecf"/>
<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="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
<library name="recaptcha" location="..\..\library\recaptcha\recaptcha-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,8 @@
{
"--email": "webmaster@example.com",
"subjet": "Thank you for contacting us",
"recaptcha": {
"site_key":"",
"secret_key":""
}
}

View File

@@ -0,0 +1,124 @@
.contact-box {
background-color: #F2F7F9;
width: 465px;
padding: 20px;
border: 6px solid #8FB5C1;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
border-radius: 15px;
position: relative;
/* Remove box shadow firefox, chrome and opera put around required fields.
* It looks rubbish.
*/
/* Normalize placeholder styles */
/* chrome, safari */
/* mozilla */
/* ie (faux placeholder) */
}
.contact-box h1 {
font-size: 42px;
}
.contact-box h2 {
margin-bottom: 15px;
font-style: italic;
font-weight: normal;
}
.contact-box label {
font-size: 15px;
margin-bottom: 2px;
display: block;
}
.contact-box input, .contact-box select, .contact-box textarea {
width: 100%;
font-size: 15px;
border: 1px solid #CEE1E8;
margin-bottom: 20px;
padding: 4px;
}
.contact-box input:focus, .contact-box select:focus, .contact-box textarea:focus {
border: 1px solid #AFCDD8;
background-color: #EBF2F4;
}
.contact-box textarea {
height: 150px;
resize: none;
}
.contact-box span.required {
font-weight: bold;
color: #F00;
}
.contact-box input[type=submit] {
width: 100px;
background-color: #333;
color: #FFF;
border: none;
display: block;
float: right;
margin-bottom: 0px;
margin-right: 6px;
background-color: #8FB5C1;
-moz-border-radius: 8px;
}
.contact-box input[type=submit]:hover {
background-color: #A6CFDD;
}
.contact-box input[type=submit]:active {
position: relative;
top: 1px;
}
.contact-box .message {
width: 95%;
margin: 25px 0px;
padding: 10px;
display: block;
border: solid 1px #ccc;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
}
.contact-box .message.hidden {
display: none;
}
.contact-box .message.error {
border-color: #E58E8E;
background-color: #FFE6E6;
}
.contact-box .message.error li {
padding: 2px;
list-style: none;
}
.contact-box .message.error li:before {
content: ' - ';
}
.contact-box .message.error #info {
font-weight: bold;
}
.contact-box .message.error #info:before {
content: '';
}
.contact-box .message.success {
border-color: #83D186;
padding-top: 25px;
background-color: #D3EDD3;
}
.contact-box .req-field-desc {
font-style: italic;
}
.contact-box input:required, .contact-box textarea:required {
-moz-box-shadow: none;
-webkit-box-shadow: none;
-o-box-shadow: none;
box-shadow: none;
}
.contact-box ::-webkit-input-placeholder {
color: #CCC;
font-style: italic;
}
.contact-box input:-moz-placeholder, .contact-box textarea:-moz-placeholder {
color: #CCC;
font-style: italic;
}
.contact-box input.placeholder-text, .contact-box textarea.placeholder-text {
color: #CCC;
font-style: italic;
}

View File

@@ -0,0 +1,140 @@
.contact-box {
background-color:#F2F7F9;
width:465px;
padding:20px;
border: 6px solid #8FB5C1;
-moz-border-radius:15px;
-webkit-border-radius:15px;
border-radius:15px;
position:relative;
h1 {
font-size:42px;
}
h2 {
margin-bottom:15px;
font-style:italic;
font-weight:normal;
}
label {
font-size:15px;
margin-bottom:2px;
display:block;
}
input, select, textarea {
width:100%;
font-size:15px;
border: 1px solid #CEE1E8;
margin-bottom:20px;
padding:4px;
&:focus {
border: 1px solid #AFCDD8;
background-color: #EBF2F4;
}
}
textarea {
height:150px;
resize: none;
}
span.required {
font-weight:bold;
color:#F00;
}
input[type=submit] {
width: 100px;
background-color:#333;
color:#FFF;
border:none;
display:block;
float:right;
margin-bottom:0px;
margin-right:6px;
background-color:#8FB5C1;
-moz-border-radius:8px;
&:hover {
background-color: #A6CFDD;
}
&:active {
position:relative;
top:1px;
}
}
.message {
width:95%;
margin:25px 0px;
padding:10px;
display:block;
border:solid 1px #ccc;
border-radius:8px;
-webkit-border-radius:8px;
-moz-border-radius:8px;
&.hidden {
display: none;
}
&.error {
border-color: #E58E8E;
background-color:#FFE6E6;
li {
padding:2px;
list-style:none;
&:before { content: ' - '; }
}
#info {
font-weight:bold;
&:before { content: ''; }
}
}
&.success {
border-color: #83D186;
padding-top: 25px;
background-color:#D3EDD3;
}
}
.req-field-desc {
font-style:italic;
}
/* Remove box shadow firefox, chrome and opera put around required fields.
* It looks rubbish.
*/
input:required, textarea:required {
-moz-box-shadow:none;
-webkit-box-shadow:none;
-o-box-shadow:none;
box-shadow:none;
}
/* Normalize placeholder styles */
/* chrome, safari */
::-webkit-input-placeholder {
color:#CCC;
font-style:italic;
}
/* mozilla */
input:-moz-placeholder, textarea:-moz-placeholder {
color:#CCC;
font-style:italic;
}
/* ie (faux placeholder) */
input.placeholder-text, textarea.placeholder-text {
color:#CCC;
font-style:italic;
}
}

View File

@@ -0,0 +1,25 @@
<div class="contact-box clearfix">
<h1>Contact us!</h1>
<form method="post" action="{$site_url/}contact" id="contact-form">
<label for="name">Name: <span class="required">*</span></label>
<input type="text" id="name" name="name" value="{$name/}" required="required" autofocus="autofocus" />
<label for="email">Email Address: <span class="required">*</span></label>
<input type="email" id="email" name="email" value="{$email/}" required="required" />
<label for="message">Message: <span class="required">*</span></label>
<textarea id="message" name="message" required="required" data-minlength="20" minlength="20" >{$message/}</textarea>
{unless isempty="$recaptcha_site_key"}
<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div>
<br/>
{/unless}
<input type="submit" value="Send" class="submit-button" />
<p class="req-field-desc"><span class="required">*</span> indicates a required field</p>
</form>
{unless isempty="$error_response"}
<ul class="message error">
{foreach item="item" from="$error_response"}<li class="info">{$item/}</li>{/foreach}
</ul>
<div class="notice"> Try again later </div>
{/unless}
</div>

View File

@@ -0,0 +1,15 @@
<div class="contact-box">
{if condition="$has_error"}
<div class="message error">
<strong>Internal Server Error <small>Error 500</small></strong>
<p>The page you requested could not be served because the server is down,
either contact the webmaster or try again.
Use your browser's <strong>Back</strong> button to navigate to the page you came from.</p>
<p><strong>Or you could just press this link:</strong> <a href="{$site_url/}" itemprop="home" rel="home">Take Me Home</a></p>
</div>
{/if}
{unless condition="$has_error"}
<p class="message success">Thank you for contacting the Eiffel Programming Language community.<br/>
We will get back to you promptly on your contact request.</p>
{/unless}
</div>

View File

@@ -0,0 +1,10 @@
<p>
Thank you for contacting {$sitename/}.<br/>
We will get back to you promptly about your contact message.
</p>
<h2>Your contact information:</h2>
<div>
<strong>Name<strong>: {$name/} <br/>
<strong>Email<strong>: {$email/} <br/>
<strong>Message<strong>: {$message/} <br/>
</div>

View File

@@ -0,0 +1,6 @@
<h2>Contact information:</h2>
<div>
<strong>Name<strong>: {$name/}<br/>
<strong>Email<strong>: {$email/} <br/>
<strong>Message<strong>: {$message/} <br/>
</div>

View File

@@ -0,0 +1,533 @@
note
description: "[
Module that provide contact us web form functionality.
]"
author: "$Author: jfiat $"
date: "$Date: 2016-01-08 22:43:12 +0100 (ven., 08 janv. 2016) $"
revision: "$Revision: 98369 $"
class
CMS_CONTACT_MODULE
inherit
CMS_MODULE
rename
module_api as contact_api
redefine
setup_hooks,
install,
initialize,
contact_api
end
CMS_HOOK_BLOCK
CMS_HOOK_BLOCK_HELPER
CMS_HOOK_AUTO_REGISTER
CMS_HOOK_MENU_SYSTEM_ALTER
SHARED_EXECUTION_ENVIRONMENT
export
{NONE} all
end
REFACTORING_HELPER
SHARED_LOGGER
create
make
feature {NONE} -- Initialization
make
-- Create current module
do
version := "1.0"
description := "Contact form module"
package := "messaging"
end
feature -- Access
name: STRING = "contact"
-- <Precursor>
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
-- <Precursor>
local
l_contact_api: like contact_api
ut: FILE_UTILITIES
p: PATH
contact_storage: CONTACT_STORAGE_I
do
Precursor (api)
-- if attached api.storage.as_sql_storage as l_storage_sql then
-- create {CONTACT_STORAGE_SQL} contact_storage.make (l_storage_sql)
-- else
p := file_system_storage_path (api)
if ut.directory_path_exists (p) then
create {CONTACT_STORAGE_FS} contact_storage.make (p, api)
else
create {CONTACT_STORAGE_NULL} contact_storage.make
end
create l_contact_api.make (api, contact_storage)
contact_api := l_contact_api
end
feature {CMS_API} -- Module management
install (api: CMS_API)
local
retried: BOOLEAN
d: DIRECTORY
do
if not retried then
create d.make_with_path (file_system_storage_path (api))
d.recursive_create_dir
Precursor {CMS_MODULE}(api) -- Marked installed
end
rescue
retried := True
retry
end
file_system_storage_path (api: CMS_API): PATH
-- Location of eventual file system based storage for contact messages.
do
Result := api.site_location.extended ("db").extended (name).extended ("messages")
end
feature {CMS_API} -- Access: API
contact_api: detachable CONTACT_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 ("/contact", create {WSF_URI_AGENT_HANDLER}.make (agent handle_contact (a_api, ?, ?)))
a_router.map (m, a_router.methods_head_get)
a_router.handle ("/contact", create {WSF_URI_AGENT_HANDLER}.make (agent handle_post_contact (a_api, ?, ?)), a_router.methods_put_post)
end
feature -- Recaptcha
recaptcha_secret_key (api: CMS_API): detachable READABLE_STRING_8
-- Get recaptcha security key.
local
utf: UTF_CONVERTER
do
if attached api.module_configuration (Current, Void) as cfg then
if
attached cfg.text_item ("recaptcha.secret_key") as l_recaptcha_key and then
not l_recaptcha_key.is_empty
then
Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key)
end
end
end
recaptcha_site_key (api: CMS_API): detachable READABLE_STRING_8
-- Get recaptcha security key.
local
utf: UTF_CONVERTER
do
if attached api.module_configuration (Current, Void) as cfg then
if
attached cfg.text_item ("recaptcha.site_key") as l_recaptcha_key and then
not l_recaptcha_key.is_empty
then
Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key)
end
end
end
feature -- Hooks configuration
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
-- Module hooks configuration.
do
auto_subscribe_to_hooks (a_hooks)
a_hooks.subscribe_to_block_hook (Current)
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 contact to menu")
end
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
do
Result := <<"?contact">>
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
do
if a_block_id.is_case_insensitive_equal_general ("contact") then
-- "contact", "post_contact"
if a_response.request.is_get_request_method then
if attached template_block (Current, a_block_id, a_response) as l_tpl_block then
if attached recaptcha_site_key (a_response.api) as l_recaptcha_site_key then
l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key")
end
a_response.add_block (l_tpl_block, "content")
a_response.add_style (a_response.url ("/module/" + name + "/files/css/contact.css", Void), Void)
else
debug ("cms")
a_response.add_warning_message ("Error with block [" + a_block_id + "]")
end
end
end
end
end
new_html_contact_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/contact.css", Void), Void)
if attached template_block (Current, "contact", a_response) as l_tpl_block then
if attached recaptcha_site_key (api) as l_recaptcha_site_key then
l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key")
end
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_contact_form (a_response, api)
api.hooks.invoke_form_alter (f, f.last_data, a_response)
Result := "<div class=%"contact-box%"><h1>Contact us!</h1>" + f.to_html (a_response.wsf_theme) + "<br/></div>"
end
end
new_contact_form (a_response: CMS_RESPONSE; api: CMS_API): CMS_FORM
local
f: CMS_FORM
f_name: WSF_FORM_TEXT_INPUT
f_email: WSF_FORM_EMAIL_INPUT
f_msg: WSF_FORM_TEXTAREA
f_submit: WSF_FORM_SUBMIT_INPUT
do
create f.make (a_response.url ("contact", Void), "contact-form")
create f_name.make ("name")
f_name.set_label ("Name")
f_name.set_is_required (True)
f.extend (f_name)
create f_email.make ("email")
f_email.set_label ("Email Address")
f_email.set_is_required (True)
f.extend (f_email)
create f_msg.make ("message")
f_msg.set_label ("Message")
f_msg.set_rows (5)
f_msg.set_is_required (True)
f.extend (f_msg)
if attached recaptcha_site_key (api) as l_recaptcha_site_key then
f.extend_html_text ("<div class=%"g-recaptcha%" data-sitekey=%"" + l_recaptcha_site_key + "%"></div><br/>")
end
create f_submit.make_with_text ("submit-op", "Send")
f.extend (f_submit)
-- f.extend_html_text ("[
-- <p class="req-field-desc"><span class="required">*</span> indicates a required field</p>
-- ]")
Result := f
end
handle_contact (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
do
-- FIXME: we should use WSF_FORM, and integrate the recaptcha using the form alter hook.
write_debug_log (generator + ".handle_contact")
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.values.force ("contact", "contact")
r.set_main_content (new_html_contact_form (r, api))
r.execute
end
handle_post_contact (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
msg: CONTACT_MESSAGE
l_params: CONTACT_EMAIL_SERVICE_PARAMETERS
e: CMS_EMAIL
vars: STRING_TABLE [READABLE_STRING_8]
l_contact_email_address: READABLE_STRING_8
do
write_information_log (generator + ".handle_post_contact")
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.add_style (r.url ("/module/" + name + "/files/css/contact.css", Void), Void)
r.values.force (False, "has_error")
create vars.make_caseless (5)
vars.put (safe_html_encoded (api.setup.site_url), "siteurl")
vars.put (safe_html_encoded (api.setup.site_name), "sitename")
write_debug_log (generator + ".handle_post_contact {Form Parameters:" + form_parameters_as_string (req) + "}")
if
attached {WSF_STRING} req.form_parameter ("name") as l_name and then
attached {WSF_STRING} req.form_parameter ("email") as l_email and then
attached {WSF_STRING} req.form_parameter ("message") as l_message
then
if
is_form_captcha_verified (req, "g-recaptcha-response", api) and then
l_email.value.is_valid_as_string_8
then
l_contact_email_address := l_email.value.to_string_8
if attached contact_api as l_contact_api then
create msg.make (l_name.value, l_message.value)
msg.set_email (l_contact_email_address)
l_contact_api.save_contact_message (msg)
end
create l_params.make (api, Current)
-- Send internal email to admin.
vars.put (html_encoded (l_name.value), "name")
vars.put (html_encoded (l_contact_email_address), "email")
vars.put (html_encoded (l_message.value), "message")
write_debug_log (generator + ".handle_post_contact: send notification email")
e := api.new_email (l_params.admin_email, "Notification Contact", email_html_message ("notification", r, vars))
e.set_from_address (l_params.admin_email)
e.add_header_line ("MIME-Version:1.0")
e.add_header_line ("Content-Type: text/html; charset=utf-8")
api.process_email (e)
if not api.has_error then
-- Send Contact email to the user
write_information_log (generator + ".handle_post_contact: preparing the message.")
e := api.new_email (l_contact_email_address, l_params.contact_subject_text, email_html_message ("message", r, vars))
e.set_from_address (l_params.admin_email)
e.add_header_line ("MIME-Version:1.0")
e.add_header_line ("Content-Type: text/html; charset=utf-8")
write_debug_log (generator + ".handle_post_contact: send_contact_email")
api.process_email (e)
end
if api.has_error then
write_error_log (generator + ".handle_post_contact: error message:["+ api.string_representation_of_errors +"]")
r.set_status_code ({HTTP_CONSTANTS}.internal_server_error)
r.values.force (True, "has_error")
vars.put ("True", "has_error")
end
if attached template_block_with_values (Current, "post_contact", r, vars) as l_tpl_block then
across
r.values as tb
loop
l_tpl_block.set_value (tb.item, tb.key)
end
r.set_main_content (l_tpl_block.to_html (r.theme))
else
r.set_main_content ("Thank you for your message.")
end
r.execute
else
-- send a bad request status code and redisplay the form with the previous data loaded.
r.set_value (False, "error")
r.set_status_code ({HTTP_STATUS_CODE}.bad_request)
if attached template_block_with_values (Current, "contact", r, vars) as l_tpl_block then
across
r.values as tb
loop
l_tpl_block.set_value (tb.item, tb.key)
end
if attached recaptcha_site_key (api) as l_recaptcha_site_key then
l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key")
l_tpl_block.set_value (<<"Missing Captcha", "Internal Server Error">>, "error_response")
end
r.set_main_content (l_tpl_block.to_html (r.theme))
else
debug ("cms")
r.add_warning_message ("Error with block [contact]")
end
end
r.execute
end
else
-- Internal server error
write_error_log (generator + ".handle_post_contact: Internal Server error")
r.values.force (True, "has_error")
r.set_status_code ({HTTP_CONSTANTS}.internal_server_error)
if attached template_block_with_values (Current, "post_contact", r, vars) as l_tpl_block then
across
r.values as tb
loop
l_tpl_block.set_value (tb.item, tb.key)
end
r.set_main_content (l_tpl_block.to_html (r.theme))
end
r.execute
end
end
is_form_captcha_verified (req: WSF_REQUEST; a_form_field_id: READABLE_STRING_GENERAL; api: CMS_API): BOOLEAN
do
if attached recaptcha_secret_key (api) as l_recaptcha_key then
if
attached {WSF_STRING} req.form_parameter (a_form_field_id) as l_recaptcha_response and then
is_captcha_verified (l_recaptcha_key, l_recaptcha_response.value)
then
Result := True
else
--| Bad or missing captcha
Result := False
end
else
--| reCaptcha is not setup, so no verification
Result := True
end
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
template_block_with_values (a_module: CMS_MODULE; a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE; a_values: STRING_TABLE [ANY]): like template_block
do
Result := template_block (a_module, a_block_id, a_response)
if Result /= Void then
across
a_values as ic
loop
Result.set_value (ic.item, ic.key)
end
end
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 (contact_message_template)
elseif a_message_id.is_case_insensitive_equal_general ("notification") then
create Result.make_from_string (contact_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
contact_message_template: STRING
do
Result := "[
<p>Thank you for contacting $sitename.<br/>
We will get back to you promptly on your contact request.
</p>
]"
+ contact_notification_message_template
end
contact_notification_message_template: STRING = "[
<h2>Contact information:</h2>
<div>
<strong>Name<strong>: $name <br/>
<strong>Email<strong>: $email <br/>
<strong>Message<strong>: $message <br/>
</div>
]"
feature {NONE} -- Google recaptcha uri template
is_captcha_verified (a_secret, a_response: READABLE_STRING_8): BOOLEAN
local
api: RECAPTCHA_API
l_errors: STRING
do
write_debug_log (generator + ".is_captcha_verified with response: [" + a_response + "]")
create api.make (a_secret, a_response)
Result := api.verify
if not Result and then attached api.errors as l_api_errors then
create l_errors.make_empty
l_errors.append_character ('%N')
across l_api_errors as ic loop
l_errors.append ( ic.item )
l_errors.append_character ('%N')
end
write_error_log (generator + ".is_captcha_verified api_errors [" + l_errors + "]")
end
end
end

View File

@@ -0,0 +1,40 @@
note
description: "API for the contact module."
date: "$Date: 2015-05-22 23:00:09 +0200 (ven., 22 mai 2015) $"
revision: "$Revision: 97349 $"
class
CONTACT_API
inherit
CMS_MODULE_API
rename
make as make_api
end
REFACTORING_HELPER
create
make
feature {NONE} -- Initialization
make (a_api: CMS_API; a_contact_storage: like contact_storage)
-- <Precursor>.
do
make_api (a_api)
contact_storage := a_contact_storage
end
feature {CMS_MODULE} -- Access nodes storage.
contact_storage: CONTACT_STORAGE_I
feature -- Basic operation
save_contact_message (msg: CONTACT_MESSAGE)
do
contact_storage.save_contact_message (msg)
end
end

View File

@@ -0,0 +1,63 @@
note
description: "Summary description for {CONTACT_EMAIL_SERVICE_PARAMETERS}."
date: "$Date: 2015-07-03 19:04:52 +0200 (ven., 03 juil. 2015) $"
revision: "$Revision: 97646 $"
class
CONTACT_EMAIL_SERVICE_PARAMETERS
create
make
feature {NONE} -- Initialization
make (a_cms_api: CMS_API; a_contact_module: CMS_CONTACT_MODULE)
local
utf: UTF_CONVERTER
l_site_name: READABLE_STRING_8
s: detachable READABLE_STRING_32
l_contact_email, l_contact_subject: detachable READABLE_STRING_8
do
-- Use global smtp setting if any, otherwise "localhost"
l_site_name := utf.escaped_utf_32_string_to_utf_8_string_8 (a_cms_api.setup.site_name)
admin_email := a_cms_api.setup.site_email
if not admin_email.has ('<') then
admin_email := l_site_name + " <" + admin_email + ">"
end
if attached {CONFIG_READER} a_cms_api.module_configuration (a_contact_module, Void) as cfg then
s := cfg.text_item ("email")
if s /= Void then
l_contact_email := utf.utf_32_string_to_utf_8_string_8 (s)
end
s := cfg.text_item ("subject")
if s /= Void then
l_contact_subject := utf.utf_32_string_to_utf_8_string_8 (s)
end
end
if l_contact_email /= Void then
if not l_contact_email.has ('<') then
l_contact_email := l_site_name + " <" + l_contact_email + ">"
end
contact_email := l_contact_email
else
contact_email := admin_email
end
if l_contact_subject /= Void then
contact_subject_text := l_contact_subject
else
contact_subject_text := "Thank you for contacting us"
end
end
feature -- Access
admin_email: IMMUTABLE_STRING_8
contact_email: IMMUTABLE_STRING_8
-- Contact email.
contact_subject_text: IMMUTABLE_STRING_8
end

View File

@@ -0,0 +1,43 @@
note
description: "Interface {CONTACT_MESSAGE} representing the contact's message."
date: "$Date: 2015-07-03 19:04:52 +0200 (ven., 03 juil. 2015) $"
revision: "$Revision: 97646 $"
class
CONTACT_MESSAGE
create
make
feature {NONE} -- Initialization
make (a_name: like username; a_message: like message)
do
username := a_name
message := a_message
create date.make_now_utc
end
feature -- Access
username: READABLE_STRING_32
email: detachable READABLE_STRING_8
message: READABLE_STRING_32
date: DATE_TIME
feature -- Change
set_email (e: like email)
do
email := e
end
set_date (d: like date)
do
date := d
end
end

View File

@@ -0,0 +1,56 @@
note
description: "[
Contact message storage based on SQL statements.
]"
date: "$Date: 2015-07-03 19:04:52 +0200 (ven., 03 juil. 2015) $"
revision: "$Revision: 97646 $"
class
CONTACT_STORAGE_FS
inherit
CONTACT_STORAGE_I
CMS_STORAGE_FS_I
REFACTORING_HELPER
create
make
feature -- Access
feature -- Change
save_contact_message (m: CONTACT_MESSAGE)
local
s: STRING
utf: UTF_CONVERTER
now: DATE_TIME
do
error_handler.reset
create now.make_now_utc
write_information_log (generator + ".save_contact_message")
create s.make_empty
s.append ("date=")
s.append (m.date.out)
s.append_character ('%N')
s.append ("name=")
s.append (utf.utf_32_string_to_utf_8_string_8 (m.username))
s.append_character ('%N')
if attached m.email as l_email then
s.append ("email=")
s.append (l_email)
s.append_character ('%N')
end
s.append ("message=%N")
s.append (utf.utf_32_string_to_utf_8_string_8 (m.message))
s.append_character ('%N')
save_to_file (s, date_to_yyyymmdd_hhmmss_string (now))
end
end

View File

@@ -0,0 +1,27 @@
note
description: "[
Persistence interface for CONTACT_MODULE.
]"
author: "$Author: jfiat $"
date: "$Date: 2015-05-22 23:00:09 +0200 (ven., 22 mai 2015) $"
revision: "$Revision: 97349 $"
deferred class
CONTACT_STORAGE_I
feature -- Error Handling
error_handler: ERROR_HANDLER
-- Error handler.
deferred
end
feature -- Access
feature -- Change
save_contact_message (m: CONTACT_MESSAGE)
deferred
end
end

View File

@@ -0,0 +1,39 @@
note
description: "[
Objects that ...
]"
author: "$Author: jfiat $"
date: "$Date: 2015-05-22 23:00:09 +0200 (ven., 22 mai 2015) $"
revision: "$Revision: 97349 $"
class
CONTACT_STORAGE_NULL
inherit
CONTACT_STORAGE_I
create
make
feature {NONE} -- Initialization
make
-- Initialize `Current'.
do
create error_handler.make
end
feature -- Error Handling
error_handler: ERROR_HANDLER
-- Error handler.
feature -- Access
feature -- Change
save_contact_message (m: CONTACT_MESSAGE)
do
end
end

View File

@@ -0,0 +1,49 @@
note
description: "[
Contact message storage based on SQL statements.
]"
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
class
CONTACT_STORAGE_SQL
inherit
CMS_PROXY_STORAGE_SQL
CONTACT_STORAGE_I
CMS_STORAGE_SQL_I
REFACTORING_HELPER
create
make
feature -- Access
feature -- Change
save_contact_message (m: CONTACT_MESSAGE)
local
l_parameters: STRING_TABLE [detachable ANY]
now: DATE_TIME
do
create now.make_now_utc
error_handler.reset
write_information_log (generator + ".save_contact_message")
create l_parameters.make (9)
l_parameters.put (m, "message")
l_parameters.put (now, "changed")
sql_begin_transaction
sql_modify (sql_insert_contact_message, l_parameters)
sql_commit_transaction
end
feature {NONE} -- Queries
sql_insert_contact_message: STRING = "INSERT INTO contact_messages (name, email, date, message) VALUES (:name, :email, :date, :message);"
-- SQL Insert to add a new contact message.
end

View File

@@ -290,9 +290,7 @@ feature -- Access: Node
is_author_of_node (u: CMS_USER; a_node: CMS_NODE): BOOLEAN is_author_of_node (u: CMS_USER; a_node: CMS_NODE): BOOLEAN
-- Is the user `u' owner of the node `n'. -- Is the user `u' owner of the node `n'.
do do
if attached node_storage.node_author (a_node) as l_author then Result := u.same_as (a_node.author)
Result := u.same_as (l_author)
end
end 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]

View File

@@ -127,8 +127,13 @@ feature {CMS_API} -- Module management
-- Schema -- Schema
if attached a_api.storage.as_sql_storage as l_sql_storage then if attached a_api.storage.as_sql_storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void) l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void)
if l_sql_storage.has_error then
a_api.logger.put_error ("Could not initialize database for module [" + name + "]", generating_type)
else
Precursor {CMS_MODULE} (a_api)
end
end end
Precursor {CMS_MODULE}(a_api)
end end
feature {CMS_API} -- Access: API feature {CMS_API} -- Access: API

Some files were not shown because too many files have changed in this diff Show More