Hi,
I've finally made un update of my initial script which I described here .
Now it checkes all the pages in our instance, and write the output in a Confluence page.
Quite sure many people here have already more sophisticated ways to do the job, but if this can help rookie-admins like me, then I'm happy.
I know I should stop using PageManager and SpaceManager get... calls, but honestly I haven't yet really understood how to make it work in the other way :-) so I'm staying on the good old managers I know ... :-)
Ciao Ciao, Andrea
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.confluence.pages.Page
import com.atlassian.confluence.pages.PageManager
import com.atlassian.confluence.spaces.Space
import com.atlassian.confluence.spaces.SpaceManager
import com.atlassian.confluence.pages.Attachment
import com.atlassian.confluence.pages.AttachmentManager
import com.atlassian.confluence.core.DefaultSaveContext
import groovy.xml.MarkupBuilder
import java.math.RoundingMode
import org.jsoup.Jsoup
def spaceManager = ComponentLocator.getComponent(SpaceManager)
def pageManager = ComponentLocator.getComponent(PageManager)
def attachmentManager = ComponentLocator.getComponent(AttachmentManager)
//All spaces to check
def spacesChecked=spaceManager.allSpaces.findAll{it instanceof Space}
//log.warn(spacesChecked)
//List and Map for attachments use cases
def attachmentUseCases=[]
//List and Map for attachment cases
def attachmentCases=[]
def attachmentCasesMap=[:]
//List and Map for unused attachment cases
def unusedAttachmentCases=[]
def unusedAttachmentCasesMap=[:]
////////////////////////////////////////
//Loop through spaces
////////////////////////////////////////
spacesChecked.each(){
spaceChecked->
//Pages to be checked
def pagesChecked=pageManager.getPages(spaceChecked, true).findAll{it instanceof Page}
////////////////////////////////////////
//Loop through space pages
////////////////////////////////////////
pagesChecked.each(){
pageChecked->
//////////////////////////////////////////
//Looking for attachment use cases in page
//////////////////////////////////////////
//Get content page for parsing
def body = pageChecked.bodyContent.body
//Parse page content
//Refs for use of Jsoup
//https://jsoup.org/cookbook/extracting-data/selector-syntax
//https://jsoup.org/cookbook/extracting-data/attributes-text-html
def parsedBody = Jsoup.parse(body)
//Looking for attachment tag
def attachments = parsedBody.select("ri|attachment")
//Going through all the attachment tags found
attachments.each(){
attachment ->
//Attachment file name
def attFileName=attachment.attr('ri:filename')
//Page of origin of the attachment
def attPageOrigin=attachment.select("ri|page").attr('ri:content-title')
if (attPageOrigin){
}
else{
attPageOrigin=pageChecked.title
}
//Space of origin of the attachment
def attSpaceOrigin=attachment.select("ri|page").attr('ri:space-key')
if (attSpaceOrigin){
}
else{
attSpaceOrigin=spaceChecked.key
}
//Attachment use case unique id
def attUseCaseId="${attSpaceOrigin}__${attPageOrigin}__${attFileName}"
//Add attachment use case id to list
if(!attachmentUseCases.contains(attUseCaseId)){
attachmentUseCases.add(attUseCaseId)
}
}
/////////////////////////////////
//Looking for attachments to page
/////////////////////////////////
def loadedAttachments=attachmentManager.getLatestVersionsOfAttachments(pageChecked)
loadedAttachments.each(){
lAttachment->
def lAttachmentFileName=lAttachment.fileName
def lAttachmentSize=(double)lAttachment.getFileSize()/(1024*1024)
BigDecimal lAttachmentSizeBD = new BigDecimal(lAttachmentSize).setScale(4, RoundingMode.HALF_UP)
def lAttachmentId="${spaceChecked.key}__${pageChecked.title}__${lAttachmentFileName}"
attachmentCases.add(lAttachmentId) //List for quick reference
def attachmentCasesMapAtt=[
space:spaceChecked.key,
page:pageChecked.title,
pageId:pageChecked.id,
pagePath:pageChecked.getUrlPath(),
name:lAttachmentFileName,
size:lAttachmentSizeBD.toString(),
path:lAttachment.getDownloadPath()
]
attachmentCasesMap.put(lAttachmentId, attachmentCasesMapAtt)
}
}
}
////////////////////////////////////////
//Check resulting lists from loops
////////////////////////////////////////
//Sort lists
attachmentCases.sort()
attachmentUseCases.sort()
//Compare lists to find unused attachment cases
attachmentCases.each(){
eAttachment->
if(!attachmentUseCases.contains(eAttachment)){
unusedAttachmentCases.add(eAttachment)
}
}
/////////////////////////////////
//Export to a table
/////////////////////////////////
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.p("Unused attachment cases:")
xml.table(class: "aui") {
thead {
tr{
th('Space')
th('Page')
th('Page Id')
th('Attachment')
th('Size (MB)')
th('Download Path')
th('Delete Link')
}
}
tbody{
unusedAttachmentCases.each(){
unusedAttachmentCase->
tr{
td(attachmentCasesMap.get(unusedAttachmentCase).get('space'))
td{
a(href:[CONFLUENCE BASE DIR]+
attachmentCasesMap.get(unusedAttachmentCase).get('pagePath')){
p(attachmentCasesMap.get(unusedAttachmentCase).get('page'))
}
}
td(attachmentCasesMap.get(unusedAttachmentCase).get('pageId'))
td(attachmentCasesMap.get(unusedAttachmentCase).get('name'))
td(attachmentCasesMap.get(unusedAttachmentCase).get('size'))
td{
a(href:[CONFLUENCE BASE DIR]+attachmentCasesMap.get(unusedAttachmentCase).get('path')){
p('Download Link')
}
}
td{
a([CONFLUENCE BASE DIR]+'/lockpoint/confirmattachmentremoval.action?pageId='
+attachmentCasesMap.get(unusedAttachmentCase).get('pageId')+'&fileName='
+attachmentCasesMap.get(unusedAttachmentCase).get('name')){
p('Delete Link')
}
}
}
}
}
}
/////////////////////////////////
//Write Page in Confluence
/////////////////////////////////
//Define Space and Page for output
def outputPage=pageManager.getPage("MySpace", "MyPage")
def oldVersion=outputPage.clone()
def contentEntityObjectOut = outputPage.getEntity()
contentEntityObjectOut.setBodyAsString(writer.toString())
pageManager.saveContentEntity(outputPage, oldVersion, DefaultSaveContext.BULK_OPERATION)
//Finally write in console
return writer
ABoerio
Program Manager, Information Technology Enthusiast
1 accepted answer
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
2 comments