From c09b2cae1b512f22fc46706d0cfa2c9a71ab34a5 Mon Sep 17 00:00:00 2001 From: James Tolley Date: Tue, 29 May 2007 23:39:24 +0000 Subject: [PATCH] EMS import/export, Form::*::getValueFromPost(alt_values), and tests --- .../Asset/Wobject/EventManagementSystem.pm | 990 +++++++++++++++++- lib/WebGUI/Form/Checkbox.pm | 16 +- lib/WebGUI/Form/ClassName.pm | 8 +- lib/WebGUI/Form/Color.pm | 12 +- lib/WebGUI/Form/Combo.pm | 14 +- lib/WebGUI/Form/Control.pm | 16 +- lib/WebGUI/Form/Date.pm | 10 +- lib/WebGUI/Form/DateTime.pm | 10 +- lib/WebGUI/Form/Email.pm | 8 +- lib/WebGUI/Form/Float.pm | 14 +- lib/WebGUI/Form/Group.pm | 4 +- lib/WebGUI/Form/HTMLArea.pm | 8 +- lib/WebGUI/Form/HexSlider.pm | 2 +- lib/WebGUI/Form/Hexadecimal.pm | 6 +- lib/WebGUI/Form/Hidden.pm | 6 +- lib/WebGUI/Form/IntSlider.pm | 9 +- lib/WebGUI/Form/Integer.pm | 14 +- lib/WebGUI/Form/Interval.pm | 12 +- lib/WebGUI/Form/List.pm | 10 +- lib/WebGUI/Form/Phone.pm | 16 +- lib/WebGUI/Form/Radio.pm | 8 +- lib/WebGUI/Form/SelectBox.pm | 11 +- lib/WebGUI/Form/SelectList.pm | 4 +- lib/WebGUI/Form/SelectSlider.pm | 10 +- lib/WebGUI/Form/Text.pm | 15 +- lib/WebGUI/Form/TimeField.pm | 23 +- lib/WebGUI/Form/Url.pm | 2 +- lib/WebGUI/Form/YesNo.pm | 28 +- lib/WebGUI/Form/Zipcode.pm | 16 +- .../Help/Asset_EventManagementSystem.pm | 99 ++ lib/WebGUI/SQL.pm | 28 +- lib/WebGUI/Session/DateTime.pm | 16 +- lib/WebGUI/Session/Env.pm | 10 +- lib/WebGUI/Session/Form.pm | 139 +-- .../English/Asset_EventManagementSystem.pm | 267 ++++- t/Form/Checkbox.t | 7 +- t/Form/ClassName.t | 7 +- t/Form/Email.t | 13 +- t/Form/Float.t | 10 +- t/Form/Integer.t | 20 +- t/Form/Phone.t | 16 +- t/Form/SelectBox.t | 19 +- t/Form/Text.t | 16 +- t/Form/Textarea.t | 15 +- t/Form/Url.t | 23 +- t/Form/Zipcode.t | 20 +- 46 files changed, 1728 insertions(+), 299 deletions(-) diff --git a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm index 7d075327d..d497410d2 100644 --- a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm +++ b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm @@ -27,7 +27,10 @@ use WebGUI::Operation::Commerce; use WebGUI::Commerce::ShoppingCart; use WebGUI::Commerce::Item; use WebGUI::Utility; -#use Data::Dumper; +use Text::CSV_XS; +use IO::Handle; +use File::Temp 'tempfile'; +use Data::Dumper; @@ -167,10 +170,11 @@ sub _acWrapper { $ac->addSubmenuItem($self->getUrl('func=managePrereqSets'), $i18n->get('manage prerequisite sets')); $ac->addSubmenuItem($self->getUrl('func=manageRegistrants'), $i18n->get('manage registrants')); $ac->addSubmenuItem($self->getUrl('func=manageDiscountPasses'), $i18n->get('manage discount passes')); + $ac->addSubmenuItem($self->getUrl('func=importEvents'), $i18n->get('import events')); + $ac->addSubmenuItem($self->getUrl('func=exportEvents'), $i18n->get('export events')); return $ac->render($html,$title); } - #------------------------------------------------------------------- sub _matchPairs { @@ -405,27 +409,34 @@ sub checkConflicts { #------------------------------------------------------------------- -=head2 checkRequiredFields ( requiredFields ) +=head2 checkRequiredFields ( [ dataHref ] [, recNum ] ) Check for null form fields. Returns an array reference containing error messages -=head3 requiredFields +=head3 dataHref -A hash reference whose keys correspond to field names and values correspond to the field name as it should be shown to the user in an error. +An href with the data for the event that we want to check. If absent, then the current form submission is used. + +=head3 recNum + +The number of the record, for error reporting =cut sub checkRequiredFields { my $self = shift; - my $requiredFields = shift; + my $event_data_href = shift || $self->session->form->paramsHashRef(); + my $rec_num = shift || ''; + + my $requiredFields = $self->getRequiredFields(); my @errors; foreach my $requiredField (keys %{$requiredFields}) { - if ($self->session->form->get($requiredField) eq "") { + if ($event_data_href->{$requiredField} eq "") { push(@errors, { - type => "nullField", + type => "nullField$rec_num", fieldName => $requiredFields->{"$requiredField"} } ); @@ -650,8 +661,14 @@ sub error { foreach my $error (@$errors) { #Null Field Error - if ($error->{type} eq "nullField") { - push(@errorMessages, sprintf($i18n->get('null field error'),$error->{fieldName})); + if ($error->{type} =~ m/nullField(\d*)/) { + my $num = $1 || ''; # there's a record number stuck in here, if they're doing a batch import of events + if ($num) { + push(@errorMessages, sprintf($i18n->get('null field error recnum'),$error->{fieldName},$num)); + } + else { + push(@errorMessages, sprintf($i18n->get('null field error'),$error->{fieldName})); + } } #General Error Message @@ -843,14 +860,16 @@ sub getEventMetaDataFields { my $globalWhere = ($useGlobalMetadata == 0 || $useGlobalMetadata == 'false')?" where f.assetId='".$self->getId."'":''; my $sql = "select f.*, d.fieldData from EventManagementSystem_metaField f - left join EventManagementSystem_metaData d on f.fieldId=d.fieldId and d.productId=".$self->session->db->quote($productId)." $globalWhere order by f.sequenceNumber"; - tie my %hash, 'Tie::IxHash'; - my $sth = $self->session->db->read($sql); - while( my $h = $sth->hashRef) { - foreach(keys %$h) { - $hash{$h->{fieldId}}{$_} = $h->{$_}; - } + left join EventManagementSystem_metaData d on f.fieldId=d.fieldId + and d.productId=".$self->session->db->quote($productId)." $globalWhere + order by f.sequenceNumber"; + tie my %hash, 'Tie::IxHash'; + my $sth = $self->session->db->read($sql); + while( my $h = $sth->hashRef) { + foreach(keys %$h) { + $hash{$h->{fieldId}}{$_} = $h->{$_}; } + } $sth->finish; return \%hash; } @@ -1277,6 +1296,33 @@ sub getAllPossibleRequiredEvents { } +#------------------------------------------------------------------ + +=head2 getAllStdEventDetails ( ) + +Get an aref hrefs of information for all events in this EMS. The information is the result of joining the products and EMS_products tables. + +=cut + +sub getAllStdEventDetails { + my $self = shift; + + if ($self->{_allEventDetails}) { + return $self->{_allEventDetails}; + } + + my $sql = <<""; + SELECT * + FROM products p, EventManagementSystem_products e + WHERE p.productId = e.productId + AND e.assetId = ? + ORDER BY e.sequenceNumber + + + $self->{_allEventDetails} = $self->session->db->buildArrayRefOfHashRefs($sql, [$self->getId]); + return $self->{_allEventDetails}; +} + #------------------------------------------------------------------ sub getEventDetails { my $self = shift; @@ -1378,28 +1424,28 @@ sub verifyPrerequisitesForm { #------------------------------------------------------------------ -=head2 validateEditEventForm ( ) +=head2 getRequiredFields ( ) -Returns array reference containing any errors generated while validating the input of the Add/Edit Event Form +Returns the required fiends as ordered hash of fieldname => $readable pairs. MetaFields are paired like so: metadata_[fieldId] => $readable. =cut -sub validateEditEventForm { - my $self = shift; - my $errors; - my $i18n = WebGUI::International->new($self->session, 'Asset_EventManagementSystem'); +sub getRequiredFields { + my $self = shift; - my %requiredFields; - tie %requiredFields, 'Tie::IxHash'; + my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); - #-----Form name--------------User Friendly Name----# - %requiredFields = ( - "title" => $i18n->get("add/edit event title"), - "description" => $i18n->get("add/edit event description"), - "price" => $i18n->get("price"), - "maximumAttendees" => $i18n->get("add/edit event maximum attendees"), - "sku" => $i18n->get("sku"), - ); + my %requiredFields; + tie %requiredFields, 'Tie::IxHash'; + + #-----Form name--------------User Friendly Name----# + %requiredFields = ( + "title" => $i18n->get("add/edit event title"), + "description" => $i18n->get("add/edit event description"), + "price" => $i18n->get("price"), + "maximumAttendees" => $i18n->get("add/edit event maximum attendees"), + "sku" => $i18n->get("sku"), + ); my $mdFields = $self->getEventMetaDataFields; foreach my $mdField (keys %{$mdFields}) { @@ -1407,28 +1453,41 @@ sub validateEditEventForm { $requiredFields{'metadata_'.$mdField} = $mdFields->{$mdField}->{name}; } - $errors = $self->checkRequiredFields(\%requiredFields); + return \%requiredFields; +} - #Check price greater than zero - if ($self->session->form->get("price") < 0) { - push (@{$errors}, { - type => "general", - message => $i18n->get("price must be greater than zero"), - } - ); - } - if ($self->session->form->get("pid") eq "meetmymaker") { - push (@{$errors}, { - type => "special", - message => '/26T@new($self->session, 'Asset_EventManagementSystem'); + + $errors = $self->checkRequiredFields; + + #Check price greater than zero + if ($self->session->form->get("price") < 0) { + push (@{$errors}, { + type => "general", + message => $i18n->get("price must be greater than zero"), + }); + } + if ($self->session->form->get("pid") eq "meetmymaker") { # TODO - could this be more opaque? + push (@{$errors}, { + type => "special", + message => '/26T@getAdminConsole->setHelp(lc($tag)." add/edit", "Asset_".$tag2); - my $i18n = WebGUI::International->new($self->session,'Asset_Wobject'); + my $i18n = WebGUI::International->new($self->session,'Asset_Wobject'); + my $i18n2 = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); my $addEdit = ($self->session->form->process("func") eq 'add') ? $i18n->get('add') : $i18n->get('edit'); $self->getAdminConsole->addSubmenuItem($self->getUrl('func=manageEventMetadata'), $i18n->get('manage event metadata', 'Asset_EventManagementSystem')); $self->getAdminConsole->addSubmenuItem($self->getUrl('func=manageEvents'), $i18n->get('manage events', 'Asset_EventManagementSystem')); + $self->getAdminConsole->addSubmenuItem($self->getUrl('func=importEvents'), $i18n2->get('import events')); + $self->getAdminConsole->addSubmenuItem($self->getUrl('func=exportEvents'), $i18n2->get('export events')); return $self->getAdminConsole->render($self->getEditForm->print,$addEdit.' '.$self->getName); } @@ -1951,7 +2013,12 @@ changePassType(); my $val = $self->session->form->process("metadata_".$meta->{$field->{fieldId}}{fieldId},$dataType); if(!$val || (ref $val eq "ARRAY" && scalar(@{$val}) == 0 ) ) { - $val = $meta->{$field->{fieldId}}{fieldData}; + if (lc $dataType eq 'timefield') { + $val = $self->session->datetime->secondsToTime($meta->{$field->{fieldId}}{fieldData}); + } + else { + $val = $meta->{$field->{fieldId}}{fieldData}; + } } $f->dynamicField( @@ -1990,7 +2057,7 @@ sub www_editEventSave { if (scalar(@$errors) > 0) { return $self->error($errors, "www_editEvent"); } my $pid = $self->session->form->get("pid"); - my $eventIsNew = 1 if ($pid eq "" || $pid eq "new"); + my $eventIsNew = 1 if ($pid eq "" || $pid eq "new"); my $event; my $storageId; $storageId = $self->session->form->process("image","image",undef,{name=>"image", value=>$storageId}) || ''; @@ -2077,6 +2144,821 @@ sub www_manageEventMetadata { #------------------------------------------------------------------- +=head2 www_test ( ) + +Test WebGUI::Form::*::getValueFromPost methods used in www_doImportEvents + +=cut + +sub www_test { + my $self = shift; + # if there's no input, output a form + my @param = $self->session->form->param(); + if (@param <= 1) { + my $f = WebGUI::HTMLForm->new($self->session, action => $self->getUrl("func=test"), ); + + #$f->Asset(); + #$f->Button(); + #$f->Captcha(); + $f->CheckList( + -name => "checkList", + -label => 'Checklist', + -options => { 1, one => 2, two => 3, 'three' }, + -value => [1,2], + ); + $f->Checkbox( + -name => 'checkbox', + -label => 'Checkbox', + -value => 42, + -checked=> 1, + ); + #$f->ClassName(); + #$f->Codearea(); + #$f->Color(); + #$f->Combo(); + #$f->ContentType(); + #$f->Control(); + #$f->Country(); + #$f->DatabaseLink(); + $f->Date( + -name => 'date', + -label => 'Date', + -value => 770000000, # ? + ); + $f->DateTime( + -name => 'dateTime', + -label => 'DateTime', + -value => 770000045, # ? + ); + #$f->DynamicField(); + #$f->Email(); + #$f->FieldType(); + #$f->File(); + #$f->FilterContent(); + $f->Float( + -name => 'float', + -label => 'Float', + -value => 42.42, + ); + #$f->Group(); + #$f->HTMLArea(); + #$f->HexSlider(); + #$f->Hexadecimal(); + #$f->Hidden(); + $f->HiddenList( + -name => "hiddenList", + -label => 'Hiddenlist', + -options => { 1, one => 2, two => 3, 'three' }, + -value => [1,2], + ); + #$f->Image(); + #$f->IntSlider(); + $f->Integer( + -name => 'integer', + -label => 'Integer', + -value => 42, + ); + $f->Interval( + -name => 'interval', + -label => 'Interval', + -value => '86400', + ); + #$f->LdapLink(); + #$f->List(); + #$f->MimeType(); + #$f->Password(); + #$f->Phone(); + #$f->Radio(); + #$f->RadioList(); + #$f->ReadOnly(); + #$f->SelectBox(); + $f->SelectList( + -name => "selectList", + -label => 'Selectlist', + -options => { 1, one => 2, two => 3, 'three' }, + -value => [1,2], + ); + #$f->SelectSlider(); + #$f->Slider(); + #$f->Submit(); + #$f->Template(); + $f->Text( + -name => 'text', + -label => 'Text', + -value => 'text', + ); + $f->Text( + -name => 'text-empty', + -label => 'Text', + -value => '', + ); + $f->Textarea( + -name => 'textarea', + -label => 'Textarea', + -value => "text\n\narea", + ); + $f->TimeField( + -name => 'timeField', + -label => 'TimeField', + -value => '12:12:12', + ); + $f->TimeField( + -name => 'timeField-nosecs', + -label => 'TimeField', + -value => '12:12', + ); + #$f->TimeZone(); + #$f->Url(); + #$f->User(); + #$f->WhatNext(); + #$f->Workflow(); + $f->YesNo( + -name => 'yesNo', + -label => 'YesNo', + -value => 1, + ); + $f->YesNo( + -name => 'yesNo-no', + -label => 'YesNo', + -value => 0, + ); + #$f->Zipcode(); + + $f->submit(-value=>'Run tests'); + return $self->_acWrapper($f->print, "test"); + } + # there's input, so test the input + else { + my $form = $self->session->form; + + my $html = ''; + for my $param (sort @param) { + next if $param eq 'func' || $param =~ /interval/i; + + # this lets us have multiple fields with the same type: text, text-empty, etc + $param =~ /^(\w+)/ or return $self->_acWrapper("There was an error with param '$param'","test"); + my $type = $1; + my @raw = $form->process($param); + my $std = $form->process($param, $type); + my $offline = $form->$type(undef, @raw); + + if ($std eq $offline and $std == $offline) { + $html .= "'$param': raw: '@raw'; std: '$std'; offline: '$offline'

"; + } + else { + $html .= "'$param': raw: '@raw'; std: '$std'; offline: '$offline'

"; + } + } + + # do the interval test + my $num = $form->process('interval_interval'); + my $units = $form->process('interval_units'); + my $std_interval = $form->process('interval', 'interval'); + my $offline_interval = $form->interval(undef, "$num $units"); # pass in as it would be in an import file + + if ($std_interval eq $offline_interval and $std_interval == $offline_interval) { + $html .= "'interval': raw: '$num $units'; std: '$std_interval'; offline: '$offline_interval'

"; + } + else { + $html .= "'interval': raw: '$num $units'; std: '$std_interval'; offline: '$offline_interval'

"; + } + + + # canned tests for things like all empty checkbox groups and yesNo fields + $html .= "

Other tests

"; + + # empty checkList + my $cl = $form->checkList(undef, ''); # passing an empty list here is not going to work + if ($cl eq '') { + $html .= "empty CheckList is: ''

"; + } + else { + $html .= "empty CheckList is: '$cl'

"; + } + + # empty date + my $date = $form->date(undef, ''); + if ($date eq '') { + $html .= "empty Date is: ''

"; + } + else { + $html .= "empty Date is: '$date'

"; + } + + # empty datetime + my $dt = $form->dateTime(undef, ''); + if ($dt eq '') { + $html .= "empty DateTime is: ''

"; + } + else { + $html .= "empty DateTime is: '$dt'

"; + } + + # empty hiddenList + my $hl = $form->hiddenList(undef, ''); # passing an empty list here is not going to work + if ($hl eq '') { + $html .= "empty HiddenList is: ''

"; + } + else { + $html .= "empty HiddenList is: '$hl'

"; + } + + # empty selectList + my $sl = $form->selectList(undef, ''); # passing an empty list here is not going to work + if ($sl eq '') { + $html .= "empty SelectList is: ''

"; + } + else { + $html .= "empty SelectList is: '$sl'

"; + } + + # empty timeField + my $std_tf = $form->process('doesnotexist', 'timeField'); + my $tf = $form->timeField(undef, ''); # passing an empty list here is not going to work + if ($tf eq $std_tf) { + $html .= "empty TimeField is: '$std_tf'

"; + } + else { + $html .= "empty TimeField is: '$tf' (not '$std_tf')

"; + } + + # yesNo + my $yn = $form->yesNo(undef, ''); + if ($yn eq '') { + $html .= "empty yesNo is: ''

"; + } + else { + $html .= "empty yesNo is: '$yn'

"; + } + + + return $self->_acWrapper("

$html
", "test"); + } +} + +#------------------------------------------------------------------- + +=head2 www_exportEvents ( ) + +Method to deliver this EMS's events in CSV format. + +=cut + +sub www_exportEvents { + my $self = shift; + + return $self->session->privilege->insufficient unless $self->canAddEvents; + + my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); + my $csv = Text::CSV_XS->new({ eol => "\n", binary => 1 }); # TODO use their newline? + + # if we need to punt + my @error_args = ($i18n->get('export error'), $i18n->get('export events')); + + # get standard & metaField labels TODO - refactor this + my @std_labels = map $i18n->get($_), ( 'status', 'add/edit event title', 'add/edit event description', + 'add/edit event image', 'add/edit useSalesTax', 'price', 'add/edit event template', 'weight', 'sku', + 'sku template', 'add/edit event start date', 'add/edit event end date', 'add/edit event maximum attendees', + 'prereq set name field label' ); + + my $meta_fields_aref = $self->getEventMetaDataArrayRef; + my @meta_labels = map $_->{label}, @$meta_fields_aref; + my @all_labels = (@std_labels, @meta_labels); + + # combine field labels for first line of CSV output + return $self->_acWrapper(@error_args) + unless $csv->combine(@all_labels); + my $csvdata = $csv->string(); + + # get events of this EMS + my $events_std_data_aref = $self->getAllStdEventDetails; + + # get the prereqs + my $prereqs_href = $self->session->db->buildHashRef(<<""); + SELECT prerequisiteId, name + FROM EventManagementSystem_prerequisites + + my $templates_href = $self->session->db->buildHashRef(<<""); + SELECT template.assetId, assetData.title + FROM template + LEFT JOIN assetData + ON assetData.assetId = template.assetId + AND assetData.revisionDate = template.revisionDate + + # format useSalesTax(yes/no), startDate, endDate, and approved values + my $dt = $self->session->datetime; + for my $event (@$events_std_data_aref) { + $event->{approved} = $self->getEventStateLabel($event->{approved}); + $event->{startDate} = $dt->epochToSet($event->{startDate},1); + $event->{endDate} = $dt->epochToSet($event->{endDate},1); + $event->{useSalesTax} = $event->{useSalesTax} ? 'Y' : 'N'; + $event->{prerequisiteId} = $prereqs_href->{$event->{prerequisiteId}}; + $event->{templateId} = $templates_href->{$event->{templateId}}; + } + + # standard field names in the same order as the web forms + my @std_fields = qw( approved title description imageId useSalesTax price templateId weight sku + skuTemplate startDate endDate maximumAttendees prerequisiteId); + + # for each event, gather std & meta data & create CSV record + for my $std_data_href (@$events_std_data_aref) { + # get the std data + my @std_data = map $std_data_href->{$_}, @std_fields; + + # get the meta data + my ($meta_data_href) = $self->getEventMetaDataFields($std_data_href->{productId}, $self->get("globalMetadata")); + my @meta_data = (); + for my $meta_field_config_href (@$meta_fields_aref) { + # get the value for this field, depending on the dataType + my $value = $meta_data_href->{$meta_field_config_href->{fieldId}}->{fieldData}; + + # format some field types + # if the type is, then the value is + my $readable = $meta_field_config_href->{dataType} eq 'Date' ? $dt->epochToSet($value) + : $meta_field_config_href->{dataType} eq 'DateTime' ? $dt->epochToSet($value,1) + : $meta_field_config_href->{dataType} eq 'YesNo' ? ( $value ? 'Y' : length($value) ? 'N' : '' ) + : $meta_field_config_href->{dataType} eq 'TimeField' ? $dt->secondsToTime($value) + : $value + ; + + $readable =~ s/\n/;/g; + push @meta_data, $readable; + } + + # create CSV record for this event or display error message + if ($csv->combine(@std_data, @meta_data)) { + $csvdata .= $csv->string(); + } + else { + return $self->_acWrapper(@error_args); + } + } + + # no errors, output file as attachment + my $filename = $self->session->db->quickScalar(" SELECT title FROM assetData WHERE assetId = ? ", [ $self->getId ]); + $filename =~ s/[^-\w.]//g; # old-school + $self->session->http->setFilename("$filename.csv", 'application/excel'); + return $csvdata; +} + +#------------------------------------------------------------------- + +=head2 getEventDataFields ( ) + +Returns a form-field ordered aref of hrefs of event data fields (standard and meta) with these keys: name, label, type, and required. + +=cut + +sub getEventDataFields { + my $self = shift; + + my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); + + my $custom_rows_aref = $self->getEventMetaDataArrayRef; + my @custom_rows = map { + label => $_->{label}, + name => "metadata_$_->{fieldId}", + required => $_->{required}, + type => $_->{dataType}, + }, @$custom_rows_aref; + + return [ + # std fields + { label => $i18n->get('status'), name => 'approved', required => 0, type => 'text' }, + { label => $i18n->get('add/edit event title'), name => 'title', required => 1, type => 'text' }, + { label => $i18n->get('add/edit event description'), name => 'description', required => 1, type => 'HTMLArea' }, + { label => $i18n->get('add/edit event image'), name => 'imageId', required => 0, type => 'text' }, + { label => $i18n->get('add/edit useSalesTax'), name => 'useSalesTax', required => 0, type => 'yesNo' }, + { label => $i18n->get('price'), name => 'price', required => 1, type => 'float' }, + { label => $i18n->get('add/edit event template'), name => 'templateId', required => 0, type => 'template' }, + { label => $i18n->get('weight'), name => 'weight', required => 0, type => 'float' }, + { label => $i18n->get('sku'), name => 'sku', required => 1, type => 'text' }, + { label => $i18n->get('sku template'), name => 'skuTemplate', required => 0, type => 'text' }, + { label => $i18n->get('add/edit event start date'), name => 'startDate', required => 0, type => 'dateTime' }, + { label => $i18n->get('add/edit event end date'), name => 'endDate', required => 0, type => 'dateTime' }, + { label => $i18n->get('add/edit event maximum attendees'), name => 'maximumAttendees', required => 1, type => 'integer' }, + { label => $i18n->get('prereq set name field label'), name => 'prerequisiteId', required => 0, type => 'text' }, + + @custom_rows, + ]; +} + +#------------------------------------------------------------------- + +=head2 www_importEvents ( [ $errors_aref ] ) + +Show the CSV-file upload form, along with optional errors. + +=cut + +sub www_importEvents { + my ($self) = shift; + my $errors_aref = shift || []; + + return $self->session->privilege->insufficient unless $self->canAddEvents; + my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); + my $form = $self->session->form; + + # header, with optional errors as unordered list + my $page_header = $i18n->get('import form header'); + if (@$errors_aref) { + $page_header .= "
    "; + for my $error_msg (@$errors_aref) { + $page_header .= "
  • $error_msg
  • "; + } + $page_header .= "
"; + } + + # create the form + my $f = WebGUI::HTMLForm->new( $self->session, action => $self->getUrl("func=doImportEvents"), enctype => 'multipart/form-data' ); + + $f->file( + -label => $i18n->get('choose a file to import'), + -hoverHelp => $i18n->get('import hoverhelp file'), + -name => 'file', + ); + $f->selectBox( + -label => $i18n->get('what about duplicates'), + -name => 'duplicates_how', + -hoverHelp => $i18n->get('import hoverhelp dups'), + -value => ($form->param('duplicates_how')||'skip'), + -options => { + skip => $i18n->get('skip'), + overwrite => $i18n->get('overwrite'), + }, + ); + $f->radioList( + -label => $i18n->get('ignore first line'), + -name => 'ignore_first_line', + -hoverHelp => $i18n->get('import hoverhelp first line'), + -value => ($form->param('ignore_first_line')||'no'), + -options => { + yes => $i18n->get('yes'), + no => $i18n->get('no'), + }, + ); + $f->fieldSetStart('Fields'); + $f->raw(q[ ]); + + # create the std & meta fields part of the form + my $rows_aref = $self->getEventDataFields; # form-field ordered aref of hrefs with these keys: name, label, required, type + my %row_data = map { $_->{name}, $_ } @$rows_aref; + for my $row (@$rows_aref) { + $f->raw(qq[ ]); + } + + $f->raw(q[
  ]. + q[ File Contains FieldField Is Duplicate Key
$row->{label} ]); + # insert the first checkbox + $f->raw(WebGUI::Form::Checkbox->new( + $self->session,{ + -name => "file_contains-$row->{name}", + -value => 1, + -checked => ($row_data{$row->{name}}->{required} || $form->param("file_contains-$row->{name}")), + })->toHtml()); + $f->raw(qq[ ]); + # insert the second checkbox + $f->raw(WebGUI::Form::Checkbox->new( + $self->session,{ + -name => "check_duplicates-$row->{name}", + -value => 1, + -checked => $form->param("check_duplicates-$row->{name}"), + })->toHtml()); + $f->raw(qq[
]); + $f->fieldSetEnd; + $f->submit(-value=>$i18n->get('import events')); + + $self->getAdminConsole->setHelp('import events','Asset_EventManagementSystem'); + return $self->_acWrapper($page_header.'

'.$f->print, $i18n->get('import events')); +} + +#------------------------------------------------------------------- + +=head2 doImportEvents ( ) + +Handle the uploading of a CSV event data file, along with other options. + +=cut + +my $max_errors = 10; # number of errors to collect before showing them, when we're in error-collecting mode. +sub www_doImportEvents { + my $start_time = time; + my $self = shift; + + return $self->session->privilege->insufficient unless $self->canAddEvents; + my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); + my $csv = Text::CSV_XS->new({ binary => 1 }); + my $no_action_taken_error = { # on error, always let the user know that we didn't partially import their data + type => 'general', + message => $i18n->get("no import took place"), + }; + + # get input: CSV data + my $storageId = $self->session->form->param("file_file"); + my $storage = WebGUI::Storage->get($self->session, $storageId); + return $self->error([{ type => 'general', message => $i18n->get("enter import file") }], 'www_importEvents') + unless $storage; + my $filename = $storage->addFileFromFormPost("file_file"); + my $csv_data = $storage->getFileContentsAsScalar($filename); + $storage->delete; + + # store the input on disk for processing - TODO can we do this whole thing more easily? + my $fh = tempfile(); + print $fh $csv_data; + seek $fh, 0, 0; + + # organize meta input: sorted fields included and duplicate keys + my $skip_duplicates = $self->session->form->process('duplicates_how') eq 'skip' ? 1 : 0; + my $ignore_first_line = $self->session->form->process('ignore_first_line') eq 'yes' ? 1 : 0; + my @params = $self->session->form->param(); + my @fields_included = grep s/^file_contains-(.+)$/$1/, @params; + my @dup_keys = grep s/^check_duplicates-(.+)$/$1/, @params; + return $self->error([$no_action_taken_error,{ + type => 'general', + message => $i18n->get('import need dup key'), + }], 'www_importEvents') unless @dup_keys; + my @all_data_fields = @{ $self->getEventDataFields() }; # aref of sorted hrefs with name, label, required, type keys + my $sku_is_required = grep { $_ eq 'sku' } @dup_keys; + if (!$sku_is_required) { + for my $field (@all_data_fields) { $field->{required} = 0 if $field->{name} eq 'sku' } # not required here + } + my @sorted_fields_included = (); + for my $field (@all_data_fields) { + if (grep { $_ eq $field->{name} } @fields_included) { + push @sorted_fields_included, $field->{name}; + } + } + my @missing_required_fields = (); + for my $field (grep $_->{required}, @all_data_fields) { + if (!grep { $_ eq $field->{name} } @fields_included) { + push @missing_required_fields, $field->{label}; + } + } + if (@missing_required_fields) { + return $self->error([$no_action_taken_error,{ + type => 'general', + message => $i18n->get('check required fields')."@missing_required_fields", + }], + 'www_importEvents', + ); + } + + # we sanity check all of the input before processing any of it + # check all records for required fields and field count + my $errors = []; + my $prerequisites_href = {}; + if (grep /^prerequisiteId$/, @fields_included) { + $prerequisites_href = $self->session->db->buildHashRef(" SELECT name, prerequisiteId FROM EventManagementSystem_prerequisites"); + } + my $templates_href = {}; + if (grep /^templateId$/, @fields_included) { + $templates_href = $self->session->db->buildHashRef(<<""); + SELECT assetData.title, template.assetId + FROM template + LEFT JOIN assetData + ON assetData.assetId = template.assetId + AND assetData.revisionDate = template.revisionDate + + } + my %approved_values = ( Approved => 1, Denied => 0, Pending => -1, Cancelled => -2); + my $meta_fields_aref = $self->getEventMetaDataArrayRef; + my %meta_fields = (); + @meta_fields{map {$_->{fieldId}} @$meta_fields_aref} = @$meta_fields_aref; # get them keyed by fieldId + my $first_line = 1; + my $before_check_time = time; + while (my $line = do { local $/ = "\n"; <$fh> }) { + if ($first_line and $ignore_first_line) { + $first_line = 0; + next; + } + + # line is blank - skip it, no error + next if $line =~ /^[\s\r\n]*$/; + + # parse the line + if (!$csv->parse($line)) { + my $error_input = $csv->error_input; + push @$errors,{ + type => 'general', # "There was an error processing this input: '$line'" + message => sprintf $i18n->get('import record parse error'), + $fh->input_line_number - $ignore_first_line, $error_input, + }; + if (@$errors >= $max_errors) { + return $self->error($errors, 'www_importEvents'); + } + next; + } + + my @columns = $csv->fields(); + + # check the field count + if (@columns != @fields_included) { + push @$errors,{ + type => 'general', + message => sprintf $i18n->get('field count mismatch'), $fh->input_line_number-$ignore_first_line, scalar @columns, scalar @fields_included, + }; + if (@$errors >= $max_errors) { + return $self->error($errors, 'www_importEvents'); + } + next; + } + # check the required fields + my %data = map { $sorted_fields_included[$_], $columns[$_] } 0..$#columns; + $data{sku} ||= 'do not check this here - we will create one later if necessary' unless $sku_is_required; + my $new_errors = $self->checkRequiredFields(\%data, $fh->input_line_number-$ignore_first_line); + if (@$new_errors) { + push @$errors, @$new_errors; + return $self->error([$no_action_taken_error,@$errors], 'www_importEvents') if @$errors >= $max_errors; + } + #check that approved, if present, is a good value + if (exists $data{approved} && ! grep { lc $_ eq lc $data{approved} } %approved_values) { + push @$errors, { + type => 'general', + message => sprintf $i18n->get('import invalid status'), $fh->input_line_number-$ignore_first_line, $data{approved}, + }; + return $self->error([$no_action_taken_error,@$errors], 'www_importEvents') if @$errors >= $max_errors; + } + #check that prerequisiteId, if present, is a good value + if (exists $data{prerequisiteId} && !exists $prerequisites_href->{$data{prerequisiteId}}) { + push @$errors, { + type => 'general', + message => sprintf $i18n->get('import invalid prereq'), $fh->input_line_number-$ignore_first_line, $data{prerequisiteId}, + }; + return $self->error([$no_action_taken_error,@$errors], 'www_importEvents') if @$errors >= $max_errors; + } + #check that templateId, if present, is a good value + if (exists $data{templateId} && !exists $templates_href->{$data{templateId}}) { + push @$errors, { + type => 'general', + message => sprintf $i18n->get('import invalid template'), $fh->input_line_number-$ignore_first_line, $data{templateId}, + }; + return $self->error([$no_action_taken_error,@$errors], 'www_importEvents') if @$errors >= $max_errors; + } + } + my $after_check_time = time; + + # errors? output them instead of proceeding with the import + return $self->error([$no_action_taken_error,@$errors], 'www_importEvents') if @$errors; + + # organize our existing events by duplicate keys + my %duplicate_events = (); + for my $event_href (@{ $self->getAllStdEventDetails }) { + my $event_meta_data_href = $self->getEventMetaDataFields($event_href->{productId}); + my $dup_key = join '|', map { /^metadata_(.+)/ ? $event_meta_data_href->{$1}->{fieldData} : $event_href->{$_} } @dup_keys; + $duplicate_events{$dup_key} = $event_href->{productId}; + } + + # input is deemed sane - time to process it + my $total_lines = $fh->input_line_number; + seek $fh, 0, 0; # start of the file, again + my %all_data_fields; + @all_data_fields{map $_->{name}, @all_data_fields} = @all_data_fields; # by name + my $existing_events_aref = $self->getAllStdEventDetails; + $first_line = 1; + my @skipped = (); + my @overwritten = (); + my @blank_lines = (); + my $before_process_time = time; + while (my $line = do { local $/ = "\n"; <$fh> }) { + if ($first_line and $ignore_first_line) { + $first_line = 0; + next; + } + + # line is blank - skip it, no error + if ($line =~ /^[\s\r\n]*$/) { + push @blank_lines, $fh->input_line_number - $ignore_first_line - $total_lines; # the record number + next; + } + + # parse the line + if (!$csv->parse($line)) { + my $error_input = $csv->error_input; + push @$errors,{ + type => 'general', # "There was an error processing this input: '$line'" + message => sprintf $i18n->get('import line parse error'), $error_input, $fh->input_line_number - $ignore_first_line - $total_lines, + }; + # this should "never happen" (TM) + return $self->error($errors, 'www_importEvents'); + } + + my @columns = $csv->fields(); + my %data = map { $sorted_fields_included[$_], $columns[$_] } 0..$#columns; + + # get the data in the form in which it will be compared to existing events + # to find dups, as well as how we'll store it in the db + for my $key (keys %data) { + if ($key eq 'approved') { + $data{$key} = $approved_values{$data{$key}}; + } + else { + my $method = $all_data_fields{$key}->{type}; + if ($method =~ /^(?:hidden|check|select)List$/i) { + $data{$key} = $self->session->form->$method(undef, split /;/, $data{$key}); + } + else { + $data{$key} = $self->session->form->$method(undef, $data{$key}); + } + } + } + + # store it or skip it + my $is_new = 1; + my $this_dup_key = join '|', map $data{$_}, @dup_keys; + my $product_id = "new"; + if (exists $duplicate_events{$this_dup_key}) { + if ($skip_duplicates) { + push @skipped, $fh->input_line_number - $ignore_first_line - $total_lines; # the record number + next; + } + push @overwritten, $fh->input_line_number - $ignore_first_line - $total_lines; # the record number + $is_new = 0; + $product_id = $duplicate_events{$this_dup_key}; # overwrite this product_id + # TODO load everything for this product_id so that we only overwrite the fields that are in the CSV file + } + + # reasonable defaults? + $data{sku} = $self->session->id->generate unless exists $data{sku}; + $data{approved} = $approved_values{Pending} unless exists $data{approved}; + + # store data in the EMS_products table + my $ems_products_href = { + productId => $product_id, + startDate => $data{startDate}, + endDate => $data{endDate}, + maximumAttendees => $data{maximumAttendees}, + approved => $data{approved}, + prerequisiteId => $prerequisites_href->{$data{prerequisiteId}}, + #passId => '', # NULL for these - there's no way to import them + #imageId => '', + #passType => '', + }; + my $pid = $self->setCollateral("EventManagementSystem_products", "productId",$ems_products_href,1,1); + + # store data in EMS_metaData + my @meta_fields = grep { $_->{name} =~ /^metadata_/ } @all_data_fields; + foreach my $field (@meta_fields) { + $field->{name} =~ /^metadata_(.+)$/; + my $field_id = $1; + my $data = $data{$field->{name}}; + my $sql = "insert into EventManagementSystem_metaData values (". + $self->session->db->quoteAndJoin([$field_id, $pid, $data]). + ") on duplicate key update fieldData=". + $self->session->db->quote($data); + $self->session->db->write($sql); + } + + # store data in products + my $data_href = { + productId => $pid, + title => $data{title}, + description => $data{description}, + price => $data{price}, + useSalesTax => ($data{useSalesTax}||0), + weight => ($data{weight}||0), + sku => $data{sku}, + skuTemplate => ($data{skuTemplate}||''), + templateId => ($templates_href->{$data{templateId}}||''), + }; + if ($is_new) { + $self->session->db->setRow("products", "productId", $data_href, $pid); + $duplicate_events{$this_dup_key} = $product_id; + } + else { + $self->session->db->setRow("products", "productId", $data_href); + } + } + my $after_process_time = time; + + # acknowledge success - &error will work fine - with the number of records processed/imported/skipped/overwritten + my $processed_count = $fh->input_line_number - $ignore_first_line - $total_lines; + my $other_count = $skip_duplicates ? @skipped : @overwritten; + my $imported_count = $processed_count - $other_count - @blank_lines; + my $what_done = $i18n->get($skip_duplicates ? 'skipped' : 'overwritten'); + my $message = sprintf $i18n->get('import ok'), $processed_count, $imported_count, scalar(@blank_lines), $other_count, $what_done; + my $html = "

  • $message
  • "; + $html .= join '', map "
  • ".sprintf($i18n->get('import blank line'),$_)."
  • ", @blank_lines; + $html .= join '', map "
  • ".sprintf($i18n->get('import other line'),$_,$what_done)."
  • ", ($skip_duplicates ? @skipped : @overwritten); + + my $total_time = $after_process_time - $start_time; + my $prep_time = $before_check_time - $start_time; + my $check_time = $after_check_time - $before_check_time; + my $prep_time2 = $before_process_time - $after_check_time; + my $process_time = $after_process_time - $before_process_time; + my $time_block = <<""; +
    + total time: $total_time
    + prep time: $prep_time
    + check time: $check_time
    + prep2 time: $prep_time2
    + process time: $process_time
    +
    + + return $self->_acWrapper("$time_block
      $html
    ", $i18n->get('import events')); +} + +#------------------------------------------------------------------- + =head2 www_managePurchases ( ) Method to display list of purchases. Event admins can see everyone's purchases. diff --git a/lib/WebGUI/Form/Checkbox.pm b/lib/WebGUI/Form/Checkbox.pm index 7577cc3dd..147215b23 100644 --- a/lib/WebGUI/Form/Checkbox.pm +++ b/lib/WebGUI/Form/Checkbox.pm @@ -96,15 +96,19 @@ sub generateIdParameter { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Retrieves a value from a form GET or POST and returns it. If the value comes back as undef, this method will return undef. +=head3 value + +An optional value to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $formValue = $self->session->form->param($self->get("name")); + my $formValue = @_ ? shift : $self->session->form->param($self->get("name")); if (defined $formValue) { return $formValue; } else { @@ -122,10 +126,10 @@ Renders and input tag of type checkbox. sub toHtml { my $self = shift; - my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->get("value")))); - my $checkedText = ' checked="checked"' if ($self->get("checked")); - my $idText = ' id="'.$self->get('id').'" ' if ($self->get('id')); - return 'get("extras").' />'; + my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->get("value")))) || ''; + my $checkedText = $self->get("checked") ? ' checked="checked"' : ''; + my $idText = $self->get('id') ? ' id="'.$self->get('id').'" ' : ''; + return 'get("extras")||'').' />'; } diff --git a/lib/WebGUI/Form/ClassName.pm b/lib/WebGUI/Form/ClassName.pm index c97742b96..b3865f1fb 100644 --- a/lib/WebGUI/Form/ClassName.pm +++ b/lib/WebGUI/Form/ClassName.pm @@ -70,9 +70,9 @@ Returns a class name which has been taint checked. sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); $value =~ s/[^\w:]//g; - return $value; + return $value; } #------------------------------------------------------------------- @@ -84,9 +84,9 @@ Renders a class name field. =cut sub toHtml { - my $self = shift; + my $self = shift; $self->session->style->setScript($self->session->url->extras('inputCheck.js'),{ type=>'text/javascript' }); - $self->set("extras", $self->get('extras') . ' onkeyup="doInputCheck(document.getElementById(\''.$self->get("id").'\'),\'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:_\')" '); + $self->set("extras", $self->get('extras') . ' onkeyup="doInputCheck(document.getElementById(\''.$self->get("id").'\'),\'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:_\')" '); return $self->SUPER::toHtml; } diff --git a/lib/WebGUI/Form/Color.pm b/lib/WebGUI/Form/Color.pm index e66961ef5..184f96a64 100644 --- a/lib/WebGUI/Form/Color.pm +++ b/lib/WebGUI/Form/Color.pm @@ -62,17 +62,21 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns a hex color like "#000000". Returns undef if the return value is not a valid color. +=head2 value + +An optional value to use instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $color = $self->session->form->param($self->get("name")); - return undef unless $color =~ /\#\w{6}/; - return $color; + my $color = @_ ? shift : $self->session->form->param($self->get("name")); + return undef unless $color =~ /\#\w{6}/; + return $color; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/Combo.pm b/lib/WebGUI/Form/Combo.pm index e6e91e1d0..44e8b7595 100644 --- a/lib/WebGUI/Form/Combo.pm +++ b/lib/WebGUI/Form/Combo.pm @@ -78,22 +78,30 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns an array or a carriage return ("\n") separated scalar depending upon whether you're returning the values into an array or a scalar. If any data is in the Text form, it is returned before a selected value from the list. +=head3 value + +Optional values to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - if ($self->session->form->param($self->get("name")."_new")) { + + if (@_) { + return $self->SUPER::getValueFromPost(@_); + } + elsif ($self->session->form->param($self->get("name")."_new")) { my $formValue = $self->session->form->param($self->get("name")."_new"); $formValue =~ tr/\r\n//d; return $formValue; - } + } return $self->SUPER::getValueFromPost; } diff --git a/lib/WebGUI/Form/Control.pm b/lib/WebGUI/Form/Control.pm index af1c4f2a3..78846d913 100644 --- a/lib/WebGUI/Form/Control.pm +++ b/lib/WebGUI/Form/Control.pm @@ -412,15 +412,27 @@ sub fixTags { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Retrieves a value from a form GET or POST and returns it. If the value comes back as undef, this method will return the defaultValue instead. +=head3 value + +An optional value to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $formValue = $self->session->form->param($self->get("name")) if ($self->session->request); + my $formValue; + + if (@_) { + $formValue = shift; + } + elsif ($self->session->request) { + $formValue = $self->session->form->param($self->get("name")); + } + if (defined $formValue) { return $formValue; } else { diff --git a/lib/WebGUI/Form/Date.pm b/lib/WebGUI/Form/Date.pm index 08293b641..51148efa1 100644 --- a/lib/WebGUI/Form/Date.pm +++ b/lib/WebGUI/Form/Date.pm @@ -133,11 +133,15 @@ sub displayValue { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns a validated form post result. If the result does not pass validation, it returns undef instead. +=head3 value + +An optional value to process, instead of POST input. This should be in the 'YY(YY)?-MM-DD' form. + =cut sub getValueFromPost { @@ -147,11 +151,11 @@ sub getValueFromPost { || $self->get("defaultValue") =~ m/^\d+$/ || !$self->get("value") || $self->get("value") =~ m/^\d+$/) { - return $self->session->datetime->setToEpoch($self->session->form->param($self->get("name"))); + return $self->session->datetime->setToEpoch(@_ ? shift : $self->session->form->param($self->get("name"))); } else { # MySQL format # YY(YY)?-MM-DD - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); # NOTE: Cannot fix time zone since we don't have a complete date/time diff --git a/lib/WebGUI/Form/DateTime.pm b/lib/WebGUI/Form/DateTime.pm index 03ed71efb..70e6b58b9 100644 --- a/lib/WebGUI/Form/DateTime.pm +++ b/lib/WebGUI/Form/DateTime.pm @@ -105,10 +105,14 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns a validated form post result. If the result does not pass validation, it returns undef instead. +=head3 value + +An optional value to process, instead of POST input. This should be in the 'YY(YY)?-MM-DD HH:MM:SS' form. + =cut sub getValueFromPost { @@ -119,11 +123,11 @@ sub getValueFromPost { || !$self->get("value") || $self->get("value") =~ m/^\d+$/) { # Epoch format - return $self->session->datetime->setToEpoch($self->session->form->param($self->get("name"))); + return $self->session->datetime->setToEpoch(@_ ? shift : $self->session->form->param($self->get("name"))); } else { # MySQL format # YY(YY)?-MM-DD HH:MM:SS - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); $self->session->errorHandler->warn("Date value: $value"); # Verify format diff --git a/lib/WebGUI/Form/Email.pm b/lib/WebGUI/Form/Email.pm index 50addd741..83bc113c6 100644 --- a/lib/WebGUI/Form/Email.pm +++ b/lib/WebGUI/Form/Email.pm @@ -70,15 +70,19 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns a validated email address. If the result does not pass validation, it returns undef instead. +=head3 value + +An optional value to process instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); if ($value =~ /^([0-9a-zA-Z]([-.+\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$/i) { return $value; } diff --git a/lib/WebGUI/Form/Float.pm b/lib/WebGUI/Form/Float.pm index 6190c4453..b21f9011f 100644 --- a/lib/WebGUI/Form/Float.pm +++ b/lib/WebGUI/Form/Float.pm @@ -94,19 +94,23 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns the integer from the form post, or returns 0.0 if the post result is invalid. +=head3 value + +An optional value to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); if ($value =~ /^-?[\d\.]+$/ and $value =~ /\d/) { - return $value; - } - return 0.0; + return $value; + } + return 0.0; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/Group.pm b/lib/WebGUI/Form/Group.pm index e69d8356b..8d68f6d28 100644 --- a/lib/WebGUI/Form/Group.pm +++ b/lib/WebGUI/Form/Group.pm @@ -110,8 +110,8 @@ Returns a group pull-down field. A group pull down provides a select list that p sub toHtml { my $self = shift; - my $where; - if ($self->get('excludeGroups')->[0] ne "") { + my $where = ''; + if (($self->get('excludeGroups')->[0]||'') ne "") { $where = "and groupId not in (".$self->session->db->quoteAndJoin($self->get("excludeGroups")).")"; } $self->set('options', $self->session->db->buildHashRef("select groupId,groupName from groups where showInForms=1 $where order by groupName")); diff --git a/lib/WebGUI/Form/HTMLArea.pm b/lib/WebGUI/Form/HTMLArea.pm index 37a09d70a..71da3da8a 100644 --- a/lib/WebGUI/Form/HTMLArea.pm +++ b/lib/WebGUI/Form/HTMLArea.pm @@ -104,15 +104,19 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns the value of this form field after stipping unwanted tags like . +=head3 value + +An optional value to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - return WebGUI::HTML::cleanSegment($self->SUPER::getValueFromPost()); + return WebGUI::HTML::cleanSegment($self->SUPER::getValueFromPost(@_)); } diff --git a/lib/WebGUI/Form/HexSlider.pm b/lib/WebGUI/Form/HexSlider.pm index 72f62846b..1aa8e8f8a 100644 --- a/lib/WebGUI/Form/HexSlider.pm +++ b/lib/WebGUI/Form/HexSlider.pm @@ -232,7 +232,7 @@ sub getValueFromPost { id => 'view-'.$self->get('id'), }; - return WebGUI::Form::hexadecimal->new($self->session, $properties)->getValueFromPost; + return WebGUI::Form::Hexadecimal->new($self->session, $properties)->getValueFromPost; } 1; diff --git a/lib/WebGUI/Form/Hexadecimal.pm b/lib/WebGUI/Form/Hexadecimal.pm index dc0853bbd..dff58712f 100644 --- a/lib/WebGUI/Form/Hexadecimal.pm +++ b/lib/WebGUI/Form/Hexadecimal.pm @@ -101,9 +101,9 @@ sub getValueFromPost { my $self = shift; my $value = $self->session->form->param($self->get("name")); if ($value =~ /^[0-9a-f]+$/i) { - return $value; - } - return 0; + return $value; + } + return 0; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/Hidden.pm b/lib/WebGUI/Form/Hidden.pm index 12e729b79..4bbd376f1 100644 --- a/lib/WebGUI/Form/Hidden.pm +++ b/lib/WebGUI/Form/Hidden.pm @@ -103,9 +103,9 @@ Renders an input tag of type hidden. sub toHtmlAsHidden { my $self = shift; - my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->get("value")))); - my $idText = ' id="'.$self->get('id').'" ' if ($self->get('id')); - return 'get("extras").$idText.' />'."\n"; + my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->get("value")))) || ''; + my $idText = $self->get('id') ? ' id="'.$self->get('id').'" ' : ''; + return 'get("extras")||'').$idText.' />'."\n"; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/IntSlider.pm b/lib/WebGUI/Form/IntSlider.pm index 6b776b623..0aa8ce0d6 100644 --- a/lib/WebGUI/Form/IntSlider.pm +++ b/lib/WebGUI/Form/IntSlider.pm @@ -130,14 +130,19 @@ sub getOnChangeSlider { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Retrieves a value from a form GET or POST and returns it. If the value comes back as undef, this method will return the defaultValue instead. Strip newlines/carriage returns from the value. +=head2 value + +A value to process instead of POST input. + =cut sub getValueFromPost { my $self = shift; + my @args = @_; my $properties = { name => $self->get('name'), @@ -146,7 +151,7 @@ sub getValueFromPost { id => 'view-'.$self->get('id'), }; - return WebGUI::Form::Integer->new($self->session, $properties)->getValueFromPost; + return WebGUI::Form::Integer->new($self->session, $properties)->getValueFromPost(@args); } 1; diff --git a/lib/WebGUI/Form/Integer.pm b/lib/WebGUI/Form/Integer.pm index f7aa273c9..a1a2f41c4 100644 --- a/lib/WebGUI/Form/Integer.pm +++ b/lib/WebGUI/Form/Integer.pm @@ -94,19 +94,23 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns the integer from the form post, or returns 0 if the post result is invalid. +=head3 value + +An optional value to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); if ($value =~ /^-?\d+$/) { - return $value; - } - return 0; + return $value; + } + return 0; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/Interval.pm b/lib/WebGUI/Form/Interval.pm index 434995b1d..09d9ccadf 100644 --- a/lib/WebGUI/Form/Interval.pm +++ b/lib/WebGUI/Form/Interval.pm @@ -85,14 +85,24 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ num_and_units ] ) Returns either the interval that was posted (in seconds) or if nothing comes back it returns 0. +=head3 num_and_units + +The number and units for this interval, to use instead of POST input, which is the default. ("3 days", for example.) Valid units are (case-insensitive): seconds, minutes, hours, days, weeks, months, years. + =cut sub getValueFromPost { my $self = shift; + + if (@_) { + my @args = split /\s+/, shift; + return $self->session->datetime->intervalToSeconds(@args); + } + return $self->session->datetime->intervalToSeconds($self->session->form->param($self->get("name")."_interval"),$self->session->form->param($self->get("name")."_units")) || 0; } diff --git a/lib/WebGUI/Form/List.pm b/lib/WebGUI/Form/List.pm index 055d10923..4aa9253f8 100644 --- a/lib/WebGUI/Form/List.pm +++ b/lib/WebGUI/Form/List.pm @@ -194,16 +194,20 @@ sub displayValue { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns an array or a carriage return ("\n") separated scalar depending upon whether you're returning the values into an array or a scalar. +=head3 value + +Optional values to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my @data = $self->session->form->param($self->get("name")); - return wantarray ? @data : join("\n",@data); + my @data = @_ ? @_ : $self->session->form->param($self->get("name")); + return wantarray ? @data : join("\n",@data); } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/Phone.pm b/lib/WebGUI/Form/Phone.pm index 5cf2c20a4..d65f46d84 100644 --- a/lib/WebGUI/Form/Phone.pm +++ b/lib/WebGUI/Form/Phone.pm @@ -70,19 +70,23 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns a string filtered to allow only digits, spaces, and these special characters: + - ( ) or it will return undef it the number doesn't validate to those. +=head3 value + +An input value to use instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); - if ($value =~ /^[x\d \.\-\+\(\)]+$/ and $value =~ /\d/) { - return $value; - } - return undef; + my $value = @_ ? shift : $self->session->form->param($self->get("name")); + if ($value =~ /^[x\d \.\-\+\(\)]+$/ and $value =~ /\d/) { + return $value; + } + return undef; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Form/Radio.pm b/lib/WebGUI/Form/Radio.pm index bdcf2cd7f..0c347606c 100644 --- a/lib/WebGUI/Form/Radio.pm +++ b/lib/WebGUI/Form/Radio.pm @@ -98,10 +98,10 @@ Renders and input tag of type radio. sub toHtml { my $self = shift; - my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->get("value")))); - my $checkedText = ' checked="checked"' if ($self->get("checked")); - my $idText = ' id="'.$self->get('id').'" ' if ($self->get('id')); - return 'get("extras").' />'; + my $value = $self->fixMacros($self->fixQuotes($self->fixSpecialCharacters($self->get("value")))) || ''; + my $checkedText = $self->get("checked") ? ' checked="checked"' : ''; + my $idText = $self->get('id') ? ' id="'.$self->get('id').'" ' : ''; + return 'get("extras")||'').' />'; } diff --git a/lib/WebGUI/Form/SelectBox.pm b/lib/WebGUI/Form/SelectBox.pm index 0ccfc02ab..091e474d4 100644 --- a/lib/WebGUI/Form/SelectBox.pm +++ b/lib/WebGUI/Form/SelectBox.pm @@ -93,15 +93,20 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Retrieves a value from a form GET or POST and returns it. If the value comes back as undef, this method will return the defaultValue instead. Note, this is exactly the same method as used by Control since SelectBoxes only support a single value. +=head3 value + +Optional values to process (read "return"), instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $formValue = $self->session->form->param($self->get("name")); + + my $formValue = @_ ? shift : $self->session->form->param($self->get("name")); if (defined $formValue) { return $formValue; } else { @@ -119,7 +124,7 @@ Renders a select list form control. sub toHtml { my $self = shift; - my $output = 'get("extras")||'').'>'; my %options; tie %options, 'Tie::IxHash'; %options = $self->orderedHash; diff --git a/lib/WebGUI/Form/SelectList.pm b/lib/WebGUI/Form/SelectList.pm index 0a09e33b5..eda25d4ec 100644 --- a/lib/WebGUI/Form/SelectList.pm +++ b/lib/WebGUI/Form/SelectList.pm @@ -95,8 +95,8 @@ Renders a select list form control. sub toHtml { my $self = shift; - my $multiple = ' multiple="multiple"' if ($self->get("multiple")); - my $output = 'get("extras")||'').$multiple.'>'; my %options; tie %options, 'Tie::IxHash'; %options = $self->orderedHash; diff --git a/lib/WebGUI/Form/SelectSlider.pm b/lib/WebGUI/Form/SelectSlider.pm index 25bb963e0..8364dfeca 100644 --- a/lib/WebGUI/Form/SelectSlider.pm +++ b/lib/WebGUI/Form/SelectSlider.pm @@ -16,6 +16,7 @@ package WebGUI::Form::SelectSlider; use strict; use base 'WebGUI::Form::Slider'; +use WebGUI::Form::SelectList; use WebGUI::International; =head1 NAME @@ -177,16 +178,21 @@ sub getSliderValue { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Retrieves a value from a form GET or POST and returns it. If the value comes back as undef, this method will return the defaultValue instead. Strip newlines/carriage returns from the value. +=head2 value + +A value to process instead of POST input. + =cut sub getValueFromPost { my $self = shift; + my @args = @_; my $properties = { -name => $self->get('name'), @@ -196,7 +202,7 @@ sub getValueFromPost { -size => 1, }; - return WebGUI::Form::selectList->new($self->session, $properties)->getValueFromPost; + return WebGUI::Form::SelectList->new($self->session, $properties)->getValueFromPost(@args); } diff --git a/lib/WebGUI/Form/Text.pm b/lib/WebGUI/Form/Text.pm index aa7a9388b..5ba382f84 100644 --- a/lib/WebGUI/Form/Text.pm +++ b/lib/WebGUI/Form/Text.pm @@ -84,15 +84,26 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Retrieves a value from a form GET or POST and returns it. If the value comes back as undef, this method will return the defaultValue instead. Strip newlines/carriage returns from the value. +=head3 value + +An optional value to process, instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $formValue = $self->session->form->param($self->get("name")) if ($self->session->request); + my $formValue; + + if (@_) { + $formValue = shift; + } + elsif ($self->session->request) { + $formValue = $self->session->form->param($self->get("name")); + } if (defined $formValue) { $formValue =~ tr/\r\n//d; return $formValue; diff --git a/lib/WebGUI/Form/TimeField.pm b/lib/WebGUI/Form/TimeField.pm index afa5fa563..a4953dc7c 100644 --- a/lib/WebGUI/Form/TimeField.pm +++ b/lib/WebGUI/Form/TimeField.pm @@ -99,7 +99,7 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) If the defaultValue is a MySQL time, the value returned by this form element will be a MySQL time. Note: Will not be adjusted for the user's time zone. @@ -107,10 +107,31 @@ will be a MySQL time. Note: Will not be adjusted for the user's time zone. Otherwise, the value returned by this form element will be a number of seconds, adjusted for the user's time zone.. +=head3 value + +An optional value to process, instead of POST input. This should be in the form of an integer of seconds, 'HH:MM', or 'HH:MM:SS'. + =cut sub getValueFromPost { my $self = shift; + + if (@_) { + my $value = shift; + if (!$self->get("defaultValue") + || $self->get("defaultValue") =~ m/^\d+$/ + || !$value + || $value =~ m/^\d+$/) { + return $self->session->datetime->timeToSeconds($value)-($self->session->user->profileField("timeOffset")*3600); + } + elsif ($value =~ /^\d{2}\D\d{2}(\D\d{2})?$/) { + return $value + } + else { + return undef; + } + } + # This should probably be rewritten as a cascading ternary if (!$self->get("defaultValue") || $self->get("defaultValue") =~ m/^\d+$/ diff --git a/lib/WebGUI/Form/Url.pm b/lib/WebGUI/Form/Url.pm index c36ca8a85..a39510dfd 100644 --- a/lib/WebGUI/Form/Url.pm +++ b/lib/WebGUI/Form/Url.pm @@ -85,7 +85,7 @@ Parses the posted value and tries to make corrections if necessary. sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); $value =~ tr/\r\n//d; if ($value =~ /mailto:/) { return $value; diff --git a/lib/WebGUI/Form/YesNo.pm b/lib/WebGUI/Form/YesNo.pm index e4ee837a7..83b5ba67b 100644 --- a/lib/WebGUI/Form/YesNo.pm +++ b/lib/WebGUI/Form/YesNo.pm @@ -81,7 +81,7 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 yesNo ( ) Returns either a 1 or 0 representing yes, no. @@ -97,6 +97,32 @@ sub yesNo { #------------------------------------------------------------------- +=head2 getValueFromPost ( [ value ] ) + +If value is present, we will process it, otherwise the superclass will handle the request. + +=head3 value + +An optional value to process, instead of POST input. This should be in the form 1, 0, 'Y' or 'N'. 1 or 0 is returned. + +=cut + +sub getValueFromPost { + my $self = shift; + my $formValue; + + if (@_) { + my $value = shift; + return '' unless length $value; # empty import value? + return ($value =~ /^y/i || $value eq '1') ? 1 : 0; + } + else { + return $self->SUPER::getValueFromPost; + } +} + +#------------------------------------------------------------------- + =head2 toHtml ( ) Renders a yes/no question field. diff --git a/lib/WebGUI/Form/Zipcode.pm b/lib/WebGUI/Form/Zipcode.pm index a78b983cc..f807caffd 100644 --- a/lib/WebGUI/Form/Zipcode.pm +++ b/lib/WebGUI/Form/Zipcode.pm @@ -77,20 +77,24 @@ sub definition { #------------------------------------------------------------------- -=head2 getValueFromPost ( ) +=head2 getValueFromPost ( [ value ] ) Returns a validated form post result. If the result does not pass validation, it returns undef instead. +=head3 value + +An optional value to use instead of POST input. + =cut sub getValueFromPost { my $self = shift; - my $value = $self->session->form->param($self->get("name")); + my $value = @_ ? shift : $self->session->form->param($self->get("name")); $value =~ tr/\r\n//d; if ($value =~ /^[A-Z\d\s\-]+$/) { - return $value; - } - return undef; + return $value; + } + return undef; } #------------------------------------------------------------------- @@ -102,7 +106,7 @@ Renders a zip code field. =cut sub toHtml { - my $self = shift; + my $self = shift; $self->session->style->setScript($self->session->url->extras('inputCheck.js'),{ type=>'text/javascript' }); $self->set("extras", $self->get('extras') . ' onkeyup="doInputCheck(document.getElementById(\''.$self->get("id").'\'),\'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ- \')"'); return $self->SUPER::toHtml; diff --git a/lib/WebGUI/Help/Asset_EventManagementSystem.pm b/lib/WebGUI/Help/Asset_EventManagementSystem.pm index fc09d1df0..379d203d0 100644 --- a/lib/WebGUI/Help/Asset_EventManagementSystem.pm +++ b/lib/WebGUI/Help/Asset_EventManagementSystem.pm @@ -156,6 +156,105 @@ our $HELP = { ], }, + 'import events' => { + source => 'sub www_importEvents', + title => 'import events help title', + body => 'import events help body', + fields => [ + { + title => 'choose a file to import', + description => 'import hoverhelp file', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'what about duplicates', + description => 'import hoverhelp dups', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'ignore first line', + description => 'import hoverhelp first line', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'import file contains field title', + description => 'import file contains field description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'import field is duplicate key title', + description => 'import field is duplicate key description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'status', + description => 'approve event description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event title', + description => 'add/edit event title description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event description', + description => 'add/edit event description description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event image', + description => 'add/edit event image description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'price', + description => 'add/edit event price description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event template', + description => 'add/edit event template description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'weight', + description => 'weight description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'sku', + description => 'sku description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'sku template', + description => 'sku template description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event start date', + description => 'add/edit event start date description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event end date', + description => 'add/edit event end date description', + namespace => 'Asset_EventManagementSystem', + }, + { + title => 'add/edit event maximum attendees', + description => 'add/edit event maximum attendees description', + namespace => 'Asset_EventManagementSystem', + }, + ], + related => [ + { + tag => 'event management system add/edit', + namespace => 'Asset_EventManagementSystem', + }, + ], + }, + 'edit event metadata field' => { source => 'sub www_editEventMetaDataField', title => 'add/edit event metadata field', diff --git a/lib/WebGUI/SQL.pm b/lib/WebGUI/SQL.pm index f53aa8281..9146365b0 100644 --- a/lib/WebGUI/SQL.pm +++ b/lib/WebGUI/SQL.pm @@ -19,6 +19,7 @@ use strict; use Tie::IxHash; use WebGUI::SQL::ResultSet; use WebGUI::Utility; +use Text::CSV_XS; =head1 NAME @@ -527,7 +528,7 @@ sub quickArray { =head2 quickCSV ( sql, params ) -Executes a query and returns a comma delimited text blob with column headers. +Executes a query and returns a comma delimited text blob with column headers. Returns undef on failure. =head3 sql @@ -543,16 +544,23 @@ sub quickCSV { my $self = shift; my $sql = shift; my $params = shift; - my ($sth, $output, @data); - $sth = $self->prepare($sql); + my ($sth, $output, @data); + + my $csv = Text::CSV_XS->new({ eol => "\n" }); + + $sth = $self->prepare($sql); $sth->execute($params); - $output = join(",",$sth->getColumnNames)."\n"; - while (@data = $sth->array) { - makeArrayCommaSafe(\@data); - $output .= join(",",@data)."\n"; - } - $sth->finish; - return $output; + + return unless $csv->combine($sth->getColumnNames); + $output = $csv->string(); + + while (@data = $sth->array) { + return unless $csv->combine(@data); + $output .= $csv->string(); + } + + $sth->finish; + return $output; } diff --git a/lib/WebGUI/Session/DateTime.pm b/lib/WebGUI/Session/DateTime.pm index b5d48d616..e48c71aab 100644 --- a/lib/WebGUI/Session/DateTime.pm +++ b/lib/WebGUI/Session/DateTime.pm @@ -664,7 +664,7 @@ An integer which represents the amount of time for the interval. =head3 units -A string which represents the units of the interval. The string must be 'years', 'months', 'weeks', 'days', 'hours', 'minutes', or 'seconds'. +A string which represents the units of the interval. The string must be (case-insensitive) 'years', 'months', 'weeks', 'days', 'hours', 'minutes', or 'seconds'. =cut @@ -672,25 +672,25 @@ sub intervalToSeconds { my $self = shift; my $interval = shift; my $units = shift; - if ($units eq "years") { + if (lc $units eq "years") { return ($interval*31536000); } - elsif ($units eq "months") { + elsif (lc $units eq "months") { return ($interval*2592000); } - elsif ($units eq "weeks") { + elsif (lc $units eq "weeks") { return ($interval*604800); } - elsif ($units eq "days") { + elsif (lc $units eq "days") { return ($interval*86400); } - elsif ($units eq "hours") { + elsif (lc $units eq "hours") { return ($interval*3600); } - elsif ($units eq "minutes") { + elsif (lc $units eq "minutes") { return ($interval*60); } - else { + else { # seconds return $interval; } } diff --git a/lib/WebGUI/Session/Env.pm b/lib/WebGUI/Session/Env.pm index 396f6c48d..4ce57d955 100644 --- a/lib/WebGUI/Session/Env.pm +++ b/lib/WebGUI/Session/Env.pm @@ -46,8 +46,8 @@ Deconstructor. =cut sub DESTROY { - my $self = shift; - undef $self; + my $self = shift; + undef $self; } @@ -80,9 +80,9 @@ Returns the user's real IP address. Normally this is REMOTE_ADDR, but if they go sub getIp { my $self = shift; - if ($self->get("HTTP_X_FORWARDED_FOR") =~ m/(\d+\.\d+\.\d+\.\d+)/) { - return $1; - } + if ($self->get("HTTP_X_FORWARDED_FOR") =~ m/(\d+\.\d+\.\d+\.\d+)/) { + return $1; + } return $self->get("REMOTE_ADDR"); } diff --git a/lib/WebGUI/Session/Form.pm b/lib/WebGUI/Session/Form.pm index 808f54dfb..9d059d954 100644 --- a/lib/WebGUI/Session/Form.pm +++ b/lib/WebGUI/Session/Form.pm @@ -16,6 +16,7 @@ package WebGUI::Session::Form; use strict qw(vars subs); use WebGUI::HTML; +use base 'WebGUI::FormValidator'; =head1 NAME @@ -23,7 +24,7 @@ Package WebGUI::Session::Form =head1 DESCRIPTION -This is a convenience package to the individual form controls. It allows you to get the form post results back without having to load each form control seperately, instantiate an object, and call methods. +This is a subclass of WebGUI::FormValidator. It processes POST input. =head1 SYNOPSIS @@ -41,79 +42,49 @@ This is a convenience package to the individual form controls. It allows you to =head1 METHODS -These functions are available from this package: - =cut #------------------------------------------------------------------- -=head2 AUTOLOAD ( ) +=head2 AUTOLOAD ( params ) -Dynamically creates functions on the fly for all the different form control types. +This just passes control to WebGUI::FormValidator::AUTOLOAD. + +=head3 params + +Either an href of parameters or the fieldName in question. =cut sub AUTOLOAD { - our $AUTOLOAD; my $self = shift; - my $name = ucfirst((split /::/, $AUTOLOAD)[-1]); - my $params = shift; - $params = {name=>$params} if ref ($params) ne "HASH"; - my $cmd = "use WebGUI::Form::".$name; - eval ($cmd); - if ($@) { - $self->session->errorHandler->error("Couldn't compile form control: ".$name.". Root cause: ".$@); - return undef; - } - my $class = "WebGUI::Form::".$name; - return $class->new($self->session, $params)->getValueFromPost; + my @args = @_; + our $AUTOLOAD; + my $method = "SUPER::".(split /::/, $AUTOLOAD)[-1]; + return $self->$method(@args); } #------------------------------------------------------------------- -=head2 DESTROY ( ) +=head2 paramsHashRef ( ) -Deconstructor. +Gets a hash ref of all the params passed in to this class, and their values. This should not be confused with the param() method. =cut -sub DESTROY { - my $self = shift; - undef $self; -} - - - -#------------------------------------------------------------------- - -=head2 get ( ) - -An alias for process() - -=cut - -sub get { +sub paramsHashRef { my $self = shift; - return $self->process(@_); -} - -#------------------------------------------------------------------- - -=head2 new ( session ) - -Constructor. - -=head3 session - -A reference to the current session. - -=cut - -sub new { - my $class = shift; - my $session = shift; - bless {_session=>$session}, $class; + unless ($self->{_paramsHashRef}) { + my %hash; + tie %hash, "Tie::IxHash"; + foreach ($self->param) { + my @arr = $self->process($_); + $hash{$_} = (scalar(@arr) > 1)?\@arr:$arr[0]; + } + $self->{_paramsHashRef} = \%hash; + } + return $self->{_paramsHashRef}; } @@ -157,29 +128,6 @@ sub param { } } -#------------------------------------------------------------------- - -=head2 paramsHashRef ( ) - -Gets a hash ref of all the params passed in to this class, and their values. This should not be confused with the param() method. - -=cut - -sub paramsHashRef { - my $self = shift; - unless ($self->{_paramsHashRef}) { - my %hash; - tie %hash, "Tie::IxHash"; - foreach ($self->param) { - my @arr = $self->process($_); - $hash{$_} = (scalar(@arr) > 1)?\@arr:$arr[0]; - } - $self->{_paramsHashRef} = \%hash; - } - return $self->{_paramsHashRef}; -} - - #------------------------------------------------------------------- =head2 process ( name, type [ , default, params ] ) @@ -206,39 +154,16 @@ A full set of form params just as you'd pass into any of the form controls when sub process { my ($self, $name, $type, $default, $params) = @_; + $type = ucfirst($type); return $self->param($name) if ($type eq ""); - $params->{name} = $name; - if (wantarray) { - my @values = $self->$type($params); - if (scalar(@values) < 1 && ref $default eq "ARRAY") { - return @{$default}; - } else { - return @values; - } - } else { - my $value = $self->$type($params); - unless (defined $value) { - return $default; - } - if ($value =~ /^[\s]+$/) { - return undef; - } - return $value; - } -} -#------------------------------------------------------------------- - -=head2 session ( ) - -Returns a reference to the current session. - -=cut - -sub session { - my $self = shift; - return $self->{_session}; + return $self->SUPER::process({ + name => $name, + type => $type, + default => $default, + params => $params, + }); } 1; diff --git a/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm b/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm index 6386e7f17..91c5d4b3b 100644 --- a/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm +++ b/lib/WebGUI/i18n/English/Asset_EventManagementSystem.pm @@ -193,15 +193,15 @@ our $I18N = { ##hashref of hashes lastUpdated => 1138312761, }, - 'add/edit useSalesTax' => { - message => q|Use Sales Tax?|, - lastUpdated => 1160109884, - }, + 'add/edit useSalesTax' => { + message => q|Use Sales Tax?|, + lastUpdated => 1160109884, + }, - 'add/edit useSalesTax description' => { - message => q|Should this event have sales tax applied to it?|, - lastUpdated => 1160109886, - }, + 'add/edit useSalesTax description' => { + message => q|Should this event have sales tax applied to it?|, + lastUpdated => 1160109886, + }, 'add/edit event maximum attendees' => { message => q|Maximum Attendees|, @@ -383,6 +383,168 @@ our $I18N = { ##hashref of hashes lastUpdated => 1147146318, }, + 'check required fields' => { + message => q|You did not include these required fields: |, + lastUpdated => 0, + context => q|Require that the user include all required fields in their import|, + }, + + 'import blank line' => { + message => q|Record %d was blank (skipped).|, + lastUpdated => 0, + context => q|Report which lines were blank.|, + }, + + 'import other line' => { + message => q|Record %d was %s.|, + lastUpdated => 0, + context => q|Report which lines were skipped or overwritten.|, + }, + + 'import record parse error' => { + message => q|There was an error processing record %d: '%s'|, + lastUpdated => 0, + context => q|Couldn't parse a line of the import file|, + }, + + 'no import took place' => { + message => q|No records were imported. There were errors in the input:|, + lastUpdated => 0, + context => q|Let the user know that we didn't partially import their bad data|, + }, + + 'export error' => { + message => q|There was an error in the export procedure.|, + lastUpdated => 0, + context => q|generic export error|, + }, + + 'import form header' => { + message => q|Using this form you can import data directly into this EMS. Be sure that your fields are specified in the order shown below.|, + lastUpdated => 0, + context => q|header to the import form...|, + }, + + 'import need dup key' => { + message => q|You must check at least one duplicate key checkbox.|, + lastUpdated => 0, + context => q|When importing, we need at least one field to tell record apart|, + }, + + 'import invalid status' => { + message => q|Record %d has an invalid Status value (%s). Valid values are: Approved, Cancelled, Denied, Pending.|, + lastUpdated => 0, + context => q|There are only a few valid valued for the event status (approved) field|, + }, + + 'import invalid prereq' => { + message => q|Record %d has an invalid Prerequisite Set Name value (%s). You need to create the relevant Prerequisite Sets prior to import.|, + lastUpdated => 0, + context => q|The prereq import field is a EMS_prereqs.name; we need it to store the id in EMS_products.prerequisiteId|, + }, + + 'import invalid template' => { + message => q|Record %d has an invalid Event Template Name value (%s). You need to create the relevant Event Template prior to import.|, + lastUpdated => 0, + context => q|The templateId import field is an assetData.title; we need it to store the assetId in EMS_products.templateId|, + }, + + 'import missing required' => { + message => q|Record %d did not have %s, a required field, filled.|, + lastUpdated => 0, + context => q|Import records need to have required fields filled|, + }, + + 'field count mismatch' => { + message => q|Record %d has %d fields, not %d as indicated by the checkboxes you clicked.|, + lastUpdated => 0, + context => q|Import records need to have the right number of fields|, + }, + + 'import ok' => { + message => q|All %d records were successfully processed. %d created, %d blank lines, %d duplicates %s.|, + lastUpdated => 0, + context => q|Let the user know that the importing of events was successful|, + }, + + 'skipped' => { + message => q|skipped|, + lastUpdated => 0, + context => q|What did we do with duplicates (skipped/overwritten)?|, + }, + + 'overwritten' => { + message => q|overwritten|, + lastUpdated => 0, + context => q|What did we do with duplicates (skipped/overwritten)?|, + }, + + 'import events help title' => { + message => q|Import Events|, + lastUpdated => 0, + context => q|Help for importing events from CSV files.|, + }, + + 'import events help body' => { + message => q|This is the body of the import events help page.|, + lastUpdated => 0, + context => q|Help for importing events from CSV files.|, + }, + + 'meta hover help' => { + message => q|This is a custom field. Please ask your administrator for guidance.|, + lastUpdated => 0, + context => q|What's this meta field for?|, + }, + + 'import hoverhelp file' => { + message => q|Upload a comma-seperated values (CSV) file for importing events. (Spreadsheet applications can output this format.) The fields must be comma-delimited, with double-quotes (") around field values which contain commas. Embedded double quotes are escaped with another double-quote (""). Your file will be checked for field count and required fields before any import takes place. If errors are found, then you are notified of the errors and no import takes place. This checking does not include checking whether or not LDAP, database links, or templates are valid. The format of special fields is as it is for exporting, so if you have a question as to how to format a given field for importing, look at how that information is exported and format your data accordingly. List fields with multiple values should be joined in the same CSV field by a semi-colon (;).|, + lastUpdated => 0, + context => q|What's the file field for?|, + }, + + 'import hoverhelp dups' => { + message => q|The system will use whatever fields you specify under 'Field Is Duplicate Key' as the fields to use to identify duplicate event records. When a duplicate is found, this pulldown will determine what we do with the duplicate event record - either skip the incoming record or overwrite the old record with the new one. Note that all fields in overwritten records are overwritten, regardless of whether they're present in the incoming record or not.|, + lastUpdated => 0, + context => q|What's the duplicates field for?|, + }, + + 'import hoverhelp first line' => { + message => q|If the first line of your import file contains field names instead of an event record, check yes. Otherwise, check no.|, + lastUpdated => 0, + context => q|What's the first line field for?|, + }, + + 'import file contains field title' => { + message => q|File Contains Field|, + lastUpdated => 0, + context => q|What's "file contains field" mean?|, + }, + + 'import file contains field description' => { + message => q|Check the checkboxes next to the fields which are included in your imput file. Please note that the fields must be in the order shown, and all required fields must be checked and filled in order for the import to proceed.|, + lastUpdated => 0, + context => q|What's "file contains field" mean?|, + }, + + 'import field is duplicate key title' => { + message => q|Field Is Duplicate Key|, + lastUpdated => 0, + context => q|What's "field is dup key" mean?|, + }, + + 'import field is duplicate key description' => { + message => q|In order to handle duplicate event records intelligently, the system needs to be able to identify a record as a duplicate. By checking these checkboxes, you're letting the system know what fields it needs to consider when trying to find an already-existing record for the event record being imported. For example, if you check Event Title and Event Start Date as the only fields which are duplicate keys, then if the incoming Event Title and Event Start Date match those of an existing event record, then the incoming record will be considered a duplicate of the already existing record. In that case, the system will either skip the incoming record, or overwrite the existing record.|, + lastUpdated => 0, + context => q|What's "field is dup key" mean?|, + }, + + 'null field error recnum' => { + message => q|The %s field cannot be blank (record %d).|, + lastUpdated => 1179563424, + context => q|When a required field is empty/blank, then this message is used in sprintf to tell the user which field it is and that it cannot be blank - it also shows the relevant import file record number|, + }, + 'null field error' => { message => q|The %s field cannot be blank.|, lastUpdated => 1138908251, @@ -489,6 +651,11 @@ in the system.

    lastUpdated => 1149828404, }, + 'short title' => { + message => q|Title|, + lastUpdated => 1149828404, + }, + 'title.url' => { message => q|A URL to display a list of events that contain this event|, lastUpdated => 1165513731, @@ -981,7 +1148,7 @@ for this event.

    'you' => { message => q|you|, lastUpdated => 1145396293, - context => q|Third person pronoun|, + context => q|Second person pronoun|, }, 'create a badge for myself' => { @@ -1064,7 +1231,7 @@ for this event.

    'filter' => { message => q|Filter|, lastUpdated => 1145402683, - context => q|Button in search form to limit displayed events based on user criteria|, + context => q|Button in search form to limit displayed eveed events based on user criteria|, }, 'managePrereqsMessage' => { @@ -1206,22 +1373,42 @@ for this event.

    context => q|The label for the sku template field in the edit event screen.| }, - 'sku template description' => { - message => q|This field defines how the SKU for each + 'sku template description' => { + message => q|This field defines how the SKU for each product variant will be composed. The syntax is the same as that of normal templates.|, - lastUpdated => 1146170930, - }, + lastUpdated => 1146170930, + }, - 'error' => { - message => q|Error:|, - lastUpdated => 1146170930, - }, + 'error no colon' => { + message => q|Error|, + lastUpdated => 0, + }, - 'manage prerequisite sets' => { - message => q|Manage Prerequisite Sets|, - lastUpdated => 1147050475, - }, + 'error' => { + message => q|Error:|, + lastUpdated => 1146170930, + }, + + 'manage prerequisite sets' => { + message => q|Manage Prerequisite Sets|, + lastUpdated => 1147050475, + }, + + 'export events' => { + message => q|Export Events|, + lastUpdated => 1179341015, + }, + + 'import events' => { + message => q|Import Events|, + lastUpdated => 1179341015, + }, + + 'enter import file' => { + message => q|Please enter a file to import|, + lastUpdated => 1179341015, + }, 'edit prerequisite set' => { message => q|Edit Prerequisite Set|, @@ -1530,6 +1717,42 @@ added to the user's cart and would be discounted if the Attend All Sessions even lastUpdated => 0, }, + 'choose a file to import' => { + message => q|Choose a file to import|, + lastUpdated => 0, + }, + + 'what about duplicates' => { + message => q|What about duplicates?|, + lastUpdated => 0, + context => q|Import EMS data form|, + }, + + 'ignore first line' => { + message => q|Ignore first line?|, + lastUpdated => 0, + context => q|Import EMS data form|, + }, + + 'yes' => { + message => q|yes|, + lastUpdated => 0, + }, + + 'no' => { + message => q|no|, + lastUpdated => 0, + }, + + 'skip' => { + message => q|Skip|, + lastUpdated => 0, + }, + + 'overwrite' => { + message => q|Overwrite|, + lastUpdated => 0, + }, }; 1; diff --git a/t/Form/Checkbox.t b/t/Form/Checkbox.t index de8c620c2..9885eea2e 100644 --- a/t/Form/Checkbox.t +++ b/t/Form/Checkbox.t @@ -45,7 +45,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::Checkbox'; my $formType = 'Checkbox'; -my $numTests = 7 + scalar @{ $testBlock } + 1; +my $numTests = 7 + scalar @{ $testBlock } + 3; plan tests => $numTests; @@ -105,3 +105,8 @@ is( $forms[0]->param('cbox3'), ' ', 'WRONG: whitespace value'); WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); +# +# test WebGUI::FormValidator::Checkbox(undef,@values) +# +is(WebGUI::Form::Checkbox->new($session)->getValueFromPost('test'), 'test', '$cbox->getValueFromPost(arg)'); +is($session->form->checkbox(undef,'test'), 'test', 'WebGUI::FormValidator::checkbox'); diff --git a/t/Form/ClassName.t b/t/Form/ClassName.t index f93890d78..0bd01f321 100644 --- a/t/Form/ClassName.t +++ b/t/Form/ClassName.t @@ -69,7 +69,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::ClassName'; my $formType = 'ClassName'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 3; plan tests => $numTests; @@ -127,3 +127,8 @@ is($input->{maxlength}, 20, 'set maxlength'); #diag $formType; WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); +# +# test WebGUI::FormValidator::ClassName(undef,@values) +# +is(WebGUI::Form::ClassName->new($session)->getValueFromPost('t*est'), 'test', '$cname->getValueFromPost(arg)'); +is($session->form->className(undef,'t*est'), 'test', 'WebGUI::FormValidator::className'); diff --git a/t/Form/Email.t b/t/Form/Email.t index ae5231018..680bad3d6 100644 --- a/t/Form/Email.t +++ b/t/Form/Email.t @@ -52,7 +52,7 @@ my $testBlock = [ my $formType = 'text'; my $formClass = 'WebGUI::Form::Email'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 5; plan tests => $numTests; @@ -106,3 +106,14 @@ is($input->{maxlength}, 200, 'Checking maxlength param, set'); ##Test Form Output parsing WebGUI::Form_Checking::auto_check($session, 'email', $testBlock); + +# just testing that getValueFromPost works with an argument + +my $email = WebGUI::Form::Email->new($session); +is($email->getValueFromPost('james@plainblack.com'), 'james@plainblack.com', 'getValueFromPost(valid) returned a valid email'); +is($email->getValueFromPost('this*isn"t and@emailaddres,s'), undef, 'getValueFromPost(invalid) returned undef instead of an invalid email'); +is($session->form->email(undef,'james@plainblack.com'), 'james@plainblack.com', '$form->email(valid) returned a valid email'); +is($session->form->email(undef,'this*isn"t and@emailaddres,s'), undef, '$form->email(invalid) returned undef instead of an invalid email'); + +__END__ + diff --git a/t/Form/Float.t b/t/Form/Float.t index 4da3b0d34..9d315832f 100644 --- a/t/Form/Float.t +++ b/t/Form/Float.t @@ -88,7 +88,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::Float'; my $formType = 'Float'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 3; plan tests => $numTests; @@ -143,3 +143,11 @@ is($input->{maxlength}, 20, 'set maxlength'); WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); +# just testing that getValueFromPost works with an argument + +my $float = WebGUI::Form::Float->new($session); +is($float->getValueFromPost('112.233'), 112.233, 'Got a valid float'); +is($float->getValueFromPost('fred'), 0, 'Returned 0 instead of an invalid float'); + +__END__ + diff --git a/t/Form/Integer.t b/t/Form/Integer.t index 20fbbd85e..76aa14042 100644 --- a/t/Form/Integer.t +++ b/t/Form/Integer.t @@ -63,7 +63,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::Integer'; my $formType = 'Integer'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 11; plan tests => $numTests; @@ -120,3 +120,21 @@ is($input->{maxlength}, 20, 'set maxlength'); WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); +# just testing that getValueFromPost works with an argument + +my $int = WebGUI::Form::Integer->new($session); +is($int->getValueFromPost(-123456), -123456, 'getValueFromPost(-123456)'); +is($int->getValueFromPost('002300'), '002300', 'getValueFromPost(002300)'); +is($int->getValueFromPost('+123456'), 0, 'getValueFromPost(+123456)'); +is($int->getValueFromPost('123-456.'), 0, 'getValueFromPost(123-456.)'); +is($int->getValueFromPost(123.456), 0, 'getValueFromPost(123.456)'); + +is($session->form->integer(undef,-123456), -123456, 'session->form->integer(undef,-123456)'); +is($session->form->integer(undef,'002300'), '002300', 'session->form->integer(undef,002300)'); +is($session->form->integer(undef,'+123456'), 0, 'session->form->integer(undef,+123456)'); +is($session->form->integer(undef,'123-456.'), 0, 'session->form->integer(undef,123-456.)'); +is($session->form->integer(undef,123.456), 0, 'session->form->integer(undef,123.456)'); + + +__END__ + diff --git a/t/Form/Phone.t b/t/Form/Phone.t index fc0f8adc9..82fe4bf87 100644 --- a/t/Form/Phone.t +++ b/t/Form/Phone.t @@ -87,7 +87,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::Phone'; my $formType = 'Phone'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 10; plan tests => $numTests; @@ -144,3 +144,17 @@ is($input->{maxlength}, 20, 'set maxlength'); WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); +# test that we can process non-POST values correctly +my $cntl = WebGUI::Form::Phone->new($session,{ defaultValue => 4242 }); +is($cntl->getValueFromPost('123-123-1234'), '123-123-1234', 'getValueFromPost(valid)'); +is($cntl->getValueFromPost('123/123-1234'), undef, 'getValueFromPost(invalid)'); +is($cntl->getValueFromPost(0), 0, 'zero'); +is($cntl->getValueFromPost(''), undef, '""'); +is($session->form->phone(undef,'123-123-1234'), '123-123-1234', 'valid'); +is($session->form->phone(undef,'123/123-1234'), undef, 'invalid'); +is($session->form->phone(undef,0), 0, 'zero'); +is($session->form->phone(undef,undef), undef, 'undef returns undef'); +is($session->form->phone(undef,''), undef, '""'); + +__END__ + diff --git a/t/Form/SelectBox.t b/t/Form/SelectBox.t index 477924dec..a3a577f22 100644 --- a/t/Form/SelectBox.t +++ b/t/Form/SelectBox.t @@ -48,7 +48,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::SelectBox'; my $formType = 'SelectBox'; -my $numTests = 8 + scalar @{ $testBlock } + 1; +my $numTests = 8 + scalar @{ $testBlock } + 12; plan tests => $numTests; @@ -107,3 +107,20 @@ is($input->{size}, 5, 'set size'); ##Test Form Output parsing WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); + +# test that we can process non-POST values correctly +my $cntl = WebGUI::Form::SelectBox->new($session,{ defaultValue => 4242 }); +is($cntl->getValueFromPost('text'), 'text', 'getValueFromPost(text)'); +is($cntl->getValueFromPost(42), 42, 'getValueFromPost(int)'); +is($cntl->getValueFromPost(0), 0, 'zero'); +is($cntl->getValueFromPost(''), '', '""'); +is($cntl->getValueFromPost(1,2,3), 1, 'list returns first item'); +is($session->form->selectBox(undef,'text'), 'text', 'text'); +is($session->form->selectBox(undef,42), 42, 'int'); +is($session->form->selectBox(undef,0), 0, 'zero'); +is($session->form->selectBox(undef,undef), '', 'undef returns ""'); +is($session->form->selectBox(undef,''), '', '""'); +is($session->form->selectBox(undef,1,2,3), 1, 'list returns first item'); + +__END__ + diff --git a/t/Form/Text.t b/t/Form/Text.t index de3821c31..fcbde3fb6 100644 --- a/t/Form/Text.t +++ b/t/Form/Text.t @@ -56,7 +56,7 @@ my $testBlock = [ my $formType = 'text'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 9; plan tests => $numTests; @@ -113,3 +113,17 @@ is($input->{maxlength}, 200, 'Checking maxlength param, set'); ##Test Form Output parsing WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); + +# test that we can process non-POST values correctly +my $cntl = WebGUI::Form::Text->new($session,{ defaultValue => 4242 }); +is($cntl->getValueFromPost('123-123-1234'), '123-123-1234', 'getValueFromPost(valid)'); +is($cntl->getValueFromPost(0), 0, 'zero'); +is($cntl->getValueFromPost(''), '', '""'); +is($cntl->getValueFromPost(undef), undef, 'undef returns undef'); +is($session->form->text(undef,'123-123-1234'), '123-123-1234', 'valid'); +is($session->form->text(undef,0), 0, 'zero'); +is($session->form->text(undef,undef), undef, 'undef returns undef'); +is($session->form->text(undef,''), '', '""'); + +__END__ + diff --git a/t/Form/Textarea.t b/t/Form/Textarea.t index 3a7854fd7..911214cd8 100644 --- a/t/Form/Textarea.t +++ b/t/Form/Textarea.t @@ -44,7 +44,7 @@ my $testBlock = [ my $formType = 'textarea'; -my $numTests = 12 + scalar @{ $testBlock } + 1; +my $numTests = 12 + scalar @{ $testBlock } + 5; plan tests => $numTests; @@ -99,3 +99,16 @@ like($input->{style}, qr/width: 500/, 'Custom width'); ##Test Form Output parsing WebGUI::Form_Checking::auto_check($session, $formType, $testBlock); + +# just testing that getValueFromPost works with an argument + +my $txt = WebGUI::Form::Textarea->new($session); +is($txt->getValueFromPost("some test here"), "some test here", 'getValueFromPost(text)'); +is($txt->getValueFromPost("some \ntest \r\nhere"), "some \ntest \r\nhere", 'getValueFromPost(newlines)'); + +is($session->form->textarea(undef,"some test here"), "some test here", 'session->form->textarea(undef,text)'); +is($session->form->textarea(undef,"some \ntest \r\nhere"), "some \ntest \r\nhere", 'session->form->textarea(undef,newlines)'); + + +__END__ + diff --git a/t/Form/Url.t b/t/Form/Url.t index a02203063..2576a2f4f 100644 --- a/t/Form/Url.t +++ b/t/Form/Url.t @@ -74,7 +74,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::Url'; -my $numTests = 11 + scalar @{ $testBlock } + 1; +my $numTests = 11 + scalar @{ $testBlock } + 15; plan tests => $numTests; @@ -131,3 +131,24 @@ is($input->{maxlength}, 1024, 'set maxlength'); ##Test Form Output parsing WebGUI::Form_Checking::auto_check($session, 'Url', $testBlock); + +# test that we can process non-POST values correctly +my $cntl = WebGUI::Form::Url->new($session,{ defaultValue => 4242 }); +is($cntl->getValueFromPost('mailto:whatever'), 'mailto:whatever', 'mailto processing'); +is($cntl->getValueFromPost('me@nowhere.com'), 'mailto:me@nowhere.com', 'email address processing'); +is($cntl->getValueFromPost('/'), '/', '/'); +is($cntl->getValueFromPost('://'), '://', '://'); +is($cntl->getValueFromPost('^'), '^', '^'); +is($cntl->getValueFromPost('mySite'), 'http://mySite', 'http://mySite'); +is($cntl->getValueFromPost('??**()!!'), 'http://??**()!!', 'random crap is passed through'); + +is($session->form->url(undef,'mailto:whatever'), 'mailto:whatever', 'mailto processing'); +is($session->form->url(undef,'me@nowhere.com'), 'mailto:me@nowhere.com', 'email address processing'); +is($session->form->url(undef,'/'), '/', '/'); +is($session->form->url(undef,'://'), '://', '://'); +is($session->form->url(undef,'^'), '^', '^'); +is($session->form->url(undef,'mySite'), 'http://mySite', 'http://mySite'); +is($session->form->url(undef,'??**()!!'), 'http://??**()!!', 'random crap is passed through'); + +__END__ + diff --git a/t/Form/Zipcode.t b/t/Form/Zipcode.t index c7d9c8b76..d8584e824 100644 --- a/t/Form/Zipcode.t +++ b/t/Form/Zipcode.t @@ -62,7 +62,7 @@ my $testBlock = [ my $formClass = 'WebGUI::Form::Zipcode'; -my $numTests = 12 + scalar @{ $testBlock } + 1; +my $numTests = 12 + scalar @{ $testBlock } + 11; plan tests => $numTests; @@ -117,3 +117,21 @@ is($input->{maxlength}, 13, 'Checking maxlength param, default'); ##Test Form Output parsing WebGUI::Form_Checking::auto_check($session, 'Zipcode', $testBlock); + +# test that we can process non-POST values correctly +my $cntl = WebGUI::Form::Zipcode->new($session,{ defaultValue => 4242 }); +is($cntl->getValueFromPost('ABCDE'), 'ABCDE', 'alpha'); +is($cntl->getValueFromPost('02468'), '02468', 'numeric'); +is($cntl->getValueFromPost('NO WHERE'), 'NO WHERE', 'alpha space'); +is($cntl->getValueFromPost('-'), '-', 'bare dash'); +is($cntl->getValueFromPost('abcde'), undef, 'lower case'); + +is($session->form->zipcode(undef,'ABCDE'), 'ABCDE', 'alpha'); +is($session->form->zipcode(undef,'02468'), '02468', 'numeric'); +is($session->form->zipcode(undef,'NO WHERE'), 'NO WHERE', 'alpha space'); +is($session->form->zipcode(undef,'-'), '-', 'bare dash'); +is($session->form->zipcode(undef,'abcde'), undef, 'lower case'); + + +__END__ +