0.15_54 release r0_15_54
authorTony Cook <tony@develop-help.com>
Wed, 21 Feb 2007 05:26:43 +0000 (05:26 +0000)
committertony <tony@45cb6cf1-00bc-42d2-bb5a-07f51df49f94>
Wed, 21 Feb 2007 05:26:43 +0000 (05:26 +0000)
32 files changed:
Makefile
schema/bse.sql
site/cgi-bin/admin/makeIndex.pl
site/cgi-bin/modules/Article.pm
site/cgi-bin/modules/BSE/DB/Mysql.pm
site/cgi-bin/modules/BSE/Edit/Article.pm
site/cgi-bin/modules/BSE/Edit/Product.pm
site/cgi-bin/modules/BSE/Generate/Seminar.pm
site/cgi-bin/modules/BSE/Permissions.pm
site/cgi-bin/modules/BSE/Search/BSE.pm
site/cgi-bin/modules/BSE/TB/Order.pm
site/cgi-bin/modules/BSE/TB/OrderItem.pm
site/cgi-bin/modules/BSE/Template.pm
site/cgi-bin/modules/BSE/UI/Shop.pm
site/cgi-bin/modules/BSE/Util/Tags.pm
site/cgi-bin/modules/DevHelp/Tags.pm
site/cgi-bin/modules/Generate.pm
site/cgi-bin/modules/Generate/Product.pm
site/cgi-bin/modules/Product.pm
site/cgi-bin/page.pl
site/cgi-bin/shop.pl
site/docs/bse.pod
site/docs/config.pod
site/htdocs/admin/help/product.html
site/templates/admin/add_product.tmpl
site/templates/admin/edit_1.tmpl
site/templates/admin/edit_product.tmpl
site/templates/base.tmpl
site/templates/checkoutnew_base.tmpl
site/util/upgrade_mysql.pl
t/t20gen.t
test.cfg

index e163552..c881a79 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.15_53
+VERSION=0.15_54
 DISTNAME=bse-$(VERSION)
 DISTBUILD=$(DISTNAME)
 DISTTAR=../$(DISTNAME).tar
index 812c745..6e81db9 100644 (file)
@@ -21,8 +21,8 @@ CREATE TABLE article (
 
   -- position of first image for this article
   imagePos char(2) not null,
-  release datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
-  expire datetime DEFAULT '9999-12-31 23:59:59' NOT NULL,
+  `release` datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
+  expire datetime DEFAULT '2999-12-31 23:59:59' NOT NULL,
   keyword varchar(255) not null default '',
 
   -- the template in $TMPLDIR used to generate this as HTML
@@ -87,6 +87,9 @@ CREATE TABLE article (
   metaDescription varchar(255) default '' not null,
   metaKeywords varchar(255) default '' not null,
 
+  -- x just so we don't get a name issue with product
+  summaryx varchar(255) default '' not null,
+
   PRIMARY KEY (id),
 
   -- if we keep id in the indexes MySQL will sometimes be able to
@@ -95,7 +98,7 @@ CREATE TABLE article (
   -- Unfortunately MySQL can only do this on fixed-width columns
   -- other databases may not need the id in the index, and may also be
   -- able to handle the variable length columns in the index
-  INDEX article_date_index (release,expire, id),
+  INDEX article_date_index (`release`,expire, id),
   INDEX article_displayOrder_index (displayOrder),
   INDEX article_parentId_index (parentId),
   INDEX article_level_index (level, id)
@@ -167,6 +170,8 @@ create table product (
   subscription_period integer not null default 0,
   subscription_usage integer not null default 3,
   subscription_required integer not null default -1,
+
+  product_code varchar(80) not null,
   
   primary key(articleId)
 );
@@ -284,6 +289,8 @@ create table orders (
   delivStreet2 varchar(127) not null default '',
   billStreet2 varchar(127) not null default '',
 
+  purchase_order varchar(80) not null default '',
+
   primary key (id),
   index order_cchash(ccNumberHash),
   index order_userId(userId, orderDate)
@@ -329,6 +336,8 @@ create table order_item (
   -- session for a seminar
   session_id integer not null default -1,
 
+  product_code varchar(80) not null default '',
+
   primary key (id),
   index order_item_order(orderId, id)
 );
@@ -345,7 +354,7 @@ create table other_parents (
   -- order as seen from the child
   childDisplayOrder integer not null,
 
-  release datetime default '0000-00-00 00:00:00' not null,
+  `release` datetime default '0000-00-00 00:00:00' not null,
   expire datetime default '9999-12-31 23:59:59' not null,
 
   primary key(id),
index 66a532d..e60f3a7 100755 (executable)
@@ -31,6 +31,9 @@ my %scores =
    file_displayName => 2,
    file_description=>2,
    file_notes => 1,
+   summary => 0,
+   description => 0,
+   product_code => 0,
   );
 
 for my $name (keys %scores) {
@@ -89,6 +92,8 @@ sub makeIndex {
     next unless $gen->visible($article) or $do_search{$sectionid};
     
     next if $dont_search{$sectionid};
+
+    $article = $gen->get_real_article($article);
     
     my %fields;
     for my $field (sort { $scores{$b} <=> $scores{$a} } keys %scores) {
index fffe9b4..cff79db 100644 (file)
@@ -15,7 +15,7 @@ sub columns {
     customInt1 customInt2 customInt3 customInt4 
     lastModifiedBy created createdBy author pageTitle
     force_dynamic cached_dynamic inherit_siteuser_rights
-    metaDescription metaKeywords/;
+    metaDescription metaKeywords summary/;
 }
 
 sub numeric {
index e115066..0c72892 100644 (file)
@@ -18,9 +18,9 @@ my %statements =
   (
    Articles => 'select * from article',
    replaceArticle =>
-     'replace article values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+     'replace article values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    addArticle =>  
-     'insert article values (null, ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+     'insert article values (null, ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    deleteArticle => 'delete from article where id = ?',
    getArticleByPkey => 'select * from article where id = ?',
    
@@ -70,9 +70,9 @@ SQL
    searchIndexWC => 'select * from searchindex where id like ?',
    
    Products=> 'select article.*, product.* from article, product where id = articleId',
-   addProduct => 'insert product values(?,?,?,?,?,?,?,?,?,?,?)',
+   addProduct => 'insert product values(?,?,?,?,?,?,?,?,?,?,?,?)',
    getProductByPkey => 'select article.*, product.* from article, product where id=? and articleId = id',
-   replaceProduct => 'replace product values(?,?,?,?,?,?,?,?,?,?,?)',
+   replaceProduct => 'replace product values(?,?,?,?,?,?,?,?,?,?,?,?)',
    'Products.stepProducts' => <<EOS,
 select ar.*, pr.* from article ar, product pr, other_parents op
    where ar.id = pr.articleId and op.childId = ar.id and op.parentId = ?
@@ -95,9 +95,9 @@ SQL
    Orders => 'select * from orders',
    getOrderByPkey => 'select * from orders where id = ?',
    getOrderItemByOrderId => 'select * from order_item where orderId = ?',
-   addOrder => 'insert orders values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
-   replaceOrder => 'replace orders values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
-   addOrderItem => 'insert order_item values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+   addOrder => 'insert orders values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+   replaceOrder => 'replace orders values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+   addOrderItem => 'insert order_item values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    getOrderByUserId => 'select * from orders where userId = ?',
    deleteOrdersItems => 'delete from order_item where orderId = ?',
 
@@ -523,6 +523,9 @@ sub _single
     my $dbh = DBI->connect_cached( $DSN, $UN, $PW)
       or die "Cannot connect to database: $DBI::errstr";
     
+    # this might fail, but I don't care
+    $dbh->do("set session sql_mode='ansi_quotes'");
+
     $self = bless { dbh => $dbh }, $class;
   }
   $self;
index f59913d..a9cc258 100644 (file)
@@ -11,11 +11,31 @@ use BSE::CfgInfo qw(custom_class admin_base_url cfg_image_dir);
 use BSE::Util::Iterate;
 use BSE::Template;
 
+sub not_logged_on {
+  my ($self, $req) = @_;
+
+  if (() = $req->cgi->param('_')) {
+    # this check doesn't seem to work on IE:
+    # $ENV{HTTP_X_REQUESTED_WITH} =~ /XMLHttpRequest/) {
+    # AJAX/Prototype request
+    return
+      {
+       content => 'Access Forbidden: login timed out',
+       headers => [
+                  "Status: 403", # forbidden
+                 ],
+      };
+  }
+  else {
+    BSE::Template->get_refresh($req->url('logon'), $req->cfg);
+  }
+}
+
 sub article_dispatch {
   my ($self, $req, $article, $articles) = @_;
 
   BSE::Permissions->check_logon($req)
-    or return BSE::Template->get_refresh($req->url('logon'), $req->cfg);
+    or return $self->not_logged_on($self);
 
   my $cgi = $req->cgi;
   my $action;
@@ -83,6 +103,9 @@ sub article_actions {
      hide => 'hide',
      unhide => 'unhide',
      a_thumb => 'req_thumb',
+     a_ajax_get => 'req_ajax_get',
+     a_ajax_save_body => 'req_ajax_save_body',
+     a_ajax_set => 'req_ajax_set',
     );
 }
 
@@ -2964,6 +2987,163 @@ sub validate_image_name {
   1; # no extra validation
 }
 
+sub req_ajax_get {
+  my ($self, $req, $article, $articles, @extras) = @_;
+
+  my $field_name = $req->cgi->param('field');
+  unless ($field_name && exists $article->{$field_name}) {
+    print STDERR "req_ajax_get: missing or invalid field parameter\n";
+    return {
+           contant => 'Invalid or missing field name',
+           headers => [
+                       "Status: 187" # bad request
+                      ],
+          };
+  }
+
+  my $value = $article->{$field_name};
+  defined $value or $value = '';
+
+  my $charset = $req->cfg->entry('html', 'charset', 'iso-8859-1');
+  
+  # re-encode to utf8
+  require Encode;
+  Encode::from_to($value, $charset, 'utf8');
+
+  # make some content
+  return
+    {
+     content => $value,
+     type => 'text/plain; charset=utf-8',
+    };
+}
+
+sub req_ajax_save_body {
+   my ($self, $req, $article, $articles, @extras) = @_;
+
+   my $cfg = $req->cfg;
+   my $cgi = $req->cgi;
+
+   $cgi->charset('utf-8');
+
+   # newer versions of CGI.pm will decode the content as UTF8 if we
+   # do the above
+   my $body = $cgi->param('body');
+
+   my $charset = $req->cfg->entry('html', 'charset', 'iso-8859-1');
+  
+   # convert it to our working charset
+   # any characters that don't convert are replaced by some 
+   # substitution character, not defined by the documentation
+   require Encode;
+   $body = Encode::encode($charset, $body);
+
+   $article->{body} = $body;
+   $article->{lastModified} = now_sqldatetime();
+   my $user = $req->getuser;
+   $article->{lastModifiedBy} = $user ? $user->{logon} : '';
+   $article->save;
+
+   my @extra_regen;
+   @extra_regen = $self->update_child_dynamic($article, $articles, $req);
+
+   if ($Constants::AUTO_GENERATE) {
+     require Util;
+     Util::generate_article($articles, $article);
+     for my $regen_id (@extra_regen) {
+       my $regen = $articles->getByPkey($regen_id);
+       Util::generate_low($articles, $regen, $self->{cfg});
+     }
+   }
+   # we need the formatted body as the result
+   my $genname = $article->{generator};
+   eval "use $genname";
+   $@ and die "Error on use $genname: $@";
+   my $gen = $genname->new(article => $articles, cfg => $cfg, top => $article);
+   my %acts;
+   %acts = $gen->baseActs($articles, \%acts, $article, 0);
+   my $template = "<:body:>";
+   my $formatted = BSE::Template->replace($template, $req->cfg, \%acts);
+
+   return
+     {
+      content => $formatted,
+      type => BSE::Template->html_type($cfg),
+     };
+}
+
+my %settable_fields = qw(title keyword author pageTitle);
+  
+
+sub req_ajax_set {
+   my ($self, $req, $article, $articles, @extras) = @_;
+
+   my $cfg = $req->cfg;
+   my $cgi = $req->cgi;
+
+   my $field = $cgi->param('field');
+
+   unless ($field && $settable_fields{$field}) {
+    return {
+           contant => 'Invalid or missing field name',
+           headers => [
+                       "Status: 187" # bad request
+                      ],
+          };
+   }
+
+   $cgi->charset('utf-8');
+
+   # newer versions of CGI.pm will decode the content as UTF8 if we
+   # do the above
+   my $value = $cgi->param('value');
+
+   # hack - validate it if it's the title
+   if ($field eq 'title') {
+     if ($value !~ /\S/) {
+       return {
+              contant => 'Invalid or missing field name',
+              headers => [
+                          "Status: 187" # bad request
+                         ],
+             };
+     }
+   }
+
+   my $charset = $req->cfg->entry('html', 'charset', 'iso-8859-1');
+  
+   # convert it to our working charset
+   # any characters that don't convert are replaced by some 
+   # substitution character, not defined by the documentation
+   require Encode;
+   $value = Encode::encode($charset, $value);
+
+   $article->{$field} = $value;
+   $article->{lastModified} = now_sqldatetime();
+   my $user = $req->getuser;
+   $article->{lastModifiedBy} = $user ? $user->{logon} : '';
+   $article->save;
+
+   my @extra_regen;
+   @extra_regen = $self->update_child_dynamic($article, $articles, $req);
+
+   if ($Constants::AUTO_GENERATE) {
+     require Util;
+     Util::generate_article($articles, $article);
+     for my $regen_id (@extra_regen) {
+       my $regen = $articles->getByPkey($regen_id);
+       Util::generate_low($articles, $regen, $self->{cfg});
+     }
+   }
+   return
+     {
+      content => $value,
+      type => BSE::Template->html_type($cfg),
+     };
+}
+
 1;
 
 =head1 NAME
index 5ab578c..9556450 100644 (file)
@@ -271,10 +271,17 @@ sub _fill_product_data {
       or $src->{leadTime} = 0;
     $data->{leadTime} = $src->{leadTime};
   }
-  if (exists $src->{summary} && length $src->{summary}) {
+  if (exists $src->{description} && length $src->{description}) {
     if ($data->{id}) {
-      if ($req->user_can('edit_field_edit_summary', $data)) {
-       $data->{summary} = $src->{summary};
+      if ($req->user_can('edit_field_edit_description', $data)) {
+       $data->{description} = $src->{description};
+      }
+    }
+  }
+  if (exists $src->{product_code} && length $src->{product_code}) {
+    if ($data->{id}) {
+      if ($req->user_can('edit_field_edit_product_code', $data)) {
+       $data->{product_code} = $src->{product_code};
       }
     }
   }
index 7c165da..54314f5 100644 (file)
@@ -49,4 +49,10 @@ sub iter_location_sessions {
   $seminar->future_location_sessions($$rlocation);
 }
 
+sub get_real_article {
+  my ($self, $article) = @_;
+
+  return BSE::TB::Seminars->getByPkey($article->{id});
+}
+
 1;
index 2120402..f375a83 100644 (file)
@@ -5,8 +5,6 @@ use strict;
 my @checks =
   qw(
      edit_delete_article
-     edit_field_edit_title
-     edit_field_edit_summary
      edit_add_child
      );
 my %checks = map { $_=> $_, "bse_$_" => $_ } @checks;  
@@ -430,28 +428,6 @@ sub check_edit_delete_article {
   return 1;
 }
 
-sub check_edit_field_edit_title {
-  my ($self, $user, $article, $action, $rmsg) = @_;
-
-  if (_is_product_and_in_use($article)) {
-    $$rmsg = "There are orders for this product.  The title cannot be changed.";
-    return;
-  }
-
-  return 1;
-}
-
-sub check_edit_field_edit_summary {
-  my ($self, $user, $article, $action, $rmsg) = @_;
-  
-  if (_is_product_and_in_use($article)) {
-    $$rmsg = "There are orders for this product.  The summary cannot be changed.";
-    return;
-  }
-
-  return 1;
-}
-
 sub check_edit_add_child {
   my ($self, $user, $article, $action, $rmsg) = @_;
 
index 64b5a7e..8bbda90 100644 (file)
@@ -150,12 +150,12 @@ sub search {
   SWITCH: for ($date) {
     $_ eq 'ar' # been released
       && do {
-       $sql .= " and $now between release and expire";
+       $sql .= " and $now between \"release\" and expire";
        last SWITCH;
       };
     /^r(\d+)$/ # released in last N days
       && do {
-       $sql .= " and release > "._sql_date(time - $oneday * $1);
+       $sql .= " and \"release\" > "._sql_date(time - $oneday * $1);
        last SWITCH;
       };
     /^e(\d+)$/ # expired in last N days
index 539e88e..8ed1c21 100644 (file)
@@ -24,7 +24,7 @@ sub columns {
            delivMobile billMobile
            ccOnline ccSuccess ccReceipt ccStatus ccStatusText
            ccStatus2 ccTranId complete delivOrganization billOrganization
-           delivStreet2 billStreet2/;
+           delivStreet2 billStreet2 purchase_order/;
 }
 
 =item siteuser
@@ -122,6 +122,7 @@ sub valid_fields {
      billMobile => { description => 'Billing Mobile Number',
                     rules=>'phone' },
      instructions => { description => 'Instructions' },
+     purchase_order => { description => 'Purchase Order No' },
     );
 
   for my $field (keys %fields) {
index 5f3c335..ace43e1 100644 (file)
@@ -9,7 +9,7 @@ sub columns {
   return qw/id productId orderId units price wholesalePrice gst options
             customInt1 customInt2 customInt3 customStr1 customStr2 customStr3
             title summary subscription_id subscription_period max_lapsed
-            session_id/;
+            session_id product_code/;
 }
 
 1;
index 75d1f88..596cc9f 100644 (file)
@@ -188,6 +188,16 @@ sub output_result {
   push @{$result->{headers}}, "Content-Type: $result->{type}"
     if $result->{type};
   push @{$result->{headers}}, $req->extra_headers;
+  my $add_cache_control = 1;
+  for my $header (@{$result->{headers}}) {
+    if ($header =~ /^cache-control:/i) {
+      $add_cache_control = 0;
+      last;
+    }
+  }
+  if ($add_cache_control) {
+    push @{$result->{headers}}, "Cache-Control: no-cache";
+  }
   if (exists $ENV{GATEWAY_INTERFACE}
       && $ENV{GATEWAY_INTERFACE} =~ /^CGI-Perl\//) {
     require Apache;
index b9acee2..6411fdb 100644 (file)
@@ -612,6 +612,7 @@ sub req_payment {
   
   my $cust_class = custom_class($req->cfg);
   eval {
+    local $SIG{__DIE__};
     my %custom = %{$session->{custom}};
     $cust_class->order_save($cgi, $order_values, \@items, \@products, 
                            \%custom, $cfg);
@@ -864,6 +865,7 @@ sub req_orderdone {
      #ifSubscribingTo => [ \&tag_ifSubscribingTo, \%subscribing_to ],
      session => [ \&tag_session, \$item, \$sem_session ],
      location => [ \&tag_location, \$item, \$location ],
+     msg => '',
     );
   for my $type (@pay_types) {
     my $id = $type->{id};
@@ -1256,6 +1258,7 @@ sub _fillout_order {
 
   # if it sets shipping cost it must also update the total
   eval {
+    local $SIG{__DIE__};
     my %custom = %{$session->{custom}};
     $cust_class->order_save($cgi, $values, $items, $items, 
                            \%custom, $cfg);
index a1a1f47..5917bf1 100644 (file)
@@ -71,6 +71,7 @@ sub tag_adminbase {
 sub static {
   my ($class, $acts, $cfg) = @_;
 
+  my $static_ajax = $cfg->entry('basic', 'staticajax', 0);
   require BSE::Util::Iterate;
   my $it = BSE::Util::Iterate->new;
   return
@@ -274,8 +275,17 @@ sub static {
      # report conflicts with a tag name used within reports
      subreport => [ \&tag_report, $cfg ],
 
-     ajax => '',
-     ifAjax => 0,
+     (
+      $static_ajax 
+      ? (
+        ajax => [ \&tag_ajax, $cfg ],
+        ifAjax => 1,
+       )
+      : (
+        ajax => '',
+        ifAjax => 0,
+       )
+      ),
 
      _format => 
      sub {
@@ -441,7 +451,7 @@ sub basic {
      dynreplace => \&tag_replace,
      dyntoday => \&tag_today,
      dynreport => [ \&tag_report, $cfg ],
-     ajax => [ \&tag_ajax, $cfg ],
+     ajax => [ \&tag_ajax_dynamic, $cfg ],
      ifAjax => [ \&tag_ifAjax, $cfg ],
     );
 }
@@ -902,11 +912,17 @@ sub tag_ifAjax {
   return _if_ajax($cfg) ? 1 : 0;
 }
 
-sub tag_ajax {
+sub tag_ajax_dynamic {
   my ($cfg, $args, $acts, $tag_name, $templater) = @_;
 
   return '' unless _if_ajax($cfg);
-  
+
+  return tag_ajax($cfg, $args, $acts, $tag_name, $templater);
+}
+
+sub tag_ajax {
+  my ($cfg, $args, $acts, $tag_name, $templater) = @_;
+
   my ($name, $arg_rest) = split ' ', $args, 2;
  
   my $defn = $cfg->entry('ajax definitions', $name)
index f862492..180bf36 100644 (file)
@@ -343,7 +343,9 @@ sub get_parms {
                        (
                         (?:\s+
                          (?:
-                          [^\s\[\]]\S*
+                          [^\s\[\]]+
+                           |
+                          \"[^"]*\"
                           |
                           \[[^\]\[]+?\]
                          )
index 31c061d..6d88cce 100644 (file)
@@ -719,6 +719,12 @@ sub _format_image {
   }
 }
 
+sub get_real_article {
+  my ($self, $article) = @_;
+
+  return $article;
+}
+
 1;
 
 __END__
index 3ee5ea0..567a244 100644 (file)
@@ -98,6 +98,12 @@ sub visible {
   return $article->{listed};
 }
 
+sub get_real_article {
+  my ($self, $article) = @_;
+
+  return Products->getByPkey($article->{id});
+}
+
 1;
 
 __END__
index 29bdb75..b6c7c71 100644 (file)
@@ -12,9 +12,9 @@ use constant SUBUSAGE_EITHER => 3;
 
 sub columns {
   return ($_[0]->SUPER::columns(), 
-         qw/articleId summary leadTime retailPrice wholesalePrice gst options
+         qw/articleId description leadTime retailPrice wholesalePrice gst options
              subscription_id subscription_period subscription_usage
-             subscription_required/ );
+             subscription_required product_code/ );
 }
 
 sub bases {
index 0af05cf..47578b6 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 # -d:ptkdb
-BEGIN { $ENV{DISPLAY} = '192.168.32.15:0.0' }
+BEGIN { $ENV{DISPLAY} = '192.168.32.50:0.0' }
 use strict;
 use FindBin;
 use lib "$FindBin::Bin/modules";
index 6619947..bf5be09 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 # -d:ptkdb
-BEGIN { $ENV{DISPLAY} = '192.168.32.15:0.0' }
+BEGIN { $ENV{DISPLAY} = '192.168.32.50:0.0' }
 use strict;
 use FindBin;
 use lib "$FindBin::Bin/modules";
index 437c1cf..04e2e07 100644 (file)
@@ -10,6 +10,68 @@ Maybe I'll add some other bits here.
 
 =head1 CHANGES
 
+=head2 0.15_54
+
+=over
+
+=item *
+
+orders now have a purchase_order field.
+
+=item *
+
+products now have a product_code field.  This is transferred to order
+items when they are ordered.
+
+=item *
+
+added a summary field to articles.  The old product summary field is
+now known as description, though the in database name of the column
+hasn't changed.
+
+=item *
+
+search indexing of the product_code, summary and description fields
+are controllable by the config file, as for the indexable article
+fields.
+
+=item *
+
+the ajax tags can be enabled for static pages 
+
+=item *
+
+we now set ansi_quote mode when connecting to a mysql database, so we
+can use portal identifier quoting in queries.
+
+=item *
+
+the handling of column defaults has changed for upgrade_mysql.pl to
+deal with some mysql 5 issues.  Be aware of this and backup your
+database before upgrading.
+
+=item *
+
+the product title and description (previously summary) fields are now
+editable on products that have been ordered previously
+
+=item *
+
+most dynamic output now has a "Cache-Control: no-cache" header, which
+should prevent caching by over-zealous UAs.
+
+=item *
+
+added new targets to cgi-bin/admin/add.pl to support ajax.
+
+=item *
+
+parsing of [] constructs in tags has changed to require spaces around
+subsidiary [].  If you have strings containing [] characters as
+arguments you will need to add "" around them.
+
+=back
+
 =head2 0.15_53
 
 =over
index f108103..b302fb9 100644 (file)
@@ -243,6 +243,10 @@ from BSE::CustomBase.  Default: BSE::Custom.
 If this is true, then pre-generation for dynamic pages will be delayed
 until the page is displayed to a user.  Default: off.
 
+=item staticajax
+
+If true, the ifAjax and ajax tags will be active for static pages.
+
 =back
 
 =head2 [mail]
@@ -802,15 +806,19 @@ default scores for each field in the articles.
 
 The default scores are:
 
-  Field   Score
-  -----   -----
-  title     5
-  body      3
-  keyword   4
-
-A special key C<file_description> can be used here to set the score
-for indexing downloadable file descriptions, which aren't indexed by
-default.  A good value is probably 2 or 1.
+  Field           Score  Notes
+  -----           -----  -----
+  title             5
+  body              3
+  keyword           4
+  pageTitle         5
+  author            4
+  summary           0
+  description       0    Products only
+  product_code      0    Products only
+  file_displayName  2    displayName for files
+  file_description  2    description for files
+  file_notes        1    notes for files
 
 =head2 [article flags]
 
index 608cc7f..101126e 100644 (file)
@@ -11,19 +11,13 @@ Transitional//EN">
 <div>
   <h2><a name="title"></a>Title</h2>
 
-  <p>The name of the product (NB: the title 
-cannot be changed once an order has 
-    been placed that includes 
-this product). (The &#145;title&#146; is indexed by the built-in search engine).</p>
+  <p>The name of the product. (The &#145;title&#146; is indexed by the built-in search engine).</p>
 
 </div>
 
 <div>
   <h2><a name="summary"></a>Summary</h2>
-  <p>The extended name of the product 
-(NB: the summary cannot be changed once 
-    an order has been placed 
-that includes this product).</p>
+  <p>The extended name of the product.</p>
 
 </div>
 
index dc7798b..705b1a4 100644 (file)
       <td>
         <table border=0 cellspacing="1" cellpadding="6">
           <tr> 
-            <th nowrap align="left" bgcolor="#FFFFFF">Title*:</th>
+            <th nowrap align="left" bgcolor="#FFFFFF">Title:</th>
             <td nowrap bgcolor="#FFFFFF"> 
               <input type="text" name="title" value="<:old title:>" size=60><:error_img title:>
             </td>
             <td nowrap bgcolor="#FFFFFF"><:help product title:></td>
           </tr>
           <tr> 
-            <th nowrap align="left" bgcolor="#FFFFFF">Summary*:</th>
+            <th nowrap align="left" bgcolor="#FFFFFF">Summary:</th>
             <td nowrap bgcolor="#FFFFFF"> 
               <input type="text" name="summary" value="<:old summary:>" size=60><:error_img summary:>
             </td>
             <td nowrap bgcolor="#FFFFFF"><:help product summary:></td>
           </tr>
+          <tr> 
+            <th nowrap align="left" bgcolor="#FFFFFF">Description:</th>
+            <td nowrap bgcolor="#FFFFFF"> 
+              <input type="text" name="description" value="<:old description:>" size=60><:error_img description:>
+            </td>
+            <td nowrap bgcolor="#FFFFFF"><:help product description:></td>
+          </tr>
+          <tr> 
+            <th nowrap align="left" bgcolor="#FFFFFF">Product Code:</th>
+            <td nowrap bgcolor="#FFFFFF"> 
+              <input type="text" name="product_code" value="<:old product_code:>" size="40"><:error_img product_code:>
+            </td>
+            <td nowrap bgcolor="#FFFFFF"><:help product product_code:></td>
+          </tr>
           <tr> 
             <th nowrap align="left" bgcolor="#FFFFFF">Catalog:</th>
             <td nowrap bgcolor="#FFFFFF"> <select name="parentid"><:list:></select><:error_img parentid:> </td>
index a38036b..18a1ea7 100644 (file)
             <:or:><:default title:><:eif:></td>
             <td nowrap="nowrap" bgcolor="#FFFFFF"><:help edit title:> <:error_img title:></td>
           </tr>
+          <tr> 
+            <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">Summary: 
+            </th>
+            <td bgcolor="#FFFFFF" width="100%"> 
+            <:ifFieldPerm summary:><input type="text" name="summary" maxlength="<:cfg fields summary_size 255:>" size="64" value="<: old summary default summary :>" />
+            <:or:><:default summary:><:eif:></td>
+            <td nowrap="nowrap" bgcolor="#FFFFFF"><:help edit summary:> <:error_img summary:></td>
+          </tr>
           <:if Cfg image title:><tr> 
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">Title image:</th>
             <td bgcolor="#FFFFFF" width="100%"><:ifFieldPerm titleImage:><:titleImages:> (upload this to 
index daa310c..0f1baaa 100644 (file)
               parentid:></td>
           </tr>
                  <tr> 
-            <th align="left" bgcolor="#FFFFFF">Title*:</th>
+            <th align="left" bgcolor="#FFFFFF">Title:</th>
             <td bgcolor="#FFFFFF"><:ifFieldPerm title:><input type="text" name="title" value="<:old title default title:>" size="60"><:or:><:product title:><:eif:> </td>
             <td nowrap="nowrap" bgcolor="#FFFFFF"><:help product title:> <:error_img title:></td>
           </tr>
           <tr> 
-            <th nowrap="nowrap" align="left" bgcolor="#FFFFFF">Summary*:</th>
+            <th nowrap="nowrap" align="left" bgcolor="#FFFFFF">Summary:</th>
             <td nowrap="nowrap" bgcolor="#FFFFFF"><:ifFieldPerm summary:><input type="text" name="summary" value="<:old summary default summary:>" size=60><:or:><:product summary:><:eif:> </td>
             <td nowrap="nowrap" bgcolor="#FFFFFF"><:help product summary:> <:error_img
             summary:></td>
           </tr>
+          <tr> 
+            <th nowrap="nowrap" align="left" bgcolor="#FFFFFF">Description:</th>
+            <td nowrap="nowrap" bgcolor="#FFFFFF"><:ifFieldPerm description:><input type="text" name="description" value="<:old description default description:>" size=60><:or:><:product description:><:eif:> </td>
+            <td nowrap="nowrap" bgcolor="#FFFFFF"><:help product description:> <:error_img
+            description:></td>
+          </tr>
+          <tr> 
+            <th nowrap="nowrap" align="left" bgcolor="#FFFFFF">Product Code:</th>
+            <td nowrap="nowrap" bgcolor="#FFFFFF"><:ifFieldPerm product_code:><input type="text" name="product_code" value="<:old product_code default product_code:>" size=60><:or:><:product product_code:><:eif:> </td>
+            <td nowrap="nowrap" bgcolor="#FFFFFF"><:help product product_code:> <:error_img
+            product_code:></td>
+          </tr>
           <tr> 
             <th align="left" bgcolor="#FFFFFF" valign="top"> Body:</th>
             <td bgcolor="#FFFFFF"> 
index a1ef2ed..f22bad8 100644 (file)
@@ -145,7 +145,7 @@ function bse_popup_image (article_id, image_id, width, height, tag_id, image_url
 </tr>
 <:iterator begin dyncart:>
 <tr>
-  <td><a href="<:dyncartitem link:>"><:dynreplace [dyncartitem title] (.{15}).* $1...:></a></td>
+  <td><a href="<:dyncartitem link:>"><:dynreplace [dyncartitem title] "((?:&[^;]*;|[^&]){15}).*" $1...:></a></td>
   <td class="cartunits"><:dyncartitem units:></td>
   <td class="cartprice"><:money dyncartitem retailPrice:></td>
   <td class="cartprice"><:money dyncartitem extended:></td>
index 996b60e..2cd1743 100644 (file)
@@ -232,6 +232,11 @@ function BSE_validateForm {
       <td> <font face="Verdana, Arial, Helvetica, sans-serif" size="2"> 
         <textarea name="instructions" rows="5" cols="40" wrap="virtual"><:old instructions:></textarea></font><:error_img instructions:></td>
     </tr>
+    <tr> 
+      <td valign="top"><font face="Verdana, Arial, Helvetica, sans-serif" size="2">Purchase<br />Order:</font></td>
+      <td> <font face="Verdana, Arial, Helvetica, sans-serif" size="2"> 
+        <input type="text" name="purchase_order" value="<:old purchase_order:>" /></font><:error_img purchase_order:></td>
+    </tr>
     <tr> 
       <td colspan="2"> <font face="Verdana, Arial, Helvetica, sans-serif" size="2"> 
         * Required information for order to be shipped</font></td>
index 52c60e7..6863aba 100644 (file)
@@ -218,7 +218,8 @@ sub create_clauses {
   for my $col (@cols) {
     my $sql = $col->{field} . " " . $col->{type};
     $sql .= $col->{null} ? ' null' : ' not null';
-    if ($col->{default} ne 'NULL') {
+    if ($col->{default} ne 'NULL' &&
+       ($col->{type} =~ /char/i || $col->{default} =~ /\d/)) {
       $sql .= " default ";
       if ($col->{default} =~ /^\d+$/) {
        $sql .= $col->{default};
index 01f2956..09da706 100644 (file)
@@ -1,7 +1,7 @@
 #!perl -w
 use strict;
 use BSE::Test ();
-use Test::More tests=>85;
+use Test::More tests=>88;
 use File::Spec;
 use FindBin;
 my $cgidir = File::Spec->catdir(BSE::Test::base_dir, 'cgi-bin');
@@ -277,6 +277,12 @@ TEMPLATE
 0
 EXPECTED
 
+template_test "replace complex re", $parent, <<'TEMPLATE', <<EXPECTED;
+<:replace "test&amp;test 01234567890123456789" ((?:&[^;]*;|[^&]){16}).* $1...:>
+TEMPLATE
+test&amp;test 012345...
+EXPECTED
+
 ############################################################
 # Cleanup
 
index 1308137..e1b2b29 100644 (file)
--- a/test.cfg
+++ b/test.cfg
@@ -12,6 +12,7 @@ sessionclass = Apache::Session::MySQL
 # the location of mysql
 mysql = mysql
 basic.access_control=0
+basic.staticajax=1
 basic.sign=0
 #basic.htusers = /home/httpd/bsetest/htdocs/images/.htusers
 #article uris.9 = /test
@@ -59,19 +60,22 @@ debug.mail_encryption=0
 site users.billing_on_main_opts=0
 #site users.user_register=0
 #paths.libraries=/home/tony/dev/bse/tandb_dealer/cvs/modules
-paths.libraries=/home/tony/dev/bse/lib
-basic.custom_class=BSE::Custom::Abberfield
+#paths.libraries=/home/tony/dev/bse/lib
+#paths.libraries=/home/tony/dev/bse/work2/modules
+#basic.custom_class=BSE::Custom::Abberfield
+#basic.custom_class=BSE::CustomTest
 #paths.siteuser_passwd=/home/httpd/bsetest/data/supasswd
 #custom.user_auth=1
 # product fields.retailPrice=Dealer Price Inc GST
 #paths.local_templates=/home/tony/dev/bse/tandb_dealer/cvs/templates
+#paths.local_templates=/home/tony/dev/bse/work2/templates
 #shop.payment_types=1,2,10,11,12
 payment type names.10=DirectDeposit
 payment type names.11=FaxProForma
 payment type names.12=EmailProForma
 payment type required.11=facsimile
 
-paths.local_templates=/home/tony/dev/bse/work/templates/
+#paths.local_templates=/home/tony/dev/bse/work/templates/
 
 affiliate.prompt_name=1
 site users.require_affiliate_name=0
@@ -244,8 +248,10 @@ seminars.free_bookings=1
 admin group template sets.test=Test Templates
 
 html.msentify=1
-html.ajaxcharset=1
+#html.ajaxcharset=1
+html.mbcs=1
 debug.convert_charset=1
+html.charset=windows-1252
 
 popink.payment_email=tony@develop-help.com
 popink.errorsto=tony@develop-help.com
@@ -256,3 +262,5 @@ popink.pop3password=forts51t
 includes.99cfg=cfg/
 
 permission full_access.permissions=*
+
+search index scores.product_code=5