return $dynamic_path . "/" . $self->{id} . ".html";
}
-sub remove {
+sub remove_images {
my ($self, $cfg) = @_;
- $cfg or confess "No \$cfg supplied to ", ref $self, "->remove";
-
- require Images;
- my @images = Images->getBy(articleId=>$self->{id});
+ my @images = $self->images;
+ my $mgr;
my $imagedir = $cfg->entry('paths', 'images', $Constants::IMAGEDIR);
for my $image (@images) {
+ if ($image->{storage} ne 'local') {
+ unless ($mgr) {
+ require BSE::StorageMgr::Images;
+ $mgr = BSE::StorageMgr::Images->new(cfg => $cfg);
+ }
+ $mgr->unstore($image->{image}, $image->{storage});
+ }
+
unlink("$imagedir/$image->{image}");
$image->remove();
}
+}
+
+sub remove {
+ my ($self, $cfg) = @_;
+
+ $cfg or confess "No \$cfg supplied to ", ref $self, "->remove";
+
+ $self->remove_images($cfg);
for my $file ($self->files) {
$file->remove($cfg);
use BSE::Cfg;
require Exporter;
@ISA = qw(Exporter);
-@EXPORT_OK = qw(bse_cfg bse_make_product bse_make_catalog bse_encoding);
-use Carp qw(confess);
+@EXPORT_OK = qw(bse_cfg bse_make_product bse_make_catalog bse_encoding bse_add_image);
+use Carp qw(confess croak);
my %acticle_defaults =
(
return $cfg->entry('html', 'charset', 'iso-8859-1');
}
+sub bse_add_image {
+ my ($cfg, $article, %opts) = @_;
+
+ my $editor;
+ ($editor, $article) = _load_editor_class($article, $cfg);
+
+ my %image;
+ my $file = delete $opts{file};
+ $file
+ or croak "Missing image filename";
+ open IN, "< $file"
+ or croak "Failed opening image file $file: $!";
+ binmode IN;
+ my %errors;
+
+ $editor->do_add_image
+ (
+ $cfg,
+ $article,
+ *IN,
+ %opts,
+ errors => \%errors,
+ filename => $file,
+ );
+}
+
+sub _load_editor_class {
+ my ($article, $cfg) = @_;
+
+ require BSE::Edit::Base;
+ return BSE::Edit::Base->article_class($article, 'Articles', $cfg);
+}
+
1;
}
sub _service_error {
- my ($self, $req, $article, $articles, $error) = @_;
+ my ($self, $req, $article, $articles, $msg, $error) = @_;
if ($req->cgi->param('_service')) {
my $body = '';
};
}
else {
- return $self->edit_form($req, $article, $articles, $error);
+ return $self->edit_form($req, $article, $articles, $msg, $error);
}
}
};
}
-sub add_image {
- my ($self, $req, $article, $articles) = @_;
-
- $req->user_can(edit_images_add => $article)
- or return $self->_service_error($req, $article, $articles,
- "You don't have access to add new images to this article");
+sub do_add_image {
+ my ($self, $cfg, $article, $image, %opts) = @_;
- my $cgi = $req->cgi;
+ my $errors = $opts{errors}
+ or die "No errors parameter";
- my %errors;
- my $msg;
- my $imageref = $cgi->param('name');
+ my $imageref = $opts{name};
if (defined $imageref && $imageref ne '') {
if ($imageref =~ /^[a-z_]\w+$/i) {
# make sure it's unique
my @images = $self->get_images($article);
for my $img (@images) {
if (defined $img->{name} && lc $img->{name} eq lc $imageref) {
- $errors{name} = 'Image name must be unique to the article';
+ $errors->{name} = 'Image name must be unique to the article';
last;
}
}
}
else {
- $errors{name} = 'Image name must be empty or alphanumeric beginning with an alpha character';
+ $errors->{name} = 'Image name must be empty or alphanumeric beginning with an alpha character';
}
}
else {
$imageref = '';
}
- unless ($errors{name}) {
+ unless ($errors->{name}) {
my $workmsg;
$self->validate_image_name($imageref, \$workmsg)
- or $errors{name} = $workmsg;
+ or $errors->{name} = $workmsg;
}
- my $image = $cgi->param('image');
if ($image) {
if (-z $image) {
- $errors{image} = 'Image file is empty';
+ $errors->{image} = 'Image file is empty';
}
}
else {
- #$msg = 'Enter or select the name of an image file on your machine';
- $errors{image} = 'Please enter an image filename';
- }
- if ($msg || keys %errors) {
- return $self->_service_error($req, $article, $articles, $msg, \%errors);
+ $errors->{image} = 'Please enter an image filename';
}
+ keys %$errors
+ and return;
- my $imagename = $image;
+ my $imagename = $opts{filename} || $image;
$imagename .= ''; # force it into a string
my $basename = '';
+ $imagename =~ tr/ //d;
$imagename =~ /([\w.-]+)$/ and $basename = $1;
# create a filename that we hope is unique
# for the sysopen() constants
use Fcntl;
- my $imagedir = cfg_image_dir($req->cfg);
+ my $imagedir = cfg_image_dir($cfg);
# loop until we have a unique filename
my $counter="";
$filename = time. '_' . $counter . '_' . $basename
my($width,$height) = imgsize("$imagedir/$filename");
- my $alt = $cgi->param('altIn');
+ my $alt = $opts{alt};
defined $alt or $alt = '';
- my $url = $cgi->param('url');
+ my $url = $opts{url};
defined $url or $url = '';
my %image =
(
shift @cols;
my $imageobj = Images->add(@image{@cols});
- my $storage = $cgi->param('storage');
+ my $storage = $opts{storage};
defined $storage or $storage = 'local';
- my $image_manager = $self->_image_manager($req->cfg);
+ my $image_manager = $self->_image_manager($cfg);
local $SIG{__DIE__};
eval {
my $src;
}
};
if ($@) {
- $req->flash($@);
+ $errors->{flash} = $@;
}
+ return $imageobj;
+}
+
+sub add_image {
+ my ($self, $req, $article, $articles) = @_;
+
+ $req->user_can(edit_images_add => $article)
+ or return $self->_service_error($req, $article, $articles,
+ "You don't have access to add new images to this article");
+
+ my $cgi = $req->cgi;
+ my %errors;
+ my $imageobj =
+ $self->do_add_image
+ (
+ $req->cfg,
+ $article,
+ scalar($cgi->param('image')),
+ name => scalar($cgi->param('name')),
+ alt => scalar($cgi->param('altIn')),
+ url => scalar($cgi->param('url')),
+ storage => scalar($cgi->param('storage')),
+ errors => \%errors,
+ );
+
+ $imageobj
+ or return $self->_service_error($req, $article, $articles, undef, \%errors);
+
+ # typically a soft failure from the storage
+ $errors{flash}
+ and $req->flash($errors{flash});
+
use Util 'generate_article';
generate_article($articles, $article) if $Constants::AUTO_GENERATE;
package BSE::ProductImportXLS;
use strict;
use Spreadsheet::ParseExcel;
-use BSE::API qw(bse_make_product bse_make_catalog);
+use BSE::API qw(bse_make_product bse_make_catalog bse_add_image);
use Articles;
use Products;
+use Config;
sub new {
- my ($class, $cfg, $profile) = @_;
+ my ($class, $cfg, $profile, %opts) = @_;
# field mapping
my $section = "xls import $profile";
my $use_codes = $cfg->entry($section, 'codes', 0);
my $parent = $cfg->entry($section, 'parent', 3);
my $price_dollar = $cfg->entry($section, 'price_dollar', 0);
+ my $reset_images = $cfg->entry($section, 'reset_images', 0);
+ my $file_path = $cfg->entry($section, 'file_path');
+ defined $file_path or $file_path = '';
+ my @file_path = split /$Config{path_sep}/, $file_path;
+ if ($opts{file_path}) {
+ unshift @file_path,
+ map
+ {
+ split /$Config{path_sep}/, $_
+ }
+ @{$opts{file_path}};
+ }
my %map;
for my $map (grep /^map_\w+$/, keys %ids) {
or die "Mapping for $out not numeric\n";
$map{$out} = $in;
}
+ my %set;
+ for my $set (grep /^set_\w+$/, keys %ids) {
+ (my $out = $set) =~ s/^set_//;
+ $set{$out} = $ids{$set};
+ }
my %xform;
for my $xform (grep /^xform_\w+$/, keys %ids) {
(my $out = $xform) =~ s/^xform_//;
$map{$out}
or die "Xform for $out but no mapping\n";
- my $code = "sub { local (\$_) = \@_; \n".$ids{$xform}."\n; return \$_ }";
+ my $code = "sub { (local \$_, my \$product) = \@_; \n".$ids{$xform}."\n; return \$_ }";
my $sub = eval $code;
$sub
or die "Compilation error for $xform code: $@\n";
{
map => \%map,
xform => \%xform,
+ set => \%set,
sheet => $sheet,
skiprows => $skiprows,
codes => $use_codes,
cats => \@cats,
parent => $parent,
price_dollar => $price_dollar,
+ reset_images => $reset_images,
cfg => $cfg,
+ file_path => \@file_path,
product_template => scalar($cfg->entry($section, 'product_template')),
catalog_template => scalar($cfg->entry($section, 'catalog_template')),
}, $class;
my %cat_cache;
for my $rownum ($self->{skiprows} ... $maxrow) {
eval {
- my %entry;
+ my %entry = %{$self->{set}};
$self->{product_template}
and $entry{template} = $self->{product_template};
for my $col (keys %{$self->{map}}) {
my $cell = $ws->get_cell($rownum, $self->{map}{$col}-1);
$entry{$col} = $cell->value;
-
- if ($self->{xform}{$col}) {
- $entry{$col} = $self->{xform}{$col}->($entry{$col});
- }
+ }
+ for my $col (keys %{$self->{xform}}) {
+ $entry{$col} = $self->{xform}{$col}->($entry{$col}, \%entry);
}
$entry{title} =~ /\S/
or die "title blank\n";
$product->save;
$callback
and $callback->("Updated $product->{id}: $entry{title}");
+ if ($self->{reset_images}) {
+ $product->remove_images($self->{cfg});
+ $callback
+ and $callback->(" $product->{id}: Reset images");
+ }
}
else
{
$callback
and $callback->("Added $product->{id}: $entry{title}");
}
+ for my $image_index (1 .. 10) {
+ my $file = $entry{"image${image_index}_file"};
+ $file
+ or next;
+ my $full_file = $self->_find_file($file);
+ $full_file
+ or die "File '$file' not found for image$image_index\n";
+
+ my %opts = ( file => $full_file );
+ for my $key (qw/alt name url storage/) {
+ my $fkey = "image${image_index}_$key";
+ $entry{$fkey}
+ and $opts{$key} = $entry{$fkey};
+ }
+
+ my %errors;
+ my $im = bse_add_image($self->{cfg}, $product, %opts,
+ errors => \%errors);
+ $im
+ or die join(", ",map "$_: $errors{$_}", keys %errors), "\n";
+ $callback
+ and $callback->(" $product->{id}: Add image '$file'");
+ }
push @{$self->{products}}, $product;
};
if ($@) {
return @{$_[0]{catalogs}};
}
+sub _find_file {
+ my ($self, $file) = @_;
+
+ for my $path (@{$self->{file_path}}) {
+ my $full = "$path/$file";
+ -f $full and return $full;
+ }
+
+ return;
+}
+
1;
my $verbose;
my $delete;
+my @file_path;
GetOptions("v", \$verbose,
- "d", \$delete);
+ "d", \$delete,
+ "path|p=s", \@file_path);
$verbose = defined $verbose;
my $cfg = bse_cfg();
my $filename = shift
or die "Usage: $0 profile filename\n";
-my $importer = BSE::ProductImportXLS->new($cfg, $profile);
+my $importer = BSE::ProductImportXLS->new
+ (
+ $cfg, $profile,
+ file_path => \@file_path
+ );
my $callback;
$verbose