[MKDoc-commit] Dynamic sitemap plugin from Sam

chris at mkdoc.demon.co.uk chris at mkdoc.demon.co.uk
Mon Aug 8 15:27:40 BST 2005


Log Message:
-----------
Dynamic sitemap plugin from Sam

Tags:
----
mkdoc-1-6

Modified Files:
--------------
    mkd/conf:
        users.conf
        www.conf

Added Files:
-----------
    mkd/flo/plugin:
        DynamicSitemap.pm
    mkd/templates/dynamic_sitemap:
        document.html
        en.html

-------------- next part --------------
--- /dev/null
+++ flo/plugin/DynamicSitemap.pm
@@ -0,0 +1,213 @@
+# ------------------------------------------------------------------------
+# flo::plugin::DynamicSitemap
+# ------------------------------------------------------------------------
+# Author : Sam Tregar.
+# Copyright : (c) MKDoc Holdings Ltd, 2005.
+#
+# This file is part of MKDoc. 
+# 
+# MKDoc is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# MKDoc is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with MKDoc; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ------------------------------------------------------------------------
+package flo::plugin::DynamicSitemap;
+use strict;
+use warnings;
+
+=head1 NAME
+
+flo::plugin::DynamicSitemap - a sitemap which shows nearby documents only
+
+=head1 SYNOPSIS
+
+Access this plugin like this:
+
+  http://www.example.com/.dyanmic-sitemap.html
+  http://www.example.com/foo/.dyanmic-sitemap.html
+
+=head1 DESCRIPTION
+
+This plugin implements a scope-limited sitemap for a given document.
+Links are shown for all ancestores, direct children and siblings.  If
+the user has permission to visit a document it will be a link.  If it
+has children of its own it will show a [+].  Hidden documents are
+shown only to editors.
+
+=cut
+
+use flo::Standard;
+use lib::sql::Condition;
+use base qw /flo::Plugin/;
+
+sub _name_default { '.dynamic-sitemap.html' }
+
+sub run {
+    my $self = shift;
+    $self->render_http(self => $self);
+
+    return 'TERMINATE';
+}
+
+sub template_path { '/dynamic_sitemap' }
+
+sub nodes {
+    my $self = shift;
+    my $doc  = flo::Standard::current_document();
+    $self->{_current_doc} = $doc;
+
+    # prefetch user-groups, used to resolve permissions
+    $self->{_user_groups} = $self->user ? user_groups($self->user) : [];
+
+    my ($tree, $parent, $cur) = $self->ancestor_tree($doc);
+
+    # add nodes for siblings if there is a parent (i.e. not for root)
+    $self->add_children($parent, $doc->parent) if $parent;
+
+    # add child nodes for the current doc
+    $self->add_children($cur, $doc);
+
+    return $tree;
+}
+
+# adds child nodes, sorting based on document sort ordering
+sub add_children {
+    my ($self, $node, $doc) = @_;
+    my $cur = $self->{_current_doc};
+    
+    my @nodes = map { $self->new_node($_) } 
+                grep { $_->id != $cur->id }
+                $self->get_children($doc);
+    push @{$node->{children}}, @nodes;
+
+    # sort the sibling list
+    $node->{children} = $self->sort_children($doc, $node->{children});
+}
+
+sub sort_children {
+    my ($self, $doc, $nodes) = @_;
+
+    my $sort_on = $doc->{Sort_By};
+
+    my @result;
+    if ($sort_on eq 'Sibling_Position') {
+	@result = sort { $a->{doc}{$sort_on} <=> $b->{doc}{$sort_on} } @$nodes;
+    } else {
+	@result = sort { $a->{doc}{$sort_on} cmp $b->{doc}{$sort_on} } @$nodes;
+    }
+
+    @result = reverse @result if $doc->{Order_By};
+
+    return \@result;
+}
+
+sub ancestor_tree {
+    my ($self, $doc) = @_;
+
+    # build nodes for the ancestors and the current doc
+    my @nodes = map { $self->new_node($_) } ($doc->ancestors, $doc);
+
+    # build the tree, top down
+    my $head = (my $p = shift @nodes);
+    my $last;
+    foreach my $node (@nodes) {
+        $last = $p;
+        $p->{children} = [ $node ];
+        $p = $p->{children}[0];
+    }
+
+    # return the root and pointer to the current doc and its parent
+    return ($head, $last, $p);
+}
+
+# creates a new node hash for use in the template, takes a document as
+# the sole arg
+sub new_node {
+    my ($self, $doc) = @_;
+    my $accessible = user_can_see($self->{_user_groups}, $doc);
+    my $children = $accessible ? $self->get_children($doc) : [];
+    return { 
+            doc          => $doc,
+            has_children => @$children ? 1 : 0,
+            is_selected  => $doc->id == $self->{_current_doc}->id,
+            accessible   => $accessible,
+           };
+}
+
+# fetch children from a document, allowing editors to see hidden documents
+sub get_children {
+    my ($self, $doc) = @_;
+    return $doc->children_showable() 
+      unless $self->user and $self->user->group eq 'editor';
+
+    # filter out unshowable but keep the hidden ones
+    my @children = grep { $_->is_showable or $_->is_hidden } $doc->children();
+    
+    return wantarray ? @children : \@children;
+}
+
+# determine if user should be able to see this document, looking at
+# group permissions.  Returns 1 if the user has access, 0 if not.
+sub user_can_see {
+    my ($groups, $document) = @_;
+
+    # lookup groups for the document, no groups means everyone can see it
+    my @doc_group_ids = find_groups($document);
+    return 1 unless @doc_group_ids;
+
+    # no results means the user wasn't in any of the groups, denied
+    return 0 unless @$groups;
+
+    # allow through if the user is in one of the document's groups
+    my %groups = map { ($_->{Grp_ID}, 1) } @$groups;
+    return 1 if grep { $groups{$_} } @doc_group_ids;
+    
+    # no dice
+    return 0;
+}
+
+# get a list of groups for a particular user
+sub user_groups {
+    my $user = shift;
+
+    my $editor_grp_t = flo::Standard::table('Editor_Grp');
+    my $con          = lib::sql::Condition->new(Editor_ID => $user->id);
+    my @groups       = $editor_grp_t->select(cols  => 'Grp_ID',
+                                             where => $con)->fetch_all;
+
+    return \@groups;
+}
+
+# get groups for a document, looking up the tree
+sub find_groups {
+    my $document = shift;
+    my $document_grp_t = flo::Standard::table('Document_Grp');
+
+    # get list of all documents to check
+    my @documents = ($document, $document->ancestors);
+
+    # get results for each document 
+    my %groups;
+    foreach my $doc (@documents) {
+        my @res = $document_grp_t->select (
+	cols => 'Grp_ID',
+        where => lib::sql::Condition->new(Document_ID => $doc->id)
+                                      )->fetch_all();
+        $groups{$_->{Grp_ID}} = 1 for @res;
+    }
+
+    return keys %groups;
+}
+
+
+1;
Index: users.conf
===================================================================
RCS file: /var/spool/cvs/mkd/conf/Attic/users.conf,v
retrieving revision 1.1.2.38
retrieving revision 1.1.2.39
diff -Lconf/users.conf -Lconf/users.conf -u -r1.1.2.38 -r1.1.2.39
--- conf/users.conf
+++ conf/users.conf
@@ -11,6 +11,7 @@
 flo::plugin::File
 flo::plugin::Search
 flo::plugin::Sitemap
+flo::plugin::DynamicSitemap
 flo::plugin::Print
 flo::plugin::Poll
 flo::plugin::Photo
Index: www.conf
===================================================================
RCS file: /var/spool/cvs/mkd/conf/www.conf,v
retrieving revision 1.1.2.21
retrieving revision 1.1.2.22
diff -Lconf/www.conf -Lconf/www.conf -u -r1.1.2.21 -r1.1.2.22
--- conf/www.conf
+++ conf/www.conf
@@ -11,6 +11,7 @@
 # misc plug-ins
 flo::plugin::Search
 flo::plugin::Sitemap
+flo::plugin::DynamicSitemap
 flo::plugin::Print
 flo::plugin::Poll
 flo::plugin::Photo
--- /dev/null
+++ templates/dynamic_sitemap/document.html
@@ -0,0 +1,65 @@
+<li xmlns:petal="http://purl.org/petal/1.0/">
+  <b petal:omit-tag="false:child/is_selected">  
+    <span
+      petal:condition="child/has_children"
+      petal:omit-tag="string:1"
+    >
+      <a 
+        href="#"
+        hreflang="en"
+        lang="en"
+        xml:lang="en"
+        petal:attributes="href string:${child/doc/Full_Path}.dynamic-sitemap.html; 
+                          hreflang child/doc/Lang; 
+                          lang child/doc/Lang;
+                          xml:lang child/doc/Lang"
+        petal:condition="false:child/is_selected"
+      >
+        [+]
+      </a>
+      <a 
+        href="#"
+        hreflang="en"
+        lang="en"
+        xml:lang="en"
+        petal:attributes="href string:${child/doc/Full_Path}../.dynamic-sitemap.html; 
+                          hreflang child/doc/Lang; 
+                          lang child/doc/Lang;
+                          xml:lang child/doc/Lang"
+        petal:condition="true:child/is_selected"
+      >
+      <!--? this should be an &ndash; but for some reason that won't work ?-->
+        [-]
+      </a>
+    </span>
+    <a 
+      href="#"
+      hreflang="en"
+      lang="en"
+      xml:lang="en"
+      petal:attributes="href child/doc/Full_Path; 
+                        hreflang child/doc/Lang; 
+                        lang child/doc/Lang;
+                        xml:lang child/doc/Lang"
+      petal:content="child/doc/Title"
+      petal:condition="true:child/accessible"
+    >
+        Accessible Child Document Title
+    </a>
+    <span
+      petal:attributes="lang child/doc/Lang;
+                        xml:lang child/doc/Lang"
+      petal:content="child/doc/Title"
+      petal:condition="false:child/accessible"
+    >
+        Inaccessible Child Document Title
+    </span>
+  </b>
+  <ul 
+    petal:define="children child/children"
+    petal:condition="children"
+    petal:repeat="child children"
+  >
+    <?include file="/dynamic_sitemap/document.html"?>
+  </ul>
+</li>
--- /dev/null
+++ templates/dynamic_sitemap/en.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html PUBLIC
+  "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
+>
+<!--?
+
+
+This template is used for rendering the sitemap page.  
+
+?-->
+<html  
+  lang="en"
+  xml:lang="en"
+  dir="ltr"
+  petal:define="
+    here                  self;
+    title                 string:Sitemap;
+    lang                  self/lang;
+    dir                   self/direction;
+    align                 self/align;
+    align_opposite        self/align_opposite;
+    sitemap               plugin: flo::plugin::DynamicSitemap;"
+  petal:attributes="lang lang; xml:lang lang; dir dir;"
+  xmlns:petal="http://purl.org/petal/1.0/"
+  xmlns="http://www.w3.org/1999/xhtml"
+>
+
+<!--? public file header ?-->
+<?include file="/fragments/head_public/"?>
+
+<body 
+  lang="en"
+  xml:lang="en"
+  dir="ltr"
+  petal:attributes="lang lang; xml:lang lang; dir dir;"
+  petal:set="child root"
+>
+
+<!--? navigation header ?-->
+<?include file="/fragments/header/"?>
+
+<div class="content">
+  <h1 
+    lang="en"
+    xml:lang="en"
+    dir="ltr"
+    align="left"
+    petal:attributes="align align"
+    petal:define="child self/nodes"
+  >
+    Sitemap
+  </h1>
+
+  <ul>
+     <?include file="/dynamic_sitemap/document.html"?>
+  </ul>
+
+</div>    
+
+</body>
+
+</html>
+


More information about the MKDoc-commit mailing list