Many, many changes to do with making database layer security.

This commit is contained in:
sb 2009-02-06 12:08:28 +00:00
parent e7a4961e9b
commit 7a977d5acd
5 changed files with 875 additions and 626 deletions

View file

@ -9,8 +9,8 @@
Transform ADL into (partial) controller classes
$Author: sb $
$Revision: 1.25 $
$Date: 2009-02-02 10:49:13 $
$Revision: 1.26 $
$Date: 2009-02-06 12:08:28 $
-->
<!-- WARNING WARNING WARNING: Do NOT reformat this file!
@ -18,9 +18,12 @@
<xsl:stylesheet version="1.0"
xmlns="http://libs.cygnets.co.uk/adl/1.1/"
xmlns:adl="http://libs.cygnets.co.uk/adl/1.1/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="urn:schemas-microsoft-com:xslt"
extension-element-prefixes="exsl">
<xsl:include href="csharp-type-include.xslt"/>
<xsl:include href="permissions-include.xslt"/>
<xsl:output encoding="UTF-8" method="text"/>
@ -67,7 +70,7 @@
//
// Automatically generated abstract super class for controllers for the
// <xsl:value-of select="/adl:application/@name"/> application; generated using
// adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.25 $', 10)"/>
// adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.26 $', 10)"/>
//
// <xsl:value-of select="/adl:application/@revision"/>
//
@ -78,8 +81,10 @@
using System;
using System.Data;
using System.Collections.Generic;
using System.Data.SqlClient;
using NHibernate;
using NHibernate.Expression;
using Cygnet.DBAuth;
using Cygnet.Web.Controllers;
using Cygnet.Web.Helpers;
using Castle.MonoRail.Framework;
@ -96,21 +101,55 @@
[ <!-- in the longer term, all the helpers which a given
project needs which not every project needs should be listed here,
with appropriate 'xsl:if' wrappers. -->
Helper(typeof(FormatterHelper), "t"),
Helper(typeof(SecurityHelper), "SecurityHelper")
]
public abstract partial class <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> : BaseController {
<xsl:choose>
<xsl:when test="$authentication-layer = 'Application'"/>
<xsl:when test="$authentication-layer = 'Database'">
public <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/>(){
dbSessionProvider = new DBLayerSessionProvider();
}
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">
ADL: ERROR: invalid value (<xsl:value-of select="$authentication-layer"/>) provided for authentication-layer
</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:for-each select="//adl:entity">
/// &lt;summary&gt;
/// Return a list of all instances of <xsl:value-of select="@name"/> for use in menus, etc;
/// &lt;/summary&gt;
protected IList&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt; <xsl:value-of select="concat( 'FetchAll', @name)"/>( ISession hibernator) {
return hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>))
protected IList&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt; <xsl:value-of select="concat( 'FetchAll', @name)"/>( ) {
IList&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt; result = new List&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt;();
<xsl:variable name="readgroups">
<xsl:call-template name="entity-read-groups">
<xsl:with-param name="entity" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$authentication-layer = 'Database'">
if (
<xsl:for-each select="exsl:node-set( $readgroups)/*">
InGroup( "<xsl:value-of select="./@name"/>")<xsl:if test="position() != last()">||</xsl:if>
</xsl:for-each>
){
</xsl:if>
result = GetDBSession().CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>))
<xsl:for-each select="descendant::adl:property[@distinct='user']">
.AddOrder( <xsl:value-of select="concat('new Order( &#34;', @name, '&#34;, true)')"/>)
</xsl:for-each>
.SetCacheable( true)
.SetCacheRegion( "<xsl:value-of select="/adl:application/@name"/>")
.List&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt;();
<xsl:if test="$authentication-layer != 'Application'">
}
</xsl:if>
return result;
}
</xsl:for-each>
@ -142,7 +181,7 @@
//
// Controller for auto-generated forms for editing <xsl:value-of select="@name"/>s
// Automatically generated from application description using
// adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.25 $', 10)"/>
// adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.26 $', 10)"/>
//
// This file is automatically generated; DO NOT EDIT IT.
//
@ -235,11 +274,7 @@
/// Temporary hack to sort a problem with uninitialised messages
/// &lt;/summary&gt;
public void fixupMessages() {
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
ICollection&lt;<xsl:value-of select="concat($entityns, '.', @name)"/>&gt; instances =
hibernator.CreateCriteria( typeof( <xsl:value-of select="concat($entityns, '.', @name)"/>))
.List&lt;<xsl:value-of select="concat($entityns, '.', @name)"/>&gt;();
@ -270,11 +305,7 @@
/// &lt;/summary&gt;
private void Store()
{
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
List&lt;string&gt; messages = new List&lt;string&gt;();
/* A 'newborn' instance can be updated even if the current user doesn't have
* update permissions, seeing that we use an update operation to set the
@ -571,11 +602,8 @@
if ( ! HasNoErrors())
{
/* the session may be polluted; create a new session */
NHibernateHelper.CloseSession();
hibernator = NHibernateHelper.GetCurrentSession(<xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
CloseDBSession();
hibernator = GetDBSession();
record = FetchRecord( hibernator);
} /* if ( ! HasNoErrors()) */
@ -592,11 +620,7 @@
public void Delete()
{
AssertUserCanDelete();
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
if ( "true".Equals( Params["reallydelete"]))
{
@ -644,11 +668,7 @@
public void InternalShowList( String view)
{
AssertUserCanRead();
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
ICriteria search =
hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>));
@ -679,9 +699,6 @@
IList&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt; instances = search.List&lt;<xsl:value-of select="concat( $entityns, '.', @name)"/>&gt;();
<xsl:if test="$authentication-layer = 'Database'">
PropertyBag["username"] = Session[ NHibernateHelper.USERTOKEN];
</xsl:if>
PropertyBag["instances"] =
PaginationHelper.CreatePagination( this, instances, 25);
@ -736,7 +753,11 @@
<xsl:template match="adl:property">
<xsl:if test="@required='true'">
if ( String.IsNullOrEmpty( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>" ]))
if (
<xsl:if test="@immutable='true'">
(record == null || <xsl:value-of select="concat( 'record.', @name)"/> == null) &amp;&amp;
</xsl:if>
String.IsNullOrEmpty( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>" ]))
{
AddError( <xsl:choose>
<xsl:when test="adl:ifmissing[@locale=$locale]">
@ -784,18 +805,11 @@
</xsl:for-each>
if ( command.Equals( "delete"))
{
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = FetchRecord( hibernator);
TypedPropertyBag = new {
<xsl:if test="$authentication-layer = 'Database'">
username = Session[ NHibernateHelper.USERTOKEN],
</xsl:if>
instance = record };
RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm");
@ -834,11 +848,7 @@
public void <xsl:value-of select="concat($form/@name, 'With', @name)"/>( string <xsl:value-of select="@name"/>)
{
AssertUserCanRead();
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
<xsl:value-of select="ancestor::adl:entity/@name"/> record = new <xsl:value-of select="ancestor::adl:entity/@name"/>();
record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance">
@ -870,11 +880,7 @@
string <xsl:value-of select="concat( ' ', @name)"/>
<xsl:if test="not( position() = last())">,</xsl:if>
</xsl:for-each>) {
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
<xsl:value-of select="concat( 'this.', @name)"/>(
hibernator.CreateCriteria( typeof(<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>))
<xsl:for-each select="ancestor::adl:entity/adl:key/adl:property">
@ -892,11 +898,7 @@
/// &lt;param name="record"&gt;the record to show&lt;/param&gt;
protected void <xsl:value-of select="@name"/>( <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record)
{
ISession hibernator =
NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">
Session[ NHibernateHelper.USERTOKEN],
Session[NHibernateHelper.PASSTOKEN]
</xsl:if>);
ISession hibernator = GetDBSession();
if ( record == null ){
record = new <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>();
@ -905,9 +907,6 @@
}
TypedPropertyBag = new {
<xsl:if test="$authentication-layer = 'Database'">
username = Session[ NHibernateHelper.USERTOKEN],
</xsl:if>
<xsl:call-template name="formmenus">
<xsl:with-param name="form" select="."/>
</xsl:call-template>
@ -1070,7 +1069,7 @@
<xsl:param name="property"/>
<xsl:variable name="entity" select="//adl:entity[@name=$property/@entity]"/>
<xsl:value-of select="concat('all_', $property/@name)"/> =
<xsl:value-of select="concat( 'FetchAll', $entity/@name)"/>( NHibernateHelper.GetCurrentSession()),
<xsl:value-of select="concat( 'FetchAll', $entity/@name)"/>( ),
</xsl:template>
<xsl:template name="primary-key-csharp-type">

View file

@ -8,8 +8,8 @@
Transform ADL into C# entity classes
$Author: sb $
$Revision: 1.16 $
$Date: 2009-02-02 18:13:39 $
$Revision: 1.17 $
$Date: 2009-02-06 12:08:28 $
-->
<!-- WARNING WARNING WARNING: Do NOT reformat this file!
@ -41,6 +41,10 @@
<!-- the name and version of the product being built -->
<xsl:param name="product-version" select="'Application Description Language Framework'"/>
<!-- Whether to authenticate at application or at database layer.
If not 'Application', then 'Database'. -->
<xsl:param name="authentication-layer" select="Application"/>
<!-- strings used in normalising names for constants.
NOTE NOTE NOTE:
this deliberately converts space and punctuation to underscore -->
@ -66,7 +70,7 @@
// (c)2007 Cygnet Solutions Ltd
//
// Automatically generated from application description using
// adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.16 $', 10)"/>
// adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.17 $', 10)"/>
//
// <xsl:value-of select="/adl:application/@revision"/>
//
@ -93,7 +97,7 @@
/// &lt;/summary&gt;
/// &lt;remarks&gt;
/// Automatically generated from description of group <xsl:value-of select="@name"/>
/// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.16 $', 10)"/>.
/// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.17 $', 10)"/>.
///
/// DO NOT EDIT THIS FILE!
/// &lt;/remarks&gt;
@ -119,7 +123,7 @@
// (c)2007 Cygnet Solutions Ltd
//
// Automatically generated from application description using
// adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.16 $', 10)"/>
// adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.17 $', 10)"/>
//
// <xsl:value-of select="/adl:application/@revision"/>
//
@ -145,7 +149,7 @@
/// &lt;/summary&gt;
/// &lt;remarks&gt;
/// Automatically generated from description of entity <xsl:value-of select="@name"/>
/// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.16 $', 10)"/>.
/// using adl2entityclass.xsl revision <xsl:value-of select="substring( '$Revision: 1.17 $', 10)"/>.
/// Note that manually maintained parts of this class may be defined in
/// a separate file called <xsl:value-of select="@name"/>.manual.cs, q.v.
///
@ -288,13 +292,13 @@
<xsl:when test="@type='date'">
<!-- if what we've got is just a date, we only want to see the date part of it -->
if ( <xsl:value-of select="@name"/> != null){
result.Append(<xsl:value-of select="@name"/>.ToString( "d"));
result.Append(((DateTime)<xsl:value-of select="@name"/>).ToShortDateString());
}
</xsl:when>
<xsl:when test="@type='time'">
<!-- if what we've got is just a time, we only want to see the time part of it -->
if ( <xsl:value-of select="@name"/> != null){
result.Append(<xsl:value-of select="@name"/>.ToString( "t"));
result.Append(((DateTime)<xsl:value-of select="@name"/>).ToShortTimeString());
}
</xsl:when>
<xsl:when test="@required = 'true' and (@type = 'integer' or @type = 'real' or @type = 'boolean' or @type = 'money')">
@ -331,6 +335,8 @@
public override string NoDeleteReason {
get {
string result = null;
<xsl:choose>
<xsl:when test="$authentication-layer='Application'">
<xsl:if test="adl:property[@type='list']|adl:property[@type='link']">
StringBuilder bob = new StringBuilder();
<!-- TODO: we ought to start worrying about internationalisation NOW, not later! -->
@ -354,6 +360,12 @@
result = bob.ToString();
}
</xsl:if>
</xsl:when>
<xsl:when test="$authentication-layer='Database'">
/* unfortunately it's not currently possible to compute no-delete reasons
* on 'Database' authenticated applications */
</xsl:when>
</xsl:choose>
return result;
}
}

File diff suppressed because it is too large Load diff

View file

@ -22,8 +22,8 @@
Templates are listed in alphabetical order.
$Author: sb $
$Revision: 1.4 $
$Date: 2009-02-04 18:39:11 $
$Revision: 1.5 $
$Date: 2009-02-06 12:08:28 $
-->
<xsl:template name="i18n-add-a-new">
@ -102,7 +102,7 @@
<xsl:value-of select="concat( $noun, 'es')"/>
</xsl:when>
<xsl:when test="starts-with( substring($noun, string-length($noun) ), 'y')">
<xsl:value-of select="concat( substring( $noun, string-length($noun)), 'ies')"/>
<xsl:value-of select="concat( substring( $noun, 1, string-length($noun) - 1), 'ies')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat( $noun, 's')"/>

View file

@ -0,0 +1,261 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns="http://libs.cygnets.co.uk/adl/1.1/"
xmlns:adl="http://libs.cygnets.co.uk/adl/1.1/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:exsl="urn:schemas-microsoft-com:xslt"
extension-element-prefixes="exsl">
<!--
Application Description Language framework
permissions-include.xslt
(c) 2007 Cygnet Solutions Ltd
Utility templates to find permissions on various things
$Author: sb $
$Revision: 1.1 $
$Date: 2009-02-06 12:08:28 $
-->
<!-- collect all groups which can edit the specified property -->
<xsl:template name="property-edit-groups">
<xsl:param name="property"/>
<xsl:for-each select="//adl:group">
<xsl:variable name="perm">
<xsl:call-template name="property-permission">
<xsl:with-param name="property" select="$property"/>
<xsl:with-param name="groupname" select="@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$perm='all'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='edit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- those groups which can insert -->
<xsl:template name="property-insert-groups">
<xsl:param name="property"/>
<xsl:for-each select="//adl:group">
<xsl:variable name="perm">
<xsl:call-template name="property-permission">
<xsl:with-param name="property" select="$property"/>
<xsl:with-param name="groupname" select="@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$perm='all'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='edit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='insert'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='noedit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- those groups which can read -->
<xsl:template name="property-read-groups">
<xsl:param name="property"/>
<xsl:for-each select="//adl:group">
<xsl:variable name="perm">
<xsl:call-template name="property-permission">
<xsl:with-param name="property" select="$property"/>
<xsl:with-param name="groupname" select="@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$perm='all'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='edit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='insert'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='noedit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='read'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- collect the groups which can read an entity -->
<xsl:template name="entity-read-groups">
<xsl:param name="entity"/>
<xsl:for-each select="//adl:group">
<xsl:variable name="groupname" select="@name"/>
<xsl:variable name="perm">
<xsl:choose>
<xsl:when test="$entity/adl:permission[@group=$groupname]">
<xsl:value-of select="$entity/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:otherwise>none</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$perm='all'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='edit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='insert'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='noedit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='read'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- collect the groups which can delete an entity -->
<xsl:template name="entity-delete-groups">
<xsl:param name="entity"/>
<xsl:for-each select="//adl:group">
<xsl:variable name="groupname" select="@name"/>
<xsl:variable name="perm">
<xsl:choose>
<xsl:when test="$entity/adl:permission[@group=$groupname]">
<xsl:value-of select="$entity/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:otherwise>none</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$perm='all'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- collect the groups which can read a page, form or list -->
<xsl:template name="page-read-groups">
<xsl:param name="page"/>
<xsl:for-each select="//adl:group">
<xsl:variable name="perm">
<xsl:call-template name="page-permission">
<xsl:with-param name="page" select="$page"/>
<xsl:with-param name="groupname" select="@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$perm='all'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='edit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='insert'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='noedit'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:when test="$perm='read'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- find, as a string, the permission which applies to this property in the context of the named group.
NOTE: recurses up the group hierarchy - if it has cycles that's your problem, buster.
page: a page, list or form element
groupname: a string, being the name of a group
-->
<xsl:template name="page-permission">
<xsl:param name="page"/>
<xsl:param name="groupname" select="'public'"/>
<xsl:choose>
<xsl:when test="$page/adl:permission[@group=$groupname]">
<xsl:value-of select="$page/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:when test="$page/ancestor::adl:entity/adl:permission[@group=$groupname]">
<xsl:value-of select="$page/ancestor::adl:entity/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:when test="//adl:group[@name=$groupname]/@parent">
<xsl:call-template name="page-permission">
<xsl:with-param name="page" select="$page"/>
<xsl:with-param name="groupname" select="//adl:group[@name=$groupname]/@parent"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>none</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- find, as a string, the permission which applies to this property in the context of the named group.
NOTE: recurses up the group hierarchy - if it has cycles that's your problem, buster.
property: a property element
groupname: a string, being the name of a group
-->
<xsl:template name="property-permission">
<xsl:param name="property"/>
<xsl:param name="groupname" select="'public'"/>
<xsl:choose>
<xsl:when test="$property/adl:permission[@group=$groupname]">
<xsl:value-of select="$property/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:when test="$property/ancestor::adl:entity/adl:permission[@group=$groupname]">
<xsl:value-of select="$property/ancestor::adl:entity/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:when test="//adl:group[@name=$groupname]/@parent">
<xsl:call-template name="property-permission">
<xsl:with-param name="property" select="$property"/>
<xsl:with-param name="groupname" select="//adl:group[@name=$groupname]/@parent"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>none</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- find, as a string, the permission which applies to this field in the context of the named group
field: a field element
groupname: a string, being the name of a group
-->
<xsl:template name="field-permission">
<xsl:param name="field"/>
<xsl:param name="groupname"/>
<xsl:choose>
<xsl:when test="$field/adl:permission[@group=$groupname]">
<xsl:value-of select="$field/adl:permission[@group=$groupname]/@permission"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="property-permission">
<xsl:with-param name="property" select="$field/ancestor::adl:entity//adl:property[@name=$field/@name]"/>
<xsl:with-param name="groupname" select="$groupname"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>