From 3d8878965994dcd231217aebae37482f82c0be03 Mon Sep 17 00:00:00 2001 From: Yung Han Khoe Date: Mon, 16 Nov 2009 17:37:18 +0100 Subject: [PATCH] Separating Thing object from Thingy --- docs/upgrades/upgrade_7.8.4-7.8.5.pl | 5 + lib/WebGUI/Asset/Wobject/Thingy.pm | 373 ++++++++--------------- lib/WebGUI/Asset/Wobject/Thingy/Thing.pm | 340 +++++++++++++++++++++ t/Asset/Wobject/Thingy.t | 87 +++++- 4 files changed, 542 insertions(+), 263 deletions(-) create mode 100644 lib/WebGUI/Asset/Wobject/Thingy/Thing.pm diff --git a/docs/upgrades/upgrade_7.8.4-7.8.5.pl b/docs/upgrades/upgrade_7.8.4-7.8.5.pl index 363cd8c5e..1314a2126 100644 --- a/docs/upgrades/upgrade_7.8.4-7.8.5.pl +++ b/docs/upgrades/upgrade_7.8.4-7.8.5.pl @@ -57,6 +57,11 @@ sub changeThingyThingTables { my $session = shift; my $db = $session->db; print "\tChanging Thingy's Thing tables to conform with CRUD ... " unless $quiet; + + $db->write('ALTER TABLE Thingy_things ADD `sequencenumber` INT(11)'); + $db->write('ALTER TABLE Thingy_things ADD `dateCreated` DATETIME'); + $db->write('ALTER TABLE Thingy_things ADD `lastUpdated` DATETIME'); + my $things = $db->read('select thingId from Thingy_things'); while (my @thing = $things->array) { my $tableName = 'Thingy_'.$thing[0]; diff --git a/lib/WebGUI/Asset/Wobject/Thingy.pm b/lib/WebGUI/Asset/Wobject/Thingy.pm index c9ed7cee1..460fef31d 100644 --- a/lib/WebGUI/Asset/Wobject/Thingy.pm +++ b/lib/WebGUI/Asset/Wobject/Thingy.pm @@ -21,8 +21,10 @@ use WebGUI::DateTime; use base 'WebGUI::Asset::Wobject'; use Data::Dumper; use WebGUI::Asset::Wobject::Thingy::ThingRecord; +use WebGUI::Asset::Wobject::Thingy::Thing; -my $THING_RECORD_CLASS = 'WebGUI::Asset::Wobject::Thingy::ThingRecord'; +my $THING_CLASS = 'WebGUI::Asset::Wobject::Thingy::Thing'; +my $THING_RECORD_CLASS = 'WebGUI::Asset::Wobject::Thingy::ThingRecord'; #------------------------------------------------------------------- @@ -99,52 +101,34 @@ If isImport is true the new thing will keep the thingId and assetId in the prope sub addThing { - my $self = shift; - my $thing = shift; - my $isImport = shift; - my $db = $self->session->db; - my $error = $self->session->errorHandler; - my ($oldThingId, $newThingId,$useAssetId); + my $self = shift; + my $thing = shift; + my $isImport = shift; + my $db = $self->session->db; + my $error = $self->session->errorHandler; + my $options; $error->info("Adding Thing, label: ".$thing->{label}.", id: ".$thing->{thingId}); if ($isImport){ - $oldThingId = $thing->{thingId}; + $options->{id} = $thing->{thingId}; } else{ - $useAssetId = 1; + $thing->{assetId} = $self->getId; } - $thing->{thingId} = "new"; - $newThingId = $self->setCollateral("Thingy_things","thingId",$thing,0,$useAssetId); + my $newThing = $THING_CLASS->create($self, $thing, $options); - if ($isImport){ - $db->write("update Thingy_things set thingId = ".$db->quote($oldThingId) - ." where thingId = ".$db->quote($newThingId)); - $newThingId = $oldThingId; - } - else{ + unless($isImport){ # Set this Thingy assets defaultThingId if this is its first Thing. my ($numberOfThings) = $db->quickArray('select count(*) from Thingy_things where assetId=?' ,[$self->getId]); if ($numberOfThings == 1){ - $self->update({defaultThingId => $newThingId}); + $self->update({defaultThingId => $newThing->getId}); } } - $db->write("create table ".$db->dbh->quote_identifier("Thingy_".$newThingId)."( - thingDataId CHAR(22) binary not null, - dateCreated datetime not null, - createdById CHAR(22) not null, - updatedById CHAR(22) not null, - updatedByName CHAR(255) not null, - lastUpdated datetime not null, - ipAddress CHAR(255), - sequenceNumber int, - primary key (thingDataId) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - - return $newThingId; + return $newThing->getId; } @@ -166,9 +150,12 @@ A thingId. Will set the isCurrent flag in these template variables for the thing sub appendThingsVars { my ($self, $vars, $currentThingId) = @_; - my $things = $self->getThings; my @thingLoop = (); - while (my $thing = $things->hashRef) { + my $getAThing = $THING_CLASS->getAllIterator($self->session,{constraints => [ + {"assetId=?" => $self->getId}, + ]}); + while (my $thingObject = $getAThing->()) { + my $thing = $thingObject->get; push @thingLoop, { name => $thing->{label}, canView => $self->hasPrivileges($thing->{groupIdView}), @@ -198,7 +185,7 @@ Pass in the groupId if you already have the view group for the thing. sub canViewThing { my ($self, $thingId, $groupId) = @_; if ($groupId eq "") { - $groupId = $self->session->db->quickScalar("select groupIdView from Thingy_things where thingId=?", [$thingId]); + $groupId = $THING_CLASS->new($self->session,$thingId)->get('groupIdView'); } return $self->hasPrivileges($groupId); } @@ -289,11 +276,12 @@ Duplicates a Thingy, including the definitions of the Things in this Thingy and =cut sub duplicate { - my $self = shift; - my $options = shift; - my $newAsset = $self->SUPER::duplicate($options); - my $db = $self->session->db; - my $assetId = $self->get("assetId"); + my $self = shift; + my $options = shift; + my $newAsset = $self->SUPER::duplicate($options); + my $session = $self->session; + my $db = $session->db; + my $assetId = $self->get("assetId"); my $fields; my $otherThingFields = $db->buildHashRefOfHashRefs( @@ -302,8 +290,11 @@ sub duplicate { [$assetId],'fieldInOtherThingId' ); - my $things = $self->getThings; - while ( my $thing = $things->hashRef) { + my $getAThing = $THING_CLASS->getAllIterator($session,{constraints => [ + {"assetId=?" => $self->getId}, + ]}); + while (my $thingObject = $getAThing->()) { + my $thing = $thingObject->get; my $oldSortBy = $thing->{sortBy}; my $oldThingId = $thing->{thingId}; my $newThingId = $newAsset->addThing($thing,0); @@ -317,10 +308,8 @@ sub duplicate { my $newFieldId = $newAsset->addField($field,0); if ($originalFieldId eq $oldSortBy){ - $self->session->db->write( "update Thingy_things set sortBy = ? where thingId = ?", - [ $newFieldId, $newThingId ] ); + $THING_CLASS->new($session,$newThingId)->update({'sortBy' => $newFieldId,}); } - if ($otherThingFields->{$originalFieldId}){ $otherThingFields->{$originalFieldId}->{newFieldType} = 'otherThing_'.$newThingId; $otherThingFields->{$originalFieldId}->{newFieldId} = $newFieldId; @@ -355,7 +344,7 @@ sub duplicateThing { my $oldThingId = shift; my $db = $self->session->db; - my $thingProperties = $self->getThing($oldThingId); + my $thingProperties = $THING_CLASS->new($self->session,$oldThingId)->get; $thingProperties->{thingId} = 'new'; $thingProperties->{label} = $thingProperties->{label}.' (copy)'; @@ -491,33 +480,6 @@ sub deleteThingData { #------------------------------------------------------------------- -=head2 deleteThing ( thingId ) - -Deletes a Thing and its fields from Collateral and drops the things table. - -=head3 thingId - -The id of the Thing that should be deleted. - -=cut - -sub deleteThing { - - my $self = shift; - my $thingId = shift; - my $session = $self->session; - my $error = $session->errorHandler; - - $self->deleteCollateral("Thingy_things","thingId",$thingId); - $self->deleteCollateral("Thingy_fields","thingId",$thingId); - $session->db->write("drop table if exists ".$session->db->dbh->quote_identifier("Thingy_".$thingId)); - - $error->info("Deleted thing: $thingId."); - return undef; -} - -#------------------------------------------------------------------- - =head2 editThingDataSave ( ) Saves a row of thing data and triggers the appropriate workflow triggers. @@ -1126,23 +1088,6 @@ sub getHtmlWithModuleWrapper { #------------------------------------------------------------------- -=head2 getThing ( thingId ) - -Returns a hash reference of the properties of a thing. - -=head3 thingId - -The unique id of a thing. - -=cut - -sub getThing { - my ($self, $thingId) = @_; - return $self->session->db->quickHashRef("select * from Thingy_things where thingId=?",[$thingId]); -} - -#------------------------------------------------------------------- - =head2 getViewThingVars ( ) Returns the field values of a thing instance and the title for its view screen in a tmpl var hashref. @@ -1215,52 +1160,6 @@ sub getViewThingVars { #------------------------------------------------------------------- -=head2 getThings ( ) - -Returns a result set with all the things in the database. - -=cut - -sub getThings { - my ($self) = @_; - return $self->session->db->read("select * from Thingy_things where assetId=?",[$self->getId]); -} - - -#------------------------------------------------------------------- - -=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 ) Checks if the current user has a certain privilege on a Thing. @@ -1320,11 +1219,12 @@ sub importAssetCollateralData { } } # delete deleted things - my $thingsInDatabase = $self->getThings; - while (my $thingInDataBase = $thingsInDatabase->hashRef) { - if (!WebGUI::Utility::isIn($thingInDataBase->{thingId},@importThings)){ - # delete thing - $self->deleteThing($thingInDataBase->{thingId}); + my $getAThing = $THING_CLASS->getAllIterator($session,{constraints => [ + {"assetId=?" => $self->getId}, + ]}); + while (my $thingInDatabase = $getAThing->()) { + if (!WebGUI::Utility::isIn($thingInDatabase->getId,@importThings)){ + $thingInDatabase->delete; } } @@ -1524,7 +1424,7 @@ sub view { if ($defaultThingId ne ""){ # get default view ($defaultView) = $db->quickArray("select defaultView from Thingy_things where thingId=?",[$defaultThingId]); - my $thingProperties = $self->getThing($defaultThingId); + my $thingProperties = $THING_CLASS->new($session,$defaultThingId)->get; if ($defaultView eq "searchThing"){ return $i18n->get("no permission to search") if( ! $self->canSearch($defaultThingId, $thingProperties)); return $self->search($defaultThingId,$thingProperties) @@ -1550,10 +1450,11 @@ Deletes a field definition. Drops the column of a Thing's table that holds the d =cut sub www_deleteFieldConfirm { - my $self = shift; + my $self = shift; my $session = $self->session; my $fieldId = $session->form->process("fieldId"); my $thingId = $session->form->process("thingId"); + return $session->privilege->insufficient() unless $self->canEdit; $self->deleteField($fieldId,$thingId); @@ -1611,12 +1512,17 @@ instances of this Thing. =cut sub www_deleteThingConfirm { - my $self = shift; + my $self = shift; + my $session = $self->session; my $thingId = $self->session->form->process("thingId"); + return $self->session->privilege->insufficient() unless $self->canEdit; - $self->deleteThing($thingId); - + my $thing = $THING_CLASS->new($session, $thingId); + if (defined $thing) { + $thing->delete; + } + return $self->www_manage; } @@ -1664,7 +1570,7 @@ sub www_deleteThingDataViaAjax { return JSON->new->encode({message => "Can't get thing data without a thingId and a thingDataId."}); } - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $THING_CLASS->new($session,$thingId)->get; if ($thingProperties->{thingId}){ return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId ,$thingProperties); @@ -1692,7 +1598,7 @@ before the form is submitted. =cut sub www_editThing { - my $self = shift; + my $self = shift; my $warning = shift; my $session = $self->session; my ($tabForm, $output, %properties, $tab, %afterSave, %defaultView, $fields, %editViewOptions); @@ -1707,32 +1613,10 @@ sub www_editThing { return $self->www_view unless ($thingId); if($thingId eq "new"){ - my $groupIdEdit = $self->get("groupIdEdit"); - %properties = ( - thingId=>$thingId, - label=>$i18n->get('thing name label'), - editScreenTitle=>$i18n->get('edit screen title label'), - groupIdAdd=>$groupIdEdit, - groupIdEdit=>$groupIdEdit, - saveButtonLabel=>$i18n->get('default save button label'), - afterSave=>'searchThisThing', - editTemplateId=>"ThingyTmpl000000000003", - groupIdView=>$groupIdEdit, - viewTemplateId=>"ThingyTmpl000000000002", - defaultView=>'searchThing', - searchScreenTitle=>$i18n->get('search screen title label'), - groupIdSearch=>$groupIdEdit, - groupIdExport=>$groupIdEdit, - groupIdImport=>$groupIdEdit, - searchTemplateId=>"ThingyTmpl000000000004", - thingsPerPage=>25, - exportMetaData=>undef, - maxEntriesPerUser=>undef, - ); $thingId = $self->addThing(\%properties,0); } else{ - %properties = %{$self->getThing($thingId)}; + %properties = %{$THING_CLASS->new($session,$thingId)->get}; } $tabForm = WebGUI::TabForm->new($self->session, undef, undef, $self->getUrl('func=view')); @@ -2139,56 +2023,34 @@ database immediately. sub www_editThingSave { - my $self = shift; - return $self->session->privilege->insufficient() unless $self->canEdit; - my $form = $self->session->form; - my ($thingId, $fields); - $thingId = $self->session->form->process("thingId"); + my $self = shift; + my $session = $self->session; + return $session->privilege->insufficient() unless $self->canEdit; + my $form = $session->form; + my ($thingId, $fields, $thing); + $thingId = $form->process("thingId"); $fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->get("assetId")).' and thingId = '.$self->session->db->quote($thingId).' order by sequenceNumber'); - - $self->setCollateral("Thingy_things","thingId",{ - thingId=>$thingId, - label=>$form->process("label"), - editScreenTitle=>$form->process("editScreenTitle"), - editInstructions=>$form->process("editInstructions"), - groupIdAdd=>$form->process("groupIdAdd"), - groupIdEdit=>$form->process("groupIdEdit"), - saveButtonLabel=>$form->process("saveButtonLabel"), - afterSave=>$form->process("afterSave"), - editTemplateId=>$form->process("editTemplateId") || 1, - onAddWorkflowId=>$form->process("onAddWorkflowId"), - onEditWorkflowId=>$form->process("onEditWorkflowId"), - onDeleteWorkflowId=>$form->process("onDeleteWorkflowId"), - groupIdView=>$form->process("groupIdView"), - viewTemplateId=>$form->process("viewTemplateId") || 1, - defaultView=>$form->process("defaultView"), - searchScreenTitle=>$form->process("searchScreenTitle"), - searchDescription=>$form->process("searchDescription"), - groupIdSearch=>$form->process("groupIdSearch"), - groupIdImport=>$form->process("groupIdImport"), - groupIdExport=>$form->process("groupIdExport"), - searchTemplateId=>$form->process("searchTemplateId") || 1, - thingsPerPage=>$form->process("thingsPerPage") || 25, - sortBy=>$form->process("sortBy") || '', - exportMetaData=>$form->process("exportMetaData") || '', - maxEntriesPerUser=>$form->process("maxEntriesPerUser") || '', - },0,1); + $thing = $THING_CLASS->new($session,$thingId); + $thing->updateFromFormPost; if($fields->rows < 1){ - $self->session->log->warn("Thing failed to create because it had no fields"); - my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + $session->log->warn("Thing failed to create because it had no fields"); + my $i18n = WebGUI::International->new($session, "Asset_Thingy"); return $self->www_editThing($i18n->get("thing must have fields")); } while (my $field = $fields->hashRef) { - my $display = $self->session->form->process("display_".$field->{fieldId}) || 0; - my $viewScreenTitle = $self->session->form->process("viewScreenTitle_".$field->{fieldId}) || 0; - my $displayInSearch = $self->session->form->process("displayInSearch_".$field->{fieldId}) || 0; - my $searchIn = $self->session->form->process("searchIn_".$field->{fieldId}) || 0; + my $display = $form->process("display_".$field->{fieldId}) || 0; + my $viewScreenTitle = $form->process("viewScreenTitle_".$field->{fieldId}) || 0; + my $displayInSearch = $form->process("displayInSearch_".$field->{fieldId}) || 0; + my $searchIn = $form->process("searchIn_".$field->{fieldId}) || 0; - $self->session->db->write("update Thingy_fields set display = ".$display.", viewScreenTitle = ".$viewScreenTitle.", displayinSearch = ".$displayInSearch.", searchIn = ".$searchIn." where fieldId = ".$self->session->db->quote($field->{fieldId})." and thingId = ".$self->session->db->quote($thingId)); + $self->session->db->write("update Thingy_fields + set display = ?, viewScreenTitle = ?, displayinSearch = ?, searchIn = ? + where fieldId = ? and thingId = ?" + ,[$display,$viewScreenTitle,$displayInSearch,$searchIn,$field->{fieldId},$thingId]); } return $self->www_manage; } @@ -2353,7 +2215,7 @@ sub canEditThingData { 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 $thingProperties = shift || $THING_CLASS->new($session,$thingId)->get; my ($privilegedGroup); if ($thingDataId eq "new"){ @@ -2400,11 +2262,11 @@ A hashRef containing the properties of a thing. sub canViewThingData { - 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 $self = shift; + my $session = $self->session; + my $thingId = shift || $session->form->process('thingId'); + my $thingDataId = shift || $session->form->process('thingDataId') || "new"; + my $thingProperties = shift || $THING_CLASS->new($session,$thingId)->get; if ($thingProperties->{groupIdView} eq 'owner'){ my $owner = $session->db->quickScalar("select createdById " @@ -2437,7 +2299,8 @@ sub editThingData { 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 $thing = $THING_CLASS->new($session,$thingId); + my $thingProperties = shift || $thing->get; my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); my $canEditThingData = $self->canEditThingData($thingId, $thingDataId, $thingProperties); @@ -2469,7 +2332,7 @@ sub editThingData { $var->{"delete_confirm"} = "onclick=\"return confirm('".$i18n->get("delete thing data warning")."')\""; } - if($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$self->hasEnteredMaxPerUser($thingId)){ + if($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$thing->hasEnteredMaxPerUser){ $var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new'); } if($self->hasPrivileges($thingProperties->{groupIdSearch})){ @@ -2526,7 +2389,7 @@ sub editThingData { $var->{"form_end"} = WebGUI::Form::formFooter($self->session); $self->appendThingsVars($var, $thingId); - if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){ + if($thingDataId eq 'new' && $thing->hasEnteredMaxPerUser){ delete $var->{form_start}; delete $var->{form_end}; delete $var->{form_submit}; @@ -2551,15 +2414,16 @@ sub www_editThingDataSave { my $thingId = $session->form->process('thingId'); my $thingDataId = $session->form->process('thingDataId'); my $i18n = WebGUI::International->new($session, "Asset_Thingy"); + my $thing = $THING_CLASS->new($session,$thingId); my ($var,$newThingDataId, $fields,%thingData,@errors,$errors,$otherThingId); my ($privilegedGroup,$workflowId); - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $thing->get; return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId ,$thingProperties); - if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){ + if($thingDataId eq 'new' && $thing->hasEnteredMaxPerUser){ return $i18n->get("has entered max per user message"); } @@ -2617,20 +2481,21 @@ sub www_editThingDataSaveViaAjax { my $thingId = shift || $session->form->process('thingId'); my $thingDataId = shift || $session->form->process('thingDataId'); my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + my $thing = $THING_CLASS->new($session,$thingId); unless ($thingId && $thingDataId) { $session->http->setStatus("400", "Bad Request"); return JSON->new->encode({message => "Can't get thing data without a thingId and a thingDataId."}); } - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $thing->get; if ($thingProperties->{thingId}){ my ($privilegedGroup,$workflowId); return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId ,$thingProperties); - if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){ + if($thingDataId eq 'new' && $thing->hasEnteredMaxPerUser){ $session->http->setStatus("400", "Bad Request"); return JSON->new->encode({message => $i18n->get("has entered max per user message")}); } @@ -2662,7 +2527,7 @@ sub www_export { my ($query,$sth,$out,$fields,@fields,$fileName,@fieldLabels); my $thingId = $session->form->process('thingId'); - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $THING_CLASS->new($session,$thingId)->get; return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties->{groupIdExport}); $fields = $session->db->read('select * from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber', @@ -2736,7 +2601,7 @@ sub www_getThingViaAjax { return JSON->new->encode({message => "Can't return thing properties without a thingId."}); } - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $THING_CLASS->new($session,$thingId)->get; if ($thingProperties->{thingId}){ return $session->privilege->insufficient() unless $self->canViewThing($thingId, $thingProperties->{groupIdView}); @@ -2775,8 +2640,11 @@ sub www_getThingsViaAjax { $session->http->setMimeType("application/json"); my @visibleThings; - my $things = $self->getThings; - while (my $thing = $things->hashRef) { + my $getAThing = $THING_CLASS->getAllIterator($session,{constraints => [ + {"assetId=?" => $self->getId}, + ]}); + while (my $thingObject = $getAThing->()) { + my $thing = $thingObject->get; if ($self->canViewThing($thing->{thingId},$thing->{groupIdView})){ $thing->{canSearch} = $self->canSearch($thing->{thingId},$thing); $thing->{canEdit} = $self->hasPrivileges($thing->{groupIdEdit}); @@ -2803,14 +2671,14 @@ Imports data from a .csv file. =cut sub www_import { - my $self = shift; + my $self = shift; my $session = $self->session; - my $dbh = $session->db->dbh; + my $dbh = $session->db->dbh; my ($sql,$fields,@fields,$fileName,@insertColumns); my ($handleDuplicates,$newThingDataId); - my $thingId = $session->form->process('thingId'); - my $thingProperties = $self->getThing($thingId); + my $thingId = $session->form->process('thingId'); + my $thingProperties = $THING_CLASS->new($session,$thingId)->get; return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties->{groupIdImport}); $fields = $session->db->read('select label, fieldId, fieldType, fieldInOtherThingId from Thingy_fields ' @@ -2933,7 +2801,7 @@ sub www_importForm { my ($i18n,$form,$fields,$fieldOptions,$output); my $thingId = $session->form->process('thingId'); - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $THING_CLASS->new($session,$thingId)->get; return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties->{groupIdImport}); $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); @@ -3023,8 +2891,11 @@ sub www_manage { $var->{"view_url"} = $session->url->page; #Get things in this Thingy - $things = $self->getThings; - while (my $thing = $things->hashRef) { + my $getAThing = $THING_CLASS->getAllIterator($session,{constraints => [ + {"assetId=?" => $self->getId}, + ]}); + while (my $thingObject = $getAThing->()) { + my $thing = $thingObject->get; my %templateVars = ( 'thing_id' => $thing->{thingId}, 'thing_label' => $thing->{label}, @@ -3144,7 +3015,7 @@ sub www_searchViaAjax { my $self = shift; my $session = $self->session; my $thingId = shift || $session->form->process('thingId'); - my $thingProperties = shift || $self->getThing($thingId); + my $thingProperties = shift || $THING_CLASS->new($session,$thingId)->get; my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); unless ($thingId) { @@ -3177,9 +3048,10 @@ Checks if the user can perform a search. =cut sub canSearch { - my $self = shift; - my $thingId = shift || $self->session->form->process('thingId'); - my $thingProperties = shift || $self->getThing($thingId); + my $self = shift; + my $session = $self->session; + my $thingId = shift || $session->form->process('thingId'); + my $thingProperties = shift || $THING_CLASS->new($session,$thingId)->get; return $self->hasPrivileges($thingProperties->{groupIdSearch}); } @@ -3193,10 +3065,11 @@ Returns the search screen without style. sub search { - my $self = shift; - my $thingId = shift || $self->session->form->process('thingId'); - my $thingProperties = shift || $self->getThing($thingId); - my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); + my $self = shift; + my $session = $self->session; + my $thingId = shift || $session->form->process('thingId'); + my $thingProperties = shift || $THING_CLASS->new($session,$thingId)->get; + my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); return $i18n->get("no permission to search") if( ! $self->canSearch($thingId, $thingProperties)); @@ -3215,10 +3088,11 @@ Performs the search and returns the tmpl var hashref. sub getSearchTemplateVars { - my $self = shift; - my $thingId = shift || $self->session->form->process('thingId'); - my $thingProperties = shift || $self->getThing($thingId); + my $self = shift; my $session = $self->session; + my $thingId = shift || $self->session->form->process('thingId'); + my $thing = $THING_CLASS->new($session,$thingId); + my $thingProperties = shift || $thing->get; my $dbh = $session->db->dbh; my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); my ($var,$url,$orderBy); @@ -3240,7 +3114,7 @@ sub getSearchTemplateVars { if ($self->hasPrivileges($thingProperties->{groupIdImport})){ $var->{"import_url"} = $session->url->append($url, 'func=importForm;thingId='.$thingId); } - if ($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$self->hasEnteredMaxPerUser($thingId)){ + if ($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$thing->hasEnteredMaxPerUser){ $var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new'); } $var->{searchScreenTitle} = $thingProperties->{searchScreenTitle}; @@ -3517,8 +3391,9 @@ sub www_viewThingData { my $var = $self->get; my $url = $self->getUrl; my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + my $thing = $THING_CLASS->new($session,$thingId); - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $thing->get;; return $self->session->privilege->insufficient() unless $self->canViewThingData( $thingId, $thingDataId, $thingProperties); @@ -3534,7 +3409,7 @@ sub www_viewThingData { .$thingId.';thingDataId='.$thingDataId); $var->{"delete_confirm"} = "onclick=\"return confirm('".$i18n->get("delete thing data warning")."')\""; } - if($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$self->hasEnteredMaxPerUser($thingId)){ + if($self->hasPrivileges($thingProperties->{groupIdAdd}) && !$thing->hasEnteredMaxPerUser){ $var->{"add_url"} = $session->url->append($url, 'func=editThingData;thingId='.$thingId.';thingDataId=new'); } if($self->hasPrivileges($thingProperties->{groupIdSearch})){ @@ -3578,7 +3453,7 @@ sub www_viewThingDataViaAjax { return JSON->new->encode({message => "Can't get thing data without a thingId and a thingDataId."}); } - my $thingProperties = $self->getThing($thingId); + my $thingProperties = $THING_CLASS->new($session,$thingId)->get;; if ($thingProperties->{thingId}){ return $self->session->privilege->insufficient() unless $self->canViewThingData( $thingId, $thingDataId, $thingProperties); diff --git a/lib/WebGUI/Asset/Wobject/Thingy/Thing.pm b/lib/WebGUI/Asset/Wobject/Thingy/Thing.pm new file mode 100644 index 000000000..30ef8e114 --- /dev/null +++ b/lib/WebGUI/Asset/Wobject/Thingy/Thing.pm @@ -0,0 +1,340 @@ +package WebGUI::Asset::Wobject::Thingy::Thing; + +=head1 LEGAL + + ------------------------------------------------------------------- + Thingy is Copyright 2008 Plain Black Corporation. + ------------------------------------------------------------------- + Please read the legal notices (docs/legal.txt) and the license + (docs/license.txt) that came with this distribution before using + this software. + ------------------------------------------------------------------- + http://www.plainblack.com info@plainblack.com + ------------------------------------------------------------------- + +=cut + +use strict; +use base 'WebGUI::Crud'; +use Class::InsideOut qw(readonly private id register); +use WebGUI::International; +#use WebGUI::Exception; +#use WebGUI::Inbox; +#use WebGUI::User; + +#private user => my %user; + + +#------------------------------------------------------------------- + +=head2 addField ( field, isImport ) + +Adds a new field. + +=head3 field + +A hashref containing the properties of the new field. + +=head3 isImport + +If isImport is true the new field will keep the fieldId and assetId in the properties hashref. The thingId is +always taken from the field hashref. + +=cut + +sub addField { + + my $self = shift; + my $field = shift; + my $isImport = shift; + my $dbDataType = shift || $self->_getDbDataType($field->{fieldType}); + my $db = $self->session->db; + my ($oldFieldId, $newFieldId,$useAssetId,$useSequence); + + if ($isImport){ + $oldFieldId = $field->{fieldId}; + } + else { + $useAssetId = 1; + } + + $field->{fieldId} = "new"; + $newFieldId = $self->setCollateral("Thingy_fields","fieldId",$field,1,$useAssetId); + + if ($isImport){ + $db->write("update Thingy_fields set fieldId = ".$db->quote($oldFieldId) + ." where fieldId = ".$db->quote($newFieldId)); + $newFieldId = $oldFieldId; + } + + my $thingyTableName = "Thingy_".$field->{thingId}; + my $columnName = "field_".$newFieldId; + $db->write( + "ALTER TABLE ".$db->dbh->quote_identifier($thingyTableName) + ." ADD ".$db->dbh->quote_identifier($columnName)." ". $dbDataType + ); + + return $newFieldId; +} + +#------------------------------------------------------------------- + +=head2 crud_definition + +WebGUI::Crud definition for this class. + +=head3 tableName + +Thingy_things + +=head3 tableKey + +thingId + +=head3 sequenceKey + +None. Things have no sequence amongst themselves. + +=cut +sub crud_definition { + my ($class, $session) = @_; + my $i18n = WebGUI::International->new($session, "Asset_Thingy"); + + my $definition = $class->SUPER::crud_definition($session); + $definition->{tableName} = 'Thingy_things'; + $definition->{tableKey} = 'thingId'; + $definition->{sequenceKey} = ''; + $definition->{properties}{assetId} = { + fieldType => 'guid', + defaultValue => undef, + }; + $definition->{properties}{label} = { + fieldType => 'text', + defaultValue => $i18n->get('thing name label'), + }; + $definition->{properties}{editScreenTitle} = { + fieldType => 'text', + defaultValue => $i18n->get('edit screen title label'), + }; + $definition->{properties}{editInstructions} = { + fieldType => 'HTMLArea', + defaultValue => '', + }; + $definition->{properties}{groupIdAdd} = { + fieldType => 'group', + defaultValue => undef, + }; + $definition->{properties}{groupIdEdit} = { + fieldType => 'group', + defaultValue => undef, + }; + $definition->{properties}{saveButtonLabel} = { + fieldType => 'text', + defaultValue => $i18n->get('default save button label'), + }; + $definition->{properties}{afterSave} = { + fieldType => 'selectBox', + defaultValue => 'searchThisThing', + }; + $definition->{properties}{editTemplateId} = { + fieldType => 'template', + defaultValue => "ThingyTmpl000000000003", + }; + $definition->{properties}{onAddWorkflowId} = { + fieldType => 'workflow', + defaultValue => undef, + }; + $definition->{properties}{onEditWorkflowId} = { + fieldType => 'workflow', + defaultValue => undef, + }; + $definition->{properties}{onDeleteWorkflowId} = { + fieldType => 'workflow', + defaultValue => undef, + }; + $definition->{properties}{groupIdView} = { + fieldType => 'group', + defaultValue => undef, + }; + $definition->{properties}{viewTemplateId} = { + fieldType => 'template', + defaultValue => "ThingyTmpl000000000002", + }; + $definition->{properties}{defaultView} = { + fieldType => 'selectBox', + defaultValue => 'searchThing', + }; + $definition->{properties}{searchScreenTitle} = { + fieldType => 'text', + defaultValue => undef, + }; + $definition->{properties}{searchDescription} = { + fieldType => 'HTMLArea', + defaultValue => '', + }; + $definition->{properties}{groupIdSearch} = { + fieldType => 'group', + defaultValue => undef, + }; + $definition->{properties}{groupIdExport} = { + fieldType => 'group', + defaultValue => undef, + }; + $definition->{properties}{groupIdImport} = { + fieldType => 'group', + defaultValue => undef, + }; + $definition->{properties}{searchTemplateId} = { + fieldType => 'template', + defaultValue => "ThingyTmpl000000000004", + }; + $definition->{properties}{thingsPerPage} = { + fieldType => 'int', + defaultValue => 25, + }; + $definition->{properties}{sortBy} = { + fieldType => 'selectBox', + defaultValue => undef, + }; + $definition->{properties}{exportMetaData} = { + fieldType => 'yesNo', + defaultValue => undef, + }; + $definition->{properties}{maxEntriesPerUser} = { + fieldType => 'int', + defaultValue => undef, + }; + return $definition; +} + +#------------------------------------------------------------------- + +=head2 create ( thingy, [ properties ], [ options ]) + +Extend the method from WebGUI::Crud to handle creating a table for the new Thing and setting +some default values based on the parent Thingy's properties. + +=head3 thingy + +A reference to a Thingy object + +=head3 properties + +A hashref containing the properties of the new thing. + +=head3 options + +A hash reference of creation options. + +=head4 id + +A guid. Use this to force the row's table key to a specific ID. + +=cut + +sub create { + my ($class, $thingy, $properties, $options) = @_; + my $session = $thingy->session; + + my $groupIdEdit = $thingy->get("groupIdEdit"); + $properties->{groupIdEdit} = $groupIdEdit; + $properties->{groupIdAdd} = $groupIdEdit; + $properties->{groupIdSearch} = $groupIdEdit; + $properties->{groupIdExport} = $groupIdEdit; + $properties->{groupIdImport} = $groupIdEdit; + + my $newThing = $class->SUPER::create($session,$properties,$options); + + $session->db->write("create table ".$session->db->dbh->quote_identifier("Thingy_".$newThing->getId)."( + thingDataId CHAR(22) binary not null, + dateCreated DATETIME not null, + createdById CHAR(22) not null, + updatedById CHAR(22) not null, + updatedByName CHAR(255) not null, + lastUpdated DATETIME not null, + ipAddress CHAR(255), + sequenceNumber INT(11), + primary key (thingDataId) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); + + return $newThing; +} + +#------------------------------------------------------------------- + +=head2 delete ( ) + +Extend the method from WebGUI::Crud to handle deleting the Thing's table and fields. + +=cut + +sub delete { + my ($self) = @_; + my $db = $self->session->db; + + $db->write("delete from Thingy_fields where thingId =?",[$self->getId]); + $db->write("drop table if exists ".$db->dbh->quote_identifier("Thingy_".$self->getId)); + + return $self->SUPER::delete; +} + +#------------------------------------------------------------------- + +=head2 _getDbDataType ( fieldType ) + +returns the database data type for a field based on the fieldType. + +=head3 fieldType + +The fieldType for which the database data type should be returned. + +=cut + +sub _getDbDataType { + + my $self = shift; + my $fieldType = shift; + my $session = $self->session; + + my ($dbDataType, $formClass); + + if ($fieldType =~ m/^otherThing/x){ + $dbDataType = "CHAR(22)"; + } + else{ + $formClass = 'WebGUI::Form::' . ucfirst $fieldType; + my $formElement = eval { WebGUI::Pluggable::instanciate($formClass, "new", [$session]) }; + $dbDataType = $formElement->getDatabaseFieldType; + } + return $dbDataType; + +} + +#------------------------------------------------------------------- + +=head2 hasEnteredMaxPerUser + +Check whether the current user has entered the maximum number of entries allowed for this thing. + +=cut + +sub hasEnteredMaxPerUser { + my ($self) = @_; + my $session = $self->session; + my $db = $session->db; + + return 0 unless $self->get('maxEntriesPerUser'); + + my $numberOfEntries = $db->quickScalar( + "select count(*) from ".$db->dbh->quote_identifier("Thingy_".$self->getId)." where createdById=?", + [$session->user->userId]); + + if($numberOfEntries < $self->get('maxEntriesPerUser')){ + return 0; + } + else{ + return 1; + } +} + +1; diff --git a/t/Asset/Wobject/Thingy.t b/t/Asset/Wobject/Thingy.t index 28a899a21..75c2f9122 100644 --- a/t/Asset/Wobject/Thingy.t +++ b/t/Asset/Wobject/Thingy.t @@ -16,7 +16,7 @@ use lib "$FindBin::Bin/../../lib"; use WebGUI::Test; use WebGUI::Session; -use Test::More tests => 28; # increment this value for each test you create +use Test::More tests => 32; # increment this value for each test you create use Test::Deep; use JSON; use WebGUI::Asset::Wobject::Thingy; @@ -82,6 +82,10 @@ my $isValidId = $session->id->valid($thingId); is($isValidId,1,"addThing returned a valid id: ".$thingId); +# Test for a sane object type +my $thing = WebGUI::Asset::Wobject::Thingy::Thing->new($session,$thingId); +isa_ok($thing, 'WebGUI::Asset::Wobject::Thingy::Thing'); + my $thingTableName = "Thingy_".$thingId; my ($thingTableNameCheck) = $session->db->quickArray("show tables like ".$session->db->quote($thingTableName)); @@ -127,6 +131,9 @@ cmp_deeply( field_loop=>[], exportMetaData=>undef, maxEntriesPerUser=>undef, + dateCreated=>$thing->get('dateCreated'), + lastUpdated=>$thing->get('lastUpdated'), + sequenceNumber=>$thing->get('sequenceNumber'), }, 'Getting newly added thing as JSON: www_getThingViaAjax returns correct data as JSON.' ); @@ -137,9 +144,7 @@ cmp_deeply( $json = $thingy->www_getThingsViaAjax(); $dataFromJSON = JSON->new->decode($json); -cmp_deeply( - $dataFromJSON, - [{ +my $thingPropertiesHashRef = { assetId=>$thingy->getId, thingId=>$thingId, label=>$i18n->get('assetName'), @@ -170,10 +175,19 @@ cmp_deeply( canSearch=>1, exportMetaData=>undef, maxEntriesPerUser=>undef, - }], + dateCreated=>$thing->get('dateCreated'), + lastUpdated=>$thing->get('lastUpdated'), + sequenceNumber=>$thing->get('sequenceNumber'), + }; + +cmp_deeply( + $dataFromJSON, + [$thingPropertiesHashRef + ], 'Getting all things in Thingy as JSON: www_getThingsViaAjax returns correct data as JSON.' ); + # Test adding a field @@ -200,18 +214,62 @@ my ($fieldLabel, $columnType, $Null, $Key, $Default, $Extra) = $session->db->qui is($fieldLabel,"field_".$fieldId,"A column for the new field Field_$fieldId exists."); is($columnType,"longtext","The columns is the right type"); -# Test duplicating a Thing +# Test export function -my $copyThingId = $thingy->duplicateThing($thingId); +my $exportData = $thingy->exportAssetData; -$isValidId = $session->id->valid($copyThingId); +delete $exportData->{properties}; +delete $exportData->{storage}; -ok($isValidId, "duplicating a Thing: duplicateThing returned a valid id: ".$copyThingId); +my $thingDatabasePropertiesHashRef = $thingPropertiesHashRef; +delete $thingDatabasePropertiesHashRef->{canAdd}; +delete $thingDatabasePropertiesHashRef->{canEdit}; +delete $thingDatabasePropertiesHashRef->{canSearch}; + +my $field = $session->db->quickHashRef('select * from Thingy_fields where fieldId=?',[$fieldId]); + +cmp_deeply( + $exportData, + { + things=>[ + $thingDatabasePropertiesHashRef + ], + fields=>[ + $field + ] + }, + 'Export returns correct data.' + ); + + +# Test duplicating and deleting a Thing + +my $duplicateThingId = $thingy->duplicateThing($thingId); + +$isValidId = $session->id->valid($duplicateThingId); + +is($isValidId,1,"duplicating a Thing: duplicateThing returned a valid id: ".$duplicateThingId); + +my $duplicateThing = WebGUI::Asset::Wobject::Thingy::Thing->new($session, $duplicateThingId); +if (defined $duplicateThing) { + $duplicateThing->delete; +} + +my @things = @{ WebGUI::Asset::Wobject::Thingy::Thing->getAllIds($session,{constraints => [ + {"assetId=?" => $thingy->getId}, + ]}) }; +is(scalar @things,1,'Duplicated thing was deleted succesfully'); + +my ($thingTableCheck) = $session->db->quickArray("show tables like ?",['Thingy_'.$duplicateThingId]); + +is($thingTableCheck,undef,"New table for duplicate Thing was deleted."); # Test adding, editing, getting and deleting thing data +is($thing->hasEnteredMaxPerUser,0,"hasEnteredMaxPerUser returns 0 before adding a record"); + my ($newThingDataId,$errors) = $thingy->editThingDataSave($thingId,'new',{"field_".$fieldId => 'test value'}); -ok( ! $thingy->hasEnteredMaxPerUser($thingId), 'hasEnteredMaxPerUser: returns false when maxEntriesPerUser=0 and 1 entry added'); +ok( ! $thing->hasEnteredMaxPerUser, 'hasEnteredMaxPerUser: returns false when maxEntriesPerUser=0 and 1 entry added'); my $isValidThingDataId = $session->id->valid($newThingDataId); @@ -314,11 +372,12 @@ cmp_deeply( my %otherThingProperties = %thingProperties; $otherThingProperties{maxEntriesPerUser} = 1; $otherThingProperties{editTemplateId } = $templateId; -my $otherThingId = $thingy->addThing(\%otherThingProperties, 0); +my $otherThingId = $thingy->addThing(\%otherThingProperties, 0); +my $otherThing = WebGUI::Asset::Wobject::Thingy::Thing->new($session,$otherThingId); my %otherFieldProperties = %fieldProperties; $otherFieldProperties{thingId} = $otherThingId; my $otherFieldId = $thingy->addField(\%otherFieldProperties, 0); -ok( ! $thingy->hasEnteredMaxPerUser($otherThingId), 'hasEnteredMaxPerUser: returns false with no data entered'); +ok( ! $otherThing->hasEnteredMaxPerUser($otherThingId), 'hasEnteredMaxPerUser: returns false with no data entered'); my @edit_thing_form_fields = qw/form_start form_end form_submit field_loop/; @@ -340,7 +399,7 @@ my @edit_thing_form_fields = qw/form_start form_end form_submit field_loop/; } $thingy->editThingDataSave($otherThingId, 'new', {"field_".$otherFieldId => 'other test value'} ); -ok( $thingy->hasEnteredMaxPerUser($otherThingId), 'hasEnteredMaxPerUser returns true with one row entered, and maxEntriesPerUser=1'); +ok( $otherThing->hasEnteredMaxPerUser($otherThingId), 'hasEnteredMaxPerUser returns true with one row entered, and maxEntriesPerUser=1'); { WebGUI::Test->mockAssetId($templateId, $templateMock); @@ -363,7 +422,7 @@ ok( $thingy->hasEnteredMaxPerUser($otherThingId), 'hasEnteredMaxPerUser returns # ################################################################# -$thingy->deleteThing($otherThingId); +$otherThing->delete; my $count; $count = $session->db->quickScalar('select count(*) from Thingy_things where thingId=?',[$otherThingId]); is($count, 0, 'deleteThing: clears thing from Thingy_things');