0.14_27 commit r0_14_27
authorTony Cook <tony@develop-help.com>
Tue, 24 Aug 2004 06:33:16 +0000 (06:33 +0000)
committertony <tony@45cb6cf1-00bc-42d2-bb5a-07f51df49f94>
Tue, 24 Aug 2004 06:33:16 +0000 (06:33 +0000)
20 files changed:
MANIFEST
Makefile
site/cgi-bin/bse.cfg
site/cgi-bin/modules/BSE/AdminSiteUsers.pm
site/cgi-bin/modules/BSE/Request.pm
site/cgi-bin/modules/BSE/UI/Affiliate.pm
site/cgi-bin/modules/BSE/UI/SiteuserCommon.pm [new file with mode: 0644]
site/cgi-bin/modules/BSE/UserReg.pm
site/cgi-bin/modules/DevHelp/FileUpload.pm [new file with mode: 0644]
site/cgi-bin/modules/SiteUser.pm
site/cgi-bin/user.pl
site/docs/bse.pod
site/docs/config.pod
site/templates/admin/users/add.tmpl
site/templates/admin/users/edit.tmpl
site/templates/affiliate.tmpl
site/templates/user/options_base.tmpl
site/templates/user/options_images_base.tmpl [new file with mode: 0644]
site/templates/user/register_base.tmpl
test.cfg

index 163fdaa..ffe0eb0 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -98,6 +98,7 @@ site/cgi-bin/modules/BSE/Template.pm
 site/cgi-bin/modules/BSE/UI/AdminDispatch.pm
 site/cgi-bin/modules/BSE/UI/Affiliate.pm
 site/cgi-bin/modules/BSE/UI/Dispatch.pm
+site/cgi-bin/modules/BSE/UI/SiteuserCommon.pm
 site/cgi-bin/modules/BSE/UI/SubAdmin.pm
 site/cgi-bin/modules/BSE/UserReg.pm
 site/cgi-bin/modules/BSE/Util/DynSort.pm
@@ -110,6 +111,7 @@ site/cgi-bin/modules/BSE/Version.pm
 site/cgi-bin/modules/BSE/WebUtil.pm
 site/cgi-bin/modules/Constants.pm
 site/cgi-bin/modules/DevHelp/DynSort.pm
+site/cgi-bin/modules/DevHelp/FileUpload.pm
 site/cgi-bin/modules/DevHelp/Formatter.pm
 site/cgi-bin/modules/DevHelp/HTML.pm
 site/cgi-bin/modules/DevHelp/Report.pm
@@ -349,6 +351,7 @@ site/templates/user/lostpwdemail_base.tmpl
 site/templates/user/nopassword_base.tmpl
 site/templates/user/options_base.tmpl
 site/templates/user/options_billing_base.tmpl
+site/templates/user/options_images_base.tmpl
 site/templates/user/options_saved_base.tmpl
 site/templates/user/register_base.tmpl
 site/templates/user/subdetail.tmpl
index a6c92f2..fa5f176 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.14_26
+VERSION=0.14_27
 DISTNAME=bse-$(VERSION)
 DISTBUILD=$(DISTNAME)
 DISTTAR=../$(DISTNAME).tar
index 774171f..e7cca18 100644 (file)
@@ -11,6 +11,7 @@ access_control=0
 [paths]
 ; the following needs to be set to a path writable by the BSE processes
 downloads = /somewhere
+siteuser_images = $(paths/downloads)
 
 [pregenerate]
 
@@ -30,6 +31,7 @@ user/nopassword.tmpl = user,user/nopassword_base.tmpl
 user/options.tmpl = user,user/options_base.tmpl
 user/options_saved.tmpl = user,user/options_saved_base.tmpl
 user/options_billing.tmpl = user,user/options_billing_base.tmpl
+user/options_images.tmpl = user,user/options_images_base.tmpl
 user/register.tmpl = user,user/register_base.tmpl
 user/toomany.tmpl = user,user/toomany_base.tmpl
 user/toosoon.tmpl = user,user/toosoon_base.tmpl
index d0cc3df..58dc8eb 100644 (file)
@@ -1,5 +1,6 @@
 package BSE::AdminSiteUsers;
 use strict;
+use base qw(BSE::UI::SiteuserCommon);
 use BSE::Util::Tags qw(tag_error_img tag_hash);
 use DevHelp::HTML;
 use SiteUsers;
@@ -201,6 +202,7 @@ sub req_edit {
      [ \&tag_if_subscribed, $cgi, \@subs, \$sub_index, \%usersubs ],
      $it->make_iterator([ \&iter_orders, $siteuser ], 
                        'userorder', 'userorders' ),
+     $class->_edit_tags($siteuser, $req->cfg),
     );  
 
   my $template = 'admin/users/edit';
@@ -302,21 +304,9 @@ sub req_save {
   }
 
   my $aff_name = $cgi->param('affiliate_name');
-  if (defined $aff_name && length $aff_name) {
-    if ($aff_name =~ /^\s*\w+\s*$/) {
-      $aff_name =~ s/^\s+|\s+$//g;
-      my $other = SiteUsers->getBy(affiliate_name => $aff_name);
-      if ($other) {
-       $errors{affiliate_name} = "affiliate name $aff_name is already in use";
-      }
-    }
-    else {
-      $errors{affiliate_name} = "invalid affiliate name, no spaces or special characters are allowed";
-    }
-  }
-  else {
-    undef $aff_name;
-  }
+  $aff_name = _validate_affiliate_name($req, $aff_name, \%errors, $user);
+
+  $class->_save_images($req->cfg, $req->cgi, $user, \%errors);
 
   keys %errors
     and return $class->req_edit($req, undef, \%errors);
@@ -549,6 +539,11 @@ sub req_add {
       $user{$col} = $value;
     }
   }
+
+  my $aff_name = $cgi->param('affiliate_name');
+  $aff_name = _validate_affiliate_name($req, $aff_name, \%errors);
+  defined $aff_name or $aff_name = '';
+
   if (keys %errors) {
     return $class->req_addform($req, undef, \%errors);
   }
@@ -558,6 +553,7 @@ sub req_add {
     $user{previousLogon} = now_datetime;
   $user{keepAddress} = 0;
   $user{wantLetter} = 0;
+  $user{affiliate_name} = $aff_name;
   if ($nopassword) {
     use BSE::Util::Secure qw/make_secret/;
     $user{password} = make_secret($cfg);
@@ -625,5 +621,43 @@ sub save_subs {
   $found;
 }
 
+sub _validate_affiliate_name {
+  my ($req, $aff_name, $errors, $user) = @_;
+
+  my $display = $req->cfg->entry('site users', 'display_affiliate_name',
+                                "Affiliate name");
+  my $required = $req->cfg->entry('site users', 'require_affiliate_name', 0);
+
+  if (defined $aff_name) {
+    $aff_name =~ s/^\s+|\s+$//g;
+    if (length $aff_name) {
+      if ($aff_name =~ /^\w+$/) {
+       my $other = SiteUsers->getBy(affiliate_name => $aff_name);
+       if ($other && (!$user || $other->{id} != $user->{id})) {
+         $errors->{affiliate_name} = "$display $aff_name is already in use";
+       }
+       else {
+         return $aff_name;
+       }
+      }
+      else {
+       $errors->{affiliate_name} = "invalid $display, no spaces or special characters are allowed";
+      }
+    }
+    elsif ($required) {
+      $errors->{affiliate_name} = "$display is a required field";
+    }
+    else {
+      return '';
+    }
+  }
+
+  # always required if making a new user
+  if (!$errors->{affiliate_name} && $required && !$user) {
+    $errors->{affiliate_name} = "$display is a required field";
+  }
+
+  return;
+}
 
 1;
index 041c795..32c3252 100644 (file)
@@ -52,6 +52,7 @@ sub getuser {
   $_[0]{adminuser};
 }
 
+# this needs to become non-admin specific
 sub url {
   my ($self, $action, $params, $name) = @_;
 
index 64a1e51..9877356 100644 (file)
@@ -1,6 +1,6 @@
 package BSE::UI::Affiliate;
 use strict;
-use base qw(BSE::UI::Dispatch);
+use base qw(BSE::UI::Dispatch BSE::UI::SiteuserCommon);
 use BSE::Util::Tags qw(tag_hash);
 use DevHelp::HTML;
 
@@ -235,7 +235,7 @@ sub req_show {
   %acts =
     (
      BSE::Util::Tags->basic(undef, $req->cgi, $req->cfg),
-     siteuser => [ \&tag_hash, $user ],
+     $class->_display_tags($user, $req->cfg),
     );
 
   return $req->dyn_response('affiliate', \%acts);
diff --git a/site/cgi-bin/modules/BSE/UI/SiteuserCommon.pm b/site/cgi-bin/modules/BSE/UI/SiteuserCommon.pm
new file mode 100644 (file)
index 0000000..6fc76c7
--- /dev/null
@@ -0,0 +1,249 @@
+package BSE::UI::SiteuserCommon;
+use strict;
+use DevHelp::HTML;
+use BSE::Util::Tags qw(tag_hash);
+
+use constant MAXWIDTH => 10000;
+use constant MAXHEIGHT => 10000;
+use constant MAXSIZE => 1_000_000;
+use constant MINRATIO => 0;
+use constant MAXRATIO => 1000;
+
+my %image_types =
+  (
+   GIF => 'image/gif',
+   JPG => 'image/jpeg',
+   PNG => 'image/png',
+   TIF => 'image/tiff',
+   BMP => 'image/bmp',
+  );
+
+sub _save_images {
+  my ($class, $cfg, $cgi, $user, $errors) = @_;
+
+  my %images = map { $_->{image_id} => $_ } $user->images;
+  my @templates = $user->images_cfg($cfg);
+  my %replace;
+  my %delete;
+
+  my $image_dir = $cfg->entryVar('paths', 'siteuser_images');
+
+  require DevHelp::FileUpload;
+  require Image::Size;
+
+  my @new_files;
+
+  for my $defn (@templates) {
+    my $id = $defn->{id};
+
+    my $file_param = "image_${id}_file";
+    my $filename = $cgi->param($file_param);
+    my $alt = $cgi->param("image_${id}_alt");
+    my $delete = $cgi->param("image_${id}_delete");
+
+    if ($filename) {
+      my $msg;
+      my ($work_file, $work_fh) = DevHelp::FileUpload->make_img_filename
+       ($image_dir, $filename, \$msg);
+      unless ($work_fh) {
+       $errors->{$file_param} = $msg;
+       next;
+      }
+      my $work_fullname = "$image_dir/$work_file";
+      local $/ = \4096;
+      my $in_fh = $cgi->upload($file_param);
+      my $data;
+      while (defined($data = <$in_fh>)) {
+       print $work_fh $data;
+      }
+      close $work_fh;
+
+      push @new_files, $work_fullname;
+
+      # image parameter validation
+      my ($width, $height, $type) = Image::Size::imgsize($work_fullname);
+      unless (defined $width) {
+       $errors->{$file_param} = "Error determining image size: $type";
+       unlink $work_fullname;
+       next;
+      }
+      unless ($image_types{$type}) {
+       $errors->{$file_param} = "Unsupported image format";
+       unlink $work_fullname;
+       next;
+      }
+      my $space = -s $work_fullname;
+      
+      my $minwidth = $defn->{minwidth} || 1;
+      $minwidth = 1 if $minwidth < 1;
+      my $minheight = $defn->{minheight} || 1;
+      $minheight = 1 if $minheight < 1;
+      my $maxwidth = $defn->{maxwidth} || MAXWIDTH;
+      my $maxheight = $defn->{maxheight} || MAXHEIGHT;
+      my $minratio = $defn->{minratio} || MINRATIO;
+      my $maxratio = $defn->{maxratio} || MAXRATIO;
+      my $maxspace = $defn->{maxspace} || MAXSIZE;
+      my %msg_names = 
+       ( 
+        name => $defn->{description}, 
+        width => $width, 
+        height => $height,
+        minw => $minwidth,
+        maxw => $maxwidth,
+        minh => $minheight,
+        maxh => $maxheight,
+        minr => $minratio,
+        maxr => $maxratio,
+        size => $space,
+        maxs => $maxspace,
+       );
+      
+      if ($width < $minwidth) {
+       $errors->{$file_param} =
+         $defn->{widthsmallerror} || $defn->{smallerror} 
+           || "\${name} image must be at least \${minw} pixels wide";
+      }
+      elsif ($width > $maxwidth) {
+       $errors->{$file_param} =
+         $defn->{widthlargeerror} || $defn->{largeerror} 
+           || "\${name} image can be at most \${maxw} pixels wide";
+      }
+      elsif ($height < $minheight) {
+       $errors->{$file_param} =
+         $defn->{heightsmallerror} || $defn->{smallerror} 
+           || "\${name} image must be at least \${minh} pixels high";
+      }
+      elsif ($height > $maxheight) {
+       $errors->{$file_param} =
+         $defn->{heightlargeerror} || $defn->{largeerror} 
+           || "\${name} image can be at most \${maxh} pixels high";
+      }
+      elsif ($space > $maxspace) {
+       $errors->{$file_param} = 
+         $defn->{spaceerror} ||
+           "\${name} image uses too much disk space";
+      }
+      else {
+       my $ratio = $width / $height;
+       if ($ratio < $minratio || $ratio > $maxratio) {
+         $errors->{$file_param} =
+           $defn->{properror}
+             || "\${name} image is out of proportion";
+       }
+      }
+      if ($errors->{$file_param}) {
+       $errors->{$file_param} =~
+         s/\$\{(\w+)\}/exists $msg_names{$1} ? $msg_names{$1} : "\${$1}"/eg;
+       next;
+      }
+      my %image =
+       (
+        image_id => $id,
+        filename => $work_file,
+        width => $width,
+        height => $height,
+        bytes => $space,
+        content_type => $image_types{$type},
+        alt => defined($alt) ? $alt : '',
+       );
+      $replace{$id} = \%image;
+    }
+    elsif ($delete) {
+      ++$delete{$id} if exists $images{$id};
+    }
+  }
+
+  if (keys %$errors) {
+    unlink @new_files;
+    return;
+  }
+  
+  for my $id ( map $_->{id}, @templates ) {
+    if ($replace{$id}) {
+      $user->set_image($cfg, $id => $replace{$id});
+    }
+    elsif ($delete{$id}) {
+      $user->remove_image($cfg, $id);
+    }
+  }
+}
+
+sub iter_images {
+  my ($siteuser, $cfg) = @_;
+
+  return $siteuser->images_cfg($cfg);
+}
+
+sub tag_siteuser_image {
+  my ($siteuser, $cfg, $images, $imgcfg, $rloaded, $args, 
+      $acts, $name, $templater) = @_;
+
+  my ($image_id, $what) = DevHelp::Tags->get_parms($args, $acts, $templater)
+    or return '';
+
+  unless (keys %$imgcfg) {
+    %$imgcfg = map { $_->{id} => $_ } $siteuser->images_cfg($cfg);
+    %$images = map { $_->{image_id} => $_ } $siteuser->images if keys %$imgcfg;
+  }
+
+  if (!$what) {
+    # just checking if the image exists
+    return exists $images->{$image_id};
+  }
+  else {
+    my $image_cfg = $imgcfg->{$image_id}
+      or return '';
+
+    if (exists $image_cfg->{$what}) {
+      return escape_html($image_cfg->{$what});
+    }
+
+    my $image = $images->{$image_id}
+      or return '';
+
+    if ($what eq 'url') {
+      return escape_html
+       ("/cgi-bin/user.pl?a_image=1&u=$siteuser->{id}&i=$image_id");
+    }
+    if (exists $image->{$what}) {
+      return escape_html($image->{$what});
+    }
+
+    return '';
+  }
+}
+
+sub _edit_tags {
+  my ($class, $siteuser, $cfg) = @_;
+
+  my $images_loaded = 0;
+  my %images;
+  my %imgcfg;
+  my $it = BSE::Util::Iterate->new;
+  return
+    (
+     $it->make_iterator([ \&iter_images, $siteuser, $cfg ],
+                       'imagetemplate', 'imagetemplates' ),
+     siteuser_image => 
+     [ \&tag_siteuser_image, $siteuser, $cfg, \%images, \%imgcfg, 
+       \$images_loaded ],
+    );
+}
+
+sub _display_tags {
+  my ($class, $siteuser, $cfg) = @_;
+
+  my $images_loaded = 0;
+  my %images;
+  my %imgcfg;
+  my $it = BSE::Util::Iterate->new;
+  return
+    (
+     siteuser => [ \&tag_hash, $siteuser ],
+     siteuser_image => 
+     [ \&tag_siteuser_image, $siteuser, $cfg, \%images, \%imgcfg, 
+       \$images_loaded ],
+    );
+}
+
+1;
index 0459d2d..2b797dd 100644 (file)
@@ -1,5 +1,6 @@
 package BSE::UserReg;
 use strict;
+use base qw(BSE::UI::SiteuserCommon);
 use SiteUsers;
 use BSE::Util::Tags qw(tag_error_img);
 use BSE::Template;
@@ -400,6 +401,7 @@ sub show_opts {
      ifRequired =>
      [ \&tag_if_required, $cfg ],
      error_img => [ \&tag_error_img, $cfg, $errors ],
+     $self->_edit_tags($user, $cfg),
     );
 
   my $base = 'user/options';
@@ -525,23 +527,9 @@ sub saveopts {
   }
 
   my $aff_name = $cgi->param('affiliate_name');
-  if (defined $aff_name && length $aff_name) {
-    if ($aff_name =~ /^\s*\w+\s*$/) {
-      $aff_name =~ s/^\s+|\s+$//g;
-      my $other = SiteUsers->getBy(affiliate_name => $aff_name);
-      if ($other) {
-       $errors{affiliate_name} = $msgs->(dupaffiliatename =>
-                                         "affiliate name $aff_name is already in use", $aff_name);
-      }
-    }
-    else {
-      $errors{affiliate_name} = $msgs->(badaffiliatename =>
-                                       "invalid affiliate name, no spaces or special characters are allowed");
-    }
-  }
-  else {
-    undef $aff_name;
-  }
+  $aff_name = _validate_affiliate_name($cfg, $aff_name, \%errors, $msgs, $user);
+
+  $self->_save_images($cfg, $cgi, $user, \%errors);
 
   keys %errors
     and return $self->show_opts($session, $cgi, $cfg, undef, \%errors);
@@ -751,6 +739,10 @@ sub register {
       $user{$col} = $value;
     }
   }
+  my $aff_name = $cgi->param('affiliate_name');
+  $aff_name = _validate_affiliate_name($cfg, $aff_name, \%errors, $msgs);
+  defined $aff_name or $aff_name = '';
+
   if (keys %errors) {
     return $self->show_register($session, $cgi, $cfg, undef, \%errors);
   }
@@ -760,6 +752,7 @@ sub register {
     $user{previousLogon} = now_datetime;
   $user{keepAddress} = 0;
   $user{wantLetter} = 0;
+  $user{affiliate_name} = $aff_name;
   if ($nopassword) {
     use BSE::Util::Secure qw/make_secret/;
     $user{password} = make_secret($cfg);
@@ -1320,4 +1313,83 @@ sub unsub {
   }
 }
 
+sub _validate_affiliate_name {
+  my ($cfg, $aff_name, $errors, $msgs, $user) = @_;
+
+  my $display = $cfg->entry('site users', 'display_affiliate_name',
+                           "Affiliate name");
+  my $required = $cfg->entry('site users', 'require_affiliate_name', 0);
+
+  if (defined $aff_name) {
+    $aff_name =~ s/^\s+|\s+$//g;
+    if (length $aff_name) {
+      if ($aff_name =~ /^\w+$/) {
+       my $other = SiteUsers->getBy(affiliate_name => $aff_name);
+       if ($other && (!$user || $other->{id} != $user->{id})) {
+         $errors->{affiliate_name} = $msgs->(dupaffiliatename =>
+                                           "$display '$aff_name' is already in use", $aff_name);
+       }
+       else {
+         return $aff_name;
+       }
+      }
+      else {
+       $errors->{affiliate_name} = $msgs->(badaffiliatename =>
+                                         "Invalid $display, no spaces or special characters are allowed");
+      }
+    }
+    elsif ($required) {
+      $errors->{affiliate_name} = $msgs->("optsrequired" =>
+                                         "$display is a required field",
+                                         "affiliate_name", $display);
+    }
+    else {
+      return '';
+    }
+  }
+
+  # always required if making a new user
+  if (!$errors->{affiliate_name} && $required && !$user) {
+    $errors->{affiliate_name} = $msgs->("optsrequired" =>
+                                       "$display is a required field",
+                                       "affiliate_name", $display);
+  }
+
+  return;
+}
+
+sub req_image {
+  my ($self, $session, $cgi, $cfg) = @_;
+
+  my $u = $cgi->param('u');
+  my $i = $cgi->param('i');
+  defined $u && $u =~ /^\d+$/ && defined $i && $i =~ /^\w+$/
+    or return $self->show_logon($session, $cgi, $cfg, 
+                               "Missing or bad image parameter");
+
+  my $user = SiteUsers->getByPkey($u)
+    or return $self->show_logon($session, $cgi, $cfg, 
+                               "Missing or bad image parameter");
+  my $image = $user->get_image($i)
+    or return $self->show_logon($session, $cgi, $cfg, 
+                               "Unknown image id");
+  my $image_dir = $cfg->entryVar('paths', 'siteuser_images');
+
+  open IMAGE, "< $image_dir/$image->{filename}"
+    or return $self->show_logon($session, $cgi, $cfg,
+                               "Image file missing");
+  binmode IMAGE;
+  binmode STDOUT;
+    
+  print "Content-Length: $image->{bytes}\r\n";
+  print "Content-Type: $image->{content_type}\r\n";
+  print "\r\n";
+  $|=1;
+  my $data;
+  while (read(IMAGE, $data, 8192)) {
+    print $data;
+  }
+  close IMAGE;
+}
+
 1;
diff --git a/site/cgi-bin/modules/DevHelp/FileUpload.pm b/site/cgi-bin/modules/DevHelp/FileUpload.pm
new file mode 100644 (file)
index 0000000..6e0e9f8
--- /dev/null
@@ -0,0 +1,88 @@
+package DevHelp::FileUpload;
+use strict;
+use IO::File;
+use File::Copy;
+
+=head1 NAME
+
+  DevHelp::FileUpload - tools to maintain a file upload directory
+
+=head1 SYNOPSIS
+
+  use DevHelp::FileUpload;
+
+  my $msg;
+  my ($name, $handle) = 
+    DevHelp::FileUpload->make_img_filename($image_dir, $original_name, \$msg)
+      or die $msg;
+  my $newname = 
+    DevHelp::FileUpload->make_img_copy($image_dir, $oldname, \$msg)
+      or die $msg;
+
+=head1 DESCRIPTION
+
+=over
+
+=item DevHelp::FileUpload->make_img_copy($imgdir, $oldname, \$msg)
+
+=cut
+
+sub make_img_copy {
+  my ($class, $imgdir, $oldname, $rmsg) = @_;
+
+  # remove the time value and optional counter
+  (my $workname = $oldname) =~ s/^\d+_(?:\d+_)?//;
+
+  my ($newname, $fh) = $class->make_img_filename($imgdir, $workname, $rmsg)
+    or return;
+
+  unless (copy("$imgdir/$oldname", $fh)) {
+    $$rmsg = "Cannot copy to new file: $!";
+    close $fh; undef $fh;
+    unlink "$imgdir/$newname";
+    return;
+  }
+    
+  close $fh;
+  undef $fh;
+
+  return $newname;
+}
+
+=item DevHelp::FileUpload->make_img_filename($imgdir, $name, \$msg)
+
+=cut
+
+sub make_img_filename {
+  my ($class, $imgdir, $name, $rmsg) = @_;
+
+  my $basename = '';
+  $name =~ /([\w.-]+)$/ and $basename = $1;
+
+  my $filename = time . '_' . $basename;
+
+  my $fh;
+  my $counter = "";
+  $filename = time . '_' . $counter . '_' . $basename
+    until $fh = IO::File->new("$imgdir/$filename", O_CREAT | O_WRONLY | O_EXCL)
+      or ++$counter > 100;
+
+  unless ($fh) {
+    $$rmsg = "Could not open image file $imgdir/$filename: $!";
+    return;
+  }
+
+  binmode $fh;
+
+  return ($filename, $fh);
+}
+
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
+
+1;
index a99a189..06affde 100644 (file)
@@ -158,9 +158,9 @@ sub send_conf_request {
 sub orders {
   my ($self) = @_;
 
-  require Orders;
+  require BSE::TB::Orders;
 
-  return Orders->getBy(userId => $self->{userId});
+  return BSE::TB::Orders->getBy(userId => $self->{userId});
 }
 
 # check if the user is subscribed to the given subscription
index 13e50aa..f205ae5 100755 (executable)
@@ -39,6 +39,7 @@ my %actions =
    unsub => 'unsub',
    setcookie => 'set_cookie',
    nopassword => 'nopassword',
+   a_image => 'req_image',
   );
 
 my $cgi = CGI->new;
index b15fddd..ace68a9 100644 (file)
@@ -10,6 +10,48 @@ Maybe I'll add some other bits here.
 
 =head1 CHANGES
 
+=head2 0.14_27
+
+=over
+
+=item *
+
+it's now possible to associate images with a site user (member), these
+are editable both by the admin and the user themselves.
+
+They work the same as the nport member images.
+
+By default they are stored in the same location as uploaded files
+(defaulted in the config file.)
+
+Don't forget to change your custom admin edit site user template to
+use the right enctype for the form.
+
+=item *
+
+you can now use siteuser images on the affiliate page.
+
+=item *
+
+SiteUser.pm was still using Orders rather than BSE::TB::Orders <sigh>
+
+=item *
+
+affiliate_name can now be set during registration or during addition
+in the admin interface.
+
+=item *
+
+the require_affiliate_name flag in the config file is now supported
+(it wasn't necessary for the original application)
+
+=item *
+
+[site users].display_affiliate_name is now used in validation errors
+for the affiliate name field.
+
+=back
+
 =head2 0.14_26
 
 =over
index d185957..f16152f 100644 (file)
@@ -85,6 +85,12 @@ implemented.  Default: $IMAGEDIR.
 Local search path for BSE::Custom, or the class configured by
 C<custom_class> in [basic].
 
+=item siteuser_images
+
+Where uploaded siteuser images are stored.  This must be set in the
+config file.  The default bse.cfg include an entry to use the current
+values of [paths].downloads
+
 =back
 
 =head2 [extensions]
@@ -940,6 +946,62 @@ Default: the site base url.
 
 =back
 
+=head2 [BSE Siteuser Images]
+
+Each key is the id of a member image, with a corresponding [BSE
+Siteuser Image I<image_id>] section.  The values are ignored.
+
+=head2 [BSE Siteuser Image I<image_id>]
+
+Provides information about a single member image "template".
+
+=over
+
+=item description
+
+Short description on the image, like "Logo".  Used in error messages.
+
+=item help
+
+Longer description of the image.  Accessible with the member_image tag.
+
+=item minwidth
+
+=item minheight
+
+=item maxwidth
+
+=item maxheight
+
+The minimum and maximum dimensions of the image.
+
+=item widthsmallerror
+
+=item heightsmallerror
+
+=item widthlargeerror
+
+=item heightlargeerror
+
+Error messages displayed in the when the image is outside the
+configured dimensions.
+
+=item largeerror
+
+=item smallerror
+
+Default error messages for the above.
+
+=item maxspace
+
+Maximum storage the image can use in bytes.  Default: 1000000.
+
+=item spaceerror
+
+Error message displayed if the image uses too much storage.
+
+=back
+
 =head1 AUTHOR
 
 Tony Cook <tony@develop-help.com>
index 2029a1e..4813b81 100644 (file)
             </td>
             <td bgcolor="#FFFFFF"><:help editsiteuser billEmail:>  <:error_img billEmail:></td>
           </tr>
+          <tr> 
+            <th bgcolor="#FFFFFF" align="left">Affiliate Name: </th>
+            <td bgcolor="#FFFFFF"> 
+              <input type="text" name="affiliate_name" value="<:old affiliate_name :>" /><:ifRequired affiliate_name:>*<:or:><:eif:>
+            </td>
+            <td bgcolor="#FFFFFF"><:help editsiteuser affiliate_name:>  <:error_img affiliate_name:></td>
+          </tr>
           <tr> 
             <th bgcolor="#FFFFFF" align="left" valign="top">Admin Notes: </th>
             <td bgcolor="#FFFFFF"> 
index a431cdd..0e840a4 100644 (file)
@@ -10,7 +10,7 @@
 <p><b><:message:></b></p>
 <:or:><:eif:> 
 
-<form method="POST" action="<:script:>">
+<form method="POST" action="<:script:>" enctype="multipart/form-data">
 <input type="hidden" name="id" value="<:siteuser id:>" />
   <table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" class="table">
     <tr> 
             <td bgcolor="#FFFFFF" valign="top"><:help editsiteuser subscriptions:></td>
           </tr>
 <:or Subscriptions:><:eif Subscriptions:>
+<:iterator begin imagetemplates:>
+          <tr> 
+            <th bgcolor="#FFFFFF" align="left"> <:imagetemplate description:>: </th>
+            <td bgcolor="#FFFFFF"> 
+              <input type="file" name="image_<:imagetemplate id:>_file" /><br />
+              Alt: <input type="text" name="image_<:imagetemplate id:>_alt" value="<:siteuser_image [imagetemplate id] alt:>" /><br />
+       <:ifSiteuser_image [imagetemplate id]:><input type="checkbox" name="image_<:imagetemplate id:>_delete" value="1" /> Delete<br /><img src="<:siteuser_image [imagetemplate id] url:>" /><:or:><:eif:>
+              </td>
+            <td bgcolor="#FFFFFF"> <:help editsiteuser images:>  <:error_img password:></td>
+          </tr>
+<:iterator end imagetemplates:>
 <:if UserCan siteuser_changepw:>
 <:if Cfg "site users" nopassword:><:or Cfg:>
           <tr> 
index b033c3b..72f6e24 100644 (file)
@@ -1,2 +1,5 @@
 <:wrap xbase.tmpl title=>"Affiliate page":>
 <p>This is a placeholder affiliate page for user <:siteuser userId:>.</p>
+<:if Siteuser_image logo:>
+<img src="<:siteuser_image logo url:>" width="<:siteuser_image logo width:>" height="<:siteuser_image logo height:>" alt="<:siteuser_image logo alt:>" />
+<:or Siteuser_image:><:eif Siteuser_image:>
\ No newline at end of file
index 1a5ebd8..df81ecc 100644 (file)
       </td>
     </tr>
     <:or Message:><:eif Message:> 
+<:if Imagetemplates:>
+    <tr> 
+      <td colspan="2" height="20" align="center"> 
+        <a href="<:script:>?show_opts=1&_t=images">Manage Logos</a>
+      </td>
+    </tr>
+<:or Imagetemplates:><:eif Imagetemplates:>
     <form action="/cgi-bin/user.pl" method="post">
     <input type="hidden" name="saveSubscriptions" value="1" />
     <:if Cfg "site users" nopassword:>
diff --git a/site/templates/user/options_images_base.tmpl b/site/templates/user/options_images_base.tmpl
new file mode 100644 (file)
index 0000000..07d1da3
--- /dev/null
@@ -0,0 +1,75 @@
+<:wrap base.tmpl:>
+<div align=center class="useroptions"> 
+<:if Cfg "site users" nopassword:><:or Cfg:>
+  <table border="0" cellspacing="0" cellpadding="0">
+    <tr> 
+      <td> 
+        <form name="yourorders" method="post" action="<:script:>">
+          <input type="submit" name="Submit" value="View your account" class="user-buttons" />
+          <input type="hidden" name="userpage" value="1" />
+        </form>
+      </td>
+      <:ifCfg shop enabled:><td> 
+        <form name="ff" method="post" action="/cgi-bin/shop.pl">
+          <input type="submit" name="cart" value="View shopping cart" class="user-buttons" />
+        </form>
+      </td><:or:><:eif:>
+    </tr>
+  </table>
+  <br />
+<:eif Cfg:>
+  <table width="250">
+    <tr> 
+      <th colspan="2" height="20" class="thead"> 
+        <p>User Options - Images</p>
+      </th>
+    </tr>
+    <tr> 
+      <td colspan="2" align="center"> 
+        <p><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2">Hello <:ifUser name1:><:user name1:> <:user name2:><:or:><:user 
+          userId:><:eif:></font></b></p>
+        <p><font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#999999">Last logged in: <:date user previousLogon:><br>
+          Registered since: <:date user whenRegistered:></font><br>
+          <br>
+        </p>
+        </td>
+    </tr>
+    <:if Message:> 
+    <tr> 
+      <td colspan="2" align="center"> 
+        <p><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><b>Error: 
+          <:message:></b></font></p>
+      </td>
+    </tr>
+    <:or Message:><:eif Message:> 
+    </tr>
+      <tr> 
+        <td colspan="2" height="20" align="center"><br>
+          <br>
+          <a href="<:script:>?show_opts=1">Return to Main Options</a></td>
+      </tr>
+    <form action="/cgi-bin/user.pl" method="post" enctype="multipart/form-data">
+    <input type="hidden" name="_t" value="billing" />
+    <:if Cfg "site users" nopassword:>
+    <input type="hidden" name="u" value="<:user id:>" />
+    <input type="hidden" name="p" value="<:user password:>" />
+    <input type="hidden" name="r" value="<:script:>?show_opts=<:user password:>&amp;u=<:user id:>&_t=saved" />
+    <:or Cfg:><:eif Cfg:>
+<:iterator begin imagetemplates:>
+      <tr>
+         <th><:imagetemplate description:>:</th>
+        <td><input type="file" name="image_<:imagetemplate id:>_file" /><br />
+              Alt: <input type="text" name="image_<:imagetemplate id:>_alt" value="<:siteuser_image [imagetemplate id] alt:>" /><br />
+       <:ifSiteuser_image [imagetemplate id]:><input type="checkbox" name="image_<:imagetemplate id:>_delete" value="1" /> Delete<:or:><:eif:>
+         </td>
+        <td><:ifSiteuser_image [imagetemplate id]:><img src="<:siteuser_image [imagetemplate id] url:>" /><:or:><:eif:></td>
+      </tr>
+<:iterator end imagetemplates:>
+      <tr> 
+        <td colspan="2" align="right"> 
+          <input type="submit" name="saveopts" value="Save Options" class="user-buttons" />
+        </td>
+      </tr>
+    </form>
+  </table>
+</div>
index 8ee15f1..0338ee4 100644 (file)
           <input type="text" name="facsimile" value="<:old facsimile:>" size="32" maxlength="80" /> <:error_img facsimile:><:ifRequired facsimile:><font face="Verdana, Arial, Helvetica, sans-serif" size="-2">*</font><:or:><:eif:>
         </td>
       </tr>
+      <tr> 
+        <th nowrap align="left"><b><font face="Verdana, Arial, Helvetica, sans-serif" size="-2">Affiliate Name:</font></b></th>
+        <td width="100%" nowrap="nowrap"> 
+          <input type="text" name="affiliate_name" value="<:old affiliate_name:>" size="32" maxlength="80" /> <:error_img affiliate_name:><:ifRequired affiliate_name:><font face="Verdana, Arial, Helvetica, sans-serif" size="-2">*</font><:or:><:eif:>
+        </td>
+      </tr>
 <:or Cfg:><:eif Cfg:>
       <tr> 
         <td colspan="2" align="right"> 
index 3982a6f..f8b4552 100644 (file)
--- a/test.cfg
+++ b/test.cfg
@@ -47,7 +47,6 @@ debug.cookies=0
 debug.logon_cookies=0
 site users.billing_on_main_opts=0
 #site users.user_register=0
-
 #paths.libraries=/home/tony/dev/bse/tandb_dealer/cvs/modules
 #paths.siteuser_passwd=/home/httpd/bsetest/data/supasswd
 #custom.user_auth=1
@@ -60,6 +59,7 @@ payment type names.12=EmailProForma
 payment type required.11=facsimile
 
 affiliate.prompt_name=1
+site users.require_affiliate_name=0
 
 dealer.bsb=999999
 dealer.accountno=77777777
@@ -84,3 +84,6 @@ subscriptions.text_link_list=[$3] '$1'$n   => $2
 site.secureadmin=0
 
 debug.dump_session=0
+
+bse siteuser images.logo=1
+bse siteuser image logo.description=Your Logo