Skip to content

Commit 0f9cb01

Browse files
authored
Feature/add icon url to issue type (#24)
* add iconUrl to JiraIssueType * fix GetIssueType Test * use jaxrs context to aquire ContextUriInfo * remove ContextUriInfo * use restApi2BaseUrl * add NotNull annotations to Jira Model * add provided to dependency
1 parent 1628e6e commit 0f9cb01

File tree

6 files changed

+68
-31
lines changed
  • kotlin-atlassian-client-core-common/src/main/kotlin/com/linkedplanet/kotlinatlassianclientcore/common/api
  • kotlin-jira-client

6 files changed

+68
-31
lines changed

kotlin-atlassian-client-core-common/src/main/kotlin/com/linkedplanet/kotlinatlassianclientcore/common/api/Page.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ package com.linkedplanet.kotlinatlassianclientcore.common.api
2121

2222
import javax.validation.constraints.NotNull
2323

24-
open class Page<T> (
24+
open class Page<T>(
2525
@field:NotNull val items: List<T>,
2626
@field:NotNull val totalItems: Int,
2727
@field:NotNull val totalPages: Int,
2828
@field:NotNull val currentPageIndex: Int,
2929
@field:NotNull val pageSize: Int
30-
) {
30+
) : List<T> by items {
3131
@Suppress("unused") // useful for inheritance by clients
3232
constructor() : this(emptyList<T>(), 0, 0, 0, 1)
3333

kotlin-jira-client/kotlin-jira-client-api/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@
2424
<artifactId>kotlin-atlassian-client-core-common</artifactId>
2525
<version>${project.version}</version>
2626
</dependency>
27+
<dependency>
28+
<groupId>javax.validation</groupId>
29+
<artifactId>validation-api</artifactId>
30+
<version>2.0.1.Final</version>
31+
<scope>provided</scope>
32+
</dependency>
2733
</dependencies>
2834
</project>

kotlin-jira-client/kotlin-jira-client-api/src/main/kotlin/com/linkedplanet/kotlinjiraclient/api/model/Model.kt

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,51 +19,58 @@
1919
*/
2020
package com.linkedplanet.kotlinjiraclient.api.model
2121

22+
import javax.validation.constraints.NotNull
23+
2224
data class JiraStatus(
23-
val id: String,
24-
val name: String,
25-
val statusCategory: String
25+
@field:NotNull val id: String,
26+
@field:NotNull val name: String,
27+
@field:NotNull val statusCategory: String
2628
)
2729

2830
data class JiraTransition(
29-
val id: String,
30-
val name: String
31+
@field:NotNull val id: String,
32+
@field:NotNull val name: String
3133
)
3234

3335
data class JiraProject(
34-
val id: String,
35-
val key: String,
36-
val name: String
36+
@field:NotNull val id: String,
37+
@field:NotNull val key: String,
38+
@field:NotNull val name: String
3739
)
3840

3941
data class JiraIssueType(
40-
val id: String,
41-
val name: String
42+
@field:NotNull val id: String,
43+
@field:NotNull val name: String,
44+
@field:NotNull val self: String,
45+
@field:NotNull val description: String,
46+
@field:NotNull val subTask: Boolean,
47+
@field:NotNull val iconUrl: String,
48+
@field:NotNull val avatarId: Long
4249
)
4350

4451
data class JiraIssueTypeAttribute(
45-
val id: String,
46-
val name: String,
47-
val schema: JiraIssueTypeAttributeSchema
52+
@field:NotNull val id: String,
53+
@field:NotNull val name: String,
54+
@field:NotNull val schema: JiraIssueTypeAttributeSchema
4855
)
4956

5057
data class JiraIssueTypeAttributeSchema(
51-
val type: String, // "date" see com.atlassian.jira.issue.fields.rest.json.JsonType
58+
@field:NotNull val type: String, // "date" see com.atlassian.jira.issue.fields.rest.json.JsonType
5259
val items: String?, // unclear what this is
5360
val system: String?, // only used if its a system field, e.g. "assignee"
5461
val custom: String?, // e.g. com.atlassian.jira.plugin.system.customfieldtypes:datepicker
5562
val customId: Long? // e.g. 10202
5663
)
5764

5865
data class JiraIssue(
59-
val id: String,
60-
val key: String,
61-
val self: String
66+
@field:NotNull val id: String,
67+
@field:NotNull val key: String,
68+
@field:NotNull val self: String
6269
)
6370

6471
data class JiraIssueComment(
65-
val id: String,
66-
val content: String,
67-
val author: String,
68-
val dateTime: String
72+
@field:NotNull val id: String,
73+
@field:NotNull val content: String,
74+
@field:NotNull val author: String,
75+
@field:NotNull val dateTime: String
6976
)

kotlin-jira-client/kotlin-jira-client-http/src/main/kotlin/com/linkedplanet/kotlinjiraclient/http/model/HttpModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ data class HttpJiraIssueType(
8383
val iconUrl: String,
8484
val name: String,
8585
val subtask: Boolean,
86-
val avatarId: Int
86+
val avatarId: Long
8787
) {
8888
fun toJiraIssueType() =
89-
JiraIssueType(id, name)
89+
JiraIssueType(id, name, self, description, subtask, iconUrl, avatarId)
9090
}
9191

9292
fun List<HttpJiraIssueType>.toJiraIssueTypes(): List<JiraIssueType> =

kotlin-jira-client/kotlin-jira-client-sdk/src/main/kotlin/com/linkedplanet/kotlinjiraclient/sdk/SdkJiraIssueTypeOperator.kt

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,25 @@ import com.atlassian.jira.bc.project.ProjectService
2424
import com.atlassian.jira.component.ComponentAccessor
2525
import com.atlassian.jira.config.IssueTypeService
2626
import com.atlassian.jira.issue.fields.rest.RestAwareField
27+
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls
2728
import com.atlassian.jira.issue.fields.screen.FieldScreenLayoutItem
2829
import com.atlassian.jira.issue.fields.screen.FieldScreenTab
2930
import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager
3031
import com.atlassian.jira.issue.issuetype.IssueType
3132
import com.atlassian.jira.issue.operation.IssueOperations
33+
import com.atlassian.jira.rest.v2.issue.IssueTypeResource
34+
import com.atlassian.jira.rest.v2.issue.ResourceUriBuilder
3235
import com.linkedplanet.kotlinjiraclient.api.error.JiraClientError
3336
import com.linkedplanet.kotlinjiraclient.api.interfaces.JiraIssueTypeOperator
3437
import com.linkedplanet.kotlinjiraclient.api.model.JiraIssueType
3538
import com.linkedplanet.kotlinjiraclient.api.model.JiraIssueTypeAttribute
3639
import com.linkedplanet.kotlinjiraclient.api.model.JiraIssueTypeAttributeSchema
3740
import com.linkedplanet.kotlinjiraclient.sdk.util.eitherAndCatch
3841
import com.linkedplanet.kotlinjiraclient.sdk.util.toEither
42+
import java.net.MalformedURLException
43+
import java.net.URL
3944
import javax.inject.Named
45+
import javax.ws.rs.core.UriBuilder
4046

4147
@Named
4248
object SdkJiraIssueTypeOperator : JiraIssueTypeOperator {
@@ -45,6 +51,7 @@ object SdkJiraIssueTypeOperator : JiraIssueTypeOperator {
4551
private val issueTypeService = ComponentAccessor.getComponent(IssueTypeService::class.java)
4652
private val issueTypeScreenSchemeManager = ComponentAccessor.getComponent(IssueTypeScreenSchemeManager::class.java)
4753
private val jiraAuthenticationContext = ComponentAccessor.getJiraAuthenticationContext()
54+
private val jiraBaseUrls: JiraBaseUrls = ComponentAccessor.getComponent(JiraBaseUrls::class.java)
4855

4956
private fun user() = jiraAuthenticationContext.loggedInUser
5057

@@ -64,6 +71,7 @@ object SdkJiraIssueTypeOperator : JiraIssueTypeOperator {
6471
screenTab.fieldScreenLayoutItems.map { layoutItem: FieldScreenLayoutItem ->
6572
val orderableField = layoutItem.orderableField
6673
val schema = (orderableField as? RestAwareField)?.jsonSchema
74+
// code inspired by AbstractMetaFieldBeanBuilder.java
6775
JiraIssueTypeAttribute(
6876
id = orderableField.id,
6977
name = orderableField.name,
@@ -88,16 +96,27 @@ object SdkJiraIssueTypeOperator : JiraIssueTypeOperator {
8896
eitherAndCatch {
8997
val issueType = issueTypeService.getIssueType(user(), issueTypeId.toString()).orNull
9098
?: return@getIssueType issueTypeNotFound(issueTypeId)
91-
issueType.let { it: IssueType ->
92-
JiraIssueType(it.id, it.name)
93-
}
99+
toJiraIssueType(issueType)
94100
}
95101

96102
override suspend fun getIssueTypes(projectId: Number): Either<JiraClientError, List<JiraIssueType>> =
97103
eitherAndCatch {
98104
projectService.getProjectById(user(), projectId.toLong()).toEither().bind().project?.issueTypes
99-
?.map { it: IssueType ->
100-
JiraIssueType(it.id, it.name)
101-
} ?: emptyList()
105+
?.map(::toJiraIssueType)
106+
?: emptyList()
102107
}
108+
109+
private fun toJiraIssueType(issueType: IssueType): JiraIssueType =
110+
issueType.run {
111+
// code inspired by IssueTypeBeanBuilder
112+
val iconAbsoluteURL = try {
113+
URL(issueType.iconUrl).toString()
114+
} catch (_: MalformedURLException) {
115+
jiraBaseUrls.baseUrl() + issueType.iconUrl
116+
}
117+
val restApiUrl = UriBuilder.fromPath(jiraBaseUrls.restApi2BaseUrl())
118+
val self = ResourceUriBuilder().build(restApiUrl, IssueTypeResource::class.java, issueType.id).toString()
119+
JiraIssueType(id, name, self, descTranslation, isSubTask, iconAbsoluteURL, avatar?.id ?: 0L)
120+
}
121+
103122
}

kotlin-jira-client/kotlin-jira-client-test-base/src/main/kotlin/com/linkedplanet/kotlinjiraclient/JiraIssueTypeOperatorTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ interface JiraIssueTypeOperatorTest<JiraFieldType> : BaseTestConfigProvider<Jira
4040
val issueType = runBlocking { issueTypeOperator.getIssueType(issueTypeId) }.orFail()
4141
assertThat(issueType.id, equalTo(issueTypeId.toString()))
4242
assertThat(issueType.name, equalTo("Story"))
43+
assertThat(issueType.subTask, equalTo(false))
44+
assertThat(issueType.description, containsString("Issue type for a user story."))
45+
assertThat(issueType.self, endsWith("rest/api/2/issuetype/10001"))
46+
assertThat(issueType.iconUrl, endsWith("images/icons/issuetypes/story.svg"))
47+
assertThat(issueType.avatarId, equalTo(0L))
4348
}
4449

4550
@Test

0 commit comments

Comments
 (0)