BSE 0.15_34 r0_15_34
authorTony Cook <tony@develop-help.com>
Mon, 10 Apr 2006 05:58:02 +0000 (05:58 +0000)
committertony <tony@45cb6cf1-00bc-42d2-bb5a-07f51df49f94>
Mon, 10 Apr 2006 05:58:02 +0000 (05:58 +0000)
=item *

added dynamic iterators, listed each here as iterator name/item name.

Global: dynlevel1s/dynlevel1, dynlevel2s/dynlevel2,
dynlevel3s/dynlevel3, dynallkids_of/dynofallkid,
dynchildren_of/dynofchild.

Article pages: dynallkids/dynallkid, dynchildren/dynchild,
dynstepparents/dynstepparent.

=item *

added cgi-bin/admin/bse_modules.pl script to check that modules used
by BSE are installed.  This should probably be removed once BSE is
installed and running.

=item *

search results now only include accessible articles by default.

=item *

the product tag no long warns when you attempt to use an undef (NULL)
value from the product.

=item *

removed method=post from some display forms used to simply display
data.

20 files changed:
MANIFEST
Makefile
site/cgi-bin/admin/admin.pl
site/cgi-bin/admin/bse_modules.pl [new file with mode: 0755]
site/cgi-bin/admin/generate.pl
site/cgi-bin/modules/BSE/Dynamic/Article.pm
site/cgi-bin/modules/BSE/Request.pm
site/cgi-bin/modules/BSE/Util/DynamicTags.pm
site/cgi-bin/modules/Generate/Article.pm
site/cgi-bin/modules/Generate/Product.pm
site/cgi-bin/modules/Util.pm
site/cgi-bin/search.pl
site/docs/bse.pod
site/docs/config.pod
site/templates/base.tmpl
site/templates/common/default.tmpl
site/templates/sidebar/logon.tmpl
site/templates/user/options_base.tmpl
site/templates/user/userpage_base.tmpl
test.cfg

index aece119..3065af4 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -16,7 +16,7 @@ site/cgi-bin/admin/add.pl
 site/cgi-bin/admin/admin.pl
 site/cgi-bin/admin/admin_seminar.pl
 site/cgi-bin/admin/adminusers.pl
-site/cgi-bin/affiliate.pl
+site/cgi-bin/admin/bse_modules.pl
 site/cgi-bin/admin/changepw.pl
 site/cgi-bin/admin/datadump.pl
 site/cgi-bin/admin/generate.pl
@@ -32,6 +32,7 @@ site/cgi-bin/admin/siteusers.pl
 site/cgi-bin/admin/subadmin.pl
 site/cgi-bin/admin/subs.pl
 site/cgi-bin/admin/userlist.pl
+site/cgi-bin/affiliate.pl
 site/cgi-bin/bse.cfg
 site/cgi-bin/fmail.pl
 site/cgi-bin/image.pl
index 4e00318..b445e65 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.15_33
+VERSION=0.15_34
 DISTNAME=bse-$(VERSION)
 DISTBUILD=$(DISTNAME)
 DISTTAR=../$(DISTNAME).tar
index e2e51fa..4b0af31 100755 (executable)
@@ -39,7 +39,7 @@ if ($req->check_admin_logon()) {
       $dyn_gen_class = "BSE::Dynamic::".$dyn_gen_class;
       (my $dyn_gen_file = $dyn_gen_class . ".pm") =~ s!::!/!g;
       require $dyn_gen_file;
-      my $dyn_gen = $dyn_gen_class->new($req);
+      my $dyn_gen = $dyn_gen_class->new($req, admin => 1);
       $article = $dyn_gen->get_real_article($article);
       my $result = $dyn_gen->generate($article, $content);
       BSE::Template->output_result($req, $result);
diff --git a/site/cgi-bin/admin/bse_modules.pl b/site/cgi-bin/admin/bse_modules.pl
new file mode 100755 (executable)
index 0000000..41b6f7c
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/perl -w
+use strict;
+
+print "Content-Type: text/html\n\n";
+
+print <<EOS;
+<html><head><title>BSE Module Check</title></head>
+<body>
+EOS
+
+my @base_check =
+  (
+   { name => "Base requirements",
+     modules => 
+     { 
+      'DBI' => 0, 
+      'DBD::mysql' => 0, 
+      'Digest::MD5' => 0,
+      'Apache::Session' => 0,
+      'Storable' => 0,
+      'HTML::Parser' => 0,
+      'URI::Escape' => 0,
+      'HTML::Entities' => 0,
+      'Image::Size' => 0,
+     }
+   },
+   {
+    name => "Securepay XML",
+    modules =>
+    {
+     'XML::Simple' => 0,
+     'LWP::UserAgent' => 0,
+     'Crypt::SSLeay' => 0,
+    },
+   },
+   {
+    name => "Nport",
+    modules => 
+    {
+     'MIME::Lite' => 0,
+     'Time::HiRes' => 0,
+     'Date::Calc' => 0,
+    },
+   },
+   {
+    name => "Optional",
+    modules =>
+    {
+     'Imager' => 0.44,
+     'Log::Agent' => 0,
+    },
+   },
+   {
+    name => 'mod-perl 1.x support',
+    modules =>
+    {
+     'Apache::Request' => 0,
+    },
+   },
+   {
+    name => 'FastCGI support',
+    modules =>
+    {
+     FCGI => 0,
+     'CGI::Fast' => 0,
+    },
+   },
+   {
+    name => "Following should fail\n",
+    modules =>
+    {
+     'ShouldNotLoad' => 0,
+    },
+   },
+  );
+
+for my $sect (@base_check) {
+  print "<h1>$sect->{name}</h1>\n";
+  for my $module (sort keys %{$sect->{modules}}) {
+    my $use = "use $module";
+    if ($sect->{modules}{$module}) {
+      $use .= " " . $sect->{modules}{$module};
+    }
+    $use .= ';';
+    eval $use;
+    if ($@) {
+      my $msg = escape_html($@);
+      $msg =~ s!\n!<br />!g;
+      print "<p>Error loading $module: $msg</p>\n";
+    }
+    else {
+      print "<p>$module loaded successfully\n</p>";
+    }
+  }
+}
+
+print "</body></html>\n";
+
+my %escape;
+
+BEGIN {
+  %escape = ( '>' => '&gt;', '<' => '&lt;', '&' => '&amp;' );
+}
+
+sub escape_html {
+  my ($str) = @_;
+
+  $str =~ s/([<>&])/$escape{$1}/g;
+
+  $str;
+}
index bbc43a6..48421ee 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl -w 
 # -d:ptkdb
 BEGIN { $ENV{DISPLAY} = '192.168.32.15:0.0' }
 use strict;
index c99bfd5..ff69fe4 100644 (file)
@@ -3,11 +3,16 @@ use strict;
 use BSE::Util::Tags qw(tag_hash);
 use BSE::Template;
 use DevHelp::HTML;
+use base qw(BSE::Util::DynamicTags);
 
 sub new {
-  my ($class, $req) = @_;
+  my ($class, $req, %opts) = @_;
 
-  return bless { req=> $req }, $class;
+  my $self = $class->SUPER::new($req, %opts);
+
+  ++$self->{admin} if $opts{admin};
+
+  return $self;
 }
 
 sub generate {
@@ -35,11 +40,77 @@ sub tags {
   $self->{req}->set_article(dynarticle => $article);
   return
     (
+     $self->SUPER::tags(),
      dynarticle => [ \&tag_hash, $article ],
-     $self->{req}->dyn_user_tags(),
+     ifAncestor => [ tag_ifAncestor => $self, $article ],
+     $self->dyn_iterator('dynallkids', 'dynallkid', $article),
+     $self->dyn_iterator('dynchildren', 'dynchild', $article),
+     $self->dyn_iterator('dynstepparents', 'dynstepparent', $article),
     );
 }
 
+sub iter_dynallkids {
+  my ($self, $article, $args) = @_;
+
+  my $result = $self->get_cached('dynallkids');
+  $result
+    and return $result;
+  $result = [ grep $self->{req}->siteuser_has_access($_), 
+             $article->all_visible_kids ];
+  $self->set_cached(dynallkids => $result);
+
+  return $result;
+}
+
+sub iter_dynchildren {
+  my ($self, $article, $args) = @_;
+
+  my $result = $self->get_cached('dynchildren');
+  $result
+    and return $result;
+
+  $result = [ grep $self->{req}->siteuser_has_access($_), 
+             Articles->listedChildren($article->{id}) ];
+  $self->set_cached(dynchildren => $result);
+
+  return $result;
+}
+
+sub iter_dynstepparents {
+  my ($self, $article, $args) = @_;
+
+  my $result = $self->get_cached('dynstepparents');
+  $result
+    and return $result;
+
+  $result = [ grep $self->{req}->siteuser_has_access($_), 
+             $article->visible_step_parents ];
+  $self->set_cached(dynstepparents => $result);
+
+  return $result;
+}
+
+sub tag_ifAncestor {
+  my ($self, $article, $arg) = @_;
+
+  unless ($arg =~ /^\d+$/) {
+    my $art = $self->{req}->get_article($arg)
+      or return 0;
+    $arg = $art->{id};
+  }
+
+  return 1 if $article->{id} == $arg;
+
+  while ($article->{parentid} != -1) {
+    $article->{parentid} == $arg
+      and return 1;
+
+    $article = $article->parent;
+  }
+
+  return 0;
+}
+
 sub get_real_article {
   my ($self, $article) = @_;
 
index 39e1e59..62204ea 100644 (file)
@@ -15,6 +15,10 @@ sub new {
   my %session;
   BSE::Session->tie_it(\%session, $self->{cfg});
   $self->{session} = \%session;
+  $self->{cache_stats} = $self->{cfg}->entry('debug', 'cache_stats', 0);
+  if ($self->{cache_stats}) {
+    @{$self}{qw/siteuser_calls siteuser_cached has_access_cached has_access_total/} = ( 0, 0, 0, 0 );
+  }
 
   $self;
 }
@@ -183,22 +187,33 @@ sub response {
 sub siteuser {
   my ($req) = @_;
 
+  ++$req->{siteuser_calls};
+  if (exists $req->{_siteuser}) {
+    ++$req->{siteuser_cached};
+    return $req->{_siteuser};
+  }
+
   my $cfg = $req->cfg;
   my $session = $req->session;
   require SiteUsers;
   if ($cfg->entryBool('custom', 'user_auth')) {
     require BSE::CfgInfo;
     my $custom = BSE::CfgInfo::custom_class($cfg);
-    
+
     return $custom->siteuser_auth($session, $req->cgi, $cfg);
   }
   else {
+    $req->{_siteuser} = undef;
+
     my $userid = $session->{userid}
       or return;
     my $user = SiteUsers->getBy(userId=>$userid)
       or return;
     $user->{disabled}
       and return;
+
+    $req->{_siteuser} = $user;
+
     return $user;
   }
 }
@@ -269,7 +284,7 @@ sub _have_group_access {
   return 0;
 }
 
-sub siteuser_has_access {
+sub _siteuser_has_access {
   my ($req, $article, $user, $default, $membership) = @_;
 
   defined $default or $default = 1;
@@ -310,15 +325,44 @@ sub siteuser_has_access {
   }
 }
 
+sub siteuser_has_access {
+  my ($req, $article, $user, $default, $membership) = @_;
+
+  $user ||= $req->siteuser;
+
+  ++$req->{has_access_total};
+  if ($req->{_siteuser} && $user && $user->{id} == $req->{_siteuser}{id}
+      && exists $req->{_access_cache}{$article->{id}}) {
+    ++$req->{has_access_cached};
+    return $req->{_access_cache}{$article->{id}};
+  }
+
+  my $result = $req->_siteuser_has_access($article, $user, $default, $membership);
+
+  if ($user && $req->{_siteuser} && $user->{id} == $req->{_siteuser}{id}) {
+    $req->{_access_cache}{$article->{id}} = $result;
+  }
+
+  return $result;
+}
+
 sub dyn_user_tags {
   my ($self) = @_;
 
   require BSE::Util::DynamicTags;
-  return BSE::Util::DynamicTags->tags($self);
+  return BSE::Util::DynamicTags->new($self)->tags;
 }
 
 sub DESTROY {
   my ($self) = @_;
+
+  if ($self->{cache_stats}) {
+    print STDERR "Siteuser cache: $self->{siteuser_calls} Total, $self->{siteuser_cached} Cached\n"
+      if $self->{siteuser_calls};
+    print STDERR "Access cache: $self->{has_access_total} Total, $self->{has_access_cached} Cached\n"
+      if $self->{has_access_total};
+  }
+
   if ($self->{session}) {
     undef $self->{session};
   }
index 23364b6..edc8a43 100644 (file)
@@ -3,15 +3,28 @@ use strict;
 use BSE::Util::Tags;
 use DevHelp::HTML;
 
-sub tags {
+sub new {
   my ($class, $req) = @_;
+  return bless { req => $req }, $class;
+}
+
+sub tags {
+  my ($self) = @_;
   
+  my $req = $self->{req};
   return
     (
      BSE::Util::Tags->basic(undef, $req->cgi, $req->cfg),
      user => [ \&tag_user, $req ],
      ifUser => [ \&tag_ifUser, $req ],
      ifUserCanSee => [ \&tag_ifUserCanSee, $req ],
+     $self->dyn_iterator('dynlevel1s', 'dynlevel1'),
+     $self->dyn_iterator('dynlevel2s', 'dynlevel2'),
+     $self->dyn_iterator('dynlevel3s', 'dynlevel3'),
+     $self->dyn_iterator('dynallkids_of', 'dynofallkid'),
+     $self->dyn_iterator('dynchildren_of', 'dynofchild'),
+     url => [ tag_url => $self ],
+     ifAncestor => 0,
     );
 }
 
@@ -59,4 +72,217 @@ sub tag_ifUserCanSee {
   $req->siteuser_has_access($article);
 }
 
+sub tag_url {
+  my ($self, $name, $acts, $func, $templater) = @_;
+
+  my $item = $self->{admin} ? 'admin' : 'link';
+  my $article = $self->{req}->get_article($name)
+    or return "** unknown article $name **";
+  return escape_html($article->{$item});
+}
+
+sub iter_dynlevel1s {
+  my ($self, $unused, $args) = @_;
+
+  my $result = $self->get_cached('dynlevel1');
+  $result
+    and return $result;
+
+  require Articles;
+  $result = [ grep $self->{req}->siteuser_has_access($_), 
+             Articles->listedChildren(-1) ];
+  $self->set_cached(dynlevel1 => $result);
+
+  return $result;
+}
+
+sub iter_dynlevel2s {
+  my ($self, $unused, $args) = @_;
+
+  my $req = $self->{req};
+  my $parent = $req->get_article('dynlevel1')
+    or return [];
+
+  my $cached = $self->get_cached('dynlevel2');
+  $cached && $cached->[0] == $parent->{id}
+    and return $cached->[1];
+
+  require Articles;
+  my $result = [ grep $req->siteuser_has_access($_), 
+                Articles->listedChildren($parent->{id}) ];
+  $self->set_cached(dynlevel2 => [ $parent->{id}, $result ]);
+
+  return $result;
+}
+
+sub iter_dynlevel3s {
+  my ($self, $unused, $args) = @_;
+
+  my $req = $self->{req};
+  my $parent = $req->get_article('dynlevel2')
+    or return [];
+
+  my $cached = $self->get_cached('dynlevel3');
+  $cached && $cached->[0] == $parent->{id}
+    and return $cached->[1];
+
+  require Articles;
+  my $result = [ grep $req->siteuser_has_access($_), 
+                Articles->listedChildren($parent->{id}) ];
+  $self->set_cached(dynlevel3 => [ $parent->{id}, $result ]);
+
+  return $result;
+}
+
+sub iter_dynallkids_of {
+  my ($self, $unused, $args, $acts, $templater) = @_;
+
+  my @ids = map { split } DevHelp::Tags->get_parms($args, $acts, $templater);
+  for my $id (@ids) {
+    unless ($id =~ /^\d+$|^-1$/) {
+      $id = $self->{req}->get_article($id);
+    }
+  }
+  @ids = grep defined && /^\d+$|^-1$/, @ids;
+  return [ grep $self->{req}->siteuser_has_access($_), 
+          map Articles->all_visible_kids($_), @ids ];
+}
+
+sub iter_dynchildren_of {
+  my ($self, $unused, $args, $acts, $templater) = @_;
+
+  my @ids = map { split } DevHelp::Tags->get_parms($args, $acts, $templater);
+  for my $id (@ids) {
+    unless ($id =~ /^\d+$|^-1$/) {
+      $id = $self->{req}->get_article($id);
+    }
+  }
+  @ids = grep defined && /^\d+$|^-1$/, @ids;
+  return [ grep $self->{req}->siteuser_has_access($_), 
+          map Articles->listedChildren($_), @ids ];
+}
+
+sub _dyn_iterate_reset {
+  my ($self, $rdata, $rindex, $plural, $context, $args, $acts, $name, 
+      $templater) = @_;
+
+  my $method = "iter_$plural";
+  $$rdata = $self->$method($context, $args, $acts, $templater);
+  $$rindex = -1;
+
+  1;
+}
+
+sub _dyn_iterate {
+  my ($self, $rdata, $rindex, $single) = @_;
+
+  if (++$$rindex < @$$rdata) {
+    $self->{req}->set_article($single => $$rdata->[$$rindex]);
+    return 1;
+  }
+  else {
+    $self->{req}->set_article($single => undef);
+    return;
+  }
+}
+
+sub _dyn_item {
+  my ($self, $rdata, $rindex, $single, $plural, $args) = @_;
+
+  if ($$rindex < 0 || $$rindex >= @$$rdata) {
+    return "** $single only usable inside iterator $plural **";
+  }
+
+  my $item = $$rdata->[$$rindex]
+    or return '';
+  my $value = $item->{$args};
+  defined $value 
+    or return '';
+
+  return escape_html($value);
+}
+
+sub _dyn_index {
+  my ($self, $rindex, $rdata, $single) = @_;
+
+  if ($$rindex < 0 || $$rindex >= @$$rdata) {
+    return "** $single only valid inside iterator **";
+  }
+
+  return $$rindex;
+}
+
+sub _dyn_number {
+  my ($self, $rindex, $rdata, $single) = @_;
+
+  if ($$rindex < 0 || $$rindex >= @$$rdata) {
+    return "** $single only valid inside iterator **";
+  }
+
+  return 1 + $$rindex;
+}
+
+sub _dyn_count {
+  my ($self, $rdata, $rindex, $plural, $context, $args, $acts, $name, 
+      $templater) = @_;
+
+  my $method = "iter_$plural";
+  my $data = $self->$method($context, $args, $acts, $templater);
+
+  return scalar @$data;
+}
+
+sub _dyn_if_first {
+  my ($self, $rindex, $rdata) = @_;
+
+  $$rindex == 0;
+}
+
+sub _dyn_if_last {
+  my ($self, $rindex, $rdata) = @_;
+
+  $$rindex == $#$$rdata;
+}
+
+sub dyn_iterator {
+  my ($self, $plural, $single, $context, $rindex, $rdata) = @_;
+
+  my $method = $plural;
+  my $index;
+  defined $rindex or $rindex = \$index;
+  my $data;
+  defined $rdata or $rdata = \$data;
+  return
+    (
+     "iterate_${plural}_reset" =>
+     [ _dyn_iterate_reset => $self, $rdata, $rindex, $plural, $context ],
+     "iterate_$plural" =>
+     [ _dyn_iterate => $self, $rdata, $rindex, $single, $context ],
+     $single => 
+     [ _dyn_item => $self, $rdata, $rindex, $single, $plural ],
+     "${single}_index" =>
+     [ _dyn_index => $self, $rindex, $rdata, $single ],
+     "${single}_number" =>
+     [ _dyn_number => $self, $rindex, $rdata ],
+     "${single}_count" =>
+     [ _dyn_count => $self, $rindex, $rdata, $plural, $context ],
+     "if\u$plural" =>
+     [ _dyn_count => $self, $rindex, $rdata, $plural, $context ],
+     "ifLast\u$single" => [ _dyn_if_last => $self, $rindex, $rdata ],
+     "ifFirst\u$single" => [ _dyn_if_first => $self, $rindex, $rdata ],
+    );
+}
+
+sub get_cached {
+  my ($self, $id) = @_;
+
+  return $self->{_cache}{$id};
+}
+
+sub set_cached {
+  my ($self, $id, $value) = @_;
+
+  $self->{_cache}{$id} = $value;
+}
+
 1;
index 5f4e911..8517ff5 100644 (file)
@@ -440,6 +440,7 @@ HTML
      sub {
        my ($arg, $acts, $name, $templater) = @_;
        unless ($arg =~ /^\d+$/) {
+        $acts->{$arg} or die "ENOIMPL\n";
         $arg = $acts->{$arg} && $templater->perform($acts, $arg, 'id')
           or return;
        }
@@ -533,6 +534,7 @@ HTML
     $acts{url} =
       sub {
         my $value = $oldurl->(@_);
+       return $value if $value =~ /^<:/; # handle "can't do it"
         unless ($value =~ /^\w+:/) {
           # put in the base site url
           $value = $urlbase . $value;
index 0c029e5..cf2d04e 100644 (file)
@@ -7,6 +7,7 @@ use base qw(Generate::Article);
 use Constants qw(:shop $CGI_URI $ADMIN_URI);
 use Carp qw(confess);
 use DevHelp::HTML;
+use BSE::Util::Tags qw(tag_hash);
 
 sub edit_link {
   my ($self, $id) = @_;
@@ -60,7 +61,7 @@ sub baseActs {
   return
     (
      $self->SUPER::baseActs($articles, $acts, $product, $embedded),
-     product=> sub { escape_html($product->{$_[0]}) },
+     product=> [ \&tag_hash, $product ],
      admin => [ tag_admin => $self, $product, 'product', $embedded ],
      iterate_options_reset => sub { $option_index = -1 },
      iterate_options => sub { ++$option_index < @options },
index 5c6995d..899dccf 100644 (file)
@@ -135,6 +135,7 @@ sub generate_shop {
     $acts{url} =
       sub {
         my $value = $oldurl->(@_);
+       $value =~ /^<:/ and return $value;
         unless ($value =~ /^\w+:/) {
           # put in the base site url
           $value = $cfg->entryErr('site', 'url').$value;
@@ -187,6 +188,7 @@ sub generate_extras {
     $acts{url} =
       sub {
        my $value = $oldurl->(@_);
+       $value =~ /^<:/ and return $value;
        unless ($value =~ /^\w+:/) {
          # put in the base site url
          $value = $cfg->entryErr('site', 'url').$value;
@@ -235,6 +237,7 @@ sub generate_extras {
       $acts{url} =
        sub {
          my $value = $oldurl->(@_);
+         $value =~ /^<:/ and return $value;
          unless ($value =~ /^\w+:/) {
            # put in the base site url
            $value = $cfg->entryErr('site', 'url').$value;
index 2e19299..2d572fc 100755 (executable)
@@ -52,13 +52,39 @@ if (@results) {
   my $articles_end = $articles_start + $results_per_page-1;
   $articles_end = $#results if $articles_end >= @results;
 
-  for my $id (@results[$articles_start..$articles_end]) {
-    my $article = Articles->getByPkey($id)
-      or die "Cannot retrieve article $id\n";
-    push(@articles, $article);
+  if ($cfg->entry('search', 'keep_inaccessible')) {
+    for my $id (@results[$articles_start..$articles_end]) {
+      my $article = Articles->getByPkey($id)
+       or die "Cannot retrieve article $id\n";
+      push(@articles, $article);
+    }
+  }
+  else {
+    my %remove; # used later to remove the inaccessible from @results;
+    # we need to check accessiblity on each article
+    my $index = 0;
+    my $seen = 0;
+    while ($index < @results && $seen <= $articles_end) {
+      my $id = $results[$index];
+      my $article = Articles->getByPkey($id)
+       or die "Cannot retrieve article $id\n";
+      if ($req->siteuser_has_access($article)) {
+       if ($seen >= $articles_start) {
+         push @articles, $article;
+       }
+       ++$seen;
+      }
+      else {
+       $remove{$id} = 1;
+      }
+      ++$index;
+    }
+    @results = grep !$remove{$_}, @results;
   }
 }
 
+$page_count = int((@results + $results_per_page - 1)/$results_per_page);
+
 # make an array of hashes (to preserve order)
 my %excluded;
 @excluded{@SEARCH_EXCLUDE} = @SEARCH_EXCLUDE;
index 89aeb0c..c0264ba 100644 (file)
@@ -10,6 +10,43 @@ Maybe I'll add some other bits here.
 
 =head1 CHANGES
 
+=head2 0.15_34
+
+=over
+
+=item *
+
+added dynamic iterators, listed each here as iterator name/item name.
+
+Global: dynlevel1s/dynlevel1, dynlevel2s/dynlevel2,
+dynlevel3s/dynlevel3, dynallkids_of/dynofallkid,
+dynchildren_of/dynofchild.
+
+Article pages: dynallkids/dynallkid, dynchildren/dynchild,
+dynstepparents/dynstepparent.
+
+=item *
+
+added cgi-bin/admin/bse_modules.pl script to check that modules used
+by BSE are installed.  This should probably be removed once BSE is
+installed and running.
+
+=item *
+
+search results now only include accessible articles by default.
+
+=item *
+
+the product tag no long warns when you attempt to use an undef (NULL)
+value from the product.
+
+=item *
+
+removed method=post from some display forms used to simply display
+data.
+
+=back
+
 =head2 0.15_33
 
 =over
index 6353dc1..d9d727a 100644 (file)
@@ -519,6 +519,11 @@ the result will be:
 If this is true then partial matches will be highlight in search
 result excerpts.  Default: True
 
+=item keep_inaccessible
+
+If this is true then resulting articles that can't be accessed by the
+user are listed in the search results.  Default: false.
+
 =back
 
 =head2 [shop]
index 0d29730..75b99cb 100644 (file)
@@ -87,6 +87,57 @@ function bse_popup_image (article_id, image_id, width, height, tag_id, image_url
                 <td><img src="/images/trans_pixel.gif" width="1" height="1" alt="spacer"></td>
               </tr>
             </table>
+<:if Dynamic:>
+       <:iterator begin dynlevel1s:>
+            <table width="100%" border="0" cellspacing="0" cellpadding="0">
+              <tr> 
+                <td> 
+                  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+                    <:if Ancestor dynlevel1:>
+                    <tr> 
+                      <td height="19" width="100%" nowrap bgcolor="#999999">&nbsp;<a href="<:url dynlevel1:>"><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#FFFFFF"><:dynlevel1
+                        title:></font></b></a> </td>
+                    </tr>
+                    <:or Ancestor:>
+                    <tr> 
+                      <td height="19" width="100%" nowrap bgcolor="#CCCCCC">&nbsp;<a href="<:url dynlevel1:>"><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><:dynlevel1 
+                        title:></font></b></a> </td>
+                    </tr>
+                    <:eif Ancestor:>
+                  </table>
+                </td>
+              </tr>
+              <:if Ancestor dynlevel1:>
+               <tr> 
+                <td>
+                 <:if Dynlevel2s:> 
+                  <table width="100%" border="0" cellspacing="0" cellpadding="3">
+                    <:iterator begin dynlevel2s:>
+                    <:ifAncestor dynlevel2:>
+                     <tr> 
+                      <td bgcolor="#FFFFFF"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:url dynlevel2:>"><:dynlevel2 title:></a></font> 
+                        </td>
+                     </tr>
+                     <:or:>
+                     <tr> 
+                      <td bgcolor="#EEEEEE"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:url dynlevel2:>"><:dynlevel2 title:></a></font> 
+                        </td>
+                     </tr>
+                     <:eif:>
+                        <:iterator end dynlevel2s:>
+                  </table>
+            <:or Dynlevel2s:> 
+            <:eif Dynlevel2s:>
+                </td>
+              </tr>
+<:or Ancestor:>
+<:eif Ancestor:>
+              <tr> 
+                <td><img src="/images/trans_pixel.gif" width="1" height="1" alt="spacer"></td>
+              </tr>
+            </table>
+        <:iterator end dynlevel1s:>
+<:or Dynamic:>
             <:iterator begin level1:>  
             <table width="100%" border="0" cellspacing="0" cellpadding="0">
               <tr> 
@@ -136,6 +187,7 @@ function bse_popup_image (article_id, image_id, width, height, tag_id, image_url
               </tr>
             </table>
 <:iterator separator level1:><:iterator end level1:> 
+<:eif Dynamic:>
             <:embed 5:> </td>
         </tr>
       </table>
index f0ee3c0..05bd0ef 100644 (file)
   title</a> | <a href="/cgi-bin/admin/reorder.pl?parentid=<:article id:>&sort=date&refreshto=/cgi-bin/admin/admin.pl?id=<:article id:>">by 
   date</a> | <a href="/cgi-bin/admin/reorder.pl?parentid=<:article id:>&reverse=1&refreshto=/cgi-bin/admin/admin.pl?id=<:article id:>">reverse 
   order</a></font></p>
-<:or Children:><:eif Children:><:or:><:eif:><:if UnderThreshold:><:iterator begin 
+<:or Children:><:eif Children:><:or:><:eif:>
+<:if Dynamic:>
+<:iterator begin dynchildren:> 
+<p><:thumbnail dynchild:> <a href="<:url dynchild:>"><b><font face="Verdana, Arial, Helvetica, sans-serif" size="3"><:dynchild 
+  title:></font></b></a><br>
+  <:if Child summaryLength:><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><:summary:></font><:or 
+  Child:><:eif Child:></p>
+<:iterator separator dynchildren:><:iterator end dynchildren:>
+<:or Dynamic:>
+<:if UnderThreshold:><:iterator begin 
 children:><:ifAdmin:> 
 <hr noshade size="1">
 <:or:><:eif:><:movekid:><:embed child:><:iterator separator children:><br>
@@ -39,7 +48,7 @@ children:><:ifAdmin:>
   title:></font></b></a><:movekid:><br>
   <:if Child summaryLength:><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><:summary:></font><:or 
   Child:><:eif Child:></p>
-<:iterator separator children:><:iterator end children:><:eif UnderThreshold:><:eif 
+<:iterator separator children:><:iterator end children:><:eif UnderThreshold:><:eif Dynamic:><:eif 
 Embedded:> <br>
 <:if Files:> <br>
 <table border="0" cellspacing="0" cellpadding="0">
index 1e27bd1..430df54 100644 (file)
 <!-- This form is not used when you have the nopassword option enabled -->
 <p><font face="Verdana, Arial, Helvetica, sans-serif" size="-2">Please use the URL from your confirmation email to access your
 details and subscription information.</font></p>
-<div align="center"><form action="/cgi-bin/user.pl" method="post"><input type="submit" name="show_register" value="Register" class="user-buttons" /></form></div>
+<div align="center"><form action="/cgi-bin/user.pl"><input type="submit" name="show_register" value="Register" class="user-buttons" /></form></div>
 <:or Cfg:><:if Dynamic:>
 <:if User:>
-<form action="/cgi-bin/user.pl" method="post">
+<form action="/cgi-bin/user.pl">
 <table><tr><td align="left"><input type="submit" name="userpage" value="User profile" class="user-buttons" /></td><td align="right"><input type="submit" name="logoff" value="Logoff" class="user-buttons" /></td></tr></table></form>
 <:or User:>
 <form action="/cgi-bin/user.pl" method="post">
@@ -46,7 +46,7 @@ if (start != -1) {
   userid = cookies.substring(start, end);
 }
 if (userid != '') {
-  document.write('<form action="/cgi-bin/user.pl" method="post">');
+  document.write('<form action="/cgi-bin/user.pl">');
   document.write('<table><tr><td align="left"><input type="submit" name="userpage" value="User profile" class="user-buttons" /></td><td align="right"><input type="submit" name="logoff" value="Logoff" class="user-buttons" /></td></tr></table></form>');
 }
 else {
index 51d3a5c..abba57a 100644 (file)
@@ -4,13 +4,13 @@
   <table border="0" cellspacing="0" cellpadding="0">
     <tr> 
       <td> 
-        <form name="yourorders" method="post" action="<:script:>">
+        <form name="yourorders" 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">
+        <form name="ff" action="/cgi-bin/shop.pl">
           <input type="submit" name="cart" value="View shopping cart" class="user-buttons" />
         </form>
       </td><:or:><:eif:>
index 2e18679..030a83e 100644 (file)
   <table border="0" cellspacing="0" cellpadding="0">
     <tr>
       <td>
-        <form name="userprofile" method="post" action="<:script:>">
+        <form name="userprofile" action="<:script:>">
           <input type="submit" name="Submit" value="Edit user profile" class="user-buttons">
           <input type="hidden" name="show_opts" value="1">
         </form>
       </td>
       <:ifCfg shop enabled:><td>
-        <form name="ff" method="post" action="/cgi-bin/shop.pl">
+        <form name="ff" action="/cgi-bin/shop.pl">
           <input type="submit" name="cart" value="View shopping cart" class="user-buttons">
         </form>
       </td><:or:><:eif:>
index ca26b5a..279aa21 100644 (file)
--- a/test.cfg
+++ b/test.cfg
@@ -200,4 +200,6 @@ body class.link=
 
 popimage.extrawidth = 20
 popimage.extraheight = 20
-popimage.popmiddle = 0
\ No newline at end of file
+popimage.popmiddle = 0
+
+debug.cache_stats = 1