Implemented basic extra handling (ie. plug-ins in Antville):

* Added global app.data.extras collection and registerExtra() method
 * Defined res.handlers.extra in HopObject.onRequest() handler to provide extra macros
 * Implemented reCAPTCHA for anonymously contacting an Antville member as proof of concept
This commit is contained in:
Tobi Schäfer 2011-03-23 13:35:02 +00:00
parent 8a83f406f8
commit 91b45b3732
8 changed files with 135 additions and 29 deletions

View file

@ -19,8 +19,8 @@
// limitations under the License.
//
// $Revision$
// $LastChangedBy$
// $LastChangedDate$
// $Author$
// $Date$
// $URL$
/**
@ -72,6 +72,8 @@ app.data.features || (app.data.features = []);
app.data.mails || (app.data.mails = []);
/** @name app.data.requests */
app.data.requests || (app.data.requests = {});
/** @name app.data.extras */
app.data.extras || (app.data.extras = {});
/**
* @name helma.File
@ -282,8 +284,6 @@ function link_macro() {
return renderLink.apply(this, arguments);
}
// FIXME: The definition with "var" is necessary; otherwise the skin_macro()
// method won't be overwritten reliably. (Looks like a Helma bug.)
/**
*
* @param {Object} param
@ -291,6 +291,8 @@ function link_macro() {
* @returns {String} The rendered skin
* @see HopObject#skin_macro
*/
// FIXME: The definition with "var" is necessary; otherwise the skin_macro()
// method won't be overwritten reliably. (Looks like a Helma bug.)
var skin_macro = function(param, name) {
return HopObject.prototype.skin_macro.apply(this, arguments);
}
@ -324,6 +326,15 @@ function breadcrumbs_macro (param, delimiter) {
return;
}
/**
* Helper macro for checking if a user session is authenticated (logged in).
* Returns true if user is logged in, false otherwise.
* @returns Boolean
*/
function user_macro() {
return !!session.user;
}
/**
*
* @param {Object} param
@ -1219,6 +1230,21 @@ var wait = function(millis) {
return;
}
/**
*
* @param {String} name
* @param {Object} extra
*/
var registerExtra = function(name, extra) {
app.data.extras[name] = extra;
if (extra._macro) {
app.data.extras[name + "_macro"] = function() {
return extra._macro.apply(this, arguments);
}
}
return;
}
/**
*
* @param {Object} param

View file

@ -19,8 +19,8 @@
// limitations under the License.
//
// $Revision$
// $LastChangedBy$
// $LastChangedDate$
// $Author$
// $Date$
// $URL$
/**
@ -141,6 +141,8 @@ HopObject.prototype.onRequest = function() {
res.meta.values = {};
res.handlers.site.renderSkinAsString("Site#values");
res.handlers.extra = app.data.extras;
return;
}

View file

@ -62,6 +62,14 @@ $(function() {
</tr>
<tr>
<td> </td>
<td colspan="4">
<% skin connect#facebook %><br />
<% skin connect#google %><br />
<% skin connect#twitter %><br />
</td>
</tr>
<tr>
<td> </td>
<td colspan="4"><br />
<button type="submit" id="submit" name="login" value="1"
tabindex="4"><% gettext Login context=verb %></button>

View file

@ -1,8 +1,10 @@
//
// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 2001-2007 by The Antville People
// Copyright 2007-2011 by Tobi Schäfer.
//
// Copyright 20012007 Robert Gaggl, Hannes Wallnöfer, Tobi Schäfer,
// Matthias & Michael Platzer, Christoph Lincke.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
@ -16,11 +18,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
// $Revision:3329 $
// $LastChangedBy:piefke3000 $
// $LastChangedDate:2007-09-14 15:18:09 +0200 (Fri, 14 Sep 2007) $
// $Revision$
// $Author$
// $Date$
// $URL$
//
/**
* @fileOverview Defines the Members prototype.
@ -112,7 +113,7 @@ Members.prototype.register_action = function() {
res.data.action = this.href(req.action);
res.data.title = gettext("Register");
res.data.body = this.renderSkinAsString("$Members#register");
this._parent.renderSkin("Site#page");
root.renderSkin("Site#page");
return;
}
@ -128,8 +129,8 @@ Members.prototype.reset_action = function() {
}
var token = User.getSalt();
user.setMetadata("resetToken", token);
sendMail(user.email, gettext("[{0}] Password reset confirmation",
root.title), user.renderSkinAsString("$User#notify_reset", {
sendMail(user.email, gettext("[{0}] Password reset confirmation", root.title),
user.renderSkinAsString("$User#notify_reset", {
href: this.href("reset"),
token: token
}));
@ -169,7 +170,7 @@ Members.prototype.reset_action = function() {
res.data.action = this.href(req.action);
res.data.title = gettext("Request Password Reset");
res.data.body = this.renderSkinAsString("$Members#reset");
this._parent.renderSkin("Site#page");
root.renderSkin("Site#page");
return;
}
@ -188,7 +189,7 @@ Members.prototype.login_action = function() {
res.data.action = this.href(req.action);
res.data.title = gettext("Login");
res.data.body = this.renderSkinAsString("$Members#login");
this._parent.renderSkin("Site#page");
root.renderSkin("Site#page");
return;
}
@ -217,7 +218,7 @@ Members.prototype.edit_action = function() {
session.data.salt = session.user.salt; // FIXME
res.data.title = gettext("User Profile");
res.data.body = session.user.renderSkinAsString("$User#edit");
this._parent.renderSkin("Site#page");
root.renderSkin("Site#page");
return;
}

View file

@ -90,6 +90,7 @@
<textarea cols="31" rows="10" class="formText" wrap="virtual"
name="text"><% request.text encoding="form" %></textarea>
</p>
<% extra.recaptcha %>
<p>
<button type="submit" name="send" value="1"><% gettext Send %></button>
<a href="" class="cancel"><% gettext Cancel %></a>

View file

@ -19,8 +19,8 @@
// limitations under the License.
//
// $Revision$
// $LastChangedBy$
// $LastChangedDate$
// $Author$
// $Date$
// $URL$
/**
@ -192,6 +192,9 @@ Membership.prototype.contact_action = function() {
if (!req.postParams.text) {
throw Error(gettext("Please enter the message text."));
}
if (app.data.extras.recaptcha && !session.user) {
app.data.extras.recaptcha.verify(req.postParams);
}
this.notify(req.action, this.creator.email, session.user ?
gettext('[{0}] Message from user {1}', root.title, session.user.name) :
gettext('[{0}] Message from anonymous user', root.title));
@ -290,15 +293,6 @@ Membership.prototype.toString = function() {
*/
Membership.prototype.valueOf = Membership.prototype.toString;
/**
* @deprecated
* @param {Object} param
* @throws {Error}
*/
Membership.prototype.email_macro = function(param) {
throw Error(gettext("Due to privacy reasons the display of e-mail addresses is disabled."));
}
/**
*
*/

View file

@ -0,0 +1,60 @@
// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 2007-2011 by Tobi Schäfer.
//
// Copyright 20012007 Robert Gaggl, Hannes Wallnöfer, Tobi Schäfer,
// Matthias & Michael Platzer, Christoph Lincke.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// $Revision$
// $Author$
// $Date$
// $URL$
/**
* @fileoverview Defines the Antville reCAPTCHA Feature.
* @see http://www.google.com/recaptcha
*/
registerExtra("recaptcha", new function() {
var key = getProperty("recaptcha.key");
return {
_macro: function() {
if (key && !session.user) {
renderSkin("recaptcha", {id: getProperty("recaptcha.id")});
}
return;
},
verify: function(data) {
var http = new helma.Http;
http.setTimeout(200);
http.setReadTimeout(300);
http.setMethod("POST");
http.setContent({
privatekey: key,
remoteip: req.data.http_remotehost,
challenge: data.recaptcha_challenge_field,
response: data.recaptcha_response_field
});
var request = http.getUrl("http://www.google.com/recaptcha/api/verify");
if (request.code === 200 && !request.content.startsWith("true")) {
throw Error(gettext("Please enter the correct words in the CAPTCHA box."));
}
return;
}
}
});

View file

@ -0,0 +1,14 @@
<script type="text/javascript">
var RecaptchaOptions = {
theme: 'default',
lang: '<% site.locale %>'
};
</script>
<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=<% param.id %>">
</script>
<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=<% param.id %>"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge">
</noscript>