I have not done a SnTT post in a while, but I figured this one was something people could use. For the past couple of months, I have been waging a war against IBM Lotus Domino Document Manager ... otherwise known and Domino.Doc. I am working on a client project that is built around the New Product submission idea, but using ILDDM as the way to store the documents. We have lots of documents in the system, from Office to editable PDFs to artwork designed on the Mac to Autocad drawings. Our system allows for the attachments to be put thru workflow (for comments, editing, and approval), but we store everything in ILDDM. Because of the lack of robust workflow in ILDDM, we are using our own enTouch.workflow product. What that means is that we have a document stub that goes thru our workflow, which links to the ILDDM document. Because of the nature of this process, security is very tight. Add in the difficulty of no ILDDM API on the Mac (today) and the lack of any good way to set security on Binders, I decided to do it my own way.
When working with ILDDM, the user sees a Binder as a folder. What a Binder is really is a document in the Binder database. Documents are stored in the Document database.The user just sees two databases on the workspace, with the Document database appending a 1 to the database name.
So what I have done is found a way to set the security on the Binder document and all of the Document documents directly. There is a couple of tricks.
First, I go thru the typical motions of adding an attachment to ILDDM. You do the following:
- Connect to the ILDDM API via the "Set API = CreateObject("DominoDoc.API")"
- Connect to the Library via "Call API.SetHttpLogin(ILDDM_UserName, ILDDM_Password)"
- Connect to the Library via "Set Library = API.GetLibrary(library)"
- Connect to the File Cabinets collection via "Set FileCabinets = Library.Cabinets"
- Connect to the File Cabinet via "Set FileCabinet = FileCabinets.ItemByTitle(fcname)"
- Connect to the Binders collection via "Set Binders = FileCabinet.binders"
- Connect to the Binder via "Set Binder = Binders.ItemByTitle (bindername)"
- Connect to the Documents collection via "Set Documents = Binder.Documents"
- Create a new document via "Set Document = Documents.Add"
- Set the attachment (need the full path to the attachment) via "Call Document.SetContents(path)"
- Set the Document Title via "Document.Title = title"
- Set the Document Description via "Document.Description = desc"
- Save the Document via "Call Document.Save"
- Get the Security object of the Document via "Set Binder_Security = Binder.Security"
- IMPORTANT: Set the All Editors flag to false via "Binder_Security.AllEditorsFlag = False"
- IMPORTANT: Set the All Readers flag to false via "Binder_Security.AllReadersFlag = False"
- Save the Document gain via "Call Document.Save"
- Check in the Document via "Call Document.CheckIn(1, 2, False, "")"
Once we have the document in ILDDM, I write the following information back to the stub document in our workflow system:
With document
.ILDDMServer = FileCabinet.NotesServer
.ILDDMBinderDatabaseRepID = FileCabinet.BinderDatabase
.ILDDMDocumentDatabaseRepID = Binder.DocumentDatabase
.ILDDMBinderDocumentUID = Binder.UniversalID
.ILDDMDocumentDocID = Document.UniversalID
Dim docdb As New notesdatabase("","")
Call docdb.OpenByReplicaID(FileCabinet.NotesServer,Binder.DocumentDatabase)
.ILDDMDOcumentDatabaseFileName = docdb.FilePath
End With
This gives me all of the information I need to access the ILDDM Server, the Binder Database, the Binder document, the Document database, and the Document itself without having to use the ILDDM API.
Now, comes the fancy piece. I call an agent in the Binder database that I have created and pass in the workflow stub document as a parameter. Our workflow engine computes the security and writes it into two fields, one Reader and one Author. The agent looks like this (I took out some of the pieces, this is just the relavant piece):
binderserver = document.ILDDMServer(0)
If binderserver = "" Then
Gotobye
End If
binderdb_value = document.ILDDMBINDERDATABASEREPID(0)
If binderdb_value = "" Then
Gotobye
End If
documentdb_value = document.ILDDMDOCUMENTDATABASEREPID(0)
If documentdb_value= "" Then
Gotobye
End If
binderdoc_uid = document.ILDDMBINDERDOCUMENTUID(0)
If binderdoc_uid = "" Then
Gotobye
End If
Set readerfield = document.GetFirstItem("SFDocReaders")
Set authorfield = document.GetFirstItem("sfdocauthors")
Call binderdb.OpenByReplicaID(binderserver,binderdb_value)
If binderdb.IsOpen = False Then
Print"Binder Database not opened"
Gotobye
End If
Call documentdb.OpenByReplicaID(binderserver,documentdb_value)
If documentdb.IsOpen = False Then
Gotobye
End If
Set binderdoc = binderdb.GetDocumentByUNID(binderdoc_uid)
If binderdoc Is Nothing Then Goto bye
Call binderdoc.removeitem("ComputedAuthors")
Call binderdoc.RemoveItem("DocAuthors")
Call binderdoc.RemoveItem("ComputedReaders")
Call binderdoc.removeitem("DocReaders")
binderdoc.computedauthors = document.sfdocauthors
binderdoc.docauthors = document.sfdocauthors
binderdoc.computedreaders = document.sfdocreaders
binderdoc.docreaders = document.sfdocreaders
Set binder_computedreaders_item = binderdoc.GetFirstItem("ComputedReaders")
Set binder_computedauthors_item = binderdoc.GetFirstItem("ComputedAuthors")
Call binder_computedreaders_item.AppendToTextList("[Administrator]")
binder_computedreaders_item.IsReaders True
binder_computedauthors_item.IsAuthors True
Call binderdoc.Save(True, False)
'update documents
document.sfdocauthorreader = Arrayappend(document.sfdocauthors,document.sfdocreaders)
document.sfdocauthorreader = Arrayunique(document.sfdocauthorreader)
document.sfdocauthorreader = Fulltrim(document.sfdocauthorreader)
Set document_computedreaders_item = document.GetFirstItem("sfdocauthorreader")
Call document_computedreaders_item.AppendToTextList("[Administrator]")
'update versions
Set docview = documentdb.GetView("vaDocsByBinderID")
Set doccol = docview.GetAllDocumentsByKey(binderdoc_uid)
If doccol.Count > 0 Then
Calldoccol.StampAll ("ComputedAuthors", document.sfdocauthors)
Calldoccol.StampAll("ComputedReaders", document.sfdocauthorreader)
End If
'update drafts
Set draftview = documentdb.GetView("DraftDocsByBinderID")
Set draftcol = draftview.GetAllDocumentsByKey(binderdoc_uid)
If draftcol.Count > 0 Then
Calldraftcol.StampAll ("ComputedAuthors", document.sfdocauthors)
Calldraftcol.StampAll("ComputedReaders", document.sfdocauthorreader)
Calldraftcol.StampAll ("ComputedDraftEditors", document.sfdocauthors)
End If
So as you can see, I set the Binder document security manually and update all of the documents with the correct fields. Since ILDDM handles the database ACL itself, I do not have to worry about that.
I only had to create one new Design Element in ILDDM for this, and that is the "DraftDocsbyBinderID" view. That view is just a copy of the "vaDocsByBinderID" with the Selection formula changed to include "& @IsResponseDoc".
While this is definitly a righteous hack as Rocky would say, it works perfectly. Next up is to figure out how to create a File Cabinet programatically, since the ILDDM API does not include that.