1919 */
2020package com.linkedplanet.kotlinjiraclient.sdk
2121
22- import arrow.core.*
22+ import arrow.core.Either
23+ import arrow.core.left
2324import arrow.core.raise.either
25+ import arrow.core.right
26+ import com.atlassian.jira.bc.ServiceResult
2427import com.atlassian.jira.bc.issue.search.SearchService
2528import com.atlassian.jira.component.ComponentAccessor
2629import com.atlassian.jira.event.type.EventDispatchOption
2730import com.atlassian.jira.issue.Issue
31+ import com.atlassian.jira.issue.IssueInputParameters
2832import com.atlassian.jira.issue.MutableIssue
2933import com.atlassian.jira.jql.parser.JqlQueryParser
34+ import com.atlassian.jira.user.ApplicationUser
35+ import com.atlassian.jira.util.ErrorCollection
36+ import com.atlassian.jira.util.ErrorCollection.Reason
37+ import com.atlassian.jira.util.ErrorCollections
38+ import com.atlassian.jira.web.bean.I18nBean
3039import com.atlassian.jira.web.bean.PagerFilter
3140import com.google.gson.JsonObject
41+ import com.linkedplanet.kotlinatlassianclientcore.common.api.Page
42+ import com.linkedplanet.kotlinatlassianclientcore.common.error.asEither
3243import com.linkedplanet.kotlinjiraclient.api.error.JiraClientError
3344import com.linkedplanet.kotlinjiraclient.api.interfaces.JiraIssueOperator
3445import com.linkedplanet.kotlinjiraclient.api.model.JiraIssue
35- import com.linkedplanet.kotlinatlassianclientcore.common.api.Page
36- import com.linkedplanet.kotlinatlassianclientcore.common.error.asEither
3746import com.linkedplanet.kotlinjiraclient.sdk.field.SdkJiraField
3847import com.linkedplanet.kotlinjiraclient.sdk.util.IssueJsonConverter
3948import com.linkedplanet.kotlinjiraclient.sdk.util.catchJiraClientError
@@ -44,8 +53,7 @@ import kotlin.math.ceil
4453object SdkJiraIssueOperator : JiraIssueOperator<SdkJiraField> {
4554 override var RESULTS_PER_PAGE : Int = 10
4655
47- private val issueManager by lazy { ComponentAccessor .getIssueManager() }
48- private val issueFactory by lazy { ComponentAccessor .getIssueFactory() }
56+ private val issueService by lazy { ComponentAccessor .getIssueService() }
4957 private val customFieldManager by lazy { ComponentAccessor .getCustomFieldManager() }
5058 private val searchService: SearchService by lazy { ComponentAccessor .getComponent(SearchService ::class .java) }
5159 private val jiraAuthenticationContext by lazy { ComponentAccessor .getJiraAuthenticationContext() }
@@ -60,43 +68,79 @@ object SdkJiraIssueOperator : JiraIssueOperator<SdkJiraField> {
6068 projectId : Long ,
6169 issueTypeId : Int ,
6270 fields : List <SdkJiraField >
63- ): Either <JiraClientError , JiraIssue ?> = Either .catchJiraClientError {
64- val freshIssue: MutableIssue = issueFactory.issue
65- freshIssue.projectId = projectId
66- freshIssue.issueTypeId = issueTypeId.toString()
67- fields.forEach { field ->
68- field.render(freshIssue)
69- }
70- val createdIssue: Issue = issueManager.createIssueObject(user(), freshIssue)
71+ ): Either <JiraClientError , JiraIssue ?> = either {
72+ Either .catchJiraClientError {
73+ val inputParameters = issueInputParameters(projectId, issueTypeId, fields)
74+ val validateCreate = issueService.validateCreate(user(), inputParameters).toEither().bind()
75+ val createResult = issueService.create(user(), validateCreate).toEither().bind()
76+ toBasicReturnTypeIssue(createResult.issue)
77+ }.bind()
78+ }
79+
80+ private fun toBasicReturnTypeIssue (createdIssue : MutableIssue ): JiraIssue {
7181 val basePath = applicationProperties.jiraBaseUrl
7282 val contextPath = webResourceUrlProvider.baseUrl
7383 val fullPath = if (contextPath.isNotEmpty()) " $basePath /$contextPath " else basePath
7484 val selfLink = fullPath + " /rest/api/2/issue/" + createdIssue.id
75- JiraIssue (createdIssue.id.toString(), createdIssue.key, selfLink)
85+ return JiraIssue (createdIssue.id.toString(), createdIssue.key, selfLink)
7686 }
7787
7888 override suspend fun updateIssue (
7989 projectId : Long ,
8090 issueTypeId : Int ,
8191 issueKey : String ,
8292 fields : List <SdkJiraField >
83- ): Either <JiraClientError , Unit > = Either .catchJiraClientError {
84- val issue = issueManager.getIssueByCurrentKey(issueKey)
85- issue.projectId = projectId
86- issue.issueTypeId = issueTypeId.toString()
93+ ): Either <JiraClientError , Unit > = either {
94+ Either .catchJiraClientError {
95+ val issueId = issueService.getIssue(user(), issueKey).toEither().bind().issue.id
96+ val inputParameters = issueInputParameters(projectId, issueTypeId, fields)
97+ val validationResult = issueService.validateUpdate(user(), issueId, inputParameters).toEither().bind()
98+ issueService.update(user(), validationResult, EventDispatchOption .ISSUE_UPDATED , false ).toEither().bind()
99+ }.bind()
100+ }
101+
102+ private fun issueInputParameters (
103+ projectId : Long ,
104+ issueTypeId : Int ,
105+ fields : List <SdkJiraField >
106+ ): IssueInputParameters ? {
107+ val issueInput = issueService.newIssueInputParameters()
108+ issueInput.projectId = projectId
109+ issueInput.issueTypeId = issueTypeId.toString()
87110 fields.forEach { field ->
88- field.render(issue )
111+ field.render(issueInput )
89112 }
90- issueManager.updateIssue(user(), issue, EventDispatchOption . ISSUE_UPDATED , false )
113+ return issueInput
91114 }
92115
93- override suspend fun deleteIssue (issueKey : String ): Either <JiraClientError , Unit > =
116+ override suspend fun deleteIssue (issueKey : String ): Either <JiraClientError , Unit > = either {
94117 Either .catchJiraClientError {
95- val issue: Issue = issueManager.getIssueByCurrentKey(issueKey)
96- val sendMail = false
97- issueManager.deleteIssue(user(), issue, EventDispatchOption .ISSUE_DELETED , sendMail)
118+ val issueToDelete = issueService.getIssue(user(), issueKey).toEither().bind()
119+ val validateDelete = issueService.validateDelete(user(), issueToDelete.issue.id).toEither().bind()
120+ issueService.delete(user(), validateDelete, EventDispatchOption .ISSUE_DELETED , false ).toEither().bind()
121+ }.bind()
122+ }
123+
124+ private fun <T : ServiceResult > T.toEither () : Either <JiraClientError , T > =
125+ when {
126+ this .isValid -> Either .Right (this )
127+ else -> Either .Left (jiraClientError(this .errorCollection))
98128 }
99129
130+ private fun ErrorCollection.toEither () : Either <JiraClientError , Unit > =
131+ when {
132+ this .hasAnyErrors() -> jiraClientError(this ).left()
133+ else -> Unit .right()
134+ }
135+
136+ private fun jiraClientError (errorCollection : ErrorCollection ): JiraClientError {
137+ val worstReason = Reason .getWorstReason(errorCollection.reasons)
138+ return JiraClientError (
139+ " DeleteFailed" ,
140+ errorCollection.errorMessages.joinToString() + " (${worstReason.httpStatusCode} )"
141+ )
142+ }
143+
100144 override suspend fun <T > getIssueById (
101145 id : Int ,
102146 parser : suspend (JsonObject , Map <String , String >) -> Either <JiraClientError , T >
@@ -133,11 +177,16 @@ object SdkJiraIssueOperator : JiraIssueOperator<SdkJiraField> {
133177 override suspend fun <T > getIssueByKey (
134178 key : String ,
135179 parser : suspend (JsonObject , Map <String , String >) -> Either <JiraClientError , T >
136- ): Either <JiraClientError , T ?> = Either .catchJiraClientError {
137- val issue = issueManager.getIssueByCurrentKey(key)
138- ? : return @catchJiraClientError null
139-
140- return issueToConcreteType(issue, parser)
180+ ): Either <JiraClientError , T ?> = either {
181+ Either .catchJiraClientError {
182+ val issueResult = issueService.getIssue(user(), key)
183+ if (Reason .getWorstReason(issueResult.errorCollection.reasons) == Reason .NOT_FOUND ){
184+ return @catchJiraClientError null
185+ }
186+ val issue = issueResult.toEither().bind().issue
187+ ? : return @catchJiraClientError null
188+ issueToConcreteType(issue, parser).bind()
189+ }.bind()
141190 }
142191
143192 override suspend fun <T > getIssuesByJQL (
@@ -170,16 +219,30 @@ object SdkJiraIssueOperator : JiraIssueOperator<SdkJiraField> {
170219 pagerFilter : PagerFilter <* >? ,
171220 parser : suspend (JsonObject , Map <String , String >) -> Either <JiraClientError , T >
172221 ): Either <JiraClientError , Page <T >> = either {
222+ val user = userOrError().bind()
173223 val query = jqlParser.parseQuery(jql)
174- val search = searchService.search(user() , query, pagerFilter)
224+ val search = searchService.search(user, query, pagerFilter)
175225 val issues = search.results
176226 .map { issue -> issueToConcreteType(issue, parser) }
177- .sequenceEither()
178- .bind()
227+ .bindAll()
179228 val totalItems = search.total
180229 val pageSize = pagerFilter?.pageSize ? : 0
181230 val totalPages = ceil(totalItems.toDouble() / pageSize.toDouble()).toInt()
182231 val currentPageIndex = pagerFilter?.start?.let { start -> start / pageSize } ? : 0
183232 Page (issues, totalItems, totalPages, currentPageIndex, pageSize)
184233 }
234+
235+ private fun userOrError () : Either <JiraClientError , ApplicationUser > = either {
236+ val applicationUser = user()
237+ return applicationUser?.right()
238+ ? : jiraClientError(
239+ ErrorCollections
240+ .create(
241+ I18nBean (I18nBean .getLocaleFromUser(applicationUser))
242+ .getText(" admin.errors.issues.no.permission.to.see" ),
243+ Reason .NOT_LOGGED_IN
244+ )
245+ ).left()
246+ }
247+
185248}
0 commit comments