Sunday 25 May 2008

Permissions Attribute class Helper Extension Methods - Part 3

Articles in this Series

Helper Extension Methods

The attribute data is held in:

  • MetaTable.Attributes
  • MetaColumn.Attributes
  • MetaForeignKeyColumn.ParentTable.Attribute
  • MetaChildrenColumn.ChildTable.Attributes

Form the above list four extension methods will be needed on to deal with each type.

  • What data type should the extension method operate on? The obvious type would be AttributeCollection but would move unnecessary casting in some of the other extension methods. The types will be MetaTable for the table permissions extension method and MetaColumn for the others and any casting will then be hidden in the extension methods themselves.
  • What type should the extension method return? The obvious and correct type would be the TablePermissionsAttribute.Permissions or FieldPermissionsAttribute.Permissions types and since there could be multiple entries per class/property then a generic List<T> of the type should be returned.
  • What other parameter will be need? A role of type String, but because a user can have several roles it should be roles of type String[] because this is what is returned by Roles.GetRolesForUser().

If a breakpoint is set at an instance of column of type MetaColumn (see Figure 1) it can be seen that the column.Attributes is of type System.ComponentModel.AttributeCollection and 1 & 2 are FieldPermissionsAttributes this means that the collection will need to be iterated through to pick out the FieldPermissionsAttributes.

Figure 1

Figure 1

Let us look at the extension method definition for MetaColumn.Attributes.

public static List<FieldPermissionsAttribute.Permissions>
GetFieldPermissions(this MetaColumn column, String[] roles)
{
    List<FieldPermissionsAttribute.Permissions> permissions = 
        new List<FieldPermissionsAttribute.Permissions>();
    //TODO: get attributes permissions
    return permissions;
}

Listing 1

Calling the GetFieldPermissions extension method:

var fieldPermissions = column.GetFieldPermissions(Roles.GetRolesForUser());
In Listing 1 each attribute is checked to see if it has one of the users roles passed in from the GetRolesForUser() method of the Roles class. If a match is found then the permission is added to “permissions” local variable.
public static List<FieldPermissionsAttribute.Permissions>
    GetFieldPermissions(this MetaColumn column, String[] roles)
{
    var permissions = new List<FieldPermissionsAttribute.Permissions>();

    // you could put: 
    // var attributes = column.Attributes;
    // but to make it clear what type we are using:
    System.ComponentModel.AttributeCollection attributes = column.Attributes;

    // check to see if any roles passed
    if (roles.Count() > 0)
    {
        // using Linq to Object to get 
        // the permissions foreach role
        permissions =
            (from a in attributes.OfType<FieldPermissionsAttribute>()
             where a.HasAnyRole(roles)
             select a.Permission).ToList<FieldPermissionsAttribute.Permissions>();
    }
    return permissions;
}

Listing 2

Above in Listing 2 is the full helper extension method GetFieldPermissions three more extension methods are required to cater for:

  • Table
  • ChileTable
  • ParentTable

MetaColumn Types. Below in Listing 3 are all the extension methods for the Permissions Attributes classes.

/// <summary>
/// Permissions Attributes Helper Extension Methods
/// </summary>
public static class PermissionsAttributesHelper
{
    /// <summary>
    /// Get a list of permissions for the specified role
    /// </summary>
    /// <param name="attributes">
    /// Is a AttributeCollection taken 
    /// from the column of a MetaTable
    /// </param>
    /// <param name="role">
    /// name of the role to be matched with
    /// </param>
    /// <returns>A List of permissions</returns>
    public static List<FieldPermissionsAttribute.Permissions>
    GetFieldPermissions(this MetaColumn column, String[] roles)
    {
        var permissions = new List<FieldPermissionsAttribute.Permissions>();

        // you could put: 
        // var attributes = column.Attributes;
        // but to make it clear what type we are using:
        System.ComponentModel.AttributeCollection attributes = column.Attributes;

        // check to see if any roles passed
        if (roles.Count() > 0)
        {
            // using Linq to Object to get 
            // the permissions foreach role
            permissions =
                (from a in attributes.OfType<FieldPermissionsAttribute>()
                 where a.HasAnyRole(roles)
                 select a.Permission).ToList<FieldPermissionsAttribute.Permissions>();
        }
        return permissions;
    }

    /// <summary>
    /// Get a list of permissions for the specified role
    /// </summary>
    /// <param name="attributes">
    /// Is a AttributeCollection taken from the column of a MetaTable
    /// </param>
    /// <param name="role">name of the role to be matched with</param>
    /// <returns>A List of permissions</returns>
    public static List<TablePermissionsAttribute.Permissions>
        GetTablePermissions(this MetaTable table, String[] roles)
    {
        var permissions = new List<TablePermissionsAttribute.Permissions>();
        var attributes = table.Attributes;

        // check to see if any roles passed
        if (roles.Count() > 0)
        {
            // using Linq to Object to get 
            // the permissions foreach role
            permissions =
                (from a in attributes.OfType<TablePermissionsAttribute>()
                 where a.HasAnyRole(roles)
                 select a.Permission).ToList<TablePermissionsAttribute.Permissions>();
        }
        return permissions;
    }

    /// <summary>
    /// Get a list of permissions for the specified role
    /// </summary>
    /// <param name="attributes">
    /// Is a AttributeCollection taken from the column of a MetaTable
    /// </param>
    /// <param name="role">name of the role to be matched with</param>
    /// <returns>A List of permissions</returns>
    public static List<TablePermissionsAttribute.Permissions>
        GetFkTablePermissions(this MetaColumn column, String[] roles)
    {
        var permissions = new List<TablePermissionsAttribute.Permissions>();
        var foreignKeyColumn = column as MetaForeignKeyColumn;
        var attributes = foreignKeyColumn.ParentTable.Attributes;

        // check to see if any roles passed
        if (roles.Count() > 0)
        {
            // using Linq to Object to get 
            // the permissions foreach role
            permissions =
                (from a in attributes.OfType<TablePermissionsAttribute>()
                 where a.HasAnyRole(roles)
                 select a.Permission).ToList<TablePermissionsAttribute.Permissions>();
        }
        return permissions;
    }

    /// <summary>
    /// Get a list of permissions for the specified role
    /// </summary>
    /// <param name="attributes">
    /// Is a AttributeCollection taken from the column of a MetaTable
    /// </param>
    /// <param name="role">name of the role to be matched with</param>
    /// <returns>A List of permissions</returns>
    public static List<TablePermissionsAttribute.Permissions>
        GetChildrenTablePermissions(this MetaColumn column, String[] roles)
    {
        var permissions = new List<TablePermissionsAttribute.Permissions>();
        var childrenColumn = column as MetaChildrenColumn;
        var attributes = childrenColumn.Attributes;

        // check to see if any roles passed
        if (roles.Count() > 0)
        {
            // using Linq to Object to get 
            // the permissions foreach role
            permissions =
                (from a in attributes.OfType<TablePermissionsAttribute>()
                 where a.HasAnyRole(roles)
                 select a.Permission).ToList<TablePermissionsAttribute.Permissions>();
        }
        return permissions;
    }

    /// <summary>
    /// Returns a copy of the array of string 
    /// all in lowercase
    /// </summary>
    /// <param name="strings">Array of strings</param>
    /// <returns>array of string all in lowercase</returns>
    public static String[] AllToLower(this String[] strings)
    {
        String[] temp = new String[strings.Count()];
        for (int i = 0; i < strings.Count(); i++)
        {
            temp[i] = strings[i].ToLower();
        }
        return temp;
    }
}

Listing 3

Next putting it all together in the Generate Columns/Rows (using IAutoFieldGenerator)

6 comments:

Unknown said...

Stephen, great set of articles about Dynamic Data. It gives great ideas on how to extend the framework. You could consider using Contains with one of the built in comparers instead of .ToLower()ing every string all the time.

public Boolean HasRole(String role)
{
return _roles.Contains(role, StringComparer.InvariantCultureIgnoreCase);
}

Stephen J. Naughton said...

That's great Liam I like that at lot, it make the code more elegant indeed. [:)]

Steve

Anonymous said...

mmm... something wrong to me...
In the GetChildrenTablePermissions method you take the column itself, cast in a MetaChildrenColumn type and then read the attribute of the childrenColumn, that is just the old column variable cast in MetaChildrenColumn.
Aren't you supposed to do something like
MetaChildrenColumn childrenColumn = column.ColumnInOtherTable ?
In fact in GetFkTablePermissions methid you refer to the foreignKeyColumn.ParentTable
Am I missing something?

Stephen J. Naughton said...

Hi Marcuz, they usually say the proff of the pudding is in the eating :D and also you posted this against the permissions series not the children column. But I would download the project and check it out before you criticise the code, because like I said the proof is if it works of not.

Steve ;D

Anonymous said...

Ya, need to change childrenColumn.Attributes;
to childrenColumn.ChildTable.Attributes;

Thanks Steve!

Stephen J. Naughton said...

Yeh well :D I'm not gonna rewrite the article ;) I'll leave the changes to the next version for Preview 2 or .Net 4.0

Steve :D