[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 – 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