Bulk replace content in pages
Last modified by Raphaël Jakse on 2024/11/18 12:47
Allows to perfrom bulk search and replace of contents in wiki pages |
Type | Snippet |
Category | Other |
Developed by | |
Rating | |
License | GNU Lesser General Public License 2.1 |
Table of contents
Description
This script allows to perform bulk search and replace of content in wiki pages.
This snippet requires the Job Macro to run.
In a new page, copy-paste the following snippet :
{{velocity}}
#set ($spacePickerParams = {
'name': 'targetSpace',
'value': "$!{request.targetSpace}"
})
This script allows to perform bulk search and replace of XWiki document contents.
Programming rights are required to use this script.
{{html clean="false"}}
<form class="xform" action="#" method="post">
<dl>
<dt>
<label for="targetSpace">Space</label>
<span class="xHint">The script will look for documents containing the given search text within the following space.</span>
</dt>
<dd>
#pagePicker($spacePickerParams)
</dd>
<dt>
<input type="checkbox" name="allSpaces" id="allSpaces" />
<label for="allSpaces">All spaces</label>
<span class="xHint">The macro replace job will execute for every document in all spaces (excerpt the XWiki system space).</span>
</dt>
<dt>
<label for="search">Text to be searched</label>
<span class="xHint">The script will look for the following text in documents. The text in document contents has to match exactly with the search.</span>
</dt>
<dd>
<textarea name="search" id="search"></textarea>
</dd>
<dt>
<label for="search">Text to replace</label>
</dt>
<dd>
<textarea name="replace" id="replace"></textarea>
</dd>
<dt>
<input id="savePages" name="savePages" type="checkbox" value="save"/> <label for="savePages">Save pages</label>
<span class="xHint">By default, this script will execute in dry-mode, and will not save pages.</span>
</dt>
</dl>
<p>
<span class="buttonwrapper">
<input type="hidden" name="form_token" value="$!{services.csrf.token}"/>
<input type="hidden" name="confirm" value="true"/>
<input class="button" type="submit" value="Replace contents"/>
</span>
</p>
</form>
{{/html}}
{{/velocity}}
{{job id="bulkReplace" start="{{velocity}}$!{request.confirm}{{/velocity}}"}}
{{groovy}}
import org.apache.commons.lang3.StringUtils;
logger = services.logging.getLogger('FixBrokenImages');
services.logging.setLevel('FixBrokenImages', org.xwiki.logging.LogLevel.INFO);
if (hasProgramming && services.csrf.isTokenValid(request.form_token)) {
// Check if we have enough to work on
boolean allSpaces = request.allSpaces && request.allSpaces != '0' && request.allSpaces != 'false' && request.allSpaces != 'off';
if ((!request.targetSpace || StringUtils.isBlank(request.targetSpace)) && !allSpaces) {
logger.error('Missing a target space. Aborting.');
return;
}
if (request.search && StringUtils.isNotBlank(request.search)
&& request.replace && StringUtils.isNotBlank(request.replace)) {
def spacePrefix = "${StringUtils.removeEnd(request.targetSpace, 'WebHome')}%";
def sanitizedSearchString = request.search.replace('\r\n','\n');
def sanitizedReplaceString = request.replace.replace('\r\n','\n');
// Get every page matching the space
List<String> documents = (
allSpaces
? services.query
.hql("select doc.fullName from XWikiDocument doc where doc.fullName not like 'XWiki.%' and doc.content like :searchContent")
: services.query
.hql('select doc.fullName from XWikiDocument doc where doc.fullName like :spacePrefix and doc.content like :searchContent')
.bindValue('spacePrefix', spacePrefix.toString())
).bindValue('searchContent').anyChars().literal(sanitizedSearchString).anyChars().query().execute();
logger.debug('Found [{}] documents to verify', documents.size());
documents.each { documentFullName ->
try {
def document = xwiki.getDocument(documentFullName);
logger.info('Verifying document [{}]', document.getDocumentReference());
def oldContent = document.getContent();
def newContent = StringUtils.replace(oldContent, sanitizedSearchString, sanitizedReplaceString);
hasContentChanged = !(oldContent.equals(newContent));
if (hasContentChanged && 'save'.equals(request.savePages)) {
logger.info('Content has changed ; saving document [{}]', document.getDocumentReference());
document.setContent(newContent);
document.save();
} else if (hasContentChanged) {
logger.info('Content for document [{}] has changed but will not be saved', document.getDocumentReference());
}
} catch (Exception e) {
logger.error('Uncaught exception [{}]', e);
}
}
} else {
logger.error('Insufficient parameters. Aborting.');
}
} else {
logger.error('Insufficient permissions or invalid CSRF token. Aborting.')
}
{{/groovy}}
{{/job}}
#set ($spacePickerParams = {
'name': 'targetSpace',
'value': "$!{request.targetSpace}"
})
This script allows to perform bulk search and replace of XWiki document contents.
Programming rights are required to use this script.
{{html clean="false"}}
<form class="xform" action="#" method="post">
<dl>
<dt>
<label for="targetSpace">Space</label>
<span class="xHint">The script will look for documents containing the given search text within the following space.</span>
</dt>
<dd>
#pagePicker($spacePickerParams)
</dd>
<dt>
<input type="checkbox" name="allSpaces" id="allSpaces" />
<label for="allSpaces">All spaces</label>
<span class="xHint">The macro replace job will execute for every document in all spaces (excerpt the XWiki system space).</span>
</dt>
<dt>
<label for="search">Text to be searched</label>
<span class="xHint">The script will look for the following text in documents. The text in document contents has to match exactly with the search.</span>
</dt>
<dd>
<textarea name="search" id="search"></textarea>
</dd>
<dt>
<label for="search">Text to replace</label>
</dt>
<dd>
<textarea name="replace" id="replace"></textarea>
</dd>
<dt>
<input id="savePages" name="savePages" type="checkbox" value="save"/> <label for="savePages">Save pages</label>
<span class="xHint">By default, this script will execute in dry-mode, and will not save pages.</span>
</dt>
</dl>
<p>
<span class="buttonwrapper">
<input type="hidden" name="form_token" value="$!{services.csrf.token}"/>
<input type="hidden" name="confirm" value="true"/>
<input class="button" type="submit" value="Replace contents"/>
</span>
</p>
</form>
{{/html}}
{{/velocity}}
{{job id="bulkReplace" start="{{velocity}}$!{request.confirm}{{/velocity}}"}}
{{groovy}}
import org.apache.commons.lang3.StringUtils;
logger = services.logging.getLogger('FixBrokenImages');
services.logging.setLevel('FixBrokenImages', org.xwiki.logging.LogLevel.INFO);
if (hasProgramming && services.csrf.isTokenValid(request.form_token)) {
// Check if we have enough to work on
boolean allSpaces = request.allSpaces && request.allSpaces != '0' && request.allSpaces != 'false' && request.allSpaces != 'off';
if ((!request.targetSpace || StringUtils.isBlank(request.targetSpace)) && !allSpaces) {
logger.error('Missing a target space. Aborting.');
return;
}
if (request.search && StringUtils.isNotBlank(request.search)
&& request.replace && StringUtils.isNotBlank(request.replace)) {
def spacePrefix = "${StringUtils.removeEnd(request.targetSpace, 'WebHome')}%";
def sanitizedSearchString = request.search.replace('\r\n','\n');
def sanitizedReplaceString = request.replace.replace('\r\n','\n');
// Get every page matching the space
List<String> documents = (
allSpaces
? services.query
.hql("select doc.fullName from XWikiDocument doc where doc.fullName not like 'XWiki.%' and doc.content like :searchContent")
: services.query
.hql('select doc.fullName from XWikiDocument doc where doc.fullName like :spacePrefix and doc.content like :searchContent')
.bindValue('spacePrefix', spacePrefix.toString())
).bindValue('searchContent').anyChars().literal(sanitizedSearchString).anyChars().query().execute();
logger.debug('Found [{}] documents to verify', documents.size());
documents.each { documentFullName ->
try {
def document = xwiki.getDocument(documentFullName);
logger.info('Verifying document [{}]', document.getDocumentReference());
def oldContent = document.getContent();
def newContent = StringUtils.replace(oldContent, sanitizedSearchString, sanitizedReplaceString);
hasContentChanged = !(oldContent.equals(newContent));
if (hasContentChanged && 'save'.equals(request.savePages)) {
logger.info('Content has changed ; saving document [{}]', document.getDocumentReference());
document.setContent(newContent);
document.save();
} else if (hasContentChanged) {
logger.info('Content for document [{}] has changed but will not be saved', document.getDocumentReference());
}
} catch (Exception e) {
logger.error('Uncaught exception [{}]', e);
}
}
} else {
logger.error('Insufficient parameters. Aborting.');
}
} else {
logger.error('Insufficient permissions or invalid CSRF token. Aborting.')
}
{{/groovy}}
{{/job}}