Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Hosting

Status
titleDATA CENTER

Problems and solutions

Here are some scripts that address common Projectrak Data Center (DC) problems. These scripts should be executed in the Projectrak console, which can be accessed from the Manage Apps section and is only accessible to Jira Administrator.
Click here to learn more about the Projectrak Script Console console.

Note

Most of the scripts make irreversible changes that can impact the proper functioning of the application. They should be used with caution.

Please contact our support team before using them.

tip

Scripts for values

Values

Problem

/ Suggestion

: You need to delete values by their identifiers

.

Solution

: The introduced identifiers are being traversed, and if they exist, they are deleted from the database.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectvalue.ProjectValueMgr
 
 
def VALUES_IDS = [x,x]
def projectValueMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectValueMgr.class)
def value = null
def println = ""
 
VALUES_IDS.each {
     
    println += "*** *** *** <br/>"
    println += "Value ID: " + it + "<br/>"
     
    value = projectValueMgr.get(it)
     
    if(value != null){
        projectValueMgr.delete(value)
        println += "Deleted!! <br/>"
    }
    else{
        println += "Can not found this Value <br/>"
    }
     
    println += "<br/><br/>"
}
 
 
return println

Problem

/ Suggestion

: Delete all values from Projectrak within a set of projects.

Solution

: All the introduced project identifiers are being traversed, and for each of them, all their values are being iterated to subsequently delete them.

expand

titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectvalue.ProjectValueMgr
 
 
def PROJECTS_IDS = [x, x]
def projectValueMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectValueMgr.class)
def value = null
def println = ""
 
PROJECTS_IDS.each {
 
    println += "*** *** *** <br/>"
    println += "Project Value for Project: " + it + "<br/>"
 
    value = projectValueMgr.getByProject((Long) it)
 
    if(value != null){
        projectValueMgr.delete(value)
        println += "Deleted!! <br/>"
    }
    else{
        println += "Can not found this Value <br/>"
    }
 
    println += "<br/><br/>"
}
 
 
return println


Problem / Suggestion

The values in the columns where the value is stored in lowercase do not have the same equivalent value as those where the value is stored as raw data.

Solution

All existing values are verified. Each field type has a different validation check.

Expand
titleScript
Code Block
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectvalue.ProjectValueMgr
import com.deiser.jira.profields.api.field.FieldService
import com.deiser.jira.profields.api.field.FieldType
 
 
def projectValueMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectValueMgr.class)
def fieldService = ComponentAccessor.getOSGiComponentInstanceOfType(FieldService.class)
def VALUES_IDS = projectValueMgr.get()
def println = "*** Values different *** <br />"
VALUES_IDS.each {
    def change = false
 
    def field = fieldService.get(it.field.ID)
 
    if(!(field.type.isCalculatedType() || field.type.isEquals("number") || field.type.isEquals("date") ||field.type.isEquals("duration"))) {
 
        if (it.value != null && !it.value.toLowerCase().equals(it.lowerValue)) {
            println += "VALUE: " + it.ID + "<br />"
            println += "Changing LowerValue <br />"
            it.setLowerValue(it.value.toLowerCase())
            change = true
        }
 
        if (it.display != null && !it.display.toLowerCase().equals(it.lowerDisplay)) {
            println += "VALUE: " + it.ID + "<br />"
            println += "Changing LowerDisplay <br />"
            it.setLowerDisplay(it.display.toLowerCase())
            change = true
        } else if (it.display == null && it.value != null) {
            println += "VALUE: " + it.ID + "<br />"
            println += "Set Display equals to Value <br />"
            it.setDisplay(it.value)
            it.setLowerDisplay(it.value.toLowerCase())
            change = true
        }
 
        if(change){
            projectValueMgr.save(it)
            println += "Change it! <br />"
        }
    }
 
 
}
 
 
return println

Problem / Suggestion

Information of values still exists in Projectrak for projects that no longer exist in Jira.

Solution

All value records are being traversed, and those where the project does not exist are being deleted.

Expand
titleScript
Code Block
import com.atlassian.jira.bc.project.ProjectService
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectvalue.AOProjectValue
import com.deiser.jira.profields.ao.v2.projectvalue.ProjectValueMgr
 
 
def projectValueMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectValueMgr.class)
def projectManager = ComponentAccessor.getProjectManager()
def println = ""
 
def allProjectValues = projectValueMgr.get()
if(allProjectValues != null){
    allProjectValues.each {
 
        def haveToDelete = it == null || projectManager.getProjectObj(it.getProjectId()) == null
        if(haveToDelete){
 
            println += "*** *** *** <br/>"
            println += (it == null || it.getProjectId() == null) ? "Project Value is empty" : "Project Value for Project: " + it.getProjectId() + "<br/>"
 
            projectValueMgr.delete(it)
            println += "<br/>"
        }
    }
     
}
 
return println

Problem / Suggestion

There are projects with duplicate values for the same field.

Solution

Traverse all values and delete the duplicates, leaving the oldest value in the database.

tip
Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectvalue.AOProjectValue
import com.deiser.jira.profields.ao.v2.projectvalue.ProjectValueMgr
import com.deiser.jira.profields.api.configuration.ConfigurationService
import com.deiser.jira.profields.api.field.FieldService
import com.deiser.jira.profields.api.field.FieldType
import groovy.transform.Field
import org.apache.commons.collections.CollectionUtils
 
@Field ProjectValueMgr projectValueMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectValueMgr.class)
 
/* ***** execution ***** */
@Field HashMap<String, List<AOProjectValue>> allValuesByHash = new HashMap<>()
@Field List println = ["<b>*** REMOVED ***</b> <br/>"]
removeAllDuplicatedValues()
return println
 
/* ***** FUNCTIONS ***** */
def removeAllDuplicatedValues(){
    projectValueMgr.get().each{addInMap(it)}
    getAllDuplicatedValues().each {list -> removeDuplicated(list)}
}
 
def getAllDuplicatedValues(){
    return allValuesByHash.entrySet().stream()
        .filter{it -> it.value.size() > 1}
        .map{it -> it.value}
        .collect()
}
 
def addInMap(AOProjectValue value){
    String hash = getHash(value)
    List currentValues = allValuesByHash.remove(hash)
    currentValues = currentValues == null ? new ArrayList() : currentValues;
    currentValues.add(value)
    allValuesByHash.put(hash, currentValues)
}
 
def getHash(AOProjectValue value){
    def fieldType = FieldType.getFieldTypeByKey(value.getField().getType())
    return fieldType.isMultiple() ? getHashForMultipleField(value) : getHashForSimpleField(value)
}
 
def getHashForMultipleField(AOProjectValue value){
    return "PROJECT("+ value.projectId +"); FIELD_ID("+ value.field.ID +"); VALUE("+ value.value +"); DISPLAY("+ value.display +"); PARENT_ID("+ value.parentId +");".toLowerCase()
}
 
def getHashForSimpleField(AOProjectValue value){
    return "PROJECT("+ value.projectId +"); FIELD_ID("+ value.field.ID +");".toLowerCase()
}
 
def getValueInString(AOProjectValue value){
    return "<br/> ID(<b>"+ value.ID +"</b>); PROJECT(<b>"+ value.projectId +"</b>); FIELD_ID(<b>"+ value.field.ID +"</b>); FIELD_TYPE(<b>"+ value.field.type +"</b>); VALUE(<b>"+ value.value +"</b>); DISPLAY(<b>"+ value.display +"</b>); PARENT-VALUE(<b>"+ value.parentValue +"</b>) PARENT-ID(<b>"+ value.parentId +"</b>); CHILDREN(<b>"+ getNumberOfChildren(value) +"</b>);"
}
 
def removeDuplicated(List<AOProjectValue> duplicated){
    List<AOProjectValue> withChildren = new ArrayList<>();
    List<AOProjectValue> withoutChildren = new ArrayList<>();
    duplicated.sort{a,b -> (a.ID <=> b.ID) }
    duplicated.each{ fillByNumberOfChildren(it, withChildren, withoutChildren)}
    def listToRemove = getListToRemove(withChildren, withoutChildren)
    listToRemove.each{
        println.add(getValueInString(it))
        projectValueMgr.delete(it)
    }
}
 
def fillByNumberOfChildren(AOProjectValue value, List withChildren, List withoutChildren){
    def numberOfChildren = getNumberOfChildren(value)
    if(numberOfChildren == 0) withoutChildren.add(value)
    else withChildren.add(value)
}
 
def getNumberOfChildren(AOProjectValue value){
    def parent = projectValueMgr.getByParentCustom(value.value)
    return parent == null ? null : parent.size();
}
 
def getListToRemove(List<AOProjectValue> withChildren, List<AOProjectValue> withoutChildren){
    if(withChildren.isEmpty()) return withoutChildren.subList(1, withoutChildren.size())
    if(withChildren.size() == 1) return withoutChildren
    List listToRemove = withChildren.size(1, withChildren.size())
    listToRemove.addAll(withoutChildren)
    return listToRemove
}

Scripts for layouts

Layouts

Problem / Suggestion

We have found non-existent fields in the structure of a layout.

Solution

Traverse the structure of all layouts to check if their fields exist, and if not, we delete them.

Expand
titleScript
Code Block
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.viewitem.AOViewItem
import com.deiser.jira.profields.ao.v2.viewitem.ViewItemMgr
import com.deiser.jira.profields.api.field.FieldService

def viewItemMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ViewItemMgr.class)
def fieldService = ComponentAccessor.getOSGiComponentInstanceOfType(FieldService.class)
def allViewItems = viewItemMgr.get()

def println = ""

allViewItems.each {

    if (it.fieldId != null) {

        def field = fieldService.get(it.fieldId)
        if(field == null){
            println += "Delete Field (" + it.fieldId + ") in Layout (" + it.layout.name + ") <br/>"
            viewItemMgr.delete(it)
        }
    }
}

println

Problem / Suggestion

Within a layout, there is duplicated information and orphaned structures.

Solution

Traverse all the layouts and verify their internal structure. If they have duplicated or orphaned structures, we delete them.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.layout.LayoutMgr
import com.deiser.jira.profields.ao.v2.viewitem.AOViewItem
import com.deiser.jira.profields.ao.v2.viewitem.ViewItemMgr
import com.deiser.jira.profields.api.layout.view.SectionView
import com.deiser.jira.profields.api.layout.view.ViewItem
import com.google.common.collect.Lists
import groovy.transform.Field
import org.apache.commons.collections.ListUtils

import java.util.stream.Collectors

@Field ViewItemMgr viewItemMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ViewItemMgr.class)
@Field LayoutMgr layoutMgr = ComponentAccessor.getOSGiComponentInstanceOfType(LayoutMgr.class)
@Field List println = []

execute()


//EXECUTE
def execute(){
    def layouts = layoutMgr.get()
    layouts.each {
        iterateByLayout(it)
    }
    return println
}

//LAYOUTS
def iterateByLayout(layout){
    def sourceItems = viewItemMgr.getByLayout(layout)
    checkAndFix(layout, sourceItems)
}

def checkAndFix(layout, sourceItems){
    //Get all structure
    def structure = getAllSections(sourceItems)
    addToPrint(layout, structure)

    //Remove all duplicated sections
    def duplicatedSections = removeAllDuplicatedSections(structure)
    addToPrintDeletedDuplicatedSections(duplicatedSections)

    //Remove all orphan
    def deletedOrphans = removeUntilThereAreNoOrphans()
    addToPrintDeletedOrphans(deletedOrphans)

    //Split
    addToPrintSplit()
}

//SECTIONS
def getAllSections(sourceItems){
    return sourceItems.stream()
            .filter{it -> isSection(it)}
            .map{it -> new ViewNode(item: it, children: getAllColumns(it, sourceItems), type: "Section")}
            .collect(Collectors.toList())
}

boolean isSection(viewItem){
    return viewItem.parentId == null
}

int compareSection(viewNode1, viewNode2){
    boolean comparative = viewNode1.item.name == viewNode2.item.name &&
            viewNode1.item.position == viewNode2.item.position &&
            ((viewNode1.children == null && viewNode2.children == null) ||
                    (viewNode1.children.size() == viewNode2.children.size()))
    return comparative ? 0 : 1
}

def removeAllDuplicatedSections(structure){
    def sectionsUniques = structure.toUnique{ sect1, sect2 -> compareSection(sect1, sect2) }
    def thereAreDuplicatedSections = structure.size() != sectionsUniques.size();
    if(thereAreDuplicatedSections){
        def repeatedSections = ListUtils.removeAll(structure, sectionsUniques)
        def repeatedViewItemSections = repeatedSections.stream().map { it -> it.item }.collect(Collectors.toList())

        this.viewItemMgr.delete(repeatedViewItemSections)
        return repeatedViewItemSections
    }
    return [];
}



//COLUMNS
def getAllColumns(section, sourceItems){
    return columns = sourceItems.stream()
            .filter{ it -> isColumn(section, it) }
            .map{it-> new ViewNode(item: it, children: getAllContainer(it, sourceItems), type: "Column")}
            .collect(Collectors.toList())
            .sort{ a -> a.item.position}
}

boolean isColumn(section, viewItem){
    return viewItem.parentId != null &&
            viewItem.parentId == section.ID &&
            viewItem.name == null &&
            viewItem.fieldId == null
}



//CONTAINERS
def getAllContainer(column, sourceItems){
    return sourceItems.stream()
            .filter{it -> isContainer(column, it)}
            .map{it -> new ViewNode(item: it, children: getAllFields(it, sourceItems), type: "Container")}
            .collect(Collectors.toList())
            .sort{ a -> a.item.position}
}

boolean isContainer(column, viewItem){
    return viewItem.parentId != null &&
            viewItem.parentId == column.ID &&
            viewItem.name
}

//FIELDS
def getAllFields(container, sourceItems){
    return sourceItems.stream()
            .filter{it ->  isField(container, it)}
            .map{it -> new ViewNode(item: it, children: null, type: "Field")}
            .collect(Collectors.toList())
            .sort{ a -> a.item.position}
}

def isField(container, viewItem){
    return viewItem.parentId != null &&
            viewItem.parentId == container.ID &&
            viewItem.getFieldId() != null
}


class ViewNode {
    AOViewItem item
    List<ViewNode> children;
    String type;

    def compare(ViewNode node){
        return item.name == node.item.name &&
                item.position == node.item.position &&
                item.fieldId == node.item.fieldId &&
                item.required == node.item.required &&
                item.layout.ID == node.item.layout.ID &&
                compareChildren(node.children)
    }

    def compareChildren(List<AOViewItem> nodeChildren){
        if(children == null && nodeChildren == null) return true;

        if(children.size() !=  nodeChildren.size()) return false;

        def compareResult = true
        children.eachWithIndex { ViewNode item, int index ->
            compareResult &= item.compare(nodeChildren.get(index))
            if(compareResult == false) return false
        }
        return compareResult
    }

    def printToString(){
        def itemString = item.position + " ID["+ item.ID +"] NAME["+ item.name +"] PARENT-ID["+ item.parentId +"] FIELD-ID["+ item.fieldId +"] <br/>"
        def childrenString = this.children == null
                ? ""
                : this.children.stream()
                .map{it -> it.printToString()}
                .collect(Collectors.joining(""))

        def tab  = ""
        switch(type){
            case "Section":
                break;
            case "Column":
                tab += "        "
                break;
            case "Container":
                tab += "        " + "        "
                break;
            case "Field":
                tab += "        " + "        " + "        " + "    "
                break;
        }

        return tab + type + " --> " +  itemString + childrenString
    }
}

//REMOVE ORPHAN
def removeUntilThereAreNoOrphans(){
    def hasOrphan = true
    def printlnToOrphans = []

    while(hasOrphan){
        hasOrphan = removeOrphan(printlnToOrphans)
    }

    return printlnToOrphans
}

def removeOrphan(println){
    def hasRemoved = false
    viewItemMgr.get().each {
        def parentId = it.getParentId()
        if(parentId != null && parentId >= 0){
            if(viewItemMgr.get(parentId) == null){
                println.add( "ID: "+ it.ID +", Name: "+ it.name +" / ")
                viewItemMgr.delete(it)
                hasRemoved = true
            }
        }
    }
    return hasRemoved
}


//PRINTS
def addToPrint(layout, structure){
    println.add("Layout ("+ layout.ID +")  <b>"+ layout.name +"</b><br/>Structure:<br/>")
    println.add(structure.stream().map{it -> it.printToString()}.collect(Collectors.toList()))
}

def addToPrintDeletedDuplicatedSections(duplicatedSections){
    if(duplicatedSections){
        def prefix = "<br/> <b>Deleted Sections:</b>";
        def duplicatedString = duplicatedSections.stream().map{it -> "ID: "+ it.ID +", Name: "+ it.name +" / "}.collect(Collectors.joining(" / "))
        println.add(prefix + duplicatedString + "<br/>")
    }
}

def addToPrintSplit(){
    println.add("   ------------    ------------    ------------   ------------    ------------    ------------   <br/>")
}

def addToPrintDeletedOrphans(deletedOrphans){
    if(!deletedOrphans.isEmpty()){
        println.add("<b>Orphans Deleted:</b> " + deletedOrphans + "<br/>")
    }
}

Problem / Suggestion

We have found duplicate associations between layouts and projects.

Solution

Traverse all existing associations and remove the duplicates.

Expand
titleScript
Code Block
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectlayout.AOProjectLayout
import com.deiser.jira.profields.ao.v2.projectlayout.ProjectLayoutMgr


def projectLayoutMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectLayoutMgr.class)

def store = [:]
def listToDelete = []


def allProjectLayout = projectLayoutMgr.get()
allProjectLayout.sort(true){a,b -> a.ID <=> b.ID}
if(allProjectLayout != null && allProjectLayout.size() > 0){
    allProjectLayout.each {

        def key = "LAYOUT: " + it.layout.ID + "; PROJECT: " + it.projectId + ";"
        def value = store.get(key)
        if(value == null){
            store.put(key, it)
        }
        else{
            listToDelete.add(it)
        }
    }
}


def println = ""
listToDelete.each {
    println += "ID: "+ it.ID +"LAYOUT: " + it.layout.ID + "; PROJECT: " + it.projectId + ";"
    projectLayoutMgr.delete(it)
    println += "Deleted! </br>"
}
println

Problem / Suggestion

We have found associations of layouts with non-existent projects.

Solution

Traverse all associations and delete those that are associated with non-existent projects.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.projectlayout.AOProjectLayout
import com.deiser.jira.profields.ao.v2.projectlayout.ProjectLayoutMgr


def projectLayoutMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ProjectLayoutMgr.class)
def projectManager = ComponentAccessor.getProjectManager()
def println = ""

def allProjectLayout = projectLayoutMgr.get()
if(allProjectLayout != null && allProjectLayout.length > 0){
    allProjectLayout.each {
        def haveToDelete = it == null || projectManager.getProjectObj(it.getProjectId()) == null
        if(haveToDelete){

            println += "<br/>"
            println += (it == null || it.getProjectId() == null) ? "Layout-Project is empty. " : "Layout-Project for Project: " + it.getProjectId() + "  "

            projectLayoutMgr.delete(it)
            println += "Deleted!!"
        }
    }
}

return println

Tip

Items of list fields

Problem / Suggestion

We are experiencing issues with the items in the list fields, but we are uncertain about the root cause. We need to identify where the problem originates.

Solution

Display the information of the problematic items.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.field.FieldMgr
import com.deiser.jira.profields.ao.v2.listitem.AOListItem
import com.deiser.jira.profields.ao.v2.listitem.ListItemMgr
import com.deiser.jira.profields.ao.v2.listitem.ListItemType
import groovy.transform.Field;

@Field ListItemMgr listItemMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ListItemMgr.class)
@Field FieldMgr fieldMgr = ComponentAccessor.getOSGiComponentInstanceOfType(FieldMgr.class)




String getMessageError(AOListItem listItem){
    String error = ""
    error += getValidField(listItem)
    error += getValidType(listItem)
    error += getValidCustomId(listItem)
    error += getValidData(listItem)
    error += getValidOrder(listItem)
    return error
}

String getValidField(AOListItem listItem){
    String error = ""
    error += listItem.getFieldId() == null ? "FieldId NULL; " : ""
    error += (error == "") && listItem.getFieldId() <= 0 ? "FieldId-0; " : ""
    error += (error == "") && fieldMgr.get(listItem.getFieldId()) == null ? "Field Not Exist; " : ""
    return error
}

String getValidType(AOListItem listItem){
    String error = ""
    error += listItem.getListItemType() == null ? "Type NULL; " : ""
    error += (error == "") && !ListItemType.isValidKey(listItem.getListItemType()) ? "Type Not Valid Value; " : ""
    return error
}

String getValidCustomId(AOListItem listItem){
    String error = ""
    error += listItem.getCustomId() == null ? "CustomId NULL" : ""
    error += (error == "") && listItem.getCustomId() == "" ? "CustomId is EMPTY;" : ""
    return error
}

String getValidData(AOListItem listItem){
    String error = ""
    error += listItem.getData() == null ? "Data NULL; " : ""
    error += (error == "") && listItem.getData() == "" ? "Data is EMPTY;" : ""
    return error
}

String getValidOrder(AOListItem listItem){
    String error = ""
    error += listItem.getOrder() == null ? "Order NULL; " : ""
    error += (error == "") && listItem.getOrder() <= 0 ? "Order-0" : ""
    return error
}



def print = ""
listItemMgr.get().each {
    def error = getMessageError(it)
    if(error != ""){
        print += "ID " + it.ID + ": " + error + " <br/> "
    }
}
return "<b>List Items With ERRORS:</b> <br/>" + print

Problem / Suggestion

There are issues with the sequential order of items in list fields. They maintain their order, but it is not sequential.

Solution

Establish a new sequential order through the script.

Connections
Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.field.FieldMgr
import com.deiser.jira.profields.ao.v2.listitem.AOListItem
import com.deiser.jira.profields.ao.v2.listitem.ListItemMgr
import com.deiser.jira.profields.api.configuration.ConfigurationService
import groovy.transform.Field
@Field ListItemMgr listItemMgr = ComponentAccessor.getOSGiComponentInstanceOfType(ListItemMgr.class)
@Field boolean UPDATE = true
main()
/* **** METHODS **** */
def main(){
    def itemsByFieldID = getAllItemsByFieldID()
    def itemsToChange = checkOrder(itemsByFieldID)
    def println = printItems(itemsToChange)
    if(UPDATE){
        listItemMgr.save(itemsToChange)
        println.add(" UPDATED ALL <br/>")
    }
    return println
}
def getAllItemsByFieldID(){
    def fieldWithItems = [:]
    listItemMgr.get().each {
        def values = fieldWithItems[it.fieldId]
        if(values == null){
            fieldWithItems[it.fieldId] = [it]
        }
        else{
            values.add(it)
            fieldWithItems[it.fieldId] = values
        }
    }
    return fieldWithItems
}
def checkOrder(HashMap map){
    def itemsToChange = []
    def keys = map.keySet()
    keys.each{
        def values = map[it]
        orderItems(values, itemsToChange)
    }
    return itemsToChange
}
def printItems(List<AOListItem> items){
    def println = [" *** ITEMS TO UPDATE *** <br/>"]
    items.each { println.add(itemToString(it))}
    return println
}
def orderItems(List<AOListItem> items, List<AOListItem> itemsToChange){
    def sortedItems = items.sort{ a, b -> a.order <=> b.order}
    sortedItems.eachWithIndex { AOListItem entry, int i ->
        if(entry.order != (i +1)){
            entry.order = i + 1
            itemsToChange.add(entry)
        }
    }
}
String itemToString(AOListItem item){
    return String.format("ID(%d); ORDER(%d) FIELD_ID(%d); TYPE(%s); <br/>",
            item.ID,
            item.order,
            item.fieldId,
            item.listItemType
    )
}
Tip

Scripts for connections

Problem / Suggestion

Establishing a connection to a pre-existing database is required for certain fields of Projectrak's external list.

Solution

Through a set of IDs of external list fields, they are traversed to establish the selected connection using their respective ID.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.ao.v2.field.AOField
import com.deiser.jira.profields.ao.v2.field.FieldMgr
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
 
def fieldMgr = ComponentAccessor.getOSGiComponentInstanceOfType(FieldMgr.class)
 
def FIELD_IDs = [X, X];
def CONNECTION_ID = Y
 
def println = "Start <br/>"
 
 
 
FIELD_IDs.each {
 
    def fieldList = fieldMgr.getById(it)
 
    if(fieldList.length == 1){
 
        def field = fieldList[0]
        def data = field.getData()
 
        println += "     Field: Id(" + field.ID + ") Name(" + field.name + ") Data(" + field.data + ") <br/>"
 
        def jsonSlurper = new JsonSlurper()
        def objectJson = jsonSlurper.parseText(data)
 
        objectJson.connectionId = CONNECTION_ID
        def newData = JsonOutput.toJson(objectJson)
 
        field.setData(newData)
 
        println += "     Before Save: Id(" + field.ID + ") Name(" + field.name + ") Data(" + field.data + ") <br/>"
 
        fieldMgr.save(field)
 
        println += "     Saved! <br/>"
    }
}
 
println

Subscriptions

Problem / Suggestion

Know which subscriptions the instance has and who their owner is.

Solution

Retrieve all subscriptions stored in Projectrak along with their respective users.

Expand
titleScript
Code Block
languagegroovy
import com.deiser.jira.profields.api.subscription.SubscriptionService
import com.atlassian.jira.component.ComponentAccessor

ComponentAccessor.getOSGiComponentInstanceOfType(SubscriptionService.class)
    .get()
    .collect{" - ${it.user}: ${it.name}"}
    .join("<br/>")
Tip

Scripts for Mapping to Jira custom fields

Problem / Suggestion

We have encountered Jira custom fields that have lost their association with Projectrak fields.

Solution

All Jira custom fields that belong to Projectrak are traversed to verify if they are related to a Projectrak field. If not, the Jira custom field is deleted.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.managedconfiguration.ManagedConfigurationItem
import com.atlassian.jira.config.managedconfiguration.ManagedConfigurationItemService
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.deiser.jira.profields.ao.v2.field.FieldMgr
 
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
ManagedConfigurationItemService managedConfigurationItemService = ComponentAccessor.getComponent(ManagedConfigurationItemService.class);
 
FieldMgr fieldMgr = ComponentAccessor.getOSGiComponentInstanceOfType(FieldMgr.class)
 
def objects = customFieldManager.getCustomFieldObjects()
print = "*** CustomFields of Profields *** <br/>"
 
def each = objects.each {
    def customType = it.getCustomFieldType().toString()
    if (customType.contains("com.deiser.jira.profields")) {
 
        print += "CustomField ID: " + it.idAsLong + "<br/>"
        print += "Type: " + it.getCustomFieldType().toString() + "<br/>"
        print += "Name: " + it.name + "<br/>"
 
        def field = fieldMgr.getFieldByCustomField(it.idAsLong)
        if(field != null){
            print += "Oh Yeah! It's correct! <br/>"
        }
        else{
            print += "This customfield doesn't exist in Profields <br/>"
 
            ManagedConfigurationItem managedCreatedCustomField = managedConfigurationItemService.getManagedCustomField(it);
            managedConfigurationItemService.removeManagedConfigurationItem(managedCreatedCustomField)
            customFieldManager.removeCustomField(it)
 
            print += "Deleted!! <br/>"
        }
 
        print += "<br/><br/>"
    }
}
 
print

Problem / Suggestion

The Jira custom fields related to Projectrak cannot be edited or deleted as they are currently locked.

Solution

All Jira custom fields that belong to Projectrak are traversed to unlock.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.managedconfiguration.ConfigurationItemAccessLevel
import com.atlassian.jira.config.managedconfiguration.ManagedConfigurationItem
import com.atlassian.jira.config.managedconfiguration.ManagedConfigurationItemBuilder
import com.atlassian.jira.config.managedconfiguration.ManagedConfigurationItemService
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.deiser.jira.profields.ao.v2.field.FieldMgr
 
 
String PLUGIN_NAME = "com.deiser.jira.profields";
 
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
ManagedConfigurationItemService managedConfigurationItemService = ComponentAccessor.getComponent(ManagedConfigurationItemService.class);
 
def objects = customFieldManager.getCustomFieldObjects()
print = "*** CustomFields of Profields *** <br/>"
 
objects.each {
    def customType = it.getCustomFieldType().toString()
    if (customType.contains(PLUGIN_NAME)) {
 
        print += "CustomField ID: " + it.idAsLong + "<br/>"
        print += "Type: " + it.getCustomFieldType().toString() + "<br/>"
        print += "Name: " + it.name + "<br/>"
 
        ManagedConfigurationItem managedCreatedCustomField = managedConfigurationItemService.getManagedCustomField(it);
        ManagedConfigurationItemBuilder managedConfigurationItemBuilder = managedCreatedCustomField.newBuilder();
        ManagedConfigurationItem managedConfigurationItem = managedConfigurationItemBuilder
                .setManaged(false)
                .setConfigurationItemAccessLevel(ConfigurationItemAccessLevel.ADMIN)
                .build();
 
        managedConfigurationItemService.updateManagedConfigurationItem(managedConfigurationItem);
        print += 'Unlock CustomField <br/><br/>'
    }
}
 
print

Problem / Suggestion

We want to regenerate the mapping of all Projectrak fields with the Jira custom fields.

Solution

Traverse the Projectrak fields that have mapping enabled to remove the current Jira custom field and generate a new one.

Gadgets
Expand
titleScript
Code Block
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.deiser.jira.profields.ao.v2.field.FieldMgr
import com.deiser.jira.profields.api.field.FieldService
 
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
FieldMgr fieldMgr = ComponentAccessor.getOSGiComponentInstanceOfType(FieldMgr.class)
FieldService fieldService = ComponentAccessor.getOSGiComponentInstanceOfType(FieldService.class)
 
def println = "Delete ID CustomField: <br/>"
 
fieldMgr.get().each {
    def customFieldId = it.getCustomFieldId()
    if(customFieldId != null){
 
        def customField = customFieldManager.getCustomFieldObject(customFieldId)
        if(customField == null){
            println += "customField(" + it.customFieldId + ") in the field(" + it.ID + "): " + it.name + " "
            it.customFieldId = null
            fieldMgr.save(it)
 
            def field = fieldService.get(it.ID)
            field.customField = true
            fieldService.update(field)
            println += "-> setted new custom field; <br/>"
        }
 
    }
}
 
println
Tip

Scripts for gadgets

Problem / Suggestion

There are issues with data migrations related to the gadgets, and we want to identify the problematic gadget.

Solution

All users of the instance are being traversed to check the Projectrak gadgets. Both correct and erroneous gadgets are displayed on the screen.

Expand
titleScript
Code Block
import org.apache.commons.codec.binary.Hex
import java.util.stream.*
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.portal.PortalPage
import com.atlassian.jira.portal.PortletConfiguration
import com.atlassian.jira.portal.PortletConfigurationManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.bc.portal.PortalPageService
import org.apache.commons.lang.StringUtils
 
def GADGET_ONEFIELD_XML = "profields_gadget_onefield.xml"
def GADGET_SUMMARY_XML = "profields_gadget_summary.xml"
def GADGET_TIMESHEET_XML = "profields_gadget_timesheet.xml"
def GADGET_TWOFIELDS_XML = "profields_gadget_twofields.xml"
 
def GADGETS_PROFIELDS = [GADGET_ONEFIELD_XML, GADGET_SUMMARY_XML, GADGET_TIMESHEET_XML, GADGET_TWOFIELDS_XML]
 
def userManager = ComponentAccessor.getUserManager()
def portalPageService = ComponentAccessor.getOSGiComponentInstanceOfType(PortalPageService.class)
def portletConfigurationManager = ComponentAccessor.getOSGiComponentInstanceOfType(PortletConfigurationManager.class)
 
def errorPortalPage = ""
def printValue = ""
def amountOfGadgetsMigrated = 0
 
def applicationUserCollection = userManager.getAllApplicationUsers()
for(ApplicationUser user: applicationUserCollection){
 
    def portalPageCollection = portalPageService.getOwnedPortalPages(user)
    for(PortalPage portalPage: portalPageCollection){
 
        try {
 
            def listPortletConfiguration = portletConfigurationManager.getByPortalPage(portalPage.getId())
            for (PortletConfiguration portletConfiguration : listPortletConfiguration) {
 
                def uri = portletConfiguration.getOpenSocialSpecUri().getOrNull()
                if (uri != null) {
 
                    GADGETS_PROFIELDS.each {
 
                        if (uri.toString().contains(it)) {
                            printValue += " *************************** <br/>"
                            printValue += " ID: " + portalPage.id
                            printValue += "<br/>"
                            printValue += " UserName: " + user.getName()
                            printValue += "<br/>"
                            printValue += " Dashboard: " + portalPage.getName()
                            printValue += "<br/>"
                            printValue += "Configuration:"
                            printValue += "<br/>"
 
                            def filter = false
                            portletConfiguration.getUserPrefs()
                                    .each {
                                key, value ->
 
                                    if (key == "overrideTitle") {
                                        printValue += "Gadget Name: ${value}"
                                        printValue += "<br/>"
                                    } else if (key == "pqlPickerSource") {
                                        if (value == "filter") {
                                            filter = true
                                            printValue += "Has FILTER"
                                            printValue += "<br/>"
                                        } else if (value == "pql") {
                                            filter = false
                                            printValue += "Has PQL"
                                            printValue += "<br/>"
                                        }
                                    } else if (key == "pqlPickerData") {
                                        if (filter) {
                                            printValue += "ID FILTER: ${value}"
                                            printValue += "<br/>"
                                        } else {
                                            if (value != null) {
                                                value = new String(Hex.decodeHex(value.toCharArray()))
                                            }
                                            printValue += "PQL: ${value}"
                                            printValue += "<br/>"
                                        }
                                    }
 
                            }
 
                            printValue += " *************************** <br/>"
                            amountOfGadgetsMigrated += 1
                        }
                    }
 
                }
            }
        }
        catch(Exception ex){
            printValue += "<br/> -- ERROR --> amount before: " + amountOfGadgetsMigrated + "<br/>"
            errorPortalPage += "<br/> **** **** **** <br/>"
            errorPortalPage += "ID: " + portalPage.id + "/ Name: " + portalPage.name + "/ Owner: " + portalPage.ownerUserName + " <br/>"
            errorPortalPage += "Before: " + amountOfGadgetsMigrated + "<br/>"
            errorPortalPage += "ERROR: " + ex.getMessage() + "<br/> <br/>"
        }
    }
}
 
return printValue + "<br/>" + errorPortalPage
Tip

Script for Projectrak

Cache

cache

Problem / Suggestion

Need to enable or disable the Projectrak cache for testing purposes.

Solution

Set the desired value in the Projectrak configuration related to the cache.

Expand
titleScript - Enable cache
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.api.configuration.ConfigurationService
import static com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType

def configurationService = ComponentAccessor.getOSGiComponentInstanceOfType(ConfigurationService.class)
configurationService.setCache(true)
Expand
titleScript Disable cache
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import com.deiser.jira.profields.api.configuration.ConfigurationService
import static com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType

def configurationService = ComponentAccessor.getOSGiComponentInstanceOfType(ConfigurationService.class)
configurationService.setCache(false)
Tip

Scripts for Projectrak database version

Problem / Suggestion

We want to know the latest Projectrak migration registered in Jira that has been performed. Please note that there may be other types of migrations that are not recorded in Jira.

Solution

Accessing the Jira tables where the migration code is stored.

Expand
titleScript
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import org.apache.commons.lang3.exception.ExceptionUtils
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface
 
import java.sql.ResultSet
import java.sql.Statement
 
def delegator = ComponentAccessor.getComponentOfType(DelegatorInterface.class)
def helperName = delegator.getGroupHelperName("default")
def connection = ConnectionFactory.getConnection(helperName)
 
def result = ""
try {
 
    def stmt = connection.createStatement()
     
     ResultSet rs = stmt.executeQuery(
            "select propertystring.id, propertystring.propertyvalue " +
            "from propertyentry, propertystring " +
            "where propertyentry.id = propertystring.id " +
            "and propertyentry.property_key = 'AO_00B950_#'"
     );
     
        while (rs.next()) {
            def id = rs.getString("id");
            def value = rs.getString("propertyvalue");
 
            result += "Version of Profields Database : " + value + "<br/>"
        }
 
} catch (def e) {
    result += "<br/> Error: <br/>" + ExceptionUtils.getStackTrace(e)
}
 
return result
Tip

Scripts for Oracle

database

Database

Problem / Suggestion

When making a change in the database properties, we encountered Clob-type columns in the Projectrak tables, which is causing errors in certain functionalities.

Solution

Execute three scripts to modify the column type. This involves creating a new column for data dumping and subsequently deleting the erroneous column. No information is lost during the execution of the scripts.

Expand
titleScript - Project Values: AO_00B950_AOPROJECT_VALUE table
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface
import java.sql.Statement
 
def delegator = ComponentAccessor.getComponentOfType(DelegatorInterface.class)
def helperName = delegator.getGroupHelperName("default")
def connection = ConnectionFactory.getConnection(helperName)
 
def arrayColumns = ["DISPLAY", "LOWER_DISPLAY", "VALUE", "LOWER_VALUE", "PARENT_VALUE"] as String[]
 
def result = ""
try {
    def statement = connection.createStatement()
 
    arrayColumns.each {
 
    statement.execute("alter table AO_00B950_AOPROJECT_VALUE add " + it +"2 clob")
        statement.execute("update AO_00B950_AOPROJECT_VALUE set " + it +"2 = " + it)
        statement.execute("update AO_00B950_AOPROJECT_VALUE set " + it +" = null")
        statement.execute("alter table AO_00B950_AOPROJECT_VALUE drop column " + it)
 
        statement.execute("alter table AO_00B950_AOPROJECT_VALUE add " + it +" varchar2(4000)")
        statement.execute("update AO_00B950_AOPROJECT_VALUE set " + it +" = " + it +"2")
        statement.execute("alter table AO_00B950_AOPROJECT_VALUE drop column " + it +"2")
 
        result += "Completed " + it + "! <br/>"
 
    }
     
 
} catch (def e) {
    result += "<br/> Error: <br/>" + ExceptionUtils.getStackTrace(e)
}
 
return result
Expand
titleScript - History: AO_00B950_AOHISTORICAL_FIELD table
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface
import java.sql.Statement
 
def delegator = ComponentAccessor.getComponentOfType(DelegatorInterface.class)
def helperName = delegator.getGroupHelperName("default")
def connection = ConnectionFactory.getConnection(helperName)
 
def arrayColumns = ["NEW_VALUE", "OLD_VALUE", "NEW_DISPLAY", "OLD_DISPLAY"] as String[]
 
 
def result = ""
try {
    def statement = connection.createStatement()
 
    arrayColumns.each {
 
    statement.execute("alter table AO_00B950_AOHISTORICAL_FIELD add " + it +"2 clob")
        statement.execute("update AO_00B950_AOHISTORICAL_FIELD set " + it +"2 = " + it)
        statement.execute("update AO_00B950_AOHISTORICAL_FIELD set " + it +" = null")
        statement.execute("alter table AO_00B950_AOHISTORICAL_FIELD drop column " + it)
 
        statement.execute("alter table AO_00B950_AOHISTORICAL_FIELD add " + it +" varchar2(4000)")
        statement.execute("update AO_00B950_AOHISTORICAL_FIELD set " + it +" = " + it +"2")
        statement.execute("alter table AO_00B950_AOHISTORICAL_FIELD drop column " + it +"2")
 
        result += "Completed " + it + "! <br/>"
 
    }
     
 
} catch (def e) {
    result += "<br/>Error:<br/>" + ExceptionUtils.getStackTrace(e)
}
 
return result
Expand
titleScript - List items: AO_00B950_AOLIST_ITEM table
Code Block
languagegroovy
import com.atlassian.jira.component.ComponentAccessor
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface
import java.sql.Statement
 
def delegator = ComponentAccessor.getComponentOfType(DelegatorInterface.class)
def helperName = delegator.getGroupHelperName("default")
def connection = ConnectionFactory.getConnection(helperName)
 
def arrayColumns = ["DATA", "LOWER_DATA"] as String[]
 
 
def result = ""
try {
    def statement = connection.createStatement()
 
    statement.execute("alter table AO_00B950_AOLIST_ITEM modify DATA null")
 
    arrayColumns.each {
 
        statement.execute("alter table AO_00B950_AOLIST_ITEM add " + it +"2 clob")
        statement.execute("update AO_00B950_AOLIST_ITEM set " + it +"2 = " + it)
        statement.execute("update AO_00B950_AOLIST_ITEM set " + it +" = null")
        statement.execute("alter table AO_00B950_AOLIST_ITEM drop column " + it)
 
        statement.execute("alter table AO_00B950_AOLIST_ITEM add " + it +" varchar2(4000)")
        statement.execute("update AO_00B950_AOLIST_ITEM set " + it +" = " + it +"2")
        statement.execute("alter table AO_00B950_AOLIST_ITEM drop column " + it +"2")
 
        result += "Completed " + it + "! <br/>"
 
    }
     
     statement.execute("alter table AO_00B950_AOLIST_ITEM modify DATA not null")
 
} catch (def e) {
    result += "<br/>Error:<br/>" + ExceptionUtils.getStackTrace(e)
}
 
return result

Filter by label (Content by label)
showLabelsfalse
max5
spacescom.atlassian.confluence.content.render.xhtml.model.resource.identifiers.SpaceResourceIdentifier@140ea
showSpacefalse
sortmodified
reversetrue
typepage
cqllabel in ( "script" , "profields" , "scriptrunner" , "exporter" ) and type = "page" and space = "SKB"
labelsprofields script scriptrunner


Page Properties
hiddentrue

Related issues