Compare commits
19 Commits
es_rev9840
...
es_rev9852
| Author | SHA1 | Date | |
|---|---|---|---|
| a7f1f14b8a | |||
| fbda2c9eb2 | |||
| ff58593bff | |||
| c65f5765d6 | |||
| 19565b9c98 | |||
| 6716cb5575 | |||
| 75332c148d | |||
| b54fd85172 | |||
| bc07aad01b | |||
| ce4bb551d2 | |||
| 5ceb9d3dd3 | |||
| c1a5838320 | |||
| db697cec3e | |||
| 892f2331de | |||
| 3496536751 | |||
| 41ac45d07b | |||
| d3b485f4d3 | |||
| 2b1d5f9693 | |||
| 59c03c5f4d |
@@ -8,7 +8,7 @@
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</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" is_obsolete_routine_type="true" void_safety="all" syntax="transitional">
|
||||
<debug name="dbglog" enabled="true"/>
|
||||
</option>
|
||||
<setting name="executable_name" value="demo"/>
|
||||
@@ -24,23 +24,23 @@
|
||||
<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_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_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_files_module" location="..\..\modules\files\files-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_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_oauth_20_module" location="..\..\modules\oauth20\oauth20-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_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">
|
||||
<option>
|
||||
<assertions/>
|
||||
</option>
|
||||
</library>
|
||||
<library name="persistence_sqlite3" location="..\..\library\persistence\sqlite3\sqlite3-safe.ecf" readonly="false"/>
|
||||
<!--
|
||||
By default, commented, since it depends on specific environment settings.
|
||||
<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" />
|
||||
-->
|
||||
@@ -48,7 +48,7 @@
|
||||
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<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"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
port=9090
|
||||
#port=12345
|
||||
#verbose=true
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set ROC_CMD=call %~dp0..\..\tools\roc.bat
|
||||
set ROC_CMS_DIR=%~dp0
|
||||
@@ -6,10 +7,14 @@ set ROC_CMS_DIR=%~dp0
|
||||
%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\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\oauth20 --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\feed_aggregator --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\google_search --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\seo --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\files --dir %ROC_CMS_DIR%
|
||||
|
||||
@@ -70,8 +70,9 @@ CREATE TABLE tb_demo(
|
||||
api.logger.put_error ("Could not initialize database for demo module", generating_type)
|
||||
end
|
||||
end
|
||||
Precursor {CMS_MODULE}(api)
|
||||
end
|
||||
-- For this demo, be flexible, and do not required sql.
|
||||
Precursor {CMS_MODULE}(api)
|
||||
end
|
||||
|
||||
feature -- Access: router
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#navigation.region=sidebar_first
|
||||
#navigation.condition=is_front
|
||||
management.conditions[]=path:admin*
|
||||
management.conditions[]=is_front
|
||||
#management.conditions[]=path:admin*
|
||||
#management.conditions[]=is_front
|
||||
|
||||
#Feeds
|
||||
feed.news.weight=3
|
||||
|
||||
@@ -4,9 +4,17 @@ root-dir=site/www
|
||||
#modules-dir=site/modules
|
||||
|
||||
[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
|
||||
|
||||
# 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
|
||||
|
||||
@@ -39,6 +47,14 @@ output=site\db\mailer.log
|
||||
[blocks]
|
||||
@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]
|
||||
# CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none)
|
||||
installation_access=all
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"subject": "Thank you for contacting us",
|
||||
"forms": {
|
||||
"registration": {
|
||||
"application_description": "Present yourself in a few lines, otherwise your application is likely to be rejected."
|
||||
}
|
||||
},
|
||||
"recaptcha": {
|
||||
"site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD",
|
||||
"secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx"
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
|
||||
<p>To reject the registration, please click on the following link <p>
|
||||
|
||||
<p><a href="$rejection_url<">$rejection_url</a></p>
|
||||
<p><a href="$rejection_url">$rejection_url</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{include file="block_account_info.tpl" /}
|
||||
@@ -1,62 +1,34 @@
|
||||
<div class="primary-tabs">
|
||||
{if isset="$user"}
|
||||
<h3>Account Information</h3>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<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>
|
||||
<ul class="user-information">
|
||||
<div>
|
||||
<label>Username:</label> {$user.name/}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{include file="block_change_password.tpl" /}
|
||||
<hr>
|
||||
<h4>Roles</h4>
|
||||
<div>
|
||||
{foreach item="ic" from="$roles"}
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>{$ic.name/}</strong>
|
||||
<ul>
|
||||
<li> <i>permissions</i>
|
||||
<ul>
|
||||
{foreach item="ip" from="$ic.permissions"}
|
||||
<li>{$ip/}</li>
|
||||
{/foreach}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label>Email:</label> {$user.email/}
|
||||
</div>
|
||||
<div>
|
||||
<label>Creation Date:</label> {$user.creation_date/} (UTC)
|
||||
</div>
|
||||
<div>
|
||||
<label>Last login:</label> {$user.last_login_date/} (UTC)
|
||||
</div>
|
||||
<div>
|
||||
<form method="get" action="{$site_url/}account/roc-logout">
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
</div>
|
||||
</ul>
|
||||
<hr>
|
||||
<h4>Profile</h4>
|
||||
<div>
|
||||
<ul class="user-profile">
|
||||
{foreach item="the_value" key="the_name" from="$user.profile"}
|
||||
<div>
|
||||
<label>{$the_name/}:</label> {$the_value/}
|
||||
</div>
|
||||
<li>
|
||||
<label>{$the_name/}:</label><div>{$the_value/}</div>
|
||||
</li>
|
||||
{/foreach}
|
||||
</div>
|
||||
</ul>
|
||||
{/if}
|
||||
{unless isset="$user"}
|
||||
<div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div>
|
||||
<form action="{$site_url/}account/change-password" method="post">
|
||||
<fieldset>
|
||||
<legend>Change Password Form</legend>
|
||||
<legend>Change Password</legend>
|
||||
<div>
|
||||
<input type="password" id="password" name="password" value="" required/>
|
||||
<label for="password">Password</label>
|
||||
|
||||
@@ -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>
|
||||
@@ -1,39 +1,38 @@
|
||||
<div>
|
||||
<form action="{$site_url/}account/roc-register" method="post">
|
||||
<fieldset>
|
||||
<legend>Registration</legend>
|
||||
<div>
|
||||
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
|
||||
<label for="name">Name</label>
|
||||
{if isset="$error_name"}
|
||||
<span><i>{$error_name/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" id="password" name="password" value="" required/>
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||
<label for="email">Email</label>
|
||||
{if isset="$error_email"}
|
||||
<span><i>{$error_email/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<textarea rows="4" cols="50" name="personal_information" id="personal_information" required>
|
||||
{$personal_information/}
|
||||
</textarea>
|
||||
<label for="personal_information">Tell us why you want to register an account</label>
|
||||
{if isset="$error_application"}
|
||||
<span><i>{$error_application/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
{unless isempty="$recaptcha_site_key"}
|
||||
<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div>
|
||||
<br/>
|
||||
{/unless}
|
||||
<button type="submit">Register</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div>
|
||||
<form action="{$site_url/}account/roc-register" method="post">
|
||||
<fieldset>
|
||||
<legend>Registration</legend>
|
||||
<div>
|
||||
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
|
||||
<label for="name">Name</label>
|
||||
{if isset="$error_name"}
|
||||
<span><i>{$error_name/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" id="password" name="password" value="" required/>
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||
<label for="email">Email</label>
|
||||
{if isset="$error_email"}
|
||||
<span><i>{$error_email/}</i></span> <br/>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<textarea rows="4" cols="50" name="personal_information" id="personal_information" required>{$personal_information/}</textarea>
|
||||
<label for="personal_information">Tell us why you want to register an account</label>
|
||||
{if isset="$error_application"}
|
||||
<span><i>{$error_application/}</i></span><br/>
|
||||
{/if}
|
||||
{if isset="$application_description"}
|
||||
<br/>
|
||||
<p class="description">{$application_description/}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{unless isempty="$recaptcha_site_key"}<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div><br/>{/unless}
|
||||
<button type="submit">Register</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,307 +1,291 @@
|
||||
var ROC_AUTH = ROC_AUTH || { };
|
||||
|
||||
var loginURL = "/basic_auth_login";
|
||||
var logoutURL = "/basic_auth_logoff";
|
||||
var loginURL = "/roc-basic-login";
|
||||
var logoutURL = "/roc-basic-logoff";
|
||||
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
var firstLogIn = true;
|
||||
|
||||
ROC_AUTH.login = function() {
|
||||
var form = document.forms['cms_basic_auth'];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
//var host = form.host.value;
|
||||
var form = document.forms['cms_basic_auth'];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
//var host = form.host.value;
|
||||
var origin = window.location.origin + window.location.pathname;
|
||||
var _login = function(){
|
||||
var _login = function(){
|
||||
if (document.getElementById('myModalFormId') !== null ) {
|
||||
ROC_AUTH.remove ('myModalFormId');
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}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 === "") {
|
||||
if (document.getElementById('myModalFormId') === null ) {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$(".primary-tabs").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';
|
||||
$(".primary-tabs").append(newdiv);
|
||||
}
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
if (userAgent.indexOf("firefox") != -1) { //TODO: check version number
|
||||
if (firstLogIn) {
|
||||
_login();
|
||||
} else {
|
||||
ROC_AUTH.logoff(_login);
|
||||
}
|
||||
} else {
|
||||
_login();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (firstLogIn) {
|
||||
firstLogIn = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.login_with_redirect = function() {
|
||||
var form = document.forms[2];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
var host = form.host.value;
|
||||
var _login = function(){
|
||||
var form = document.forms[2];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
var host = form.host.value;
|
||||
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();
|
||||
|
||||
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';
|
||||
$(".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;
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||
if (firstLogIn) {
|
||||
_login();
|
||||
} else {
|
||||
ROC_AUTH.logoff(_login);
|
||||
}
|
||||
} else{
|
||||
_login();
|
||||
}
|
||||
if (firstLogIn) {
|
||||
firstLogIn = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.getQueryParameterByName = function (name) {
|
||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||||
results = regex.exec(location.search);
|
||||
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search);
|
||||
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
ROC_AUTH.logoff = function(callback){
|
||||
var form = document.forms[0];
|
||||
var host = form.host.value;
|
||||
|
||||
if (userAgent.indexOf("msie") != -1) {
|
||||
document.execCommand("ClearAuthenticationCache");
|
||||
}
|
||||
else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||
|
||||
var request1 = new XMLHttpRequest();
|
||||
var request2 = new XMLHttpRequest();
|
||||
|
||||
//Logout. Tell the server not to return the "WWW-Authenticate" header
|
||||
request1.open("GET", host.concat(logoutURL) + "?prompt=false", true);
|
||||
request1.send("");
|
||||
request1.onreadystatechange = function(){
|
||||
if (request1.readyState == 4) {
|
||||
|
||||
//Sign in with dummy credentials to clear the auth cache
|
||||
request2.open("GET", host.concat(logoutURL), true, "logout", "logout");
|
||||
request2.send("");
|
||||
|
||||
request2.onreadystatechange = function(){
|
||||
if (request2.readyState == 4) {
|
||||
if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||
request.open("GET", host.concat(logoutURL), true, "logout", "logout");
|
||||
request.send("");
|
||||
request.onreadystatechange = function(){
|
||||
if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
var form = document.forms[0];
|
||||
var host = form.host.value;
|
||||
|
||||
if (userAgent.indexOf("msie") != -1) {
|
||||
document.execCommand("ClearAuthenticationCache");
|
||||
} else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||
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);
|
||||
request1.send("");
|
||||
request1.onreadystatechange = function(){
|
||||
if (request1.readyState == 4) {
|
||||
//Sign in with dummy credentials to clear the auth cache
|
||||
request2.open("GET", host + logoutURL, true, "logout", "logout");
|
||||
request2.send("");
|
||||
request2.onreadystatechange = function(){
|
||||
if (request2.readyState == 4) {
|
||||
if (callback!=null) {
|
||||
callback.call();
|
||||
} else {
|
||||
window.location=host + logoutURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||
request.open("GET", host + logoutURL, true, "logout", "logout");
|
||||
request.send("");
|
||||
request.onreadystatechange = function(){
|
||||
if (request.status==401 || request.status==403 ) {
|
||||
window.location=host + logoutURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.remove = function (id)
|
||||
{
|
||||
var element = document.getElementById(id);
|
||||
element.outerHTML = "";
|
||||
delete element;
|
||||
return;
|
||||
ROC_AUTH.remove = function (id) {
|
||||
var element = document.getElementById(id);
|
||||
element.outerHTML = "";
|
||||
delete element;
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
if (typeof String.prototype.contains != 'function') {
|
||||
String.prototype.contains = function (str){
|
||||
return this.indexOf(str) != -1;
|
||||
};
|
||||
}
|
||||
ROC_AUTH.progressive_loging();
|
||||
|
||||
if (typeof String.prototype.contains != 'function') {
|
||||
String.prototype.contains = function (str){
|
||||
return this.indexOf(str) != -1;
|
||||
};
|
||||
}
|
||||
ROC_AUTH.progressive_loging();
|
||||
});
|
||||
|
||||
|
||||
ROC_AUTH.progressive_loging = function () {
|
||||
|
||||
ROC_AUTH.login_href();
|
||||
ROC_AUTH.login_href();
|
||||
};
|
||||
|
||||
|
||||
$(document).keypress(function(e) {
|
||||
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
|
||||
ROC_AUTH.login();
|
||||
}
|
||||
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
|
||||
ROC_AUTH.login();
|
||||
}
|
||||
});
|
||||
|
||||
ROC_AUTH.OnOneClick = function(event) {
|
||||
event.preventDefault();
|
||||
if ( document.forms[0] === undefined ) {
|
||||
ROC_AUTH.create_form();
|
||||
}
|
||||
return false;
|
||||
event.preventDefault();
|
||||
if ( document.forms[0] === undefined ) {
|
||||
ROC_AUTH.create_form();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
ROC_AUTH.login_href = function() {
|
||||
var els = document.getElementsByTagName("a");
|
||||
for (var i = 0, l = els.length; i < l; i++) {
|
||||
var el = els[i];
|
||||
if (el.href.contains("/basic_auth_login?destination")) {
|
||||
loginURL = el.href;
|
||||
var OneClick = el;
|
||||
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
|
||||
}
|
||||
}
|
||||
var els = document.getElementsByTagName("a");
|
||||
for (var i = 0, l = els.length; i < l; i++) {
|
||||
var el = els[i];
|
||||
if (el.href.contains(loginURL + "?destination")) {
|
||||
// loginURL = el.href;
|
||||
var OneClick = el;
|
||||
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.create_form = function() {
|
||||
|
||||
// Fetching HTML Elements in Variables by ID.
|
||||
var createform = document.createElement('form'); // Create New Element Form
|
||||
createform.setAttribute("action", ""); // Setting Action Attribute on Form
|
||||
createform.setAttribute("method", "post"); // Setting Method Attribute on Form
|
||||
$("body").append(createform);
|
||||
// Fetching HTML Elements in Variables by ID.
|
||||
var createform = document.createElement('form'); // Create New Element Form
|
||||
createform.setAttribute("action", ""); // Setting Action Attribute on Form
|
||||
createform.setAttribute("method", "post"); // Setting Method Attribute on Form
|
||||
$("body").append(createform);
|
||||
|
||||
var heading = document.createElement('h2'); // Heading of Form
|
||||
heading.innerHTML = "Login Form ";
|
||||
createform.appendChild(heading);
|
||||
var heading = document.createElement('h2'); // Heading of Form
|
||||
heading.innerHTML = "Login Form ";
|
||||
createform.appendChild(heading);
|
||||
|
||||
var line = document.createElement('hr'); // Giving Horizontal Row After Heading
|
||||
createform.appendChild(line);
|
||||
var line = document.createElement('hr'); // Giving Horizontal Row After Heading
|
||||
createform.appendChild(line);
|
||||
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
|
||||
var namelabel = document.createElement('label'); // Create Label for Name Field
|
||||
namelabel.innerHTML = "Username : "; // Set Field Labels
|
||||
createform.appendChild(namelabel);
|
||||
var namelabel = document.createElement('label'); // Create Label for Name Field
|
||||
namelabel.innerHTML = "Username : "; // Set Field Labels
|
||||
createform.appendChild(namelabel);
|
||||
|
||||
var inputelement = document.createElement('input'); // Create Input Field for UserName
|
||||
inputelement.setAttribute("type", "text");
|
||||
inputelement.setAttribute("name", "username");
|
||||
inputelement.setAttribute("required","required");
|
||||
createform.appendChild(inputelement);
|
||||
var inputelement = document.createElement('input'); // Create Input Field for UserName
|
||||
inputelement.setAttribute("type", "text");
|
||||
inputelement.setAttribute("name", "username");
|
||||
inputelement.setAttribute("required","required");
|
||||
createform.appendChild(inputelement);
|
||||
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
|
||||
var passwordlabel = document.createElement('label'); // Create Label for Password Field
|
||||
passwordlabel.innerHTML = "Password : ";
|
||||
createform.appendChild(passwordlabel);
|
||||
var passwordlabel = document.createElement('label'); // Create Label for Password Field
|
||||
passwordlabel.innerHTML = "Password : ";
|
||||
createform.appendChild(passwordlabel);
|
||||
|
||||
var passwordelement = document.createElement('input'); // Create Input Field for Password.
|
||||
passwordelement.setAttribute("type", "password");
|
||||
passwordelement.setAttribute("name", "password");
|
||||
passwordelement.setAttribute("id", "password");
|
||||
passwordelement.setAttribute("required","required");
|
||||
createform.appendChild(passwordelement);
|
||||
var passwordelement = document.createElement('input'); // Create Input Field for Password.
|
||||
passwordelement.setAttribute("type", "password");
|
||||
passwordelement.setAttribute("name", "password");
|
||||
passwordelement.setAttribute("id", "password");
|
||||
passwordelement.setAttribute("required","required");
|
||||
createform.appendChild(passwordelement);
|
||||
|
||||
|
||||
var passwordbreak = document.createElement('br');
|
||||
createform.appendChild(passwordbreak);
|
||||
var passwordbreak = document.createElement('br');
|
||||
createform.appendChild(passwordbreak);
|
||||
|
||||
|
||||
var submitelement = document.createElement('button'); // Append Submit Button
|
||||
submitelement.setAttribute("type", "button");
|
||||
submitelement.setAttribute("onclick", "ROC_AUTH.login();");
|
||||
submitelement.innerHTML = "Sign In ";
|
||||
createform.appendChild(submitelement);
|
||||
var submitelement = document.createElement('button'); // Append Submit Button
|
||||
submitelement.setAttribute("type", "button");
|
||||
submitelement.setAttribute("onclick", "ROC_AUTH.login();");
|
||||
submitelement.innerHTML = "Sign In ";
|
||||
createform.appendChild(submitelement);
|
||||
|
||||
};
|
||||
|
||||
@@ -310,16 +294,16 @@ var password = document.getElementById("password");
|
||||
var confirm_password = document.getElementById("confirm_password");
|
||||
|
||||
ROC_AUTH.validatePassword =function(){
|
||||
if ((password != null) && (confirm_password != null)) {
|
||||
if(password.value != confirm_password.value) {
|
||||
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||
} else {
|
||||
confirm_password.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
if ((password != null) && (confirm_password != null)) {
|
||||
if(password.value != confirm_password.value) {
|
||||
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||
} else {
|
||||
confirm_password.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((password != null) && (confirm_password != null)) {
|
||||
password.onchange = ROC_AUTH.validatePassword();
|
||||
confirm_password.onkeyup = ROC_AUTH.validatePassword;
|
||||
password.onchange = ROC_AUTH.validatePassword();
|
||||
confirm_password.onkeyup = ROC_AUTH.validatePassword;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
<div class="primary-tabs">
|
||||
{unless isset="$user"}
|
||||
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
|
||||
{unless isset="$user"}
|
||||
<div class="login-box">
|
||||
<div class="description">The "Basic Auth" relies on the HTTP basic access 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>
|
||||
<form name="cms_basic_auth" action method="POST">
|
||||
<div>
|
||||
<input type="text" name="username" id="username" required>
|
||||
<label>Username</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label>Password</label>
|
||||
</div>
|
||||
|
||||
<button type="button" onclick="ROC_AUTH.login();">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<form name="cms_basic_auth" action="{$site_url/}roc-basic-login" method="POST">
|
||||
<input type="hidden" name="host" id="host" value="{$site_url/}">
|
||||
<div>
|
||||
<input type="text" name="username" id="username" required>
|
||||
<label>Username</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label>Password</label>
|
||||
</div>
|
||||
<button type="button" onclick="ROC_AUTH.login();">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||
</p>
|
||||
</div>
|
||||
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||
</div>
|
||||
{/unless}
|
||||
</div>
|
||||
{/unless}
|
||||
|
||||
6
examples/demo/site/modules/blog/scripts/install.sql
Normal file
6
examples/demo/site/modules/blog/scripts/install.sql
Normal 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)
|
||||
);
|
||||
8
examples/demo/site/modules/contact/config/contact.json
Normal file
8
examples/demo/site/modules/contact/config/contact.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"--email": "webmaster@example.com",
|
||||
"subjet": "Thank you for contacting us",
|
||||
"recaptcha": {
|
||||
"site_key":"",
|
||||
"secret_key":""
|
||||
}
|
||||
}
|
||||
124
examples/demo/site/modules/contact/files/css/contact.css
Normal file
124
examples/demo/site/modules/contact/files/css/contact.css
Normal 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;
|
||||
}
|
||||
140
examples/demo/site/modules/contact/files/scss/contact.scss
Normal file
140
examples/demo/site/modules/contact/files/scss/contact.scss
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
52
examples/demo/site/modules/files/files/css/files.css
Normal file
52
examples/demo/site/modules/files/files/css/files.css
Normal file
@@ -0,0 +1,52 @@
|
||||
.uploaded-files table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.uploaded-files table th {
|
||||
padding: 3px 0 3px 5px;
|
||||
}
|
||||
.uploaded-files table td {
|
||||
padding: 3px 0 3px 5px;
|
||||
}
|
||||
.uploaded-files a.button {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border: solid 1px #999;
|
||||
background-color: #ddd;
|
||||
padding: 2px 4px 2px 4px;
|
||||
}
|
||||
.uploaded-files a.button:hover {
|
||||
color: black;
|
||||
border: solid 1px #06f;
|
||||
background-color: #cff;
|
||||
}
|
||||
|
||||
.upload-files .center {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
.upload-files a.button {
|
||||
margin: auto;
|
||||
width: 100px;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border: solid 1px #999;
|
||||
background-color: #ddd;
|
||||
padding: 2px 4px 2px 4px;
|
||||
}
|
||||
.upload-files a.button:hover {
|
||||
color: black;
|
||||
border: solid 1px #06f;
|
||||
background-color: #cff;
|
||||
}
|
||||
|
||||
/******************* Drop Zone *******************/
|
||||
.dropzone {
|
||||
width: 100%;
|
||||
border: 2px dashed blue;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
BIN
examples/demo/site/modules/files/files/img/file-logo.png
Normal file
BIN
examples/demo/site/modules/files/files/img/file-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
1
examples/demo/site/modules/files/files/js/dropzone.css
Normal file
1
examples/demo/site/modules/files/files/js/dropzone.css
Normal file
File diff suppressed because one or more lines are too long
1763
examples/demo/site/modules/files/files/js/dropzone.js
Normal file
1763
examples/demo/site/modules/files/files/js/dropzone.js
Normal file
File diff suppressed because it is too large
Load Diff
78
examples/demo/site/modules/files/files/js/src/basic.scss
Normal file
78
examples/demo/site/modules/files/files/js/src/basic.scss
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright (c) 2012 Matias Meno <m@tias.me>
|
||||
*/
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
.dropzone, .dropzone * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.dropzone {
|
||||
|
||||
position: relative;
|
||||
|
||||
.dz-preview {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
margin: 0.5em;
|
||||
|
||||
.dz-progress {
|
||||
display: block;
|
||||
height: 15px;
|
||||
border: 1px solid #aaa;
|
||||
.dz-upload {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background: green;
|
||||
}
|
||||
}
|
||||
|
||||
.dz-error-message {
|
||||
color: red;
|
||||
display: none;
|
||||
}
|
||||
&.dz-error {
|
||||
.dz-error-message, .dz-error-mark {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.dz-success {
|
||||
.dz-success-mark {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.dz-error-mark, .dz-success-mark {
|
||||
position: absolute;
|
||||
display: none;
|
||||
left: 30px;
|
||||
top: 30px;
|
||||
width: 54px;
|
||||
height: 58px;
|
||||
left: 50%;
|
||||
margin-left: -(54px/2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
1590
examples/demo/site/modules/files/files/js/src/dropzone.coffee
Normal file
1590
examples/demo/site/modules/files/files/js/src/dropzone.coffee
Normal file
File diff suppressed because it is too large
Load Diff
413
examples/demo/site/modules/files/files/js/src/dropzone.scss
Normal file
413
examples/demo/site/modules/files/files/js/src/dropzone.scss
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright (c) 2012 Matias Meno <m@tias.me>
|
||||
*/
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
@mixin keyframes($name) {
|
||||
@-webkit-keyframes #{$name} {
|
||||
@content;
|
||||
}
|
||||
@-moz-keyframes #{$name} {
|
||||
@content;
|
||||
}
|
||||
@keyframes #{$name} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@mixin prefix($map, $vendors: webkit moz ms o) {
|
||||
@each $prop, $value in $map {
|
||||
@if $vendors {
|
||||
@each $vendor in $vendors {
|
||||
#{"-" + $vendor + "-" + $prop}: #{$value};
|
||||
}
|
||||
}
|
||||
// Dump regular property anyway
|
||||
#{$prop}: #{$value};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include keyframes(passing-through) {
|
||||
|
||||
0% {
|
||||
opacity: 0;
|
||||
@include prefix((transform: translateY(40px)));
|
||||
}
|
||||
|
||||
30%, 70% {
|
||||
opacity: 1;
|
||||
@include prefix((transform: translateY(0px)));
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
@include prefix((transform: translateY(-40px)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include keyframes(slide-in) {
|
||||
|
||||
0% {
|
||||
opacity: 0;
|
||||
@include prefix((transform: translateY(40px)));
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
@include prefix((transform: translateY(0px)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@include keyframes(pulse) {
|
||||
|
||||
0% { @include prefix((transform: scale(1))); }
|
||||
10% { @include prefix((transform: scale(1.1))); }
|
||||
20% { @include prefix((transform: scale(1))); }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.dropzone, .dropzone * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.dropzone {
|
||||
|
||||
$image-size: 120px;
|
||||
|
||||
$image-border-radius: 20px;
|
||||
|
||||
&.dz-clickable {
|
||||
cursor: pointer;
|
||||
|
||||
* {
|
||||
cursor: default;
|
||||
}
|
||||
.dz-message {
|
||||
&, * {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
min-height: 150px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.3);
|
||||
background: white;
|
||||
padding: 20px 20px;
|
||||
|
||||
&.dz-started {
|
||||
.dz-message {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.dz-drag-hover {
|
||||
border-style: solid;
|
||||
.dz-message {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
.dz-message {
|
||||
text-align: center;
|
||||
margin: 2em 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.dz-preview {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
vertical-align: top;
|
||||
|
||||
margin: 16px;
|
||||
min-height: 100px;
|
||||
|
||||
&:hover {
|
||||
// Making sure that always the hovered preview element is on top
|
||||
z-index: 1000;
|
||||
.dz-details {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.dz-file-preview {
|
||||
|
||||
.dz-image {
|
||||
border-radius: $image-border-radius;
|
||||
background: #999;
|
||||
background: linear-gradient(to bottom, #eee, #ddd);
|
||||
}
|
||||
|
||||
.dz-details {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.dz-image-preview {
|
||||
background: white;
|
||||
.dz-details {
|
||||
@include prefix((transition: opacity 0.2s linear));
|
||||
}
|
||||
}
|
||||
|
||||
.dz-remove {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .dz-details {
|
||||
opacity: 1;
|
||||
}
|
||||
.dz-details {
|
||||
$background-color: #444;
|
||||
|
||||
z-index: 20;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
font-size: 13px;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 2em 1em;
|
||||
text-align: center;
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
|
||||
$width: 120px;
|
||||
|
||||
line-height: 150%;
|
||||
|
||||
.dz-size {
|
||||
margin-bottom: 1em;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.dz-filename {
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
span {
|
||||
border: 1px solid rgba(200, 200, 200, 0.8);
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
&:not(:hover) {
|
||||
span {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.dz-filename, .dz-size {
|
||||
span {
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
padding: 0 0.4em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.dz-image {
|
||||
// opacity: 0.8;
|
||||
img {
|
||||
@include prefix((transform: scale(1.05, 1.05))); // Getting rid of that white bleed-in
|
||||
@include prefix((filter: blur(8px)), webkit); // Getting rid of that white bleed-in
|
||||
}
|
||||
}
|
||||
}
|
||||
.dz-image {
|
||||
border-radius: $image-border-radius;
|
||||
overflow: hidden;
|
||||
width: $image-size;
|
||||
height: $image-size;
|
||||
position: relative;
|
||||
display: block;
|
||||
z-index: 10;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.dz-success {
|
||||
.dz-success-mark {
|
||||
@include prefix((animation: passing-through 3s cubic-bezier(0.770, 0.000, 0.175, 1.000)));
|
||||
}
|
||||
}
|
||||
&.dz-error {
|
||||
.dz-error-mark {
|
||||
opacity: 1;
|
||||
@include prefix((animation: slide-in 3s cubic-bezier(0.770, 0.000, 0.175, 1.000)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.dz-success-mark, .dz-error-mark {
|
||||
|
||||
$image-height: 54px;
|
||||
$image-width: 54px;
|
||||
|
||||
pointer-events: none;
|
||||
|
||||
opacity: 0;
|
||||
z-index: 500;
|
||||
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -($image-width/2);
|
||||
margin-top: -($image-height/2);
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
width: $image-width;
|
||||
height: $image-height;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.dz-processing .dz-progress {
|
||||
opacity: 1;
|
||||
@include prefix((transition: all 0.2s linear));
|
||||
}
|
||||
&.dz-complete .dz-progress {
|
||||
opacity: 0;
|
||||
@include prefix((transition: opacity 0.4s ease-in));
|
||||
}
|
||||
|
||||
&:not(.dz-processing) {
|
||||
.dz-progress {
|
||||
@include prefix((animation: pulse 6s ease infinite));
|
||||
}
|
||||
}
|
||||
.dz-progress {
|
||||
|
||||
opacity: 1;
|
||||
z-index: 1000;
|
||||
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
|
||||
width: 80px;
|
||||
margin-left: -40px;
|
||||
|
||||
// border: 2px solid #333;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
|
||||
// Fix for chrome bug: https://code.google.com/p/chromium/issues/detail?id=157218
|
||||
-webkit-transform: scale(1);
|
||||
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
.dz-upload {
|
||||
background: #333;
|
||||
background: linear-gradient(to bottom, #666, #444);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 0;
|
||||
@include prefix((transition: width 300ms ease-in-out));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.dz-error {
|
||||
.dz-error-message {
|
||||
display: block;
|
||||
}
|
||||
&:hover .dz-error-message {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.dz-error-message {
|
||||
$width: $image-size + 20px;
|
||||
$color: rgb(190, 38, 38);
|
||||
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
display: block;
|
||||
display: none;
|
||||
opacity: 0;
|
||||
@include prefix((transition: opacity 0.3s ease));
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
top: $image-size + 10px;
|
||||
left: -10px;
|
||||
width: $width;
|
||||
background: $color;
|
||||
background: linear-gradient(to bottom, $color, darken($color, 5%));
|
||||
padding: 0.5em 1.2em;
|
||||
color: white;
|
||||
|
||||
// The triangle pointing up
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: $width / 2 - 6px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid $color;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
examples/demo/site/modules/files/files/scss/files.scss
Normal file
63
examples/demo/site/modules/files/files/scss/files.scss
Normal file
@@ -0,0 +1,63 @@
|
||||
.uploaded-files {
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid black;
|
||||
|
||||
th {
|
||||
padding: 3px 0 3px 5px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 3px 0 3px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
a.button{
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border: solid 1px #999;
|
||||
background-color: #ddd;
|
||||
padding: 2px 4px 2px 4px;
|
||||
&:hover {
|
||||
color: black;
|
||||
border: solid 1px #06f;
|
||||
background-color: #cff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-files {
|
||||
.center {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
a.button{
|
||||
margin: auto;
|
||||
width: 100px;
|
||||
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border: solid 1px #999;
|
||||
background-color: #ddd;
|
||||
padding: 2px 4px 2px 4px;
|
||||
&:hover {
|
||||
color: black;
|
||||
border: solid 1px #06f;
|
||||
background-color: #cff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************* Drop Zone *******************/
|
||||
|
||||
.dropzone {
|
||||
width: 100%;
|
||||
border: 2px dashed blue;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
@@ -3,22 +3,17 @@ ul.cms-nodes {
|
||||
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_type_page a::before {
|
||||
content: "[page] ";
|
||||
}
|
||||
|
||||
li.cms_type_blog a::before {
|
||||
content: "[blog] ";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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`)
|
||||
);
|
||||
|
||||
@@ -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`)
|
||||
);
|
||||
|
||||
@@ -1,37 +1,23 @@
|
||||
<div class="primary-tabs">
|
||||
{unless isset="$user"}
|
||||
<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">
|
||||
<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>
|
||||
{unless isset="$user"}
|
||||
<div class="login-box">
|
||||
<div class="description">The "Session" is the standard authentication system. (based on cookie)</div>
|
||||
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
|
||||
<div>
|
||||
<form name="cms_session_auth" action="{$site_url/}account/auth/roc-session-login" method="POST">
|
||||
<div>
|
||||
<p>
|
||||
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||
</p>
|
||||
<input type="text" name="username" id="username" required value="{$username/}">
|
||||
<label>Username</label>
|
||||
</div>
|
||||
</div>
|
||||
{/unless}
|
||||
{if isset=$error}
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
<strong>{$error/}
|
||||
</p>
|
||||
<input type="password" name="password" id="password" required >
|
||||
<label>Password</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||
</div>
|
||||
{if isset="$error"}<div class="error">{$error/}</div>{/if}
|
||||
</div>
|
||||
{/unless}
|
||||
|
||||
@@ -51,11 +51,21 @@ feature -- CMS modules
|
||||
a_setup.register_module (create {CMS_BASIC_AUTH_MODULE}.make)
|
||||
a_setup.register_module (create {CMS_OAUTH_20_MODULE}.make)
|
||||
a_setup.register_module (create {CMS_OPENID_MODULE}.make)
|
||||
a_setup.register_module (create {CMS_SESSION_AUTH_MODULE}.make)
|
||||
|
||||
-- Nodes
|
||||
a_setup.register_module (create {CMS_NODE_MODULE}.make (a_setup))
|
||||
a_setup.register_module (create {CMS_BLOG_MODULE}.make)
|
||||
|
||||
-- Files
|
||||
a_setup.register_module (create {CMS_FILES_MODULE}.make)
|
||||
|
||||
-- Contact
|
||||
a_setup.register_module (create {CMS_CONTACT_MODULE}.make)
|
||||
|
||||
-- Misc
|
||||
a_setup.register_module (create {CMS_SEO_MODULE}.make)
|
||||
|
||||
-- Taxonomy
|
||||
a_setup.register_module (create {CMS_TAXONOMY_MODULE}.make)
|
||||
|
||||
@@ -66,10 +76,10 @@ feature -- CMS modules
|
||||
a_setup.register_module (create {FEED_AGGREGATOR_MODULE}.make)
|
||||
|
||||
-- Miscellanious
|
||||
a_setup.register_module (create {GOOGLE_CUSTOM_SEARCH_MODULE}.make)
|
||||
a_setup.register_module (create {CMS_DEBUG_MODULE}.make)
|
||||
a_setup.register_module (create {CMS_DEMO_MODULE}.make)
|
||||
a_setup.register_module (create {GOOGLE_CUSTOM_SEARCH_MODULE}.make)
|
||||
a_setup.register_module (create {CMS_SESSION_AUTH_MODULE}.make)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -37,6 +37,80 @@ feature -- Access
|
||||
weight: INTEGER
|
||||
-- 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
|
||||
|
||||
is_less alias "<" (other: like Current): BOOLEAN
|
||||
@@ -89,6 +163,22 @@ feature -- Security
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_title (a_title: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `title' to `a_title' or `location'.
|
||||
do
|
||||
if a_title /= Void then
|
||||
title := a_title.as_string_32
|
||||
else
|
||||
title := location.as_string_32
|
||||
end
|
||||
end
|
||||
|
||||
set_location (a_loc: READABLE_STRING_8)
|
||||
-- Set `location' to `a_loc'.
|
||||
do
|
||||
location := a_loc
|
||||
end
|
||||
|
||||
set_weight (a_weight: INTEGER)
|
||||
-- Set `weight' to `a_weight'.
|
||||
do
|
||||
@@ -134,6 +224,6 @@ feature -- Status report
|
||||
end
|
||||
|
||||
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)"
|
||||
end
|
||||
|
||||
@@ -18,13 +18,82 @@ feature -- Access
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
item_by_title (a_title: READABLE_STRING_GENERAL): detachable CMS_LINK
|
||||
-- First link with title `a_title' if any.
|
||||
do
|
||||
if attached items as l_items then
|
||||
across
|
||||
l_items as ic
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
Result := ic.item
|
||||
if not a_title.is_case_insensitive_equal (Result.title) then
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
coherent_result: Result /= Void implies Result.title.is_case_insensitive_equal_general (a_title)
|
||||
end
|
||||
|
||||
item_by_location (a_loc: READABLE_STRING_8): detachable CMS_LINK
|
||||
-- First link with location `a_loc' if any.
|
||||
do
|
||||
if attached items as l_items then
|
||||
across
|
||||
l_items as ic
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
Result := ic.item
|
||||
if not a_loc.same_string (Result.location) then
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
coherent_result: Result /= Void implies Result.location.same_string (a_loc)
|
||||
end
|
||||
|
||||
new_composite_item (a_title: detachable READABLE_STRING_GENERAL; a_location: READABLE_STRING_8): CMS_LINK_COMPOSITE
|
||||
-- If exists, item with location `a_location' or title `a_title',
|
||||
-- otherwise create new local link and extend to Current.
|
||||
local
|
||||
lnk: CMS_LOCAL_LINK
|
||||
do
|
||||
if attached {CMS_LINK_COMPOSITE} item_by_location (a_location) as l_parent then
|
||||
Result := l_parent
|
||||
elseif a_title /= Void and then attached {CMS_LINK_COMPOSITE} item_by_title (a_title) as l_parent then
|
||||
Result := l_parent
|
||||
else
|
||||
create lnk.make (a_title, a_location)
|
||||
extend (lnk)
|
||||
Result := lnk
|
||||
end
|
||||
if attached {CMS_LOCAL_LINK} Result as l_local_lnk and then not l_local_lnk.is_expanded then
|
||||
l_local_lnk.set_expandable (True)
|
||||
l_local_lnk.set_collapsed (True)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
extend (lnk: CMS_LINK)
|
||||
-- Add `lnk' as a sub link.
|
||||
deferred
|
||||
end
|
||||
|
||||
extend_into (lnk: CMS_LINK; a_parent_title: detachable READABLE_STRING_GENERAL; a_parent_location: READABLE_STRING_8)
|
||||
-- Extend `lnk' into local link with location `a_parent_location'.
|
||||
-- If the parent is not found, create it with title `a_parent_title'.
|
||||
local
|
||||
l_parent: CMS_LINK_COMPOSITE
|
||||
do
|
||||
l_parent := new_composite_item (a_parent_title, a_parent_location)
|
||||
l_parent.extend (lnk)
|
||||
end
|
||||
|
||||
remove (lnk: CMS_LINK)
|
||||
-- Remove link `lnk' from Current container.
|
||||
deferred
|
||||
@@ -68,6 +137,6 @@ feature -- status report
|
||||
end
|
||||
|
||||
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)"
|
||||
end
|
||||
|
||||
@@ -79,16 +79,6 @@ feature -- Security
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_title (a_title: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `title' to `a_title' or `location'.
|
||||
do
|
||||
if a_title /= Void then
|
||||
title := a_title.as_string_32
|
||||
else
|
||||
title := location.as_string_32
|
||||
end
|
||||
end
|
||||
|
||||
add_link (lnk: CMS_LINK)
|
||||
-- <Precursor>
|
||||
local
|
||||
@@ -194,6 +184,6 @@ feature {NONE} -- Implementation
|
||||
invariant
|
||||
|
||||
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)"
|
||||
end
|
||||
|
||||
@@ -73,7 +73,7 @@ feature -- Status report
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
feature -- Element change
|
||||
|
||||
extend (lnk: CMS_LINK)
|
||||
-- <Precursor>
|
||||
@@ -104,6 +104,6 @@ feature -- Access
|
||||
invariant
|
||||
|
||||
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)"
|
||||
end
|
||||
|
||||
@@ -65,9 +65,6 @@ feature -- Access
|
||||
email: detachable READABLE_STRING_8
|
||||
-- User email.
|
||||
|
||||
profile: detachable CMS_USER_PROFILE
|
||||
-- User profile.
|
||||
|
||||
creation_date: DATE_TIME
|
||||
-- Creation date.
|
||||
|
||||
@@ -189,26 +186,6 @@ feature -- Change element
|
||||
email_set: email = a_email
|
||||
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)
|
||||
do
|
||||
last_login_date := dt
|
||||
@@ -284,7 +261,6 @@ feature -- Status change
|
||||
status_set: status = a_status
|
||||
end
|
||||
|
||||
|
||||
feature -- User status
|
||||
|
||||
not_active: INTEGER = 0
|
||||
|
||||
@@ -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
|
||||
@@ -80,7 +80,7 @@ feature -- Cursor
|
||||
|
||||
feature -- Action
|
||||
|
||||
action: FUNCTION [detachable TUPLE, G]
|
||||
action: FUNCTION [DB_TUPLE, G]
|
||||
-- Agent to create a new item of type G.
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?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">
|
||||
<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"/>
|
||||
</option>
|
||||
<setting name="console_application" value="true"/>
|
||||
@@ -26,9 +27,9 @@
|
||||
</cluster>
|
||||
<cluster name="persistence_store_mysql" location=".\src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?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">
|
||||
<description>CMS Eiffel Store ODBC persistence solution</description>
|
||||
<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"/>
|
||||
</option>
|
||||
<setting name="console_application" value="true"/>
|
||||
@@ -22,9 +23,9 @@
|
||||
<cluster name="common" location="..\implementation\store\" recursive="true"/>
|
||||
<cluster name="persistence_store_odbc" location=".\src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
|
||||
@@ -103,7 +103,7 @@ feature -- Security
|
||||
-- List of permission ids, used by this module, and declared.
|
||||
do
|
||||
Result := Precursor
|
||||
Result.force ("manage admin")
|
||||
Result.force ("access admin")
|
||||
Result.force ("admin users")
|
||||
Result.force ("admin roles")
|
||||
Result.force ("admin modules")
|
||||
@@ -132,28 +132,35 @@ feature -- Hooks
|
||||
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||
local
|
||||
lnk: CMS_LOCAL_LINK
|
||||
admin_lnk: CMS_LINK_COMPOSITE
|
||||
do
|
||||
if
|
||||
a_response.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) -- Note: admin user has all permissions enabled by default.
|
||||
then
|
||||
-- TODO: we should probably use more side menu and less primary_menu.
|
||||
create lnk.make ("Admin", "admin")
|
||||
lnk.set_permission_arguments (<<"manage " + {CMS_ADMIN_MODULE}.name>>)
|
||||
a_menu_system.management_menu.extend (lnk)
|
||||
if a_response.api.user_is_authenticated then
|
||||
admin_lnk := a_menu_system.management_menu.new_composite_item ("Admin", "admin")
|
||||
|
||||
create lnk.make ("Module", "admin/modules")
|
||||
lnk.set_permission_arguments (<<"manage module">>)
|
||||
admin_lnk.extend (lnk)
|
||||
|
||||
-- Per module cache permission!
|
||||
create lnk.make ("Cache", "admin/cache")
|
||||
admin_lnk.extend (lnk)
|
||||
|
||||
-- Per module export permission!
|
||||
create lnk.make ("Export", "admin/export")
|
||||
admin_lnk.extend (lnk)
|
||||
|
||||
-- if
|
||||
-- a_response.has_permission ("access " + {CMS_ADMIN_MODULE}.name) -- Note: admin user has all permissions enabled by default.
|
||||
-- then
|
||||
-- lnk := admin_lnk
|
||||
-- lnk.set_title ("Admin")
|
||||
|
||||
-- a_menu_system.management_menu.extend (lnk)
|
||||
-- elseif admin_lnk.has_children then
|
||||
-- a_menu_system.management_menu.extend (admin_lnk)
|
||||
-- end
|
||||
-- admin_lnk.set_permission_arguments (<<"access " + {CMS_ADMIN_MODULE}.name>>)
|
||||
end
|
||||
|
||||
create lnk.make ("Module", "admin/modules")
|
||||
lnk.set_permission_arguments (<<"manage module">>)
|
||||
a_menu_system.management_menu.extend (lnk)
|
||||
|
||||
-- Per module cache permission!
|
||||
create lnk.make ("Cache", "admin/cache")
|
||||
a_menu_system.management_menu.extend (lnk)
|
||||
|
||||
-- Per module export permission!
|
||||
create lnk.make ("Export", "admin/export")
|
||||
a_menu_system.management_menu.extend (lnk)
|
||||
end
|
||||
|
||||
note
|
||||
|
||||
@@ -17,22 +17,58 @@ feature -- Process
|
||||
process
|
||||
local
|
||||
b: STRING
|
||||
l_admin_links: ARRAYED_LIST [TUPLE [package: READABLE_STRING_8; permissions: ARRAY [READABLE_STRING_GENERAL]; link: CMS_LINK; help: READABLE_STRING_GENERAL]]
|
||||
lst: detachable ARRAYED_LIST [TUPLE [permissions: ARRAY [READABLE_STRING_GENERAL]; link: CMS_LINK; help: READABLE_STRING_GENERAL]]
|
||||
categories: STRING_TABLE [ARRAYED_LIST [TUPLE [permissions: ARRAY [READABLE_STRING_GENERAL]; link: CMS_LINK; help: READABLE_STRING_GENERAL]]]
|
||||
l_package: READABLE_STRING_8
|
||||
do
|
||||
create l_admin_links.make (5)
|
||||
l_admin_links.force (["core", <<"admin users">>, local_link ("Users", "admin/users"), "View/Edit/Add Users"])
|
||||
l_admin_links.force (["core", <<"admin roles">>, local_link ("Roles", "admin/roles"), "View/Edit/Add Roles"])
|
||||
l_admin_links.force (["core", <<"admin modules">>, local_link ("Modules", "admin/modules"), "(un)Install modules"])
|
||||
l_admin_links.force (["support", <<"admin cache">>, local_link ("Cache", "admin/cache"), "Clear caches"])
|
||||
l_admin_links.force (["support", <<"admin export">>, local_link ("Export", "admin/export"), "Export CMS contents, and modules contents."])
|
||||
create categories.make_caseless (3)
|
||||
across
|
||||
l_admin_links as ic
|
||||
loop
|
||||
l_package := ic.item.package
|
||||
lst := categories.item (l_package)
|
||||
if lst = Void then
|
||||
create lst.make (1)
|
||||
categories.force (lst, l_package)
|
||||
end
|
||||
lst.force ([ic.item.permissions, ic.item.link, ic.item.help])
|
||||
end
|
||||
|
||||
create b.make_empty
|
||||
set_title (translation ("Admin Page", Void))
|
||||
b.append ("<ul id=%"content-types%">")
|
||||
fixme ("Check how to make it configurable")
|
||||
if has_permissions (<< "admin users">>) then
|
||||
b.append ("<li>" + link ("Users", "admin/users", Void))
|
||||
b.append ("<div class=%"description%">View/Edit/Add Users</div>")
|
||||
b.append ("</li>")
|
||||
across
|
||||
categories as cats_ic
|
||||
loop
|
||||
lst := cats_ic.item
|
||||
b.append ("<h3>")
|
||||
b.append (html_encoded (cats_ic.key))
|
||||
b.append ("</h3>")
|
||||
b.append ("<ul>")
|
||||
across
|
||||
lst as ic
|
||||
loop
|
||||
if has_permissions (ic.item.permissions) then
|
||||
b.append ("<li>")
|
||||
if attached ic.item.link as lnk then
|
||||
b.append (link (lnk.title, lnk.location, Void))
|
||||
end
|
||||
b.append ("<div class=%"description%">")
|
||||
b.append (html_encoded (ic.item.help))
|
||||
b.append ("</div>")
|
||||
b.append ("</li>")
|
||||
end
|
||||
end
|
||||
b.append ("</ul>")
|
||||
end
|
||||
if has_permissions (<< "admin roles">>) then
|
||||
b.append ("<li>" + link ("Roles", "admin/roles", Void))
|
||||
b.append ("<div class=%"description%">View/Edit/Add Roles</div>")
|
||||
b.append ("</li>")
|
||||
end
|
||||
b.append ("</ul>")
|
||||
|
||||
set_main_content (b)
|
||||
end
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ feature -- Error
|
||||
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- <Precursor>
|
||||
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
|
||||
l_id.is_integer and then
|
||||
|
||||
@@ -166,7 +166,7 @@ feature -- Error
|
||||
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- <Precursor>
|
||||
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
|
||||
l_id.is_integer and then
|
||||
|
||||
@@ -86,12 +86,13 @@ feature -- Execution
|
||||
not l_roles.is_empty
|
||||
then
|
||||
s.append ("<h4>Role(s):</h4>")
|
||||
s.append ("<ul class=%"user-roles%">")
|
||||
across l_roles as ic loop
|
||||
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 ("</i>")
|
||||
debug
|
||||
s.append ("</li>")
|
||||
if request.query_parameter ("debug") /= Void then
|
||||
s.append ("<h5>Permissions:</h5>")
|
||||
s.append ("<ul class=%"cms-permissions%">%N")
|
||||
across l_role.permissions as perms_ic loop
|
||||
@@ -100,6 +101,7 @@ feature -- Execution
|
||||
s.append ("</ul>%N")
|
||||
end
|
||||
end
|
||||
s.append ("</ul>%N")
|
||||
end
|
||||
|
||||
s.append ("</div>")
|
||||
|
||||
17
modules/auth/cms_auth_api_i.e
Normal file
17
modules/auth/cms_auth_api_i.e
Normal 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
|
||||
44
modules/auth/cms_auth_filter_i.e
Normal file
44
modules/auth/cms_auth_filter_i.e
Normal 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
|
||||
91
modules/auth/cms_auth_module_i.e
Normal file
91
modules/auth/cms_auth_module_i.e
Normal file
@@ -0,0 +1,91 @@
|
||||
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
|
||||
|
||||
CMS_HOOK_BLOCK_HELPER
|
||||
|
||||
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
|
||||
|
||||
end
|
||||
@@ -112,6 +112,7 @@ feature -- Basic Operations / Contact
|
||||
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)
|
||||
l_message.replace_substring_all ("$email", a_to)
|
||||
send_message (contact_email_address, a_to, parameters.contact_subject_register, l_message)
|
||||
end
|
||||
|
||||
@@ -126,6 +127,7 @@ feature -- Basic Operations / Contact
|
||||
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)
|
||||
l_message.replace_substring_all ("$email", a_to)
|
||||
send_message (contact_email_address, a_to, parameters.contact_subject_activate, l_message)
|
||||
end
|
||||
|
||||
@@ -137,7 +139,7 @@ feature -- Basic Operations / Contact
|
||||
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 ("$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)
|
||||
l_message.replace_substring_all ("$email", a_to)
|
||||
|
||||
@@ -130,13 +130,13 @@ feature -- Access
|
||||
account_re_activation: STRING
|
||||
-- Account re_activation template email message.
|
||||
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
|
||||
|
||||
account_rejected: STRING
|
||||
-- Account rejected template email message.
|
||||
do
|
||||
Result := template_string ("accunt_rejected.html", default_template_account_rejected)
|
||||
Result := template_string ("account_rejected.html", default_template_account_rejected)
|
||||
end
|
||||
|
||||
account_password: STRING
|
||||
@@ -277,7 +277,7 @@ feature {NONE} -- Message email
|
||||
</head>
|
||||
|
||||
<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>
|
||||
</html>
|
||||
]"
|
||||
@@ -316,7 +316,7 @@ feature {NONE} -- Message email
|
||||
</head>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -337,7 +337,7 @@ feature {NONE} -- Message email
|
||||
</head>
|
||||
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
note
|
||||
description: "Module Auth"
|
||||
date: "$Date: 2015-05-20 06:50:50 -0300 (mi. 20 de may. de 2015) $"
|
||||
revision: "$Revision: 97328 $"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_AUTHENTICATION_MODULE
|
||||
|
||||
inherit
|
||||
|
||||
CMS_MODULE
|
||||
redefine
|
||||
setup_hooks,
|
||||
@@ -22,6 +21,8 @@ inherit
|
||||
|
||||
CMS_HOOK_BLOCK
|
||||
|
||||
CMS_HOOK_BLOCK_HELPER
|
||||
|
||||
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
@@ -33,8 +34,6 @@ inherit
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
CMS_REQUEST_UTIL
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -82,6 +81,10 @@ feature -- Access: docs
|
||||
|
||||
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)
|
||||
-- <Precursor>
|
||||
do
|
||||
@@ -93,19 +96,22 @@ feature -- Router
|
||||
local
|
||||
m: WSF_URI_MAPPING
|
||||
do
|
||||
create m.make_trailing_slash_ignored ("/account", create {WSF_URI_AGENT_HANDLER}.make (agent handle_account(a_api, ?, ?)))
|
||||
create m.make_trailing_slash_ignored ("/account", create {WSF_URI_AGENT_HANDLER}.make (agent handle_account (a_api, ?, ?)))
|
||||
a_router.map (m, a_router.methods_head_get)
|
||||
|
||||
a_router.handle ("/account/roc-login", create {WSF_URI_AGENT_HANDLER}.make (agent handle_login(a_api, ?, ?)), 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/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/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/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/post-change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_post_change_password(a_api, ?, ?)), a_router.methods_get)
|
||||
a_router.handle ("/account/change/{field}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_change_field (a_api, ?, ?)), a_router.methods_get_post)
|
||||
end
|
||||
|
||||
|
||||
@@ -128,8 +134,35 @@ feature -- Hooks configuration
|
||||
|
||||
value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE)
|
||||
-- <Precursor>
|
||||
local
|
||||
l_destination: detachable READABLE_STRING_GENERAL
|
||||
l_url: STRING
|
||||
l_url_name: READABLE_STRING_GENERAL
|
||||
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
|
||||
|
||||
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||
@@ -142,18 +175,26 @@ feature -- Hooks configuration
|
||||
create lnk.make (u.name, "account")
|
||||
lnk.set_weight (97)
|
||||
a_menu_system.primary_menu.extend (lnk)
|
||||
create lnk.make ("Logout", "account/roc-logout")
|
||||
lnk.set_weight (98)
|
||||
a_menu_system.primary_menu.extend (lnk)
|
||||
|
||||
create lnk.make ("Logout", roc_logout_location)
|
||||
else
|
||||
create lnk.make ("Login", "account/roc-login")
|
||||
lnk.set_weight (98)
|
||||
a_menu_system.primary_menu.extend (lnk)
|
||||
create lnk.make ("Login", roc_login_location)
|
||||
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
|
||||
if a_response.has_permission ("admin registration") then
|
||||
create lnk.make ("Registration", "admin/pending-registrations/")
|
||||
a_menu_system.management_menu.extend (lnk)
|
||||
a_menu_system.management_menu.extend_into (lnk, "Admin", "admin")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -162,18 +203,78 @@ feature -- Handler
|
||||
handle_account (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
l_user: detachable CMS_USER
|
||||
b: STRING
|
||||
lnk: CMS_LOCAL_LINK
|
||||
do
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
if attached template_block ("account_info", r) as l_tpl_block then
|
||||
if attached r.user as l_user then
|
||||
r.set_value (api.user_api.user_roles (l_user), "roles")
|
||||
end
|
||||
create b.make_empty
|
||||
l_user := r.user
|
||||
if attached template_block (Current, "account_info", api) 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
|
||||
|
||||
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 (Current, "account_edit", api) 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
|
||||
end
|
||||
|
||||
@@ -181,10 +282,30 @@ feature -- Handler
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
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.
|
||||
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
|
||||
else
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
@@ -195,9 +316,19 @@ feature -- Handler
|
||||
handle_logout (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
loc: STRING
|
||||
do
|
||||
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
|
||||
end
|
||||
|
||||
@@ -232,7 +363,7 @@ feature -- Handler
|
||||
l_exist := True
|
||||
end
|
||||
if attached l_user_api.user_by_email (l_email) or else attached l_user_api.temp_user_by_email (l_email) then
|
||||
-- Emails already exist.
|
||||
-- Email already exists.
|
||||
r.set_value ("An account is already associated with that email address!", "error_email")
|
||||
l_exist := True
|
||||
end
|
||||
@@ -524,45 +655,91 @@ feature -- Handler
|
||||
r.execute
|
||||
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
|
||||
r: CMS_RESPONSE
|
||||
l_user_api: CMS_USER_API
|
||||
f: CMS_FORM
|
||||
l_fieldname: detachable READABLE_STRING_8
|
||||
b: STRING
|
||||
lnk: CMS_LOCAL_LINK
|
||||
do
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
l_user_api := api.user_api
|
||||
if req.is_post_request_method then
|
||||
if attached r.user as l_user then
|
||||
r.set_value (api.user_api.user_roles (l_user), "roles")
|
||||
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
|
||||
-- Does the passwords match?
|
||||
l_user.set_password (l_password.value)
|
||||
l_user_api.update_user (l_user)
|
||||
r.set_redirection (req.absolute_script_url ("/account/post-change-password"))
|
||||
else
|
||||
if attached template_block ("account_info", r) as l_tpl_block then
|
||||
-- r.set_value (l_user, "user")
|
||||
r.set_value ("Passwords Don't Match", "error_password")
|
||||
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
|
||||
r.add_block (l_tpl_block, "content")
|
||||
if attached {WSF_STRING} req.path_parameter ("field") as p_field then
|
||||
l_fieldname := p_field.url_encoded_value
|
||||
end
|
||||
if l_fieldname = Void then
|
||||
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
else
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
r.execute
|
||||
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)
|
||||
local
|
||||
l_response: CMS_RESPONSE
|
||||
@@ -655,37 +832,73 @@ feature -- Handler
|
||||
end
|
||||
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
local
|
||||
l_string: STRING
|
||||
do
|
||||
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
|
||||
Result := <<"register", "reactivate", "new_password", "reset_password">>
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
local
|
||||
loc: READABLE_STRING_8
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
elseif a_block_id.is_case_insensitive_equal_general ("registration") and then a_response.location.starts_with ("admin/pending-registrations") then
|
||||
get_block_view_registration (a_block_id, a_response)
|
||||
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
|
||||
|
||||
new_token: STRING
|
||||
@@ -710,32 +923,24 @@ feature {NONE} -- Token Generation
|
||||
Result := l_token
|
||||
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
|
||||
|
||||
get_block_view_register (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
if a_response.has_permission ("account register") then
|
||||
if a_response.request.is_get_request_method then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if
|
||||
a_response.request.is_get_request_method
|
||||
or else (
|
||||
a_response.values.has ("error_name")
|
||||
or else a_response.values.has ("error_email")
|
||||
)
|
||||
then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_name"), "error_name")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("name"), "name")
|
||||
l_tpl_block.set_value (form_registration_application_description (a_response.api), "application_description")
|
||||
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
|
||||
@@ -746,28 +951,11 @@ feature {NONE} -- Block views
|
||||
end
|
||||
end
|
||||
elseif a_response.request.is_post_request_method then
|
||||
if a_response.values.has ("error_name") or else a_response.values.has ("error_email") then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_name"), "error_name")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("name"), "name")
|
||||
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")
|
||||
else
|
||||
debug ("cms")
|
||||
a_response.add_warning_message ("Error with block [" + a_block_id + "]")
|
||||
end
|
||||
end
|
||||
if attached template_block (Current, "post_register", a_response.api) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
if attached template_block ("post_register", a_response) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
a_response.add_warning_message ("Error with block [" + a_block_id + "]")
|
||||
end
|
||||
debug ("cms")
|
||||
a_response.add_warning_message ("Error with block [" + a_block_id + "]")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -777,7 +965,7 @@ feature {NONE} -- Block views
|
||||
get_block_view_reactivate (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
if a_response.request.is_get_request_method then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
@@ -786,7 +974,7 @@ feature {NONE} -- Block views
|
||||
end
|
||||
elseif a_response.request.is_post_request_method then
|
||||
if a_response.values.has ("error_email") or else a_response.values.has ("is_active") then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("is_active"), "is_active")
|
||||
@@ -797,7 +985,7 @@ feature {NONE} -- Block views
|
||||
end
|
||||
end
|
||||
else
|
||||
if attached template_block ("post_reactivate", a_response) as l_tpl_block then
|
||||
if attached template_block (Current, "post_reactivate", a_response.api) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
@@ -811,7 +999,7 @@ feature {NONE} -- Block views
|
||||
get_block_view_new_password (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
if a_response.request.is_get_request_method then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
@@ -820,7 +1008,7 @@ feature {NONE} -- Block views
|
||||
end
|
||||
elseif a_response.request.is_post_request_method then
|
||||
if a_response.values.has ("error_email") or else a_response.values.has ("error_username") then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_username"), "error_username")
|
||||
@@ -832,7 +1020,7 @@ feature {NONE} -- Block views
|
||||
end
|
||||
end
|
||||
else
|
||||
if attached template_block ("post_password", a_response) as l_tpl_block then
|
||||
if attached template_block (Current, "post_password", a_response.api) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
@@ -846,7 +1034,7 @@ feature {NONE} -- Block views
|
||||
get_block_view_reset_password (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
if a_response.request.is_get_request_method then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
-- l_tpl_block.set_value (a_response.values.item ("token"), "token")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_token"), "error_token")
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
@@ -857,7 +1045,7 @@ feature {NONE} -- Block views
|
||||
end
|
||||
elseif a_response.request.is_post_request_method then
|
||||
if a_response.values.has ("error_token") or else a_response.values.has ("error_password") then
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_token"), "error_token")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("error_password"), "error_password")
|
||||
-- l_tpl_block.set_value (a_response.values.item ("token"), "token")
|
||||
@@ -868,7 +1056,7 @@ feature {NONE} -- Block views
|
||||
end
|
||||
end
|
||||
else
|
||||
if attached template_block ("post_reset", a_response) as l_tpl_block then
|
||||
if attached template_block (Current, "post_reset", a_response.api) as l_tpl_block then
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
@@ -879,11 +1067,19 @@ feature {NONE} -- Block views
|
||||
end
|
||||
end
|
||||
|
||||
get_block_view_registration (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
end
|
||||
feature -- Access: configuration
|
||||
|
||||
feature -- Recaptcha
|
||||
form_registration_application_description (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 ("forms.registration.application_description") as l_desc and then not l_desc.is_whitespace then
|
||||
Result := utf.utf_32_string_to_utf_8_string_8 (l_desc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
recaptcha_secret_key (api: CMS_API): detachable READABLE_STRING_8
|
||||
-- Get recaptcha security key.
|
||||
@@ -916,6 +1112,7 @@ feature -- Response Alter
|
||||
a_response.add_javascript_url ("https://www.google.com/recaptcha/api.js")
|
||||
a_response.add_style (a_response.url ("/module/" + name + "/files/css/auth.css", Void), Void)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
is_captcha_verified (a_secret, a_response: READABLE_STRING_8): BOOLEAN
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"email": "webmaster@example.com",
|
||||
"subjet_register": "Thank you for regitering with us, activate account",
|
||||
"subjet_activate": "New account ativation token",
|
||||
"subjet_password": "Password Recovery!!!",
|
||||
"subjet_oauth": "Welcome",
|
||||
"smtp": "127.0.0.1"
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"subject": "Thank you for contacting us",
|
||||
"forms": {
|
||||
"registration": {
|
||||
"application_description": "Present yourself in a few lines, otherwise your application is likely to be rejected."
|
||||
}
|
||||
},
|
||||
"recaptcha": {
|
||||
"site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD",
|
||||
"secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx"
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
|
||||
<p>To reject the registration, please click on the following link <p>
|
||||
|
||||
<p><a href="$rejection_url<">$rejection_url</a></p>
|
||||
<p><a href="$rejection_url">$rejection_url</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1
modules/auth/site/templates/block_account_edit.tpl
Normal file
1
modules/auth/site/templates/block_account_edit.tpl
Normal file
@@ -0,0 +1 @@
|
||||
{include file="block_account_info.tpl" /}
|
||||
@@ -1,62 +1,34 @@
|
||||
<div class="primary-tabs">
|
||||
{if isset="$user"}
|
||||
<h3>Account Information</h3>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<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>
|
||||
<ul class="user-information">
|
||||
<div>
|
||||
<label>Username:</label> {$user.name/}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{include file="block_change_password.tpl" /}
|
||||
<hr>
|
||||
<h4>Roles</h4>
|
||||
<div>
|
||||
{foreach item="ic" from="$roles"}
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>{$ic.name/}</strong>
|
||||
<ul>
|
||||
<li> <i>permissions</i>
|
||||
<ul>
|
||||
{foreach item="ip" from="$ic.permissions"}
|
||||
<li>{$ip/}</li>
|
||||
{/foreach}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label>Email:</label> {$user.email/}
|
||||
</div>
|
||||
<div>
|
||||
<label>Creation Date:</label> {$user.creation_date/} (UTC)
|
||||
</div>
|
||||
<div>
|
||||
<label>Last login:</label> {$user.last_login_date/} (UTC)
|
||||
</div>
|
||||
<div>
|
||||
<form method="get" action="{$site_url/}account/roc-logout">
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
</div>
|
||||
</ul>
|
||||
<hr>
|
||||
<h4>Profile</h4>
|
||||
<div>
|
||||
<ul class="user-profile">
|
||||
{foreach item="the_value" key="the_name" from="$user.profile"}
|
||||
<div>
|
||||
<label>{$the_name/}:</label> {$the_value/}
|
||||
</div>
|
||||
<li>
|
||||
<label>{$the_name/}:</label><div>{$the_value/}</div>
|
||||
</li>
|
||||
{/foreach}
|
||||
</div>
|
||||
</ul>
|
||||
{/if}
|
||||
{unless isset="$user"}
|
||||
<div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div>
|
||||
<form action="{$site_url/}account/change-password" method="post">
|
||||
<fieldset>
|
||||
<legend>Change Password Form</legend>
|
||||
<legend>Change Password</legend>
|
||||
<div>
|
||||
<input type="password" id="password" name="password" value="" required/>
|
||||
<label for="password">Password</label>
|
||||
|
||||
@@ -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>
|
||||
@@ -1,39 +1,38 @@
|
||||
<div>
|
||||
<form action="{$site_url/}account/roc-register" method="post">
|
||||
<fieldset>
|
||||
<legend>Registration</legend>
|
||||
<div>
|
||||
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
|
||||
<label for="name">Name</label>
|
||||
{if isset="$error_name"}
|
||||
<span><i>{$error_name/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" id="password" name="password" value="" required/>
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||
<label for="email">Email</label>
|
||||
{if isset="$error_email"}
|
||||
<span><i>{$error_email/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<textarea rows="4" cols="50" name="personal_information" id="personal_information" required>
|
||||
{$personal_information/}
|
||||
</textarea>
|
||||
<label for="personal_information">Tell us why you want to register an account</label>
|
||||
{if isset="$error_application"}
|
||||
<span><i>{$error_application/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
{unless isempty="$recaptcha_site_key"}
|
||||
<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div>
|
||||
<br/>
|
||||
{/unless}
|
||||
<button type="submit">Register</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div>
|
||||
<form action="{$site_url/}account/roc-register" method="post">
|
||||
<fieldset>
|
||||
<legend>Registration</legend>
|
||||
<div>
|
||||
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
|
||||
<label for="name">Name</label>
|
||||
{if isset="$error_name"}
|
||||
<span><i>{$error_name/}</i></span> <br>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" id="password" name="password" value="" required/>
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||
<label for="email">Email</label>
|
||||
{if isset="$error_email"}
|
||||
<span><i>{$error_email/}</i></span> <br/>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<textarea rows="4" cols="50" name="personal_information" id="personal_information" required>{$personal_information/}</textarea>
|
||||
<label for="personal_information">Tell us why you want to register an account</label>
|
||||
{if isset="$error_application"}
|
||||
<span><i>{$error_application/}</i></span><br/>
|
||||
{/if}
|
||||
{if isset="$application_description"}
|
||||
<br/>
|
||||
<p class="description">{$application_description/}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{unless isempty="$recaptcha_site_key"}<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div><br/>{/unless}
|
||||
<button type="submit">Register</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -10,24 +10,17 @@ class
|
||||
CMS_BASIC_AUTH_MODULE
|
||||
|
||||
inherit
|
||||
CMS_MODULE
|
||||
CMS_AUTH_MODULE_I
|
||||
rename
|
||||
module_api as basic_auth_api
|
||||
redefine
|
||||
make,
|
||||
filters,
|
||||
setup_hooks
|
||||
end
|
||||
|
||||
CMS_HOOK_AUTO_REGISTER
|
||||
|
||||
CMS_HOOK_BLOCK
|
||||
|
||||
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||
|
||||
CMS_HOOK_VALUE_TABLE_ALTER
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
CMS_REQUEST_UTIL
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -35,26 +28,42 @@ feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
Precursor
|
||||
version := "1.0"
|
||||
description := "Service to manage basic authentication"
|
||||
package := "authentication"
|
||||
add_dependency ({CMS_AUTHENTICATION_MODULE})
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
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>
|
||||
do
|
||||
configure_api_login (a_api, a_router)
|
||||
configure_api_logoff (a_api, a_router)
|
||||
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)
|
||||
if
|
||||
a_response.is_authenticated and then
|
||||
a_response.request.http_authorization /= Void
|
||||
then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
feature {CMS_API} -- Access: API
|
||||
|
||||
oauth20_api: detachable CMS_AUTH_API_I
|
||||
-- <Precursor>
|
||||
|
||||
feature -- Access: 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))
|
||||
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
|
||||
|
||||
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_methods
|
||||
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
|
||||
|
||||
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_methods
|
||||
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
|
||||
|
||||
|
||||
handle_login_basic_auth (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
vals: CMS_VALUE_TABLE
|
||||
do
|
||||
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 (Current, "login", api) 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
|
||||
end
|
||||
|
||||
@@ -104,113 +145,35 @@ feature -- Hooks configuration
|
||||
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
|
||||
-- Module hooks configuration.
|
||||
do
|
||||
auto_subscribe_to_hooks (a_hooks)
|
||||
Precursor (a_hooks)
|
||||
a_hooks.subscribe_to_block_hook (Current)
|
||||
a_hooks.subscribe_to_value_table_alter_hook (Current)
|
||||
end
|
||||
|
||||
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]
|
||||
local
|
||||
l_string: STRING
|
||||
do
|
||||
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
|
||||
Result := <<"?login">>
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
if
|
||||
a_block_id.is_case_insensitive_equal_general ("login") and then
|
||||
a_response.location.starts_with ("account/roc-basic-auth")
|
||||
then
|
||||
if a_block_id.is_case_insensitive_equal_general ("login") then
|
||||
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)
|
||||
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
|
||||
|
||||
get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
local
|
||||
vals: CMS_VALUE_TABLE
|
||||
do
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
if attached template_block (Current, a_block_id, a_response.api) as l_tpl_block then
|
||||
create vals.make (1)
|
||||
-- add the variable to the block
|
||||
value_table_alter (vals, a_response)
|
||||
a_response.api.hooks.invoke_value_table_alter (vals, a_response)
|
||||
across
|
||||
vals as ic
|
||||
loop
|
||||
|
||||
@@ -9,54 +9,46 @@ class
|
||||
CMS_BASIC_AUTH_FILTER
|
||||
|
||||
inherit
|
||||
WSF_URI_TEMPLATE_HANDLER
|
||||
CMS_HANDLER
|
||||
WSF_FILTER
|
||||
CMS_AUTH_FILTER_I
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
auth_strategy: STRING
|
||||
do
|
||||
Result := {CMS_BASIC_AUTH_MODULE}.logout_location
|
||||
end
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the filter.
|
||||
local
|
||||
l_auth: HTTP_AUTHORIZATION
|
||||
do
|
||||
api.logger.put_debug (generator + ".execute ", Void)
|
||||
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
|
||||
(attached l_auth.type as l_auth_type and then l_auth_type.is_case_insensitive_equal_general ("basic")) and then
|
||||
attached l_auth.login as l_auth_login and then attached l_auth.password as l_auth_password
|
||||
l_auth.is_basic and then
|
||||
attached l_auth.login as l_auth_login and then
|
||||
attached l_auth.password as l_auth_password
|
||||
then
|
||||
if api.user_api.is_valid_credential (l_auth_login, l_auth_password) then
|
||||
if attached api.user_api.user_by_name (l_auth_login) as l_user then
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT")
|
||||
-- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user))
|
||||
-- other authentication filters (OpenID, etc) should implement the same approach.
|
||||
end
|
||||
set_current_user (req, l_user)
|
||||
execute_next (req, res)
|
||||
else
|
||||
debug ("refactor_fixme")
|
||||
to_implement ("Internal server error")
|
||||
end
|
||||
if
|
||||
api.user_api.is_valid_credential (l_auth_login, l_auth_password) and then
|
||||
attached api.user_api.user_by_name (l_auth_login) as l_user
|
||||
then
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT")
|
||||
-- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user))
|
||||
-- other authentication filters (OpenID, etc) should implement the same approach.
|
||||
end
|
||||
set_current_user (l_user)
|
||||
else
|
||||
api.logger.put_error (generator + ".execute login_valid failed for: " + l_auth_login, Void)
|
||||
execute_next (req, res)
|
||||
end
|
||||
else
|
||||
api.logger.put_debug (generator + ".execute without authentication", Void)
|
||||
execute_next (req, res)
|
||||
end
|
||||
execute_next (req, res)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -49,9 +49,9 @@ feature -- HTTP Methods
|
||||
-- <Precursor>
|
||||
do
|
||||
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
|
||||
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
|
||||
redirect_to (req.absolute_script_url ("/"), res)
|
||||
end
|
||||
|
||||
@@ -51,11 +51,11 @@ feature -- HTTP Methods
|
||||
do
|
||||
api.logger.put_information (generator + ".do_get Processing basic auth logoff", Void)
|
||||
if attached req.query_parameter ("prompt") as l_prompt then
|
||||
unset_current_user (req)
|
||||
api.unset_current_user (req)
|
||||
send_access_denied_message (res)
|
||||
else
|
||||
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_url := req.absolute_script_url ("")
|
||||
i := l_url.substring_index ("://", 1)
|
||||
|
||||
@@ -1,307 +1,291 @@
|
||||
var ROC_AUTH = ROC_AUTH || { };
|
||||
|
||||
var loginURL = "/basic_auth_login";
|
||||
var logoutURL = "/basic_auth_logoff";
|
||||
var loginURL = "/roc-basic-login";
|
||||
var logoutURL = "/roc-basic-logoff";
|
||||
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
var firstLogIn = true;
|
||||
|
||||
ROC_AUTH.login = function() {
|
||||
var form = document.forms['cms_basic_auth'];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
//var host = form.host.value;
|
||||
var form = document.forms['cms_basic_auth'];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
//var host = form.host.value;
|
||||
var origin = window.location.origin + window.location.pathname;
|
||||
var _login = function(){
|
||||
var _login = function(){
|
||||
if (document.getElementById('myModalFormId') !== null ) {
|
||||
ROC_AUTH.remove ('myModalFormId');
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}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 === "") {
|
||||
if (document.getElementById('myModalFormId') === null ) {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$(".primary-tabs").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';
|
||||
$(".primary-tabs").append(newdiv);
|
||||
}
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
if (userAgent.indexOf("firefox") != -1) { //TODO: check version number
|
||||
if (firstLogIn) {
|
||||
_login();
|
||||
} else {
|
||||
ROC_AUTH.logoff(_login);
|
||||
}
|
||||
} else {
|
||||
_login();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (firstLogIn) {
|
||||
firstLogIn = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.login_with_redirect = function() {
|
||||
var form = document.forms[2];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
var host = form.host.value;
|
||||
var _login = function(){
|
||||
var form = document.forms[2];
|
||||
var username = form.username.value;
|
||||
var password = form.password.value;
|
||||
var host = form.host.value;
|
||||
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();
|
||||
|
||||
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';
|
||||
$(".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;
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||
if (firstLogIn) {
|
||||
_login();
|
||||
} else {
|
||||
ROC_AUTH.logoff(_login);
|
||||
}
|
||||
} else{
|
||||
_login();
|
||||
}
|
||||
if (firstLogIn) {
|
||||
firstLogIn = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.getQueryParameterByName = function (name) {
|
||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||||
results = regex.exec(location.search);
|
||||
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search);
|
||||
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
ROC_AUTH.logoff = function(callback){
|
||||
var form = document.forms[0];
|
||||
var host = form.host.value;
|
||||
|
||||
if (userAgent.indexOf("msie") != -1) {
|
||||
document.execCommand("ClearAuthenticationCache");
|
||||
}
|
||||
else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||
|
||||
var request1 = new XMLHttpRequest();
|
||||
var request2 = new XMLHttpRequest();
|
||||
|
||||
//Logout. Tell the server not to return the "WWW-Authenticate" header
|
||||
request1.open("GET", host.concat(logoutURL) + "?prompt=false", true);
|
||||
request1.send("");
|
||||
request1.onreadystatechange = function(){
|
||||
if (request1.readyState == 4) {
|
||||
|
||||
//Sign in with dummy credentials to clear the auth cache
|
||||
request2.open("GET", host.concat(logoutURL), true, "logout", "logout");
|
||||
request2.send("");
|
||||
|
||||
request2.onreadystatechange = function(){
|
||||
if (request2.readyState == 4) {
|
||||
if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||
request.open("GET", host.concat(logoutURL), true, "logout", "logout");
|
||||
request.send("");
|
||||
request.onreadystatechange = function(){
|
||||
if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
var form = document.forms[0];
|
||||
var host = form.host.value;
|
||||
|
||||
if (userAgent.indexOf("msie") != -1) {
|
||||
document.execCommand("ClearAuthenticationCache");
|
||||
} else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||
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);
|
||||
request1.send("");
|
||||
request1.onreadystatechange = function(){
|
||||
if (request1.readyState == 4) {
|
||||
//Sign in with dummy credentials to clear the auth cache
|
||||
request2.open("GET", host + logoutURL, true, "logout", "logout");
|
||||
request2.send("");
|
||||
request2.onreadystatechange = function(){
|
||||
if (request2.readyState == 4) {
|
||||
if (callback!=null) {
|
||||
callback.call();
|
||||
} else {
|
||||
window.location=host + logoutURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||
request.open("GET", host + logoutURL, true, "logout", "logout");
|
||||
request.send("");
|
||||
request.onreadystatechange = function(){
|
||||
if (request.status==401 || request.status==403 ) {
|
||||
window.location=host + logoutURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.remove = function (id)
|
||||
{
|
||||
var element = document.getElementById(id);
|
||||
element.outerHTML = "";
|
||||
delete element;
|
||||
return;
|
||||
ROC_AUTH.remove = function (id) {
|
||||
var element = document.getElementById(id);
|
||||
element.outerHTML = "";
|
||||
delete element;
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
if (typeof String.prototype.contains != 'function') {
|
||||
String.prototype.contains = function (str){
|
||||
return this.indexOf(str) != -1;
|
||||
};
|
||||
}
|
||||
ROC_AUTH.progressive_loging();
|
||||
|
||||
if (typeof String.prototype.contains != 'function') {
|
||||
String.prototype.contains = function (str){
|
||||
return this.indexOf(str) != -1;
|
||||
};
|
||||
}
|
||||
ROC_AUTH.progressive_loging();
|
||||
});
|
||||
|
||||
|
||||
ROC_AUTH.progressive_loging = function () {
|
||||
|
||||
ROC_AUTH.login_href();
|
||||
ROC_AUTH.login_href();
|
||||
};
|
||||
|
||||
|
||||
$(document).keypress(function(e) {
|
||||
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
|
||||
ROC_AUTH.login();
|
||||
}
|
||||
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
|
||||
ROC_AUTH.login();
|
||||
}
|
||||
});
|
||||
|
||||
ROC_AUTH.OnOneClick = function(event) {
|
||||
event.preventDefault();
|
||||
if ( document.forms[0] === undefined ) {
|
||||
ROC_AUTH.create_form();
|
||||
}
|
||||
return false;
|
||||
event.preventDefault();
|
||||
if ( document.forms[0] === undefined ) {
|
||||
ROC_AUTH.create_form();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
ROC_AUTH.login_href = function() {
|
||||
var els = document.getElementsByTagName("a");
|
||||
for (var i = 0, l = els.length; i < l; i++) {
|
||||
var el = els[i];
|
||||
if (el.href.contains("/basic_auth_login?destination")) {
|
||||
loginURL = el.href;
|
||||
var OneClick = el;
|
||||
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
|
||||
}
|
||||
}
|
||||
var els = document.getElementsByTagName("a");
|
||||
for (var i = 0, l = els.length; i < l; i++) {
|
||||
var el = els[i];
|
||||
if (el.href.contains(loginURL + "?destination")) {
|
||||
// loginURL = el.href;
|
||||
var OneClick = el;
|
||||
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ROC_AUTH.create_form = function() {
|
||||
|
||||
// Fetching HTML Elements in Variables by ID.
|
||||
var createform = document.createElement('form'); // Create New Element Form
|
||||
createform.setAttribute("action", ""); // Setting Action Attribute on Form
|
||||
createform.setAttribute("method", "post"); // Setting Method Attribute on Form
|
||||
$("body").append(createform);
|
||||
// Fetching HTML Elements in Variables by ID.
|
||||
var createform = document.createElement('form'); // Create New Element Form
|
||||
createform.setAttribute("action", ""); // Setting Action Attribute on Form
|
||||
createform.setAttribute("method", "post"); // Setting Method Attribute on Form
|
||||
$("body").append(createform);
|
||||
|
||||
var heading = document.createElement('h2'); // Heading of Form
|
||||
heading.innerHTML = "Login Form ";
|
||||
createform.appendChild(heading);
|
||||
var heading = document.createElement('h2'); // Heading of Form
|
||||
heading.innerHTML = "Login Form ";
|
||||
createform.appendChild(heading);
|
||||
|
||||
var line = document.createElement('hr'); // Giving Horizontal Row After Heading
|
||||
createform.appendChild(line);
|
||||
var line = document.createElement('hr'); // Giving Horizontal Row After Heading
|
||||
createform.appendChild(line);
|
||||
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
|
||||
var namelabel = document.createElement('label'); // Create Label for Name Field
|
||||
namelabel.innerHTML = "Username : "; // Set Field Labels
|
||||
createform.appendChild(namelabel);
|
||||
var namelabel = document.createElement('label'); // Create Label for Name Field
|
||||
namelabel.innerHTML = "Username : "; // Set Field Labels
|
||||
createform.appendChild(namelabel);
|
||||
|
||||
var inputelement = document.createElement('input'); // Create Input Field for UserName
|
||||
inputelement.setAttribute("type", "text");
|
||||
inputelement.setAttribute("name", "username");
|
||||
inputelement.setAttribute("required","required");
|
||||
createform.appendChild(inputelement);
|
||||
var inputelement = document.createElement('input'); // Create Input Field for UserName
|
||||
inputelement.setAttribute("type", "text");
|
||||
inputelement.setAttribute("name", "username");
|
||||
inputelement.setAttribute("required","required");
|
||||
createform.appendChild(inputelement);
|
||||
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
var linebreak = document.createElement('br');
|
||||
createform.appendChild(linebreak);
|
||||
|
||||
var passwordlabel = document.createElement('label'); // Create Label for Password Field
|
||||
passwordlabel.innerHTML = "Password : ";
|
||||
createform.appendChild(passwordlabel);
|
||||
var passwordlabel = document.createElement('label'); // Create Label for Password Field
|
||||
passwordlabel.innerHTML = "Password : ";
|
||||
createform.appendChild(passwordlabel);
|
||||
|
||||
var passwordelement = document.createElement('input'); // Create Input Field for Password.
|
||||
passwordelement.setAttribute("type", "password");
|
||||
passwordelement.setAttribute("name", "password");
|
||||
passwordelement.setAttribute("id", "password");
|
||||
passwordelement.setAttribute("required","required");
|
||||
createform.appendChild(passwordelement);
|
||||
var passwordelement = document.createElement('input'); // Create Input Field for Password.
|
||||
passwordelement.setAttribute("type", "password");
|
||||
passwordelement.setAttribute("name", "password");
|
||||
passwordelement.setAttribute("id", "password");
|
||||
passwordelement.setAttribute("required","required");
|
||||
createform.appendChild(passwordelement);
|
||||
|
||||
|
||||
var passwordbreak = document.createElement('br');
|
||||
createform.appendChild(passwordbreak);
|
||||
var passwordbreak = document.createElement('br');
|
||||
createform.appendChild(passwordbreak);
|
||||
|
||||
|
||||
var submitelement = document.createElement('button'); // Append Submit Button
|
||||
submitelement.setAttribute("type", "button");
|
||||
submitelement.setAttribute("onclick", "ROC_AUTH.login();");
|
||||
submitelement.innerHTML = "Sign In ";
|
||||
createform.appendChild(submitelement);
|
||||
var submitelement = document.createElement('button'); // Append Submit Button
|
||||
submitelement.setAttribute("type", "button");
|
||||
submitelement.setAttribute("onclick", "ROC_AUTH.login();");
|
||||
submitelement.innerHTML = "Sign In ";
|
||||
createform.appendChild(submitelement);
|
||||
|
||||
};
|
||||
|
||||
@@ -310,16 +294,16 @@ var password = document.getElementById("password");
|
||||
var confirm_password = document.getElementById("confirm_password");
|
||||
|
||||
ROC_AUTH.validatePassword =function(){
|
||||
if ((password != null) && (confirm_password != null)) {
|
||||
if(password.value != confirm_password.value) {
|
||||
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||
} else {
|
||||
confirm_password.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
if ((password != null) && (confirm_password != null)) {
|
||||
if(password.value != confirm_password.value) {
|
||||
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||
} else {
|
||||
confirm_password.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((password != null) && (confirm_password != null)) {
|
||||
password.onchange = ROC_AUTH.validatePassword();
|
||||
confirm_password.onkeyup = ROC_AUTH.validatePassword;
|
||||
password.onchange = ROC_AUTH.validatePassword();
|
||||
confirm_password.onkeyup = ROC_AUTH.validatePassword;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
<div class="primary-tabs">
|
||||
{unless isset="$user"}
|
||||
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
|
||||
{unless isset="$user"}
|
||||
<div class="login-box">
|
||||
<div class="description">The "Basic Auth" relies on the HTTP basic access 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>
|
||||
<form name="cms_basic_auth" action method="POST">
|
||||
<div>
|
||||
<input type="text" name="username" id="username" required>
|
||||
<label>Username</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label>Password</label>
|
||||
</div>
|
||||
|
||||
<button type="button" onclick="ROC_AUTH.login();">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<form name="cms_basic_auth" action="{$site_url/}roc-basic-login" method="POST">
|
||||
<input type="hidden" name="host" id="host" value="{$site_url/}">
|
||||
<div>
|
||||
<input type="text" name="username" id="username" required>
|
||||
<label>Username</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label>Password</label>
|
||||
</div>
|
||||
<button type="button" onclick="ROC_AUTH.login();">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||
</p>
|
||||
</div>
|
||||
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||
</div>
|
||||
{/unless}
|
||||
</div>
|
||||
{/unless}
|
||||
|
||||
@@ -78,27 +78,17 @@ feature {CMS_API} -- Module Initialization
|
||||
|
||||
feature {CMS_API} -- Module management
|
||||
|
||||
install (api: CMS_API)
|
||||
local
|
||||
sql: STRING
|
||||
install (a_api: CMS_API)
|
||||
do
|
||||
-- Schema
|
||||
if attached api.storage.as_sql_storage as l_sql_storage then
|
||||
if not l_sql_storage.sql_table_exists ("blog_post_nodes") then
|
||||
sql := "[
|
||||
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)
|
||||
);
|
||||
]"
|
||||
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
|
||||
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 ("install.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
|
||||
Precursor (api)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
6
modules/blog/site/scripts/install.sql
Normal file
6
modules/blog/site/scripts/install.sql
Normal 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)
|
||||
);
|
||||
21
modules/contact/contact-safe.ecf
Normal file
21
modules/contact/contact-safe.ecf
Normal 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>
|
||||
8
modules/contact/site/config/contact.json
Normal file
8
modules/contact/site/config/contact.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"--email": "webmaster@example.com",
|
||||
"subjet": "Thank you for contacting us",
|
||||
"recaptcha": {
|
||||
"site_key":"",
|
||||
"secret_key":""
|
||||
}
|
||||
}
|
||||
124
modules/contact/site/files/css/contact.css
Normal file
124
modules/contact/site/files/css/contact.css
Normal 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;
|
||||
}
|
||||
140
modules/contact/site/files/scss/contact.scss
Normal file
140
modules/contact/site/files/scss/contact.scss
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
modules/contact/site/templates/block_contact.tpl
Normal file
25
modules/contact/site/templates/block_contact.tpl
Normal 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>
|
||||
15
modules/contact/site/templates/block_post_contact.tpl
Normal file
15
modules/contact/site/templates/block_post_contact.tpl
Normal 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>
|
||||
10
modules/contact/site/templates/email_message.tpl
Normal file
10
modules/contact/site/templates/email_message.tpl
Normal 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>
|
||||
6
modules/contact/site/templates/email_notification.tpl
Normal file
6
modules/contact/site/templates/email_notification.tpl
Normal 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>
|
||||
521
modules/contact/src/cms_contact_module.e
Normal file
521
modules/contact/src/cms_contact_module.e
Normal file
@@ -0,0 +1,521 @@
|
||||
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.api) 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", api) 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", api, 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", api, 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", api, 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
|
||||
|
||||
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
|
||||
40
modules/contact/src/contact_api.e
Normal file
40
modules/contact/src/contact_api.e
Normal 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
|
||||
63
modules/contact/src/contact_email_service_parameters.e
Normal file
63
modules/contact/src/contact_email_service_parameters.e
Normal 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
|
||||
43
modules/contact/src/contact_message.e
Normal file
43
modules/contact/src/contact_message.e
Normal 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
|
||||
56
modules/contact/src/persistence/contact_storage_fs.e
Normal file
56
modules/contact/src/persistence/contact_storage_fs.e
Normal 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
|
||||
27
modules/contact/src/persistence/contact_storage_i.e
Normal file
27
modules/contact/src/persistence/contact_storage_i.e
Normal 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
|
||||
39
modules/contact/src/persistence/contact_storage_null.e
Normal file
39
modules/contact/src/persistence/contact_storage_null.e
Normal 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
|
||||
49
modules/contact/src/persistence/contact_storage_sql.e
Normal file
49
modules/contact/src/persistence/contact_storage_sql.e
Normal 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
|
||||
@@ -346,9 +346,11 @@ feature -- Hook
|
||||
-- Hook execution on collection of menu contained by `a_menu_system'
|
||||
-- for related response `a_response'.
|
||||
do
|
||||
a_menu_system.navigation_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds", "feed_aggregation/"))
|
||||
if a_response.has_permission (permission__manage_feed_aggregator) then
|
||||
a_menu_system.management_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds (admin)", "admin/feed_aggregator/"))
|
||||
if a_response.is_authenticated then
|
||||
a_menu_system.navigation_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds", "feed_aggregation/"))
|
||||
if a_response.has_permission (permission__manage_feed_aggregator) then
|
||||
a_menu_system.management_menu.extend_into (create {CMS_LOCAL_LINK}.make ("Feeds (admin)", "admin/feed_aggregator/"), "Admin", "admin")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
69
modules/files/cms_file.e
Normal file
69
modules/files/cms_file.e
Normal file
@@ -0,0 +1,69 @@
|
||||
note
|
||||
description: "Interface representing any files under `{CMS_API}.files_location' ."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_FILE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initializaion
|
||||
|
||||
make (a_relative_path: PATH; a_api: CMS_API)
|
||||
do
|
||||
cms_api := a_api
|
||||
relative_path := a_relative_path
|
||||
end
|
||||
|
||||
cms_api: CMS_API
|
||||
|
||||
feature -- Access
|
||||
|
||||
filename: STRING_32
|
||||
-- File name of Current file.
|
||||
local
|
||||
p: PATH
|
||||
do
|
||||
p := relative_path
|
||||
if attached p.entry as e then
|
||||
Result := e.name
|
||||
else
|
||||
Result := p.name
|
||||
end
|
||||
end
|
||||
|
||||
relative_path: PATH
|
||||
-- Path relative the `CMS_API.files_location'.
|
||||
|
||||
owner: detachable CMS_USER
|
||||
-- Optional owner.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_directory: BOOLEAN
|
||||
local
|
||||
d: DIRECTORY
|
||||
do
|
||||
create d.make_with_path (cms_api.files_location.extended_path (relative_path))
|
||||
Result := d.exists
|
||||
end
|
||||
|
||||
is_file: BOOLEAN
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make_with_path (cms_api.files_location.extended_path (relative_path))
|
||||
Result := f.exists
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_owner (u: detachable CMS_USER)
|
||||
-- Set `owner' to `u'.
|
||||
do
|
||||
owner := u
|
||||
end
|
||||
|
||||
end
|
||||
57
modules/files/cms_file_metadata.e
Normal file
57
modules/files/cms_file_metadata.e
Normal file
@@ -0,0 +1,57 @@
|
||||
note
|
||||
description: "Metadata associated to a CMS_FILE."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_FILE_METADATA
|
||||
|
||||
create
|
||||
make,
|
||||
make_empty
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_empty
|
||||
do
|
||||
create date.make_now_utc
|
||||
end
|
||||
|
||||
make (f: CMS_FILE)
|
||||
do
|
||||
make_empty
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
user: detachable CMS_USER
|
||||
|
||||
date: detachable DATE_TIME
|
||||
|
||||
size: INTEGER
|
||||
|
||||
file_type: detachable READABLE_STRING_8
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_user (u: detachable CMS_USER)
|
||||
do
|
||||
user := u
|
||||
end
|
||||
|
||||
set_date (dt: detachable DATE_TIME)
|
||||
do
|
||||
date := dt
|
||||
end
|
||||
|
||||
set_size (a_size: INTEGER)
|
||||
do
|
||||
size := a_size
|
||||
end
|
||||
|
||||
set_file_type (a_type: detachable READABLE_STRING_8)
|
||||
do
|
||||
file_type := a_type
|
||||
end
|
||||
|
||||
end
|
||||
272
modules/files/cms_files_api.e
Normal file
272
modules/files/cms_files_api.e
Normal file
@@ -0,0 +1,272 @@
|
||||
note
|
||||
description: "API to manage files."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_FILES_API
|
||||
|
||||
inherit
|
||||
CMS_MODULE_API
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Access : path
|
||||
|
||||
uploads_relative_path: PATH
|
||||
-- Path relative to `{CMS_API}.files_location'.
|
||||
do
|
||||
create Result.make_from_string (uploads_directory_name)
|
||||
end
|
||||
|
||||
uploads_directory: PATH
|
||||
do
|
||||
Result := cms_api.files_location.extended (uploads_directory_name)
|
||||
end
|
||||
|
||||
uploaded_file_path (f: READABLE_STRING_GENERAL): PATH
|
||||
do
|
||||
Result := uploads_directory.extended (f)
|
||||
end
|
||||
|
||||
thumbnail_directory: PATH
|
||||
do
|
||||
Result := uploads_directory.extended (thumbnail_directory_name)
|
||||
end
|
||||
|
||||
feature {CMS_FILES_MODULE} -- Access : metadata path
|
||||
|
||||
metadata_path (f: READABLE_STRING_GENERAL): PATH
|
||||
do
|
||||
Result := metadata_directory.extended (f).appended_with_extension ("cms-metadata")
|
||||
end
|
||||
|
||||
metadata_directory: PATH
|
||||
do
|
||||
Result := uploads_directory.extended (metadata_directory_name)
|
||||
end
|
||||
|
||||
feature -- Access : links
|
||||
|
||||
file_link (f: CMS_FILE): CMS_LOCAL_LINK
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
s := "files"
|
||||
across
|
||||
f.relative_path.components as ic
|
||||
loop
|
||||
s.append_character ('/')
|
||||
s.append (percent_encoded (ic.item.name))
|
||||
end
|
||||
create Result.make (f.filename, s)
|
||||
end
|
||||
|
||||
feature {NONE} -- Constants
|
||||
|
||||
uploads_directory_name: STRING = "uploads"
|
||||
|
||||
metadata_directory_name: STRING = ".metadata"
|
||||
|
||||
thumbnail_directory_name: STRING = ".thumbnails"
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_file (a_relative_path: PATH): CMS_FILE
|
||||
-- New CMS_FILE for path `a_relative_path' relative to `files' directory.
|
||||
do
|
||||
create Result.make (a_relative_path, cms_api)
|
||||
end
|
||||
|
||||
new_uploads_file (p: PATH): CMS_FILE
|
||||
-- New uploaded path from `p' relative to `uploads_directory'.
|
||||
do
|
||||
create Result.make (uploads_relative_path.extended_path (p), cms_api)
|
||||
end
|
||||
|
||||
feature -- Storage
|
||||
|
||||
delete_file (fn: READABLE_STRING_GENERAL)
|
||||
-- Delete file at `fn'.
|
||||
local
|
||||
p: PATH
|
||||
do
|
||||
error_handler.reset
|
||||
p := uploaded_file_path (fn)
|
||||
safe_delete (p)
|
||||
if not has_error then
|
||||
p := metadata_path (fn)
|
||||
safe_delete (p)
|
||||
end
|
||||
end
|
||||
|
||||
save_uploaded_file (uf: CMS_UPLOADED_FILE)
|
||||
local
|
||||
p: PATH
|
||||
ut: FILE_UTILITIES
|
||||
stored: BOOLEAN
|
||||
original_name: STRING_32
|
||||
n: INTEGER_32
|
||||
finished: BOOLEAN
|
||||
do
|
||||
reset_error
|
||||
create original_name.make_from_string (uf.filename)
|
||||
|
||||
p := uf.location
|
||||
if not p.is_absolute then
|
||||
p := uploads_directory.extended_path (p)
|
||||
end
|
||||
|
||||
if ut.file_path_exists (p) then
|
||||
|
||||
from
|
||||
n := 1
|
||||
until
|
||||
finished
|
||||
loop
|
||||
if ut.file_path_exists (p) then
|
||||
uf.set_new_location_with_number (n)
|
||||
p := uf.location
|
||||
if p.is_absolute then
|
||||
else
|
||||
p := uploads_directory.extended_path (p)
|
||||
end
|
||||
n := n + 1
|
||||
else
|
||||
finished := True
|
||||
end
|
||||
end
|
||||
stored := uf.move_to (p)
|
||||
else
|
||||
-- move file to path
|
||||
stored := uf.move_to (p)
|
||||
end
|
||||
|
||||
if stored then
|
||||
save_metadata_from_uploaded_file (uf, cms_api.user)
|
||||
else
|
||||
error_handler.add_custom_error (-1, "uploaded file storage failed", "Issue occurred when saving uploaded file!")
|
||||
end
|
||||
end
|
||||
|
||||
save_metadata_from_uploaded_file (a_uploaded_file: CMS_UPLOADED_FILE; u: detachable CMS_USER)
|
||||
local
|
||||
f: detachable RAW_FILE
|
||||
h_date: HTTP_DATE
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if retried then
|
||||
-- FIXME: Report error?
|
||||
if f /= Void and then not f.is_closed then
|
||||
f.close
|
||||
end
|
||||
else
|
||||
-- create a file for metadata
|
||||
create f.make_with_path (metadata_path (a_uploaded_file.filename))
|
||||
|
||||
if f.exists then
|
||||
f.open_write
|
||||
else
|
||||
f.create_read_write
|
||||
end
|
||||
-- insert username
|
||||
if u /= Void then
|
||||
f.put_string (u.id.out)
|
||||
f.put_new_line
|
||||
-- f.put_string (utf.utf_32_string_to_utf_8_string_8 (u.name))
|
||||
-- f.put_new_line
|
||||
else
|
||||
f.put_new_line
|
||||
f.put_new_line
|
||||
end
|
||||
-- insert uploaded_time
|
||||
create h_date.make_now_utc
|
||||
f.put_string (h_date.timestamp.out)
|
||||
f.put_new_line
|
||||
|
||||
-- insert size of file
|
||||
f.put_string (a_uploaded_file.size.out)
|
||||
f.put_new_line
|
||||
|
||||
-- insert file type
|
||||
if attached a_uploaded_file.type as type then
|
||||
f.put_string (type.out)
|
||||
f.put_new_line
|
||||
end
|
||||
|
||||
f.close
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
metadata (a_cms_file: CMS_FILE): detachable CMS_FILE_METADATA
|
||||
local
|
||||
f: RAW_FILE
|
||||
s: READABLE_STRING_8
|
||||
do
|
||||
if attached metadata_path (a_cms_file.filename) as p then
|
||||
create f.make_with_path (p)
|
||||
if f.exists and then f.is_access_readable then
|
||||
create Result.make_empty
|
||||
|
||||
f.open_read
|
||||
|
||||
f.read_line
|
||||
s := f.last_string
|
||||
if s.is_integer_64 then
|
||||
Result.set_user (cms_api.user_api.user_by_id (s.to_integer_64))
|
||||
else
|
||||
Result.set_user (cms_api.user_api.user_by_name (s))
|
||||
end
|
||||
|
||||
f.read_line
|
||||
s := f.last_string
|
||||
if s.is_integer_64 then
|
||||
Result.set_date ((create {HTTP_DATE}.make_from_timestamp (s.to_integer_64)).date_time)
|
||||
end
|
||||
|
||||
f.read_line
|
||||
s := f.last_string
|
||||
if s.is_integer_32 then
|
||||
Result.set_size (s.to_integer_32)
|
||||
else
|
||||
Result.set_size (-1)
|
||||
end
|
||||
|
||||
if not f.end_of_file then
|
||||
f.read_line
|
||||
Result.set_file_type (f.last_string)
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
safe_delete (p: PATH)
|
||||
-- Safe remove file at path `p'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if retried then
|
||||
error_handler.add_custom_error (-1, "Can not delete file", {STRING_32} "Can not delete file %"" + p.name + "%"")
|
||||
else
|
||||
create f.make_with_path (p)
|
||||
if f.exists then
|
||||
f.delete
|
||||
else
|
||||
-- Not considered as failure.
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
504
modules/files/cms_files_module.e
Normal file
504
modules/files/cms_files_module.e
Normal file
@@ -0,0 +1,504 @@
|
||||
note
|
||||
description: "files module."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_FILES_MODULE
|
||||
|
||||
inherit
|
||||
CMS_MODULE
|
||||
rename
|
||||
module_api as files_api
|
||||
redefine
|
||||
install,
|
||||
initialize,
|
||||
setup_hooks,
|
||||
permissions,
|
||||
files_api
|
||||
end
|
||||
|
||||
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
name := "files"
|
||||
version := "1.0"
|
||||
description := "Service to upload files, and manage them."
|
||||
package := "file"
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING
|
||||
|
||||
permissions: LIST [READABLE_STRING_8]
|
||||
-- List of permission ids, used by this module, and declared.
|
||||
do
|
||||
Result := Precursor
|
||||
Result.force (admin_files_permission)
|
||||
Result.force (upload_files_permission)
|
||||
Result.force (browse_files_permission)
|
||||
end
|
||||
|
||||
admin_files_permission: STRING = "admin files"
|
||||
upload_files_permission: STRING = "upload files"
|
||||
browse_files_permission: STRING = "browse files"
|
||||
|
||||
feature {CMS_API} -- Module Initialization
|
||||
|
||||
initialize (api: CMS_API)
|
||||
-- <Precursor>
|
||||
do
|
||||
Precursor (api)
|
||||
if files_api = Void then
|
||||
create files_api.make (api)
|
||||
end
|
||||
end
|
||||
|
||||
feature {CMS_API}-- Module management
|
||||
|
||||
install (api: CMS_API)
|
||||
-- install the module
|
||||
local
|
||||
l_files_api: like files_api
|
||||
d: DIRECTORY
|
||||
do
|
||||
create l_files_api.make (api)
|
||||
create d.make_with_path (l_files_api.uploads_directory)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
create d.make_with_path (l_files_api.metadata_directory)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
|
||||
files_api := l_files_api
|
||||
Precursor (api)
|
||||
end
|
||||
|
||||
feature {CMS_API} -- Access: API
|
||||
|
||||
files_api: detachable CMS_FILES_API
|
||||
-- <Precursor>
|
||||
|
||||
feature -- Access: router
|
||||
|
||||
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
|
||||
-- <Precursor>
|
||||
do
|
||||
map_uri_template_agent (a_router, "/" + uploads_location, agent execute_upload (?, ?, a_api), Void) -- Accepts any method GET, HEAD, POST, PUT, DELETE, ...
|
||||
map_uri_template_agent (a_router, "/" + uploads_location + "{filename}", agent display_uploaded_file_info (?, ?, a_api), a_router.methods_get)
|
||||
map_uri_template_agent (a_router, "/" + uploads_location + "remove/{filename}", agent remove_file (?, ?, a_api), a_router.methods_get)
|
||||
end
|
||||
|
||||
uploads_location: STRING = "upload/"
|
||||
|
||||
feature -- Hooks
|
||||
|
||||
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
|
||||
do
|
||||
a_hooks.subscribe_to_menu_system_alter_hook (Current)
|
||||
end
|
||||
|
||||
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||
local
|
||||
link: CMS_LOCAL_LINK
|
||||
do
|
||||
-- login in demo did somehow not work
|
||||
if a_response.has_permission (upload_files_permission) then
|
||||
create link.make ("Upload files", uploads_location)
|
||||
a_menu_system.navigation_menu.extend (link)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Handler
|
||||
|
||||
execute_not_found_handler (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- `uri' is not found, redirect to default page
|
||||
do
|
||||
res.redirect_now_with_content (req.script_url ("/"), uri + ": not found. %N Redirection to" + req.script_url ("/"), "text/html")
|
||||
end
|
||||
|
||||
display_uploaded_file_info (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
|
||||
-- Display information related to a cms uploaded file.
|
||||
local
|
||||
body: STRING_8
|
||||
r: CMS_RESPONSE
|
||||
f: CMS_FILE
|
||||
md: detachable CMS_FILE_METADATA
|
||||
fn: READABLE_STRING_32
|
||||
do
|
||||
check req.is_get_request_method end
|
||||
if not api.has_permission (browse_files_permission) then
|
||||
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
r.add_error_message ("You are not allowed to browse CMS files!")
|
||||
elseif attached {WSF_STRING} req.path_parameter ("filename") as p_filename then
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
|
||||
-- add style
|
||||
r.add_style (r.url ("/module/" + name + "/files/css/files.css", Void), Void)
|
||||
|
||||
create body.make_empty
|
||||
|
||||
fn := p_filename.value
|
||||
r.set_page_title ({STRING_32} "File %"" + fn + {STRING_32} "%"")
|
||||
body.append ("<div class=%"uploaded-files%">%N") -- To ease css customization.
|
||||
if attached files_api as l_files_api then
|
||||
f := l_files_api.new_uploads_file (create {PATH}.make_from_string (fn))
|
||||
|
||||
body.append ("<div class=%"metadata%">")
|
||||
|
||||
md := l_files_api.metadata (f)
|
||||
|
||||
--| Uploader user
|
||||
body.append ("<strong>User: </strong>")
|
||||
if md /= Void and then attached md.user as meta_user then
|
||||
body.append (api.html_encoded (meta_user.name))
|
||||
else
|
||||
body.append ("unknown user")
|
||||
end
|
||||
body.append ("<br/>%N")
|
||||
|
||||
--| Uploaded date
|
||||
body.append ("<strong>Upload Time: </strong>")
|
||||
if md /= Void and then attached md.date as meta_time then
|
||||
body.append (meta_time.out)
|
||||
else
|
||||
body.append ("NA")
|
||||
end
|
||||
body.append ("<br/>%N")
|
||||
|
||||
--| File size
|
||||
body.append ("<strong> File Size: </strong>")
|
||||
if md /= Void and then md.size > 0 then
|
||||
body.append (file_size_human_string (md.size))
|
||||
else
|
||||
body.append ("NA")
|
||||
end
|
||||
body.append ("<br/>%N")
|
||||
|
||||
--| File type
|
||||
body.append ("<strong>File Type: </strong>")
|
||||
if md /= Void and then attached md.file_type as meta_type then
|
||||
body.append (meta_type)
|
||||
else
|
||||
body.append ("NA")
|
||||
end
|
||||
body.append ("<br/><br/>%N")
|
||||
|
||||
body.append ("<a class=%"button%" href=%"" + req.script_url ("/" + l_files_api.file_link (f).location) + "%">Download</a>%N")
|
||||
body.append ("<a class=%"button%" href=%"" + req.script_url ("/" + uploads_location + "remove/" + f.filename) + "%">Remove</a>%N")
|
||||
body.append ("</div>%N") -- metadata
|
||||
|
||||
body.append ("<div class=%"overview%">")
|
||||
if
|
||||
attached f.relative_path.extension as ext and then
|
||||
(
|
||||
ext.is_case_insensitive_equal_general ("png")
|
||||
or ext.is_case_insensitive_equal_general ("jpg")
|
||||
or ext.is_case_insensitive_equal_general ("gif")
|
||||
)
|
||||
then
|
||||
body.append ("<img src=%"" + req.script_url ("/" + l_files_api.file_link (f).location) + "%" />")
|
||||
else
|
||||
-- add default thumbnail
|
||||
body.append ("<img src=%"" + req.script_url ("/module/" + name + "/files/img/file-logo.png") + "%" />")
|
||||
end
|
||||
body.append ("</div>%N") -- Overview
|
||||
end
|
||||
body.append ("</div>%N")
|
||||
|
||||
r.add_to_primary_tabs (create {CMS_LOCAL_LINK}.make ("Uploaded files", uploads_location))
|
||||
r.set_main_content (body)
|
||||
else
|
||||
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
r.set_main_content ("Missing 'filename' field value!")
|
||||
end
|
||||
r.execute
|
||||
end
|
||||
|
||||
execute_upload (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
|
||||
local
|
||||
body: STRING_8
|
||||
r: CMS_RESPONSE
|
||||
do
|
||||
if req.is_get_head_request_method or req.is_post_request_method then
|
||||
create body.make_empty
|
||||
body.append ("<h1> Upload files </h1>%N")
|
||||
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
|
||||
-- set style
|
||||
r.add_style (r.url ("/module/" + name + "/files/css/files.css", void), void)
|
||||
|
||||
-- add JS for dropzone
|
||||
r.add_javascript_url (r.url ("/module/" + name + "/files/js/dropzone.js", void))
|
||||
r.add_style (r.url ("/module/" + name + "/files/js/dropzone.css", void), void)
|
||||
|
||||
if api.has_permission (upload_files_permission) then
|
||||
-- create body
|
||||
body.append ("<p>Please choose some file(s) to upload.</p>")
|
||||
|
||||
-- create form to choose files and upload them
|
||||
body.append ("<div class=%"upload-files%">")
|
||||
body.append ("<form action=%"" + r.url (uploads_location, Void) + "%" class=%"dropzone%">")
|
||||
body.append ("</form>%N")
|
||||
body.append ("<div class=%"center%"><a class=%"button%" href=%""+ r.url (uploads_location, Void) +"%">Upload Files</a></div>")
|
||||
body.append ("</div>")
|
||||
if req.is_post_request_method then
|
||||
process_uploaded_files (req, api, body)
|
||||
end
|
||||
else
|
||||
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
end
|
||||
|
||||
-- Build the response.
|
||||
if r.has_permission (browse_files_permission) then
|
||||
append_uploaded_file_album_to (req, api, body)
|
||||
else
|
||||
r.add_warning_message ("You are not allowed to browse files!")
|
||||
end
|
||||
|
||||
r.set_main_content (body)
|
||||
else
|
||||
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
end
|
||||
r.execute
|
||||
end
|
||||
|
||||
process_uploaded_files (req: WSF_REQUEST; api: CMS_API; a_output: STRING)
|
||||
-- Process http request uploaded files.
|
||||
require
|
||||
has_permission: api.has_permission (upload_files_permission)
|
||||
local
|
||||
l_uploaded_file: CMS_UPLOADED_FILE
|
||||
uf: WSF_UPLOADED_FILE
|
||||
do
|
||||
if attached files_api as l_files_api then
|
||||
-- if has uploaded files, then store them
|
||||
if req.has_uploaded_file then
|
||||
a_output.append ("<strong>Newly uploaded file(s): </strong>%N")
|
||||
a_output.append ("<ul class=%"uploaded-files%">")
|
||||
across
|
||||
req.uploaded_files as ic
|
||||
loop
|
||||
uf := ic.item
|
||||
create l_uploaded_file.make_with_uploaded_file (l_files_api.uploads_directory, uf)
|
||||
a_output.append ("<li>")
|
||||
a_output.append (api.html_encoded (l_uploaded_file.filename))
|
||||
|
||||
-- create medadata file
|
||||
l_uploaded_file.set_size (uf.size)
|
||||
l_uploaded_file.set_type (uf.content_type)
|
||||
|
||||
-- store the just uploaded file
|
||||
l_files_api.save_uploaded_file (l_uploaded_file)
|
||||
|
||||
if l_files_api.has_error then
|
||||
a_output.append (" <span class=%"error%">: upload failed!</span>")
|
||||
end
|
||||
a_output.append ("</li>")
|
||||
end
|
||||
a_output.append ("</ul>%N")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
append_uploaded_file_album_to (req: WSF_REQUEST; api: CMS_API; a_output: STRING)
|
||||
local
|
||||
d: DIRECTORY
|
||||
f: CMS_FILE
|
||||
p: PATH
|
||||
rel: PATH
|
||||
md: detachable CMS_FILE_METADATA
|
||||
do
|
||||
if attached files_api as l_files_api then
|
||||
rel := l_files_api.uploads_relative_path
|
||||
p := l_files_api.uploads_directory
|
||||
|
||||
a_output.append ("<div class=%"uploaded-files%">%N")
|
||||
a_output.append ("<strong>Uploaded files:</strong>%N")
|
||||
a_output.append ("<table>%N")
|
||||
a_output.append ("<tr><th>Filename</th><th>Uploading Time</th><th>User</th><th>Size</th><th></th><th></th></tr>%N")
|
||||
|
||||
create d.make_with_path (p)
|
||||
if d.exists then
|
||||
across
|
||||
d.entries as ic
|
||||
loop
|
||||
|
||||
if ic.item.is_current_symbol then
|
||||
-- Ignore
|
||||
elseif ic.item.is_parent_symbol then
|
||||
-- Ignore for now.
|
||||
else
|
||||
f := l_files_api.new_file (rel.extended_path (ic.item))
|
||||
|
||||
-- check if f is directory -> yes, then do not show
|
||||
if not f.is_directory then
|
||||
a_output.append ("<tr>")
|
||||
|
||||
-- add filename
|
||||
a_output.append ("<td class=%"filename%">")
|
||||
a_output.append ("<a href=%"" + api.percent_encoded (f.filename) + "%">")
|
||||
a_output.append (api.html_encoded (f.filename))
|
||||
a_output.append ("</a>")
|
||||
a_output.append ("</td>%N")
|
||||
|
||||
md := l_files_api.metadata (f)
|
||||
if md = Void then
|
||||
a_output.append ("<td class=%"date%"></td>%N")
|
||||
a_output.append ("<td class=%"user%"></td>%N")
|
||||
a_output.append ("<td class=%"size%"></td>%N")
|
||||
else
|
||||
|
||||
-- add uploading time
|
||||
a_output.append ("<td class=%"date%">")
|
||||
if attached md.date as meta_time then
|
||||
a_output.append (meta_time.out)
|
||||
end
|
||||
a_output.append ("</td>%N")
|
||||
|
||||
-- add user
|
||||
a_output.append ("<td class=%"user%">")
|
||||
if attached md.user as u then
|
||||
a_output.append (api.html_encoded (u.name))
|
||||
end
|
||||
a_output.append ("</td>%N")
|
||||
|
||||
-- add size
|
||||
a_output.append ("<td class=%"size%">")
|
||||
if md.size > 0 then
|
||||
a_output.append (file_size_human_string (md.size))
|
||||
else
|
||||
a_output.append ("NA")
|
||||
end
|
||||
a_output.append ("</td>%N")
|
||||
end
|
||||
|
||||
-- add download link
|
||||
a_output.append ("<td>")
|
||||
a_output.append ("<a class=%"button%" href=%"" + req.script_url ("/" + l_files_api.file_link (f).location) + "%" download>Download</a>%N")
|
||||
a_output.append ("</td>%N")
|
||||
|
||||
-- add remove button
|
||||
a_output.append ("<td>")
|
||||
a_output.append ("<a class=%"button%" href=%"" + req.script_url ("/" + uploads_location + "remove/" + f.filename) + "%">Remove</a>%N")
|
||||
a_output.append ("</td>%N")
|
||||
|
||||
a_output.append ("</tr>%N")
|
||||
else
|
||||
if f.relative_path.is_current_symbol or f.relative_path.is_parent_symbol then
|
||||
-- Ignore "." and ".."
|
||||
else
|
||||
|
||||
-- folder support not yet supported
|
||||
|
||||
-- -- add directory identifier
|
||||
-- a_output.append ("<td>[dir]</td>%N")
|
||||
|
||||
-- a_output.append ("<td>")
|
||||
-- a_output.append ("<a href=%"" + api.percent_encoded (f.filename) + "%">")
|
||||
-- a_output.append (api.html_encoded (f.filename))
|
||||
-- a_output.append ("</a>")
|
||||
-- a_output.append ("</td>%N")
|
||||
|
||||
-- a_output.append ("<td></td><td></td><td></td><td></td><td></td>")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
a_output.append ("</table>%N")
|
||||
a_output.append ("</div>%N")
|
||||
end
|
||||
end
|
||||
|
||||
remove_file (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
|
||||
local
|
||||
body: STRING
|
||||
r: CMS_RESPONSE
|
||||
err: BOOLEAN
|
||||
do
|
||||
if attached files_api as l_files_api then
|
||||
if not api.has_permission (admin_files_permission) then
|
||||
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
r.add_error_message ("You are not allowed to remove file!")
|
||||
elseif attached {WSF_STRING} req.path_parameter ("filename") as p_filename then
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
|
||||
l_files_api.delete_file (p_filename.value)
|
||||
err := l_files_api.has_error
|
||||
l_files_api.reset_error
|
||||
create body.make_empty
|
||||
|
||||
if err then
|
||||
body.append ("<h3>The file has been removed successfully!</h3>")
|
||||
else
|
||||
body.append ("<h3>The file removal failed!</h3>")
|
||||
end
|
||||
|
||||
r.add_to_primary_tabs (create {CMS_LOCAL_LINK}.make ("Uploaded files", uploads_location))
|
||||
r.set_main_content (body)
|
||||
else
|
||||
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
r.add_error_message ("Missing 'filename' parameter!")
|
||||
end
|
||||
else
|
||||
create {INTERNAL_SERVER_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
r.set_main_content ("Removal of file failed due to internal server error!")
|
||||
end
|
||||
r.execute
|
||||
end
|
||||
|
||||
feature -- Helpers
|
||||
|
||||
file_size_human_string (a_size: INTEGER): STRING
|
||||
local
|
||||
size: INTEGER
|
||||
do
|
||||
size := a_size
|
||||
if size >= 1000000 then
|
||||
size := size // 1000000
|
||||
Result := size.out + " MB"
|
||||
else
|
||||
if size >= 1000 then
|
||||
size := size // 1000
|
||||
Result := size.out + " kB"
|
||||
else
|
||||
Result := size.out + " bytes"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Mapping helper: uri template agent (analogue to the demo-module)
|
||||
|
||||
map_uri_template (a_router: WSF_ROUTER; a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
-- Map `h' as handler for `a_tpl', according to `rqst_methods'.
|
||||
require
|
||||
a_tpl_attached: a_tpl /= Void
|
||||
h_attached: h /= Void
|
||||
do
|
||||
a_router.map (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods)
|
||||
end
|
||||
|
||||
map_uri_template_agent (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
-- Map `proc' as handler for `a_tpl', according to `rqst_methods'.
|
||||
require
|
||||
a_tpl_attached: a_tpl /= Void
|
||||
proc_attached: proc /= Void
|
||||
do
|
||||
map_uri_template (a_router, a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods)
|
||||
end
|
||||
|
||||
end
|
||||
105
modules/files/cms_uploaded_file.e
Normal file
105
modules/files/cms_uploaded_file.e
Normal file
@@ -0,0 +1,105 @@
|
||||
note
|
||||
description: "Summary description for {CMS_UPLOADED_FILE}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_UPLOADED_FILE
|
||||
|
||||
create
|
||||
make_with_uploaded_file
|
||||
|
||||
feature {NONE} -- Initializaion
|
||||
|
||||
make_with_uploaded_file (a_uploads_directory: PATH; uf: WSF_UPLOADED_FILE)
|
||||
do
|
||||
uploads_directory := a_uploads_directory
|
||||
uploaded_file := uf
|
||||
location := a_uploads_directory.extended (uf.safe_filename)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
uploaded_file: WSF_UPLOADED_FILE
|
||||
|
||||
uploads_directory: PATH
|
||||
|
||||
filename: STRING_32
|
||||
-- File name of Current file.
|
||||
local
|
||||
p: PATH
|
||||
do
|
||||
p := location
|
||||
if attached p.entry as e then
|
||||
Result := e.name
|
||||
else
|
||||
Result := p.name
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
location: PATH
|
||||
-- Absolute path, or relative path to the `CMS_API.files_location'.
|
||||
|
||||
owner: detachable CMS_USER
|
||||
-- Optional owner.
|
||||
|
||||
upload_time: detachable DATE_TIME
|
||||
-- time when the file was uploaded
|
||||
|
||||
size: detachable INTEGER_32
|
||||
-- file size
|
||||
|
||||
type: detachable STRING
|
||||
-- file type
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_owner (u: detachable CMS_USER)
|
||||
-- Set `owner' to `u'.
|
||||
do
|
||||
owner := u
|
||||
end
|
||||
|
||||
set_time (a_time: detachable DATE_TIME)
|
||||
-- Set `upload_time' to `a_time'
|
||||
do
|
||||
upload_time := a_time
|
||||
end
|
||||
|
||||
set_size (a_size: detachable INTEGER_32)
|
||||
-- Set `size' to `a_size'
|
||||
do
|
||||
size := a_size
|
||||
end
|
||||
|
||||
set_type (a_type: detachable STRING)
|
||||
-- Set `type' to `a_type'
|
||||
do
|
||||
type := a_type
|
||||
end
|
||||
|
||||
set_new_location_with_number (a_number: INTEGER_32)
|
||||
-- sets `a_number' after the name. This is done when the file was already uploaded
|
||||
local
|
||||
position: INTEGER_32
|
||||
new_name: STRING_8
|
||||
do
|
||||
position := uploaded_file.string_representation.index_of ('.', 1)
|
||||
create new_name.make_empty
|
||||
|
||||
new_name := uploaded_file.string_representation.head (position-1)
|
||||
new_name.append ("_(" + a_number.out + ")")
|
||||
new_name.append (uploaded_file.string_representation.substring (position, uploaded_file.string_representation.count))
|
||||
|
||||
location := uploads_directory.extended (new_name)
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
move_to (p: PATH): BOOLEAN
|
||||
do
|
||||
Result := uploaded_file.move_to (p.name)
|
||||
end
|
||||
|
||||
end
|
||||
21
modules/files/files-safe.ecf
Normal file
21
modules/files/files-safe.ecf
Normal 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="files_module" uuid="795C88E5-9218-4F35-A985-5501340E2D9D" library_target="files_module">
|
||||
<target name="files_module">
|
||||
<root all_classes="true" />
|
||||
<file_rule>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="cms" location="..\..\cms-safe.ecf"/>
|
||||
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf"/>
|
||||
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-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"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
22
modules/files/files.ecf
Normal file
22
modules/files/files.ecf
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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="files_module" uuid="795C88E5-9218-4F35-A985-5501340E2D9D" library_target="files_module">
|
||||
<target name="files_module">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.svn$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="cms" location="..\..\cms.ecf"/>
|
||||
<library name="cms_model" location="..\..\library\model\cms_model.ecf"/>
|
||||
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http.ecf"/>
|
||||
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
|
||||
<library name="wsf_encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
52
modules/files/site/files/css/files.css
Normal file
52
modules/files/site/files/css/files.css
Normal file
@@ -0,0 +1,52 @@
|
||||
.uploaded-files table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.uploaded-files table th {
|
||||
padding: 3px 0 3px 5px;
|
||||
}
|
||||
.uploaded-files table td {
|
||||
padding: 3px 0 3px 5px;
|
||||
}
|
||||
.uploaded-files a.button {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border: solid 1px #999;
|
||||
background-color: #ddd;
|
||||
padding: 2px 4px 2px 4px;
|
||||
}
|
||||
.uploaded-files a.button:hover {
|
||||
color: black;
|
||||
border: solid 1px #06f;
|
||||
background-color: #cff;
|
||||
}
|
||||
|
||||
.upload-files .center {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
.upload-files a.button {
|
||||
margin: auto;
|
||||
width: 100px;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
border: solid 1px #999;
|
||||
background-color: #ddd;
|
||||
padding: 2px 4px 2px 4px;
|
||||
}
|
||||
.upload-files a.button:hover {
|
||||
color: black;
|
||||
border: solid 1px #06f;
|
||||
background-color: #cff;
|
||||
}
|
||||
|
||||
/******************* Drop Zone *******************/
|
||||
.dropzone {
|
||||
width: 100%;
|
||||
border: 2px dashed blue;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
BIN
modules/files/site/files/img/file-logo.png
Normal file
BIN
modules/files/site/files/img/file-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
1
modules/files/site/files/js/dropzone.css
Normal file
1
modules/files/site/files/js/dropzone.css
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user