You are viewing limited content. For full access, please sign in.

Question

Question

Need to perform an Undo Check Out from within a Workflow

asked on June 15, 2018 Show version history

Hi,

There is a Workflow process that needs to move a folder at the end of the approval. Sometimes, some users may have PDF documents still open from their Web Client session when they finish their process and the WF will move that folder, but the WF will terminate with following error message:

Multistatus response. [9039] Another operation on which this operation depends failed. [9054] Document locked with a persistent lock. [9167] 

FYI, in this process, I can safely cancel any checked out document.

I need to ensure the tasks does complete successfully so I can put a Try-Catch around that Move activity, and I would like to execute an Undo Check Out, just like an administrator account can do within the Laserfiche Client, but within a SDK VB Script.

From the WF activity called Find Entries, I have enabled the additional Property IsCheckedOut but that property doesn’t seem to change state when a document is checked out. The only property I can use is CheckedOutBy where a username will be present if a document is actually checked out.


Then, I have set a SDK Script to run like this: 

Using di As DocumentInfo = DirectCast(me.BoundEntryInfo, DocumentInfo)
    'If di.IsCheckedOut = True Then
        di.UndoCheckOut
        di.Save
    'End IF
End Using


But I get an error that says... The document must be checked out first... And it's really checked out as I can see with the Windows Client.

Any help would be appreciated.

0 0

Replies

replied on June 18, 2018

I believe UndoCheckOut would only apply within the scope of the script session meaning it probably only works if the same process/session checked out the document and does not affect any locks created by other users/sessions.

I use the following code to force unlocks on documents I need to edit/update with SDK scripts, but this is in C# rather than VB.NET

            // Initialize lock list settings
            EntryLockListingSettings lockListSettings = new EntryLockListingSettings();
            lockListSettings.IdentityReference = null; // Null to get locks for all users
            lockListSettings.PersistentLocksOnly = false; // Get all lock types
            lockListSettings.SortColumn = PersistentLockColumn.CreationTime;
            lockListSettings.SortDirection = SortDirection.Ascending;

            // Get the lock listings
            EntryLockListing lockListing = EntryLockListing.GetListing(0,lockListSettings,RASession);

            // Iterate through the list to find the target entries
            foreach(EntryLockListingRow row in lockListing){
                // If current entry matches target entry
                if(row.EntryId == this.BoundEntryId){
                    // Unlock the entry
                    Entry.Unlock(row.EntryId,row.LockToken,RASession);
                }
            } 

 

3 0
replied on June 18, 2018 Show version history

Thanks for your reply Jason but a Checked Out document can be cancelled by any administrator (or another user that has sufficient rights) and this option is available in the Windows and Web Client interfaces.

I'm looking for the right code syntax to perform the "Undo Check Out".

And can Laserfiche provide a comment about the "IsCheckedOut" property that doesn't seem to reflect the real state of the document?

0 0
replied on June 18, 2018

Jason is right. A user can undo their own check-out. Even with more rights, you can't undo another user's check-out. You can release the persistent lock caused by their check-out (either through the client or by using the code above).

Why do you think the IsCheckedOut property does not reflect the real state of the document?

0 0
replied on June 18, 2018

As Miruna said, you can cancel a check out through the client, but UndoCheckOut is not the same kind of function.

The code I provided is more similar to what is happening behind the scenes when you cancel a check out through the admin console.

As for checking whether or not something is checked out, the Find Entry activity allows you to get the "Checked Out By" and "Locked By" or ("Checked Out By SID" and "Locked By SID") properties of the document.

If either of those is not empty, then it is safe to assume the document is checked out, and if you want to get more specific you can use the SID versions to create an identity object and only retrieve a list of locks associated with that user.

For Example, the following uses the CheckedOutBySID and LockedBySID value(s) obtained from a Find Entry activity and unlocks the document if it is checked out or locked.

            // Create array containing each lock type
            string[] lockTypes = new string[] { "CheckedOut", "Locked" };

            foreach(string lockType in lockTypes){
                // Get identity token object
                var identityToken = GetTokenValue("FindEntry_OutputEntry_" + lockType + "BySID");

                // Check if entry is locked
                if(identityToken.ToString() != ""){
                    // Get Identity Reference
                    IdentityReference identity = identityToken as IdentityReference;

                    // Initialize lock list settings only for the target account
                    EntryLockListingSettings lockListSettings = new EntryLockListingSettings();
                    lockListSettings.IdentityReference = identity;
                    lockListSettings.PersistentLocksOnly = false;
                    lockListSettings.SortColumn = PersistentLockColumn.CreationTime;
                    lockListSettings.SortDirection = SortDirection.Ascending;

                    // Get the lock listings
                    EntryLockListing lockListing = EntryLockListing.GetListing(0,lockListSettings,RASession);

                    // Iterate through the list to find the target entries
                    foreach(EntryLockListingRow row in lockListing){
                        // If current entry matches target entry
                        if(row.EntryId == this.BoundEntryId){
                            // Unlock the entry
                            Entry.Unlock(row.EntryId,row.LockToken,RASession);
                        }
                    }
                }
            }
1 0
replied on December 8, 2020

Jason,

I know this is an old post, but it's exactly what I need in my current situation, and I'm hoping you can assist me in implementing it.  I used the code in your last reply, and set up the Find Entries and conditional sequence just as you did, but I'm getting the following error:

 Error    1    The type or namespace name 'IdentityReference' could not be found (are you missing a using directive or an assembly reference?)

I'm not great at coding, so I'm just assuming that I'm missing something from another part of your code where it references the ID of the current entry?  I don't see anywhere in this snippet where it does that, so I assume that's what I'm missing.  Could you help me figure out if that's the case?

Here's my code:

// Create array containing each lock type
string[] lockTypes = new string[] { "CheckedOut", "Locked" };

foreach(string lockType in lockTypes){
    // Get identity token object
    var identityToken = GetTokenValue("ForEachDocuments_CurrentEntry_" + lockType + "BySID");

    // Check if entry is locked
    if(identityToken.ToString() != ""){
        // Get Identity Reference
        IdentityReference identity = identityToken as IdentityReference;

        // Initialize lock list settings only for the target account
        EntryLockListingSettings lockListSettings = new EntryLockListingSettings();
        lockListSettings.IdentityReference = identity;
        lockListSettings.PersistentLocksOnly = false;
        lockListSettings.SortColumn = PersistentLockColumn.CreationTime;
        lockListSettings.SortDirection = SortDirection.Ascending;

        // Get the lock listings
        EntryLockListing lockListing = EntryLockListing.GetListing(0,lockListSettings,RASession);

        // Iterate through the list to find the target entries
        foreach(EntryLockListingRow row in lockListing){
            // If current entry matches target entry
            if(row.EntryId == this.BoundEntryId){
                // Unlock the entry
                Entry.Unlock(row.EntryId,row.LockToken,RASession);
            }
        }
    }
}
        }
    }
}

 

Thanks in advance!

0 0
replied on December 8, 2020 Show version history

Since you're actually creating an IdentityReference object to use instead of using a null value like I did in my example, then you need to include a reference to the assembly.

IdentityReference comes from System.Security.Principal

 

You can add the using statement to include the reference; this goes up at the top with the other using statements.

using System.Security.Principal;

 

Or you could use the full name reference like

System.Security.Principal.IdentityReference identity = ....

1 0
replied on December 8, 2020

Awesome!  That sorted out the build issue.  My only other question is, how does the script know which document to remove the lock/checkout from?  The only token that seems to be passed to it is the checkedoutby or lockedby.  Does it just by default use the current entry's ID without it being specified?

0 0
replied on December 8, 2020

The code for this.BoundEntryId is referencing the entry id of the script's default entry, which is set outside of the script editor in the activity settings.

Basically, the "Bound Entry" is the "Default Entry" you set for the activity; it can be the starting entry, or an entry from another activity in the workflow.

Whenever you use a script activity and set a default entry, BountEntryId is the default entry id, and BoundEntryInfo is the EntryInfo object.

For example, if you know for sure that the default entry is a document, instead of having to retrieve the DocumentInfo object again, you can just cast the BoundEntryInfo object to a DocumentInfo type like so:

DocumentInfo docInfo = (DocumentInfo)this.BoundEntryInfo;

2 0
replied on December 9, 2020

After I posted, I looked at it again and saw that line and thought that might be the case.  Thanks again for the assistance on this!  Very helpful.

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.