Skip to content

Commit 7f3af23

Browse files
committed
feat: implement global variables
1 parent 5b10964 commit 7f3af23

File tree

5 files changed

+183
-2
lines changed

5 files changed

+183
-2
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Copyright (C) 2025 Tolgee s.r.o. and contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.tolgee.email
18+
19+
import io.tolgee.component.publicBillingConfProvider.PublicBillingConfProvider
20+
import io.tolgee.configuration.tolgee.TolgeeProperties
21+
import org.springframework.stereotype.Component
22+
import java.net.URI
23+
import java.net.URISyntaxException
24+
25+
@Component
26+
class EmailGlobalVariablesProvider(
27+
// Used to identify whether we're Tolgee Cloud or not
28+
private val billingConfigProvider: PublicBillingConfProvider,
29+
private val tolgeeProperties: TolgeeProperties,
30+
) {
31+
operator fun invoke(): Map<String, Any?> {
32+
val isCloud = billingConfigProvider().enabled
33+
34+
return mapOf(
35+
"isCloud" to isCloud,
36+
"instanceQualifier" to if (isCloud) tolgeeProperties.appName else tolgeeProperties.frontEndUrl.intoQualifier(),
37+
"instanceUrl" to tolgeeProperties.frontEndUrl,
38+
)
39+
}
40+
41+
private fun String?.intoQualifier(): String {
42+
return this?.let {
43+
try {
44+
return@let URI(it).host
45+
} catch (_: URISyntaxException) {
46+
return@let null
47+
}
48+
} ?: SELF_HOSTED_DEFAULT_QUALIFIER
49+
}
50+
51+
companion object {
52+
// Not ideal because not translated... But shouldn't show up on properly configured instances :)
53+
const val SELF_HOSTED_DEFAULT_QUALIFIER = "a self-hosted instance"
54+
}
55+
}

backend/data/src/main/kotlin/io/tolgee/email/EmailMessageSource.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/**
2+
* Copyright (C) 2025 Tolgee s.r.o. and contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
117
package io.tolgee.email
218

319
import com.transferwise.icu.ICUMessageSource

backend/data/src/main/kotlin/io/tolgee/email/EmailService.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import java.util.*
3131
class EmailService(
3232
private val smtpProperties: SmtpProperties,
3333
private val mailSender: JavaMailSender,
34+
private val emailGlobalVariablesProvider: EmailGlobalVariablesProvider,
3435
@Qualifier("emailTemplateEngine") private val templateEngine: TemplateEngine,
3536
) {
3637
private val smtpFrom
@@ -50,13 +51,13 @@ class EmailService(
5051
attachments: List<EmailAttachment> = listOf(),
5152
) {
5253
val context = Context(locale, properties)
54+
val globalVariables = emailGlobalVariablesProvider()
55+
context.setVariables(globalVariables)
5356

5457
// Do two passes, so Thymeleaf expressions rendered by messages can get processed
5558
context.setVariable("isSecondPass", false)
5659
val firstPass = templateEngine.process(template, context)
5760

58-
println(firstPass)
59-
6061
context.setVariable("isSecondPass", true)
6162
val html = templateEngine.process(firstPass, context)
6263

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Copyright (C) 2025 Tolgee s.r.o. and contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.tolgee.email
18+
19+
import io.tolgee.component.publicBillingConfProvider.PublicBillingConfProvider
20+
import io.tolgee.configuration.tolgee.TolgeeProperties
21+
import io.tolgee.dtos.response.PublicBillingConfigurationDTO
22+
import io.tolgee.email.EmailGlobalVariablesProvider.Companion.SELF_HOSTED_DEFAULT_QUALIFIER
23+
import io.tolgee.testing.assert
24+
import org.junit.jupiter.api.Test
25+
import org.junit.jupiter.api.extension.ExtendWith
26+
import org.mockito.kotlin.whenever
27+
import org.springframework.beans.factory.annotation.Autowired
28+
import org.springframework.boot.test.mock.mockito.MockBean
29+
import org.springframework.context.annotation.Import
30+
import org.springframework.stereotype.Component
31+
import org.springframework.test.context.junit.jupiter.SpringExtension
32+
33+
@Component
34+
@ExtendWith(SpringExtension::class)
35+
@Import(EmailGlobalVariablesProvider::class)
36+
class EmailGlobalVariablesProviderTest {
37+
@MockBean
38+
private lateinit var publicBillingConfProvider: PublicBillingConfProvider
39+
40+
@MockBean
41+
private lateinit var tolgeeProperties: TolgeeProperties
42+
43+
@Autowired
44+
private lateinit var emailGlobalVariablesProvider: EmailGlobalVariablesProvider
45+
46+
@Test
47+
fun `it returns the correct properties based on config in cloud`() {
48+
whenever(publicBillingConfProvider.invoke()).thenReturn(PublicBillingConfigurationDTO(true))
49+
whenever(tolgeeProperties.appName).thenReturn("Tolgee Test Edition")
50+
whenever(tolgeeProperties.frontEndUrl).thenReturn("https://tolgee.test")
51+
52+
emailGlobalVariablesProvider().assert
53+
.containsEntry("isCloud", true)
54+
.containsEntry("instanceQualifier", "Tolgee Test Edition")
55+
.containsEntry("instanceUrl", "https://tolgee.test")
56+
.hasSize(3)
57+
}
58+
59+
@Test
60+
fun `it returns the correct properties based on config in self-hosted`() {
61+
whenever(publicBillingConfProvider.invoke()).thenReturn(PublicBillingConfigurationDTO(false))
62+
whenever(tolgeeProperties.appName).thenReturn("Tolgee Test Edition")
63+
whenever(tolgeeProperties.frontEndUrl).thenReturn("https://tolgee.test")
64+
65+
emailGlobalVariablesProvider().assert
66+
.containsEntry("isCloud", false)
67+
.containsEntry("instanceQualifier", "tolgee.test")
68+
.containsEntry("instanceUrl", "https://tolgee.test")
69+
.hasSize(3)
70+
}
71+
72+
@Test
73+
fun `it gracefully handles bad frontend url configuration`() {
74+
whenever(publicBillingConfProvider.invoke()).thenReturn(PublicBillingConfigurationDTO(false))
75+
whenever(tolgeeProperties.appName).thenReturn("Tolgee Test Edition")
76+
whenever(tolgeeProperties.frontEndUrl).thenReturn("https:/tolgee.test")
77+
78+
emailGlobalVariablesProvider().assert
79+
.containsEntry("isCloud", false)
80+
.containsEntry("instanceQualifier", SELF_HOSTED_DEFAULT_QUALIFIER)
81+
.containsEntry("instanceUrl", "https:/tolgee.test")
82+
.hasSize(3)
83+
}
84+
85+
@Test
86+
fun `it gracefully handles missing frontend url configuration`() {
87+
// That's a pathological situation to be in... but it can happen... :shrug:
88+
whenever(publicBillingConfProvider.invoke()).thenReturn(PublicBillingConfigurationDTO(false))
89+
whenever(tolgeeProperties.appName).thenReturn("Tolgee Test Edition")
90+
whenever(tolgeeProperties.frontEndUrl).thenReturn(null)
91+
92+
emailGlobalVariablesProvider().assert
93+
.containsEntry("isCloud", false)
94+
.containsEntry("instanceQualifier", SELF_HOSTED_DEFAULT_QUALIFIER)
95+
.containsEntry("instanceUrl", null)
96+
.hasSize(3)
97+
}
98+
}

backend/data/src/test/kotlin/io/tolgee/email/EmailServiceTest.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class EmailServiceTest {
4747
@MockBean
4848
private lateinit var mailSender: JavaMailSender
4949

50+
@MockBean
51+
private lateinit var emailGlobalVariablesProvider: EmailGlobalVariablesProvider
52+
5053
@Autowired
5154
private lateinit var emailService: EmailService
5255

@@ -61,6 +64,14 @@ class EmailServiceTest {
6164
val msg = sender.createMimeMessage()
6265
it.thenReturn(msg)
6366
}
67+
68+
whenever(emailGlobalVariablesProvider.invoke()).thenReturn(
69+
mapOf(
70+
"isCloud" to true,
71+
"instanceQualifier" to "Tolgee",
72+
"instanceUrl" to "https://tolgee.test",
73+
)
74+
)
6475
}
6576

6677
@Test

0 commit comments

Comments
 (0)