diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 1d1048b36..010b1a9ab 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,7 +1,7 @@ 7.6.1 - changed: the list of extensions for the export system to pass through unmodified has been moved to the configuration file under the - "exportBianryExtensions" field. + "exportBinaryExtensions" field. - fixed: some default assets have ids shorter than 22 characters - fixed: failure when submitting a dataform that sends mail with an empty file field - fixed: DataForm ignores height on textarea fields @@ -30,6 +30,8 @@ - rfe: Thingy Private Rows (SDH Consulting Group) - fixed: Shop: Percentage of Weight Shipping Method doesn't work - fixed #8776: duplicate does not duplicate keywords + - rfe: Thingy: export extra rows, meta data (SDH Consulting Group) + - rfe: Thingy: Max entries per user (SDH Consulting Group) 7.6.0 - added: users may now customize the post received page for the CS diff --git a/docs/upgrades/upgrade_7.6.0-7.6.1.pl b/docs/upgrades/upgrade_7.6.0-7.6.1.pl index 6cdef2273..beeffbfa0 100644 --- a/docs/upgrades/upgrade_7.6.0-7.6.1.pl +++ b/docs/upgrades/upgrade_7.6.0-7.6.1.pl @@ -31,6 +31,7 @@ my $session = start(); # this line required addExportExtensionsToConfigFile($session); fixShortAssetIds( $session ); addDataFormDataIndexes($session); +addThingyColumns( $session ); finish($session); # this line required @@ -82,6 +83,13 @@ sub addDataFormDataIndexes { print "Done.\n" unless $quiet; } +sub addThingyColumns { + my $session = shift; + print "\tAdding exportMetaData and maxEntriesPerUser columns to Thingy_things table... " unless $quiet; + $session->db->write('ALTER TABLE `Thingy_things` ADD exportMetaData int(11)'); + $session->db->write('ALTER TABLE `Thingy_things` ADD maxEntriesPerUser int(11)'); + print "Done.\n" unless $quiet; +} # -------------- DO NOT EDIT BELOW THIS LINE -------------------------------- diff --git a/lib/WebGUI/Asset/Wobject/Thingy.pm b/lib/WebGUI/Asset/Wobject/Thingy.pm index 5cfe1797c..6097facb5 100644 --- a/lib/WebGUI/Asset/Wobject/Thingy.pm +++ b/lib/WebGUI/Asset/Wobject/Thingy.pm @@ -350,8 +350,7 @@ sub deleteThingData { my $thingDataId = shift; my $db = $self->session->db; - my ($groupIdEdit) = $db->quickArray("select groupIdEdit from Thingy_things where thingId=?",[$thingId]); - return undef unless $self->hasPrivileges($groupIdEdit); + return undef unless $self->canEditThingData($thingId, $thingDataId);; $self->deleteCollateral("Thingy_".$thingId,"thingDataId",$thingDataId); @@ -1042,6 +1041,38 @@ sub getThings { } +#------------------------------------------------------------------- + +=head2 hasEnteredMaxPerUser + +Check whether the current user has entered the maximum number of entries allowed for this thing. + +=head3 thingId + +The unique id of a thing. + +=cut + +sub hasEnteredMaxPerUser { + my ($self,$thingId) = @_; + my $session = $self->session; + my $db = $session->db; + + my $maxEntriesPerUser = $db->quickScalar("select maxEntriesPerUser from Thingy_things where thingId=?",[$thingId]); + + return 0 unless $maxEntriesPerUser; + + my $numberOfEntries = $session->db->quickScalar("select count(*) " + ."from ".$session->db->dbh->quote_identifier("Thingy_".$thingId)." where createdById=?",[$session->user->userId]); + + if($numberOfEntries < $maxEntriesPerUser){ + return 0; + } + else{ + return 1; + } +} + #------------------------------------------------------------------- =head2 hasPrivileges ( groupId ) @@ -1359,14 +1390,11 @@ Deletes data in a Thing. sub www_deleteThingDataConfirm { - my $self = shift; - my $db = $self->session->db; - - my $thingId = $self->session->form->process("thingId"); + my $self = shift; + my $thingId = $self->session->form->process("thingId"); my $thingDataId = $self->session->form->process('thingDataId'); - my ($groupIdEdit) = $db->quickArray("select groupIdEdit from Thingy_things where thingId=?",[$thingId]); - return $self->session->privilege->insufficient() unless $self->hasPrivileges($groupIdEdit); + return $self->session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId); $self->deleteThingData($thingId,$thingDataId); @@ -1385,7 +1413,6 @@ sub www_deleteThingDataViaAjax { my $self = shift; my $session = $self->session; - my $db = $session->db; my $thingId = $self->session->form->process("thingId"); my $thingDataId = $self->session->form->process('thingDataId'); @@ -1399,8 +1426,8 @@ sub www_deleteThingDataViaAjax { my $thingProperties = $self->getThing($thingId); if ($thingProperties->{thingId}){ - my ($groupIdEdit) = $db->quickArray("select groupIdEdit from Thingy_things where thingId=?",[$thingId]); - return $session->privilege->insufficient() unless $self->hasPrivileges($groupIdEdit); + return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId + ,$thingProperties); $self->deleteThingData($thingId,$thingDataId); @@ -1459,6 +1486,8 @@ sub www_editThing { groupIdImport=>$groupIdEdit, searchTemplateId=>"ThingyTmpl000000000004", thingsPerPage=>25, + exportMetaData=>undef, + maxEntriesPerUser=>undef, ); $thingId = $self->addThing(\%properties,0); } @@ -1654,6 +1683,12 @@ sub www_editThing { -width => 300, -height => 200, ); + $tab->integer( + -name=> "maxEntriesPerUser", + -value=> $properties{maxEntriesPerUser}, + -hoverHelp=> $i18n->get('max entries per user description'), + -label => $i18n->get('max entries per user label') + ); $tab->group( -name=> "groupIdAdd", -value=> $properties{groupIdAdd}, @@ -1804,6 +1839,12 @@ sub www_editThing { -hoverHelp=> $i18n->get('who can export description'), -label=>$i18n->get('who can export label') ); + $tab->yesNo( + -name=> "exportMetaData", + -value=> $properties{exportMetaData}, + -hoverHelp=> $i18n->get('export metadata description'), + -label=>$i18n->get('export metadata label') + ); $tab->template( -name=>"searchTemplateId", -value=>$properties{searchTemplateId}, @@ -1881,7 +1922,9 @@ sub www_editThingSave { groupIdExport=>$form->process("groupIdExport"), searchTemplateId=>$form->process("searchTemplateId") || 1, thingsPerPage=>$form->process("thingsPerPage") || 25, - sortBy=>$form->process("sortBy"), + sortBy=>$form->process("sortBy") || '', + exportMetaData=>$form->process("exportMetaData") || '', + maxEntriesPerUser=>$form->process("maxEntriesPerUser") || '', },0,1); if($fields->rows < 1){ @@ -2120,18 +2163,24 @@ Shows a form to edit a things data. sub editThingData { - my $self = shift; - my $session = $self->session; - my $thingId = shift || $session->form->process('thingId'); - my $thingDataId = shift || $session->form->process('thingDataId') || "new"; + my $self = shift; + my $session = $self->session; + my $thingId = shift || $session->form->process('thingId'); + my $thingDataId = shift || $session->form->process('thingDataId') || "new"; my $thingProperties = shift || $self->getThing($thingId); + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); - return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId, $thingProperties); + my $canEditThingData = $self->canEditThingData($thingId, $thingDataId, $thingProperties); + + return $session->privilege->insufficient() unless $canEditThingData; + + if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){ + return $i18n->get("has entered max per user message"); + } my (%thingData, $fields,@field_loop,$fieldValue, $privilegedGroup); my $var = $self->get; my $url = $self->getUrl; - my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); my $errors = shift; $var->{error_loop} = $errors if ($errors); @@ -2140,14 +2189,14 @@ sub editThingData { $var->{"manage_url"} = $session->url->append($url, 'func=manage'); $var->{"thing_label"} = $thingProperties->{label}; - if($self->hasPrivileges($thingProperties->{groupIdEdit})){ + if($canEditThingData){ if ($thingDataId ne "new"){ $var->{"delete_url"} = $session->url->append($url, 'func=deleteThingDataConfirm;thingId=' .$thingId.';thingDataId='.$thingDataId); } $var->{"delete_confirm"} = "onclick=\"return confirm('".$i18n->get("delete thing data warning")."')\""; } - if($self->hasPrivileges($thingProperties->{groupIdAdd})){ + if($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$self->hasEnteredMaxPerUser($thingId)){ $var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new'); } if($self->hasPrivileges($thingProperties->{groupIdSearch})){ @@ -2215,18 +2264,23 @@ Processes and saves data for a Thing. sub www_editThingDataSave { - my $self = shift; - my $session = $self->session; + my $self = shift; + my $session = $self->session; + my $thingId = $session->form->process('thingId'); + my $thingDataId = $session->form->process('thingDataId'); + my $i18n = WebGUI::International->new($session, "Asset_Thingy"); + my ($var,$newThingDataId, $fields,%thingData,@errors,$errors,$otherThingId); my ($privilegedGroup,$workflowId); - my $thingId = $session->form->process('thingId'); - my $thingDataId = $session->form->process('thingDataId'); - my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); my $thingProperties = $self->getThing($thingId); return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId ,$thingProperties); + if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){ + return $i18n->get("has entered max per user message"); + } + ($newThingDataId,$errors) = $self->editThingDataSave($thingId,$thingDataId); if (scalar @$errors > 0){ @@ -2280,6 +2334,7 @@ sub www_editThingDataSaveViaAjax { my $session = $self->session; my $thingId = shift || $session->form->process('thingId'); my $thingDataId = shift || $session->form->process('thingDataId'); + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); unless ($thingId && $thingDataId) { $session->http->setStatus("400", "Bad Request"); @@ -2292,6 +2347,12 @@ sub www_editThingDataSaveViaAjax { return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId ,$thingProperties); + + if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){ + $session->http->setStatus("400", "Bad Request"); + return JSON->new->utf8->encode({message => $i18n->get("has entered max per user message")}); + } + my ($newThingDataId,$errors) = $self->editThingDataSave($thingId,$thingDataId); if ($errors){ @@ -2333,6 +2394,10 @@ sub www_export { push(@fieldLabels,$field->{label}); } } + my @metaDataFields = ('thingDataId','dateCreated','createdById','updatedById','updatedByName','lastUpdated','ipAddress'); + if ($thingProperties->{exportMetaData}){ + push(@fieldLabels,@metaDataFields) + } $query = WebGUI::Cache->new($self->session,"query_".$thingId)->get; $sth = $session->db->read($query); @@ -2350,6 +2415,9 @@ sub www_export { my $value = $self->getFieldValue($data->{"field_".$fieldId},$field->{properties},"%y-%m-%d","%y-%m-%d %j:%n:%s"); push(@fieldValues, $value); } + foreach my $metaDataField (@metaDataFields){ + push(@fieldValues,$data->{$metaDataField}); + } $out .= "\n".WebGUI::Text::joinCSV( @fieldValues ); @@ -2500,11 +2568,12 @@ sub www_import { my @duplicatesConstraint; # Create duplicate constraint - foreach my $insertValue (@data){ - my $fieldId = $insertColumns[$fieldNumber]->{fieldId}; - if ($session->form->process("checkDuplicates_".$fieldId)){ + foreach my $insertColumn (@insertColumns){ + my $insertValue = $data[$fieldNumber]; + if ($session->form->process("checkDuplicates_".$insertColumn->{fieldId})){ #$error->info("adding $fieldId to duplicates constraint"); - push(@duplicatesConstraint,$dbh->quote_identifer("field_".$fieldId)." = ".$session->db->quote($insertValue)); + push(@duplicatesConstraint,$dbh->quote_identifier("field_".$insertColumn->{fieldId}) + ." = ".$session->db->quote($insertValue)); } $fieldNumber++; } @@ -2523,10 +2592,11 @@ sub www_import { $fieldNumber = 0; # Populate thingData hash - foreach my $fieldValue (@data){ - my $fieldName = "field_".$insertColumns[$fieldNumber]->{fieldId}; - my $fieldType = $insertColumns[$fieldNumber]->{fieldType}; - my $fieldInOtherThingId = $insertColumns[$fieldNumber]->{fieldInOtherThingId}; + foreach my $insertColumn (@insertColumns){ + my $fieldValue = $data[$fieldNumber]; + my $fieldName = "field_".$insertColumn->{fieldId}; + my $fieldType = $insertColumn->{fieldType}; + my $fieldInOtherThingId = $insertColumn->{fieldInOtherThingId}; # TODO: process dates and otherThing field id's if ($fieldType eq "date" || $fieldType eq "dateTime"){ $fieldValue =~ s/\//-/gx; @@ -2885,7 +2955,7 @@ sub getSearchTemplateVars { if ($self->hasPrivileges($thingProperties->{groupIdImport})){ $var->{"import_url"} = $session->url->append($url, 'func=importForm;thingId='.$thingId); } - if ($self->hasPrivileges($thingProperties->{groupIdAdd})){ + if ($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$self->hasEnteredMaxPerUser($thingId)){ $var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new'); } $var->{searchScreenTitle} = $thingProperties->{searchScreenTitle}; @@ -2943,6 +3013,9 @@ sequenceNumber'); my $noFields = 0; if (scalar(@displayInSearchFields)){ $query = "select thingDataId, "; + if ($thingProperties->{exportMetaData}){ + $query .= "dateCreated, createdById, updatedById, updatedByName, lastUpdated, ipAddress, "; + } $query .= join(", ",map {$dbh->quote_identifier('field_'.$_->{fieldId})} @displayInSearchFields); $query .= " from ".$dbh->quote_identifier("Thingy_".$thingId); $query .= " where ".join(" and ",@constraints) if (scalar(@constraints) > 0); @@ -3156,7 +3229,7 @@ sub www_viewThingData { .$thingId.';thingDataId='.$thingDataId); $var->{"delete_confirm"} = "onclick=\"return confirm('".$i18n->get("delete thing data warning")."')\""; } - if($self->hasPrivileges($thingProperties->{groupIdAdd})){ + if($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$self->hasEnteredMaxPerUser($thingId)){ $var->{"add_url"} = $session->url->append($url, 'func=editThingData;thingId='.$thingId.';thingDataId=new'); } if($self->hasPrivileges($thingProperties->{groupIdSearch})){ diff --git a/lib/WebGUI/i18n/English/Asset_Thingy.pm b/lib/WebGUI/i18n/English/Asset_Thingy.pm index 8fc42ce63..ebfd5e681 100644 --- a/lib/WebGUI/i18n/English/Asset_Thingy.pm +++ b/lib/WebGUI/i18n/English/Asset_Thingy.pm @@ -112,6 +112,21 @@ our $I18N = { lastUpdated => 1104630516, }, + 'max entries per user label' => { + message => q|Max entries per user|, + lastUpdated => 1223638290, + }, + + 'max entries per user description' => { + message => q|The maximum number of entries a user can add of this thing.|, + lastUpdated => 1223638290, + }, + + 'has entered max per user message' => { + message => q|You have reached the maximum number of entries.|, + lastUpdated => 1223638290, + }, + 'who can add label' => { message => q|Who can add?|, lastUpdated => 1104630516, @@ -322,6 +337,17 @@ wobject can always view and edit all data.|, lastUpdated => 1104630516, }, + 'export metadata label' => { + message => q|Export meta data?|, + lastUpdated => 1223555688, + }, + + 'export metadata description' => { + message => q|Should the export function include the meta data fields like thingDataId, lastUpdated, +ipAddress etc?|, + lastUpdated => 1223555688, + }, + 'search button label' => { message => q|Search|, lastUpdated => 1104630516,