9Sep/0613
Domino Document Locking Class 1.3
Here is an update to the Document Locking Class 1.1 and Document Locking Class , this update allows the unlocking overriding for Manager access (coded by Michael Sobczak) or overriding by group or role.
Public Sub new ( inDoc As Variant ) Public Sub SetCurrentUser ( user As String ) Public Function hasDocument () Public Sub setDocument ( inDoc As NotesDocument ) Public Sub setUIDocument ( inUIDoc As NotesUIDocument ) Public Property Get CurrentUser As String Public Property Get toString As String Public Property Get ShowPrompts As Boolean Public Property Set ShowPrompts As Boolean Public Function LockingEnabled () As Boolean Public Function IsLockedByCurrentUser () As Boolean Public Function IsDocumentLockedByCurrentUser (doc As NotesDocument ) As Boolean Public Function IsUIDocumentLockedByCurrentUser ( uiDoc As NotesUIDocument ) As Boolean Public Function LockedBy ( ) As String Public Function IsLocked ( ) As Boolean Public Function IsDocumentLocked ( doc As NotesDocument ) As Boolean Public Function IsUIDocumentLocked ( uiDoc As NotesUIDocument ) As Boolean Public Function Lock ( ) As Boolean Public Function LockUIDocument (uiDoc As NotesUIDocument ) As Boolean Public Function LockDocument ( doc As NotesDocument ) As Boolean Public Function UnLock ( ) As Boolean Public Function UnLockUIDocument ( uiDoc As NotesUIDocument ) As Boolean Public Function UnLockDocument ( doc As NotesDocument ) As Boolean Public Sub RoleGroupOverRide ( RoleGroup As String )
Domino Document Locking
%INCLUDE "LSCONST.LSS" '/** ' * A rapper around the built-in document locking that is available in Notes/Domino 6. ' * The purpose is to provide a better more consistant way of locking and unlocking documents. ' * Will not lock a new document since it can not be locked. Will only show warnings once. ' * ' * @author Chad Schelfhout http://www.chadsmiley.com/ ' * @version 1.3 ' * @history ' * 1.0 Created ' * 1.1 Added ability to check the current user or a different user ' * 1.2 Added Manager override. by Michael Sobczak ' * 1.3 Added Role or Group override ' */ Class DominoDocumentLocking Private pUser As String Private pDoc As NotesDocument Private pToString As String Private pShowPrompts As Boolean Private pDatabase_Locking_Not_Enabled As String Private pDatabase_Locking_Not_Enabled_Title As String Private pDocument_Locked As String Private pDocument_Locked_Title As String Private pEnabled As Boolean Private pAlreadyLocked As Boolean Private pRoleGroupOverRide As String 'Flag used so user is only informed once that database locking is not enabled Private pDatabasePrompted As Boolean Private db As NotesDatabase '/** ' * Constructor ' */ Public Sub new( inDoc As Variant ) pDatabase_Locking_Not_Enabled = "Database locking has not been enabled." pDatabase_Locking_Not_Enabled_Title = "Locking Not Enabled" pDocument_Locked = "Unable to lock, currently locked by: " pDocument_Locked_Title = "Document Locked" pDatabasePrompted = False pAlreadyLocked = False pShowPrompts = True pToString = "" If Not inDoc Is Nothing Then If Typename( inDoc ) = "NOTESDOCUMENT" Then Set pDoc = inDoc Elseif Typename( inDoc ) = "NOTESUIDOCUMENT" Then Set pDoc = inDoc.Document End If End If Dim Session As New NotesSession pUser = Session.UserName 'Msgbox "Current user is = " & pUser Set db = Session.CurrentDatabase If db.IsDocumentLockingEnabled Then pEnabled = True Else pEnabled = False End If End Sub '/** ' * Determines if the document is locked ' */ Private Function HasLock ( ) As Boolean If pDoc Is Nothing Then HasLock = True Else 'if there is no text then it is not locked HasLock = Len( pDoc.LockHolders(0) ) > 0 End If End Function '/** ' * Gets the current user ' */ Private Property Get CurrentUser As String CurrentUser = pUser End Property '/** ' * Gets the current user ' */ Public Sub SetCurrentUser( user As String ) pUser = user End Sub '/** ' * Determines if the document is locked but the current user. ' */ Private Function CurrentUserHasLock( ) As Boolean CurrentUserHasLock = HasLock () If CurrentUserHasLock Then If pDoc.LockHolders(0) = pUser Then CurrentUserHasLock = True Else 'Not the current user. CurrentUserHasLock = False End If End If End Function '/** ' * Determines if a document exists ' */ Public Function hasDocument() hasDocument = Not pDoc Is Nothing End Function '/** ' * Sets the Document ' */ Public Sub setDocument( inDoc As NotesDocument ) Set pDoc = inDoc End Sub '/** ' * Sets the document base on the UI document ' */ Public Sub setUIDocument( inUIDoc As NotesUIDocument ) If inUIDoc Is Nothing Then Call setDocument( inUIDoc.Document ) End If End Sub '/** ' * Returns string of any messages ' */ Public Property Get toString As String toString = pToString End Property '/** ' * Returns wether prompts are displayed ' */ Public Property Get ShowPrompts As Boolean ShowPrompts = pShowPrompts End Property '/** ' * Sets wether prompts are displayed ' */ Public Property Set ShowPrompts As Boolean pShowPrompts = ShowPrompts End Property '/** ' * Determines if database locking is enabled. ' */ Public Function LockingEnabled() As Boolean If Not pEnabled Then If Not pDatabasePrompted Then pToString = pDatabase_Locking_Not_Enabled If showPrompts Then Msgbox pToString , MB_ICONSTOP , pDatabase_Locking_Not_Enabled_Title End If pDatabasePrompted = True End If End If LockingEnabled = pEnabled End Function '/** ' * Determines if the current document is locked by the current user. ' */ Public Function IsLockedByCurrentUser () As Boolean IsLockedByCurrentUser = LockingEnabled() If IsLockedByCurrentUser Then IsLockedByCurrentUser = CurrentUserHasLock( ) Else 'Locking not enabled IsLockedByCurrentUser = False End If End Function '/** ' * Determines if the document is locked but the current user. ' */ Public Function IsDocumentLockedByCurrentUser (doc As NotesDocument ) As Boolean Call SetDocument( doc ) IsDocumentLockedByCurrentUser = IsLockedByCurrentUser End Function '/** ' * Determines if the UI document is locked but the current user. ' */ Public Function IsUIDocumentLockedByCurrentUser ( uiDoc As NotesUIDocument ) As Boolean Call setUIDocument( uiDoc ) IsUIDocumentLockedByCurrentUser = IsLockedByCurrentUser( ) End Function '/** ' * Returns who the document is locked by ' */ Public Function LockedBy ( ) As String If hasDocument() Then LockedBy = pDoc.LockHolders(0) Else LockedBy = "" End If End Function '/** ' * Determines if the currnet document is locked ' */ Public Function IsLocked ( ) As Boolean isLocked = LockingEnabled() If isLocked Then isLocked = HasLock( ) Else 'Locking is not enabled isLocked = False End If End Function '/** ' * Determines if the the document is locked ' */ Public Function IsDocumentLocked ( doc As NotesDocument ) As Boolean Call setDocument( doc ) isDocumentLocked = IsLocked() End Function '/** ' * Determines if the UI document is locked ' */ Public Function IsUIDocumentLocked (uiDoc As NotesUIDocument ) As Boolean 'Check to make sure that there is a document, If there is none it is a new document If ( uiDoc.Document Is Nothing ) Then IsUIDocumentLocked = False Else IsUIDocumentLocked= IsDocumentLocked( uiDoc.Document ) End If End Function '/** ' * Locks the current document ' */ Public Function Lock() As Boolean Me.Lock = LockingEnabled() If Me.Lock Then 'Check to make locking is enabled. If Not pAlreadyLocked Then 'Make sure that the document is not allready locked. If HasLock( ) Then 'Msgbox "Document is currently locked" If CurrentUserHasLock( ) Then 'Msgbox "Document is currently locked by the current user" 'Since the current user has the document locked then we don't need to. pAlreadyLocked = True Me.Lock = True Else 'Msgbox "Document is not currently locked by the current user" 'Document is locked by someone else. Let's display the name pToString = pDocument_Locked + pDoc.LockHolders(0) If showPrompts Then Msgbox pToString , MB_ICONSTOP, pDocument_Locked_Title End If Me.Lock = False End If Else 'Msgbox "Document is not locked" 'Make sure that there is a document to lock, New documents can not be locked. If Not pDoc.IsNewNote Then Call pdoc.Lock End If pAlreadyLocked = True Me.Lock = True End If End If End If End Function '/** ' * Locks the UI document ' */ Public Function LockUIDocument (uiDoc As NotesUIDocument ) As Boolean Call setUIDocument( uiDoc ) LockUIDocument = Me.Lock() End Function '/** ' * Locks the document ' */ Public Function LockDocument (doc As NotesDocument ) As Boolean Call setDocument ( doc ) LockDocument = Me.Lock() End Function '/** ' * Unlocks the current document ' */ Public Function UnLock () As Boolean Me.UnLock = False If Not pDoc Is Nothing Then If Not pDoc.IsNewNote Then 'Only unlock if the current user has it locked 'or if the current user is defined as a Manager in the ACL. If ( CurrentUserHasLock () ) Then pDoc.UnLock Me.UnLock = True Elseif ( OverRideDocumentOwner() ) Then On Error Goto NotAuthor Call pDoc.RemoveItem( "$PWriters" ) Call pDoc.RemoveItem( "$WritersDate" ) Call pDoc.RemoveItem( "$Writers" ) Call pDoc.Save( True, False , False ) Me.UnLock = True NotAuthor: pToString = Error If showPrompts Then Msgbox pToString , MB_ICONSTOP, pDocument_Locked_Title End If Exit Function Else 'Msgbox "Current user does not have the lock" End If Else 'Msgbox "Current document is a new note" End If Else 'Msgbox "Document is nothing" End If End Function '/** ' * Unlocks the UI document ' */ Public Function UnLockUIDocument (uiDoc As NotesUIDocument ) As Boolean Call setUIDocument( uiDoc ) UnLockUIDocument = Me.UnLock() End Function '/** ' * Unlocks the document ' */ Public Function UnLockDocument (doc As NotesDocument ) As Boolean Call setDocument( doc ) UnLockDocument = Me.UnLock() End Function '/** '* Is User Database manager ' */ Private Function IsUserDbManager () As Boolean If ( db.CurrentAccessLevel = ACLLEVEL_MANAGER ) Then IsUserDbManager = True Else IsUserDbManager = False End If End Function '/** ' * Role or Group Override ' * The group or role will be used to determine if document can be unlocked ' * even if the current user does not have the document locked. ' */ Public Sub RoleGroupOverRide( RoleGroup As String ) pRoleGroupOverRide = RoleGroup End Sub '/** ' * Determine if the role or group allows the unlocking to be overridden ' */ Private Function OverRideDocumentOwner () As Boolean OverRideDocumentOwner = IsUserDbManager If Not OverRideDocumentOwner Then Dim unl As Variant unl = Evaluate ( "@UserNamesList" ) OverRideDocumentOwner = Not Isnull( Arraygetindex ( unl , pRoleGroupOverRide ) ) If Not OverRideDocumentOwner Then OverRideDocumentOwner = Not Isnull( Arraygetindex ( unl , "["+pRoleGroupOverRide+"]" ) ) End If End If End Function End Class
October 17th, 2006 - 08:24
Hi Chad,
just want to emphasize the requirement for overiding the manager access:
Unlocking without manager rights does only work if you are explicitly listed in an author item of the document – by Name, Role or Groupmembership.
Editor or designer access does not suffice.
Otherwise you recieve an error that the document is already locked by another user. :-
Thanks for sharing.
VM
February 29th, 2008 - 01:27
Hi Chad
Is that work on the web?
And with a load balancing cluster…
Thanks
February 29th, 2008 - 10:06
I have used it on the web, so yes it will. As for the balancing cluster, it should work because this class is using the Domino Document Locking feature and nothing else, this class is just a wrapper to handle the common errors/situations that are not provided by Domino.
October 1st, 2008 - 04:09
Hi Chad, great work the Domino Document Locking Class, but I’ve got a problem unlocking a doc using that code from a web agent. The problem is in line
pUser = Session.UserName
because Session.UsersName returns the server name where the agent is executed rather than the user name, so when you check if user can unlock a doc the comparison always fails.
I avoid that issue using this code
pUser = Session.EffectiveUserName
I don’t check if with this change the code still work on client.
October 1st, 2008 - 05:16
October 1st, 2008 - 05:49
Thanks Dennis I will take a look at it.
November 11th, 2008 - 14:36
I am new to Domino. Where do I past the document locking logic.
November 14th, 2008 - 06:53
I would place the code into a script library so it can be used by anything.
June 1st, 2009 - 07:19
Chad I need a help,
I paste code ‘Domino Document Locking’ in script library.
Where and how I can call function from this class.
Thank’s Bojana
June 9th, 2009 - 12:47
Bojana, it all depends on what you need done. Is this a UI or backend usage. For the most basic usage you would need to call LockUIDocument and UnLockUIDocument if you where need to lock a UI document.
April 29th, 2010 - 13:13
Hello Chad
The locking feature has helped me a lot. How I used it is
In the querymodechange event I used
Sub Querymodechange(Source As Notesuidocument, Continue As Variant)
If source.EditMode Then
Dim locker As New DominoDocumentLocking( source )
Call locker.LockUIDocument( source )
End If
End Sub
and in the Queryclose event I used
Sub Queryclose(Source As Notesuidocument, Continue As Variant)
If source.EditMode Then
Dim locker As New DominoDocumentLocking( source )
Call locker.UnLockUIDocument( source )
End If
End Sub
When one document is locked by a user and another user tries to edit the same document the code works fine.
Here is one problem I am facing
When the same user opens two instances of the same document then it allows both the instances of the document to get into the edit mode and then when you save the documents there is a replication conflict
I have tried checking using the following code in the query open
Dim locker As New DominoDocumentLocking( source )
Dim islocked As Boolean
islocked =locker.IsUIDocumentLockedByCurrentUser ( Source)
If islocked = True Then
Msgbox “Another copy of this document is already open”
Continue = False
End If
this works in the query open but not in the Querymodechange it returns True in both the cases and I cannot check if it is the first instance that is being sent into the edit mode
Please suggest what i need to do
April 29th, 2010 - 17:42
As I was review the code, this jumped out at me:
Call pDoc.RemoveItem( “$WritersDate” )
Call pDoc.RemoveItem( “$Writers” )
Why not check the time of the $WritersDate, and see if it is the current time, or relatively close, if it is then it is the current document. I no longer have a Domino server to do any testing, but that is the first idea that came
August 13th, 2010 - 02:25
Hi Chad . Thanks .
This is if others face this issue of the same user opening two instances of the same document. I used environment variables and set an environment variable using the document id I have the following code in the QueryOpen
Dim session As New NotesSession
Dim latestNumber As String
latestNumber = session.GetEnvironmentString(source.Document.UniversalID)
If latestNumber =”" Then
Call session.SetEnvironmentVar( Cstr(source.Document.UniversalID), Cstr(source.Document.UniversalID) )
Else
Msgbox “Another instance of this document is already open ”
Continue = False
End If