HistoryScheduler
Version 4.1 by Jiahao Lai on 2025/09/10 12:55
- Remove the History of Documents
-
The documents to remove the history for are configured on this configuration page
- 0 0 3 5 * ?
- The script is the code that will be executed when the job is triggered by the scheduler. It should be written in the Groovy language. The XWiki API is available through the xwiki and context pre-defined variables.
- import org.slf4j.LoggerFactory;
import com.xpn.xwiki.api.*;
import com.xpn.xwiki.doc.*;
import com.xpn.xwiki.web.*;
def LOGGER = LoggerFactory.getLogger("RemoveHistory");
def cXWiki = xwiki.getXWiki();
def cContext = xcontext;
def doc = cContext.getDoc();
def cDocs = [];
def hql = "";
def fromClause = "";
def whereClause = "";
def maxResults = 0;
def configObject = xwiki.getDocument('Code.RemoveHistoryConfiguration').getObject('Code.RemoveHistoryConfigurationClass');
def spaces = configObject.getProperty('spaceList').value;
def pages = configObject.getProperty('pageList').value;
def configWhereClause = configObject.getProperty('whereClause').value;
def configFromClause = configObject.getProperty('fromClause').value;
def configMaxResults = configObject.getProperty('maxResults').value;
if(spaces != null && !spaces.equals("")) {
whereClause = whereClause + "doc.space in (" + spaces + ")";
LOGGER.warn("Configuration spaces: $spaces");
}
if(pages != null && !pages.equals("")) {
if(whereClause.equals("")) {
whereClause = "(doc.fullName in (" + pages + "))";
} else {
whereClause = whereClause + "or (doc.fullName in (" + pages + "))";
}
LOGGER.warn("Configuration pages: $pages");
}
if(configWhereClause != null && !configWhereClause.equals("")) {
whereClause = whereClause + configWhereClause;
LOGGER.warn("Configuration where clause: $configWhereClause");
}
if(configFromClause != null && !configFromClause.equals("")) {
fromClause = configFromClause;
LOGGER.warn("Configuration from clause: $configFromClause");
}
if(configMaxResults != null) {
maxResults = configMaxResults;
LOGGER.warn("Max number of results: $maxResults");
}
if(!fromClause.equals("") || !whereClause.equals("")) {
// select just the users and do not check the versions to improve performance
//hql = "select doc2 from XWikiDocument as doc2, XWikiRCSNodeInfo as node where node.id.docId=doc2.id and doc2.fullName in (select doc.fullName from XWikiDocument as doc " + fromClause + " where "+ whereClause + ") group by doc2.fullName having count(node.id.version1)>1";
hql = "select doc from XWikiDocument as doc " + fromClause + " where "+ whereClause;
LOGGER.warn("Final query: $hql");
cDocs = cXWiki.getStore().search(hql, maxResults, 0, cContext);
def totalDocs = cDocs.size();
LOGGER.warn("Found " + totalDocs + " documents in the list.");
} else {
LOGGER.warn("No restrictions available");
}
def index = 0;
for(cDoc in cDocs) {
def cArchive = cDoc.getDocumentArchive(cContext);
def cLatestVersion = cArchive.getLatestVersion();
def v0 = v1 = v2 = 0;
if(cLatestVersion != null) {
v2 = cArchive.getPrevVersion(cLatestVersion);
// We assume there are 2 versions in total
// -> remove the oldest one
v1 = v2;
v0 = v1;
// Build archive range to delete (v1 -> v2)
while(v0 != null) {
v0 = cArchive.getPrevVersion(v0);
// Get the oldest (non-null) version
if(v0 != null) {
v1 = v0;
}
}
if(v1 != null) {
cArchive.removeVersions(v2, v1, cContext);
cXWiki.getVersioningStore().saveXWikiDocArchive(cArchive, true, cContext);
cDoc.setDocumentArchive(cArchive);
LOGGER.warn("Removed archive for " + cDoc.prefixedFullName + " from v" + v1 + " to v" + v2);
} else {
LOGGER.warn("Previous version not available for " + cDoc.prefixedFullName + " because v1= " + v1 + " and v2= " + v2);
}
index++;
}
}