Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Search for unused attachments in server instance

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

 

Immagine 2020-11-26 005534.jpg

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

 

2 comments

Fabienne Gerhard
Community Champion
November 25, 2020

Hi @ABoerio 

this looks really interesting - especially at the end of the year a good "house-clean" -> it's time for!

Definitely gonna give it a try! Thanks for sharing 😊

ABoerio
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 1, 2020

Corrected this section of my previous code

Immagine 2020-12-01 191642.jpg

Added .title and .key

Ciao, Andrea

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events