webgui/lib/WebGUI/Asset/Wobject/Thingy.pm
2010-02-11 12:56:21 -08:00

3529 lines
122 KiB
Perl

package WebGUI::Asset::Wobject::Thingy;
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 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
#-------------------------------------------------------------------
use strict;
use Tie::IxHash;
use JSON;
use WebGUI::International;
use WebGUI::Utility;
use WebGUI::Text;
use WebGUI::Form::File;
use WebGUI::DateTime;
use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Wobject';
aspect assetName => ['assetName', 'Asset_Thingy'];
aspect icon => 'thingy.gif';
aspect tableName => 'Thingy';
property templateId => (
fieldType => "template",
default => 'ThingyTmpl000000000001',
tab => "display",
namespace => "Thingy",
hoverHelp => ['thingy template description', 'Asset_Thingy'],
label => ['thingy template label', 'Asset_Thingy'],
);
property defaultThingId => (
default => undef,
fieldType => "selectBox",
label => ["default thing label", 'Asset_Thingy'],
options => \&_defaultThingId_options,
);
sub _defaultThingId_options {
my $self = shift;
my $things = $self->session->db->buildHashRef('select thingId, label from Thingy_things where assetId = ?',[$self->getId]);
return $things;
}
#-------------------------------------------------------------------
=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 $error = $self->session->errorHandler;
my ($oldFieldId, $newFieldId,$useAssetId,$useSequence);
$error->info("Adding Field, label: ".$field->{label}.", fieldId: ".$field->{fieldId}.",thingId: ".$field->{thingId});
if ($isImport){
$oldFieldId = $field->{fieldId};
}
else {
$useAssetId = 1;
#$useSequence = 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 addThing ( thing, isImport )
Adds a new thing.
=head3 thing
A hashref containing the properties of the new thing.
=head3 isImport
If isImport is true the new thing will keep the thingId and assetId in the properties hashref.
=cut
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);
$error->info("Adding Thing, label: ".$thing->{label}.", id: ".$thing->{thingId});
if ($isImport){
$oldThingId = $thing->{thingId};
}
else{
$useAssetId = 1;
}
$thing->{thingId} = "new";
$newThingId = $self->setCollateral("Thingy_things","thingId",$thing,0,$useAssetId);
if ($isImport){
$db->write("update Thingy_things set thingId = ".$db->quote($oldThingId)
." where thingId = ".$db->quote($newThingId));
$newThingId = $oldThingId;
}
else{
# 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});
}
}
$db->write("create table ".$db->dbh->quote_identifier("Thingy_".$newThingId)."(
thingDataId CHAR(22) binary not null,
dateCreated int not null,
createdById CHAR(22) not null,
updatedById CHAR(22) not null,
updatedByName CHAR(255) not null,
lastUpdated int not null,
ipAddress CHAR(255),
primary key (thingDataId)
) ENGINE=MyISAM DEFAULT CHARSET=utf8");
return $newThingId;
}
#-------------------------------------------------------------------
=head2 appendThingsVars ( vars, currentThingId )
Appends the list of things to a set of template vars.
=head3 vars
A hashref containing template variables.
=head3 currentThingId
A thingId. Will set the isCurrent flag in these template variables for the thing that the user is currently working with.
=cut
sub appendThingsVars {
my ($self, $vars, $currentThingId) = @_;
my $things = $self->getThings;
my @thingLoop = ();
while (my $thing = $things->hashRef) {
push @thingLoop, {
name => $thing->{label},
canView => $self->hasPrivileges($thing->{groupIdView}),
search_url => $self->getUrl('func=search;thingId='.$thing->{thingId}),
isCurrent => ($currentThingId eq $thing->{thingId}),
};
}
$vars->{listOfThings} = \@thingLoop;
}
#-------------------------------------------------------------------
=head2 canViewThing ( thingId, [ groupId ] )
Can the current user view the specified thing.
=head3 thingId
The unique id for a thing.
=head3 groupId
Pass in the groupId if you already have the view group for the thing.
=cut
sub canViewThing {
my ($self, $thingId, $groupId) = @_;
if ($groupId eq "") {
$groupId = $self->session->db->quickScalar("select groupIdView from Thingy_things where thingId=?", [$thingId]);
}
return $self->hasPrivileges($groupId);
}
#-------------------------------------------------------------------
=head2 badOtherThing ( tableName, fieldName )
Checks that the table and field for the other Thing are okay. Returns 0 if okay,
otherwise, returns an i18n message appropriate for the type of error, like the
table or the field in the table not existing.
=head3 tableName
The table name for the other thing.
=head3 fieldName
The field in the other thing to check for.
=cut
sub badOtherThing {
my ($self, $tableName, $fieldName) = @_;
my $session = $self->session;
my $db = $session->db;
my $i18n = WebGUI::International->new($session, 'Asset_Thingy');
my ($otherThingTableExists) = $db->quickArray('show tables like ?',[$tableName]);
return $i18n->get('other thing missing message') unless $otherThingTableExists;
my ($otherThingFieldExists) = $db->quickArray(
sprintf('show columns from %s like ?', $db->dbh->quote_identifier($tableName)),
[$fieldName]);
return $i18n->get('other thing field missing message') unless $otherThingFieldExists;
return undef;
}
#-------------------------------------------------------------------
=head2 duplicate ( )
Duplicates a Thingy, including the definitions of the Things in this Thingy and their fields.
=cut
sub duplicate {
my $self = shift;
my $options = shift;
my $newAsset = $self->SUPER::duplicate($options);
my $db = $self->session->db;
my $assetId = $self->getId;
my $fields;
my $otherThingFields = $db->buildHashRefOfHashRefs(
"select fieldType, fieldId, right(fieldType,22) as otherThingId, fieldInOtherThingId from Thingy_fields
where fieldType like 'otherThing_%' and assetId = ?",
[$assetId],'fieldInOtherThingId'
);
my $things = $self->getThings;
while ( my $thing = $things->hashRef) {
my $oldSortBy = $thing->{sortBy};
my $oldThingId = $thing->{thingId};
my $newThingId = $newAsset->addThing($thing,0);
$fields = $db->buildArrayRefOfHashRefs('select * from Thingy_fields where assetId=? and thingId=?'
,[$assetId,$oldThingId]);
foreach my $field (@$fields) {
# set thingId to newly created thing's id.
$field->{thingId} = $newThingId;
my $originalFieldId = $field->{fieldId};
my $newFieldId = $newAsset->addField($field,0);
if ($originalFieldId eq $oldSortBy){
$self->session->db->write( "update Thingy_things set sortBy = ? where thingId = ?",
[ $newFieldId, $newThingId ] );
}
if ($otherThingFields->{$originalFieldId}){
$otherThingFields->{$originalFieldId}->{newFieldType} = 'otherThing_'.$newThingId;
$otherThingFields->{$originalFieldId}->{newFieldId} = $newFieldId;
}
}
}
foreach my $otherThingField (keys %$otherThingFields){
$db->write('update Thingy_fields set fieldType = ?, fieldInOtherThingId = ?
where fieldInOtherThingId = ? and assetId = ?',
[$otherThingFields->{$otherThingField}->{newFieldType},
$otherThingFields->{$otherThingField}->{newFieldId},
$otherThingFields->{$otherThingField}->{fieldInOtherThingId}, $newAsset->getId]);
}
return $newAsset;
}
#-------------------------------------------------------------------
=head2 duplicateThing ( thingId )
Duplicates a thing.
=head3 thingId
The id of the Thing that will be duplicated.
=cut
sub duplicateThing {
my $self = shift;
my $oldThingId = shift;
my $db = $self->session->db;
my $thingProperties = $self->getThing($oldThingId);
$thingProperties->{thingId} = 'new';
$thingProperties->{label} = $thingProperties->{label}.' (copy)';
my $newThingId = $self->addThing($thingProperties);
my $fields = $db->buildArrayRefOfHashRefs('select * from Thingy_fields where assetId=? and thingId=?'
,[$self->getId,$oldThingId]);
foreach my $field (@$fields) {
# set thingId to newly created thing's id.
$field->{thingId} = $newThingId;
$self->addField($field,0);
}
return $newThingId;
}
#-------------------------------------------------------------------
=head2 deleteField ( fieldId , thingId )
Deletes a field from Collateral and drops the fields column in the thingy table.
=head3 fieldId
The id of the field that should be deleted.
=head3 thingId
The id of the thing to which the field to be deleted belongs.
=head3 keepSequenceNumbers
Boolean indicating that the sequence numbers should not be changed. This is used by importAssetCollateralData.
=cut
sub deleteField {
my $self = shift;
my $fieldId = shift;
my $thingId = shift;
my $keepSequenceNumbers = shift;
my $db = $self->session->db;
my $error = $self->session->errorHandler;
my $deletedSequenceNumber;
if ($keepSequenceNumbers ne "1"){
($deletedSequenceNumber) = $db->quickArray("select sequenceNumber from Thingy_fields where fieldId = ?"
,[$fieldId]);
}
$self->deleteCollateral("Thingy_fields","fieldId",$fieldId);
if ($keepSequenceNumbers ne "1"){
$db->write("update Thingy_fields set sequenceNumber = sequenceNumber -1 where sequenceNumber > ?"
,[$deletedSequenceNumber]);
}
my ($columnExists) = $db->quickArray("show columns from ".$db->dbh->quote_identifier("Thingy_".$thingId)
." like ".$db->quote("field_".$fieldId));
if ($columnExists){
$db->write("ALTER TABLE ".$db->dbh->quote_identifier("Thingy_".$thingId)." DROP "
.$db->dbh->quote_identifier("field_".$fieldId));
}
$error->info("Deleted field: $fieldId in thing: $thingId.");
return undef;
}
#-------------------------------------------------------------------
=head2 copyThingData ( )
Copies data in a Thing.
=head3 thingId
The id of the Thing that should be copied.
=head3 thingDataId
The id of row of data that should be copied.
=cut
sub copyThingData {
my $self = shift;
my $thingId = shift;
my $thingDataId = shift;
my $db = $self->session->db;
return undef unless $self->canEditThingData($thingId, $thingDataId);;
$self->copyCollateral("Thingy_".$thingId,"thingDataId",$thingDataId);
return undef;
}
#-------------------------------------------------------------------
=head2 deleteThingData ( )
Deletes data in a Thing.
=head3 thingId
The id of the Thing that should be deleted.
=head3 thingDataId
The id of row of data that should be deleted.
=cut
sub deleteThingData {
my $self = shift;
my $thingId = shift;
my $thingDataId = shift;
my $db = $self->session->db;
return undef unless $self->canEditThingData($thingId, $thingDataId);;
my ($onDeleteWorkflowId) = $db->quickArray("select onDeleteWorkflowId from Thingy_things where thingId=?"
,[$thingId]);
if ($onDeleteWorkflowId){
$self->triggerWorkflow($onDeleteWorkflowId, $thingId,$thingDataId);
}
$self->deleteCollateral("Thingy_".$thingId,"thingDataId",$thingDataId);
return undef;
}
#-------------------------------------------------------------------
=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.
=head3 thingId
The id of the Thing which this row of data is an instance of.
=head3 thingDataId
The id of the row of data. This can be an existing id or 'new'.
=head3 thingData
An optional hashref containing the new data. This will override values passed in by a form post.
Use this hashref for testing purposes.
=cut
sub editThingDataSave {
my $self = shift;
my $thingId = shift;
my $thingDataId = shift;
my $thingData = shift;
my $session = $self->session;
my (%thingData,$fields,@errors,$hadErrors,$newThingDataId);
my $i18n = WebGUI::International->new($session, 'Asset_Thingy');
if ($thingDataId eq "new"){
$thingData{dateCreated} = time();
$thingData{createdById} = $session->user->userId;
$thingData{ipAddress} = $session->env->getIp;
}
else {
%thingData = $session->db->quickHash("select * from ".$session->db->dbh->quote_identifier("Thingy_".$thingId)
." where thingDataId = ?",[$thingDataId]);
}
%thingData = ( %thingData,
thingDataId=>$thingDataId,
updatedById=>$session->user->userId,
updatedByName=>$session->user->username,
lastUpDated=>time(),
);
$fields = $session->db->read('select * from Thingy_fields where assetId = ? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
while (my $field = $fields->hashRef) {
my $fieldName = 'field_'.$field->{fieldId};
my $fieldValue;
if ($field->{status} eq "required" || $field->{status} eq "editable"){
my $fieldType = $field->{fieldType};
$fieldType = "" if ($fieldType =~ m/^otherThing/x);
# Modify the defaultValue for certain field types. For most types we want to use
# the default in the database, for these we want the last known value for this thingData
if ( $fieldType eq "File" || $fieldType eq "Image" ) {
$field->{ defaultValue } = $thingData{ "field_" . $field->{ fieldId } };
}
$fieldValue = $thingData->{$fieldName} || $session->form->process($fieldName,$fieldType,$field->{defaultValue},$field);
}
if ($field->{status} eq "required" && ($fieldValue =~ /^\s$/x || $fieldValue eq "" || !(defined $fieldValue))) {
push (@errors,{
"error_message"=>$field->{label}." ".$i18n->get('is required error').".",
});
#$hadErrors = 1;
}
if ($field->{status} eq "hidden") {
$fieldValue = $field->{defaultValue};
WebGUI::Macro::process($self->session,\$fieldValue);
}
if ($field->{status} eq "visible") {
$fieldValue = $field->{defaultValue};
#WebGUI::Macro::process($self->session,\$fieldValue);
}
$thingData{$fieldName} = $fieldValue;
}
$newThingDataId = $self->setCollateral("Thingy_".$thingId,"thingDataId",\%thingData,0,0);
# trigger workflow
if($thingDataId eq "new"){
my ($onAddWorkflowId) = $session->db->quickArray("select onAddWorkflowId from Thingy_things where thingId=?"
,[$thingId]);
if ($onAddWorkflowId){
$self->triggerWorkflow($onAddWorkflowId,$thingId,$newThingDataId);
}
}else{
my ($onEditWorkflowId) = $session->db->quickArray("select onEditWorkflowId from Thingy_things where thingId=?"
,[$thingId]);
if ($onEditWorkflowId){
$self->triggerWorkflow($onEditWorkflowId,$thingId,$newThingDataId);
}
}
return($newThingDataId,\@errors);
}
#-------------------------------------------------------------------
=head2 exportAssetData ( )
See WebGUI::AssetPackage::exportAssetData() for details.
=cut
sub exportAssetData {
my $self = shift;
my $data = $self->SUPER::exportAssetData;
my $db = $self->session->db;
my $assetId = $self->getId;
$data->{things} = $db->buildArrayRefOfHashRefs('select * from Thingy_things where assetId = ?',[$assetId]);
$data->{fields} = $db->buildArrayRefOfHashRefs('select * from Thingy_fields where assetId = ?',[$assetId]);
return $data;
}
#-------------------------------------------------------------------
=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 getEditFieldForm ( )
returns the form that will be used in the edit dialog for Thingy_fields.
=cut
sub getEditFieldForm {
my $self = shift;
my $session = $self->session;
my $field = shift;
my (%fieldStatus, $f, %fieldTypes, $things);
my $fieldId = $field->{fieldId} || "new";
my $i18n = WebGUI::International->new($session, 'Asset_Thingy');
my $defaultValue;
tie %fieldStatus, 'Tie::IxHash';
tie %fieldTypes, 'Tie::IxHash';
%fieldStatus = (
"hidden" => $i18n->get('fieldstatus hidden label'),
"visible" => $i18n->get('fieldstatus visible label'),
"editable" => $i18n->get('fieldstatus editable label'),
"required" => $i18n->get('fieldstatus required label'),
);
%fieldTypes = %{WebGUI::Form::FieldType->new($session)->getTypes};
%fieldTypes = WebGUI::Utility::sortHash(%fieldTypes);
$things = $self->session->db->read('select thingId, Thingy_things.label, count(*) from Thingy_things '
.'left join Thingy_fields using(thingId) where Thingy_things.assetId = ? and fieldId != "" '
.'group by thingId',[$self->getId]);
while (my $thing = $things->hashRef) {
my $fieldType = "otherThing_".$thing->{thingId};
$fieldTypes{$fieldType} = $thing->{label};
}
my $dialogPrefix;
if ($field->{oldFieldId}){
$dialogPrefix = "edit_".$field->{oldFieldId}."_Dialog_copy";
}
elsif($fieldId eq "new"){
$dialogPrefix = "addDialog";
}
else{
$dialogPrefix = "edit_".$fieldId."_Dialog";
}
$f = WebGUI::HTMLForm->new($self->session,{
action=>$self->getUrl,
tableExtras=>' cellpadding="0" cellspacing="0"'
});
$f->hidden(
-name => "fieldId",
-value => $fieldId,
);
$f->hidden(
-name => "thingId",
-value => $field->{thingId},
);
$f->hidden(
-name => "func",
-value => "editFieldSave"
);
$f->text(
-name=>"label",
-label=>$i18n->get('field label label'),
-hoverHelp=>$i18n->get('field label description'),
-value=>$field->{label}
);
$f->selectBox(
-name=>"fieldType",
-label=>$i18n->get('field type label'),
-hoverHelp=>$i18n->get('field type description'),
-value=>$field->{fieldType} || "Text",
-options=>\%fieldTypes,
-id=>$dialogPrefix."_fieldType_formId",
);
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_fieldInThing_module"));
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_defaultFieldInThing_module"));
unless ($field->{fieldType} =~ m/^otherThing/x){
$defaultValue = $field->{defaultValue};
}
my $defaultValueForm = WebGUI::Form::Textarea($self->session, {
name=>"defaultValue",
value=>$defaultValue,
subtext=>'<br />'.$i18n->get('default value subtext'),
width=>200,
height=>40,
resizable=>0,
});
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_defaultValue_module",$defaultValueForm,
$i18n->get('default value label'),$i18n->get('default value description')));
$f->text(
-name=>"pretext",
-value=>$field->{pretext},
-label=>$i18n->get('pretext label'),
-hoverHelp=>$i18n->get('pretext description'),
);
$f->text(
-name=>"subtext",
-value=>$field->{subtext},
-label=>$i18n->get('subtext label'),
-hoverHelp=>$i18n->get('subtext description'),
);
$f->selectBox(
-name=>"status",
-options=>\%fieldStatus,
-label=>$i18n->get('field status label'),
-hoverHelp=>$i18n->get('field status description'),
-value=> [ $field->{status} || "editable" ] ,
);
my $widthForm = WebGUI::Form::Integer($self->session, {
name=>"width",
value=>($field->{width} || 250),
size=>10,
});
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_width_module",$widthForm,$i18n->get('width label'),
$i18n->get('width description')));
my $sizeForm = WebGUI::Form::Integer($self->session, {
name=>"size",
value=>($field->{size} || 25),
size=>10,
});
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_size_module",$sizeForm,$i18n->get('size label'),
$i18n->get('size description'),));
my $heightForm = WebGUI::Form::Integer($self->session, {
name=>"height",
value=>$field->{height} || 40,
label=>$i18n->get('height label'),
size=>10,
});
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_height_module",$heightForm,$i18n->get('height label'),
$i18n->get('height description')));
my $verticalForm = WebGUI::Form::YesNo($self->session, {
name=>"vertical",
value=>$field->{vertical},
label=>$i18n->get('vertical label'),
});
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_vertical_module",$verticalForm,$i18n->get('vertical label'),
$i18n->get('vertical description')));
my $valuesForm = WebGUI::Form::Textarea($self->session, {
name=>"possibleValues",
value=>$field->{possibleValues},
width=>200,
height=>60,
resizable=>0,
});
$f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_values_module",$valuesForm,$i18n->get('possible values label'),
$i18n->get('possible values description')));
$f->text(
-name=>"extras",
-value=>$field->{extras},
-label=>$i18n->get('extras label'),
-hoverHelp=>$i18n->get('extras description'),
);
#unless ($dialogPrefix eq "addDialog") {
# $f->raw('<script type="text/javascript">initHoverHelp("'.$dialogPrefix.'");</script>');
#}
return $f;
}
#-------------------------------------------------------------------
=head2 getFieldValue ( value, field )
Processes the field value for date(Time) fields and Other Thing fields.
=head3 value
The value as stored in the database.
=head3 field
A reference to a hash containing the fields properties.
=cut
sub getFieldValue {
my $self = shift;
my $value = shift;
my $field = shift;
my $dateFormat = shift || "%z";
my $dateTimeFormat = shift;
my $processedValue = $value;
my $dbh = $self->session->db->dbh;
if ($field->{fieldType} eq "date"){
$processedValue = $self->session->datetime->epochToHuman($value,$dateFormat);
}
elsif ($field->{fieldType} eq "dateTime"){
$processedValue = $self->session->datetime->epochToHuman($value,$dateTimeFormat);
}
# TODO: The otherThing field type is probably also handled by getFormPlugin, so the elsif below can probably be
# safely removed. However, this requires more testing than I can provide right now, so for now this stays the
# way it was.
elsif ($field->{fieldType} =~ m/^otherThing/x) {
my $otherThingId = $field->{fieldType};
$otherThingId =~ s/^otherThing_//x;
my $tableName = 'Thingy_'.$otherThingId;
my $fieldName = 'field_'.$field->{fieldInOtherThingId};
my $badThing = $self->badOtherThing($tableName, $fieldName);
if (! $badThing){
($processedValue) = $self->session->db->quickArray('select '
.$dbh->quote_identifier($fieldName)
.' from '.$dbh->quote_identifier($tableName)
.' where thingDataId = ?',[$value]);
}
}
else {
$field->{ value } = $value;
$field->{ defaultValue } = $value;
my $plugin = $self->getFormPlugin( $field );
$processedValue = $plugin->getValueAsHtml;
}
return $processedValue;
}
#-------------------------------------------------------------------
=head2 getFormElement ( data )
Returns the form element tied to this field.
=head3 data
A hashref containing the properties of this field.
=cut
sub getFormElement {
my $self = shift;
return $self->getFormPlugin( @_, 1 )->toHtml;
}
#-------------------------------------------------------------------
=head2 getFormPlugin ( properties, [ useFormPostData ] )
Returns an instanciated WebGUI::Form::* plugin.
=head3 proeprties
The properties to configure the form plugin with. The fieldType key should contain the type of the form plugin.
=head3 useFormPostData
If set to true, the value of the form element will be set to the data posted by it if available.
=cut
sub getFormPlugin {
my $self = shift;
my $data = shift;
my $useFormPostData = shift;
my %param;
my $session = $self->session;
my $db = $session->db;
my $dbh = $db->dbh;
my $i18n = WebGUI::International->new($session,"Asset_Thingy");
$param{name} = "field_".$data->{fieldId};
my $name = $param{name};
$name =~ s/\^.*?\;//xgs ; # remove macro's from user input
$param{value} = $data->{value} || $data->{defaultValue};
$param{size} = $data->{size};
$param{height} = $data->{height};
$param{width} = $data->{width};
$param{extras} = $data->{extras};
$param{vertical} = $data->{vertical};
$param{fieldType} = $data->{fieldType};
if ($data->{fieldType} eq "Checkbox") {
$param{value} = 1;
if ($data->{value} == 1){
$param{checked} = 1;
}
}
if ( WebGUI::Utility::isIn( $data->{fieldType}, qw(SelectList CheckList SelectBox Attachments) ) ) {
my @values;
if ( $useFormPostData && $self->session->form->param($name) ) {
$param{ value } = [ $session->form->process( $name, $data->{fieldType} ) ];
}
elsif ( $data->{ value } ) {
foreach (split(/\n/x, $data->{value})) {
s/\s+$//x; # remove trailing spaces
push(@values, $_);
}
$param{value} = \@values;
}
}
elsif ( $useFormPostData && $self->session->form->param($name) ) {
$param{value} = $session->form->process( $name, $data->{fieldType} );
}
my $class = 'WebGUI::Form::'. ucfirst $data->{fieldType};
eval { WebGUI::Pluggable::load($class) };
if ($class->isa('WebGUI::Form::List')) {
delete $param{size};
my $values = WebGUI::Operation::Shared::secureEval($session,$data->{possibleValues});
if (ref $values eq 'HASH') {
$param{options} = $values;
}
else{
my %options;
tie %options, 'Tie::IxHash';
foreach (split(/\n/x, $data->{possibleValues})) {
s/\s+$//x; # remove trailing spaces
$options{$_} = $_;
}
$param{options} = \%options;
}
}
if ($data->{fieldType} eq "YesNo") {
if ($data->{defaultValue} =~ /yes/xi) {
$param{value} = 1;
}
elsif ($data->{defaultValue} =~ /no/xi) {
$param{value} = 0;
}
}
if ($data->{fieldType} =~ m/^otherThing/x){
my $otherThingId = $data->{fieldType};
$otherThingId =~ s/^otherThing_(.*)/$1/x;
$param{fieldType} = "SelectList";
$class = 'WebGUI::Form::'. $param{fieldType};
my $options = ();
my $tableName = 'Thingy_'.$otherThingId;
my $fieldName = 'field_'.$data->{fieldInOtherThingId};
my $errorMessage = $self->badOtherThing($tableName, $fieldName);
return $errorMessage if $errorMessage;
$options = $db->buildHashRef('select thingDataId, '
.$dbh->quote_identifier($fieldName)
.' from '.$dbh->quote_identifier($tableName));
my $value = $data->{value} || $data->{defaultValue};
($param{value}) = $db->quickArray('select '
.$dbh->quote_identifier($fieldName)
.' from '.$dbh->quote_identifier($tableName)
.' where thingDataId = ?',[$value]);
$param{size} = 1;
$param{multiple} = 0;
$param{options} = $options;
$param{value} = $data->{value} || $data->{defaultValue};
}
my $formElement = eval { WebGUI::Pluggable::instanciate($class, "new", [$session, \%param ])};
return $formElement;
}
#-------------------------------------------------------------------
=head2 getHtmlWithModuleWrapper ( id , formElement, formDescription )
Returns a table row containing a form element in a yui module.
=head3 id
An id for the module div.
=head3 formElement
The from element rendered as html.
=head3 formDescription
The description of the from element.
=cut
sub getHtmlWithModuleWrapper {
my $self = shift;
my $id = shift;
my $formElement = shift;
my $formDescription = shift;
my $hoverHelp = shift;
$hoverHelp &&= '<div class="wg-hoverhelp">' . $hoverHelp . '</div>';
my $html = "\n<tr><td colspan='2'>\n";
$html .= "\t<div id='".$id."'>\n";
$html .= "\t<div class='bd' style='padding:0px;'>\n";
$html .= "\t<table cellpadding='0' cellspacing='0' style='width: 100%;'>\n";
$html .= "\t<tr><td class='formDescription' valign='top' style='width:180px'>";
$html .= $formDescription.$hoverHelp."</td>";
$html .= "<td valign='top' class='tableData' style='padding-left:4px'>";
$html .= $formElement."</td>";
$html .= "\t\n</tr>\n";
$html .= "\t</table>";
$html .= "\t\n</div>\t\n</div>\n";
$html .= "</td></tr>";
return $html;
}
#-------------------------------------------------------------------
=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.
If a tmpl var hashref is supplied tmpl_var's will be appended to that.
=cut
sub getViewThingVars {
my ($self, $thingId, $thingDataId,$var) = @_;
my $db = $self->session->db;
my (@field_loop, @viewScreenTitleFields, $viewScreenTitle);
return undef unless ($thingId && $thingDataId);
my %thingData = $db->quickHash("select * from ".$db->dbh->quote_identifier("Thingy_".$thingId)
." where thingDataId = ?",[$thingDataId]);
if (%thingData) {
my $fields = $db->read('select * from Thingy_fields where assetId = ? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
while (my %field = $fields->hash) {
next unless ($field{display} eq '1');
my $hidden = ($field{status} eq "hidden" && !$self->session->var->isAdminOn);
my $originalValue = $thingData{"field_".$field{fieldId}};
my $value = $self->getFieldValue($originalValue,\%field);
my $otherThingUrl;
if ($field{fieldType} =~ m/^otherThing/x) {
my $otherThingId = $field{fieldType};
$otherThingId =~ s/^otherThing_//x;
if($self->canViewThing($otherThingId)){
$otherThingUrl = $self->session->url->append(
$self->getUrl,
"func=viewThingData;thingId=$otherThingId;thingDataId=$originalValue"
);
}
}
my %fieldProperties = (
"id" => $field{fieldId},
"name" => "field_".$field{fieldId},
"type" => $field{fieldType},
"value" => $value,
"label" => $field{label},
"isHidden" => $hidden,
"url" => $otherThingUrl,
"isVisible" => ($field{status} eq "visible" && !$hidden),
"isRequired" => ($field{status} eq "required" && !$hidden),
"pretext" => $field{pretext},
"subtext" => $field{subtext},
);
push(@viewScreenTitleFields,$value) if ($field{viewScreenTitle});
push(@field_loop, { map {("field_".$_ => $fieldProperties{$_})} keys(%fieldProperties) });
}
$var->{viewScreenTitle} = join(" ",@viewScreenTitleFields);
$var->{field_loop} = \@field_loop;
return $var;
}
else{
return undef;
}
}
#-------------------------------------------------------------------
=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.
A user that can edit a Thingy asset has all rights on every Thing by definition.
=head3 groupId
The id of the group that has the privileges that are to be checked.
=cut
sub hasPrivileges {
my $self = shift;
my $privilegedGroupId = shift;
return ($self->session->user->isInGroup($privilegedGroupId) || $self->canEdit);
}
#-------------------------------------------------------------------
=head2 importAssetCollateralData ( data )
Imports Things and fields that where exported with a Thingy asset.
=head3 data
Hashref containing the Thingy's exported data.
=cut
sub importAssetCollateralData {
my $self = shift;
my $session = $self->session;
my $error = $session->errorHandler;
my $data = shift;
my $id = $data->{properties}{assetId};
my $class = $data->{properties}{className};
my $version = $data->{properties}{revisionDate};
my $assetExists = WebGUI::Asset->new($self->session, $id, $class, $version);
$error->info("Importing Things for Thingy ".$data->{properties}{title});
my @importThings;
foreach my $thing (@{$data->{things}}) {
push(@importThings,$thing->{thingId});
my ($thingIdExists) = $session->db->quickArray("select thingId from Thingy_things where thingId = ?",
[$thing->{thingId}]);
if ($assetExists && $thingIdExists){
# update existing thing
$error->info("Updating Thing, label: ".$thing->{label}.", id: ".$thing->{thingId});
$self->setCollateral("Thingy_things","thingId",$thing,0,0);
}
else{
# add new thing
$self->addThing($thing,1);
}
}
# 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 @importFields;
foreach my $field (@{$data->{fields}}) {
push(@importFields,$field->{fieldId});
my $dbDataType = $self->_getDbDataType($field->{fieldType});
my ($fieldIdExists) = $session->db->quickArray("select fieldId from Thingy_fields where fieldId = ? and thingId = ? ",[$field->{fieldId},$field->{thingId}]);
if ($assetExists && $fieldIdExists){
# update existing field
$error->info("Updating Field, label: ".$field->{label}.", id: ".$field->{fieldId}.",seq :"
.$field->{sequenceNumber});
$self->_updateFieldType($field->{fieldType},$field->{fieldId},$field->{thingId},$field->{assetId},$dbDataType);
$self->setCollateral("Thingy_fields","fieldId",$field,1,0,"","",1);
}
else{
# Add field as Collateral, retain fieldId.
$self->addField($field,1,$dbDataType);
}
}
# delete deleted fields
my $fieldsInDatabase = $session->db->read('select fieldId, thingId from Thingy_fields where assetId = ?',
[$self->getId]);
while (my $fieldInDataBase = $fieldsInDatabase->hashRef) {
if (!WebGUI::Utility::isIn($fieldInDataBase->{fieldId},@importFields)){
# delete field
$self->deleteField($fieldInDataBase->{fieldId},$fieldInDataBase->{thingId},"1");
}
}
return undef;
}
#-------------------------------------------------------------------
=head2 prepareView ( )
See WebGUI::Asset::prepareView() for details.
=cut
sub prepareView {
my $self = shift;
$self->SUPER::prepareView();
my $template = WebGUI::Asset::Template->new($self->session, $self->templateId);
if (!$template) {
WebGUI::Error::ObjectNotFound::Template->throw(
error => qq{Template not found},
templateId => $self->templateId,
assetId => $self->getId,
);
}
$template->prepare($self->getMetaDataAsTemplateVariables);
$self->{_viewTemplate} = $template;
return undef;
}
#-------------------------------------------------------------------
=head2 purge ( )
Removes collateral data and drops tables associated with a Thingy asset when the system
purges it's data.
=cut
sub purge {
my $self = shift;
my $session = $self->session;
my $db = $self->session->db;
my @thingIds = $db->buildArray("select thingId from Thingy_things where assetId = ?", [$self->getId]);
foreach my $thingId (@thingIds){
$db->write("drop table if exists ".$db->dbh->quote_identifier("Thingy_".$thingId));
}
$db->write("delete from Thingy_things where assetId = ?",[$self->getId]);
$db->write("delete from Thingy_fields where assetId = ?",[$self->getId]);
return $self->SUPER::purge;
}
#-------------------------------------------------------------------
=head2 triggerWorkflow ( workflowId, thingId, thingDataId )
Runs the specified workflow when this Thingy changes.
=head3 workflowId
The id of the workflow that has to be triggered.
=cut
sub triggerWorkflow {
my $self = shift;
my $workflowId = shift;
my $thingId = shift ;
my $thingDataId = shift ;
my $workflowInstance = WebGUI::Workflow::Instance->create($self->session, {
workflowId=>$workflowId,
className=>"WebGUI::Asset::Wobject::Thingy",
methodName=>"new",
parameters=>$self->getId
});
$workflowInstance->setScratch("thingId", $thingId);
$workflowInstance->setScratch("thingDataId",$thingDataId);
$workflowInstance->start;
return undef;
}
#-------------------------------------------------------------------
=head2 _updateFieldType ( fieldType, fieldId, thingId, assetId, dbDataType )
Alters a column for a field if the field's fieldType has changed.
=head3 fieldType
The new fieldType for the field that has to be changed.
=head3 fieldId
The id of the field of which should be changed.
=head3 thingId
The id of the Thing to which the field belongs.
=head3 assetId
The id of the Thingy asset to which the field belongs.
=head3 dbDataType
The data type that the field should have in the database.
=cut
sub _updateFieldType {
my $self = shift;
my $session = $self->session;
my $error = $session->errorHandler;
my $newFieldType = shift;
my $fieldId = shift;
my $thingId = shift;
my $assetId = shift;
my $dbDataType = shift;
my $db = $session->db;
my ($fieldType) = $self->session->db->quickArray("select fieldType from Thingy_fields where fieldId = "
.$db->quote($fieldId)." and assetId = ".$db->quote($assetId)
." and thingId = ".$db->quote($thingId));
if($newFieldType ne $fieldType){
my $thingyTableName = "Thingy_".$thingId;
my $columnName = "field_".$fieldId;
$error->info("changing column: $columnName, table: $thingyTableName");
$self->session->db->write(
"ALTER TABLE ".$db->dbh->quote_identifier($thingyTableName).
" CHANGE ".$db->dbh->quote_identifier($columnName)." "
.$db->dbh->quote_identifier($columnName)." ".$dbDataType
);
}
return undef;
}
#-------------------------------------------------------------------
=head2 view ( )
method called by the www_view method. Returns a processed template
to be displayed within the page style.
=cut
sub view {
my $self = shift;
my $session = $self->session;
my $db = $self->session->db;
my $i18n = WebGUI::International->new($self->session,"Asset_Thingy");
my ($defaultThingId,$defaultView);
my $var = $self->get;
my $url = $self->getUrl;
$var->{canEditThings} = $self->canEdit;
$var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new');
$var->{"manage_url"} = $session->url->append($url, 'func=manage');
#Get this Thingy's default thing
$defaultThingId = $self->defaultThingId;
$self->appendThingsVars($var, $defaultThingId);
if ($defaultThingId ne ""){
# get default view
($defaultView) = $db->quickArray("select defaultView from Thingy_things where thingId=?",[$defaultThingId]);
my $thingProperties = $self->getThing($defaultThingId);
if ($defaultView eq "searchThing"){
return $i18n->get("no permission to search") if( ! $self->canSearch($defaultThingId, $thingProperties));
return $self->search($defaultThingId,$thingProperties)
}
elsif ($defaultView eq "addThing"){
return $i18n->get("no permission to edit") if( ! $self->canEditThingData($defaultThingId, "new", $thingProperties));
return $self->editThingData($defaultThingId,"new", $thingProperties);
}
else{
return $self->processTemplate($var, undef, $self->{_viewTemplate});
}
}
else{
return $self->processTemplate($var, undef, $self->{_viewTemplate});
}
}
#-------------------------------------------------------------------
=head2 www_deleteFieldConfirm ( )
Deletes a field definition. Drops the column of a Thing's table that holds the data of this field.
=cut
sub www_deleteFieldConfirm {
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);
return 1;
}
#-------------------------------------------------------------------
=head2 www_duplicateThing ( )
Duplicates a Thing.
=cut
sub www_duplicateThing {
my $self = shift;
my $session = $self->session;
my $thingId = $session->form->process("thingId");
return $session->privilege->insufficient() unless $self->canEdit;
$self->duplicateThing($thingId);
return $self->www_manage;
}
#-------------------------------------------------------------------
=head2 www_copyThingData( )
Copies data in a Thing.
=cut
sub www_copyThingData{
my $self = shift;
my $thingId = $self->session->form->process("thingId");
my $thingDataId = $self->session->form->process('thingDataId');
return $self->session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId);
$self->copyThingData($thingId,$thingDataId);
return $self->www_search;
}
#-------------------------------------------------------------------
=head2 www_deleteThingConfirm ( )
Deletes a Thing, including field definitions and instances of this Thing and drops the table that holds the
instances of this Thing.
=cut
sub www_deleteThingConfirm {
my $self = shift;
my $thingId = $self->session->form->process("thingId");
return $self->session->privilege->insufficient() unless $self->canEdit;
$self->deleteThing($thingId);
return $self->www_manage;
}
#-------------------------------------------------------------------
=head2 www_deleteThingDataConfirm ( )
Deletes data in a Thing.
=cut
sub www_deleteThingDataConfirm {
my $self = shift;
my $thingId = $self->session->form->process("thingId");
my $thingDataId = $self->session->form->process('thingDataId');
return $self->session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId);
$self->deleteThingData($thingId,$thingDataId);
return $self->www_search;
}
#-------------------------------------------------------------------
=head2 www_deleteThingDataViaAjax ( )
Deletes data in a Thing.
=cut
sub www_deleteThingDataViaAjax {
my $self = shift;
my $session = $self->session;
my $thingId = $self->session->form->process("thingId");
my $thingDataId = $self->session->form->process('thingDataId');
$session->http->setMimeType("application/json");
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);
if ($thingProperties->{thingId}){
return $session->privilege->insufficient() unless $self->canEditThingData($thingId, $thingDataId
,$thingProperties);
$self->deleteThingData($thingId,$thingDataId);
$session->http->setMimeType("application/json");
return JSON->new->encode({message => "Data with thingDataId $thingDataId was deleted."});
}
else {
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "The thingId you specified can not be found."});
}
}
#-------------------------------------------------------------------
=head2 www_editThing ( )
Shows a form to edit or add a Thing. General properties of a Thing are stored when the form is submitted.
When editing fields in a thing some changes are saved immediately. Because of this a table has to be created for a new Thing
before the form is submitted.
=cut
sub www_editThing {
my $self = shift;
my $warning = shift;
my $session = $self->session;
my ($tabForm, $output, %properties, $tab, %afterSave, %defaultView, $fields, %editViewOptions);
my ($fieldsHTML, $fieldsViewScreen, $fieldsSearchScreen);
my (@hasHeightWidth,@hasSize,@hasVertical,@hasValues);
tie %afterSave, 'Tie::IxHash';
tie %editViewOptions, 'Tie::IxHash';
return $session->privilege->insufficient() unless $self->canEdit;
my $i18n = WebGUI::International->new($session, "Asset_Thingy");
my $thingId = $session->form->process("thingId");
return $self->www_view unless ($thingId);
if($thingId eq "new"){
my $groupIdEdit = $self->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)};
}
$tabForm = WebGUI::TabForm->new($self->session, undef, undef, $self->getUrl('func=view'));
$tabForm->hidden({
name => 'func',
value => 'editThingSave'
});
$tabForm->hidden({
name => 'thingId',
value => $thingId
});
$tabForm->addTab('fields', $i18n->get('fields tab label'));
$self->session->style->setScript($self->session->url->extras('yui/build/utilities/utilities.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/connection/connection-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('wobject/Thingy/thingy.js'), {type=>
'text/javascript'});
$self->session->style->setLink($self->session->url->extras('wobject/Thingy/thingy.css'), {type
=>'text/css', rel=>'stylesheet'});
$tab = $tabForm->getTab('fields');
foreach my $fieldType ( keys %{ WebGUI::Form::FieldType->new($session)->getTypes }) {
my $form = eval { WebGUI::Pluggable::instanciate("WebGUI::Form::".$fieldType, "new", [$session]) };
if ($@) {
$session->errorHandler->error($@);
next;
}
my $definition = $form->definition($session);
if ($form->get("height")){
push(@hasHeightWidth, $fieldType);
}
if ($form->get("size")){
push(@hasSize, $fieldType);
}
if (defined $definition->[0]->{vertical}->{defaultValue}){
push(@hasVertical, $fieldType);
}
if ($form->areOptionsSettable){
push(@hasValues, $fieldType);
}
}
$tab->raw("<script type='text/javascript'>\n");
$tab->raw('var hasHeightWidth = {'.join(", ",map {'"'.$_.'": true'} @hasHeightWidth).'};');
$tab->raw('var hasSize = {'.join(", ",map {'"'.$_.'": true'} @hasSize).'};');
$tab->raw('var hasVertical = {'.join(", ",map {'"'.$_.'": true'} @hasVertical).'};');
$tab->raw('var hasValues = {'.join(", ",map {'"'.$_.'": true'} @hasValues).'};');
if ($session->form->process("thingId") eq 'new'){
$tab->raw("var newThingId = '$thingId';\n");
$tab->raw("YAHOO.util.Event.onDOMReady(setCancelButton);\n");
}
$tab->raw("</script>");
$tab->text(
-name => 'label',
-label => $i18n->get('thing name label'),
-hoverHelp => $i18n->get('thing name description'),
-value => $properties{label},
-maxlength => 64,
);
$fieldsHTML = "</tr>\n"
."</tbody></table>\n"
."<fieldset>\n"
."<legend>".$i18n->get('fields label')."</legend>\n"
."<table><tbody>\n"
."<tr>\n"
." <td>\n"
." <div id='user_actions'>"
." <input id='showAddFormButton' value='".$i18n->get('add field label')."' type='button'>"
." </div>\n"
." </td>\n"
."</tr>\n"
."<tr id='fields_row'>\n"
." <td valign='top' colspan='2'>\n"
." <div class='workarea'>\n"
." <ul id='ul1' class='draglist'>\n";
$fieldsViewScreen = "</tbody></table>\n<fieldset>"
."<legend>".$i18n->get('fields label')."</legend>"
."<table><tbody id='view_fields_table'>\n"
."<tr>\n"
." <td></td>\n"
." <td class='formDescription'>".$i18n->get('display label')."</td>"
." <td class='formDescription'>".$i18n->get('view screen title label')."</td>\n"
."</tr>";
$fieldsSearchScreen = "</tbody></table>\n<fieldset>\n"
."<legend>".$i18n->get('fields label')."</legend>\n"
."<table><tbody id='search_fields_table'>\n"
."<tr>\n"
." <td></td>\n"
." <td class='formDescription'>".$i18n->get('display label')."</td>\n"
." <td class='formDescription'>".$i18n->get('search label')."</td>\n"
." <td class='formDescription'>".$i18n->get('sort by label')."</td>\n"
."</tr>\n";
$fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->getId).' and thingId = '.$self->session->db->quote($thingId).' order by sequenceNumber');
while (my $field = $fields->hashRef) {
my $formElement;
if ($field->{fieldType} eq "File"){
$formElement = "<input type='file' name='file'>";
}
if ($field->{fieldType} eq "Image"){
$formElement = "<input type='file' name='image'>";
}
else{
$formElement = $self->getFormElement($field);
}
if ($field->{pretext}){
$formElement = '<span class="formPretext">'.$field->{pretext}.'</span><br />'.$formElement;
}
if ($field->{subtext}){
$formElement .= '<br /><span class="formSubtext">'.$field->{subtext}.'</span>';
}
$fieldsHTML .= "<li class='list1' id='$field->{fieldId}'>"
."\n<table>\n<tr>\n"
." <td style='width:100px;' valign='top' class='formDescription'>".$field->{label}."</td>\n"
." <td style='width:370px;'>".$formElement."</td>\n"
." <td style='width:120px;' valign='top'> <input onClick=\"editListItem('".$self->session->url->page()
."?func=editField;fieldId=".$field->{fieldId}.";thingId=".$thingId."','".$field->{fieldId}."')\" value='Edit' type='button'>"
." <input onClick=\"editListItem('".$self->session->url->page()
."?func=editField;copy=1;fieldId=".$field->{fieldId}.";thingId=".$thingId."','".$field->{fieldId}
."','copy')\" value='Copy' type='button'>"
."<input onClick=\"deleteListItem('".$self->session->url->page()."','".$field->{fieldId}."','".$thingId."')\" "
."value='".$i18n->get('Delete','Icon')."' type='button'></td>\n</tr>\n</table>\n</li>\n";
$fieldsViewScreen .= "<tr id='view_tr_".$field->{fieldId}."'>"
."<td class='formDescription' style='width:180px;' id='view_label_".$field->{fieldId}."'>".$field->{label}
."</td><td valign='top' class='tableData'>";
$fieldsViewScreen .= WebGUI::Form::checkbox($self->session, {
checked => $field->{display},
name => "display_".$field->{fieldId},
value => 1,
});
$fieldsViewScreen .= "</td>\n<td valign='top' class='tableData'>";
$fieldsViewScreen .= WebGUI::Form::checkbox($self->session, {
checked => $field->{viewScreenTitle},
name => "viewScreenTitle_".$field->{fieldId},
value => 1,
});
$fieldsViewScreen .= "</td>\n</tr>\n</fieldset>";
$fieldsSearchScreen .= "<tr id='search_tr_".$field->{fieldId}."'>\n"
."<td class='formDescription' style='width:180px;' id='search_label_".$field->{fieldId}."'>".$field->{label}
."</td>\n<td valign='top' class='tableData'>";
$fieldsSearchScreen .= WebGUI::Form::checkbox($self->session, {
checked => $field->{displayInSearch},
name => "displayInSearch_".$field->{fieldId},
value => 1,
});
$fieldsSearchScreen .= "</td>\n<td valign='top' class='tableData'>";
$fieldsSearchScreen .= WebGUI::Form::checkbox($self->session, {
checked => $field->{searchIn},
name => "searchIn_".$field->{fieldId},
value => 1,
});
my $sortBy;
$sortBy = 1 if ($properties{sortBy} eq $field->{fieldId});
$fieldsSearchScreen .= "</td>\n<td valign='top' class='tableData'>";
$fieldsSearchScreen .= WebGUI::Form::radio($self->session, {
checked => $sortBy,
name => "sortBy",
value => $field->{fieldId},
});
$fieldsSearchScreen .= "</td>\n</tr>\n</fieldset>";
}
$fieldsHTML .= "</ul>\n"
."</div>\n"
."</td>\n"
."</fieldset>\n";
$tab->raw($fieldsHTML);
$tabForm->addTab('edit', $i18n->get('edit screen tab label'));
$tab = $tabForm->getTab('edit');
$tab->text(
-name => 'editScreenTitle',
-label => $i18n->get('edit screen title label'),
-hoverHelp => $i18n->get('edit screen title description'),
-value => $properties{editScreenTitle},
-maxlength => 64,
);
$tab->HTMLArea(
-name => 'editInstructions',
-label => $i18n->get('edit instructions label'),
-hoverHelp => $i18n->get('edit instructions description'),
-value => $properties{editInstructions},
-maxlength => 64,
-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},
-hoverHelp=> $i18n->get('who can add description'),
-label => $i18n->get('who can add label')
);
# create the options hash for the 'Who can edit' and 'Who can view' selectBoxes.
%editViewOptions = ('owner'=>'owner',$session->db->buildHash(
"select groupId,groupName from groups where showInForms=1 order by groupName"
));
$tab->selectBox(
-name=> "groupIdEdit",
-value=> $properties{groupIdEdit},
-hoverHelp=> $i18n->get('who can edit description'),
-label => $i18n->get('who can edit label'),
-options => \%editViewOptions,
);
$tab->text(
-name => 'saveButtonLabel',
-label => $i18n->get('save button label label'),
-hoverHelp => $i18n->get('save button label description'),
-value => $properties{saveButtonLabel} || $i18n->get('default save button label'),
-maxlength => 64,
);
%afterSave = (
"searchThisThing" => $i18n->get('search this thing label'),
"viewLastEdited" => $i18n->get('view last edited label'),
"addThing" => $i18n->get('add thing label'),
"thingyDefault" => $i18n->get('view thingy default label'),
);
my $otherThings = $session->db->read("select thingId, label from Thingy_things where thingId != ? and assetId =?",
[$thingId,$self->getId]);
while (my $otherThing = $otherThings->hashRef) {
$afterSave{'searchOther_'.$otherThing->{thingId}} = $i18n->get('search other thing label').$otherThing->{label};
$afterSave{'addOther_'.$otherThing->{thingId}} = $i18n->get('add other thing label').$otherThing->{label};
}
$tab->selectBox(
-name=>"afterSave",
-options=>\%afterSave,
-label=>$i18n->get('after save label'),
-hoverHelp=>$i18n->get('after save description'),
-value=>[ $properties{afterSave} || 'searchThisThing' ]
);
$tab->template(
-name=>"editTemplateId",
-value=>$properties{editTemplateId},
-namespace=>"Thingy/EditThing",
-label=>$i18n->get('edit template label'),
-hoverHelp=>$i18n->get('edit template description'),
);
$tab->workflow(
-name=>"onAddWorkflowId",
-value=>$properties{onAddWorkflowId} || "",
-type=>"WebGUI::Asset::Wobject::Thingy",
-label=>$i18n->get('on add workflow label'),
-none=>1,
-hoverHelp=>$i18n->get('on add workflow description'),
);
$tab->workflow(
-name=>"onEditWorkflowId",
-value=>$properties{onEditWorkflowId} || "",
-type=>"WebGUI::Asset::Wobject::Thingy",
-label=>$i18n->get('on edit workflow label'),
-none=>1,
-hoverHelp=>$i18n->get('on edit workflow description'),
);
$tab->workflow(
-name=>"onDeleteWorkflowId",
-value=>$properties{onDeleteWorkflowId} || "",
-type=>"WebGUI::Asset::Wobject::Thingy",
-label=>$i18n->get('on delete workflow label'),
-none=>1,
-hoverHelp=>$i18n->get('on delete workflow description'),
);
$tabForm->addTab('view', $i18n->get('view screen tab label'));
$tab = $tabForm->getTab('view');
$tab->selectBox(
-name=> "groupIdView",
-value=> $properties{groupIdView},
-hoverHelp=> $i18n->get('who can view description'),
-label => $i18n->get('who can view label'),
-options => \%editViewOptions,
);
$tab->template(
-name=>"viewTemplateId",
-value=>$properties{viewTemplateId},
-namespace=>"Thingy/ViewThing",
-label=>$i18n->get('view template label'),
-hoverHelp=>$i18n->get('view template description')
);
%defaultView = (
"searchThing" => $i18n->get('search thing label'),
"addThing" => $i18n->get('add thing label'),
);
$tab->selectBox(
-name=>"defaultView",
-options=>\%defaultView,
-label=>$i18n->get('default view label'),
-hoverHelp=>$i18n->get('default view description'),
-value=>[ $properties{defaultView} || 'searchThing' ]
);
$tab->raw($fieldsViewScreen);
$tabForm->addTab('search', $i18n->get('search screen tab label'));
$tab = $tabForm->getTab('search');
$tab->text(
-name => 'searchScreenTitle',
-label => $i18n->get('search screen title label'),
-hoverHelp => $i18n->get('search screen title description'),
-value => $properties{searchScreenTitle},
-maxlength => 64,
);
$tab->HTMLArea(
-name => 'searchDescription',
-label => $i18n->get('search description label'),
-hoverHelp => $i18n->get('search description description'),
-value => $properties{searchDescription},
-maxlength => 64,
-width => 300,
-height => 200,
);
$tab->group(
-name=> "groupIdSearch",
-value=> $properties{groupIdSearch},
-hoverHelp=> $i18n->get('who can search description'),
-label=> $i18n->get('who can search label')
);
$tab->group(
-name=> "groupIdImport",
-value=> $properties{groupIdImport},
-hoverHelp=> $i18n->get('who can import description'),
-label=> $i18n->get('who can import label')
);
$tab->group(
-name=> "groupIdExport",
-value=> $properties{groupIdExport},
-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},
-namespace=>"Thingy/SearchThing",
-label=>$i18n->get('search template label'),
-hoverHelp=>$i18n->get('search template description')
);
$tab->integer(
-name=>'thingsPerPage',
-label=>$i18n->get('things per page label'),
-hoverHelp => $i18n->get('things per page description'),
-value => $properties{thingsPerPage},
);
$tab->raw($fieldsSearchScreen);
if($warning){$output .= "$warning";}
$output .= $tabForm->print;
my $dialog = "<div id='addDialog'>\n"
."<div class='hd'>".$i18n->get('add field label')."</div>\n"
."<div class='bd'>\n";
my %fieldProperties;
$fieldProperties{thingId} = $thingId;
my $dialogBody = $self->getEditFieldForm(\%fieldProperties);
$dialog .= $dialogBody->print;
$dialog .= "</div>\n"
."</div>";
$output = $self->getAdminConsole->render($output, $i18n->get('edit thing title'));
$output .= $dialog;
return $output;
}
#-------------------------------------------------------------------
=head2 www_editThingSave ( )
Processes and saves the general properties of a Thing and some field properties that are not persisted to the
database immediately.
=cut
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");
$fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->getId).' 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);
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");
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;
$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));
}
return $self->www_manage;
}
#-------------------------------------------------------------------
=head2 www_editField ( )
Returns the html for a pop-up dialog to add or edit a field.
=cut
sub www_editField {
my $self = shift;
my $session = $self->session;
my (%properties,$thingId,$fieldId,$dialogBody);
return $session->privilege->insufficient() unless $self->canEdit;
$fieldId = $session->form->process("fieldId");
$thingId = $session->form->process("thingId");
%properties = $session->db->quickHash("select * from Thingy_fields where thingId=? and fieldId=? and assetId=?",
[$thingId,$fieldId,$self->getId]);
if($session->form->process("copy")){
$properties{oldFieldId} = $properties{fieldId};
$properties{fieldId} = 'new';
$properties{label} = $properties{label}.' (copy)';
}
$dialogBody = $self->getEditFieldForm(\%properties);
# Make sure we send debug information along with the field edit screen.
$session->log->preventDebugOutput;
$self->session->output->print($dialogBody->print);
return "chunked";
}
#-------------------------------------------------------------------
=head2 www_editFieldSave ( )
Processes and saves a field. Returns the edited/added fieldId and the inner html for a list item on the fields tab of the edit Thing screen.
=cut
sub www_editFieldSave {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless $self->canEdit;
my ($fieldId, $fieldTypeChanged, $newFieldId, $formClass, $dbDataType, $thingyTableName, $columnName);
my (%properties,$listItemHTML,$formElement);
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
my $label = $session->form->process("label");
my $thingId = $self->session->form->process("thingId");
my $error = $self->session->errorHandler;
my $defaultValue = $session->form->process("defaultValue");
my $fieldType = $session->form->process("fieldType") || "ReadOnly";
if ($fieldType =~ m/^otherThing/){
$defaultValue = $session->form->process("defaultFieldInThing");
}
$fieldId = $self->session->form->process("fieldId");
%properties = (
fieldId=>$fieldId,
thingId=>$thingId,
label=>$label,
fieldType=>$fieldType,
defaultValue=>$defaultValue,
possibleValues=>$self->session->form->process("possibleValues"),
pretext=>$self->session->form->process("pretext"),
subtext=>$self->session->form->process("subtext"),
status=>$self->session->form->process("status"),
size=>$self->session->form->process("size"),
width=>$self->session->form->process("width"),
height=>$self->session->form->process("height"),
vertical=>$self->session->form->process("vertical"),
extras=>$self->session->form->process("extras"),
display=>$self->session->form->process("display") || 1,
viewScreenTitle=>$self->session->form->process("viewScreenTitle") || 0,
fieldInOtherThingId=>$session->form->process("fieldInOtherThingId") || "",
);
# Get the field's data type
$dbDataType = $self->_getDbDataType($properties{fieldType});
if ($fieldId eq "new") {
$properties{dateCreated} = time();
$properties{createdBy} = $self->session->user->userId;
$newFieldId = $self->addField(\%properties,0,$dbDataType);
}
else{
$properties{dateUpdated} = time();
$properties{updatedBy} = $self->session->user->userId;
# Check if column has to be altered for existing fields.
$self->_updateFieldType($fieldType,$fieldId,$thingId,$self->getId,$dbDataType);
$newFieldId = $self->setCollateral("Thingy_fields","fieldId",\%properties,1,1,"thingId",$thingId);
}
if ($properties{fieldType} eq "File"){
$formElement = "<input type='file' name='file'>";
}
elsif ($properties{fieldType} eq "Image"){
$formElement = "<input type='file' name='image'>";
}
else{
$formElement = $self->getFormElement(\%properties);
}
if ($properties{pretext}){
$formElement = '<span class="formSubtext">'.$properties{pretext}.'</span><br />'.$formElement;
}
if ($properties{subtext}){
$formElement .= '<br /><span class="formSubtext">'.$properties{subtext}.'</span>';
}
$listItemHTML = "<table>\n<tr>\n<td style='width:100px;' valign='top' class='formDescription'>".$label."</td>\n"
."<td style='width:370px;'>".$formElement."</td>\n"
."<td style='width:120px;' valign='top'> <input onClick=\"editListItem('".$self->session->url->page()
."?func=editField;fieldId=".$newFieldId.";thingId=".$properties{thingId}."','".$newFieldId."')\" value='".$i18n->get('Edit','Icon')."' type='button'>"
."<input onClick=\"deleteListItem('".$self->session->url->page()."','".$newFieldId
."','".$properties{thingId}."')\" value='".$i18n->get('Delete','Icon')."' type='button'></td>\n</tr>\n</table>";
# Make sure we send debug information along with the field.
$session->log->preventDebugOutput;
$session->output->print($newFieldId.$listItemHTML);
return "chunked";
}
#-------------------------------------------------------------------
=head2 www_editThingData ( )
Shows a form to edit a things data.
=cut
sub www_editThingData {
my $self = shift;
return $self->processStyle($self->editThingData(@_));
}
#-------------------------------------------------------------------
=head2 canEditThingData ( )
Checks if the user can edit thing data.
=head3 thingId
The unique id of a thing.
=head3 thingDataId
The unique id of a row of thing data.
=head3 thingProperties
A hashRef containing the properties of a thing.
=cut
sub canEditThingData {
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 ($privilegedGroup);
if ($thingDataId eq "new"){
$privilegedGroup = $thingProperties->{groupIdAdd};
}
else {
if ($thingProperties->{groupIdEdit} eq 'owner'){
my $owner = $session->db->quickScalar("select createdById "
."from ".$session->db->dbh->quote_identifier("Thingy_".$thingId)
." where thingDataId = ?",[$thingDataId]);
if ($session->user->userId eq $owner || $self->canEdit){
return 1;
}
else{
return undef;
}
}
else{
$privilegedGroup = $thingProperties->{groupIdEdit};
}
}
return $self->hasPrivileges($privilegedGroup);
}
#-------------------------------------------------------------------
=head2 canViewThingData ( )
Checks if the user can view a specific row of thing data.
=head3 thingId
The unique id of a thing.
=head3 thingDataId
The unique id of a row of thing data.
=head3 thingProperties
A hashRef containing the properties of a thing.
=cut
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);
if ($thingProperties->{groupIdView} eq 'owner'){
my $owner = $session->db->quickScalar("select createdById "
."from ".$session->db->dbh->quote_identifier("Thingy_".$thingId)
." where thingDataId = ?",[$thingDataId]);
if ($session->user->userId eq $owner || $self->canEdit){
return 1;
}
else{
return undef;
}
}
else{
return $self->hasPrivileges($thingProperties->{groupIdView});
}
}
#-------------------------------------------------------------------
=head2 editThingData ( )
Shows a form to edit a things data.
=cut
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 $thingProperties = shift || $self->getThing($thingId);
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
my $canEditThingData = $self->canEditThingData($thingId, $thingDataId, $thingProperties);
return $session->privilege->insufficient() unless $canEditThingData;
my (%thingData, $fields,@field_loop,$fieldValue, $privilegedGroup);
my $var = $self->get;
my $url = $self->getUrl;
my $errors = shift;
$var->{error_loop} = $errors if ($errors);
$var->{canEditThings} = $self->canEdit;
$var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new');
$var->{"manage_url"} = $session->url->append($url, 'func=manage');
$var->{"thing_label"} = $thingProperties->{label};
if($canEditThingData){
if ($thingDataId ne "new"){
$var->{"copy_url"} = $session->url->append($url, 'func=copyThingData;thingId='.$thingId.';thingDataId='.$thingDataId);
}
}
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}) && !$self->hasEnteredMaxPerUser($thingId)){
$var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new');
}
if($self->hasPrivileges($thingProperties->{groupIdSearch})){
$var->{"search_url"} = $session->url->append($url, 'func=search;thingId='.$thingId);
}
$var->{"form_start"} = WebGUI::Form::formHeader($self->session,{action=>$self->getUrl})
.WebGUI::Form::hidden($self->session,{name=>"func",value=>"editThingDataSave"});
$var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"thingDataId",value=>$thingDataId});
$var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"thingId",value=>$thingId});
$var->{editScreenTitle} = $thingProperties->{editScreenTitle};
$var->{editInstructions} = $thingProperties->{editInstructions};
if ($thingDataId ne "new"){
# Get Field Values
%thingData = $session->db->quickHash("select * from ".$session->db->dbh->quote_identifier("Thingy_".$thingId)
." where thingDataId = ?",[$thingDataId]);
}
$fields = $session->db->read('select * from Thingy_fields where assetId = ? and thingId = ? order by sequenceNumber'
,[$self->getId,$thingId]);
while (my %field = $fields->hash) {
my $fieldName = 'field_'.$field{fieldId};
if ($session->form->process("func") eq "editThingDataSave"){
$fieldValue = $session->form->process($fieldName,$field{fieldType},$field{defaultValue});
}
else{
$fieldValue = $thingData{"field_".$field{fieldId}};
}
$field{value} = $fieldValue || $field{defaultValue};
my $formElement .= $self->getFormElement(\%field);
my $hidden = ($field{status} eq "hidden" && !$self->session->var->isAdminOn);
my $value = $field{value};
$value = $self->getFieldValue($value,\%field);
my %fieldProperties = (
"form" => $formElement,
"name" => "field_".$field{fieldId},
"value" => $value,
"label" => $field{label},
"isHidden" => $hidden,
"isVisible" => ($field{status} eq "visible" && !$hidden),
"isRequired" => ($field{status} eq "required" && !$hidden),
"pretext" => $field{pretext},
"subtext" => $field{subtext},
);
push(@field_loop, { map {("field_".$_ => $fieldProperties{$_})} keys(%fieldProperties) });
}
$var->{field_loop} = \@field_loop;
$var->{"form_submit"} = WebGUI::Form::submit($self->session,{value => $thingProperties->{saveButtonLabel}});
$var->{"form_end"} = WebGUI::Form::formFooter($self->session);
$self->appendThingsVars($var, $thingId);
if($thingDataId eq 'new' && $self->hasEnteredMaxPerUser($thingId)){
delete $var->{form_start};
delete $var->{form_end};
delete $var->{form_submit};
delete $var->{field_loop};
$var->{editInstructions} = $i18n->get("has entered max per user message");
}
return $self->processTemplate($var,$thingProperties->{editTemplateId});
}
#-------------------------------------------------------------------
=head2 www_editThingDataSave ( )
Processes and saves data for a Thing.
=cut
sub www_editThingDataSave {
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 $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){
return $self->www_editThingData($thingId,$thingDataId,'',$errors);
}
if ($thingProperties->{afterSave} eq "searchThisThing") {
return $self->www_search($thingId);
}
elsif ($thingProperties->{afterSave} eq "viewLastEdited"){
return $self->www_viewThingData($thingId,$newThingDataId);
}
elsif ($thingProperties->{afterSave} eq "addThing") {
return $self->www_editThingData($thingId,"new");
}
elsif ($thingProperties->{afterSave} =~ m/^searchOther_/x){
$otherThingId = $thingProperties->{afterSave};
$otherThingId =~ s/^searchOther_//x;
return $self->www_search($otherThingId);
}
elsif ($thingProperties->{afterSave} =~ m/^addOther_/x){
$otherThingId = $thingProperties->{afterSave};
$otherThingId =~ s/^addOther_//x;
return $self->www_editThingData($otherThingId,"new");
}
# if afterSave is thingy default or in any other case return www_view()
else {
return $self->www_view();
}
}
#-------------------------------------------------------------------
=head2 www_editThingDataSaveViaAjax ( )
Returns a thing instance as JSON data.
=head3 thingId
The unique id of a thing.
=head3 thingDataId
The unique id of a row of thing data. When this is 'new' a new row of data will be added.
=cut
sub www_editThingDataSaveViaAjax {
my $self = shift;
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");
return JSON->new->encode({message => "Can't get thing data without a thingId and a thingDataId."});
}
my $thingProperties = $self->getThing($thingId);
if ($thingProperties->{thingId}){
my ($privilegedGroup,$workflowId);
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->encode({message => $i18n->get("has entered max per user message")});
}
my ($newThingDataId,$errors) = $self->editThingDataSave($thingId,$thingDataId);
if ($errors){
$session->http->setStatus("400", "Bad Request");
return JSON->new->encode($errors);
}
}
else {
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "The thingId you requested can not be found."});
}
}
#-------------------------------------------------------------------
=head2 www_export ( )
Exports search results as csv.
=cut
sub www_export {
my $self = shift;
my $session = $self->session;
my ($query,$sth,$out,$fields,@fields,$fileName,@fieldLabels);
my $thingId = $session->form->process('thingId');
my $thingProperties = $self->getThing($thingId);
return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties->{groupIdExport});
$fields = $session->db->read('select * from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
while (my $field = $fields->hashRef) {
if ($field->{displayInSearch}){
push(@fields, {
fieldId => $field->{fieldId},
properties => $field,
});
push(@fieldLabels,$field->{label});
}
}
my @metaDataFields = ('thingDataId','dateCreated','createdById','updatedById','updatedByName','lastUpdated','ipAddress');
if ($thingProperties->{exportMetaData}){
push(@fieldLabels,@metaDataFields)
}
$query = eval{$session->cache->get("query_".$thingId)};
$sth = $session->db->read($query);
### Loop through the returned structure and put it through Text::CSV
# Column heads
$out = WebGUI::Text::joinCSV(@fieldLabels);
# Data lines
while (my $data = $sth->hashRef) {
my @fieldValues;
foreach my $field (@fields){
my $fieldId = $field->{fieldId};
# Export date and dateTime fields in an importable format.
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
);
}
$fileName = "export_".$thingProperties->{label}.".csv";
$self->session->http->setFilename($fileName,"application/octet-stream");
$self->session->http->sendHeader;
return $out;
}
#-------------------------------------------------------------------
=head2 www_getThingViaAjax ( )
Returns a things properties as JSON.
=head3 thingId
The unique id of a thing.
=cut
sub www_getThingViaAjax {
my $self = shift;
my $session = $self->session;
my $thingId = shift || $session->form->process('thingId');
$session->http->setMimeType("application/json");
unless ($thingId) {
$session->http->setStatus("400", "Bad Request");
return JSON->new->encode({message => "Can't return thing properties without a thingId."});
}
my $thingProperties = $self->getThing($thingId);
if ($thingProperties->{thingId}){
return $session->privilege->insufficient() unless $self->canViewThing($thingId,
$thingProperties->{groupIdView});
my @field_loop;
my $fields = $session->db->read('select * from Thingy_fields where assetId=? and thingId=? order by sequenceNumber'
,[$self->getId,$thingId]);
while (my $field = $fields->hashRef) {
$field->{formElement} = $self->getFormElement($field);
push(@field_loop,$field);
}
$thingProperties->{field_loop} = \@field_loop;
$session->http->setMimeType("application/json");
return JSON->new->encode($thingProperties);
}
else {
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "The thingId you requested can not be found."});
}
}
#-------------------------------------------------------------------
=head2 www_getThingsViaAjax ( )
Returns the Things in a Thingy as JSON.
=cut
sub www_getThingsViaAjax {
my $self = shift;
my $session = $self->session;
$session->http->setMimeType("application/json");
my @visibleThings;
my $things = $self->getThings;
while (my $thing = $things->hashRef) {
if ($self->canViewThing($thing->{thingId},$thing->{groupIdView})){
$thing->{canSearch} = $self->canSearch($thing->{thingId},$thing);
$thing->{canEdit} = $self->hasPrivileges($thing->{groupIdEdit});
$thing->{canAdd} = $self->hasPrivileges($thing->{groupIdAdd});
push(@visibleThings,$thing);
}
}
if (scalar @visibleThings > 0){
return JSON->new->encode(\@visibleThings);
}
else {
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "No visible Things were found in this Thingy."});
}
}
#-------------------------------------------------------------------
=head2 www_import ( )
Imports data from a .csv file.
=cut
sub www_import {
my $self = shift;
my $session = $self->session;
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);
return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties->{groupIdImport});
$fields = $session->db->read('select label, fieldId, fieldType, fieldInOtherThingId from Thingy_fields '
.' where assetId = '.$session->db->quote($self->getId)
.' and thingId = '.$session->db->quote($thingId)
.' order by sequenceNumber');
while (my $field = $fields->hashRef) {
push(@insertColumns, $field) if ($session->form->process("fileContains_".$field->{fieldId}));
}
my $error = $self->session->errorHandler;
my $storage = WebGUI::Storage->createTemp($self->session);
$handleDuplicates = $session->form->process("handleDuplicates");
$storage->addFileFromFormPost("importFile_file",1);
foreach my $file (sort(@{$storage->getFiles})) {
next unless ($storage->getFileExtension($file) eq "csv");
$error->info("Found import file $file");
open my $importFile,"<",$storage->getPath($file);
my $lineNumber = 0;
my @data = ();
while ( my $row = WebGUI::Text::readCSV($importFile) ) {
if ($lineNumber == 0 && $session->form->process('ignoreFirstLine')){
$lineNumber++;
$error->info("Skipping first line");
next;
}
$error->info("Reading line $lineNumber: @{ $row }");
$lineNumber++;
@data = @{ $row };
# check for duplicates
my $fieldNumber = 0;
my $foundDuplicateId = "";
my @duplicatesConstraint;
# Create duplicate constraint
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_identifier("field_".$insertColumn->{fieldId})
." = ".$session->db->quote($insertValue));
}
$fieldNumber++;
}
if((scalar @duplicatesConstraint) > 0){
my $query = "select thingDataId from ".$dbh->quote_identifier("Thingy_".$thingId)." where ";
$query .= join(" and ",@duplicatesConstraint);
$query .= " limit 1";
($foundDuplicateId) = $session->db->quickArray($query);
if ($foundDuplicateId){
$error->info("found duplicate record: ".$foundDuplicateId." for data: ". @{ $row });
}
}
my %thingData = ();
$fieldNumber = 0;
# Populate thingData hash
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;
$fieldValue = $session->datetime->setToEpoch($fieldValue);
}
elsif($fieldType =~ m/^otherThing/x){
my $otherThingId = $fieldType;
$otherThingId =~ s/^otherThing_(.*)/$1/x;
($fieldValue) = $self->session->db->quickArray('select thingDataId '
.' from '.$dbh->quote_identifier('Thingy_'.$otherThingId)
.' where '.$dbh->quote_identifier('field_'.$fieldInOtherThingId).' = ?',[$fieldValue]);
}
$thingData{$fieldName} = $fieldValue;
$fieldNumber++;
}
if ($foundDuplicateId && $handleDuplicates eq "overwrite"){
$thingData{thingDataId} = $foundDuplicateId;
$error->info("Overwriting, thingDataId = ".$thingData{thingDataId});
}
elsif ($foundDuplicateId eq ""){
$thingData{thingDataId} = "new";
$error->info("Importing new line");
}
else{
$error->info("Skipping line");
next;
}
$thingData{lastUpdated} = time();
$thingData{updatedByName} = $session->user->username;
$thingData{updatedById} = $session->user->userId;
$self->setCollateral("Thingy_".$thingId,"thingDataId",\%thingData,0,0) if ($thingData{thingDataId});
}
close $importFile;
}
return $self->www_search($thingId);
}
#-------------------------------------------------------------------
=head2 www_importForm ( )
Shows the import screen.
=cut
sub www_importForm {
my $self = shift;
my $session = $self->session;
my $db = $session->db;
my ($i18n,$form,$fields,$fieldOptions,$output);
my $thingId = $session->form->process('thingId');
my $thingProperties = $self->getThing($thingId);
return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties->{groupIdImport});
$i18n = WebGUI::International->new($self->session, "Asset_Thingy");
$output = "<h1>".$i18n->get("import label")."</h1>";
$form = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl);
$form->hidden(
-name => "thingId",
-value => $thingId
);
$form->hidden(
-name => "func",
-value => "import"
);
$form->file(
-name => "importFile",
-label => $i18n->get("import file label"),
);
$form->selectBox(
-name => "handleDuplicates",
-label=> $i18n->get("duplicates label"),
-options=> {
"skip" => $i18n->get("skip label"),
"overwrite" => $i18n->get("overwrite label"),
},
);
$form->yesNo(
-name=>"ignoreFirstLine",
-label=>$i18n->get("ignore first line label"),
);
$fieldOptions = "<table>"
."<tr><td></td>"
." <td>".$i18n->get("file contains label")."</td>"
." <td>".$i18n->get("check duplicates label")."</td>"
."</tr>";
$fields = $db->read('select label, fieldId from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber',
[$self->getId,$thingId]);
while (my $field = $fields->hashRef) {
$fieldOptions .= "<tr><td>".$field->{label}."</td><td>";
$fieldOptions .= WebGUI::Form::checkbox($self->session, {
checked => "",
name => "fileContains_".$field->{fieldId},
value => 1,
});
$fieldOptions .= "</td><td>";
$fieldOptions .= WebGUI::Form::checkbox($self->session, {
checked => "",
name => "checkDuplicates_".$field->{fieldId},
value => 1,
});
$fieldOptions .= "</td></tr>";
}
$fieldOptions .= "</table>";
$form->raw($fieldOptions);
$form->submit;
$output .= $form->print;
return $self->processStyle($output);
}
#-------------------------------------------------------------------
=head2 www_manage ( )
Shows the screen to manage things in a Thingy.
=cut
sub www_manage {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless $self->canEdit;
my $i18n = WebGUI::International->new($self->session,"Asset_Thingy");
my ($things, @things_loop);
my $var = $self->get;
my $url = $self->getUrl;
$var->{canEditThings} = $self->canEdit;
$var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new');
$var->{"manage_url"} = $session->url->append($url, 'func=manage');
$var->{"view_url"} = $session->url->page;
#Get things in this Thingy
$things = $self->getThings;
while (my $thing = $things->hashRef) {
my %templateVars = (
'thing_id' => $thing->{thingId},
'thing_label' => $thing->{label},
'thing_deleteUrl' => $session->url->append($url, 'func=deleteThingConfirm;thingId='.$thing->{thingId}),
'thing_deleteIcon' => $session->icon->delete('func=deleteThingConfirm;thingId='.$thing->{thingId},
"",$i18n->get('delete thing warning')),
'thing_editUrl' => $session->url->append($url, 'func=editThing;thingId='.$thing->{thingId}),
'thing_editIcon' => $session->icon->edit('func=editThing;thingId='.$thing->{thingId}),
'thing_copyUrl' => $session->url->append($url, 'func=duplicateThing;thingId='.$thing->{thingId}),
'thing_copyIcon' => $session->icon->copy('func=duplicateThing;thingId='.$thing->{thingId}),
'thing_addUrl' => $session->url->append($url,
'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new'),
'thing_searchUrl' => $session->url->append($url, 'func=search;thingId='.$thing->{thingId}),
);
# set the url for the view icon to the things default view
my $viewParams;
if ($thing->{defaultView} eq "addThing") {
$viewParams = 'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new';
}
else{
$viewParams = 'func=search;thingId='.$thing->{thingId};
}
$templateVars{'thing_viewIcon'} = $session->icon->view($viewParams);
push (@things_loop, \%templateVars);
}
$var->{"things_loop"} = \@things_loop;
return $self->processStyle($self->processTemplate($var, $self->templateId));
}
#-------------------------------------------------------------------
=head2 www_moveFieldConfirm ( )
Moves a field up or down in the sequence of fields.
=cut
sub www_moveFieldConfirm {
my $self = shift;
my $session = $self->session;
return $session->privilege->insufficient() unless $self->canEdit;
my $error = $self->session->errorHandler;
my $direction = $session->form->process('direction');
my $assetId = $self->getId;
my $fieldId = $session->form->process('fieldId');
my $targetFieldId = $session->form->process('targetFieldId');
$error->info("moving $fieldId to target $targetFieldId, direction: $direction");
my ($thingId,$originalRank) = $session->db->quickArray(
"select thingId, sequenceNumber from Thingy_fields where fieldId = ".$session->db->quote($fieldId)." and assetId = ".$session->db->quote($assetId));
my ($targetRank) = $session->db->quickArray(
"select sequenceNumber from Thingy_fields where fieldId = ".$session->db->quote($targetFieldId)." and assetId = ".$session->db->quote($assetId));
if($targetRank > $originalRank){
# seq -- for orig seq < seq =< newseq
if ($direction eq "up"){
$targetRank--;
}
my $sql = "update Thingy_fields set sequenceNumber = sequenceNumber - 1 where sequenceNumber > "
.$originalRank." and sequenceNumber <= ".$targetRank." and assetId = ".$session->db->quote($assetId)
." and thingId = ".$session->db->quote($thingId);
$session->db->write($sql);
}
else{
# seq ++ for newseq =< seq < orig seq
if ($direction eq "down") {
$targetRank++;
}
$session->db->write("update Thingy_fields set sequenceNumber = sequenceNumber + 1 where sequenceNumber >= "
.$targetRank." and sequenceNumber < ".$originalRank." and assetId = ".$session->db->quote($assetId)." and thingId = ".$session->db->quote($thingId));
}
# orig seq = target seq
$self->session->db->write("update Thingy_fields set sequenceNumber = ".$targetRank." where fieldId = ".$self->session->db->quote($fieldId)." and assetId = ".$self->session->db->quote($assetId)." and thingId = ".$self->session->db->quote($thingId));
$self->session->output->print("fieldMoved");
return "chunked";
}
#-------------------------------------------------------------------
=head2 www_search ( )
Shows the search screen wrapped in a style.
=cut
sub www_search {
my $self = shift;
return $self->processStyle($self->search(@_));
}
#-------------------------------------------------------------------
=head2 www_searchViaAjax ( )
Shows the search screen wrapped in a style.
=head3 thingId
The unique id of a thing.
=head3 thingProperties
A hashref containing the properties of a thing.
=cut
sub www_searchViaAjax {
my $self = shift;
my $session = $self->session;
my $thingId = shift || $session->form->process('thingId');
my $thingProperties = shift || $self->getThing($thingId);
my $i18n = WebGUI::International->new($self->session,"Asset_Thingy");
unless ($thingId) {
$session->http->setStatus("400", "Bad Request");
return JSON->new->encode({message => "Can't perform search without a thingId."});
}
if ($thingProperties->{thingId}){
return $session->privilege->insufficient() unless $self->canViewThing($thingId,
$thingProperties->{groupIdView});
my $var = $self->getSearchTemplateVars($thingId,$thingProperties);
$session->http->setMimeType("application/json");
return JSON->new->encode($var);
}
else {
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "The thingId you requested can not be found."});
}
}
#-------------------------------------------------------------------
=head2 canSearch ( )
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);
return $self->hasPrivileges($thingProperties->{groupIdSearch});
}
#-------------------------------------------------------------------
=head2 search ( )
Returns the search screen without style.
=cut
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");
return $i18n->get("no permission to search") if( ! $self->canSearch($thingId, $thingProperties));
my $var = $self->getSearchTemplateVars($thingId,$thingProperties);
return $self->processTemplate($var,$thingProperties->{searchTemplateId});
}
#-------------------------------------------------------------------
=head2 getSearchTemplateVars ( )
Performs the search and returns the tmpl var hashref.
=cut
sub getSearchTemplateVars {
my $self = shift;
my $thingId = shift || $self->session->form->process('thingId');
my $thingProperties = shift || $self->getThing($thingId);
my $session = $self->session;
my $dbh = $session->db->dbh;
my $i18n = WebGUI::International->new($self->session,"Asset_Thingy");
my ($var,$url,$orderBy);
my ($fields,@searchFields_loop,@displayInSearchFields_loop,$query,@constraints);
my (@searchResult_loop,$searchResults,@searchResults,@displayInSearchFields,$paginatePage,$currentUrl,$p);
$orderBy = $session->form->process("orderBy") || $thingProperties->{sortBy};
$var = $self->get;
$url = $self->getUrl;
$var->{canEditThings} = $self->canEdit;
$var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new');
$var->{"manage_url"} = $session->url->append($url, 'func=manage');
$var->{"thing_label"} = $thingProperties->{label};
if ($self->hasPrivileges($thingProperties->{groupIdExport})){
$var->{"export_url"} = $session->url->append($url, 'func=export;thingId='.$thingId);
}
if ($self->hasPrivileges($thingProperties->{groupIdImport})){
$var->{"import_url"} = $session->url->append($url, 'func=importForm;thingId='.$thingId);
}
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};
$var->{searchDescription} = $thingProperties->{searchDescription};
$currentUrl = $self->getUrl();
foreach ($self->session->form->param) {
# if we just saved data from an edit, we do not want to keep any of the params
last if $_ eq 'func' and $self->session->form->process($_) eq 'editThingDataSave';
unless ($_ eq "pn" || $_ eq "op" || $_ =~ /identifier/xi || $_ =~ /password/xi || $_ eq "orderBy" ||
$self->session->form->process($_) eq "") {
$currentUrl = $self->session->url->append($currentUrl,$self->session->url->escape($_)
.'='.$self->session->url->escape($self->session->form->process($_)));
}
}
$fields = $session->db->read('select * from Thingy_fields where assetId =
'.$session->db->quote($self->getId).' and thingId = '.$session->db->quote($thingId).' order by
sequenceNumber');
while (my $field = $fields->hashRef) {
if ($field->{searchIn}){
my $searchForm = $self->getFormElement($field);
my $searchTextForm = WebGUI::Form::Text($self->session, {
name=>"field_".$field->{fieldId},
size=>25,
});
my $fieldType;
if ($field->{fieldType} =~ m/^otherThing/x){
$fieldType = "OtherThing";
}
else{
$fieldType = ucfirst $field->{fieldType};
}
push(@searchFields_loop, {
"searchFields_fieldId" => $field->{fieldId},
"searchFields_label" => $field->{label},
"searchFields_form" => $searchForm,
"searchFields_textForm" => $searchTextForm,
"searchFields_is".$fieldType => 1,
});
my @searchValue = $session->form->process("field_".$field->{fieldId});
my $constraint =
join ' OR ',
map { $dbh->quote_identifier("field_".$field->{fieldId}) . " LIKE " . $dbh->quote('%'.$_.'%') }
@searchValue ;
push @constraints, " ( $constraint ) " if @searchValue;
}
if($field->{displayInSearch}){
my $orderByUrl = $self->session->url->append($currentUrl,"orderBy=".$field->{fieldId});
push(@displayInSearchFields_loop, {
"displayInSearchFields_fieldId" => $field->{fieldId},
"displayInSearchFields_label" => $field->{label},
"displayInSearchFields_orderByUrl" => $orderByUrl,
});
push(@displayInSearchFields, {
fieldId => $field->{fieldId},
properties => $field,
});
}
}
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);
if($session->form->process('func') eq 'search'){
# Don't add constraints when the search screen is displayed as an 'after save' option.
$query .= " where ".join(" and ",@constraints) if (scalar(@constraints) > 0);
}
if ($orderBy){
$query .= " order by ".$dbh->quote_identifier("field_".$orderBy);
}
}
else{
$self->session->errorHandler->warn("The default Thing has no fields selected to display in the search.");
$noFields = 1;
}
# store query in cache for thirty minutes
eval{$self->session->cache->set("query_".$thingId, $query, 30*60)};
$paginatePage = $self->session->form->param('pn') || 1;
$currentUrl = $self->session->url->append($currentUrl, "orderBy=".$orderBy) if $orderBy;
$p = WebGUI::Paginator->new($self->session,$currentUrl,$thingProperties->{thingsPerPage}, undef, $paginatePage);
my $sth = $self->session->db->read($query) if ! $noFields;
my @visibleResults;
while (my $result = $sth->hashRef){
if ($self->canViewThingData($thingId,$result->{thingDataId})){
push(@visibleResults,$result);
}
}
$p->setDataByArrayRef(\@visibleResults) if ! $noFields;
$searchResults = $p->getPageData($paginatePage);
foreach my $searchResult (@$searchResults){
my (@field_loop);
foreach my $field (@displayInSearchFields){
my $fieldId = $field->{fieldId};
my $value = $self->getFieldValue($searchResult->{"field_".$fieldId},$field->{properties});
push(@field_loop,{
"field_value" => $value,
"field_id" => $fieldId,
});
}
my $thingDataId = $searchResult->{thingDataId};
my %templateVars = (
"searchResult_id" => $thingDataId,
"searchResult_view_url" => $session->url->append($url, 'func=viewThingData;thingId='
.$thingId.';thingDataId='.$thingDataId),
"searchResult_field_loop" => \@field_loop,
);
if ($self->canEditThingData($thingId,$thingDataId,$thingProperties)){
$templateVars{canEditThingData} = 1;
$templateVars{searchResult_delete_icon} = $session->icon->delete('func=deleteThingDataConfirm;thingId='
.$thingId.';thingDataId='.$thingDataId,$self->url,$i18n->get('delete thing data warning'));
$templateVars{searchResult_delete_url} = $session->url->append($url,
'func=deleteThingDataConfirm;thingId='.$thingId.';thingDataId='.$thingDataId);
$templateVars{searchResult_edit_icon} = $session->icon->edit('func=editThingData;thingId='
.$thingId.';thingDataId='.$thingDataId,$self->url);
$templateVars{searchResult_edit_url} = $session->url->append($url,
'func=editThingData;thingId='.$thingId.';thingDataId='.$thingDataId);
$templateVars{searchResult_copy_icon} = $session->icon->copy('func=copyThingData;thingId='
.$thingId.';thingDataId='.$thingDataId,$self->url);
$templateVars{searchResult_copy_url} = $session->url->append($url,
'func=copyThingData;thingId='.$thingId.';thingDataId='.$thingDataId,);
}
push(@searchResult_loop,\%templateVars);
}
$var->{searchResult_loop} = \@searchResult_loop;
$p->appendTemplateVars($var);
$var->{"form_start"} = WebGUI::Form::formHeader($self->session,{action=>$self->getUrl,method=>'GET'})
.WebGUI::Form::hidden($self->session,{name=>"func",value=>"search"});
$var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"thingId",value=>$thingId});
$var->{"form_submit"} = WebGUI::Form::submit($self->session,{value=>$i18n->get("search button label")});
$var->{"form_end"} = WebGUI::Form::formFooter($self->session);
$var->{searchFields_loop} = \@searchFields_loop;
$var->{displayInSearchFields_loop} = \@displayInSearchFields_loop;
$self->appendThingsVars($var, $thingId);
return $var;
}
#-------------------------------------------------------------------
=head2 www_selectDefaultFieldValue ( )
Returns a form element to select a field in a thing.
=cut
sub www_selectDefaultFieldValue {
my $self = shift;
my $thingId = $self->session->form->process('thingId');
my $fieldId = $self->session->form->process('fieldId');
my $fieldInOtherThingId = $self->session->form->process('fieldInOtherThingId');
return "" if ($thingId eq "" || $fieldId eq "");
my $session = $self->session;
my $dbh = $session->db->dbh;
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
return $session->privilege->insufficient() unless $self->canViewThing($thingId);
my $options = $session->db->buildHashRef('select thingDataId, '
.$dbh->quote_identifier('field_'.$fieldInOtherThingId)
.' from '.$dbh->quote_identifier('Thingy_'.$thingId)
.' where '.$dbh->quote_identifier('field_'.$fieldInOtherThingId).' != ""');
my ($value) = $session->db->quickArray('select defaultValue from Thingy_fields where fieldId=?',[$fieldId]);
my $formElement;
if (scalar(keys %$options) > 0){
$formElement = WebGUI::Form::SelectBox($self->session,{
name => "defaultFieldInThing",
options => $options,
value => $value,
extras => 'style="width: 200px;"',
});
}
else{
$formElement = $i18n->get('no field values message');
}
my $html .= "\t<table cellpadding='0' cellspacing='0' style='width: 100%;'>\n";
$html .= "\t<tr><td class='formDescription' valign='top' style='width:180px'>";
$html .= $i18n->get("default value label")."</td>";
$html .= "<td valign='top' class='tableData' style='padding-left:4px'>";
$html .= $formElement."</td>";
$html .= "\t\n</tr>\n";
$html .= "\t</table>";
$self->session->output->print($html);
return "chunked";
}
#-------------------------------------------------------------------
=head2 www_selectFieldInThing ( )
Returns a form element to select a field in a thing.
=cut
sub www_selectFieldInThing {
my $self = shift;
my $thingId = $self->session->form->process('thingId');
my $fieldId = $self->session->form->process('fieldId');
my $prefix = $self->session->form->process('prefix');
my $session = $self->session;
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
return $session->privilege->insufficient() unless $self->canViewThing($thingId);
my $fields = $session->db->buildHashRef('select fieldId, label from Thingy_fields'
.' where assetId = ? and thingId = ? and fieldId != ? order by sequenceNumber',
[$self->getId,$thingId,$fieldId]);
my ($value) = $session->db->quickArray('select fieldInOtherThingId from Thingy_fields where fieldId = '
.$session->db->quote($fieldId));
my $formElement = WebGUI::Form::SelectBox($self->session,{
name => "fieldInOtherThingId",
options => $fields,
id => $prefix."_fieldInOtherThing_formId",
value => $value,
extras => 'style="width: 200px;"',
});
my $html .= "\t<table cellpadding='0' cellspacing='0' style='width: 100%;'>\n";
$html .= "\t<tr><td class='formDescription' valign='top' style='width:180px'>";
$html .= $i18n->get("field in other thing label")."</td>";
$html .= "<td valign='top' class='tableData' style='padding-left:4px'>";
$html .= $formElement."</td>";
$html .= "\t\n</tr>\n";
$html .= "\t</table>";
$self->session->output->print($html);
return "chunked";
}
#-------------------------------------------------------------------
=head2 www_viewThingData ( )
Shows the view screen of a Thing
=head3 thingId
The unique id of a thing.
=head3 thingDataId
The unique id of a row of thing data.
=cut
sub www_viewThingData {
my $self = shift;
my $session = $self->session;
my $thingId = shift || $session->form->process('thingId');
my $thingDataId = shift || $session->form->process('thingDataId');
my $var = $self->get;
my $url = $self->getUrl;
my $i18n = WebGUI::International->new($self->session, "Asset_Thingy");
my $thingProperties = $self->getThing($thingId);
return $self->session->privilege->insufficient() unless $self->canViewThingData(
$thingId, $thingDataId, $thingProperties);
$var->{canEditThings} = $self->canEdit;
$var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new');
$var->{"manage_url"} = $session->url->append($url, 'func=manage');
$var->{"thing_label"} = $thingProperties->{label};
if($self->hasPrivileges($thingProperties->{groupIdEdit})){
$var->{"edit_url"} = $session->url->append($url,'func=editThingData;thingId='
.$thingId.';thingDataId='.$thingDataId);
$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}) && !$self->hasEnteredMaxPerUser($thingId)){
$var->{"add_url"} = $session->url->append($url, 'func=editThingData;thingId='.$thingId.';thingDataId=new');
}
if($self->hasPrivileges($thingProperties->{groupIdSearch})){
$var->{"search_url"} = $session->url->append($url, 'func=search;thingId='.$thingId);
}
$self->getViewThingVars($thingId,$thingDataId,$var);
$self->appendThingsVars($var, $thingId);
return $self->processStyle(
$self->processTemplate($var,$thingProperties->{viewTemplateId})
);
}
#-------------------------------------------------------------------
=head2 www_viewThingDataViaAjax ( )
Returns a thing instance as JSON data.
=head3 thingId
The unique id of a thing.
=head3 thingDataId
The unique id of a row of thing data.
=cut
sub www_viewThingDataViaAjax {
my $self = shift;
my $session = $self->session;
my $thingId = shift || $session->form->process('thingId');
my $thingDataId = shift || $session->form->process('thingDataId');
$session->http->setMimeType("application/json");
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);
if ($thingProperties->{thingId}){
return $self->session->privilege->insufficient() unless $self->canViewThingData(
$thingId, $thingDataId, $thingProperties);
my $output = $self->getViewThingVars($thingId,$thingDataId);
if ($output){
return JSON->new->encode($output);
}
else{
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "The thingDataId you requested can not be found."});
}
}
else {
$session->http->setStatus("404", "Not Found");
return JSON->new->encode({message => "The thingId you requested can not be found."});
}
}
1;