From cb4729f7e70b4b8443286a9178f8ab30f3936564 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Sat, 19 Nov 2005 20:54:15 +0000 Subject: [PATCH] added zip archive and in/out board assets --- docs/changelog/6.x.x.txt | 3 +- docs/gotcha.txt | 11 +- docs/upgrades/upgrade_6.7.8-6.8.0.pl | 186 +++++++- lib/WebGUI/Asset/File/ZipArchive.pm | 312 ++++++++++++ lib/WebGUI/Asset/Wobject/InOutBoard.pm | 504 ++++++++++++++++++++ lib/WebGUI/Help/Asset_InOutBoard.pm | 61 +++ lib/WebGUI/Help/Asset_ZipArchive.pm | 57 +++ lib/WebGUI/i18n/English/Asset_InOutBoard.pm | 230 +++++++++ lib/WebGUI/i18n/English/Asset_ZipArchive.pm | 91 ++++ sbin/changeIobStatus.pl | 136 ++++++ sbin/preload.perl | 1 + sbin/spectre.pl | 108 ++++- sbin/testEnvironment.pl | 8 +- www/extras/assets/small/ziparchive.gif | Bin 0 -> 373 bytes www/extras/assets/ziparchive.gif | Bin 0 -> 1961 bytes 15 files changed, 1674 insertions(+), 34 deletions(-) create mode 100644 lib/WebGUI/Asset/File/ZipArchive.pm create mode 100644 lib/WebGUI/Asset/Wobject/InOutBoard.pm create mode 100644 lib/WebGUI/Help/Asset_InOutBoard.pm create mode 100644 lib/WebGUI/Help/Asset_ZipArchive.pm create mode 100644 lib/WebGUI/i18n/English/Asset_InOutBoard.pm create mode 100644 lib/WebGUI/i18n/English/Asset_ZipArchive.pm create mode 100644 sbin/changeIobStatus.pl create mode 100644 www/extras/assets/small/ziparchive.gif create mode 100644 www/extras/assets/ziparchive.gif diff --git a/docs/changelog/6.x.x.txt b/docs/changelog/6.x.x.txt index 44736108e..7a526d9e4 100644 --- a/docs/changelog/6.x.x.txt +++ b/docs/changelog/6.x.x.txt @@ -14,9 +14,8 @@ - Added template to Collaboration RSS feeds. - Added page.isContainer and page.isUtility template variables to Navigation templates. - - Added Spectre, WebGUI's new background processing engine which manages - things like scheduled tasks and workflow processing. - Added Matrix asset. + - Added In/Out Board asset. 6.7.7 diff --git a/docs/gotcha.txt b/docs/gotcha.txt index 3e3c6e445..324036a2b 100644 --- a/docs/gotcha.txt +++ b/docs/gotcha.txt @@ -13,9 +13,16 @@ save you many hours of grief. DateTime DateTime::Format::Strptime DateTime::Cron::Simple - POE - POE::Component::IKC::Server + Archive::Zip + + And optionally, these: + Test::More + Pod::Coverage + + * If you have previously installed the community contributed version + of the In/Out Board (IOB) then you will need to completely + uninstall it before you can proceed with this upgrade. * The core API has changed. Check docs/migration.txt for details. diff --git a/docs/upgrades/upgrade_6.7.8-6.8.0.pl b/docs/upgrades/upgrade_6.7.8-6.8.0.pl index 996f05e0c..fb4e5433d 100644 --- a/docs/upgrades/upgrade_6.7.8-6.8.0.pl +++ b/docs/upgrades/upgrade_6.7.8-6.8.0.pl @@ -35,12 +35,69 @@ updateCollaboration(); addPhotoField(); addAvatarField(); addEnableAvatarColumn(); -addSpectre(); -addWorkflow(); +#addSpectre(); +#addWorkflow(); addMatrix(); updateConfigFile(); +addInOuutBoard(); +addZipArchive(); finish(); +#------------------------------------------------- +sub addZipArchive { + print "\nAdding Zip Archive Asset\n" unless ($quiet); + WebGUI::SQL->write("create table ZipArchiveAsset ( + assetId varchar(22) binary not null, + templateId varchar(22) binary not null default '', + showPage varchar(255) not null default 'index.html', + revisionDate bigint not null, + primary key (assetId,revisionDate) +)"); + my $import = WebGUI::Asset->getImportNode; + my $folder = $import->addChild({ + title=>"Zip Archive Templates", + menuTitle=>"Zip Archive Templates", + className=>"WebGUI::Asset::Wobject::Folder", + url=>"ziparchive-templates", + }); + my $template = < + +

+
+ + + +
    +
  • +
+
+ + + + + + Error: No initial page specified + + Error: No file specified + + + STOP + my $newAsset = $folder->addChild({ + title=>"Default Zip Archive Template", + menuTitle=>"Default Zip Archive Template", + namespace=>"ZipArchiveAsset", + url=>"zip-archive-template", + className=>"WebGUI::Asset::Template", + template=>$template + }, "ZipArchiveTMPL00000001"); + $newAsset->commit; +} + #------------------------------------------------- sub updateConfigFile { print "\tUpdating config file.\n" unless ($quiet); @@ -53,11 +110,136 @@ sub updateConfigFile { } } push(@{$newConfig{assets}}, "WebGUI::Asset::Wobject::Matrix"); + push(@{$newConfig{assets}}, "WebGUI::Asset::Wobject::InOutBoard"); $conf->purge; $conf->set(%newConfig); $conf->write; } +#------------------------------------------------- +sub addInOutBoard { + print "\tAdding In/Out Board Asset\n" unless ($quiet); + WebGUI::SQL->write("create table InOutBoard ( + assetId varchar(22) binary not null primary key, + revisionDate bigint, + statusList text, + reportViewerGroup varchar(22) binary not null default '3', + inOutGroup varchar(22) binary not null default '2', + inOutTemplateId varchar(22) binary not null default 'IOB0000000000000000001', + reportTemplateId varchar(22) binary not null default 'IOB0000000000000000002', + paginateAfter int not null default 50, + reportPaginateAfter int not null default 50 + )"); + WebGUI::SQL->write("create table InOutBoard_status ( + assetId varchar(22) binary not null, + userId varchar(22) binary not null, + status varchar(255), + dateStamp int not null, + message text + )"); + WebGUI::SQL->write("create table InOutBoard_statusLog ( + assetId varchar(22) binary not null, + userId varchar(22) binary not null, + status varchar(255), + dateStamp int not null, + message text + )"); + WebGUI::SQl->write("insert into userProfileField (fieldName,fieldLabel,visible,dataType,dataValues,dataDefault,sequenceNumber,profileCategoryId,editable) values ('department',".quote("'Department'").",1,'selectList',".quote("{'IT'=>'IT','HR'=>'HR','Regular Staff'=>'Regular Staff'}").",".quote("['Regular Staff']").",8,'6',1)"); + my $import = WebGUI::Asset->getImportNode; + my $folder = $import->addChild({ + title=>"In/Out Board Templates", + menuTitle=>"In/Out Board Templates", + className=>"WebGUI::Asset::Wobject::Folder", + url=>"iob-templates", + }); + my $template = <In/Out Board Report +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+STOP + my $newAsset = $folder->addChild({ + title=>"Default InOutBoard Report Template", + menuTitle=>"Default InOutBoard Report Template", + namespace=>"InOutBoard/Report", + url=>"iob-report-template", + className=>"WebGUI::Asset::Template", + template=>$template + }, "IOB0000000000000000002"); + $newAsset->commit; + my $template = < + +

+
+ + +

+
+ + + + + Select delegates + + + +  ·  + + View Report + + +
+
+ + + + + + + + + + + + + + +
+STOP + my $newAsset = $folder->addChild({ + title=>"Default InOutBoard Template", + menuTitle=>"Default InOutBoard Template", + namespace=>"InOutBoard", + url=>"iob-template", + className=>"WebGUI::Asset::Template", + template=>$template + }, "IOB0000000000000000001"); + $newAsset->commit; +} + #------------------------------------------------- sub addMatrix { print "\tAdding Matrix Asset\n" unless ($quiet); diff --git a/lib/WebGUI/Asset/File/ZipArchive.pm b/lib/WebGUI/Asset/File/ZipArchive.pm new file mode 100644 index 000000000..eec512876 --- /dev/null +++ b/lib/WebGUI/Asset/File/ZipArchive.pm @@ -0,0 +1,312 @@ +package WebGUI::Asset::File::ZipArchive; + +=head1 LEGAL + + ------------------------------------------------------------------- + WebGUI is Copyright 2001-2005 Plain Black Corporation. + ------------------------------------------------------------------- + Please read the legal notices (docs/legal.txt) and the license + (docs/license.txt) that came with this distribution before using + this software. + ------------------------------------------------------------------- + http://www.plainblack.com info@plainblack.com + ------------------------------------------------------------------- + +=cut + +use strict; +use WebGUI::Asset::File; +use WebGUI::HTMLForm; +use WebGUI::HTTP; +use WebGUI::Session; +use WebGUI::SQL; +use WebGUI::Utility; + +use Archive::Tar; +use Archive::Zip; + +our @ISA = qw(WebGUI::Asset::File); + + +=head1 NAME + +Package WebGUI::Asset::ZipArchive + +=head1 DESCRIPTION + +Provides a mechanism to upload and automatically extract a zip archive +containing related items. An asset setting will set the launch point of the archive. + +=head1 SYNOPSIS + +use WebGUI::Asset::ZipArchive; + + +=head1 METHODS + +These methods are available from this class: + +=cut + +#------------------------------------------------------------------- +sub unzip { + my $self = shift; + my $storage = $_[0]; + my $filename = $_[1]; + + my $filepath = $storage->getPath(); + chdir $filepath; + + if($filename =~ m/\.zip/i){ + my $zip = Archive::Zip->new(); + unless ($zip->read($filename) == $zip->AZ_OK){ + WebGUI::ErrorHandler::warn(WebGUI::International::get("zip_error","Asset_ZipArchive")); + return 0; + } + $zip->extractTree(); + } elsif($filename =~ m/\.tar/i){ + Archive::Tar->extract_archive($filepath.$session{os}{slash}.$filename,1); + if (Archive::Tar->error){ + WebGUI::ErrorHandler::warn(Archive::Tar->error); + return 0; + } + } else{ + WebGUI::ErrorHandler::warn(WebGUI::International::get("bad_archive","Asset_ZipArchive")); + } + + return 1; +} + +#------------------------------------------------------------------- +=head2 addRevision + + This method exists for demonstration purposes only. The superclass + handles revisions to ZipArchive Assets. + +=cut + +sub addRevision { + my $self = shift; + my $newSelf = $self->SUPER::addRevision(@_); + return $newSelf; +} + +#------------------------------------------------------------------- +=head2 definition ( definition ) + +Defines the properties of this asset. + +=head3 definition + +A hash reference passed in from a subclass definition. + +=cut + +sub definition { + my $class = shift; + my $definition = shift; + push(@{$definition}, { + assetName=>WebGUI::International::get('asset label',"Asset_ZipArchive"), + tableName=>'ZipArchiveAsset', + className=>'WebGUI::Asset::File', + properties=>{ + showPage=>{ + fieldType=>'text', + defaultValue=>'index.html' + }, + templateId=>{ + fieldType=>'template', + defaultValue=>'' + }, + } + }); + return $class->SUPER::definition($definition); +} + + +#------------------------------------------------------------------- +=head2 duplicate + + This method exists for demonstration purposes only. The superclass + handles duplicating ZipArchive Assets. This method will be called + whenever a copy action is executed + +=cut + +sub duplicate { + my $self = shift; + my $newAsset = $self->SUPER::duplicate(shift); + return $newAsset; +} + + +#------------------------------------------------------------------- +=head2 getEditForm () + +Returns the TabForm object that will be used in generating the edit page for this asset. + +=cut + +sub getEditForm { + my $self = shift; + my $tabform = $self->SUPER::getEditForm(); + $tabform->getTab("display")->template( + -value=>$self->getValue("templateId"), + -label=>WebGUI::International::get('template label', 'Asset_ZipArchive'), + -namespace=>"ZipArchiveAsset" + ); + $tabform->getTab("properties")->text ( + -name=>"showPage", + -label=>WebGUI::International::get('show page', 'Asset_ZipArchive'), + -value=>$self->getValue("showPage"), + -hoverHelp=>WebGUI::International::get('show page description', 'Asset_ZipArchive'), + ); + return $tabform; +} + + +#------------------------------------------------------------------- +=head2 getIcon ( [small] ) + +Returns the icons to be associated with this asset + +=head3 small + +If this evaluates to True, then the smaller icon is returned. + +=cut + +sub getIcon { + my $self = shift; + my $small = shift; + return $session{config}{extrasURL}.'/assets/ziparchive.gif' unless ($small); + return $session{config}{extrasURL}.'/assets/small/ziparchive.gif'; +} + + +#------------------------------------------------------------------- +=head2 processPropertiesFromFormPost ( ) + +Used to process properties from the form posted. In this asset, we use +this method to deflate the zip file into the proper folder + +=cut + +sub processPropertiesFromFormPost { + my $self = shift; + #File should be saved here by the superclass + $self->SUPER::processPropertiesFromFormPost; + my $storage = $self->getStorageLocation(); + + my $file = $self->get("filename"); + + #return unless $file; + unless($session{form}{showPage}) { + $storage->delete; + WebGUI::SQL->write("update FileAsset set filename=NULL where assetId=".quote($self->getId)); + WebGUI::Session::setScratch("za_error",WebGUI::International::get("za_show_error","Asset_ZipArchive")); + return; + } + + unless($file =~ m/\.tar/i || $file =~ m/\.zip/i) { + $storage->delete; + WebGUI::SQL->write("update FileAsset set filename=NULL where assetId=".quote($self->getId)); + WebGUI::Session::setScratch("za_error",WebGUI::International::get("za_error","Asset_ZipArchive")); + return; + } + + unless ($self->unzip($storage,$self->get("filename"))) { + WebGUI::ErrorHandler::warn(WebGUI::International::get("unzip_error","Asset_ZipArchive")); + } +} + + +#------------------------------------------------------------------- +=head2 purge ( ) + +This method is called when data is purged by the system. + +=cut + +sub purge { + my $self = shift; + return $self->SUPER::purge; +} + +#------------------------------------------------------------------- +=head2 purgeRevision ( ) + +This method is called when data is purged by the system. + +=cut + +sub purgeRevision { + my $self = shift; + return $self->SUPER::purgeRevision; +} + +#------------------------------------------------------------------- +=head2 view ( ) + +method called by the container www_view method. In this asset, this is +used to show the file to administrators. + +=cut + +sub view { + my $self = shift; + my %var = %{$self->get}; + #WebGUI::ErrorHandler::warn($self->getId); + $var{controls} = $self->getToolbar; + if($session{scratch}{za_error}) { + $var{error} = $session{scratch}{za_error}; + } + WebGUI::Session::deleteScratch("za_error"); + my $storage = $self->getStorageLocation; + if($self->get("filename") ne "") { + $var{fileUrl} = $storage->getUrl($self->get("showPage")); + $var{fileIcon} = $storage->getFileIconUrl($self->get("showPage")); + } + unless($self->get("showPage")) { + $var{pageError} = "true"; + } + return $self->processTemplate(\%var,$self->get("templateId")); +} + + +#------------------------------------------------------------------- +=head2 www_edit ( ) + +Web facing method which is the default edit page + +=cut + +sub www_edit { + my $self = shift; + return WebGUI::Privilege::insufficient() unless $self->canEdit; + $self->getAdminConsole->setHelp("zip archive add/edit", "Asset_ZipArchive"); + return $self->getAdminConsole->render($self->getEditForm->print, + WebGUI::International::get('edit asset',"Asset_ZipArchive")); +} + +#------------------------------------------------------------------- +=head2 www_view ( ) + +Web facing method which is the default view page. This method does a +302 redirect to the "showPage" file in the storage location. + +=cut + +sub www_view { + my $self = shift; + return WebGUI::Privilege::noAccess() unless $self->canView; + if (WebGUI::Session::isAdminOn()) { + return $self->getContainer->www_view; + } + WebGUI::HTTP::setRedirect($self->getFileUrl($self->getValue("showPage"))); + return ""; +} + + +1; + diff --git a/lib/WebGUI/Asset/Wobject/InOutBoard.pm b/lib/WebGUI/Asset/Wobject/InOutBoard.pm new file mode 100644 index 000000000..2c243e9ce --- /dev/null +++ b/lib/WebGUI/Asset/Wobject/InOutBoard.pm @@ -0,0 +1,504 @@ +package WebGUI::Asset::Wobject::InOutBoard; + +$VERSION = "0.5.3"; + +use strict; +use WebGUI::DateTime; +use WebGUI::FormProcessor; +use WebGUI::Grouping; +use WebGUI::HTMLForm; +use WebGUI::International; +use WebGUI::Paginator; +use WebGUI::Privilege; +use WebGUI::Session; +use WebGUI::SQL; +use WebGUI::URL; +use WebGUI::Asset::Wobject; +use WebGUI::ErrorHandler; +use Data::Dumper; + +our @ISA = qw(WebGUI::Asset::Wobject); + +#See line 285 if you wish to change the users visible in the delegate select list + +#------------------------------------------------------------------- + +sub _defineUsername { + my $data = shift; + if ($data->{firstName} ne "" && $data->{lastName} ne "") { + return join ' ', $data->{firstName}, $data->{lastName}; + } + else { + return $data->{username}; + } +} + +#------------------------------------------------------------------- + +sub _fetchNames { + my @userIds = @_; + my %nameHash; + my $sql = "select users.username, +users.userId, +a.fieldData as firstName, +b.fieldData as lastName +from users +left join userProfileData a on users.userId=a.userId and a.fieldName='firstName' +left join userProfileData b on users.userId=b.userId and b.fieldName='lastName' +where users.userId=?"; + my $sth = WebGUI::SQL->prepare($sql); + foreach my $userId (@userIds) { + $sth->execute([ $userId ]); + $nameHash{ $userId } = _defineUsername($sth->hashRef); + } + $sth->finish; + return %nameHash; +} + +#------------------------------------------------------------------- +sub _fetchDepartments { + return WebGUI::SQL->buildArray("select fieldData from userProfileData where fieldName='department' GROUP by fieldData"); +} + + +#------------------------------------------------------------------- +sub definition { + my $class = shift; + my $definition = shift; + push(@{$definition}, { + tableName=>'InOutBoard', + className=>'WebGUI::Asset::Wobject::InOutBoard', + properties=>{ + statusList => { + defaultValue => WebGUI::International::get(10, "Asset_InOutBoard")."\n" + .WebGUI::International::get(11, "Asset_InOutBoard")."\n", + fieldType=>"textarea" + }, + reportViewerGroup => { + defaultValue => 3, + fieldType => "group" + }, + inOutGroup => { + defaultValue => 2, + fieldType => "group" + }, + inOutTemplateId => { + fieldType=>"template", + defaultValue => 'IOB0000000000000000001' + }, + reportTemplateId => { + fieldType=>"template", + defaultValue => 'IOB0000000000000000002' + }, + paginateAfter => { + fieldType=>"integer", + defaultValue => 50 + }, + } + }); + return $class->SUPER::definition($definition); +} + + +#------------------------------------------------------------------- +sub getEditForm { + my $self = shift; + my $tabform = $self->SUPER::getEditForm(); + $tabform->getTab("properties")->textarea( + -name=>"statusList", + -label=>WebGUI::International::get(1, "Asset_InOutBoard"), + -value=>$self->getValue("statusList"), + -subtext=>WebGUI::International::get(2, "Asset_InOutBoard"), + ); + $tabform->getTab("display")->integer( + -name=>"paginateAfter", + -label=>WebGUI::International::get(12, "Asset_InOutBoard"), + -value=>$self->getValue("paginateAfter") + ); + $tabform->getTab("display")->template ( + -name => "inOutTemplateId", + -value => $self->getValue("inOutTemplateId"), + -label => WebGUI::International::get("In Out Template", "Asset_InOutBoard"), + -namespace => "InOutBoard" + ); + $tabform->getTab("display")->template ( + -name => "reportTemplateId", + -value => $self->getValue("reportTemplateId"), + -label => WebGUI::International::get(13, "Asset_InOutBoard"), + -namespace => "InOutBoard/Report" + ); + $tabform->getTab("security")->group( + -name=>"reportViewerGroup", + -value=>[$self->getValue("reportViewerGroup")], + -label=>WebGUI::International::get(3, "Asset_InOutBoard") + ); + $tabform->getTab("security")->group( + -name=>"inOutGroup", + -value=>[$self->getValue("inOutGroup")], + -label=>WebGUI::International::get('inOutGroup', "Asset_InOutBoard") + ); + return $tabform; +} + + +#------------------------------------------------------------------- +sub getName { + return WebGUI::International::get(9,"Asset_InOutBoard"); +} + +#------------------------------------------------------------------- +sub view { + my $self = shift; + my %var; + my $url = $self->getUrl('func=view'); + + if (WebGUI::Grouping::isInGroup($self->getValue("reportViewerGroup"))) { + $var{'viewReportURL'} = $self->getUrl("func=viewReport"); + $var{canViewReport} = 1; + } + else { $var{canViewReport} = 0; } + + my $statusUserId = $session{scratch}{userId} || $session{user}{userId}; + my $statusListString = $self->getValue("statusList"); + chop($statusListString); + my @statusListArray = split("\n",$statusListString); + my $statusListHashRef; + + foreach my $status (@statusListArray) { + chop($status); + $statusListHashRef->{$status} = $status; + } + + #WebGUI::ErrorHandler::warn("VIEW: userId: ".$statusUserId."\n" ); + my ($status) = WebGUI::SQL->quickArray("select status from InOutBoard_status where userId=".quote($statusUserId)." and assetId=".quote($self->getId)); + + ##Find all the users for which I am a delegate + my @users = WebGUI::SQL->buildArray("select userId from InOutBoard_delegates where assetId=".quote($self->getId)." and delegateUserId=".quote($session{user}{userId})); + + my $f = WebGUI::HTMLForm->new(-action=>$self->getUrl); + if (@users) { + my %nameHash; + tie %nameHash, "Tie::IxHash"; + %nameHash = _fetchNames(@users); + $nameHash{""} = WebGUI::International::get('myself',"Asset_InOutBoard"); + %nameHash = WebGUI::Utility::sortHash(%nameHash); + + $f->selectList( + -name=>"delegate", + -options=>\%nameHash, + -value=>[ $session{scratch}{userId} ], + -label=>WebGUI::International::get('delegate', "Asset_InOutBoard"), + -extras=>q|onchange="this.form.submit();"|, + ); + } + $f->radioList( + -name=>"status", + -value=>$status, + -options=>$statusListHashRef, + -label=>WebGUI::International::get(5, "Asset_InOutBoard") + ); + $f->text( + -name=>"message", + -label=>WebGUI::International::get(6, "Asset_InOutBoard") + ); + $f->hidden( + -name=>"func", + -value=>"setStatus" + ); + $f->submit; + + my ($isInGroup) = WebGUI::SQL->quickArray("select count(*) from groupings where userId=".quote($session{user}{userId})." and groupId=".quote($self->get("inOutGroup"))); + if ($isInGroup) { + $var{displayForm} = 1; + $var{'form'} = $f->print; + $var{'selectDelegatesURL'} = $self->getUrl("func=selectDelegates"); + } + else { $var{displayForm} = 0; } + + my $lastDepartment = "_nothing_"; + + my $p = WebGUI::Paginator->new($url, $self->getValue("paginateAfter")); + + my $sql = "select users.username, +users.userId, +a.fieldData as firstName, +InOutBoard_status.message, +b.fieldData as lastName, +InOutBoard_status.status, +InOutBoard_status.dateStamp, +c.fieldData as department, +groupings.groupId +from users, InOutBoard, groupings +left join userProfileData a on users.userId=a.userId and a.fieldName='firstName' +left join userProfileData b on users.userId=b.userId and b.fieldName='lastName' +left join userProfileData c on users.userId=c.userId and c.fieldName='department' +left join InOutBoard_status on users.userId=InOutBoard_status.userId and InOutBoard_status.assetId=".quote($self->getId())." +where users.userId<>'1' and groupings.groupId=InOutBoard.inOutGroup and groupings.userId=users.userId and InOutBoard.inOutGroup=".quote($self->get("inOutGroup"))." +group by userId +order by department, lastName, firstName"; + + $p->setDataByQuery($sql); + my $rowdata = $p->getPageData(); + my @rows; + foreach my $data (@$rowdata) { + my %row; + if ($lastDepartment ne $data->{department}) { + $row{deptHasChanged} = 1; + $row{'department'} = ($data->{department}||WebGUI::International::get(7, "Asset_InOutBoard")); + $lastDepartment = $data->{department}; + } + else { $row{deptHasChanged} = 0; } + + if ($data->{firstName} ne "" && $data->{lastName} ne "") { + $row{'username'} = $data->{firstName}." ".$data->{lastName}; + } + else { + $row{'username'} = $data->{username}; + } + + $row{'status'} = ($data->{status}||WebGUI::International::get(15, "Asset_InOutBoard")); + $row{'dateStamp'} = WebGUI::DateTime::epochToHuman($data->{dateStamp}); + $row{'message'} = ($data->{message}||" "); + + push (@rows, \%row); + } + $var{rows_loop} = \@rows; + $var{'paginateBar'} = $p->getBarTraditional(); + $p->appendTemplateVars(\%var); + + return $self->processTemplate(\%var,$self->getValue("inOutTemplateId")); +} + +#------------------------------------------------------------------- +sub www_edit { + my $self = shift; + return WebGUI::Privilege::insufficient() unless $self->canEdit; + return $self->getAdminConsole->render($self->getEditForm->print,WebGUI::International::get("Edit In/Out Board","Asset_InOutBoard")); +} + +#------------------------------------------------------------------- +sub www_selectDelegates { + my $self = shift; + + #Uncomment the sql query below (lines 286 - 294) to show all users of the system in the delegate select list + #my $sql = sprintf "select users.username, +#users.userId, +#a.fieldData as firstName, +#b.fieldData as lastName +#from users +#left join userProfileData a on users.userId=a.userId and a.fieldName='firstName' +#left join userProfileData b on users.userId=b.userId and b.fieldName='lastName' +#where users.userId<>'1' and users.status='Active' and users.userId<>%s +#group by userId", quote($session{user}{userId}); + + #Comment the sql query below (lines 297 - 307) to show all users of the system in the delegate select list + my $sql = sprintf "select users.username, +users.userId, +a.fieldData as firstName, +b.fieldData as lastName +from users, InOutBoard, groupings +left join userProfileData a on users.userId=a.userId and a.fieldName='firstName' +left join userProfileData b on users.userId=b.userId and b.fieldName='lastName' +left join userProfileData c on users.userId=c.userId and c.fieldName='department' +left join InOutBoard_status on users.userId=InOutBoard_status.userId and InOutBoard_status.assetId=%s +where users.userId<>'1' and groupings.groupId=InOutBoard.inOutGroup and users.status='Active' and users.userId <> %s and groupings.userId=users.userId and InOutBoard.inOutGroup=%s +group by userId", quote($self->getId), quote($session{user}{userId}), quote($self->getValue("inOutGroup")) ; + my %userNames = (); + my $sth = WebGUI::SQL->read($sql); + while (my $data = $sth->hashRef) { + $userNames{ $data->{userId} } = _defineUsername($data); + } + $sth->finish; + $sql = sprintf "select delegateUserId from InOutBoard_delegates where userId=%s and assetId=%s", + quote($session{user}{userId}), quote($self->getId); + my $delegates = WebGUI::SQL->buildArrayRef($sql); + my $f = WebGUI::HTMLForm->new(-action=>$self->getUrl); + $f->hidden( + -name => "func", + -value => "selectDelegatesEditSave" + ); + $f->selectList( + -name => "delegates", + -label => WebGUI::International::get('in/out status delegates','Asset_InOutBoard'), + -options => \%userNames, + -multiple => 1, ##Multiple select + -size => 10, ##Multiple select + -sortByValue => 1, + -value => $delegates, ##My current delegates, if any + -subtext => WebGUI::International::get('in/out status delegates subtext','Asset_InOutBoard'), + ); + $f->submit; + my $ac = $self->getAdminConsole; + return $ac->render($f->print, + WebGUI::International::get('select delegate','Asset_InOutBoard')); +} + +#------------------------------------------------------------------- +sub www_selectDelegatesEditSave { + my $self = shift; + my @delegates = WebGUI::FormProcessor::selectList("delegates"); + WebGUI::SQL->write("delete from InOutBoard_delegates where assetId=".quote($self->getId)." and userId=".quote($session{user}{userId})); + + foreach my $delegate (@delegates) { + WebGUI::SQL->write("insert into InOutBoard_delegates + (userId,delegateUserId,assetId) values + (".quote($session{user}{userId}).",".quote($delegate).",".quote($self->getId).")"); + } + return ""; +} +#------------------------------------------------------------------- +sub www_setStatus { + my $self = shift; + #WebGUI::ErrorHandler::warn("delegateId: ". $session{form}{delegate}."\n" ); + #WebGUI::ErrorHandler::warn("userId: ".$session{scratch}{userId} ."\n" ); + if ($session{form}{delegate} eq $session{scratch}{userId}) { + #WebGUI::ErrorHandler::warn("Wrote data and removed scratch\n"); + my $sessionUserId = $session{scratch}{userId} || $session{user}{userId}; + #WebGUI::ErrorHandler::warn("user Id: ".$sessionUserId."\n"); + WebGUI::Session::deleteScratch("userId"); + WebGUI::SQL->write("delete from InOutBoard_status where userId=".quote($sessionUserId)." and assetId=".quote($self->getId)); + WebGUI::SQL->write("insert into InOutBoard_status (assetId,userId,status,dateStamp,message) values (".quote($self->getId).",".quote($sessionUserId)."," + .quote($session{form}{status}).",".WebGUI::DateTime::time().",".quote($session{form}{message}).")"); + WebGUI::SQL->write("insert into InOutBoard_statusLog (assetId,userId,createdBy,status,dateStamp,message) values (".quote($self->getId).",".quote($sessionUserId).",".quote($session{user}{userId})."," + .quote($session{form}{status}).",".WebGUI::DateTime::time().",".quote($session{form}{message}).")"); + } + else { + #WebGUI::ErrorHandler::warn("Set scratch, redisplay\n"); + #WebGUI::ErrorHandler::warn(sprintf "Delegate is %s\n", $session{form}{delegate}); + WebGUI::Session::setScratch("userId",$session{form}{delegate}); + } + return $self->www_view; +} + +sub www_view { + my $self = shift; + $self->SUPER::www_view(1); +} + +#------------------------------------------------------------------- +sub www_viewReport { + my $self = shift; + return "" unless (WebGUI::Grouping::isInGroup($self->getValue("reportViewerGroup"))); + my %var; + my $f = WebGUI::HTMLForm->new(-action=>$self->getUrl, -method=>"GET"); + my %changedBy = (); + $f->hidden( + -name=>"func", + -value=>"viewReport" + ); + $f->hidden( + -name=>"doit", + -value=>"1" + ); + my $startDate = WebGUI::DateTime::addToDate(WebGUI::DateTime::time(),0,0,-15); + $startDate = WebGUI::FormProcessor::date("startDate") if ($session{form}{doit}); + $f->date( + -name=>"startDate", + -label=>WebGUI::International::get(16, "Asset_InOutBoard"), + -value=>$startDate + ); + my $endDate = WebGUI::FormProcessor::date("endDate"); + $f->date( + -name=>"endDate", + -label=>WebGUI::International::get(17, "Asset_InOutBoard"), + -value=>$endDate + ); + my %depHash; + %depHash = map { $_ => $_ } (_fetchDepartments(), + WebGUI::International::get('all departments', 'Asset_InOutBoard')); + my $defaultDepartment = $session{form}{selectDepartment} + || WebGUI::International::get('all departments', 'Asset_InOutBoard'); + my $departmentSQLclause = ($defaultDepartment eq WebGUI::International::get('all departments', 'Asset_InOutBoard')) + ? '' + : 'and c.fieldData='.quote($defaultDepartment); + $f->selectList( + -name=>"selectDepartment", + -options=>\%depHash, + -value=>[ $defaultDepartment ], + -label=>WebGUI::International::get('filter departments', "Asset_InOutBoard"), + ); + my %paginHash; + tie %paginHash, "Tie::IxHash"; ##Because default sort order is alpha + %paginHash = (50 => 50, 100 => 100, 300 => 300, 500 => 500, 1000 => 1000, 10_000 => 10_000,); + my $pageReportAfter = $session{form}{reportPagination} || 50; + $f->selectList( + -name=>"reportPagination", + -options=>\%paginHash, + -value=>[ $pageReportAfter ], + -label=>WebGUI::International::get(14, "Asset_InOutBoard"), + ); + $f->submit(-value=>"Search"); + $var{'form'} = $f->print; + my $url = $self->getUrl("func=viewReport&selectDepartment=$session{form}{selectDepartment}&reportPagination=$session{form}{reportPagination}&startDate=$session{form}{startDate}&endDate=$session{form}{endDate}&doit=1"); + if ($session{form}{doit}) { + $var{showReport} = 1; + $endDate = WebGUI::DateTime::addToTime($endDate,24,0,0); + my $lastDepartment = "_none_"; + my $p = WebGUI::Paginator->new($url, $pageReportAfter); + + my $sql = "select users.username, +users.userId, +a.fieldData as firstName, +InOutBoard_statusLog.message, +b.fieldData as lastName, +InOutBoard_statusLog.status, +InOutBoard_statusLog.dateStamp, +InOutBoard_statusLog.createdBy, +c.fieldData as department, +groupings.groupId +from users, InOutBoard, groupings +left join userProfileData a on users.userId=a.userId and a.fieldName='firstName' +left join userProfileData b on users.userId=b.userId and b.fieldName='lastName' +left join userProfileData c on users.userId=c.userId and c.fieldName='department' +left join InOutBoard_statusLog on users.userId=InOutBoard_statusLog.userId and InOutBoard_statusLog.assetId=".quote($self->getId())." +where users.userId<>'1' and + groupings.groupId=".quote($self->getValue("inOutGroup"))." and + groupings.userId=users.userId and + InOutBoard_statusLog.dateStamp>=$startDate and + InOutBoard_statusLog.dateStamp<=$endDate + $departmentSQLclause +group by InOutBoard_statusLog.dateStamp +order by department, lastName, firstName, InOutBoard_statusLog.dateStamp"; + #WebGUI::ErrorHandler::warn("QUERY: $sql\n"); + $p->setDataByQuery($sql); + my $rowdata = $p->getPageData(); + my @rows; + foreach my $data (@$rowdata) { + my %row; + + if ($lastDepartment ne $data->{department}) { + $row{deptHasChanged} = 1; + $row{'department'} = ($data->{department}||WebGUI::International::get(7, "Asset_InOutBoard")); + $lastDepartment = $data->{department}; + } + else { $row{deptHasChanged} = 0; } + + $row{'username'} = _defineUsername($data); + + $row{'status'} = ($data->{status}||WebGUI::International::get(15, "Asset_InOutBoard")); + $row{'dateStamp'} = WebGUI::DateTime::epochToHuman($data->{dateStamp}); + $row{'message'} = ($data->{message}||" "); + if (! exists $changedBy{ $data->{createdBy} }) { + my %whoChanged = _fetchNames($data->{createdBy}); + $changedBy{ $data->{createdBy} } = $whoChanged{ $data->{createdBy} }; + } + $row{'createdBy'} = $changedBy{ $data->{createdBy} }; + + push (@rows, \%row); + } + $var{rows_loop} = \@rows; + $var{'paginateBar'} = $p->getBarTraditional(); + $var{'username.label'} = WebGUI::International::get('username.label','Asset_InOutBoard'); + $var{'status.label'} = WebGUI::International::get(5,'Asset_InOutBoard'); + $var{'date.label'} = WebGUI::International::get('date.label','Asset_InOutBoard'); + $var{'message.label'} = WebGUI::International::get('message.label','Asset_InOutBoard'); + $var{'updatedBy.label'} = WebGUI::International::get('updatedBy.label','Asset_InOutBoard'); + $p->appendTemplateVars(\%var); + } + else { $var{showReport} = 0; } + + return $self->processStyle($self->processTemplate(\%var, $self->getValue("reportTemplateId"))); +} + +1; + diff --git a/lib/WebGUI/Help/Asset_InOutBoard.pm b/lib/WebGUI/Help/Asset_InOutBoard.pm new file mode 100644 index 000000000..e8c700cc8 --- /dev/null +++ b/lib/WebGUI/Help/Asset_InOutBoard.pm @@ -0,0 +1,61 @@ +package WebGUI::Help::Asset_InOutBoard; + +our $HELP = { + '1' => { + title => '18', + body => '19', + related => [ + { + tag => '2', + namespace => 'Asset_InOutBoard' + }, + { + tag => 'wobject add/edit', + namespace => 'WebGUI' + }, + { + tag => 'wobjects using', + namespace => 'WebGUI' + } + ] + }, + '2' => { + title => '20', + body => '21', + related => [ + { + tag => '1', + namespace => 'Asset_InOutBoard' + }, + { + tag => 'template language', + namespace => 'WebGUI' + }, + { + tag => 'wobject template', + namespace => 'WebGUI' + } + ] + }, + '3' => { + title => '22', + body => '23', + related => [ + { + tag => '1', + namespace => 'Asset_InOutBoard' + }, + { + tag => '2', + namespace => 'Asset_InOutBoard' + }, + { + tag => 'template language', + namespace => 'WebGUI' + } + ] + }, +}; + +1; + diff --git a/lib/WebGUI/Help/Asset_ZipArchive.pm b/lib/WebGUI/Help/Asset_ZipArchive.pm new file mode 100644 index 000000000..4a6dd0fbf --- /dev/null +++ b/lib/WebGUI/Help/Asset_ZipArchive.pm @@ -0,0 +1,57 @@ +package WebGUI::Help::Asset_ZipArchive; + +our $HELP = { + + 'zip archive add/edit' => { + title => 'zip archive add/edit title', + body => 'zip archive add/edit body', + fields => [ + { + title => 'new file', + description => 'new file description', + namespace => 'Asset_File', + }, + { + title => 'current file', + description => 'current file description', + namespace => 'Asset_File', + }, + { + title => 'show page', + description => 'show page description', + namespace => 'Asset_ZipArchive', + }, + + ], + related => [ + { + tag => 'asset fields', + namespace => 'Asset', + }, + { + tag => 'zip archive template', + namespace => 'Asset_ZipArchive', + }, + ] + }, + + 'zip archive template' => { + title => 'zip archive template title', + body => 'zip archive template body', + fields => [ + ], + related => [ + { + tag => 'file add/edit', + namespace => 'Asset_File', + }, + { + tag => 'template language', + namespace => 'Asset_Template', + }, + ] + }, + +}; + +1; diff --git a/lib/WebGUI/i18n/English/Asset_InOutBoard.pm b/lib/WebGUI/i18n/English/Asset_InOutBoard.pm new file mode 100644 index 000000000..145a26fb9 --- /dev/null +++ b/lib/WebGUI/i18n/English/Asset_InOutBoard.pm @@ -0,0 +1,230 @@ +package WebGUI::i18n::English::Asset_InOutBoard; + +our $I18N = { + 'In Out Template' => { + message => q|In/Out Template|, + lastUpdated =>1091624565 + }, + + '22' => { + message => q|In/Out Board, Report Template|, + lastUpdated =>1091624565 + }, + + '18' => { + message => q|In/Out Board, Add/Edit|, + lastUpdated =>1091624565 + }, + + 'select delegate' => { + message => q|In/Out Board, Select Delegates|, + lastUpdated =>1122010599 + }, + + 'in/out status delegates' => { + message => q|In/Out Status Delegates|, + lastUpdated =>1122010599 + }, + + '23' => { + message => q| The following variables are made available from In/Out Board Report: +

showReport
A boolean indicating whether or not the rows_loop variable will be set.

form
A variable that contains the HTML for displaying the Date Range Selector Form for the report. 

rows_loop
A loop containing the rows of data for the In/Out Board Report 

+

deptHasChanged
A boolean value indicating whether or not this row of data is for a department that is differnet than the previous rows

username
A variable that returns the users name. If the first and last name fields are defined in the user profile, that is what is returned. Otherwise, the users WebGUI username is returned. i.e., "John Doe" vs "Jdoe"

status
A variable that returns the users status. The status of a user is defined by the Status List in the Wobject Properties. If no status is set for the current user 'Never Checked In' is returned.

dateStamp
A variable that returns the date the status of the user was last updated.

message
A variable that returns what the user entered in the "What's going on?" field when updating their status.

paginateBar
A variable that returns the HTML necessary to create a Traditional Pagination Bar. i.e., << First, 1, 2, Last >>

|, + + lastUpdated =>1091624565 + }, + + '19' => { + message => q|An In/Out board is used to keep track of whether people are currently in/out of the office. It shows the current In/Out status of all WebGUI users and also logs the event the person has left for, the time they left and the time they return.

Status List
The status list allows you to customize what the 'states' of a user are. i.e., 'In' or 'Out'.

Paginate After
How many rows should be displayed before splitting the results into separate pages? In other words, how many rows should be displayed per page?

Report Paginate After
Same as paginate after except that it controls the number of rows displayed in the In/Out Report.

Who Can View Reports?
What group is allowed to view reports generated by the In/Out Board Wobject.

|, + lastUpdated =>1091624565 + }, + + '20' => { + message => q|In/Out Board, Template|, + lastUpdated =>1091624565 + }, + + '21' => { + message => q|The following variables are made available from In/Out Board: +

canViewReport
+A boolean indicating whether or not the viewReportURL variable will be set.

+ +

viewReportURL
+URL that links to the view report page.

+ +

selectDelegatesURL
+URL that links to a form where users can select other users (delegates) who +can alter their status.

+ +

displayForm
+A boolean indicating whether or not the form variable will be set.

+ +

form
+A variable that contains the HTML for displaying the In/Out Entry Form.

+ +

rows_loop
+A loop containing the rows of data for the In/Out Board

+ +
+ +

deptHasChanged
+A boolean value indicating whether or not this row of data is for a department that is differnet than the previous rows

+ +

username
+A variable that returns the users name. If the first and last name fields are defined in the user profile, that is what is returned. Otherwise, the users WebGUI username is returned. i.e., "John Doe" vs "Jdoe"

+ +

status
+A variable that returns the users status. The status of a user is defined by the Status List in the Wobject Properties. If no status is set for the current user 'Never Checked In' is returned.

+ +

dateStamp
+A variable that returns the date the status of the user was last updated.

+ +

message
+A variable that returns what the user entered in the "What's going on?" field when updating their status.

+
+

paginateBar
+A variable that returns the HTML necessary to create a Traditional Pagination Bar. i.e., >> First, 1, 2, Last <<

+ + |, + lastUpdated =>1122523725 + }, + + '2' => { + message => q|Enter one per line.|, + lastUpdated =>1091624565 + }, + + 'in/out status delegates subtext' => { + message => q|Multiple users can be selected as delegates. Delegates will be able to update your status.|, + lastUpdated =>1122523790, + }, + + '17' => { + message => q|End Date|, + lastUpdated =>1091624565 + }, + + '16' => { + message => q|Start Date|, + lastUpdated =>1091624565 + }, + + '15' => { + message => q|Never Checked In|, + lastUpdated =>1091624565 + }, + + '14' => { + message => q|Paginate Report After|, + lastUpdated =>1091624565 + }, + + '13' => { + message => q|Report Template|, + lastUpdated =>1091624565 + }, + + '12' => { + message => q|Paginate After|, + lastUpdated =>1091624565 + }, + + '11' => { + message => q|Out|, + lastUpdated =>1091624565 + }, + + '10' => { + message => q|In|, + lastUpdated =>1091624565 + }, + + '9' => { + message => q|In/Out Board|, + lastUpdated =>1091624565 + }, + + '8' => { + message => q|Status Log Report|, + lastUpdated =>1091624565 + }, + + '7' => { + message => q|No Department|, + lastUpdated =>1091624565 + }, + + '6' => { + message => q|What's happening?|, + lastUpdated =>1091624565 + }, + + 'delegate' => { + message => q|Update status for: |, + lastUpdated =>1122319088 + }, + + 'myself' => { + message => q|Myself|, + lastUpdated =>1122319088 + }, + + '5' => { + message => q|Status|, + lastUpdated =>1091624565 + }, + + '4' => { + message => q|View Report|, + lastUpdated =>1091624565 + }, + + '3' => { + message => q|Who can view reports?|, + lastUpdated =>1091624565 + }, + + '1' => { + message => q|Status List|, + lastUpdated =>1091624565 + }, + + 'inOutGroup' => { + message => q|Who can log in/out?|, + lastUpdated =>1091624565 + }, + + 'username.label' => { + message => q|Username|, + lastUpdated =>1123199740 + }, + + 'date.label' => { + message => q|Date|, + lastUpdated =>1123199740 + }, + + 'message.label' => { + message => q|Message|, + lastUpdated =>1123199740 + }, + + 'updatedBy.label' => { + message => q|Updated By|, + lastUpdated =>1123199740 + }, + + 'all departments' => { + message => q|All Departments|, + lastUpdated =>1123266324 + }, + + 'filter departments' => { + message => q|Filter departments:|, + lastUpdated =>1123266322 + }, + + +}; + +1; diff --git a/lib/WebGUI/i18n/English/Asset_ZipArchive.pm b/lib/WebGUI/i18n/English/Asset_ZipArchive.pm new file mode 100644 index 000000000..7fe15456a --- /dev/null +++ b/lib/WebGUI/i18n/English/Asset_ZipArchive.pm @@ -0,0 +1,91 @@ +package WebGUI::i18n::English::Asset_ZipArchive; + +our $I18N = { + + + 'zip_error' => { + message => q|An error occurred while trying to unzip the archive. Please check to make sure the file is not password protected and can be accessed by the operating system.|, + lastUpdated => 1119068809 + }, + + 'bad_archive' => { + message => q|Not a valid archive. Please use zip or tar archives to import files |, + lastUpdated => 1119068809 + }, + + 'unzip_error' => { + message => q|File could not be unzipped. Please upload a valid archive|, + lastUpdated => 1119068809 + }, + + 'template label' => { + message => q|Zip Archive Template|, + context => q|label for Zip Archive asset form|, + lastUpdated => 1121703035, + }, + + 'show page' => { + message => q|Initial Page|, + context => q|label for Zip Archive asset form|, + lastUpdated => 1106762088 + }, + + 'asset label' => { + message => q|Zip Archive|, + context => q|label for Asset Manager, getName|, + lastUpdated => 1121703035, + }, + + 'show page description' => { + message => q|Enter the name of the file which serves as the "base" file for this archive. This is the page which will initially be served up|, + lastUpdated => 1119068745 + }, + + 'za_error' => { + message => q|This asset only accepts valid tar and zip files|, + lastUpdated => 1119068745 + }, + + 'za_show_error' => { + message => q|You must provide an initial page to direct users|, + lastUpdated => 1119068745 + }, + + 'zip archive add/edit title' => { + message => q|Zip Archive, Add/Edit|, + lastUpdated => 1119068745 + }, + + 'zip archive add/edit body' => { + message => q|

Zip Archive Assets are assets on your site that are allow you to upload a zip archive (as either zip or tar) containing files that require collateral (static html pages with images or movies, etc) that you wish to display to your users outside of the WebGUI context, but retain WebGUI's file security. The asset uzips the folder in a WebGUI storage location, and redirects the user to the initial page when the link provided is clicked

|, + lastUpdated => 1119068839, + }, + + 'zip archive template title' => { + message => q|Zip Archive, Template|, + lastUpdated => 1109287565, + }, + + 'zip archive template body' => { + message => q|

The following variables are available in Zip Archive Templates:

+ +

controls
+Asset controls for administrators. + +

error
+Any errors reported during upload or unzip + +

fileUrl
+URL to the initial file + +

fileIcon
+Initial file file type icon + |, + context => 'Describing the zip archive template variables', + lastUpdated => 1109287834, + }, + + +}; + +1; diff --git a/sbin/changeIobStatus.pl b/sbin/changeIobStatus.pl new file mode 100644 index 000000000..cdbf5e460 --- /dev/null +++ b/sbin/changeIobStatus.pl @@ -0,0 +1,136 @@ +#!/usr/bin/perl + +our ($webguiRoot); + +BEGIN { + $webguiRoot = ".."; + unshift (@INC, $webguiRoot."/lib"); +} + +use Getopt::Long; +use strict; +use WebGUI::DateTime; +use WebGUI::MessageLog; +use WebGUI::Session; +use WebGUI::SQL; +use WebGUI::User; + +$|=1; + +my $configFile; +my $help; +my $quiet; +my $whatsHappening = "Automatically signed out."; +my $newStatus = "Out"; +my $currentStatus = "In"; +my $userMessage = "You were logged out of the In/Out Board automatically."; +my $userMessageFile; + + +GetOptions( + 'configfile=s'=>\$configFile, + 'help'=>\$help, + 'quiet'=>\$quiet, + 'whatsHappening:s'=>\$whatsHappening, + 'userMessage:s'=>\$userMessage, + 'userMessageFile:s'=>\$userMessageFile, + 'currentStatus:s'=>\$currentStatus, + 'newStatus:s'=>\$newStatus +); + + + + + +unless ($configFile && !$help) { + print < + + --configFile WebGUI config file (with no path info). + +Description: This utility allows you to automate the switching of status + for users in the IOB. For instance, you may wish to + automatically mark out all users each night that haven't + already marked out. + +Options: + + --currentStatus The status to check for. Defaults to "$currentStatus". + + --help Display this help message. + + --newStatus The status to set the user to. Defaults to + "$newStatus". + + --quiet Disable output unless there's an error. + + --userMessage A message to be sent to the user upon getting their + status changed. Defaults to "$userMessage". + + --userMessageFile A path to a filename to override the + --userMessage with. This option will read the + contents of the file and send that as the + message. + + --whatsHappening The message attached to the IOB when + changing status. Defaults to + "$whatsHappening". + +STOP + exit; +} + + + + +print "Starting up...\n" unless ($quiet); +WebGUI::Session::open($webguiRoot,$configFile); + +if ($userMessageFile) { + print "Opening message file.." unless ($quiet); + if (open(FILE,"<".$userMessageFile)) { + print "OK\n" unless ($quiet); + my $contents; + while () { + $contents .= $_; + } + close(FILE); + if (length($contents) == 0) { + print "Message file empty, reverting to original message.\n"; + } else { + $userMessage = $contents; + } + } else { + print "Failed to open message file.\n"; + } +} + +print "Searching for users with a status of $currentStatus ...\n" unless ($quiet); +my $userList; +my $now = WebGUI::DateTime::time(); +my $sth = WebGUI::SQL->read("select userId,assetId from InOutBoard_status where status=".quote($currentStatus)); +while (my ($userId,$assetId) = $sth->array) { + my $user = WebGUI::User->new($userId); + print "\tFound user ".$user->username."\n" unless ($quiet); + $userList .= $user->username." (".$userId.")\n"; + WebGUI::SQL->write("update InOutBoard_status set dateStamp=".$now.", message=".quote($whatsHappening).", + status=".quote($newStatus)." where userId=".quote($userId)." and assetId=".quote($assetId)); + WebGUI::SQL->write("insert into InOutBoard_statusLog (userId, createdBy, dateStamp, message, status, assetId) values ( + ".quote($userId).", ".quote(3).", ".$now.", ".quote($whatsHappening).", ".quote($newStatus).", ".quote($assetId).")"); + WebGUI::MessageLog::addEntry($userId,undef,"IOB Update",$userMessage); +} +$sth->finish; + +if (length($userList) > 0) { + print "Alerting admins of changes\n" unless ($quiet); + my $message = "The following users had their status changed:\n\n".$userList; + WebGUI::MessageLog::addEntry(undef,"3","IOB Update",$message); +} + +print "Cleaning up..." unless ($quiet); +WebGUI::Session::end($session{var}{sessionId}); +WebGUI::Session::close(); +print "OK\n" unless ($quiet); + diff --git a/sbin/preload.perl b/sbin/preload.perl index df1ca55e5..7890eb61a 100644 --- a/sbin/preload.perl +++ b/sbin/preload.perl @@ -53,6 +53,7 @@ use Storable; use XML::Simple (); use Compress::Zlib (); use Archive::Tar (); +use Archive::Zip (); use IO::Zlib (); #### diff --git a/sbin/spectre.pl b/sbin/spectre.pl index 225831394..fe55ea240 100644 --- a/sbin/spectre.pl +++ b/sbin/spectre.pl @@ -18,6 +18,7 @@ use POE qw(Session); use POE::Component::IKC::ClientLite; use POE::Component::IKC::Server; use POE::Component::IKC::Specifier; +use POE::Component::JobQueue; use WebGUI::Session; use WebGUI::Workflow; @@ -67,27 +68,36 @@ fork and exit; create_ikc_server( - port => 32133, - name => 'Spectre', -); + port => 32133, + name => 'Spectre', + ); POE::Session->create( - inline_states => { - _start => \&initializeScheduler, - _stop => \&shutdown, - "shutdown" => \&shutdown, - loadSchedule => \&loadSchedule, - checkSchedule => \&checkSchedule, - checkEvent => \&checkEvent, - } -); + inline_states => { + _start => \&initializeScheduler, + _stop => \&shutdown, + "shutdown" => \&shutdown, + loadSchedule => \&loadSchedule, + checkSchedule => \&checkSchedule, + checkEvent => \&checkEvent, + } + ); POE::Session->create( - inline_states => { - _start => \&initializeJobQueue, - _stop => \&shutdown, - } -); + inline_states => { + _start => \&initializeJobQueue, + _stop => \&shutdown, + } + ); + +POE::Component::JobQueue->spawn ( + Alias => 'queuer', + WorkerLimit => 10, + Worker => \&spawnWorker, + Passive => { + Prioritizer => \&prioritizeJobs, + }, + ); POE::Kernel->run(); exit 0; @@ -122,6 +132,9 @@ sub initializeJobQueue { $kernel->alias_set($serviceName); $kernel->call( IKC => publish => $serviceName, ["shutdown"] ); print "OK\n"; + foreach my $config (keys %{WebGUI::Config::readAllConfigs("..")}) { + $kernel->yield("loadJobs", $config); + } } #------------------------------------------------------------------- @@ -138,6 +151,12 @@ sub initializeScheduler { $kernel->yield("checkSchedule"); } +#------------------------------------------------------------------- +sub loadJobs { + my ($heap, $config) = @_[HEAP, ARG0]; + sessionOpen($config); +} + #------------------------------------------------------------------- sub loadSchedule { my ($heap, $config) = @_[HEAP, ARG0]; @@ -147,14 +166,13 @@ sub loadSchedule { } #------------------------------------------------------------------- -sub shutdown { - my $kernel = $_[KERNEL]; - print "Stopping WebGUI Spectre..."; - if ($session{var}{userId}) { - sessionClose(); - } - print "OK\n"; - $kernel->stop; +sub performJob { + +} + +#------------------------------------------------------------------- +sub prioritizeJobs { + return 1; # FIFO queue, but let's add priorities at some point } #------------------------------------------------------------------- @@ -169,4 +187,44 @@ sub sessionClose { WebGUI::Session::close(); } +#------------------------------------------------------------------- +sub shutdown { + my $kernel = $_[KERNEL]; + print "Stopping WebGUI Spectre..."; + if ($session{var}{userId}) { + sessionClose(); + } + print "OK\n"; + $kernel->stop; +} + +#------------------------------------------------------------------- +sub spawnWorker { + my ($postback, @jobParams) = @_; + POE::Session->create ( + inline_states => { + _start => \&startWorker, + _stop => \&stopWorker, + performJob => \&performJob + }, + args => [ + $postback, + @jobParams, + ], + ); +} + +#------------------------------------------------------------------- +sub startWorker { + +} + +#------------------------------------------------------------------- +sub stopWorker { + +} + + + + diff --git a/sbin/testEnvironment.pl b/sbin/testEnvironment.pl index c0af30d2d..231d0dd5e 100644 --- a/sbin/testEnvironment.pl +++ b/sbin/testEnvironment.pl @@ -52,6 +52,7 @@ checkModule("DBI",1.40); checkModule("DBD::mysql",2.1021); checkModule("HTML::Parser",3.36); checkModule("Archive::Tar",1.05); +checkModule("Archive::Zip",1.16); checkModule("IO::Zlib",1.01); checkModule("Compress::Zlib",1.34); checkModule("Net::SMTP",2.24); @@ -61,7 +62,7 @@ checkModule("XML::Simple",2.09); checkModule("SOAP::Lite",0.60); checkModule("DateTime",0.2901); checkModule("Time::HiRes",1.38); -checkModule("DateTime::Format::Strptime"); +checkModule("DateTime::Format::Strptime",1.0601); checkModule("DateTime::Cron::Simple",0.2); checkModule("Image::Magick",5.47,1); checkModule("Log::Log4perl",0.51); @@ -71,8 +72,9 @@ checkModule("HTML::TagFilter",0.07); checkModule("HTML::Template",2.7); checkModule("Parse::PlainConfig",1.1); checkModule("XML::RSSLite",0.11); -checkModule("POE",0.3202); -checkModule("POE::Component::IKC::Server",0.18); +#checkModule("POE",0.3202); +#checkModule("POE::Component::IKC::Server",0.18); +#checkModule("POE::Component::JobQueue",0.5402); checkModule("Apache2::Request",2.06); ################################### diff --git a/www/extras/assets/small/ziparchive.gif b/www/extras/assets/small/ziparchive.gif new file mode 100644 index 0000000000000000000000000000000000000000..1e8f480785c18024962095c2a9b0db4dfc612fc3 GIT binary patch literal 373 zcmZ?wbhEHb6krfwxN6R@Y}vBq%a<=*x^&g*)k~HvS-pDoi4!N*ty}lz&6}p`>g6j| z+`fIgC?{v*=FJZuKD>VY`lWN{{@)3F_3G6gE2{}TJ%4`x-ln0kEFfS-Zryt2 z@|7b;j+{GpZj-$HuHCy=u3UNW;K9ub3X2yn7Ghw?O-=m|1ZNn41OpDB_>+Z^fx(IuEW|;;o(v&%|@5&AK=v!8MAIw-9FDWw z3=7D}$#V({`kxHK!^7g@<3d70tpWnD0s_y@&g|^$zP`WY+9d%-^Zmm9 zr!jYScdo6hH!dzqM?RvWqNSy!v9YoL%mAdMq^72(sHmuPbadzF=c%cwu&}VFr>CZ- zr}XsnA0Hju+})+5q)13e+}zyV-QBRUvA@8-rl+T;sHnNQx#s2Ozretwq@>2h#mmgh z`TF_Y+})_DsjjZA-{0V*q@$>(sN&(_tgNe~rKH^5+}z#WtE{Z3sHv!_sHv){h&MO- z`ueZ1u(`UrwYIj!#>LIf&Dq-7si~^T$;rdP!Q`t%;;cvfz+je@m8Yksv9PiDvJk4O zsb3Bacn%Qup%%u)#;2&K`JfS_qokdjo8aKz?Ck5ex3{^vxv#IU)XK`WwY8|Hr?$1V zqokwd<>vRpZl8UvTyb7LLTdu0A#l^*> zqon8O=g`m4t*xyj83nz)z3iqhpNEI=$A8Vu&GYl~+1c6J+1aiK2g%CG^{5xg%F5N% z)upAR!NS4t@9^yF>%zjpsEl6T-QMcy>f@_J&(F`LrlzH(rswGB?d|TSrKS1#`TF|# z{l)~Yt*)e`rK_x~S1&KCtE=7I+}GFFs;R1~sj2Vp@UyeCok7zd2eH za_xHa#nP|}kkyHx;fAOyA*Kf4H!aInx*+?Rs8OQ_rAxuws3W8-*sn7i%v2yV$0%a2 zCTP@f08P+d4G|n6L*vg3fE8p6AO3uE@#te^)v0r1*^rqKIx0+&IhU^D#x3^X;hS0z zn%^PBxFt@zHjNg(a;vNSiw%=2D+0LxDmpvaXT?+;G$_OzkE&TZuKd8@${%^T9nYvi zjNXAKWx7@72LN|`5!6ffE!0sQ<*3n0SN#+~11i)o_Xsjy%<#nsP`qRxb^dUo$Qq46 zSimULghkj7P!(0bm=)i!MAtiVaP4{>S<{NRWVMk&u z0He-2l6b*{7zt$7CWy7%g9ZW2EbzuEyX@ytKP}LrfdO8GumT1H*yN@`G>L!-1!!2( zPCTacv4%U3qB0FRSNwEAhnj-_2!bE6fI15^jD#u28G(poOdf6gz`zAEBDHBjH0=R` z0kviT2LX^Q5Q!YZ^wLj1Dqw&?03FbEEI~AVqb#$9K07BL{iKmbKOGDpXjk73L=!SG z0OE`RBHVHhDYssm?z-2Gfmpm7b>spvC+va4FP<8DZ503Z1H-lT!3*LOoqTYD6${f! zK|fJI%uX@=u)<0|Is{mhzjmF&IFslXqgmP^u*j$@RKS`);EQlm5BTY6RAj6Ha ze$;$z7hNpfPZE@=F=zy5M@x1F&biO3@y04_MjAM~R{7g8K? z1Q%R*@U$4V?25~vN6PR@9+7K9Ld%_4o_P?R5An?BVXi?YQ6T1m&ko^m-~-ia_oEB! zoj(%>7*8_*W+bDS)2l~&)5HP!bRhQx8kom`d;i#W0m#3ts^4-_EoT3dKp1@5tr z{=I<>Ye=7h{1E|r+@J|=$b}3Lfw~6vgB*j%SU*1Tv=LZ<0{XDTAs9gqMQHF%9hpN4 z?17FZoZ}BN*a0tw`eB3z_JasK8^I-FQ441sB3d`(R7bR+!*2AD1%JTDBKi@HDr{jK z;{XLHCeRN$1YlVrD3l&<6-8uqL;_SyK{uA*jp^m!T2&Ya5ynWyGA>{b_e$fwX3<7) voyUk}yo1jgH=EA{AOH+#LmL?INN*7bBbdyjCif