Sunday, November 3, 2013

Trustees - How to Get or Set Access Rights to Documents in eDOCS DM

PCDDocObjectClass of DM API has a few methods to work with a document's trustees - the list of users or groups who have access to the document: FetchTrustees, GetTrustees, SetTrustees, UpdateTrustees, etc. eDOCS DM 5.3.1 DM API Reference Guide.pdf includes corresponding code samples.


However, those code samples didn't work for me, when I tried to implement the Trustees support in my DMApiHelpers class library. After several trials and errors, I ended up with the following code which works for me (unit tests can be found in the full source code of DMApiHelpers).
// methods of the DMApiHelpers.DMDocument class

public TrusteeInfo[] FetchTrustees(int docNumber) {
    var doc = new PCDDocObjectClass();
    doc.SetDST(Dst);
    doc.SetObjectType(ObjectFormDefaultProfile);
    doc.SetProperty(PropertyTargetLibrary, Library);
    doc.SetProperty(PropertyObjectIdentifier, docNumber);

    int result = doc.FetchTrustees();
    if(result != S_OK || doc.ErrNumber != 0)
        throw new DMApiException(string.Format("Cannot fetch trustees for document# {0}.",
            docNumber), doc.ErrNumber, doc.ErrDescription);

    var trustees = doc.GetTrustees();
    if(doc.ErrNumber != 0)
        throw new DMApiException(string.Format("Cannot get trustees for document# {0}.",
            docNumber), doc.ErrNumber, doc.ErrDescription);

    var list = new List();
    var count = trustees.GetSize();
    if(count > 0) {
        trustees.BeginIter();
        for(int i = 0; i < count; i++) {
            list.Add(new TrusteeInfo(
                trustees.GetCurrentTrusteeName(),
                (TrusteeType)trustees.GetCurrentTrusteeFlags(),
                (AccessRights)trustees.GetCurrentTrusteeRights()));
            trustees.NextTrustee();

        }
    }
    return list.ToArray();
}

public void UpdateTrustees(int docNumber, TrusteeInfo[] trusteesToSet) {
    if(trusteesToSet == null)
        throw new ArgumentNullException("trusteesToSet");
    if(trusteesToSet.Length == 0)
        throw new ArgumentException("trusteesToSet is empty");

    var doc = new PCDDocObjectClass();
    doc.SetDST(Dst);
    doc.SetObjectType(ObjectFormDefaultProfile);
    doc.SetProperty(PropertyTargetLibrary, Library);
    doc.SetProperty(PropertyObjectIdentifier, docNumber);
    
    int result = doc.FetchTrustees();
    if(result != S_OK || doc.ErrNumber != 0)
        throw new DMApiException(string.Format("Cannot fetch trustees for document# {0}.",
            docNumber), doc.ErrNumber, doc.ErrDescription);

    // season greetings, DM API developers...
    var trustees = doc.GetTrustees();
    if(doc.ErrNumber != 0)
        throw new DMApiException("GetTrustees failed.", doc.ErrNumber, doc.ErrDescription);
    
    int size = trustees.GetSize();
    foreach(var t in trusteesToSet) {
        int idx = trustees.GetTrusteeIndex(t.Trustee, (int)t.TrusteeType);
        // funking DM API returns index equal GetSize() if trustee is not found 
        if(idx == size) {
            if(t.AccessRights != AccessRights.NoAccess)
                trustees.AddTrustee(t.Trustee, (int)t.TrusteeType, (int)t.AccessRights);
        }
        else  // update existing
            if(t.AccessRights == AccessRights.NoAccess)
                trustees.DeleteTrustee(idx);
            else
                trustees.SetTrusteeRights(idx, (int)t.AccessRights);
    }
    result = doc.SetTrustees(trustees);
    if(result != S_OK || doc.ErrNumber != 0)
        throw new DMApiException("SetTrustees failed.", doc.ErrNumber, doc.ErrDescription);

    result = doc.UpdateTrustees();
    if(result != S_OK || doc.ErrNumber != 0)
        throw new DMApiException(string.Format("UpdateTrustees failed for document# {0}.",
            docNumber), doc.ErrNumber, doc.ErrDescription);
    
    result = doc.Update();
    if(result != S_OK || doc.ErrNumber != 0)
        throw new DMApiException(string.Format("Cannot update document# {0}.", docNumber),
            doc.ErrNumber, doc.ErrDescription);
}


A few notes about my code to anyone who wants to use it:
  • Enhanced ACL (where you can set Deny permission flags) is not implemented;
  • Permission removal is implemented by passing AccessRights.NoAccess to DMDocument.UpdateTrustees.

I wish the code were simpler... If you know how to simplify it - great, but don't forget unit testing. Two tests are already included, but you may want to write more.

No comments:

Post a Comment