From 06e38f61ecacd8a52af787c09ee023e12ac7e10a Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Tue, 17 Dec 2024 14:45:30 +0100 Subject: [PATCH 1/3] fix: enabledFeatures on self-hosted instances & Sentry false positives --- .../hateoas/ee/SelfHostedEePlanModel.kt | 25 ++++++++++- .../component/SentryBeforeSendCallback.kt | 1 + .../kotlin/io/tolgee/constants/Feature.kt | 8 ++++ .../tolgee/service/security/ApiKeyService.kt | 7 +++- .../ee/unit/SelfHostedEePlanModelTest.kt | 41 +++++++++++++++++++ 5 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt index 2545eaee2e..9df5686a8d 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt @@ -1,5 +1,8 @@ package io.tolgee.hateoas.ee +import com.fasterxml.jackson.annotation.JsonGetter +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter import io.tolgee.constants.Feature import org.springframework.hateoas.RepresentationModel import org.springframework.hateoas.server.core.Relation @@ -10,10 +13,28 @@ open class SelfHostedEePlanModel( val id: Long = 0, var name: String = "", val public: Boolean = true, - val enabledFeatures: Array = arrayOf(), + @JsonIgnore + var enabledFeatures: Array = arrayOf(), val prices: PlanPricesModel, val includedUsage: PlanIncludedUsageModel = PlanIncludedUsageModel(), val hasYearlyPrice: Boolean = false, val free: Boolean, val nonCommercial: Boolean, -) : RepresentationModel() +) : RepresentationModel() { + + /** + * We need to provide this setter so unrecognized features are ignored in situation + * that self-hosted instance is not upgraded to version containing the new features introduced + * in Tolgee cloud. + */ + @JsonSetter("enabledFeatures") + fun setJsonEnabledFeatures(features: Set) { + this.enabledFeatures = features.mapNotNull { Feature.findByName(it) }.toTypedArray() + } + + + @JsonGetter("enabledFeatures") + fun getJsonEnabledFeatures(): Array { + return this.enabledFeatures + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/component/SentryBeforeSendCallback.kt b/backend/data/src/main/kotlin/io/tolgee/component/SentryBeforeSendCallback.kt index c1ca10d58e..910a8f76b5 100644 --- a/backend/data/src/main/kotlin/io/tolgee/component/SentryBeforeSendCallback.kt +++ b/backend/data/src/main/kotlin/io/tolgee/component/SentryBeforeSendCallback.kt @@ -18,6 +18,7 @@ class SentryBeforeSendCallback : SentryOptions.BeforeSendCallback { listOf( "FailedDontRequeueException", "ClientAbortException", + "AsyncRequestNotUsableException", ) } diff --git a/backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt b/backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt index 5d142193c4..948729d617 100644 --- a/backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt +++ b/backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt @@ -21,4 +21,12 @@ enum class Feature { TASKS, SSO, ORDER_TRANSLATION, + + ; + + companion object { + fun findByName(name: String): Feature? { + return entries.find { it.name == name } + } + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt index 93e5a4038e..7a3d8da29c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt @@ -1,6 +1,7 @@ package io.tolgee.service.security import com.google.common.io.BaseEncoding +import io.sentry.Breadcrumb import io.sentry.Sentry import io.tolgee.component.CurrentDateProvider import io.tolgee.component.KeyGenerator @@ -243,11 +244,13 @@ class ApiKeyService( } private fun logTransactionIsolation() { - if (logger.isDebugEnabled) { val isolationLevel = entityManager.createNativeQuery("show transaction_isolation") .singleResult as String - logger.debug("Transaction isolation level: $isolationLevel") + val message = "Transaction isolation level: $isolationLevel" + if (logger.isDebugEnabled) { + Sentry.addBreadcrumb(message) + logger.debug(message) } } diff --git a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt new file mode 100644 index 0000000000..9e52863740 --- /dev/null +++ b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt @@ -0,0 +1,41 @@ +package io.tolgee.ee.unit + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import io.tolgee.constants.Feature +import io.tolgee.hateoas.ee.PlanPricesModel +import io.tolgee.hateoas.ee.SelfHostedEePlanModel +import io.tolgee.testing.assert +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class SelfHostedEePlanModelTest { + @Autowired + private lateinit var objectMapper: ObjectMapper + + @Test + fun `parses plan response with unknown features`() { + + val parsed = objectMapper.readValue( + """ + { + "enabledFeatures": ["I've made this up", "ASSISTED_UPDATES"], + "prices": $pricesJson, + "free": false, + "nonCommercial": false + } + """.trimIndent() + ) + + parsed.enabledFeatures.toList().assert.containsExactly(Feature.ASSISTED_UPDATES) + } + + val pricesJson: String + get() { + return objectMapper.writeValueAsString(PlanPricesModel()) + } + +} From d218969d24cfd9c2f1941d6b7cf79920c453c663 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Wed, 18 Dec 2024 09:34:04 +0100 Subject: [PATCH 2/3] fix: enabledFeatures on self-hosted instances & Sentry false positives --- .../hateoas/ee/SelfHostedEePlanModel.kt | 2 -- .../tolgee/service/security/ApiKeyService.kt | 7 +++--- .../ee/unit/SelfHostedEePlanModelTest.kt | 24 +++++++++---------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt index 9df5686a8d..894f538fd8 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SelfHostedEePlanModel.kt @@ -21,7 +21,6 @@ open class SelfHostedEePlanModel( val free: Boolean, val nonCommercial: Boolean, ) : RepresentationModel() { - /** * We need to provide this setter so unrecognized features are ignored in situation * that self-hosted instance is not upgraded to version containing the new features introduced @@ -32,7 +31,6 @@ open class SelfHostedEePlanModel( this.enabledFeatures = features.mapNotNull { Feature.findByName(it) }.toTypedArray() } - @JsonGetter("enabledFeatures") fun getJsonEnabledFeatures(): Array { return this.enabledFeatures diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt index 7a3d8da29c..9cf0741146 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt @@ -1,7 +1,6 @@ package io.tolgee.service.security import com.google.common.io.BaseEncoding -import io.sentry.Breadcrumb import io.sentry.Sentry import io.tolgee.component.CurrentDateProvider import io.tolgee.component.KeyGenerator @@ -244,9 +243,9 @@ class ApiKeyService( } private fun logTransactionIsolation() { - val isolationLevel = - entityManager.createNativeQuery("show transaction_isolation") - .singleResult as String + val isolationLevel = + entityManager.createNativeQuery("show transaction_isolation") + .singleResult as String val message = "Transaction isolation level: $isolationLevel" if (logger.isDebugEnabled) { Sentry.addBreadcrumb(message) diff --git a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt index 9e52863740..0677eded37 100644 --- a/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt +++ b/ee/backend/tests/src/test/kotlin/io/tolgee/ee/unit/SelfHostedEePlanModelTest.kt @@ -1,7 +1,6 @@ package io.tolgee.ee.unit import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import io.tolgee.constants.Feature import io.tolgee.hateoas.ee.PlanPricesModel @@ -18,17 +17,17 @@ class SelfHostedEePlanModelTest { @Test fun `parses plan response with unknown features`() { - - val parsed = objectMapper.readValue( - """ - { - "enabledFeatures": ["I've made this up", "ASSISTED_UPDATES"], - "prices": $pricesJson, - "free": false, - "nonCommercial": false - } - """.trimIndent() - ) + val parsed = + objectMapper.readValue( + """ + { + "enabledFeatures": ["I've made this up", "ASSISTED_UPDATES"], + "prices": $pricesJson, + "free": false, + "nonCommercial": false + } + """.trimIndent(), + ) parsed.enabledFeatures.toList().assert.containsExactly(Feature.ASSISTED_UPDATES) } @@ -37,5 +36,4 @@ class SelfHostedEePlanModelTest { get() { return objectMapper.writeValueAsString(PlanPricesModel()) } - } From a8049db901bc495465da3fa78cb8050bf697c1dd Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Wed, 18 Dec 2024 09:46:33 +0000 Subject: [PATCH 3/3] fix: enabledFeatures on self-hosted instances & Sentry false positives --- .../src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt index 9cf0741146..39a2645585 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/ApiKeyService.kt @@ -247,8 +247,8 @@ class ApiKeyService( entityManager.createNativeQuery("show transaction_isolation") .singleResult as String val message = "Transaction isolation level: $isolationLevel" + Sentry.addBreadcrumb(message) if (logger.isDebugEnabled) { - Sentry.addBreadcrumb(message) logger.debug(message) } }