[freeside-commits] branch FREESIDE_3_BRANCH updated. f25c596ba479c7c5cebcfd4447bb0db9c70a1e06

Mark Wells mark at 420.am
Tue Dec 30 16:05:04 PST 2014


The branch, FREESIDE_3_BRANCH has been updated
       via  f25c596ba479c7c5cebcfd4447bb0db9c70a1e06 (commit)
       via  de5fa0a86c7ea64d699c68d3e39219b63e4614f8 (commit)
      from  3c89032f8902e137e70528c5e8c3b24c4c40f238 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f25c596ba479c7c5cebcfd4447bb0db9c70a1e06
Author: Mark Wells <mark at freeside.biz>
Date:   Tue Dec 30 16:02:14 2014 -0800

    import deployment zone census block list, #32625

diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm
index 4623766..f2236b0 100644
--- a/FS/FS/Record.pm
+++ b/FS/FS/Record.pm
@@ -1584,7 +1584,7 @@ Table name (required).
 
 =item params
 
-Listref of field names for static fields.  They will be given values from the
+Arrayref of field names for static fields.  They will be given values from the
 PARAMS hashref and passed as a "params" hashref to batch_import.
 
 =item formats
@@ -1633,13 +1633,15 @@ format_types).
 
 =back
 
-PARAMS is a base64-encoded Storable string containing the POSTed data as
-a hash ref.  It normally contains at least one field, "uploaded files",
-generated by /elements/file-upload.html and containing the list of uploaded
-files.  Currently only supports a single file named "file".
+PARAMS is a hashref (or base64-encoded Storable hashref) containing the 
+POSTed data.  It must contain the field "uploaded files", generated by 
+/elements/file-upload.html and containing the list of uploaded files.
+Currently only supports a single file named "file".
 
 =cut
 
+# uploaded_files is kind of bizarre; fix that some time
+
 use Storable qw(thaw);
 use Data::Dumper;
 use MIME::Base64;
@@ -1650,7 +1652,13 @@ sub process_batch_import {
   my @pass_params = $opt->{params} ? @{ $opt->{params} } : ();
   my %formats = %{ $opt->{formats} };
 
-  my $param = thaw(decode_base64(shift));
+  my $param = shift;
+  # because some job-spawning code (JSRPC) pre-freezes the arguments,
+  # and then the 'frozen' attribute doesn't get set, and thus $job->args 
+  # doesn't know to thaw them, we have to do this everywhere.
+  if (!ref $param) {
+    $param = thaw(decode_base64($param));
+  }
   warn Dumper($param) if $DEBUG;
   
   my $files = $param->{'uploaded_files'}
diff --git a/FS/FS/deploy_zone.pm b/FS/FS/deploy_zone.pm
index 6142b91..38dd7dc 100644
--- a/FS/FS/deploy_zone.pm
+++ b/FS/FS/deploy_zone.pm
@@ -3,6 +3,8 @@ package FS::deploy_zone;
 use strict;
 use base qw( FS::o2m_Common FS::Record );
 use FS::Record qw( qsearch qsearchs dbh );
+use Storable qw(thaw);
+use MIME::Base64;
 
 =head1 NAME
 
@@ -265,6 +267,55 @@ sub deploy_zone_vertex {
   });
 }
 
+=back
+
+=head2 SUBROUTINES
+
+=over 4
+
+=item process_batch_import JOB, PARAMS
+
+=cut
+
+sub process_batch_import {
+  eval {
+    use FS::deploy_zone_block;
+    use FS::deploy_zone_vertex;
+  };
+  my $job = shift;
+  my $param = shift;
+  if (!ref($param)) {
+    $param = thaw(decode_base64($param));
+  }
+
+  # even if creating a new zone, the deploy_zone object should already
+  # be inserted by this point
+  my $zonenum = $param->{zonenum}
+    or die "zonenum required";
+  my $zone = FS::deploy_zone->by_key($zonenum)
+    or die "deploy_zone #$zonenum not found";
+  my $opt;
+  if ( $zone->zonetype eq 'B' ) {
+    $opt = { 'table'    => 'deploy_zone_block',
+             'params'   => [ 'zonenum', 'censusyear' ],
+             'formats'  => { 'plain' => [ 'censusblock' ] },
+             'default_csv' => 1,
+           };
+    $job->update_statustext('1,Inserting census blocks');
+  } elsif ( $zone->zonetype eq 'P' ) {
+    $opt = { 'table'    => 'deploy_zone_vertex',
+             'params'   => [ 'zonenum' ],
+             'formats'  => { 'plain' => [ 'latitude', 'longitude' ] },
+             'default_csv' => 1,
+           };
+  } else {
+    die "don't know how to import to zonetype ".$zone->zonetype;
+  }
+
+  FS::Record::process_batch_import( $job, $opt, $param );
+
+}
+        
 =head1 BUGS
 
 =head1 SEE ALSO
diff --git a/httemplate/edit/deploy_zone-fixed.html b/httemplate/edit/deploy_zone-fixed.html
index fb26c49..90d1b66 100644
--- a/httemplate/edit/deploy_zone-fixed.html
+++ b/httemplate/edit/deploy_zone-fixed.html
@@ -16,6 +16,8 @@
         'is_business'     => 'Business/government',
         'blocknum'        => '',
         'active_date'     => 'Active since',
+        'file'            => 'Import blocks from text file',
+        'censusyear'      => 'as census year',
     },
     'fields'        => [
         { field         => 'zonetype',
@@ -54,6 +56,19 @@
         'cir_speed_up',
 
         { type => 'tablebreak-tr-title', value => 'Census blocks'},
+        { field => 'file',
+          type  => 'file-upload',
+        },
+        { field => 'format',
+          type  => 'hidden',
+          value => 'plain',
+        },
+        { field => 'censusyear',
+          type  => 'select',
+          options => [ '', qw( 2013 2012 2011 ) ],
+        },
+
+        { type => 'tablebreak-tr-title', value => '', },
         { field => 'blocknum',
           type              => 'deploy_zone_block',
           o2m_table         => 'deploy_zone_block',
diff --git a/httemplate/edit/process/deploy_zone-fixed.html b/httemplate/edit/process/deploy_zone-fixed.html
index c14c81c..eae3a74 100644
--- a/httemplate/edit/process/deploy_zone-fixed.html
+++ b/httemplate/edit/process/deploy_zone-fixed.html
@@ -1,9 +1,14 @@
 <& elements/process.html, 
-    error_redirect => popurl(2).'deploy_zone-fixed.html?',
+    debug => 1,
+    error_redirect => popurl(2).'deploy_zone-fixed.html',
     table       => 'deploy_zone',
     viewall_dir => 'browse',
-    process_o2m => 
-      { 'table'  => 'deploy_zone_block',
-                     'fields' => [qw( censusblock censusyear )]
-      },
+    process_o2m => {
+      'table'  => 'deploy_zone_block',
+      'fields' => [qw( censusblock censusyear )]
+    },
+    process_upload => {
+      'process' => 'misc/process/deploy_zone-import.html',
+      'fields' => [qw( censusyear format )],
+    },
 &>
diff --git a/httemplate/edit/process/deploy_zone-mobile.html b/httemplate/edit/process/deploy_zone-mobile.html
index c913c5c..7b8f911 100644
--- a/httemplate/edit/process/deploy_zone-mobile.html
+++ b/httemplate/edit/process/deploy_zone-mobile.html
@@ -1,5 +1,5 @@
 <& elements/process.html, 
-    error_redirect => popurl(2).'deploy_zone-mobile.html?',
+    error_redirect => popurl(2).'deploy_zone-mobile.html',
     table       => 'deploy_zone',
     viewall_dir => 'browse',
     process_o2m => 
diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html
index fb1ee7a..698540b 100644
--- a/httemplate/edit/process/elements/process.html
+++ b/httemplate/edit/process/elements/process.html
@@ -62,6 +62,13 @@ Example:
                       'fields' => [qw( fieldname fieldname2 )],
                     },
 
+   'process_upload' => {
+                         'process'  => 'misc/mytable-import.html',
+                          # fields to pass to the back end job, besides the 
+                          # primary key of the object
+                         'fields'   => [qw( fieldname fieldname2 )],
+                       },
+
    'skip_process' => 0, #boolean, if set true, will skip the main table
                         #add/edit processing and only run any linked table
                         #process_ items
@@ -91,9 +98,6 @@ Example:
 </%doc>
 %if ( $error ) {
 %
-%  my $edit_ext = $opt{'edit_ext'} || 'html';
-%  my $url = $opt{'error_redirect'} || popurl(2)."$table.$edit_ext";
-
 %  #my $query = $m->scomp('/elements/create_uri_query');
 %  #$cgi->redirect("$url?$query");
 %  if ( length($cgi->query_string) > 1920 ) { #stupid IE 2083 URL limit
@@ -111,16 +115,48 @@ Example:
 %          " attempting to set redirect$session to ". $cgi->query_string."\n";
 %    }
 %
-<% $cgi->redirect("$url?redirect=$session") %>
+<% $cgi->redirect("$error_redirect?redirect=$session") %>
 %
 %  } else {
 %
-<% $cgi->redirect("$url?". $cgi->query_string ) %>
+<% $cgi->redirect("$error_redirect?". $cgi->query_string ) %>
 %
-%  } 
+%  }
 %
 % #different ways of handling success
 %
+%} elsif ( $opt{'process_upload'} and @uploaded_files ) {
+%
+% # construct a form to pass all the requested fields, the 
+%
+<& /elements/header.html &>
+<form name="UploadForm">
+%   my $job_fields = $opt{'process_upload'}{'fields'};
+%   foreach my $field ( @$job_fields ) {
+  <input type="hidden" name="<% $field %>" value="<% $cgi->param($field) |h %>">
+%   }
+%   push @$job_fields, 'uploaded_files', $pkey;
+%
+  <input type="hidden" name="uploaded_files" value="<% join(',', @uploaded_files) %>">
+  <input type="hidden" name="<% $pkey %>" value="<% $new->get($pkey) %>">
+<& /elements/progress-init.html,
+  'UploadForm',
+  $job_fields,
+  $fsurl . $opt{'process_upload'}{'process'},
+  {
+    url => $redirect,
+    error_url => "$error_redirect?$new_pkey"
+  },
+&>
+<input type="submit" style="display:none">
+</form>
+<script>
+<&| /elements/onload.js &>
+process();
+</&>
+</script>
+<& /elements/footer.html &>
+
 %} elsif ( $opt{'popup_reload'} ) {
 
   <% include('/elements/header-popup.html', $opt{'popup_reload'} ) %>
@@ -133,26 +169,8 @@ Example:
   </HTML>
 
 %} else {
-%  
-%  $opt{'redirect'} = &{$opt{'redirect'}}($cgi, $new)
-%    if ref($opt{'redirect'}) eq 'CODE';
-%
-%  if ( $opt{'redirect'} ) {
-%
-<% $cgi->redirect( $opt{'redirect'}. $new_pkey) %>
-%
-%  } else { 
-%
-%    my $ext = $opt{'viewall_ext'} || 'html';
-%    my $viewall_dir = $opt{'viewall_dir'} || 'search';
-%    my $viewall_url = $opt{'viewall_url'} || ($viewall_dir . "/$table.$ext");
-%
-%#<% $cgi->redirect( popurl(3). ($opt{viewall_dir}||'search'). "/$table.$ext" ) %>
-<% $cgi->redirect( popurl(3) . $viewall_url ) %>
-%  }
-%
+<% $cgi->redirect($redirect) %>
 %}
-%
 <%init>
 
 my $me = 'process.html:';
@@ -204,6 +222,8 @@ if ( $bfield ) {
   warn join(',', @values);
 }
 
+my @uploaded_files;
+
 my $new;
 my $new_pkey = '';
 foreach my $value ( @values ) {
@@ -338,6 +358,47 @@ foreach my $value ( @values ) {
   }
 
 
+  if ( !$error and $opt{'process_upload'} ) {
+    # mostly duplicates misc/file-upload.html
+    $cgi->param('upload_fields') =~ /^([,\w]+)$/
+      or $error = "invalid upload_fields";
+    my $fields = $1;
+
+    my $dir = $FS::UID::cache_dir. "/cache.". $FS::UID::datasrc;
+
+    foreach my $field (split /,/, $fields) {
+      next if $error;
+      my $source_name = $cgi->param($field);
+
+      if ( $opt{'debug'} ) {
+        warn "$me processing upload: $source_name\n";
+      }
+      my $fh = $cgi->upload( $field ); # if no file provided, that's fine
+      next if !$fh;
+
+      my $suffix = '';
+      if ( $source_name =~ /(\.\w+)$/ ) {
+        $suffix = lc($1);
+      }
+
+      my $sh = File::Temp->new( TEMPLATE => 'upload.XXXXXXXX',
+                                SUFFIX   => $suffix,
+                                DIR      => $dir,
+                                UNLINK   => 0,
+                              )
+        or $error ||= "can't open temporary file to store upload: $!\n";
+      next if $error;
+      while(<$fh>) {
+        print $sh $_;
+      }
+      $sh->filename =~ m!.*/([.\w]+)$!;
+      push @uploaded_files, "$field:$1";
+      if ( $opt{'debug'} ) {
+        warn "uploaded as $1\n";
+      }
+    }
+  }
+
   if ( $error ) {
 
     $cgi->param('error', $error);
@@ -358,4 +419,30 @@ foreach my $value ( @values ) {
   last if $error;
 
 }
+
+# set up redirect URLs
+
+my $redirect;
+if ( !$error ) {
+  $opt{'redirect'} = &{$opt{'redirect'}}($cgi, $new)
+    if ref($opt{'redirect'}) eq 'CODE';
+
+  if ( $opt{'redirect'} ) {
+
+    $redirect = $opt{'redirect'} . $new_pkey;
+
+  } else { 
+
+    my $ext = $opt{'viewall_ext'} || 'html';
+    my $viewall_dir = $opt{'viewall_dir'} || 'search';
+    my $viewall_url = $opt{'viewall_url'} || ($viewall_dir . "/$table.$ext");
+
+    $redirect = popurl(3) . $viewall_url;
+  
+  }
+}
+
+my $edit_ext = $opt{'edit_ext'} || 'html';
+my $error_redirect = $opt{'error_redirect'}
+                     || popurl(2)."$table.$edit_ext";
 </%init>
diff --git a/httemplate/elements/file-upload.html b/httemplate/elements/file-upload.html
index 034eaec..f69df34 100644
--- a/httemplate/elements/file-upload.html
+++ b/httemplate/elements/file-upload.html
@@ -47,6 +47,11 @@
     }
   }
 
+<&| onload.js &>
+// force the form to submit as multipart
+var thisform = document.getElementById('uploaded_files').form;
+thisform.enctype = 'multipart/form-data';
+</&>
 </SCRIPT>
 
 <INPUT TYPE="hidden" NAME="uploaded_files" ID="uploaded_files" VALUE="" />
diff --git a/httemplate/elements/progress-init.html b/httemplate/elements/progress-init.html
index cef54b8..5b42aa1 100644
--- a/httemplate/elements/progress-init.html
+++ b/httemplate/elements/progress-init.html
@@ -17,6 +17,9 @@ In misc/something.html:
          # redirecting to the URL.
          #or { popup_url => $p.'popup_contents.html' }
          # which loads that URL into the popup after completion
+         #or { url => $p.'where_to_go.html',
+               error_url => $p.'where_we_just_were.html' }
+         # to redirect somewhere different on error
          ) %>
   </FORM>
   <SCRIPT TYPE="text/javascript>process();</SCRIPT>
@@ -45,6 +48,33 @@ sub process_whatever { #class method
   return 'this value will be ignored';
 }
 
+Internal notes:
+
+This component creates two JS functions: process(), which starts the 
+submission process, and start_job(), which starts the job on the 
+server side.
+
+process() does the following:
+- disable the form submit button
+- for all form fields named in "fields", collect their values into an array
+- declare a callback function "myCallback"
+- pass the array and callback to start_job()
+
+start_job() is an xmlhttp standard function that turns the array of values 
+into a JSON string, posts it to the location given in $action, receives a 
+job number back, and then invokes the callback with the job number as an 
+argument. Normally, the post target script will use FS::UI::Web::JSRPC to insert
+a queue job (with the form field values as arguments), and return its
+job number.
+
+myCallback() opens an Overlib popup containing progress-popup.html, with 
+the job number, form name, and destination options (url, message, popup_url,
+error_url) as URL parameters. This popup will poll the server for the status
+of the job, display a progress bar, and on completion, either redirect to 
+'url' or 'popup_url', display 'message' in the popup window, or (on failure)
+display the job statustext as an error message. If 'error_url' is specified,
+the "Close" button in the popup will then redirect the user to that location.
+
 </%doc>
 <% include('/elements/xmlhttp.html',
               'method' => 'POST',
@@ -108,7 +138,9 @@ function <%$key%>process () {
 
 function <%$key%>myCallback( jobnum ) {
 
-  overlib( OLiframeContent('<%$fsurl%>elements/progress-popup.html?jobnum=' + jobnum + ';<%$url_or_message_link%>;formname=<%$formname%>' , 444, 168, '<% $popup_name %>'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
+  var url = <% $progress_url->as_string |js_string %>;
+  url = url.replace('_JOBNUM_', jobnum);
+  overlib( OLiframeContent(url, 444, 168, '<% $popup_name %>'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
 
 }
 
@@ -119,18 +151,23 @@ function <%$key%>myCallback( jobnum ) {
 my( $formname, $fields, $action, $url_or_message, $key ) = @_;
 $key = '' unless defined $key;
 
-my $url_or_message_link;
+my %dest_info;
 if ( ref($url_or_message) ) { #its a message or something
-  $url_or_message_link = 'message='. uri_escape( $url_or_message->{'message'} );
-  $url_or_message_link .= ';url='.   uri_escape( $url_or_message->{'url'} )
-    if $url_or_message->{'url'};
-  $url_or_message_link = 'popup_url=' .uri_escape( $url_or_message->{'popup_url'} )
-    if $url_or_message->{'popup_url'};
-
+  %dest_info = map { $_ => $url_or_message->{$_} }
+               grep { $url_or_message->{$_} }
+               qw( message url popup_url error_url );
 } else {
-  $url_or_message_link = "url=$url_or_message";
+  # it can also just be a url
+  %dest_info = ( 'url' => $url_or_message );
 }
 
+my $progress_url = URI->new($fsurl.'elements/progress-popup.html');
+$progress_url->query_form(
+  'jobnum'    => '_JOBNUM_',
+  'formname'  => $formname,
+  %dest_info,
+);
+
 #stupid safari is caching the "location" of popup iframs, and submitting them
 #instead of displaying them.  this should prevent that.
 my $popup_name = 'popup-'.time. "-$$-". rand() * 2**32;
diff --git a/httemplate/elements/progress-popup.html b/httemplate/elements/progress-popup.html
index 2d27388..a37cf24 100644
--- a/httemplate/elements/progress-popup.html
+++ b/httemplate/elements/progress-popup.html
@@ -4,6 +4,7 @@
 %  my $message = $cgi->param('message');
 %  my $popup_url = $cgi->param('popup_url');
 %  my $formname = scalar($cgi->param('formname'));
+%  my $error_url = $cgi->param('error_url');
 %
 
 <HTML>
@@ -62,7 +63,7 @@ function updateStatus( status_statustext ) {
         }
 %   }
 
-% } elsif ( $url ) { 
+% } elsif ( $url ) {
     parent.nd(1);
     window.top.location.href = '<% $url %>';
 % } elsif ( $popup_url ) {
@@ -81,9 +82,16 @@ function updateStatus( status_statustext ) {
     window.top.location.href = statustext.substr(8, statustext.length-18);
 
   } else if ( status.indexOf('error') > -1 ) {
+%
+% # default behavior: just close the popup
+% my $onClick = 'parent.nd(1);';
+% if ( $error_url ) { # then on clicking to confirm, redirect somewhere
+%   $onClick = "window.top.location.href = \\'$error_url\\';";
+% }
+
     document.getElementById("progress_message").innerHTML = '<FONT SIZE="+1" COLOR="#FF0000">Error: ' + statustext + '</FONT>';
     document.getElementById("progress_bar").innerHTML = '';
-    document.getElementById("progress_percent").innerHTML = '<INPUT TYPE="button" VALUE="OK" onClick="parent.nd(1);">';
+    document.getElementById("progress_percent").innerHTML = '<INPUT TYPE="button" VALUE="OK" onClick="<% $onClick %>">';
     document.getElementById("progress_jobnum").innerHTML = '';
     if ( parent.document.<%$formname%>.submit.disabled == true ) {
       parent.document.<%$formname%>.submit.disabled=false;
diff --git a/httemplate/elements/tr-file-upload.html b/httemplate/elements/tr-file-upload.html
new file mode 100644
index 0000000..c50e4cb
--- /dev/null
+++ b/httemplate/elements/tr-file-upload.html
@@ -0,0 +1 @@
+<& file-upload.html, @_ &>
diff --git a/httemplate/misc/process/deploy_zone-import.html b/httemplate/misc/process/deploy_zone-import.html
new file mode 100644
index 0000000..a0f1717
--- /dev/null
+++ b/httemplate/misc/process/deploy_zone-import.html
@@ -0,0 +1,9 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+my $server = new FS::UI::Web::JSRPC 'FS::deploy_zone::process_batch_import', $cgi;
+
+</%init>

commit de5fa0a86c7ea64d699c68d3e39219b63e4614f8
Author: Mark Wells <mark at freeside.biz>
Date:   Mon Dec 29 17:11:18 2014 -0800

    fix misspelling of cache directory, #31834

diff --git a/FS/FS/part_export/voip_ms.pm b/FS/FS/part_export/voip_ms.pm
index 44ce908..53a4926 100644
--- a/FS/FS/part_export/voip_ms.pm
+++ b/FS/FS/part_export/voip_ms.pm
@@ -503,7 +503,7 @@ sub cache {
   my $province = shift;
 
   $CACHE ||= Cache::FileCache->new({
-    'cache_root' => $FS::UID::cache_dir.'/cache'.$FS::UID::datasrc,
+    'cache_root' => $FS::UID::cache_dir.'/cache.'.$FS::UID::datasrc,
     'namespace'  => __PACKAGE__,
     'default_expires_in' => $cache_timeout,
   });

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Record.pm                                    |   20 ++-
 FS/FS/deploy_zone.pm                               |   51 ++++++++
 FS/FS/part_export/voip_ms.pm                       |    2 +-
 httemplate/edit/deploy_zone-fixed.html             |   15 +++
 httemplate/edit/process/deploy_zone-fixed.html     |   15 ++-
 httemplate/edit/process/deploy_zone-mobile.html    |    2 +-
 httemplate/edit/process/elements/process.html      |  137 ++++++++++++++++----
 httemplate/elements/file-upload.html               |    5 +
 httemplate/elements/progress-init.html             |   55 ++++++--
 httemplate/elements/progress-popup.html            |   12 +-
 httemplate/elements/tr-file-upload.html            |    1 +
 ..._device-import.html => deploy_zone-import.html} |    2 +-
 12 files changed, 267 insertions(+), 50 deletions(-)
 create mode 100644 httemplate/elements/tr-file-upload.html
 copy httemplate/misc/process/{part_device-import.html => deploy_zone-import.html} (69%)




More information about the freeside-commits mailing list