added CAPTCHA to DataForm

This commit is contained in:
Doug Bell 2008-04-27 21:28:18 +00:00
parent db5a948c6b
commit 614da0d2ab
7 changed files with 247 additions and 90 deletions

View file

@ -41,6 +41,8 @@
- Fixed all Test::WWW::Mechanize tests and updated the skeleton. Should be - Fixed all Test::WWW::Mechanize tests and updated the skeleton. Should be
usable now. usable now.
- fixed: Registration form now saves all progress if there is an error - fixed: Registration form now saves all progress if there is an error
- added: DataForm now can use CAPTCHA for Visitors
- Spent some time cleaning up DataForm, but it could use more.
7.5.10 7.5.10

View file

@ -43,9 +43,23 @@ convertTransactionLog($session);
upgradeEMS($session); upgradeEMS($session);
migrateOldProduct($session); migrateOldProduct($session);
mergeProductsWithCommerce($session); mergeProductsWithCommerce($session);
addCaptchaToDataForm( $session );
finish($session); # this line required finish($session); # this line required
#----------------------------------------------------------------------------
# Add the useCaptcha field to DataForm assets
sub addCaptchaToDataForm {
my $session = shift;
print "\tAdding CAPTCHA to DataForm... " unless $quiet;
$session->db->write(
q{ ALTER TABLE DataForm ADD COLUMN useCaptcha INT(1) DEFAULT 0 }
);
print "DONE!\n" unless $quiet;
}
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
sub addReferralHandler { sub addReferralHandler {
my $session = shift; my $session = shift;

View file

@ -175,40 +175,44 @@ sub definition {
templateId =>{ templateId =>{
fieldType=>"template", fieldType=>"template",
defaultValue=>'PBtmpl0000000000000141', defaultValue=>'PBtmpl0000000000000141',
}, },
acknowledgement=>{ acknowledgement=>{
fieldType=>"textarea", fieldType=>"textarea",
defaultValue=>undef defaultValue=>undef
}, },
emailTemplateId=>{ emailTemplateId=>{
fieldType=>"template", fieldType=>"template",
defaultValue=>'PBtmpl0000000000000085', defaultValue=>'PBtmpl0000000000000085',
}, },
acknowlegementTemplateId=>{ acknowlegementTemplateId=>{
fieldType=>"template", fieldType=>"template",
defaultValue=>'PBtmpl0000000000000104', defaultValue=>'PBtmpl0000000000000104',
}, },
listTemplateId=>{ listTemplateId=>{
defaultValue=>'PBtmpl0000000000000021', defaultValue=>'PBtmpl0000000000000021',
fieldType=>"template" fieldType=>"template"
}, },
mailData=>{ mailData=>{
defaultValue=>0, defaultValue=>0,
fieldType=>"yesNo" fieldType=>"yesNo"
}, },
mailAttachments=>{ mailAttachments=>{
defaultValue=>0, defaultValue=>0,
fieldType=>'yesNo', fieldType=>'yesNo',
}, },
defaultView=>{ defaultView=>{
defaultValue=>0, defaultValue=>0,
fieldType=>"integer" fieldType=>"integer"
}, },
groupToViewEntries=>{ groupToViewEntries=>{
defaultValue=>7, defaultValue=>7,
fieldType=>"group" fieldType=>"group"
}, },
} useCaptcha => {
fieldType => "yesNo",
defaultValue => 0,
},
}
}); });
return $class->SUPER::definition($session, $definition); return $class->SUPER::definition($session, $definition);
} }
@ -354,6 +358,13 @@ sub getEditForm {
-value=>$self->getValue("mailAttachments"), -value=>$self->getValue("mailAttachments"),
); );
$tabform->getTab("properties")->yesNo(
-name => "useCaptcha",
-label => $i18n->get( "editForm useCaptcha label" ),
-hoverHelp => $i18n->get( "editForm useCaptcha description" ),
-value => $self->getValue( "useCaptcha" ),
);
$tabform->getTab("security")->group( $tabform->getTab("security")->group(
-name=>"groupToViewEntries", -name=>"groupToViewEntries",
-label=>$i18n->get('group to view entries'), -label=>$i18n->get('group to view entries'),
@ -605,6 +616,18 @@ sub getRecordTemplateVars {
$var->{tab_loop} = \@tabs; $var->{tab_loop} = \@tabs;
$var->{"form.send"} = WebGUI::Form::submit($self->session,{value=>$i18n->get(73)}); $var->{"form.send"} = WebGUI::Form::submit($self->session,{value=>$i18n->get(73)});
$var->{"form.save"} = WebGUI::Form::submit($self->session,); $var->{"form.save"} = WebGUI::Form::submit($self->session,);
# Create CAPTCHA if configured and user is not a Registered User
if ( $self->useCaptcha ) {
# Create one captcha we can use multiple times
my $captcha
= WebGUI::Form::Captcha( $self->session, {
name => 'captcha',
} );
$var->{ "form.captcha" } = $captcha;
}
$var->{"form.end"} = WebGUI::Form::formFooter($self->session,); $var->{"form.end"} = WebGUI::Form::formFooter($self->session,);
return $var; return $var;
} }
@ -621,24 +644,25 @@ as well as shared template vars.
sub getTemplateVars { sub getTemplateVars {
my $self = shift; my $self = shift;
my $var = $self->get; my $var = $self->get;
my $i18n = WebGUI::International->new($self->session,"Asset_DataForm"); my $i18n = WebGUI::International->new($self->session,"Asset_DataForm");
$var->{canEdit} = ($self->canEdit); $var->{ useCaptcha } = ( $self->useCaptcha ? 1 : 0 );
$var->{canEdit} = ($self->canEdit);
$var->{canViewEntries} = ($self->session->user->isInGroup($self->get("groupToViewEntries"))); $var->{canViewEntries} = ($self->session->user->isInGroup($self->get("groupToViewEntries")));
$var->{"hasEntries"} = $self->hasEntries; $var->{"hasEntries"} = $self->hasEntries;
$var->{"entryList.url"} = $self->getListUrl; $var->{"entryList.url"} = $self->getListUrl;
$var->{"entryList.label"} = $i18n->get(86); $var->{"entryList.label"} = $i18n->get(86);
$var->{"export.tab.url"} = $self->getUrl('func=exportTab'); $var->{"export.tab.url"} = $self->getUrl('func=exportTab');
$var->{"export.tab.label"} = $i18n->get(84); $var->{"export.tab.label"} = $i18n->get(84);
$var->{"addField.url"} = $self->getUrl('func=editField'); $var->{"addField.url"} = $self->getUrl('func=editField');
$var->{"addField.label"} = $i18n->get(76); $var->{"addField.label"} = $i18n->get(76);
$var->{"deleteAllEntries.url"} = $self->getUrl("func=deleteAllEntriesConfirm"); $var->{"deleteAllEntries.url"} = $self->getUrl("func=deleteAllEntriesConfirm");
$var->{"deleteAllEntries.label"} = $i18n->get(91); $var->{"deleteAllEntries.label"} = $i18n->get(91);
$var->{"javascript.confirmation.deleteAll"} = sprintf("return confirm('%s');",$i18n->get('confirm delete all')); $var->{"javascript.confirmation.deleteAll"} = sprintf("return confirm('%s');",$i18n->get('confirm delete all'));
$var->{"javascript.confirmation.deleteOne"} = sprintf("return confirm('%s');",$i18n->get('confirm delete one')); $var->{"javascript.confirmation.deleteOne"} = sprintf("return confirm('%s');",$i18n->get('confirm delete one'));
$var->{"addTab.label"}= $i18n->get(105);; $var->{"addTab.label"}= $i18n->get(105);;
$var->{"addTab.url"}= $self->getUrl('func=editTab'); $var->{"addTab.url"}= $self->getUrl('func=editTab');
$var->{"tab.init"}= $self->_createTabInit($self->getId); $var->{"tab.init"}= $self->_createTabInit($self->getId);
return $var; return $var;
} }
@ -854,6 +878,29 @@ sub sendEmail {
} }
} }
#----------------------------------------------------------------------------
=head2 useCaptcha ( )
Returns true if we should use and process the CAPTCHA.
We should use the CAPTCHA if it is selected in the asset properties and the
user is not a Registered User.
=cut
sub useCaptcha {
my $self = shift;
if ( $self->get('useCaptcha') ) {
if ( !$self->session->user->isInGroup( '2' ) ) {
return 1;
}
}
return 0;
}
#------------------------------------------------------------------- #-------------------------------------------------------------------
sub view { sub view {
my $self = shift; my $self = shift;
@ -1257,65 +1304,107 @@ sub www_moveTabLeft {
#------------------------------------------------------------------- #-------------------------------------------------------------------
sub www_process { sub www_process {
my $self = shift; my $self = shift;
return $self->session->privilege->insufficient() unless $self->canView; return $self->session->privilege->insufficient() unless $self->canView;
my $entryId = $self->setCollateral("DataForm_entry","DataForm_entryId",{ my $session = $self->session;
DataForm_entryId=>$self->session->form->process("entryId") || undef, my $db = $self->session->db;
assetId=>$self->getId, my $i18n = WebGUI::International->new($session,"Asset_DataForm");
userId=>$self->session->user->userId, # TODO: Why do we create the entire entry instead of just generating the entryId
username=>$self->session->user->username, # and only adding the entry data if there are no errors?
ipAddress=>$self->session->env->getIp, my $entryId
submissionDate=>$self->session->datetime->time() = $self->setCollateral("DataForm_entry","DataForm_entryId", {
},0); DataForm_entryId => $session->form->process("entryId") || undef,
my ($var, %row, @errors, $updating, $hadErrors); assetId => $self->getId,
$var = $self->getTemplateVars; userId => $session->user->userId,
$var->{entryId} = $entryId; username => $session->user->username,
my $i18n = WebGUI::International->new($self->session,"Asset_DataForm"); ipAddress => $session->env->getIp,
tie %row, "Tie::CPHash"; submissionDate => $session->datetime->time,
my $sth = $self->session->db->read("select DataForm_fieldId,label,name,status,type,defaultValue,isMailField from DataForm_field }, 0
where assetId=".$self->session->db->quote($self->getId)." order by sequenceNumber"); );
while (%row = $sth->hash) { my $var = $self->getTemplateVars;
my $value = $row{defaultValue}; $var->{entryId} = $entryId;
if ($row{status} eq "required" || $row{status} eq "editable") {
$value = $self->session->form->process($row{name},$row{type},$row{defaultValue}); # Process form
WebGUI::Macro::filter(\$value); my (@errors, $updating, $hadErrors);
} tie my %row, "Tie::CPHash";
if ($row{status} eq "required" && ($value =~ /^\s$/ || $value eq "" || not defined $value)) { my $sth = $self->session->db->read(
push (@errors,{ "SELECT * FROM DataForm_field WHERE assetId=? ORDER BY sequenceNumber",
"error.message"=>$row{label}." ".$i18n->get(29).".", [ $self->getId ]
}); );
$hadErrors = 1; while (%row = $sth->hash) {
delete $var->{entryId}; my $value = $row{defaultValue};
} if ($row{status} eq "required" || $row{status} eq "editable") {
if ($row{status} eq "hidden") { $value = $self->session->form->process($row{name},$row{type},$row{defaultValue});
$value = $row{defaultValue}; WebGUI::Macro::filter(\$value);
WebGUI::Macro::process($self->session,\$value); }
if ($row{status} eq "required" && (!$value || $value =~ /^\s*$/)) {
push @errors, {
"error.message" => $row{label} . " " . $i18n->get(29) . ".",
};
$hadErrors = 1;
delete $var->{entryId};
}
if ($row{status} eq "hidden") {
$value = $row{defaultValue};
WebGUI::Macro::process($self->session,\$value);
}
# Keep adding rows unless there was an error
unless ($hadErrors) {
# Check if this entry / field exists and do what's appropriate
# TODO: This should be refactored into a method
my $exists
= $db->quickScalar(
"SELECT COUNT(*) FROM DataForm_entryData WHERE DataForm_entryId=?
AND DataForm_fieldId=?",
[ $entryId, $row{DataForm_fieldId} ]
);
if ($exists) {
if ( $self->canEdit ) {
$db->write(
"UPDATE DataForm_entryData SET value=?
WHERE DataForm_entryId=? AND DataForm_fieldId=?",
[ $value, $entryId, $row{DataForm_fieldId} ],
);
$updating = 1;
} }
unless ($hadErrors) { } else {
my ($exists) = $self->session->db->quickArray("select count(*) from DataForm_entryData where DataForm_entryId=".$self->session->db->quote($entryId)." $db->write(
and DataForm_fieldId=".$self->session->db->quote($row{DataForm_fieldId})); "INSERT INTO DataForm_entryData ( DataForm_entryId, DataForm_fieldId, assetId, value)
if ($exists) { VALUES ( ?, ?, ?, ? )",
$self->session->db->write("update DataForm_entryData set value=".$self->session->db->quote($value)." [ $entryId, $row{DataForm_fieldId}, $self->getId, $value ],
where DataForm_entryId=".$self->session->db->quote($entryId)." and DataForm_fieldId=".$self->session->db->quote($row{DataForm_fieldId})) if $self->canEdit; );
$updating = 1; }
} else { }
$self->session->db->write("insert into DataForm_entryData (DataForm_entryId,DataForm_fieldId,assetId,value) values }
(".$self->session->db->quote($entryId).", ".$self->session->db->quote($row{DataForm_fieldId}).", ".$self->session->db->quote($self->getId).", ".$self->session->db->quote($value).")"); $sth->finish;
}
} # Process CAPTCHA
} if ( $self->useCaptcha ) {
$sth->finish; if ( !$self->session->form->process( 'captcha', 'captcha' ) ) {
$var->{error_loop} = \@errors; $hadErrors = 1;
$var = $self->getRecordTemplateVars($var); delete $var->{ entryId };
if ($hadErrors && !$updating) { push @errors, {
$self->session->db->write("delete from DataForm_entryData where DataForm_entryId=".$self->session->db->quote($entryId)); "error.message" => $i18n->get( 'error captcha' ),
$self->deleteCollateral("DataForm_entry","DataForm_entryId",$entryId); };
$self->prepareView($var); }
$self->processStyle($self->view); }
} else {
$self->sendEmail($var) if ($self->get("mailData") && !$updating); $var->{error_loop} = \@errors;
return $self->session->style->process($self->processTemplate($var,$self->get("acknowlegementTemplateId")),$self->get("styleTemplateId")) if $self->defaultViewForm; $var = $self->getRecordTemplateVars($var);
} if ($hadErrors && !$updating) {
# TODO: This is not right. See the TODO at the top of this method (where the entry is created)
$db->write(
"DELETE FROM DataForm_entryData WHERE DataForm_entryId=?",
[ $entryId ]
);
$self->deleteCollateral("DataForm_entry","DataForm_entryId",$entryId);
$self->prepareView($var);
$self->processStyle($self->view);
} else {
$self->sendEmail($var) if ($self->get("mailData") && !$updating);
return $self->session->style->process($self->processTemplate($var,$self->get("acknowlegementTemplateId")),$self->get("styleTemplateId")) if $self->defaultViewForm;
}
} }

View file

@ -100,11 +100,16 @@ Returns a boolean indicating whether the string typed matched the image.
=cut =cut
sub getValue { sub getValue {
my $self = shift; my $self = shift;
my $value = $self->SUPER::getValue(@_); my $value = $self->SUPER::getValue(@_);
my $challenge = $self->session->scratch->get("captcha_".$self->get("name")); my $challenge = $self->session->scratch->get("captcha_".$self->get("name"));
$self->session->scratch->delete("captcha_".$self->get("name")); $self->session->scratch->delete("captcha_".$self->get("name"));
return (lc($value) eq lc($challenge)); my $passed = lc $value eq lc $challenge;
$self->session->errorHandler->info(
"Checking CAPTCHA '" . $self->get("name") . "': " . ( $passed ? "PASSED!" : "FAILED!" )
. " Got: '" . $value . "', Wanted: '" . $challenge . "'"
);
return $passed;
} }
#------------------------------------------------------------------- #-------------------------------------------------------------------

View file

@ -111,7 +111,18 @@ our $HELP = {
}, },
{ 'required' => 1, { 'required' => 1,
'name' => 'form.end' 'name' => 'form.end'
} },
{
name => 'useCaptcha',
required => 1,
description => 'helpvar useCaptcha',
},
{
name => 'form.captcha',
required => 1,
description => 'helpvar form.captcha',
},
], ],
related => [ related => [
{ tag => 'data form list template', { tag => 'data form list template',

View file

@ -955,6 +955,42 @@ be useful, others may not.|,
lastUpdated => 1164910794, lastUpdated => 1164910794,
}, },
'error captcha' => {
message => q{CAPTCHA entered incorrectly. Please try again.},
lastUpdated => 0,
context => q{Error message for CAPTCHA "Verify Your Humanity" failure},
},
'template captcha label' => {
message => q{Verify Your Humanity},
lastUpdated => 0,
context => q{Label for CAPTCHA field in data form},
},
'editForm useCaptcha label' => {
message => q{Use Captcha for Visitors?},
lastUpdated => 0,
context => q{Label for asset property},
},
'editForm useCaptcha description' => {
message => q{If 'yes', the DataForm will require a CAPTCHA for Visitors. Registered users
will not see the CAPTCHA.},
lastUpdated => 0,
context => q{Description of asset property},
},
'helpvar useCaptcha' => {
message => q{This variable is true when the CAPTCHA should be shown.},
lastUpdated => 0,
context => q{Description of template variable},
},
'helpvar form.captcha' => {
message => q{The input field and image for the CAPTCHA},
lastUpdated => 0,
context => q{Description of template variable},
},
}; };
1; 1;