When you open a file from Sharepoint, it will receive a short term lock that will prevent others to change some properties on the file.
This protection can be useful, but also very annoying, for example when the file is not closed properly, then the lock could stay “forever”.
There are many posts on the web about it.
I found one that has been super useful: https://pholpar.wordpress.com/2014/04/07/how-to-use-javascript-to-delete-short-term-locks-from-documents-opened-from-sharepoint/
The author explains very well the different steps what I’m trying to summarize:
- Send a request to
_vti_bin/_vti_aut/author.dllwith special headers/body - Auth.dll will provide the
lockid - Send a request to
_vti_bin/cellstorage.svc/CellStorageServicewith special headers/body, included thelockid - The file is unlocked
The code to send to CellStorageService, and provided by the author, didn’t work for me. I’ve had to use Fiddler and open the document into Office on my computer to see the kind of requests send by it to unlock a document. Based on it, I’ve re-built the code and you can find my solution below.
Tested on Sharepoint 2013 On-Promise only. I don’t know if this solution works for Sharepoint Online or other version.
Also note that I use $SP().ajax() from SharepointPlus, but it’s equivalent to the $.ajax from jQuery.
// full path to the document
var docUrl = "https://website.com/website/Doc_Library/Test.docx";
// start by querying author.dll to find the lockid and the user who locked it
$SP().ajax({
url: 'https://website.com/website/_vti_bin/_vti_aut/author.dll',
headers:{
"Content-Type": "application/x-www-form-urlencoded",
"MIME-Version": "1.0",
"Accept": "auth/sicily",
"X-Vermeer-Content-Type": "application/x-www-form-urlencoded"
},
body: 'method=getDocsMetaInfo%3a14%2e0%2e0%2e6009&url%5flist=%5b' + encodeURIComponent(docUrl) + '%5d&listHiddenDocs=false&listLinkInfo=false',
}).then(function(source) {
// go thru the source page returned to find the lockid and current user
var nextLine = false;
var ret = { "lockid":"", "user":"", when:"" };
source.split("\n").forEach(function(line) {
if (line.indexOf("vti_sourcecontrollockid") !== -1) nextLine="lockid"; // vti_sourcecontrollockid -> the lockid to use later
else if (line.indexOf("vti_sourcecontrolcheckedoutby") !== -1) nextLine="user"; // vti_sourcecontrolcheckedoutby -> username of the user who locked it
else if (line.indexOf("vti_sourcecontrollockexpires") !== -1) nextLine="when"; // vti_sourcecontrollockexpires -> when the server is supposed to unlock it
else if (nextLine !== false) {
ret[nextLine] = line.slice(7).replace(/([0-9]|[1-9][0-9]|[[01][0-9][0-9]|2[0-4][0-9]|25[0-5]);/g, function (str, match) { return String.fromCharCode(match); });
nextLine = false;
}
});
if (!ret.lockid) { alert("Not Locked") }
else {
// compose a request based on what Microsoft Office sends to the Sharepoint server
// found using Fiddler
var releaseLockReq = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/><RequestCollection CorrelationId="{96A244BD-D13B-4696-9355-231FB673BC4F}" xmlns="http://schemas.microsoft.com/sharepoint/soap/"><Request Url="'+docUrl+'" UseResourceID="true" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="16.0.8201.2102" MetaData="1031" RequestToken="1"><SubRequest Type="ExclusiveLock" SubRequestToken="1"><SubRequestData ExclusiveLockRequestType="ReleaseLock" ExclusiveLockID="'+ret.lockid+'"/></SubRequest></Request></RequestCollection></s:Body></s:Envelope>';
// we send it to the webservice cellstorage.svc
$SP().ajax({
url:'https://website.com/website/_vti_bin/cellstorage.svc/CellStorageService',
body:releaseLockReq,
headers:{
'Content-Type':'text/xml; charset=UTF-8',
'SOAPAction': "http://schemas.microsoft.com/sharepoint/soap/ICellStorages/ExecuteCellStorageRequest"
}
})
.then(function(res) {
if (res.indexOf('ErrorCode="Success"') !== -1) alert("Success") // the file has been unlocked
else alert("Failed")
})
}
})
I hope it will be useful to someone else!