Added SQLReport download and Product AddToGroup handler
This commit is contained in:
parent
03822a9488
commit
6d56df1362
13 changed files with 946 additions and 28 deletions
|
|
@ -12,6 +12,11 @@
|
|||
- fix: Events Calendar: error in "big" template (Martin Kamerbeek / Procolix)
|
||||
- fix: PM task editor not preserving duration
|
||||
- fix: PM project completion percentage updates not working right
|
||||
- Added ability to download an SQLReport in either CSV or as a template.
|
||||
- Added ability for Products to add a user to a group when purchased.
|
||||
- Changed the ?op=editProduct form to a TabForm.
|
||||
- fixed a small error in WebGUI::Group documentation.
|
||||
- Added WebGUI::Text with some CSV functions.
|
||||
|
||||
7.0.9
|
||||
- Removed the need for DateTime::Cron::Simple, which also added the ability
|
||||
|
|
|
|||
129
docs/upgrades/templates-7.1.0/SQLReport-Download.tmpl
Normal file
129
docs/upgrades/templates-7.1.0/SQLReport-Download.tmpl
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#SQLReportDownload0001
|
||||
#namespace:SQLReport/Download
|
||||
#title:SQLReport Download Default Template
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<!-- Handle nested query2 -->
|
||||
<tmpl_if hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query2.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query2.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query2.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<!-- Handle nested query3 -->
|
||||
<tmpl_if query2.hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var query2.columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:20px;"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query3.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query3.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query3.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<!-- Handle nested query4 -->
|
||||
<tmpl_if query3.hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var query3.columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:20px;"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query4.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query4.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query4.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
<!-- Handle nested query5 -->
|
||||
<tmpl_if query4.hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var query4.columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:20px;"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query5.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query5.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query5.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
161
docs/upgrades/templates-7.1.0/SQLReport.tmpl
Normal file
161
docs/upgrades/templates-7.1.0/SQLReport.tmpl
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
#PBtmpl0000000000000059
|
||||
<a name="id<tmpl_var assetId>" id="id<tmpl_var assetId>"></a>
|
||||
|
||||
<tmpl_if session.var.adminOn>
|
||||
<p><tmpl_var controls></p>
|
||||
</tmpl_if>
|
||||
|
||||
<tmpl_if displayTitle>
|
||||
<h2><tmpl_var title></h2>
|
||||
</tmpl_if>
|
||||
|
||||
<tmpl_if description>
|
||||
<tmpl_var description>
|
||||
<p />
|
||||
</tmpl_if>
|
||||
|
||||
<tmpl_if canDownload>
|
||||
<a href="/<tmpl_var url>?func=download">Download this data</a>
|
||||
</tmpl_if>
|
||||
|
||||
<tmpl_if debugMode>
|
||||
<ul>
|
||||
<tmpl_loop debug_loop>
|
||||
<li><tmpl_var debug.output></li>
|
||||
</tmpl_loop>
|
||||
</ul>
|
||||
</tmpl_if>
|
||||
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<!-- Handle nested query2 -->
|
||||
<tmpl_if hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td width="20"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query2.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query2.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query2.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<!-- Handle nested query3 -->
|
||||
<tmpl_if query2.hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var query2.columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:20px;"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query3.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query3.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query3.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<!-- Handle nested query4 -->
|
||||
<tmpl_if query3.hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var query3.columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:20px;"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query4.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query4.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query4.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
<!-- Handle nested query5 -->
|
||||
<tmpl_if query4.hasNest>
|
||||
<tr>
|
||||
<td colspan="<tmpl_var query4.columns.count>">
|
||||
<table width="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:20px;"> </td>
|
||||
<td>
|
||||
<table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<tmpl_loop query5.columns_loop>
|
||||
<td class="tableHeader"><tmpl_var column.name></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
<tmpl_loop query5.rows_loop>
|
||||
<tr>
|
||||
<tmpl_loop query5.row.field_loop>
|
||||
<td class="tableData"><tmpl_var field.value></td>
|
||||
</tmpl_loop>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tr>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tmpl_if>
|
||||
</tmpl_loop>
|
||||
</table>
|
||||
|
||||
<tmpl_if pagination.pageCount.isMultiple>
|
||||
<div class="pagination">
|
||||
<tmpl_var pagination.previousPage> <tmpl_var pagination.pageList.upTo20> <tmpl_var pagination.nextPage>
|
||||
</div>
|
||||
</tmpl_if>
|
||||
|
||||
16
docs/upgrades/upgrade_7.0.9-7.1.0.pl
Normal file → Executable file
16
docs/upgrades/upgrade_7.0.9-7.1.0.pl
Normal file → Executable file
|
|
@ -20,6 +20,8 @@ my $quiet; # this line required
|
|||
my $session = start(); # this line required
|
||||
|
||||
recalculateProjectCompletion($session);
|
||||
updateSqlReportTable($session);
|
||||
updateProductsTable($session);
|
||||
|
||||
finish($session); # this line required
|
||||
|
||||
|
|
@ -38,6 +40,20 @@ sub recalculateProjectCompletion {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
sub updateSqlReportTable {
|
||||
my $session = shift;
|
||||
print "\tUpdating SQLReport table structure.\n" unless ($quiet);
|
||||
$session->db->write("alter table `SQLReport` ADD COLUMN ( downloadType varchar(255), downloadFilename varchar(255), downloadTemplateId varchar(22), downloadMimeType varchar(255), downloadUserGroup varchar(22))");
|
||||
}
|
||||
|
||||
|
||||
sub updateProductsTable {
|
||||
my $session = shift;
|
||||
print "\tUpdating products table structure.\n" unless ($quiet);
|
||||
$session->db->write("alter table products add column (groupId varchar(22), groupExpiresOffset varchar(16))");
|
||||
}
|
||||
|
||||
# ---- DO NOT EDIT BELOW THIS LINE ----
|
||||
|
||||
#-------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use WebGUI::SQL;
|
|||
use WebGUI::Utility;
|
||||
use WebGUI::Asset::Wobject;
|
||||
use WebGUI::Cache;
|
||||
use WebGUI::Text qw(:csv);
|
||||
|
||||
our @ISA = qw(WebGUI::Asset::Wobject);
|
||||
|
||||
|
|
@ -153,6 +154,30 @@ sub definition {
|
|||
fieldType=>"yesNo",
|
||||
defaultValue=>0
|
||||
},
|
||||
|
||||
# download
|
||||
downloadType=>{
|
||||
fieldType=>"text",
|
||||
defaultValue=>"",
|
||||
},
|
||||
downloadFilename=>{
|
||||
fieldType=>"text",
|
||||
defaultValue=>"",
|
||||
},
|
||||
downloadTemplateId=>{
|
||||
fieldType=>"template",
|
||||
defaultValue=>'SQLReportDownload0001',
|
||||
},
|
||||
downloadMimeType=>{
|
||||
fieldType=>"text",
|
||||
defaultValue=>"text/html",
|
||||
},
|
||||
downloadUserGroup=>{
|
||||
fieldType=>"group",
|
||||
defaultValue=>"text/html",
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
|
|
@ -182,7 +207,79 @@ sub getEditForm {
|
|||
-uiLevel => 8,
|
||||
-value=>$self->getValue("cacheTimeout")
|
||||
);
|
||||
|
||||
|
||||
### Download
|
||||
# Download Type
|
||||
my %downloadTypes;
|
||||
tie %downloadTypes, 'Tie::IxHash',
|
||||
"none" => "No Download",
|
||||
"csv" => "CSV",
|
||||
"template" => "Template",
|
||||
;
|
||||
|
||||
$tabform->getTab("properties")->radioList(
|
||||
-name=>"downloadType", # ID is downloadType_formId
|
||||
-label=>$i18n->get("download type"),
|
||||
-hoverHelp=>$i18n->get("download type description"),
|
||||
-vertical=>1,
|
||||
-options=> \%downloadTypes,
|
||||
-defaultValue=>"none",
|
||||
-value=>$self->getValue("downloadType"),
|
||||
-extras=> "onclick='changeDownloadType(this)'"
|
||||
);
|
||||
|
||||
# Download Filename
|
||||
$tabform->getTab("properties")->text(
|
||||
-name=>"downloadFilename", # ID is downloadFilename_formId
|
||||
-label=>$i18n->get("download filename"),
|
||||
-hoverHelp=>$i18n->get("download filename description"),
|
||||
-value=>$self->getValue("downloadFilename"),
|
||||
);
|
||||
|
||||
# Download template (if necessary)
|
||||
$tabform->getTab("properties")->template(
|
||||
-name=>"downloadTemplateId", # ID is downloadTemplateId_formId
|
||||
-label=>$i18n->get("download template"),
|
||||
-hoverHelp=>$i18n->get("download template description"),
|
||||
-value=>$self->getValue("downloadTemplateId"),
|
||||
-namespace=>"SQLReport/Download",
|
||||
);
|
||||
|
||||
# Download mimeType (if necessary)
|
||||
my %downloadMimeType;
|
||||
tie %downloadMimeType, 'Tie::IxHash',
|
||||
"application/octet-stream" => "application/octet-stream",
|
||||
"application/xml" => "application/xml",
|
||||
"application/csv" => "application/csv",
|
||||
"text/html" => "text/html",
|
||||
"text/plain" => "text/plain",
|
||||
;
|
||||
|
||||
$tabform->getTab("properties")->selectBox(
|
||||
-name=>"downloadMimeType",
|
||||
-label=>$i18n->get("download mimetype"),
|
||||
-hoverHelp=>$i18n->get("download mimetype description"),
|
||||
-options=> \%downloadMimeType,
|
||||
-value=>$self->getValue("downloadMimeType"),
|
||||
-defaultValue=>"application/octet-stream",
|
||||
);
|
||||
|
||||
# Download UserGroup
|
||||
$tabform->getTab("security")->group(
|
||||
-name=>"downloadUserGroup",
|
||||
-label=>$i18n->get("download usergroup"),
|
||||
-hoverHelp=>$i18n->get("download usergroup description"),
|
||||
-value=>$self->getValue("downloadUserGroup"),
|
||||
-defaultValue=>$self->getValue("groupIdView"),
|
||||
);
|
||||
|
||||
# javascript
|
||||
$self->session->style->setScript("/extras/wobject/SQLReport/editFormDownload.js");
|
||||
|
||||
### /DOWNLOAD
|
||||
|
||||
|
||||
# Add toggleQuery javascript
|
||||
$tabform->getTab("properties")->raw(qq|
|
||||
<script type="text/javascript">
|
||||
|
|
@ -274,6 +371,64 @@ sub getEditForm {
|
|||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 download ( )
|
||||
|
||||
Returns the SQLReport in the configured manner. Returns nothing if download is
|
||||
not enabled.
|
||||
|
||||
=cut
|
||||
|
||||
sub download {
|
||||
my $self = shift;
|
||||
|
||||
# Instead of going through some costly exercises...
|
||||
return if ($self->getValue("downloadType") eq "none");
|
||||
|
||||
# Initiate an empty debug loop
|
||||
$self->{_debug_loop} = [] ;
|
||||
|
||||
# Store queries in class
|
||||
$self->_storeQueries();
|
||||
|
||||
# Call _processQuery
|
||||
my $data = $self->_processQuery(0,0);
|
||||
|
||||
|
||||
# If we're downloading CSV
|
||||
if ($self->getValue("downloadType") eq "csv") {
|
||||
my $out = "";
|
||||
|
||||
### Loop through the returned structure and put it through Text::CSV
|
||||
# Column heads
|
||||
$out .= joinCSV(
|
||||
map { $_->{"field.name"} }
|
||||
@{$data->{rows_loop}->[0]->{"row.field_loop"}}
|
||||
);
|
||||
|
||||
|
||||
# Data lines
|
||||
for my $row (@{$data->{rows_loop}}) {
|
||||
$out .= "\n".joinCSV(map { $_->{"field.value"} }
|
||||
@{$row->{"row.field_loop"}}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $out;
|
||||
|
||||
} elsif ($self->getValue("downloadType") eq "template") {
|
||||
return $self->processTemplate($data,$self->get("downloadTemplateId"));
|
||||
|
||||
} else {
|
||||
# I don't know what to do
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 prepareView ( )
|
||||
|
|
@ -324,6 +479,13 @@ sub view {
|
|||
# Add debug loop to template vars
|
||||
$var->{'debug_loop'} = $self->{_debug_loop};
|
||||
#use Data::Dumper; return '<pre>'.Dumper($var).'</pre>';
|
||||
|
||||
# Add the "Download data" link if the user is allowed to download
|
||||
$var->{'canDownload'} = 1
|
||||
if ($self->getValue("downloadType") ne "none"
|
||||
&& $self->session->user->isInGroup($self->getValue("downloadUserGroup"))
|
||||
);
|
||||
|
||||
my $out = $self->processTemplate($var,undef,$self->{_viewTemplate});
|
||||
if (!$self->session->var->isAdminOn && $self->get("cacheTimeout") > 10) {
|
||||
WebGUI::Cache->new($self->session,"view_".$self->getId)->set($out,$self->get("cacheTimeout"));
|
||||
|
|
@ -370,9 +532,20 @@ sub _parsePlaceholderParams {
|
|||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# _processQuery($nest, $page, $nr)
|
||||
# Recursive sub to process this SQLReport's queries.
|
||||
# Arguments: $nest - If true, will run the nested queries. Defaults to true
|
||||
# $page - If true, will paginate. Defaults to true
|
||||
# $nr - This query number. Defaults to one. This is used
|
||||
# internally to tell which query we're performing. You should not
|
||||
# send this yourself.
|
||||
# Returns: A reference to a datastructure containing template variables to
|
||||
# be passed to processTemplate()
|
||||
sub _processQuery {
|
||||
my $self = shift;
|
||||
my $nr = shift || 1;
|
||||
my $self = shift;
|
||||
my $nest = shift || 1;
|
||||
my $page = shift || 1;
|
||||
my $nr = shift || 1;
|
||||
my ($query, %var, $prefix);
|
||||
|
||||
if($nr > 1) {
|
||||
|
|
@ -427,8 +600,16 @@ sub _processQuery {
|
|||
.'='.$self->session->url->escape($self->session->form->process($_)));
|
||||
}
|
||||
}
|
||||
my $paginateAfter = $self->get("paginateAfter");
|
||||
$paginateAfter = 1000 if($self->{_query}{$nr + 1}{dbQuery});
|
||||
my $paginateAfter;
|
||||
if ($page) # Set page length
|
||||
{
|
||||
$paginateAfter = $self->get("paginateAfter");
|
||||
$paginateAfter = 1000 if($self->{_query}{$nr + 1}{dbQuery});
|
||||
}
|
||||
else
|
||||
{
|
||||
$paginateAfter = 1000000;
|
||||
}
|
||||
my $p = WebGUI::Paginator->new($self->session,$url,$paginateAfter);
|
||||
my $error = $p->setDataByQuery($query,$dbh,1,$placeholderParams);
|
||||
if ($error ne "") {
|
||||
|
|
@ -461,8 +642,8 @@ sub _processQuery {
|
|||
$row{$prefix.'row.field.'.$name.'.value'} = $data->{$name};
|
||||
}
|
||||
# Process nested query
|
||||
if($self->{_query}{$nr + 1}{dbQuery}) {
|
||||
my $nest = $self->_processQuery($nr+1);
|
||||
if($nest && $self->{_query}{$nr + 1}{dbQuery}) {
|
||||
my $nest = $self->_processQuery($nest,$page,$nr+1);
|
||||
%row = (%row , %$nest);
|
||||
$row{$prefix.'hasNest'} = $nest->{'query'.($nr+1).'.rows.count'};
|
||||
}
|
||||
|
|
@ -492,6 +673,42 @@ sub _processQuery {
|
|||
return \%var;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_download ( )
|
||||
|
||||
Calls download() to let user download the SQLReport in the configured manner.
|
||||
|
||||
=cut
|
||||
|
||||
sub www_download {
|
||||
my $self = shift;
|
||||
|
||||
# Only allow if download type is not "none"
|
||||
return if $self->getValue("downloadType") eq "none";
|
||||
|
||||
# Only allow users in appropriate group
|
||||
return $self->session->privilege->noAccess()
|
||||
unless $self->session->user->isInGroup($self->getValue("downloadUserGroup"));
|
||||
|
||||
# Set filename and mimetype
|
||||
if ($self->getValue("downloadType") eq "csv")
|
||||
{
|
||||
$self->session->http->setFilename($self->getValue("downloadFilename"),"application/octet-stream");
|
||||
}
|
||||
else
|
||||
{
|
||||
$self->session->http->setFilename($self->getValue("downloadFilename"),$self->getValue("downloadMimeType"));
|
||||
}
|
||||
|
||||
$self->session->http->sendHeader;
|
||||
|
||||
|
||||
return $self->download;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 www_view ( )
|
||||
|
|
|
|||
|
|
@ -43,8 +43,36 @@ sub description {
|
|||
#
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#sub handler {
|
||||
#}
|
||||
sub handler {
|
||||
my $self = shift;
|
||||
|
||||
### Add to group action
|
||||
# If group is 'everyone', skip
|
||||
unless ($self->{_product}->get('groupId') eq '7') {
|
||||
my $g = WebGUI::Group->new($self->session,$self->{_product}->get('groupId'));
|
||||
my $expiresOffset;
|
||||
|
||||
# Parse the value
|
||||
if ($self->{_product}->get('groupExpiresOffset') =~ /^(\d+)month/i) {
|
||||
$expiresOffset = $1 * 3600*24*30; # One month
|
||||
} elsif ($self->{_product}->get('groupExpiresOffset') =~ /^(\d+)year/i) {
|
||||
$expiresOffset = $1 * 3600*24*365; # One year
|
||||
}
|
||||
|
||||
# Multiply by how many quantity we're purchasing
|
||||
#!!! TODO !!! - handlers don't know how many we're purchasing
|
||||
|
||||
# If user has time left
|
||||
my $remains = $g->userGroupExpireDate($self->session->user->userId);
|
||||
if ($remains) {
|
||||
# Add any remaining time to the offset
|
||||
$expiresOffset += $remains - time();
|
||||
}
|
||||
|
||||
# Add user to group
|
||||
$g->addUsers([$self->session->user->userId],$expiresOffset);
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
sub id {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ This package provides an object-oriented way of managing WebGUI groups and group
|
|||
$arrayRef = $group->getAllUsers(); ##All users in all groups in this group
|
||||
$boolean = $self->session->user->isInGroup($groupId);
|
||||
$boolean = $group->userIsAdmin($userId,$groupId);
|
||||
$epoch = $group->userGroupExpireDate($userId,$groupId);
|
||||
$epoch = $group->userGroupExpireDate($userId,$date);
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ sub www_checkoutSubmit {
|
|||
|
||||
foreach (@{$currentPurchase->{items}}) {
|
||||
my $priceLineItem = ($_->{item}->{priceLineItem}) ? ($_->{item}->priceLineItem($_->{quantity},\@copyOfNormal)) : undef; # pass in the quantity and the normal items in the cart.
|
||||
$session->errorHandler->warn("Price Line Item: $priceLineItem");
|
||||
#$session->errorHandler->warn("Price Line Item: $priceLineItem");
|
||||
$transaction->addItem($_->{item}, $_->{quantity},$priceLineItem);
|
||||
# use the item plugin's lineItem method for price override
|
||||
# situations.
|
||||
|
|
|
|||
|
|
@ -151,66 +151,97 @@ sub www_editProduct {
|
|||
$product = WebGUI::Product->new($session,$productId)->get;
|
||||
}
|
||||
|
||||
$f = WebGUI::HTMLForm->new($session);
|
||||
$f = WebGUI::TabForm->new($session);
|
||||
$f->addTab("properties","Properties");
|
||||
$f->addTab("actions","Actions");
|
||||
|
||||
$f->submit;
|
||||
$f->hidden(
|
||||
-name => 'op',
|
||||
-value => 'editProductSave'
|
||||
);
|
||||
$f->hidden(
|
||||
-name => 'productId',
|
||||
-value => $productId
|
||||
);
|
||||
$f->text(
|
||||
$f->hidden({
|
||||
name => 'op',
|
||||
value => 'editProductSave'
|
||||
});
|
||||
$f->hidden({
|
||||
name => 'productId',
|
||||
value => $productId
|
||||
});
|
||||
|
||||
$f->getTab("properties")->text(
|
||||
-name => 'title',
|
||||
-label => $i18n->get('title'),
|
||||
-hoverHelp => $i18n->get('title description'),
|
||||
-value => $session->form->process("title") || $product->{title},
|
||||
-maxlength => 255,
|
||||
);
|
||||
$f->textarea(
|
||||
$f->getTab("properties")->textarea(
|
||||
-name => 'description',
|
||||
-label => $i18n->get('description'),
|
||||
-hoverHelp => $i18n->get('description description'),
|
||||
-value => $session->form->process("decsription") || $product->{description},
|
||||
);
|
||||
$f->float(
|
||||
$f->getTab("properties")->float(
|
||||
-name => 'price',
|
||||
-label => $i18n->get('price'),
|
||||
-hoverHelp => $i18n->get('price description'),
|
||||
-value => $session->form->process("price") || $product->{price},
|
||||
-maxlength => 13,
|
||||
);
|
||||
$f->float(
|
||||
$f->getTab("properties")->float(
|
||||
-name => 'weight',
|
||||
-label => $i18n->get('weight'),
|
||||
-hoverHelp => $i18n->get('weight description'),
|
||||
-value => $session->form->process("weight") || $product->{weight},
|
||||
-maxlength => 9,
|
||||
);
|
||||
$f->text(
|
||||
$f->getTab("properties")->text(
|
||||
-name => 'sku',
|
||||
-label => $i18n->get('sku'),
|
||||
-hoverHelp => $i18n->get('sku description'),
|
||||
-value => $session->form->process("sku") || $product->{sku},
|
||||
-maxlength => 64,
|
||||
);
|
||||
$f->template(
|
||||
$f->getTab("properties")->template(
|
||||
-name => 'templateId',
|
||||
-label => $i18n->get('template'),
|
||||
-hoverHelp => $i18n->get('template description'),
|
||||
-value => $session->form->process("templateId") || $product->{templateId},
|
||||
-namespace => 'Commerce/Product',
|
||||
);
|
||||
$f->text(
|
||||
$f->getTab("properties")->text(
|
||||
-name => 'skuTemplate',
|
||||
-label => $i18n->get('sku template'),
|
||||
-hoverHelp => $i18n->get('sku template description'),
|
||||
-value => $session->form->process("skuTemplate") || $product->{skuTemplate},
|
||||
-maxlength => 255,
|
||||
);
|
||||
$f->submit;
|
||||
|
||||
|
||||
$f->getTab("actions")->group(
|
||||
-name => 'groupId',
|
||||
-label => $i18n->get('group id'),
|
||||
-hoverHelp => $i18n->get('group id description'),
|
||||
-value => $session->form->process("groupId") || $product->{groupId},
|
||||
);
|
||||
|
||||
my %groupExpiresOffsetOptions;
|
||||
tie %groupExpiresOffsetOptions, 'Tie::IxHash',
|
||||
'1month' => $i18n->get("1 month"),
|
||||
'6month' => $i18n->get("6 months"),
|
||||
'1year' => $i18n->get("1 year"),
|
||||
'2year' => $i18n->get("2 years"),
|
||||
'3year' => $i18n->get("3 years"),
|
||||
'5year' => $i18n->get("5 years"),
|
||||
'10year' => $i18n->get("10 years"),
|
||||
'1000year' => $i18n->get("lifetime"),
|
||||
;
|
||||
|
||||
$f->getTab("actions")->selectBox(
|
||||
-name => 'groupExpiresOffset',
|
||||
-label => $i18n->get('group expires offset'),
|
||||
-hoverHelp => $i18n->get('group expires offset description'),
|
||||
-value => $session->form->process("groupExpiresOffset") || $product->{groupExpiresOffset},
|
||||
-options => \%groupExpiresOffsetOptions,
|
||||
-defaultValue => '1000year',
|
||||
);
|
||||
|
||||
return _submenu($session,$f->print, 'edit product', 'edit product', 'ProductManager');
|
||||
}
|
||||
|
||||
|
|
@ -251,6 +282,10 @@ sub www_editProductSave {
|
|||
sku => $session->form->process("sku"),
|
||||
templateId => $session->form->process("templateId"),
|
||||
skuTemplate => $session->form->process("skuTemplate"),
|
||||
|
||||
groupId => $session->form->process('groupId'),
|
||||
groupExpiresOffset => $session->form->process('groupExpiresOffset'),
|
||||
|
||||
});
|
||||
|
||||
return www_manageProduct($session, $product->get('productId'));
|
||||
|
|
|
|||
148
lib/WebGUI/Text.pm
Normal file
148
lib/WebGUI/Text.pm
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package WebGUI::Text;
|
||||
|
||||
=head1 LEGAL
|
||||
|
||||
-------------------------------------------------------------------
|
||||
WebGUI is Copyright 2001-2006 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 warnings;
|
||||
|
||||
use base 'Exporter';
|
||||
|
||||
our @EXPORT_OK = qw(
|
||||
joinCSV splitCSV
|
||||
|
||||
);
|
||||
|
||||
our %EXPORT_TAGS = (
|
||||
"csv" => [qw( joinCSV splitCSV )],
|
||||
|
||||
);
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
WebGUI::Text - Routines for manipulating text.
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use WebGUI::Text qw(:csv);
|
||||
my $string = joinCSV(@array);
|
||||
my @array = splitCSV($string);
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Some convenience routines that can be exported to work with text data.
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 joinCSV ( @array )
|
||||
|
||||
Join an array of data together to create a properly formatted and escaped CSV
|
||||
string according to the de-facto standard outlined by RFC 4180.
|
||||
|
||||
=cut
|
||||
|
||||
sub joinCSV {
|
||||
my @input = @_;
|
||||
my @fixed; # The properly escaped data
|
||||
for my $i (@input) {
|
||||
# Ignore all characters that aren't ASCII printable characters
|
||||
$i =~ s/[^\x09\x20-\x7e]//g;
|
||||
|
||||
# All strings with these chars in them must be quoted
|
||||
if ($i =~ /[",\n\t]/ || $i =~ /^\s|\s$/s) {
|
||||
# " must be doubled ("")
|
||||
$i =~ s/"/""/g;
|
||||
|
||||
$i = qq{"$i"};
|
||||
}
|
||||
|
||||
push @fixed, $i;
|
||||
}
|
||||
|
||||
return join ",",@fixed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 splitCSV ( $string )
|
||||
|
||||
Splits a CSV string and fixes any escaping done.
|
||||
|
||||
=cut
|
||||
|
||||
sub splitCSV {
|
||||
my $s = shift;
|
||||
|
||||
# Split on ,
|
||||
my @array = split /,/, $s;
|
||||
|
||||
for (my $i = 0; $i < @array; $i++) {
|
||||
# Fix quoted strings being used to escape commas.
|
||||
# If it begins with a " but doesn't end with an odd number of "
|
||||
# shift, add to previous, and try again
|
||||
if ($array[$i] =~ /^"/s && length(($array[$i] =~ m/("*)$/s)[0]) % 2 == 0 ) {
|
||||
# If there are no more elements, this line is erroneous
|
||||
if ($i+1 > @array) { warn "Error parsing CSV line."; return; }
|
||||
$array[$i] .= ",".splice(@array,$i+1,1);
|
||||
redo;
|
||||
}
|
||||
|
||||
# Remove quotes on end of string
|
||||
$array[$i] =~ s/^"|"$//sg;
|
||||
|
||||
# Fix doubled quotes
|
||||
$array[$i] =~ s/""/"/g;
|
||||
}
|
||||
|
||||
return @array;
|
||||
}
|
||||
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
splitCSV doesn't properly handle quoted fields with no text inside (...,"",...)
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
RFC 4180 (http://tools.ietf.org/html/rfc4180)
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
|
|
@ -319,6 +319,59 @@ query, but will be prefixed with queryN where N goes from 2 to 5.</p>
|
|||
<p>The prequery statements are seperated from each other by returns and cannot use placeholders. You can use macro's within the prequery statements, however. Please note that prequery statements are only visible in the query they belong to and that you can only use statements that are allowed by the database link.</p>|,
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
|
||||
|
||||
'download type' => {
|
||||
message => 'Download Type',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download type description' => {
|
||||
message => "The type of download to create.",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download filename' => {
|
||||
message => 'Download File Name',
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download filename description' => {
|
||||
message => "The filename of the file to download. If left blank, will autogenerate.",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download template' => {
|
||||
message => "Download Template",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download template description' => {
|
||||
message => "The template to use to generate the download file.",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download mimetype' => {
|
||||
message => "Download Mime-Type",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download mimetype description' => {
|
||||
message => "Mime-Type for the downloaded template.",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download usergroup' => {
|
||||
message => "Download User Group",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
'download usergroup description' => {
|
||||
message => "Group of users allowed to download the report.",
|
||||
lastUpdated => 0,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -567,6 +567,68 @@ the form.<br />|,
|
|||
message => q|Product Manager|,
|
||||
lastUpdated => 1128919931,
|
||||
},
|
||||
|
||||
|
||||
'group id' => {
|
||||
message => "Add to Group",
|
||||
lastUpdated => 0,
|
||||
context => "Label for add to group action",
|
||||
},
|
||||
|
||||
'group id description' => {
|
||||
message => "Add purchasers of this product to this group. Set to 'everyone' to disable.",
|
||||
lastUpdated => 0,
|
||||
context => "Hover help for add to group action",
|
||||
},
|
||||
|
||||
'group expires offset' => {
|
||||
message => "Group Expires Offset",
|
||||
lastUpdated => 0,
|
||||
context => "Label for group expires offset",
|
||||
},
|
||||
|
||||
'group expires offset description' => {
|
||||
message => "Length of time added to user's expiration from the above group each time this product is purchased.",
|
||||
lastUpdated => 0,
|
||||
context => "Hover help for group expires offset",
|
||||
},
|
||||
|
||||
|
||||
'6 months' => {
|
||||
message => "6 months",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
'1 year' => {
|
||||
message => "1 year",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
'2 years' => {
|
||||
message => "2 years",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
'3 years' => {
|
||||
message => "3 years",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
'5 years' => {
|
||||
message => "5 years",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
'10 years' => {
|
||||
message => "10 years",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
'lifetime' => {
|
||||
message => "lifetime",
|
||||
lastUpdated => 0,
|
||||
context => "A time period for group expires offset",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
64
www/extras/wobject/SQLReport/editFormDownload.js
Executable file
64
www/extras/wobject/SQLReport/editFormDownload.js
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
/* changeDownloadType(Element type)
|
||||
* Disables/Enables/Hides/Shows the
|
||||
* downloadFilename
|
||||
* downloadTemplateId
|
||||
* downloadMimeType
|
||||
* form elements whenever the downloadType element is
|
||||
* changed.
|
||||
*/
|
||||
function changeDownloadType(type) {
|
||||
file = document.getElementById("downloadFilename_formId");
|
||||
while (file.nodeName.toLowerCase() != "tr")
|
||||
file = file.parentNode;
|
||||
template = document.getElementById("downloadTemplateId_formId").parentNode;
|
||||
while (template.nodeName.toLowerCase() != "tr")
|
||||
template = template.parentNode;
|
||||
mimeType = document.getElementById("downloadMimeType_formId").parentNode;
|
||||
while (mimeType.nodeName.toLowerCase() != "tr")
|
||||
mimeType = mimeType.parentNode;
|
||||
|
||||
if (type.value == "none") {
|
||||
file.style.display = "none";
|
||||
template.style.display = "none";
|
||||
mimeType.style.display = "none";
|
||||
} else if (type.value == "template") {
|
||||
file.style.display = "";
|
||||
template.style.display = "";
|
||||
mimeType.style.display = "";
|
||||
} else {
|
||||
file.style.display = "";
|
||||
template.style.display = "none";
|
||||
mimeType.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Add a window.onload event to handle hiding the inappropriate form values
|
||||
|
||||
// addLoadEvent(function)
|
||||
// Adds an event to window.onload without overriding events already there.
|
||||
// Taken from http://simon.incutio.com/archive/2004/05/26/addLoadEvent
|
||||
function addLoadEvent(func) {
|
||||
var oldonload = window.onload;
|
||||
if (typeof window.onload != 'function') {
|
||||
window.onload = func;
|
||||
} else {
|
||||
window.onload = function() {
|
||||
if (oldonload) {
|
||||
oldonload();
|
||||
}
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
// Find out which radio button is checked by default
|
||||
for (i=0;i<document.forms[0].downloadType.length;i++) {
|
||||
if (document.forms[0].downloadType[i].checked) {
|
||||
changeDownloadType(document.forms[0].downloadType[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue