Skip to content

Commit 754e587

Browse files
authored
Merge pull request #39 from linked-planet/feature/target_jira_10_7_3_lts
Feature/target jira 10 7 3 lts
2 parents 869efcd + ee99772 commit 754e587

File tree

24 files changed

+203
-254
lines changed

24 files changed

+203
-254
lines changed

kotlin-http-client/kotlin-http-client-atlas/src/main/kotlin/com/linkedplanet/kotlinhttpclient/atlas/AtlasHttpClient.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ class AtlasHttpClient(private val appLink: ApplicationLink) : BaseHttpClient() {
115115
val file = tempFileWithData(filename, inputStream)
116116
val filePart = RequestFilePart(mimeType, filename, file, "file")
117117
request.setFiles(listOf(filePart))
118-
118+
request.apply {
119+
setHeader("X-Atlassian-Token", "no-check")
120+
setHeader("Connection", "keep-alive")
121+
setHeader("Cache-Control", "no-cache")
122+
}
119123
request.execute(object : ApplicationLinkResponseHandler<Either<HttpDomainError, HttpResponse<InputStream>>> {
120124
override fun credentialsRequired(response: Response) = null
121125

kotlin-http-client/kotlin-http-client-ktor/src/main/kotlin/com/linkedplanet/kotlinhttpclient/ktor/KtorHttpClient.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class KtorHttpClient(
141141
}
142142
) {
143143
url("$baseUrl$url")
144+
header("X-Atlassian-Token", "no-check")
144145
header("Connection", "keep-alive")
145146
header("Cache-Control", "no-cache")
146147
}

kotlin-insight-client/kotlin-insight-client-api/src/main/kotlin/com/linkedplanet/kotlininsightclient/api/error/InsightClientError.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ sealed class InsightClientError(
5252
) : AtlassianClientError(error, message, stacktrace, statusCode) {
5353

5454
companion object {
55-
private const val internalErrorString = "Jira/Insight hat ein internes Problem festgestellt"
55+
private const val internalErrorString = "Jira/Assets hat ein internes Problem festgestellt"
5656
fun fromException(e: Throwable): InsightClientError =
57-
ExceptionInsightClientError("Insight-Fehler", e.message ?: internalErrorString, e.stackTraceToString())
57+
ExceptionInsightClientError("Assets-Fehler", e.message ?: internalErrorString, e.stackTraceToString())
5858

5959
fun internalError(message: String): Either<InsightClientError, InsightAttribute> =
60-
InternalInsightClientError("Interner Insight-Fehler", message).asEither()
60+
InternalInsightClientError("Interner Assets-Fehler", message).asEither()
6161

6262
}
6363
}
@@ -75,16 +75,16 @@ class ObjectNotFoundError(val objectId: InsightObjectId):
7575
class ObjectTypeNotFoundError(val rootObjectTypeId: InsightObjectTypeId) :
7676
InsightClientError("Insight Objekttyp unbekannt", "Der Objekttyp mit der angegebenen InsightObjectTypeId=$rootObjectTypeId wurde nicht gefunden.")
7777

78-
class OtherNotFoundError(message: String) : InsightClientError("Nicht gefunden.", message)
78+
class OtherNotFoundError(message: String) : InsightClientError("Nicht gefunden.", message, statusCode = 404)
7979

8080
open class OtherInsightClientError(error: String, message: String) : InsightClientError(error, message)
8181

8282
/**
8383
* Somewhere inside an HTTP connection failed.
8484
*/
85-
class HttpInsightClientError(statusCode: Int, error: String, message: String) :
85+
class HttpInsightClientError(statusCode: Int, error: String = "Assets-Fehler", message: String) :
8686
InsightClientError(
8787
error = error,
88-
message = "$message StatusCode:$statusCode",
88+
message = "$message (StatusCode:$statusCode)",
8989
statusCode = statusCode
9090
)

kotlin-insight-client/kotlin-insight-client-http/src/main/kotlin/com/linkedplanet/kotlininsightclient/http/HttpInsightAttachmentOperator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ class HttpInsightAttachmentOperator(private val context: HttpInsightClientContex
102102
override suspend fun downloadAttachmentZip(objectId: InsightObjectId): Either<InsightClientError, InputStream> =
103103
either {
104104
val attachments = getAttachments(objectId).bind()
105-
val fileMap: Map<String, InputStream> = attachments.map { attachment ->
105+
val fileMap: Map<String, InputStream> = attachments.associate { attachment ->
106106
val attachmentContent = downloadAttachment(attachment.url).bind()
107107
attachment.filename to attachmentContent
108-
}.toMap()
108+
}
109109
zipInputStreamForMultipleInputStreams(fileMap).bind()
110110
}
111111

kotlin-insight-client/kotlin-insight-client-sdk/pom.xml

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,10 @@
2020
<version>${project.version}</version>
2121
</dependency>
2222

23-
<!-- Kotlin -->
24-
<dependency>
25-
<groupId>org.jetbrains.kotlinx</groupId>
26-
<artifactId>kotlinx-coroutines-core</artifactId>
27-
</dependency>
28-
2923
<!-- Atlassian -->
3024
<dependency>
3125
<groupId>com.atlassian.jira</groupId>
3226
<artifactId>jira-api</artifactId>
33-
<version>${jira.version}</version>
3427
<scope>provided</scope>
3528
</dependency>
3629
<dependency>
@@ -75,31 +68,5 @@
7568
</exclusion>
7669
</exclusions>
7770
</dependency>
78-
<dependency>
79-
<groupId>com.atlassian.servicedesk</groupId>
80-
<artifactId>insight-core-model</artifactId>
81-
<version>${insight.version}</version>
82-
<scope>provided</scope>
83-
</dependency>
84-
<dependency>
85-
<groupId>com.atlassian.servicedesk</groupId>
86-
<artifactId>insight-core-persistence</artifactId>
87-
<version>${insight.version}</version>
88-
<scope>provided</scope>
89-
</dependency>
90-
<dependency>
91-
<groupId>com.atlassian.plugin</groupId>
92-
<artifactId>atlassian-spring-scanner-annotation</artifactId>
93-
<version>${atlassian.spring.scanner.version}</version>
94-
<scope>provided</scope>
95-
</dependency>
96-
97-
<!-- Others -->
98-
<dependency>
99-
<groupId>javax.inject</groupId>
100-
<artifactId>javax.inject</artifactId>
101-
<version>1</version>
102-
<scope>provided</scope>
103-
</dependency>
10471
</dependencies>
10572
</project>

kotlin-insight-client/kotlin-insight-client-sdk/src/main/kotlin/com/linkedplanet/kotlininsightclient/sdk/SdkInsightAttachmentOperator.kt

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,25 @@ package com.linkedplanet.kotlininsightclient.sdk
2121

2222
import arrow.core.Either
2323
import arrow.core.raise.either
24+
import com.atlassian.jira.security.JiraAuthenticationContext
25+
import com.atlassian.sal.api.net.Request
26+
import com.atlassian.sal.api.net.Response
27+
import com.atlassian.sal.api.net.TrustedRequest
28+
import com.atlassian.sal.api.net.TrustedRequestFactory
29+
import com.linkedplanet.kotlininsightclient.api.error.HttpInsightClientError
2430
import com.linkedplanet.kotlininsightclient.api.error.InsightClientError
25-
import com.linkedplanet.kotlininsightclient.api.error.OtherNotFoundError
2631
import com.linkedplanet.kotlininsightclient.api.interfaces.InsightAttachmentOperator
2732
import com.linkedplanet.kotlininsightclient.api.model.AttachmentId
2833
import com.linkedplanet.kotlininsightclient.api.model.InsightAttachment
2934
import com.linkedplanet.kotlininsightclient.api.model.InsightObjectId
3035
import com.linkedplanet.kotlininsightclient.sdk.services.ReverseEngineeredAttachmentUrlResolver
31-
import com.linkedplanet.kotlininsightclient.sdk.services.ReverseEngineeredFileManager
3236
import com.linkedplanet.kotlininsightclient.sdk.util.catchAsInsightClientError
37+
import com.linkedplanet.kotlininsightclient.sdk.util.getComponent
3338
import com.linkedplanet.kotlininsightclient.sdk.util.getOSGiComponent
3439
import com.linkedplanet.kotlininsightclient.sdk.util.toISOString
3540
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
3641
import com.riadalabs.jira.plugins.insight.services.model.AttachmentBean
42+
import org.apache.http.client.utils.URIBuilder
3743
import java.io.InputStream
3844
import java.io.PipedInputStream
3945
import java.io.PipedOutputStream
@@ -47,13 +53,12 @@ import java.util.zip.ZipEntry
4753
import java.util.zip.ZipOutputStream
4854
import kotlin.io.path.createTempFile
4955

50-
5156
object SdkInsightAttachmentOperator : InsightAttachmentOperator {
5257

5358
private val objectFacade: ObjectFacade by getOSGiComponent()
54-
55-
private val fileManager = ReverseEngineeredFileManager()
59+
private val jiraAuthenticationContext: JiraAuthenticationContext by getComponent()
5660
private val attachmentUrlResolver = ReverseEngineeredAttachmentUrlResolver()
61+
private val trustedRequestFactory: TrustedRequestFactory<*> by getOSGiComponent()
5762

5863
override suspend fun getAttachments(objectId: InsightObjectId): Either<InsightClientError, List<InsightAttachment>> =
5964
catchAsInsightClientError {
@@ -63,27 +68,44 @@ object SdkInsightAttachmentOperator : InsightAttachmentOperator {
6368
}
6469

6570
override suspend fun downloadAttachment(url: String): Either<InsightClientError, InputStream> =
66-
catchAsInsightClientError {
67-
val attachmentId = attachmentUrlResolver.parseAttachmentIdFromPathInformation(url)
68-
val attachmentBean = objectFacade.loadAttachmentBeanById(attachmentId)
69-
fileManager.getObjectAttachmentContent(attachmentBean.objectId, attachmentBean.nameInFileSystem)
70-
}.mapLeft { OtherNotFoundError("Attachment download failed for url:$url") }
71+
either {
72+
val request = trustedGetRequestForCurrentUser(url).bind()
73+
val response = Either.catch { request.executeAndReturn<Response> { it } as Response }
74+
.mapLeft { downloadFailed(500, url) }.bind()
75+
if (!response.isSuccessful) {
76+
raise(downloadFailed(response.statusCode, url))
77+
}
78+
response.responseBodyAsStream
79+
}
80+
81+
private fun downloadFailed(statusCode: Int, url: String, ) = HttpInsightClientError(
82+
statusCode = statusCode,
83+
message = "Anhang Download fehlgeschlagen für URL: $url"
84+
)
85+
86+
private fun trustedGetRequestForCurrentUser(url: String): Either<InsightClientError, TrustedRequest> =
87+
Either.catch {
88+
trustedRequestFactory.createTrustedRequest(Request.MethodType.GET, url).apply {
89+
addTrustedTokenAuthentication(URIBuilder(url).host, jiraAuthenticationContext.loggedInUser.username)
90+
setHeader("Content-Type", "application/json")
91+
}
92+
}.mapLeft {
93+
HttpInsightClientError(
94+
statusCode = 500,
95+
message = "Es konnte keine Verbindung zu Assets erzeugt werden."
96+
)
97+
}
7198

7299
override suspend fun downloadAttachmentZip(objectId: InsightObjectId): Either<InsightClientError, InputStream> =
73100
either {
74-
val fileMap = allAttachmentStreamsForInsightObject(objectId).bind()
101+
val attachments = getAttachments(objectId).bind()
102+
val fileMap: Map<String, InputStream> = attachments.associate { attachment ->
103+
val attachmentContent = downloadAttachment(attachment.url).bind()
104+
attachment.filename to attachmentContent
105+
}
75106
zipInputStreamForMultipleInputStreams(fileMap).bind()
76107
}
77108

78-
private fun allAttachmentStreamsForInsightObject(objectId: InsightObjectId) =
79-
catchAsInsightClientError {
80-
val attachmentBeans = objectFacade.findAttachmentBeans(objectId.raw)
81-
attachmentBeans.map { bean ->
82-
val attachmentContent = fileManager.getObjectAttachmentContent(bean.objectId, bean.nameInFileSystem)
83-
bean.filename to attachmentContent
84-
}.toMap()
85-
}
86-
87109
private fun zipInputStreamForMultipleInputStreams(
88110
fileMap: Map<String, InputStream>
89111
): Either<InsightClientError, InputStream> =
@@ -112,8 +134,7 @@ object SdkInsightAttachmentOperator : InsightAttachmentOperator {
112134
Files.copy(inputStream, tempFilePath, StandardCopyOption.REPLACE_EXISTING)
113135
val mimeType = URLConnection.guessContentTypeFromName(filename)
114136
val bean = objectFacade.addAttachmentBean(objectId.raw, tempFilePath.toFile(), filename, mimeType, null)
115-
val insightAttachment = beanToInsightAttachment(bean)
116-
insightAttachment
137+
beanToInsightAttachment(bean)
117138
}
118139

119140
override suspend fun deleteAttachment(attachmentId: AttachmentId): Either<InsightClientError, Unit> =

kotlin-insight-client/kotlin-insight-client-sdk/src/main/kotlin/com/linkedplanet/kotlininsightclient/sdk/services/ReverseEngineeredFileManager.kt

Lines changed: 0 additions & 75 deletions
This file was deleted.

kotlin-insight-client/kotlin-insight-client-test-base/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
<!-- <version>defined by the platform dependency management </version> -->
3939
<scope>provided</scope>
4040
</dependency>
41+
<dependency>
42+
<groupId>org.slf4j</groupId>
43+
<artifactId>slf4j-api</artifactId>
44+
<scope>provided</scope>
45+
</dependency>
4146

4247
</dependencies>
4348

kotlin-insight-client/kotlin-insight-client-test-base/src/main/kotlin/com/linkedplanet/kotlininsightclient/AuthenticatedJiraHttpClientFactory.kt

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@
2020
package com.linkedplanet.kotlininsightclient
2121

2222
import arrow.core.Either
23-
import arrow.core.left
2423
import arrow.core.right
2524
import com.google.gson.Gson
26-
import com.linkedplanet.kotlininsightclient.api.error.AuthenticationError
2725
import com.linkedplanet.kotlininsightclient.api.error.InsightClientError
26+
import org.slf4j.LoggerFactory
2827
import org.http4k.client.Java8HttpClient
2928
import org.http4k.core.Body
3029
import org.http4k.core.HttpHandler
@@ -36,6 +35,7 @@ import org.http4k.core.then
3635
import org.http4k.filter.ClientFilters
3736
import org.http4k.filter.cookie.BasicCookieStorage
3837
import org.http4k.filter.cookie.CookieStorage
38+
import java.util.*
3939

4040
/**
4141
* Provides access to Jira itself via a logged in AuthenticatedHttpHandler
@@ -46,31 +46,35 @@ class AuthenticatedJiraHttpClientFactory(
4646
companion object {
4747
data class Credentials(val username: String, val password: String)
4848
}
49+
private val log = LoggerFactory.getLogger(this::class.java)
4950

5051
private val storage: CookieStorage = BasicCookieStorage() // this is just a HashMap
5152
private val httpHandler: HttpHandler = ClientFilters.Cookies(storage = storage).then(Java8HttpClient())
5253
private val gson = Gson()
5354

54-
fun login(credentials: Credentials) : Either<InsightClientError, AuthenticatedHttpHandler> {
55+
fun login(credentials: Credentials): Either<InsightClientError, AuthenticatedHttpHandler> {
56+
val username = credentials.username
57+
val password = credentials.password
5558
val body = gson.toJson(credentials)
5659
val request = Request(Method.POST, "$jiraOrigin/rest/auth/1/session")
5760
.header("content-type", "application/json")
5861
.body(Body(body))
59-
6062
val loginResponse = httpHandler(request)
6163
if (loginResponse.status != Status.OK) {
62-
return AuthenticationError(
63-
"Login failed with HTTP StatusCode:${loginResponse.status.code}"
64-
).left()
65-
} else {
66-
val privateHandler = object : AuthenticatedHttpHandler, HttpHandler by httpHandler {
67-
override fun getWithRelativePath(path: String): Response {
68-
val absolutePath = "$jiraOrigin$path"
69-
return this(Request(Method.GET, absolutePath))
70-
}
64+
log.debug("Continue despite 'session' login failing with HTTP StatusCode:${loginResponse.status.code}")
65+
}
66+
val privateHandler = object : AuthenticatedHttpHandler, HttpHandler by httpHandler {
67+
override fun getWithRelativePath(path: String): Response {
68+
val absolutePath = "$jiraOrigin$path"
69+
val getRequest = Request(Method.GET, absolutePath)
70+
.header(
71+
"Authorization",
72+
"Basic ${Base64.getEncoder().encodeToString("$username:$password".toByteArray())}"
73+
)
74+
return this(getRequest)
7175
}
72-
return privateHandler.right()
7376
}
77+
return privateHandler.right()
7478
}
7579
}
7680

0 commit comments

Comments
 (0)