Skip to content

Adding attribute filter values for SDK, extending InsightAttribute-Data #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ value class InsightAttributeId(@field:NotNull val raw: Int)

// endregion ID wrapper

data class AttributeValueResponse(
@field:NotNull val page: Int,
@field:NotNull val pages: Int,
@field:NotNull val pageSize: Int,
@field:NotNull val results: List<String>
)

data class InsightObjectPage<T>(
@field:NotNull val totalFilterCount: Int = -1,
@field:NotNull val objects: List<T> = emptyList(),
Expand Down Expand Up @@ -121,14 +128,17 @@ sealed class InsightAttribute(
@get:JvmName("getAttributeId")
@Transient @field:NotNull open val attributeId: InsightAttributeId,
@Transient open val schema: ObjectTypeSchemaAttribute?,
@field:NotNull val type: AttributeTypeEnum
@field:NotNull val type: AttributeTypeEnum,
val isMulti: Boolean,
@Transient open val displayValue: String? = null,
@Transient open val displayValues: List<String>? = null
) {
data class Text(
@get:JvmName("getAttributeId")
@field:NotNull override val attributeId: InsightAttributeId,
val value: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Text) {
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Text, false, value, null) {
override fun toString() = value ?: ""
}

Expand All @@ -137,7 +147,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val value: Int?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Integer){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Integer, false, value?.toString(), null) {
override fun toString() = value?.toString() ?: ""
}

Expand All @@ -146,7 +156,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val value: Boolean?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Bool){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Bool, false, value?.toString(), null) {
override fun toString() = value?.toString() ?: ""
}

Expand All @@ -155,17 +165,17 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val value: Double?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.DoubleNumber){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.DoubleNumber, false, value?.toString(), null){
override fun toString() = value?.toString() ?: ""
}

data class Date(
@get:JvmName("getAttributeId")
@field:NotNull override val attributeId: InsightAttributeId,
val value: LocalDate?,
val displayValue: String?,
override val displayValue: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Date){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Date, false, displayValue, null){
override fun toString() = value?.toString() ?: ""
}

Expand All @@ -176,19 +186,19 @@ sealed class InsightAttribute(
@get:JvmName("getAttributeId")
@field:NotNull override val attributeId: InsightAttributeId,
val value: LocalTime?,
val displayValue: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Time){
override val schema: ObjectTypeSchemaAttribute?,
override val displayValue: String? = null
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Time, false, displayValue, null){
override fun toString() = value?.toString() ?: ""
}

data class DateTime(
@get:JvmName("getAttributeId")
@field:NotNull override val attributeId: InsightAttributeId,
val value: ZonedDateTime?,
val displayValue: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.DateTime){
override val schema: ObjectTypeSchemaAttribute?,
override val displayValue: String? = null
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.DateTime, false, displayValue, null){
override fun toString() = value?.toString() ?: ""
}

Expand All @@ -197,7 +207,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val value: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Email){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Email, false, value, null){
override fun toString() = value ?: ""
}

Expand All @@ -206,7 +216,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val value: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Textarea){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Textarea, false, value, null){
override fun toString() = value ?: ""
}

Expand All @@ -215,7 +225,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val value: String?,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Ipaddress){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Ipaddress, false, value, null){
override fun toString() = value ?: ""
}

Expand All @@ -225,7 +235,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val values: List<String>,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Url){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Url, true, values.joinToString(","), values){
override fun toString() = values.joinToString(",")
}

Expand All @@ -234,7 +244,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
val values: List<String>,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Select){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Select, true, values.joinToString(","), values){
override fun toString() = values.joinToString(",")
}

Expand All @@ -244,7 +254,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
@field:NotNull val referencedObjects: List<ReferencedObject>,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Reference) {
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.Reference, true, referencedObjects.map { it.label }.joinToString(","), referencedObjects.map { it.label }) {
override fun toString() = referencedObjects.joinToString(",") { it.objectKey }
}

Expand All @@ -253,7 +263,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
@field:NotNull val users: List<JiraUser>,
override val schema: ObjectTypeSchemaAttribute?
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.User){
) : InsightAttribute(attributeId, schema, AttributeTypeEnum.User, true, users.map { it.displayName }.joinToString(","), users.map { it.displayName }){
override fun toString() = users.joinToString(",") { it.key }
}

Expand All @@ -268,7 +278,10 @@ sealed class InsightAttribute(
) : InsightAttribute(
attributeId,
schema,
AttributeTypeEnum.Confluence
AttributeTypeEnum.Confluence,
true,
pages.map { it.title }.joinToString(","),
pages.map { it.title }
) {
override fun toString() = "Confluence attributeId=$attributeId"
}
Expand All @@ -284,7 +297,10 @@ sealed class InsightAttribute(
) : InsightAttribute(
attributeId,
schema,
AttributeTypeEnum.Group
AttributeTypeEnum.Group,
true,
groups.map { it.name }.joinToString(","),
groups.map { it.name }
) {
override fun toString() = "Group attributeId=$attributeId"
}
Expand All @@ -298,7 +314,7 @@ sealed class InsightAttribute(
@field:NotNull val versions: List<ProjectVersion>,
override val schema: ObjectTypeSchemaAttribute?
) :
InsightAttribute(attributeId, schema, AttributeTypeEnum.Version) {
InsightAttribute(attributeId, schema, AttributeTypeEnum.Version, true, versions.map { it.name }.joinToString(","), versions.map { it.name }) {
override fun toString() = "Version attributeId=$attributeId"
}

Expand All @@ -310,7 +326,7 @@ sealed class InsightAttribute(
@field:NotNull override val attributeId: InsightAttributeId,
@field:NotNull val projects: List<JiraProject>,
override val schema: ObjectTypeSchemaAttribute?) :
InsightAttribute(attributeId, schema, AttributeTypeEnum.Project){
InsightAttribute(attributeId, schema, AttributeTypeEnum.Project, true, projects.map { it.name }.joinToString(","), projects.map { it.name }) {
override fun toString() = "Project attributeId=$attributeId"
}

Expand All @@ -326,7 +342,10 @@ sealed class InsightAttribute(
) : InsightAttribute(
attributeId,
schema,
AttributeTypeEnum.Status
AttributeTypeEnum.Status,
false,
status?.name,
null
) {
override fun toString() = "Status attributeId=$attributeId"
}
Expand All @@ -335,7 +354,7 @@ sealed class InsightAttribute(
@get:JvmName("getAttributeId")
@field:NotNull override val attributeId: InsightAttributeId,
override val schema: ObjectTypeSchemaAttribute?) :
InsightAttribute(attributeId, schema, AttributeTypeEnum.Unknown){
InsightAttribute(attributeId, schema, AttributeTypeEnum.Unknown, false, null, null){
override fun toString() = ""
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,11 @@ class HttpInsightObjectOperator(private val context: HttpInsightClientContext) :
}
DefaultType.TIME -> {
val localTime = singleValue()?.let { LocalTime.parse(it) }
InsightAttribute.Time(attributeId, localTime, values.firstOrNull()?.displayValue as? String?, schema)
InsightAttribute.Time(attributeId, localTime, schema, values.firstOrNull()?.displayValue as? String?, )
}
DefaultType.DATE_TIME -> {
val zonedDateTime = singleValue()?.let { ZonedDateTime.parse(it) }
InsightAttribute.DateTime(attributeId, zonedDateTime, values.firstOrNull()?.displayValue as? String?, schema)
InsightAttribute.DateTime(attributeId, zonedDateTime, schema, values.firstOrNull()?.displayValue as? String?)
}
DefaultType.EMAIL -> InsightAttribute.Email(attributeId, singleValue(), schema)
DefaultType.TEXTAREA -> InsightAttribute.Textarea(attributeId, singleValue(), schema)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.atlassian.jira.bc.project.ProjectService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.properties.ApplicationProperties
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.util.NaturalOrderStringComparator
import com.linkedplanet.kotlinatlassianclientcore.common.api.StatusAttribute
import com.linkedplanet.kotlinatlassianclientcore.common.api.StatusCategory
import com.linkedplanet.kotlinatlassianclientcore.common.api.ConfluencePage
Expand All @@ -41,15 +42,7 @@ import com.linkedplanet.kotlininsightclient.api.error.ObjectTypeNotFoundError
import com.linkedplanet.kotlininsightclient.api.interfaces.InsightObjectOperator
import com.linkedplanet.kotlininsightclient.api.interfaces.MapToDomain
import com.linkedplanet.kotlininsightclient.api.interfaces.identity
import com.linkedplanet.kotlininsightclient.api.model.InsightAttribute
import com.linkedplanet.kotlininsightclient.api.model.InsightAttributeId
import com.linkedplanet.kotlininsightclient.api.model.InsightObject
import com.linkedplanet.kotlininsightclient.api.model.InsightObjectId
import com.linkedplanet.kotlininsightclient.api.model.InsightObjectPage
import com.linkedplanet.kotlininsightclient.api.model.InsightObjectTypeId
import com.linkedplanet.kotlininsightclient.api.model.ObjectTypeSchemaAttribute
import com.linkedplanet.kotlininsightclient.api.model.ReferencedObject
import com.linkedplanet.kotlininsightclient.api.model.ReferencedObjectType
import com.linkedplanet.kotlininsightclient.api.model.*
import com.linkedplanet.kotlininsightclient.sdk.SdkInsightObjectTypeOperator.typeAttributeBeanToSchema
import com.linkedplanet.kotlininsightclient.sdk.services.ReverseEngineeredDateTimeFormatterInJira
import com.linkedplanet.kotlininsightclient.sdk.services.ReverseEngineeredVersionAssembler
Expand All @@ -73,8 +66,10 @@ import com.riadalabs.jira.plugins.insight.services.model.ObjectTypeAttributeBean
import com.riadalabs.jira.plugins.insight.services.model.ObjectTypeBean
import com.riadalabs.jira.plugins.insight.services.model.StatusTypeBean
import com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory
import kotlinx.coroutines.runBlocking
import java.time.ZoneId
import java.util.*
import kotlin.math.min

object SdkInsightObjectOperator : InsightObjectOperator {

Expand Down Expand Up @@ -307,6 +302,45 @@ object SdkInsightObjectOperator : InsightObjectOperator {
?.right() ?: ObjectNotFoundError(insightObjectId).left<ObjectNotFoundError>()).bind()
}

suspend fun getAttributeValues(
objectTypeId: Int,
attributeId: Int,
query: String?,
exceptionList: String?,
page: Int,
pageSize: Int
): Either<InsightClientError, AttributeValueResponse> = catchAsInsightClientError {
val exceptions = exceptionList?.split(",")?.map { it.lowercase() }?: emptyList()
val objectTypeAttributeBean =
objectTypeAttributeFacade.findObjectTypeAttributeBeans(objectTypeId).firstOrNull { it.id == attributeId }
?: throw RuntimeException("objectType not found")

val objects: List<ObjectBean> = iqlFacade.findObjects("objectTypeId = $objectTypeId", 0, 1000000).objects
val allAttributeValues = objects.flatMap { it ->
val attributeBean = it.objectAttributeBeans.firstOrNull { it.objectTypeAttributeId == attributeId }
attributeBean?.let { runBlocking { mapAttributeBeanToInsightAttribute(it, objectTypeAttributeBean)
.getOrNull() } }?.let {
if(it.isMulti) {
it.displayValues?: emptyList()
} else {
it.displayValue?.let {listOf(it)}?: emptyList()
}
}?: emptyList()
}.toSet().sortedWith(NaturalOrderStringComparator.CASE_INSENSITIVE_ORDER)
val filteredAttributeValues = allAttributeValues.filter {!exceptions.contains(it.lowercase()) }
.filter { query.isNullOrEmpty() || it.lowercase().contains(query.lowercase()) }
val pages = (filteredAttributeValues.size + pageSize - 1) / pageSize
val paginationIndex = ((page-1).takeIf { it >= 0 }?:0)*pageSize
val paginationEndIndex = min(paginationIndex+pageSize, filteredAttributeValues.size)
val paginatedValues = filteredAttributeValues.subList(paginationIndex, paginationEndIndex)
AttributeValueResponse(
page,
pages,
pageSize,
paginatedValues
)
}

private fun createEmptyDomainObject(
objectTypeId: InsightObjectTypeId,
objectTypeBean: ObjectTypeBean
Expand Down Expand Up @@ -484,13 +518,13 @@ object SdkInsightObjectOperator : InsightObjectOperator {
val date = values.firstOrNull()?.dateValue
val localTime = date?.toInstant()?.atZone(zoneId)?.toLocalTime()
val displayValue = null // Insights original ObjectAssembler does not handle this case at all.
InsightAttribute.Time(id,localTime, displayValue, schema)
InsightAttribute.Time(id,localTime, schema, displayValue)
}
DefaultType.DATE_TIME -> {
val date = values.firstOrNull()?.dateValue
val zonedDateTime = date?.toInstant()?.atZone(zoneId)
val displayValue = zonedDateTime?.let { dateTimeFormatter.formatDateTimeToString(Date.from(it.toInstant())) }
InsightAttribute.DateTime(id,zonedDateTime, displayValue, schema)
InsightAttribute.DateTime(id,zonedDateTime, schema, displayValue)
}
DefaultType.EMAIL -> InsightAttribute.Email(id,values.firstOrNull()?.textValue, schema)
DefaultType.TEXTAREA -> InsightAttribute.Textarea(id,values.firstOrNull()?.textValue, schema)
Expand Down
Loading
Loading