linkAlias change:
authorTony Cook <tony@develop-help.com>
Wed, 23 Jan 2008 00:17:33 +0000 (00:17 +0000)
committertony <tony@45cb6cf1-00bc-42d2-bb5a-07f51df49f94>
Wed, 23 Jan 2008 00:17:33 +0000 (00:17 +0000)
- new article field linkAlias "Link alias", this field must contain
only alphanumerics and at least one letter

- articles with a linkAlias have a url generated for them based on the
alias and their title.  You will need to use an ErrorDocument or
RewriteRule to point these at page.pl

- page.pl now accepts an alias parameter, and will display the article
with that alias.

- page.pl can now act as an Apache ErrorDocument handler and if the
original URI was a linkAlias url it will extract the alias and display
the given article.  Unfortunately Apache will still write an error to
the error log.

25 files changed:
schema/bse.sql
site/cgi-bin/modules/Article.pm
site/cgi-bin/modules/BSE/DB/Mysql.pm
site/cgi-bin/modules/BSE/Dynamic/Article.pm
site/cgi-bin/modules/BSE/Edit/Article.pm
site/cgi-bin/modules/BSE/Formatter.pm
site/cgi-bin/modules/BSE/Generate/Seminar.pm
site/cgi-bin/modules/BSE/UI/Page.pm
site/cgi-bin/modules/BSE/Util/DynamicTags.pm
site/cgi-bin/modules/BSE/Util/Iterate.pm
site/cgi-bin/modules/BSE/Util/Tags.pm
site/cgi-bin/modules/DevHelp/Tags/Iterate.pm
site/cgi-bin/modules/Generate.pm
site/cgi-bin/modules/Generate/Article.pm
site/cgi-bin/modules/Generate/Catalog.pm
site/cgi-bin/modules/Generate/Product.pm
site/cgi-bin/modules/Squirrel/Template.pm
site/cgi-bin/page.pl
site/docs/bse.pod
site/templates/admin/edit_1.tmpl
site/templates/admin/edit_catalog.tmpl
site/templates/admin/edit_product.tmpl
site/templates/admin/edit_seminar.tmpl
site/util/mysql.str
test.cfg

index a8af870..425f32b 100644 (file)
@@ -96,6 +96,9 @@ CREATE TABLE article (
 
   -- short title for menus  
   titleAlias varchar(60) not null default '',
+
+  -- alias used to generate links
+  linkAlias varchar(255) not null default '',
   
   PRIMARY KEY (id),
 
@@ -108,7 +111,8 @@ CREATE TABLE article (
   INDEX article_date_index (`release`,expire, id),
   INDEX article_displayOrder_index (displayOrder),
   INDEX article_parentId_index (parentId),
-  INDEX article_level_index (level, id)
+  INDEX article_level_index (level, id),
+  INDEX article_alias(linkAlias)
 );
 
 #
index 30db689..1b0f798 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 summary menu titleAlias/;
+    metaDescription metaKeywords summary menu titleAlias linkAlias/;
 }
 
 sub numeric {
@@ -319,4 +319,18 @@ sub possible_stepchildren {
   return BSE::DB->query(articlePossibleStepchildren => $self->{id}, $self->{id});
 }
 
+sub link {
+  my ($self, $cfg) = @_;
+
+  if ($self->{linkAlias} && $cfg->entry('basic', 'use_alias', 1)) {
+    my $prefix = $cfg->entry('basic', 'alias_prefix', '');
+    my $title = $self->{title};
+    $title =~ tr/a-zA-Z0-9/_/cs;
+    return $prefix . '/' . $self->{linkAlias} . '/' . $title;
+  }
+  else {
+    return $self->{link};
+  }
+}
+
 1;
index 11fa0a6..d332230 100644 (file)
@@ -22,14 +22,15 @@ my %statements =
    # don't ever load the entire articles table
    #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 = ?',
    
    getArticleByLevel => 'select * from article where level = ?',
    getArticleByParentid => 'select * from article where parentid = ?',
+   getArticleByLinkAlias => 'select * from article where linkAlias = ?',
    'Articles.stepParents' => <<EOS,
 select ar.* from article ar, other_parents op
   where ar.id = op.parentId and op.childId = ?
index 75a711b..64d01d7 100644 (file)
@@ -1,6 +1,6 @@
 package BSE::Dynamic::Article;
 use strict;
-use BSE::Util::Tags qw(tag_hash);
+use BSE::Util::Tags qw(tag_article);
 use BSE::Template;
 use DevHelp::HTML;
 use base qw(BSE::Util::DynamicTags);
@@ -49,13 +49,13 @@ sub tags {
   return
     (
      $self->SUPER::tags(),
-     dynarticle => [ \&tag_hash, $article ],
+     dynarticle => [ \&tag_article, $self->{req}->cfg, $article ],
      ifAncestor => [ tag_ifAncestor => $self, $article ],
      ifStepAncestor => [ tag_ifStepAncestor => $self, $article ],
-     $self->dyn_iterator('dynallkids', 'dynallkid', $article,
+     $self->dyn_article_iterator('dynallkids', 'dynallkid', $article,
                         \$allkid_index, \$allkid_data),
-     $self->dyn_iterator('dynchildren', 'dynchild', $article),
-     $self->dyn_iterator('dynstepparents', 'dynstepparent', $article),
+     $self->dyn_article_iterator('dynchildren', 'dynchild', $article),
+     $self->dyn_article_iterator('dynstepparents', 'dynstepparent', $article),
      dynmoveallkid => 
      [ tag_dynmove => $self, \$allkid_index, \$allkid_data, 
        "stepparent=$article->{id}" ],
@@ -174,7 +174,7 @@ sub tag_url {
   my $article = $self->{req}->get_article($name)
     or return "** unknown article $name **";
 
-  my $value = $article->{$item};
+  my $value = $item eq 'link' ? $article->link($self->{req}->cfg) : $article->{$item};
 
   if ($top->{$item} =~ /^\w+:/ && $value !~ /^\w+:/) {
     $value = $self->{req}->cfg->entryErr('site', 'url') . $value;
index 82003b9..8d18c7b 100644 (file)
@@ -1294,13 +1294,25 @@ sub _validate_common {
   if (exists $data->{template} && $data->{template} =~ /\.\./) {
     $errors->{template} = "Please only select templates from the list provided";
   }
-  
+  if (exists $data->{linkAlias} 
+      && length $data->{linkAlias}) {
+    unless ($data->{linkAlias} =~ /\A[a-zA-Z0-9-]+\z/
+           && $data->{linkAlias} =~ /[A-Za-z]/) {
+      $errors->{linkAlias} = "Link alias must contain only alphanumerics and contain at least one letter";
+    }
+  }
 }
 
 sub validate {
   my ($self, $data, $articles, $errors) = @_;
 
   $self->_validate_common($data, $articles, $errors);
+  if (!$errors->{linkAlias} && defined $data->{linkAlias} && length $data->{linkAlias}) {
+    my $other = $articles->getBy(linkAlias => $data->{linkAlias});
+    $other
+      and $errors->{linkAlias} =
+       "Duplicate link alias - already used by article $other->{id}";
+  }
   custom_class($self->{cfg})
     ->article_validate($data, undef, $self->typename, $errors);
 
@@ -1318,6 +1330,15 @@ sub validate_old {
     $errors->{release} = "Invalid release date";
   }
 
+  if (!$errors->{linkAlias} 
+      && defined $data->{linkAlias} 
+      && length $data->{linkAlias} 
+      && $data->{linkAlias} ne $article->{linkAlias}) {
+    my $other = $articles->getBy(linkAlias => $data->{linkAlias});
+    $other
+      and $errors->{linkAlias} = "Duplicate link alias - already used by article $other->{id}";
+  }
+
   return !keys %$errors;
 }
 
@@ -1454,7 +1475,7 @@ sub save_new {
 # end adrian
 
   $self->fill_new_data($req, \%data, $articles);
-  for my $col (qw(titleImage imagePos template keyword menu titleAlias)) {
+  for my $col (qw(titleImage imagePos template keyword menu titleAlias linkAlias)) {
     defined $data{$col} 
       or $data{$col} = $self->default_value($req, \%data, $col);
   }
@@ -3422,6 +3443,7 @@ my %defaults =
    inherit_siteuser_rights => 1,
    menu => 0,
    titleAlias => '',
+   linkAlias => '',
   );
 
 sub default_value {
index 972ba10..6d8d5e8 100644 (file)
@@ -142,20 +142,25 @@ sub _get_article {
   my $cfg = $self->{gen}->{cfg}
     or confess "cfg not set in acts";
   my $dispid;
+  my $art;
   if ($id =~ /^\d+$/) {
     $dispid = $id;
+    $art = $self->{articles}->getByPkey($id);
   }
-  else {
+  elsif (my $work = $cfg->entry('articles', $id)) {
     # try to find it in the config
-    my $work = $cfg->entry('articles', $id);
-    unless ($work) {
-      $$error = "&#42;&#42; No article name '".escape_html($id)."' in the [articles] section of bse.cfg &#42;&#42;";
-      return;
-    }
     $dispid = "$id ($work)";
     $id = $work;
+    $art = $self->{articles}->getByPkey($id);
+  }
+  else {
+    ($art) = $self->{articles}->getBy(linkAlias => $id);
+    unless ($art) {
+      $$error = "&#42;&#42; No article name '".escape_html($id)."' found &#42;&#42;";
+      return;
+    }
   }
-  my $art = $self->{articles}->getByPkey($id);
+
   unless ($art) {
     $$error = "&#42;&#42; Cannot find article id $dispid &#42;&#42;";
     return;
@@ -176,8 +181,7 @@ sub doclink {
 
   # make the URL absolute if necessary
   my $admin = $self->{gen}{admin};
-  my $link = $admin ? 'admin' : 'link';
-  my $url = $art->{$link};
+  my $url = $admin ? $art->{admin} : $art->link($self->{gen}{cfg});
   if ($self->{abs_urls}) {
     $url = $cfg->entryErr('site', 'url') . $url
       unless $url =~ /^\w+:/;
index 54314f5..2bffa81 100644 (file)
@@ -3,7 +3,7 @@ use strict;
 use base 'Generate::Product';
 use BSE::TB::Seminars;
 use DevHelp::HTML;
-use BSE::Util::Tags qw(tag_hash);
+use BSE::Util::Tags qw(tag_article);
 use BSE::Util::Iterate;
 
 sub baseActs {
@@ -17,7 +17,7 @@ sub baseActs {
   return
     (
      $self->SUPER::baseActs($articles, $acts, $seminar, $embedded),
-     seminar => [ \&tag_hash, $seminar ],
+     seminar => [ \&tag_article, $self->{cfg}, $seminar ],
      admin => [ tag_admin => $self, $seminar, 'seminar', $embedded ],
      $it->make_iterator([ \&iter_sessions, $seminar ], 'session', 'sessions'),
      $it->make_iterator
index 9086e67..214da18 100644 (file)
@@ -10,10 +10,32 @@ sub dispatch {
 
   my $cgi = $req->cgi;
   my $id = $cgi->param('page');
-  $id && $id =~ /^\d+$/
-    or return $class->error($req, "required page parameter not present or invalid");
-  my $article = Articles->getByPkey($id)
-    or return $class->error($req, "unknown article id $id");
+  my $article;
+  my $prefix = $req->cfg->entry('article', 'alias_prefix', '');
+  my @more_headers;
+  if ($id) {
+    $id && $id =~ /^\d+$/
+      or return $class->error($req, "page parameter not valid");
+    $article = Articles->getByPkey($id)
+      or return $class->error($req, "unknown article id $id");
+  }
+  elsif (my $alias = $cgi->param('alias')) {
+    $article = Articles->getBy(linkAlias => $alias)
+      or return $class->error($req, "Unknown article alias '$alias'");
+  }
+  elsif ($ENV{REDIRECT_URL} && $ENV{SCRIPT_URL} =~ m(^\Q$prefix\E/)) {
+    (my $url = $ENV{SCRIPT_URL}) =~ s(^\Q$prefix\E/)();
+    my ($alias) = $url =~ /^([a-zA-Z0-9_]+)/
+      or return $class->error($req, "Missing document $ENV{SCRIPT_URL}");
+
+    $article = Articles->getBy(linkAlias => $alias)
+      or return $class->error($req, "unknown article alias '$alias'");
+
+    # have the client treat this as successful, though an error is
+    # still written to the Apache error log
+    push @more_headers, "Status: 200";
+  }
+  $id = $article->{id};
 
   # get the dynamic generate for this article type
   my $gen_class = $article->{generator};
@@ -68,7 +90,13 @@ sub dispatch {
     $template = $class->_generate_pregen($req, $article, $srcname);
   }
 
-  return $gen->generate($article, $template);
+  my $result = $gen->generate($article, $template);
+
+  if (@more_headers) {
+    push @{$result->{headers}}, @more_headers;
+  }
+
+  return $result;
 }
 
 # returns an error page
index 955c987..96fd212 100644 (file)
@@ -1,6 +1,6 @@
 package BSE::Util::DynamicTags;
 use strict;
-use BSE::Util::Tags;
+use BSE::Util::Tags qw(tag_article);
 use DevHelp::HTML;
 use base 'BSE::ThumbLow';
 
@@ -19,11 +19,11 @@ sub tags {
      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'),
+     $self->dyn_article_iterator('dynlevel1s', 'dynlevel1'),
+     $self->dyn_article_iterator('dynlevel2s', 'dynlevel2'),
+     $self->dyn_article_iterator('dynlevel3s', 'dynlevel3'),
+     $self->dyn_article_iterator('dynallkids_of', 'dynofallkid'),
+     $self->dyn_article_iterator('dynchildren_of', 'dynofchild'),
      $self->dyn_iterator('dyncart', 'dyncartitem'),
      url => [ tag_url => $self ],
      dyncarttotalcost => [ tag_dyncarttotal => $self, 'total_cost' ],
@@ -112,7 +112,13 @@ sub tag_url {
   my $article = $self->{req}->get_article($name)
     or return "** unknown article $name **";
 
-  my $value = $article->{$item};
+  my $value;
+  if ($item eq 'link' and ref $article ne 'HASH') {
+    $value = $article->link;
+  }
+  else {
+    $value = $article->{$item};
+  }
 
   # we don't know our context, so always produce absolute URLs
   if ($value !~ /^\w+:/) {
@@ -314,6 +320,19 @@ sub _dyn_item {
   return escape_html($value);
 }
 
+sub _dyn_article {
+  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 '';
+
+  return tag_article($item, $self->{req}->cfg, $args);
+}
+
 sub _dyn_index {
   my ($self, $rindex, $rdata, $single) = @_;
 
@@ -385,6 +404,35 @@ sub dyn_iterator {
     );
 }
 
+sub dyn_article_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_article => $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) = @_;
 
index 04f3878..50e561e 100644 (file)
@@ -35,4 +35,25 @@ sub make_paged_iterator {
      [ \&_paged_get, $session, $name ], $rstore);
 }
 
+package BSE::Util::Iterate::Article;
+use vars qw(@ISA);
+@ISA = 'BSE::Util::Iterate';
+use Carp qw(confess);
+use BSE::Util::Tags qw(tag_article);
+
+sub new {
+  my ($class, %opts) = @_;
+
+  $opts{cfg}
+    or confess "cfg option mission\n";
+
+  return $class->SUPER::new(%opts);
+}
+
+sub item {
+  my ($self, $item, $args) = @_;
+
+  return tag_article($item, $args);
+}
+
 1;
index c327603..7db4960 100644 (file)
@@ -4,7 +4,7 @@ use HTML::Entities;
 use DevHelp::Tags;
 use DevHelp::HTML qw(:default escape_xml);
 use vars qw(@EXPORT_OK @ISA);
-@EXPORT_OK = qw(tag_error_img tag_hash tag_hash_plain tag_hash_mbcs);
+@EXPORT_OK = qw(tag_error_img tag_hash tag_hash_plain tag_hash_mbcs tag_article);
 @ISA = qw(Exporter);
 require Exporter;
 
@@ -954,5 +954,24 @@ sub tag_ajax {
   }
 }
 
+sub tag_article {
+  my ($article, $cfg, $args) = @_;
+
+  my $value;
+  if ($args eq 'link'
+     && ref($article) ne 'HASH') {
+    $value = $article->link($cfg);
+  }
+  else {
+    $value = $article->{$args};
+    defined $value or $value = '';
+    if ($value =~ /\cJ/ && $value =~ /\cM/) {
+      $value =~ tr/\cM//d;
+    }
+  }
+
+  return escape_html($value);
+}
+
 1;
 
index 15eebb0..66cff95 100644 (file)
@@ -31,17 +31,22 @@ sub _iter_iterate {
   return;
 }
 
+sub item {
+  my ($self, $entry, $args) = @_;
+
+  my $value = $entry->{$args};
+  defined $value or return '';
+
+  return $self->escape($value);
+}
+
 sub _iter_item {
   my ($self, $rdata, $rindex, $single, $plural, $args) = @_;
 
   $$rindex >= 0 && $$rindex < @$rdata
     or return "** $single should only be used inside iterator $plural **";
 
-  my $value = $rdata->[$$rindex]{$args};
-
-  defined $value or return '';
-
-  return $self->escape($value);
+  return $self->item($rdata->[$$rindex], $args);
 }
 
 sub _iter_number_paged {
index ec55594..4ca1dee 100644 (file)
@@ -5,7 +5,7 @@ use Constants qw($IMAGEDIR $LOCAL_FORMAT $BODY_EMBED
                  $EMBED_MAX_DEPTH $HAVE_HTML_PARSER);
 use DevHelp::Tags;
 use DevHelp::HTML;
-use BSE::Util::Tags;
+use BSE::Util::Tags qw(tag_article);
 use BSE::CfgInfo qw(custom_class);
 use BSE::Util::Iterate;
 use base 'BSE::ThumbLow';
@@ -304,7 +304,7 @@ sub format_body {
 
 sub embed {
   my ($self, $article, $articles, $template) = @_;
-  
+
   if (defined $template && $template =~ /\$/) {
     $template =~ s/\$/$article->{template}/;
   }
@@ -472,13 +472,15 @@ sub tag_sthumbimage {
     require Articles;
     $article = Articles->getByPkey($args);
   }
-  else {
-    $acts->{$article_id}
-      or return "** no tag $article_id **";
+  elsif ($acts->{$article_id}) {
     my $id = $templater->perform($acts, $article_id, "id");
     $article = Articles->getByPkey($id)
       or return "** article $article_id/$id not found **";
   }
+  else {
+    ($article) = Articles->getBy(linkAlias => $article_id)
+      or return "** no article $article_id found **";
+  }
   $article
     or return '';
 
@@ -530,6 +532,7 @@ sub baseActs {
 
   my $current_gimage;
   my $it = BSE::Util::Iterate->new;
+  my $art_it = BSE::Util::Iterate::Article->new(cfg => $cfg);
   return 
     (
      %extras,
@@ -579,7 +582,7 @@ sub baseActs {
        }
      },
      level1 => sub {
-       return escape_html($sections[$section_index]{$_[0]});
+       return tag_article($sections[$section_index], $cfg, $_[0]);
      },
 
      # used to generate a list of subsections for the side-menu
@@ -594,7 +597,7 @@ sub baseActs {
        return 0;
      },
      level2 => sub {
-       return escape_html($subsections[$subsect_index]{$_[0]});
+       return tag_article($subsections[$subsect_index], $cfg, $_[0]);
      },
      ifLevel2 => 
      sub {
@@ -605,7 +608,9 @@ sub baseActs {
      iterate_level3 => sub {
        return ++$level3_index < @level3;
      },
-     level3 => sub { escape_html($level3[$level3_index]{$_[0]}) },
+     level3 => sub { 
+       tag_article($level3[$level3_index], $cfg, $_[0])
+     },
      ifLevel3 => sub { scalar @level3 },
 
      # generate an admin or link url, depending on admin state
@@ -631,18 +636,18 @@ sub baseActs {
          return escape_html($text);
        }
      },
-     $it->make_iterator( \&iter_kids_of, 'ofchild', 'children_of', 
+     $art_it->make_iterator( \&iter_kids_of, 'ofchild', 'children_of', 
                         undef, undef, 'nocache' ), 
-     $it->make_iterator( \&iter_kids_of, 'ofchild2', 'children_of2',
+     $art_it->make_iterator( \&iter_kids_of, 'ofchild2', 'children_of2',
                         undef, undef, 'nocache' ),
-     $it->make_iterator( \&iter_kids_of, 'ofchild3', 'children_of3',
+     $art_it->make_iterator( \&iter_kids_of, 'ofchild3', 'children_of3',
                          undef, undef, 'nocache' ),
-     $it->make_iterator( [ iter_all_kids_of => $self ], 'ofallkid', 'allkids_of' ), 
-     $it->make_iterator( [ iter_all_kids_of => $self ], 'ofallkid2', 'allkids_of2', 
+     $art_it->make_iterator( [ iter_all_kids_of => $self ], 'ofallkid', 'allkids_of' ), 
+     $art_it->make_iterator( [ iter_all_kids_of => $self ], 'ofallkid2', 'allkids_of2', 
                         undef, undef, 'nocache' ), 
-     $it->make_iterator( [ iter_all_kids_of => $self ], 'ofallkid3', 'allkids_of3',
+     $art_it->make_iterator( [ iter_all_kids_of => $self ], 'ofallkid3', 'allkids_of3',
                         undef, undef, 'nocache' ), 
-     $it->make_iterator( \&iter_inlines, 'inline', 'inlines' ),
+     $art_it->make_iterator( \&iter_inlines, 'inline', 'inlines' ),
      gimage => 
      sub {
        my ($name, $align, $rest) = split ' ', $_[0], 3;
index 1ff9fd6..5e7d2f1 100644 (file)
@@ -7,12 +7,13 @@ use Images;
 use vars qw(@ISA);
 use Generate;
 use Util qw(generate_button);
-use BSE::Util::Tags;
+use BSE::Util::Tags qw(tag_article);
 use ArticleFiles;
 @ISA = qw/Generate/;
 use DevHelp::HTML;
 use BSE::Arrows;
 use Carp 'confess';
+use BSE::Util::Iterate;
 
 my $excerptSize = 300;
 
@@ -73,9 +74,9 @@ sub tag_title {
   exists $acts->{$which} 
     or return "** no such object $which **";
 
-  my $title = $acts->{$which}->('title');
+  my $title = $templater->perform($acts, $which, 'title');
   my $imagename = $which eq 'article' ? $article->{titleImage} : 
-    $acts->{$which}->('titleImage');
+    $templater->perform($acts, $which, 'titleImage');
   $imagename and
     return qq!<img src="/images/titles/$imagename"!
       .qq! border="0" alt="$title" />! ;
@@ -84,7 +85,7 @@ sub tag_title {
     ($im) = grep lc $_->{name} eq 'bse_title', @$images;
   }
   else {
-    my $id = $acts->{$which}->('id');
+    my $id = $templater->perform($acts, $which, 'id');
     require Images;
     my @images = Images->getBy(articleId=>$id);
     ($im) = grep lc $_->{name} eq 'bse_title', @$images;
@@ -152,16 +153,6 @@ HTML
   return $html;
 }
 
-sub tag_article {
-  my ($article, $arg) = @_;
-
-  $arg or return '';
-  $article or return '';
-  defined $article->{$arg} or return '';
-
-  return escape_html($article->{$arg});
-}
-
 sub abs_urls {
   my ($self, $article) = @_;
 
@@ -191,8 +182,8 @@ sub tag_admin {
      BSE::Util::Tags->static(\%acts, $cfg),
      BSE::Util::Tags->admin(\%acts, $cfg),
      BSE::Util::Tags->secure($self->{request}),
-     article => [ \&tag_article, $article ],
-     parent => [ \&tag_article, $parent ],
+     article => [ \&tag_article, $article, $cfg ],
+     parent => [ \&tag_article, $parent, $cfg ],
      ifParent => $parent,
      ifEmbedded => $embedded,
     );
@@ -262,11 +253,12 @@ sub baseActs {
   }
   my $allkids_index;
   my $current_image;
+  my $art_it = BSE::Util::Iterate::Article->new(cfg =>$cfg);
   # separate these so the closures can see %acts
   my %acts =
     (
      $self->SUPER::baseActs($articles, $acts, $article, $embedded),
-     article=>sub { escape_html($article->{$_[0]}) },
+     article=>[ \&tag_article, $article, $cfg ],
      ifTitleImage => 
      sub { 
        my $which = shift || 'article';
@@ -330,10 +322,10 @@ sub baseActs {
      },
      child =>
      sub {
-       return escape_html($children[$child_index]{$_[0]});
+       return tag_article($children[$child_index], $cfg, $_[0]);
      },
 
-     section=>sub { escape_html($section->{$_[0]}) },
+     section=> [ \&tag_article, $section, $cfg ],
 
      # these are mostly obsolete, use moveUp and moveDown instead
      # where possible
@@ -378,11 +370,11 @@ sub baseActs {
      crumbs =>
      sub {
        # obsolete me
-       return escape_html($work_crumbs[$crumb_index]{$_[0]});
+       return tag_article($work_crumbs[$crumb_index], $cfg, $_[0]);
      },
      crumb =>
      sub {
-       return escape_html($work_crumbs[$crumb_index]{$_[0]});
+       return tag_article($work_crumbs[$crumb_index], $cfg, $_[0]);
      },
      ifCrumbs =>
      sub {
@@ -401,7 +393,7 @@ sub baseActs {
      # access to parent
      ifParent => sub { $parent },
      parent =>
-     sub { return $parent && escape_html($parent->{$_[0]}) },
+     sub { return $parent && tag_article($parent, $cfg, $_[0]) },
      # for rearranging order in admin mode
      moveDown=>
      sub {
@@ -554,9 +546,9 @@ HTML
      thumbimage => [ tag_thumbimage => $self, \$current_image, \@images ],
      BSE::Util::Tags->make_iterator(\@files, 'file', 'files'),
      BSE::Util::Tags->make_iterator(\@stepkids, 'stepkid', 'stepkids'),
-     BSE::Util::Tags->make_iterator(\@allkids, 'allkid', 'allkids', \$allkids_index),
-     BSE::Util::Tags->make_iterator(\@stepparents, 'stepparent', 'stepparents'),
-     top => [ \&tag_top, $self, $article ],
+     $art_it->make_iterator(undef, 'allkid', 'allkids', \@allkids, \$allkids_index),
+     $art_it->make_iterator(undef, 'stepparent', 'stepparents', \@stepparents),
+     top => [ \&tag_article, $cfg, $self->{top} || $article ],
      ifDynamic => $dynamic,
      ifAccessControlled => [ \&tag_ifAccessControlled, $article ],
     );
@@ -685,17 +677,6 @@ sub tag_movekid {
   return make_arrows($self->{cfg}, $down_url, $up_url, $refreshto, $img_prefix);
 }
 
-sub tag_top {
-  my ($self, $article, $args) = @_;
-
-  my $top = $self->{top} || $article;
-
-  my $value = $top->{$args};
-  defined $value or $value = '';
-
-  escape_html($value);
-}
-
 1;
 
 __END__
index 3ddd05b..1d834e3 100644 (file)
@@ -131,12 +131,14 @@ sub generate_low {
   my $catalog_index = -1;
   my $allcat_index;
   my $it = BSE::Util::Iterate->new;
+  my $cfg = $self->{cfg};
+  my $art_it = BSE::Util::Iterate::Article->new(cfg => $cfg);
   my %acts;
   %acts =
     (
      $self->baseActs($articles, \%acts, $article, $embedded),
-     article => sub { escape_html($article->{$_[0]}) },
-     $it->make_iterator(undef, 'product', 'products', \@products, 
+     #article => sub { escape_html($article->{$_[0]}) },
+     $art_it->make_iterator(undef, 'product', 'products', \@products, 
                        \$product_index),
      admin => [ tag_admin => $self, $article, 'catalog', $embedded ],
      # for rearranging order in admin mode
@@ -203,13 +205,13 @@ HTML
        return make_arrows($self->{cfg}, $down_url, $up_url, $refreshto, $img_prefix);
      },
      ifAnyProds => scalar(@allprods),
-     $it->make_iterator(undef, 'stepprod', 'stepprods', \@stepprods,
+     $art_it->make_iterator(undef, 'stepprod', 'stepprods', \@stepprods,
                        \$stepprod_index),
      ifStepProds => sub { @stepprods },
-     $it->make_iterator(undef, 'catalog', 'catalogs', \@subcats, 
+     $art_it->make_iterator(undef, 'catalog', 'catalogs', \@subcats, 
                        \$catalog_index),
      ifSubcats => sub { @subcats },
-     $it->make_iterator(undef, 'allcat', 'allcats', \@allcats, \$allcat_index),
+     $art_it->make_iterator(undef, 'allcat', 'allcats', \@allcats, \$allcat_index),
      moveallcat => 
      [ \&tag_moveallcat, $self, \@allcats, \$allcat_index, $article ],
     );
index 567a244..2881ae7 100644 (file)
@@ -7,7 +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);
+use BSE::Util::Tags qw(tag_article);
 use BSE::CfgInfo 'product_options';
 
 sub edit_link {
@@ -63,7 +63,7 @@ sub baseActs {
   return
     (
      $self->SUPER::baseActs($articles, $acts, $product, $embedded),
-     product=> [ \&tag_hash, $product ],
+     product=> [ \&tag_article, $self->{cfg}, $product ],
      admin => [ tag_admin => $self, $product, 'product', $embedded ],
      iterate_options_reset => sub { $option_index = -1 },
      iterate_options => sub { ++$option_index < @options },
@@ -88,7 +88,7 @@ sub baseActs {
      ifOptions => sub { @options },
      iterate_stepcats_reset => sub { $stepcat_index = -1 },
      iterate_stepcats => sub { ++$stepcat_index < @stepcats },
-     stepcat => sub { escape_html($stepcats[$stepcat_index]{$_[0]}) },
+     stepcat => sub { tag_article($stepcats[$stepcat_index], $self->{cfg}, $_[0]) },
      ifStepCats => sub { @stepcats },
     );
 }
index 2ec160d..067baf5 100644 (file)
@@ -244,7 +244,7 @@ sub cond {
     };
   if ($@) {
     my $msg = $@;
-    if ($msg =~ /^ENOIMPL\b/) {
+    if ($msg =~ /\bENOIMPL\b/) {
       print STDERR "Cond ENOIMPL\n" if DEBUG;
       $true = $self->replace_template($true, $acts) if length $true;
       $false = $self->replace_template($false, $acts) if length $false;
index 47578b6..c8ac2c2 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 # -d:ptkdb
-BEGIN { $ENV{DISPLAY} = '192.168.32.50:0.0' }
+BEGIN { $ENV{DISPLAY} = '192.168.32.51:0.0' }
 use strict;
 use FindBin;
 use lib "$FindBin::Bin/modules";
index 5e1f4c7..f83c9e6 100644 (file)
@@ -16,6 +16,37 @@ Maybe I'll add some other bits here.
 
 =item *
 
+check the freshness of the database connection on each request for
+fcgi
+
+=item *
+
+added hooks to process login, logout, sending session cookies.
+
+=item *
+
+articles created by the newletter tool are now more consistent with
+articles created using the article editor.
+
+=item *
+
+added a default favicon.ico
+
+=item *
+
+release is a reserved word in mysql 5.0, quote it appropriately
+
+=item *
+
+include filename information in the content disposition when
+downloading a file for display inline.
+
+=item *
+
+avoid double HTML-escaping the displayed filename for filelink
+
+=item *
+
 add dthumbimage tag, see BSE::Util::DynamicTags for documentation
 
 =item *
index 7260cbe..0a42612 100644 (file)
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">List article:</th>
             <td bgcolor="#FFFFFF" width="100%"> <:if FieldPerm listed:><:list listed:><:or FieldPerm:><:if Article listed:><:ifEq [article listed] "1":>Yes<:or:>In Sections, but not menu<:eif:><:or Article:>No<:eif Article:><:eif FieldPerm:> </td>
             <td nowrap="nowrap" bgcolor="#FFFFFF"><:help edit listed:> <:error_img listed:></td>
+          </tr>
+          <tr> 
+            <th nowrap bgcolor="#FFFFFF" align="left">Link alias: 
+            </th>
+            <td bgcolor="#FFFFFF" width="100%"> 
+            <:ifFieldPerm linkAlias:><input type="text" name="linkAlias" maxlength="<:cfg fields linkAlias_size 255:>" size="40" value="<: old linkAlias article linkAlias :>">
+            <:or:><:default linkAlias:><:eif:></td>
+            <td nowrap bgcolor="#FFFFFF"><:help edit linkAlias:> <:error_img linkAlias:></td>
           </tr>
                  <tr>
             <th valign="top" nowrap="nowrap" bgcolor="#FFFFFF" align="left">Flags:</th>
index 0501545..9e808cf 100644 (file)
             <th bgcolor="#FFFFFF" nowrap="nowrap" align="left">List article:</th>
             <td bgcolor="#FFFFFF" width="100%"> <:if FieldPerm listed:><:list listed:><:or FieldPerm:><:if Article listed:><:ifEq [article listed] "1":>Yes<:or:>In Sections, but not menu<:eif:><:or Article:>No<:eif Article:><:eif FieldPerm:> </td>
             <td nowrap="nowrap" bgcolor="#FFFFFF"><:help catalog list:> <:error_img listed:></td>
+          </tr>
+          <tr> 
+            <th nowrap bgcolor="#FFFFFF" align="left">Link alias: 
+            </th>
+            <td bgcolor="#FFFFFF" width="100%"> 
+            <:ifFieldPerm linkAlias:><input type="text" name="linkAlias" maxlength="<:cfg fields linkAlias_size 255:>" size="40" value="<: old linkAlias article linkAlias :>">
+            <:or:><:default linkAlias:><:eif:></td>
+            <td nowrap bgcolor="#FFFFFF"><:help edit linkAlias:> <:error_img linkAlias:></td>
           </tr>
                  <tr>
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">Flags:</th>
index 578880f..2611f60 100644 (file)
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">List article:</th>
             <td bgcolor="#FFFFFF" width="100%"> <:if FieldPerm listed:><:list listed:><:or FieldPerm:><:if Article listed:><:ifEq [article listed] "1":>Yes<:or:>In Sections, but not menu<:eif:><:or Article:>No<:eif Article:><:eif FieldPerm:> </td>
             <td bgcolor="#FFFFFF"><:help edit listed:> <:error_img listed:></td>
+          </tr>
+          <tr> 
+            <th nowrap bgcolor="#FFFFFF" align="left">Link alias: 
+            </th>
+            <td bgcolor="#FFFFFF" width="100%"> 
+            <:ifFieldPerm linkAlias:><input type="text" name="linkAlias" maxlength="<:cfg fields linkAlias_size 255:>" size="40" value="<: old linkAlias article linkAlias :>">
+            <:or:><:default linkAlias:><:eif:></td>
+            <td nowrap bgcolor="#FFFFFF"><:help edit linkAlias:> <:error_img linkAlias:></td>
           </tr>
                  <tr>
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">Flags:</th>
index 19b05cd..dd3e512 100644 (file)
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">List article:</th>
             <td bgcolor="#FFFFFF" width="100%"> <:if FieldPerm listed:><:list listed:><:or FieldPerm:><:if Article listed:><:ifEq [article listed] "1":>Yes<:or:>In Sections, but not menu<:eif:><:or Article:>No<:eif Article:><:eif FieldPerm:> </td>
             <td bgcolor="#FFFFFF"><:help edit listed:> <:error_img listed:></td>
+          </tr>
+          <tr> 
+            <th nowrap bgcolor="#FFFFFF" align="left">Link alias: 
+            </th>
+            <td bgcolor="#FFFFFF" width="100%"> 
+            <:ifFieldPerm linkAlias:><input type="text" name="linkAlias" maxlength="<:cfg fields linkAlias_size 255:>" size="40" value="<: old linkAlias article linkAlias :>">
+            <:or:><:default linkAlias:><:eif:></td>
+            <td nowrap bgcolor="#FFFFFF"><:help edit linkAlias:> <:error_img linkAlias:></td>
           </tr>
                  <tr>
             <th nowrap="nowrap" bgcolor="#FFFFFF" align="left">Flags:</th>
index 662d99c..03d1ce7 100644 (file)
@@ -72,7 +72,9 @@ Column metaKeywords;varchar(255);NO;;
 Column summaryx;text;NO;;
 Column menu;smallint(5);NO;0;
 Column titleAlias;varchar(60);NO;;
+Column linkAlias;varchar(255);NO;;
 Index PRIMARY;1;[id]
+Index article_alias;0;[linkAlias]
 Index article_date_index;0;[release;expire;id]
 Index article_displayOrder_index;0;[displayOrder]
 Index article_level_index;0;[level;id]
index 9a499d7..2e30624 100644 (file)
--- a/test.cfg
+++ b/test.cfg
@@ -357,3 +357,5 @@ imager thumb driver.blib=/home/tony/dev/imager/svn/Imager
 imager thumb driver.include=/home/tony/dev/imager/svn/Imager/testout:/home/tony/dev/bse
 
 imager thumb driver.debug=1
+
+basic.alias_prefix=/test