[freeside-commits] branch FREESIDE_4_BRANCH updated. 7c47d157c69a164b2c7b745f8738d0ce10426a6d

Jonathan Prykop jonathan at 420.am
Mon Aug 24 17:46:21 PDT 2015


The branch, FREESIDE_4_BRANCH has been updated
       via  7c47d157c69a164b2c7b745f8738d0ce10426a6d (commit)
       via  4ff211f203e8b99b12735de5ffd239f03425ea7f (commit)
      from  64c20943b248398a194699fb0066b44b200b7405 (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 7c47d157c69a164b2c7b745f8738d0ce10426a6d
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Mon Aug 24 19:28:54 2015 -0500

    RT#18361: Delay package from billing until services are provisioned [text change]

diff --git a/httemplate/elements/template_image-dialog.html b/httemplate/elements/template_image-dialog.html
index 5691d52..f7fb0c2 100644
--- a/httemplate/elements/template_image-dialog.html
+++ b/httemplate/elements/template_image-dialog.html
@@ -94,7 +94,7 @@ url - to redirect to after upload, otherwise just refreshes dialog window
 
   <% include( '/elements/tr-select-agent.html',
                  'label'       => "<B>Agent</B>",
-                 'empty_label' => 'Select agent',
+                 'empty_label' => '(global)',
                  'agent_virt'  => 1,
                  'agent_null_right' => 'Edit global templates',
              )

commit 4ff211f203e8b99b12735de5ffd239f03425ea7f
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Mon Aug 17 23:01:31 2015 -0500

    RT#18830: Upload file to message template

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 2ff92eb..a799cee 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -204,6 +204,7 @@ sub dbdef_dist {
            && ( ! /^queue(_arg|_depend|_stat)?$/ || ! $opt->{'queue-no_history'} )
            && ! $tables_hashref_torrus->{$_}
            && ! /^cacti_page$/
+           && ! /^template_image$/
          }
       $dbdef->tables
   ) {
@@ -6350,6 +6351,19 @@ sub tables_hashref {
                         ],
     },
 
+    'template_image' => {
+      'columns' => [
+        'imgnum',     'serial',     '',      '', '', '',
+        'name',      'varchar',     '', $char_d, '', '',
+        'agentnum',      'int', 'NULL',      '', '', '',
+        'mime_type', 'varchar',     '', $char_d, '', '',
+        'base64',       'text',     '',      '', '', '',
+      ],
+      'primary_key'  => 'imgnum',
+      'unique'       => [ ],
+      'index'        => [ ['name'], ['agentnum'] ],
+    },
+
     'cust_msg' => {
       'columns' => [
         'custmsgnum', 'serial',     '',     '', '', '',
diff --git a/FS/FS/template_image.pm b/FS/FS/template_image.pm
new file mode 100644
index 0000000..e7f4bab
--- /dev/null
+++ b/FS/FS/template_image.pm
@@ -0,0 +1,222 @@
+package FS::template_image;
+use base qw( FS::Agent_Mixin FS::Record );
+
+use strict;
+use FS::Record qw( qsearchs );
+use File::Slurp qw( slurp );
+use MIME::Base64 qw( encode_base64 );
+
+my %ext_to_type = (
+  'jpeg' => 'image/jpeg',
+  'jpg'  => 'image/jpeg',
+  'png'  => 'image/png',
+  'gif'  => 'image/gif',
+);
+
+=head1 NAME
+
+FS::template_image - Object methods for template_image records
+
+=head1 SYNOPSIS
+
+  use FS::template_image;
+
+  $record = new FS::template_image {
+              'name'      => 'logo',
+              'agentnum'  => $agentnum,
+              'base64'    => encode_base64($rawdata),
+              'mime_type' => 'image/jpg',
+  };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::template_image object represents an uploaded image for insertion into templates.
+FS::template_image inherits from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item imgnum - primary key
+
+=item name - unique name, for selecting/editing images
+
+=item agentnum - image agent
+
+=item mime-type - image mime-type
+
+=item base64 - base64-encoded raw contents of image file
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new object.  To add the object to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'template_image'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid example.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('imgnum','agentnum')
+    || $self->ut_text('name','mime-type')
+    || $self->ut_anything('base64')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item src
+
+Returns a data url for this image, incorporating mime_type & base64
+
+=cut
+
+sub src {
+  my $self = shift;
+  'data:'
+  . $self->mime_type
+  . ';base64,'
+  . $self->base64;
+}
+
+=item html
+
+Returns html for a basic img tag for this image (no attributes)
+
+=cut
+
+sub html {
+  my $self = shift;
+  '<IMG SRC="'
+  . $self->src
+  . '">';
+}
+
+=item process_image_delete
+
+Process for deleting an image.  Run as a job using L<FS::queue>.
+
+=cut
+
+sub process_image_delete {
+  my $job = shift;
+  my $param = shift;
+  my $template_image = qsearchs('template_image',{ 'imgnum' => $param->{'imgnum'} })
+    or die "Could not load template_image";
+  my $error = $template_image->delete;
+  die $error if $error;
+  '';
+}
+
+=item process_image_upload
+
+Process for uploading an image.  Run as a job using L<FS::queue>.
+
+=cut
+
+sub process_image_upload {
+  my $job = shift;
+  my $param = shift;
+
+  my $files = $param->{'uploaded_files'}
+    or die "No files provided.\n";
+
+  my (%files) = map { /^(\w+):([\.\w]+)$/ ? ($1,$2):() } split /,/, $files;
+
+  my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc. '/';
+  my $file = $dir. $files{'file'};
+
+  my $type;
+  if ( $file =~ /\.(\w+)$/i ) {
+    my $ext = lc($1);
+    die "Unrecognized file extension $ext"
+      unless $ext_to_type{$ext};
+    $type = $ext_to_type{$ext};
+  } else {
+    die "Cannot upload image file without extension"
+  }
+
+  my $template_image = new FS::template_image {
+    'name'   => $param->{'name'},
+    'mime_type' => $type,
+    'agentnum'  => $param->{'agentnum'},
+    'base64'    => encode_base64( slurp($file, binmode => ':raw'), '' ),
+  };
+  my $error = $template_image->insert();
+  die $error if $error;
+  unlink $file;
+  '';
+
+}
+
+=back
+
+=head1 BUGS
+
+Will be described here once found.
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/httemplate/browse/msg_template.html b/httemplate/browse/msg_template.html
index ef0b2da..1646bc1 100644
--- a/httemplate/browse/msg_template.html
+++ b/httemplate/browse/msg_template.html
@@ -28,6 +28,7 @@ my @menubar = ();
 if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) {
   push @menubar, 'Add a new template' => $p.'edit/msg_template.html';
 }
+push @menubar, 'View template images' => $p.'browse/template_image.html';
 
 my $link = [ "${p}edit/msg_template.html?msgnum=", 'msgnum' ];
 
@@ -52,7 +53,7 @@ my $disable_link = sub {
     action      => $p.'misc/disable-msg_template.cgi?msgnum=' .
                      $template->msgnum .
                      ($template->disabled ? ';enable=1' : ''),
-    actionlabel => 'Disable lemplate',
+    actionlabel => 'Disable template',
   );
 };
 
diff --git a/httemplate/browse/template_image.html b/httemplate/browse/template_image.html
new file mode 100644
index 0000000..eb4325f
--- /dev/null
+++ b/httemplate/browse/template_image.html
@@ -0,0 +1,68 @@
+<% include('/elements/init_overlib.html') %>
+
+<% include( 'elements/browse.html',
+              'title'         => 'Template images',
+              'name_singular' => 'image',
+              'menubar'       => \@menubar,
+              'query'         => { 'table' => 'template_image', },
+              'count_query'   => 'SELECT COUNT(*) FROM template_image',
+              'agent_virt'         => 1,
+              'agent_null_right'   => ['View global templates','Edit global templates'],
+              'agent_pos'          => 1,
+              'header'      => [ 'Name', '', '' ],
+              'fields'      => [ 'name', $tag, $delete_text ],
+              'links'       => [ '', '', '' ],
+              'cell_style'    => [ '', '', '' ],
+          )
+%>
+
+<% include('/elements/template_image-dialog.html',
+     'url' => $p.'browse/template_image.html'
+   ) %>
+
+<%init>
+use FS::template_image;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right([ 'View templates', 'View global templates',
+                                  'Edit templates', 'Edit global templates', ]);
+
+my $canedit = $curuser->access_right(['Edit templates', 'Edit global templates']);
+
+my @menubar = ();
+if ($canedit) {
+  push @menubar, 'Upload a new image' => 'javascript:insertImageDialog(\'upload\')';
+}
+push @menubar, ( 'View message templates' => $p.'browse/msg_template.html' );
+
+my $tag = sub { qq!<A HREF="javascript:insertImageDialog(! . $_[0]->imgnum . qq!)">view</A>! };
+
+my $delete_text = $canedit ? sub {
+  my $image = shift;
+  my $imgnum = $image->imgnum;
+  unless ($image->agentnum) {
+    unless ($FS::CurrentUser::CurrentUser->access_right('Edit global templates')) {
+      return '';
+    }
+  }
+  my $out = <<EOF;
+<FORM name="delete_template_image_$imgnum">
+<INPUT TYPE="hidden" name="imgnum" value="$imgnum">
+</FORM>
+EOF
+  $out .= include('/elements/progress-init.html',
+            "delete_template_image_$imgnum",
+            [ 'imgnum' ],
+            $p.'misc/process/template_image-delete.cgi',
+            $p.'browse/template_image.html',
+            "imgnum$imgnum",
+          );
+  my $onclick = 'if ( confirm(\'';
+  $onclick .= emt('Are you sure you want to delete template image ') . $imgnum;
+  $onclick .= '\') ) { imgnum' . $imgnum . 'process() }';
+  return $out . '<A HREF="javascript:void(0)" ONCLICK="' . $onclick . '">delete</A>';
+} : '';
+
+</%init>
diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html
index 7f38241..df72c5b 100644
--- a/httemplate/edit/msg_template.html
+++ b/httemplate/edit/msg_template.html
@@ -27,6 +27,7 @@
      'no_submit'        => $no_submit,
 &>
 <%init>
+use FS::template_image;
 
 my $curuser = $FS::CurrentUser::CurrentUser;
 
@@ -345,10 +346,16 @@ function areyousure(url, message) {
 <TD valign="top"><FORM name="dummy">
 Substitutions: '
 . $widget->html .
-'<BR>Click links to insert.
-<BR>Enclose substitutions and other Perl expressions in braces:
+'<P>Click above links to insert substitution code.</P>
+<P>
+Enclose substitutions and other Perl expressions in braces:
 <BR>{ $name } = ExampleCo (Smith, John)
 <BR>{ time2str("%D", time) } = '.time2str("%D", time).'
+</P>';
+$sidebar .= include('/elements/template_image-dialog.html',
+              'callback' => 'insertHtml'
+            );
+$sidebar .= '<P><A HREF="javascript:insertImageDialog()">Insert Uploaded Image</A></P>
 </FONT></TD>
 ';
 
diff --git a/httemplate/elements/form-file_upload.html b/httemplate/elements/form-file_upload.html
index 45b6c97..3542a5a 100644
--- a/httemplate/elements/form-file_upload.html
+++ b/httemplate/elements/form-file_upload.html
@@ -69,6 +69,7 @@ Example:
 <div style="display:none:" id="uploadError"></div>
 
 <FORM NAME     = "<% $opt{name} %>"
+      ID       = "<% $opt{id} %>"
       ACTION   = "<% $fsurl %>misc/file-upload.html"
       METHOD   = "POST"
       ENCTYPE  = "multipart/form-data"
diff --git a/httemplate/elements/images/ui-icons_ef8c08_256x240.png b/httemplate/elements/images/ui-icons_ef8c08_256x240.png
new file mode 100644
index 0000000..85e63e9
Binary files /dev/null and b/httemplate/elements/images/ui-icons_ef8c08_256x240.png differ
diff --git a/httemplate/elements/template_image-dialog.html b/httemplate/elements/template_image-dialog.html
new file mode 100644
index 0000000..5691d52
--- /dev/null
+++ b/httemplate/elements/template_image-dialog.html
@@ -0,0 +1,279 @@
+<%doc>
+
+Creates a jquery dialog box that opens when javascript function insertImageDialog
+is called, allows user to select an image and specify attributes for it, then passes 
+img tag with base64 encoded data url to a callback javascript function.
+
+Accepts the following options:
+
+callback - pass the html for the selected img to this javascript function;
+if omitted, will only include fields for viewing/uploading image
+
+url - to redirect to after upload, otherwise just refreshes dialog window
+
+</%doc>
+
+<% include('/elements/xmlhttp.html',
+        'url'  => $p.'misc/xmlhttp-template_image.cgi',
+        'subs' => [ 'get_template_image' ],
+   ) %>
+
+<DIV ID="insert_image_dialog" title="Template Images">
+
+<TABLE BORDER="0" STYLE="width: 100%"><TR><TD>
+
+<FORM ID="insert_image_form">
+
+<% &ntable("#cccccc", 2) %>
+
+  <TR>
+    <TH>Image</TH>
+    <TD>
+      <SELECT ID="insert_image_imgnum" ONCHANGE="insertImageDialog($('#insert_image_imgnum').val())">
+        <OPTION VALUE="">(select an image)</OPTION>
+      </SELECT>
+    </TD>
+  </TR>
+% if ($opt{'callback'}) {
+  <TR>
+    <TH>Width</TH>
+    <TD><INPUT TYPE="text" SIZE="5" ID="insert_image_width" ONCHANGE="previewInsertImage()"></TD>
+  </TR>
+  <TR>
+    <TH>Height</TH>
+    <TD><INPUT TYPE="text" SIZE="5" ID="insert_image_height" ONCHANGE="previewInsertImage()"></TD>
+  </TR>
+  <TR>
+    <TH>Align</TH>
+    <TD>
+      <SELECT ID="insert_image_float" ONCHANGE="previewInsertImage()">
+        <OPTION VALUE="none">inline</OPTION>
+        <OPTION VALUE="left">left</OPTION>
+        <OPTION VALUE="right">right</OPTION>
+      </SELECT>
+    </TD>
+  </TR>
+  <TR>
+    <TH>Alt Text</TH>
+    <TD><INPUT TYPE="text" SIZE="20" ID="insert_image_alt" ONCHANGE="previewInsertImage()"></TD>
+  </TR>
+  <TR>
+    <TD COLSPAN="2" ALIGN="center" STYLE="padding-top:6px">
+      <INPUT TYPE="button" ID="insert_image_button" VALUE="Insert Image" ONCLICK="insertImage()">
+    </TD>
+  </TR>
+% } # if $opt{'callback'}
+
+</TABLE>
+
+</FORM>
+
+% if ($canedit) {
+
+<P><B><% emt('Upload New Image') %></B></P>
+
+<% include('/elements/form-file_upload.html',
+     'name'      => 'TemplateImageUploadForm',
+     'id'        => 'TemplateImageUploadForm',
+     'action'    => $p.'misc/process/template_image-upload.cgi',
+     'num_files' => 1,
+     'fields'    => [ 'name', 'agentnum' ],
+     'url'       => $opt{'url'} || 'javascript:refreshImageList(1)',
+   )
+ %>
+
+ <% &ntable("#cccccc", 2) %>
+
+  <% include( '/elements/tr-input-text.html',
+                'field' => 'name',
+                'label' => 'Name',
+                'required' => 1,
+                'id' => 'upload_form_name',
+            )
+  %>
+
+  <% include( '/elements/tr-select-agent.html',
+                 'label'       => "<B>Agent</B>",
+                 'empty_label' => 'Select agent',
+                 'agent_virt'  => 1,
+                 'agent_null_right' => 'Edit global templates',
+             )
+  %>
+
+  <% include( '/elements/tr-file-upload.html',
+                'field' => 'file',
+                'label' => 'File',
+            )
+  %>
+
+  <TR>
+    <TD COLSPAN="2" ALIGN="center" STYLE="padding-top:6px">
+      <INPUT TYPE    = "submit"
+             NAME    = "submitButton"
+             ID      = "submitButton"
+             VALUE   = "Upload image"
+      >
+    </TD>
+  </TR>
+
+</TABLE>
+
+</FORM>
+
+% } #if canedit
+
+</TD><TD width="100%">
+
+<DIV ID="insert_image_preview_box">
+  <P><B><% emt('Image Preview') %></B></P>
+  <SPAN ID="insert_image_loading"><B>(<% emt('Loading image...') %>)</B></SPAN>
+  <IMG SRC="" ID="insert_image_preview">
+</DIV>
+
+</TD></TR></TABLE>
+</DIV>
+
+<SCRIPT>
+
+// initialize & close dialog window, initialize imgobj cache && image list
+$( '#insert_image_dialog' ).dialog({
+  width: 800,
+  height: 550,
+  resizable: true,
+  autoOpen: false,
+});
+var imgobj = new Object;
+refreshImageList(0);
+
+// this is the main func to invoke from links outside this file.
+// opens dialog if needed
+// updates dialog with passed imgnum
+// caches image info through an xmlhttp request if needed
+// pass 'upload' as imgnum for upload-only view
+function insertImageDialog (imgnum) {
+  if (imgnum == 'upload') {
+    $('#insert_image_form').hide();
+    $('#insert_image_preview_box').hide();
+    imgnum = undefined;
+  } else {
+    $('#insert_image_form').show();
+    $('#insert_image_preview_box').show();
+  }
+  if (imgnum && !imgobj[imgnum]) {
+    clearInsertImageDialog();
+    $('#insert_image_loading').show();
+    $('#insert_image_imgnum').val(imgnum);
+    get_template_image('imgnum',imgnum,
+      function (result) {
+        var images = JSON.parse(result) || [];
+        for (i = 0; i < images.length; i++) {
+          imgobj[images[i].imgnum] = images[i];
+        }
+        updateInsertImageDialog();
+      }
+    );
+  } else if (imgnum) {
+    $('#insert_image_imgnum').val(imgnum);
+    updateInsertImageDialog();
+  } else {
+    clearInsertImageDialog();
+  }
+  if (!$( '#insert_image_dialog' ).dialog( 'isOpen' )) {
+    $( '#insert_image_dialog' ).dialog( 'open' );
+  }
+}
+
+// sets dialog values to a default "Loading..." state, including imgnum
+function clearInsertImageDialog () {
+  $('#insert_image_imgnum').val('');
+  $('#insert_image_preview').attr('src','');
+  $('#insert_image_loading').hide();
+}
+
+// updates preview src from cache based on imgnum from form
+// then calls previewInsertImage
+function updateInsertImageDialog () {
+  var imgnum = $('#insert_image_imgnum').val();
+  $('#insert_image_loading').hide();
+  $('#insert_image_preview').attr('src',imgobj[imgnum].src);
+  previewInsertImage();
+}
+
+// updates preview width/height/alt/float based on current form values
+function previewInsertImage () {
+  $('#insert_image_preview').css('width',$('#insert_image_width').val());
+  $('#insert_image_preview').css('height',$('#insert_image_height').val());
+  $('#insert_image_preview').css('float',$('#insert_image_float').val());
+  $('#insert_image_preview').attr('alt',$('#insert_image_alt').val());
+}
+
+// constructs html based on the form contents,
+// passes it to callback & closes dialog
+function insertImage() {
+  var imgnum = $('#insert_image_imgnum').val();
+  if (!(imgnum && imgobj[imgnum])) {
+    return '';
+  }
+  var width = $('#insert_image_width').val() || '';
+  var height = $('#insert_image_height').val() || '';
+  var alt = $('#insert_image_alt').val() || '';
+  var float = $('#insert_image_float').val();
+  var imgtag = '<IMG SRC="' + imgobj[imgnum].src + '"';
+  if (width) {
+    imgtag += ' WIDTH="' + width + '"';
+  }
+  if (height) {
+    imgtag += ' HEIGHT="' + height + '"';
+  }
+  if (alt) {
+    imgtag += ' ALT="' + alt + '"';
+  }
+  if (float) {
+    imgtag += ' STYLE="float: ' + float + '"';
+  }
+  imgtag += '>';
+  <% $opt{'callback'} %>(imgtag);
+  $( '#insert_image_dialog' ).dialog( 'close' );
+}
+
+// uses xmlhttp request to initialize image list & refresh it after uploads
+function refreshImageList (fromupload) {
+  get_template_image('no_src','1',
+    function (result) {
+      if (fromupload) {
+        $("#TemplateImageUploadForm")[0].reset();
+      }
+      var images = JSON.parse(result) || [];
+      var latest;
+      for (i = 0; i < images.length; i++) {
+        if ( $("#insert_image_imgnum option[value='" + images[i].imgnum + "']").length == 0 ) {
+          $("#insert_image_imgnum").append('<OPTION VALUE="'+images[i].imgnum+'">'+images[i].name+'</OPTION>');
+          latest = images[i].imgnum;
+        }
+      }
+      if (fromupload) {
+        location.hash = "insert_image_dialog";
+        if (latest) {
+          // small risk of a race condition with other newly-uploaded images,
+          // but does no real damage (our image still shows up in the list)
+          insertImageDialog(latest);
+        }
+      }
+    }
+  );
+}
+
+</SCRIPT>
+
+<%init>
+my %opt = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right([ 'View templates', 'View global templates',
+                                  'Edit templates', 'Edit global templates', ]);
+
+my $canedit = $curuser->access_right([ 'Edit templates', 'Edit global templates' ]);
+</%init>
+
diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html
index 47e6a5b..8ac44af 100644
--- a/httemplate/misc/email-customers.html
+++ b/httemplate/misc/email-customers.html
@@ -36,7 +36,7 @@ should be used to set msgnum or from/subject/html_body cgi params
 % }
 
 
-<FORM NAME="OneTrueForm" ACTION="<% $form_action %>" METHOD="GET">
+<FORM NAME="OneTrueForm" ACTION="<% $form_action %>" METHOD="POST">
 <INPUT TYPE="hidden" NAME="table" VALUE="<% $table %>">
 %# Mixing search params with from address, subject, etc. required special-case
 %# handling of those, risked name conflicts, and caused massive problems with 
diff --git a/httemplate/misc/process/template_image-delete.cgi b/httemplate/misc/process/template_image-delete.cgi
new file mode 100644
index 0000000..58c3f2c
--- /dev/null
+++ b/httemplate/misc/process/template_image-delete.cgi
@@ -0,0 +1,28 @@
+<% $server->process %>
+
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+# make sure user can generally edit
+die "access denied"
+  unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]);
+
+# make sure user can edit this particular image
+my %arg = $cgi->param('arg');
+my $imgnum = $arg{'imgnum'};
+die "bad imgnum" unless $imgnum =~ /^\d+$/;
+die "access denied" unless qsearchs({
+               'table'     => 'template_image',
+               'select'    => 'imgnum',
+               'hashref'   => { 'imgnum' => $imgnum },
+               'extra_sql' => ' AND ' . 
+                              $curuser->agentnums_sql(
+                                'null_right' => ['Edit global templates']
+                              ),
+             });
+
+my $server =
+  new FS::UI::Web::JSRPC 'FS::template_image::process_image_delete', $cgi;
+
+</%init>
diff --git a/httemplate/misc/process/template_image-upload.cgi b/httemplate/misc/process/template_image-upload.cgi
new file mode 100644
index 0000000..c3c9059
--- /dev/null
+++ b/httemplate/misc/process/template_image-upload.cgi
@@ -0,0 +1,26 @@
+<% $server->process %>
+
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]);
+
+my %arg = $cgi->param('arg');
+my $agentnum = $arg{'agentnum'};
+
+if (!$agentnum) {
+  die "access denied"
+    unless $curuser->access_right([ 'Edit global templates' ]);
+} else {
+  die "bad agentnum"
+    unless $agentnum =~ /^\d+$/;
+  die "access denied"
+    unless $curuser->agentnum($agentnum);
+}
+
+my $server =
+  new FS::UI::Web::JSRPC 'FS::template_image::process_image_upload', $cgi;
+
+</%init>
diff --git a/httemplate/misc/xmlhttp-template_image.cgi b/httemplate/misc/xmlhttp-template_image.cgi
new file mode 100644
index 0000000..a8c50ed
--- /dev/null
+++ b/httemplate/misc/xmlhttp-template_image.cgi
@@ -0,0 +1,48 @@
+<%doc>
+Returns JSON encoded array of objects with details about FS::template_image
+objects.  Attributes in each returned object are imgnum, name, and src.
+
+Accepts the following options:
+
+imgnum - only return object for this imgnum
+
+no_src - do not include the src field
+
+</%doc>
+<% encode_json(\@result) %>\
+<%init>
+use FS::template_image;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right([ 'View templates', 'View global templates',
+                                  'Edit templates', 'Edit global templates', ]);
+
+my %arg = $cgi->param('arg');
+
+my $search = {
+  'table' => 'template_image',
+  'hashref' => {},
+};
+
+my $imgnum = $arg{'imgnum'} || '';
+die "Bad imgnum" unless $imgnum =~ /^\d*$/;
+$search->{'hashref'}->{'imgnum'} = $imgnum if $imgnum;
+
+$search->{'select'} = 'imgnum, name' if $arg{'no_src'};
+
+$search->{'extra_sql'} = ($imgnum ? ' AND ' : ' WHERE ')
+                       . $curuser->agentnums_sql(
+                           'null_right' => ['View global templates','Edit global templates']
+                         );
+
+my @images = qsearch($search); #needs agent virtualization
+
+my @result = map { +{
+  'imgnum' => $_->imgnum,
+  'name'   => $_->name,
+  'src'    => $arg{'no_src'} ? '' : $_->src,
+} } @images;
+
+</%init>

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

Summary of changes:
 FS/FS/Schema.pm                                    |   14 +
 FS/FS/template_image.pm                            |  222 ++++++++++++++++
 httemplate/browse/msg_template.html                |    3 +-
 httemplate/browse/template_image.html              |   68 +++++
 httemplate/edit/msg_template.html                  |   11 +-
 httemplate/elements/form-file_upload.html          |    1 +
 .../elements/images}/ui-icons_ef8c08_256x240.png   |  Bin 4369 -> 4369 bytes
 httemplate/elements/template_image-dialog.html     |  279 ++++++++++++++++++++
 httemplate/misc/email-customers.html               |    2 +-
 httemplate/misc/process/template_image-delete.cgi  |   28 ++
 httemplate/misc/process/template_image-upload.cgi  |   26 ++
 httemplate/misc/xmlhttp-template_image.cgi         |   48 ++++
 12 files changed, 698 insertions(+), 4 deletions(-)
 create mode 100644 FS/FS/template_image.pm
 create mode 100644 httemplate/browse/template_image.html
 copy {rt/share/html/NoAuth/images/jquery_ui => httemplate/elements/images}/ui-icons_ef8c08_256x240.png (100%)
 mode change 100755 => 100644
 create mode 100644 httemplate/elements/template_image-dialog.html
 create mode 100644 httemplate/misc/process/template_image-delete.cgi
 create mode 100644 httemplate/misc/process/template_image-upload.cgi
 create mode 100644 httemplate/misc/xmlhttp-template_image.cgi




More information about the freeside-commits mailing list