Hosting
DATA 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.
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.
Scripts for values
Problem: 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.
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: 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.
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: 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.
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: 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.
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: 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.
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
Problem: 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.
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: 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.
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: We have found duplicate associations between layouts and projects.
Solution: Traverse all existing associations and remove the duplicates.
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: We have found associations of layouts with non-existent projects.
Solution: Traverse all associations and delete those that are associated with non-existent projects.
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
Scripts for items of list fields
Problem: 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.
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: 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.
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 ) }
Scripts for connections
Problem: 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.
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
Scripts for subscriptions
Problem: Know which subscriptions the instance has and who their owner is.
Solution: Retrieve all subscriptions stored in Projectrak along with their respective users.
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/>")
Scripts for mapping to Jira custom fields
Problem: 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.
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: 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.
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: 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.
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
Scripts for gadgets
Problem: 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.
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
Script for Projectrak cache
Problem: Need to enable or disable the Projectrak cache for testing purposes.
Solution: Set the desired value in the Projectrak configuration related to the cache.
Enable cache:
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)
Disable cache:
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)
Scripts for Projectrak database version
Problem: 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.
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
Problem: We want to reset 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: Reset the record in the Jira tables where the migration code is stored.
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 NEW_VERSION = 26 def stmt = connection.createStatement() def isOk = stmt.execute( "update propertystring " + "set propertyvalue = ('"+ NEW_VERSION +"') " + "where id = ( " + "select propertystring.id " + " from propertyentry, propertystring " + " where propertyentry.id = propertystring.id " + " and propertyentry.property_key = 'AO_00B950_#'" + ")" ) if(isOk != true){ result += " Update the database version of Profields to (" + NEW_VERSION + ")" } else{ result += " Error: Can not update the database version of Profields to (" + NEW_VERSION + ")" } } catch (def e) { result += "<br/> Error: <br/>" + ExceptionUtils.getStackTrace(e) } return result
Scripts for Oracle database
Problem: 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.
Project Values (Table: AO_00B950_AOPROJECT_VALUE)
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
Historical (Table: AO_00B950_AOHISTORICAL_FIELD)
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
List items (Table: AO_00B950_AOLIST_ITEM)
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