import data user interface
authorTony Cook <tony@develop-help.com>
Fri, 2 Nov 2012 04:11:42 +0000 (15:11 +1100)
committerTony Cook <tony@develop-help.com>
Mon, 5 Nov 2012 00:02:32 +0000 (11:02 +1100)
MANIFEST
site/cgi-bin/bse.cfg
site/cgi-bin/modules/BSE/Importer.pm
site/cgi-bin/modules/BSE/UI/AdminImporter.pm [new file with mode: 0644]
site/templates/admin/import/import.tmpl [new file with mode: 0644]
site/templates/admin/import/start.tmpl [new file with mode: 0644]
site/templates/admin/menu.tmpl

index 9cfb12a..06a0059 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -239,6 +239,7 @@ site/cgi-bin/modules/BSE/UI.pm
 site/cgi-bin/modules/BSE/UI/AdminAudit.pm
 site/cgi-bin/modules/BSE/UI/AdminDispatch.pm
 site/cgi-bin/modules/BSE/UI/AdminImageClean.pm
+site/cgi-bin/modules/BSE/UI/AdminImporter.pm
 site/cgi-bin/modules/BSE/UI/AdminMessages.pm
 site/cgi-bin/modules/BSE/UI/AdminModules.pm
 site/cgi-bin/modules/BSE/UI/AdminNewsletter.pm
@@ -563,6 +564,8 @@ site/templates/admin/image_edit.tmpl        Edit a single image
 site/templates/admin/imageclean/final.tmpl
 site/templates/admin/imageclean/intro.tmpl
 site/templates/admin/imageclean/preview.tmpl
+site/templates/admin/import/import.tmpl
+site/templates/admin/import/start.tmpl
 site/templates/admin/include/article_menu.tmpl
 site/templates/admin/include/auditentry.tmpl
 site/templates/admin/include/audithead.tmpl
index cf82f25..dbc7f98 100644 (file)
@@ -442,6 +442,7 @@ default=shop
 shopadmin=BSE::UI::AdminShop
 modules=BSE::UI::AdminModules
 log=BSE::UI::AdminAudit
+importer=BSE::UI::AdminImporter
 
 [includes]
 00install=bse-install.cfg
index 4eb51d1..9da93f5 100644 (file)
@@ -2,7 +2,7 @@ package BSE::Importer;
 use strict;
 use Config;
 
-our $VERSION = "1.002";
+our $VERSION = "1.003";
 
 =head1 NAME
 
@@ -289,6 +289,18 @@ sub parents {
   return $_[0]{target}->parents;
 }
 
+=item set_callback()
+
+Replace the callback sub reference.
+
+=cut
+
+sub set_callback {
+  my ($self, $callback) = @_;
+
+  $self->{callback} = $callback;
+}
+
 =back
 
 =head2 Internal
diff --git a/site/cgi-bin/modules/BSE/UI/AdminImporter.pm b/site/cgi-bin/modules/BSE/UI/AdminImporter.pm
new file mode 100644 (file)
index 0000000..8e36c7e
--- /dev/null
@@ -0,0 +1,159 @@
+package BSE::UI::AdminImporter;
+use strict;
+use base 'BSE::UI::AdminDispatch';
+use BSE::Importer;
+use BSE::Util::Tags qw(tag_error_img);
+
+our $VERSION = "1.000";
+
+my %actions =
+  (
+   start => "bse_import",
+   import => "bse_import",
+  );
+
+sub actions { \%actions }
+
+sub rights { \%actions }
+
+sub default_action { "start" }
+
+=head1 NAME
+
+BSE::UI::AdminImporter - Web UI for the import tool
+
+=head1 DESCRIPTION
+
+Provides a simple user interface for the import tool.
+
+=head1 TARGETS
+
+=over
+
+=item start
+
+The initial, default form for the import process.
+
+Provides default admin tags, and the following variables:
+
+=over
+
+=item *
+
+profiles - a list of hashes each with the id and label of a profile.
+
+=item *
+
+profile_errors - a list of errors from attempting to load profiles.
+
+=back
+
+Template: F<admin/import/start>.
+
+Access required: C<bse_import>.
+
+=cut
+
+sub req_start {
+  my ($self, $req, $errors) = @_;
+
+  my $profiles = BSE::Importer->profiles;
+  my @errors;
+  my @profiles;
+  my $message = $req->message($errors);
+  for my $profile (keys %$profiles) {
+    if (eval {
+      local $SIG{__DIE__};
+      BSE::Importer->new(profile => $profile, cfg => $req->cfg);
+    }) {
+      push @profiles, { id => $profile, label => $profiles->{$profile} };
+    }
+    else {
+      push @errors, "Loading profile '$profile': $@";
+    }
+  }
+
+  $req->set_variable(profiles => \@profiles);
+  $req->set_variable(profile_errors => \@errors);
+  my %acts =
+    (
+     $req->admin_tags,
+     message => $message,
+     error_img => [ \&tag_error_img, $req->cfg, $errors ],
+    );
+
+  return $req->dyn_response("admin/import/start", \%acts);
+}
+
+=item Target import
+
+Perform import processing.
+
+CRSF token: C<bse_admin_import>.
+
+Template: F<admin/import/import>.
+
+Access required: C<bse_import>.
+
+=cut
+
+sub req_import {
+  my ($self, $req) = @_;
+
+  $req->check_csrf("bse_admin_import")
+    or return $self->req_start($req, $req->csrf_error);
+
+  my %errors;
+  my $profile = $req->cgi->param("profile");
+  my $profiles = BSE::Importer->profiles;
+  if (!defined $profile) {
+    $errors{profile} = "No profile specified";
+  }
+  elsif (!$profiles->{$profile}) {
+    $errors{profile} = "Unknown profile '$profile' specified";
+  }
+
+  my $file = $req->cgi->upload("file")
+    or $errors{file} = "No file provided";
+
+  keys %errors
+    and return $self->req_start($req, \%errors);
+
+  my $imp;
+  {
+    local $SIG{__DIE__};
+    eval { $imp = BSE::Importer->new(profile => $profile, cfg => $req->cfg) }
+      or return $self->req_start($req, "Cannot load profile '$profile': $@");
+  }
+
+  $req->set_variable
+    (perline => sub {
+       my ($cb, $templater) = @_;
+       my $mycb = sub {
+        $templater->set_var(importmessage => "@_");
+        $cb->()
+       };
+       $imp->set_callback
+        (
+         $mycb
+        );
+       local $SIG{__DIE__};
+       unless (eval { $imp->process($file); 1 }) {
+        $mycb->($@);
+       }
+     });
+
+  my %acts = $req->admin_tags;
+
+  return $req->dyn_response("admin/import/import", \%acts);
+}
+
+1;
+
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
diff --git a/site/templates/admin/import/import.tmpl b/site/templates/admin/import/import.tmpl
new file mode 100644 (file)
index 0000000..e786d07
--- /dev/null
@@ -0,0 +1,8 @@
+<:wrap admin/base.tmpl title => "Import Data - Processing":>
+<h1>Import Data</h1>
+<h2>Processing</h2>
+<p>| <a href="/admin/">Admin Menu</a> |</p>
+
+<:.iterateover perline :>
+<div><:= importmessage | html :></div>
+<:.end:>
diff --git a/site/templates/admin/import/start.tmpl b/site/templates/admin/import/start.tmpl
new file mode 100644 (file)
index 0000000..470a37a
--- /dev/null
@@ -0,0 +1,38 @@
+<:wrap admin/base.tmpl title => "Import Data":>
+<h1>Import Data</h1>
+<p>| <a href="/admin/">Admin Menu</a> |</p>
+
+<:.if request.messages.size != 0:>
+<:-.for m in request.messages -:>
+<div class="message <:= m.class:>"><:= m.html :></div>
+<:.end for-:>
+<:.end if:>
+
+<:.if profile_errors.size:>
+<div class="message errors">
+<:.for m in profile_errors:>
+<div><:= m | html :></div>
+<:.end for:>
+</div>
+<:.end if:>
+
+<form action="<:= cfg.admin_url("importer") | html:>" method="post" enctype="multipart/form-data">
+<:csrfp bse_admin_import hidden:>
+  <table class="editform editformsmall">
+    <tr>
+      <th>Import profile:</th>
+      <td><:.call "make_select", "list":profiles, "name":"profile", "id":"id", "desc":"label", "default":cgi.param('profile') :></td>
+      <td><:error_img profile:></td>
+    </tr>
+    <tr>
+      <th>File:</th>
+      <td><input type="file" name="file" /></td>
+      <td><:error_img file:></td>
+    </tr>
+    <tr>
+      <td colspan="3" class="buttons">
+        <input type="submit" value="Import" name="a_import" />
+      </td>
+    </tr>
+  </table>
+</form>
index f85b17a..e182d9f 100644 (file)
@@ -93,6 +93,10 @@ href="<:= cfg.admin_url2("shopadmin", "order_list_filled", { "template":"order_l
 <li><a href="<:= cfg.admin_url("add", { "parentid":3 }) | html :>">Add catalog</a></li>
 
 </ul>
+
+<:.if request.user_can("bse_admin_import") :>
+<p><a href="<:= cfg.admin_url("importer") | html :>">Import data</a></p>
+<:.end if:>
   </td>
 </tr>
 </table>