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
replied on August 28, 2024

I apologize again for another tag onto this old post, but it seems as though it is what I am after. We occasionally have errant locks, rather locks that give a warning to the user that it is locked, but nothing showing in the admin console. However, the document properties show a user account in "checked out by." We log in as that user check out and either undo or re check in the document to clear the lock error. 

 

I am hoping to implement a business process that gives a couple admins the ability to remove these error locks without having to give them other users' credentials. However, it does seem that if the script is executed while the user has the document open, they then save and close that document it now marks it as checked out:

running the script again will not clear this value. Additionally, if a user has this checked out, and we run the script, it clears the appearance of a lock, but the item still shows that user as having checked out the document. Ultimately I just need something that completely clears the lock and any values that may hang up a document. Any ideas?

 

0 0
replied on August 29, 2024 Show version history

@████████ Just confirm, when you say there are no locks in the admin console, are you clearing both Entry Locks and Checked Out Documents? I've never seen the exact scenario you're describing, so I'm not too sure.

Although related, locks and checkouts are separate things; locks can apply to all entries but check outs are for documents with version control. I have not used a script like this to force unlock version-controlled documents before.

In the SDK there are check in/out related methods for DocumentInfo objects, but EntryInfo objects only have the lock/unlock methods; however, those methods are for the current user context not undoing other user checkouts.

The user saving would still be a problem since they'll already have the document open, so you might also have to disconnect their Session.

 

 

0 0
replied on August 29, 2024

That is correct. After running the script to clear the locks, if the user for some reason has the document open and saves it, the status changes to checked out, but doesn't show up in the admin console. Even if that user saves and closes the document the name remains in the "checked out by" field and the only way it can become editable again is for them to do a check out and back in. FYI we have every document in our repository under version control.

The error that occurs is that a user for whatever reason was editing a document, they think they save and close the document, but it remains locked even though there is no lock (nor check out) displayed in the admin console and they have no document open. When that occurs the user that triggered the error is listed in the "checked out by" field. It is very frustrating for non-admins to track that person down to do the fix, which is just checking out and rechecking in or undoing the checkout through normal means.

 

I guess what I am after is a script that finds the starting entry in the lock list and clears locks, check outs and any hanging fields that indicate to the system that a document is un-editable. IS that even possible? Thank you so much for still replying to this thread!!!

0 0
replied on August 29, 2024 Show version history

I'm not sure to be honest. Are they using the Web Client or Windows Client? There are a lot of factors to consider. For example, sometimes I need to manually refresh before the lock icon actually goes away.

I guess the question to start with is, when and why is the script being used in the first place? It sounds like the script is causing the behavior, so it could be that as-is the script doesn't work quite right with versioned documents.

It sounds like maybe you're trying to use the script so non-admins can force unlock documents checked out by others, but I've never used the script in that way and things get more complicated with versioning in the mix.

It might be best to post a new question with a more detailed summary of the start-to-end process (i.e., why the script is being run, who is running it, along with all the other details you've mentioned).

0 0
replied on August 29, 2024

Sounds great. I will get that stuff together for a stand-alone post. Thank you for your time!

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

Sign in to reply to this post.