diff --git a/backend/app/src/main/kotlin/io/tolgee/Application.kt b/backend/app/src/main/kotlin/io/tolgee/Application.kt index b5f6e432c0..0801ecaad9 100644 --- a/backend/app/src/main/kotlin/io/tolgee/Application.kt +++ b/backend/app/src/main/kotlin/io/tolgee/Application.kt @@ -5,13 +5,14 @@ import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration +import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration import org.springframework.boot.context.properties.ConfigurationPropertiesScan import org.springframework.data.jpa.repository.config.EnableJpaAuditing import org.springframework.data.jpa.repository.config.EnableJpaRepositories @SpringBootApplication( scanBasePackages = ["io.tolgee"], - exclude = [LdapAutoConfiguration::class], + exclude = [LdapAutoConfiguration::class, ThymeleafAutoConfiguration::class], ) @EnableJpaAuditing @EntityScan("io.tolgee.model") diff --git a/backend/data/build.gradle b/backend/data/build.gradle index b31c54334a..c9bad3f334 100644 --- a/backend/data/build.gradle +++ b/backend/data/build.gradle @@ -52,7 +52,6 @@ apply plugin: 'org.hibernate.orm' repositories { mavenCentral() - jcenter() } idea { @@ -71,6 +70,7 @@ allOpen { annotation("org.springframework.beans.factory.annotation.Configurable") } +apply from: "$rootDir/gradle/email.gradle" apply from: "$rootDir/gradle/liquibase.gradle" configureLiquibase("public", "hibernate:spring:io.tolgee", 'src/main/resources/db/changelog/schema.xml') @@ -98,6 +98,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-configuration-processor" implementation "org.springframework.boot:spring-boot-starter-batch" implementation "org.springframework.boot:spring-boot-starter-websocket" + implementation "org.springframework.boot:spring-boot-starter-thymeleaf" /** * DB @@ -170,6 +171,7 @@ dependencies { implementation("org.apache.commons:commons-configuration2:2.10.1") implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jacksonVersion" implementation("com.opencsv:opencsv:5.9") + implementation 'ognl:ognl:3.3.4' /** * Google translation API @@ -231,6 +233,10 @@ tasks.named('compileJava') { inputs.files(tasks.named('processResources')) } +tasks.named('compileKotlin') { + dependsOn 'buildEmails' +} + ktlint { debug = true verbose = true @@ -238,11 +244,3 @@ ktlint { exclude("**/PluralData.kt") } } - -hibernate { - enhancement { - enableDirtyTracking = false - enableAssociationManagement = false - enableExtendedEnhancement = false - } -} diff --git a/backend/data/src/main/kotlin/io/tolgee/email/EmailService.kt b/backend/data/src/main/kotlin/io/tolgee/email/EmailService.kt new file mode 100644 index 0000000000..f8428714ca --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/email/EmailService.kt @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.email + +import io.tolgee.configuration.tolgee.SmtpProperties +import io.tolgee.dtos.misc.EmailAttachment +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.MimeMessageHelper +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Service +import org.thymeleaf.TemplateEngine +import org.thymeleaf.context.Context +import java.util.* + +@Service +class EmailService( + private val smtpProperties: SmtpProperties, + private val mailSender: JavaMailSender, + @Qualifier("emailTemplateEngine") private val templateEngine: TemplateEngine, +) { + private val smtpFrom + get() = smtpProperties.from + ?: throw IllegalStateException("SMTP sender is not configured. See https://docs.tolgee.io/platform/self_hosting/configuration#smtp") + + @Async + fun sendEmailTemplate( + recipient: String, + template: String, + locale: Locale, + properties: Map = mapOf(), + attachments: List = listOf() + ) { + val context = Context(locale, properties) + val html = templateEngine.process(template, context) + val subject = extractEmailTitle(html) + + sendEmail(recipient, subject, html, attachments) + } + + @Async + fun sendEmail( + recipient: String, + subject: String, + contents: String, + attachments: List = listOf() + ) { + val message = mailSender.createMimeMessage() + val helper = MimeMessageHelper(message, MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,"UTF8") + + helper.setFrom(smtpFrom) + helper.setTo(recipient) + helper.setSubject(subject) + helper.setText(contents, true) + attachments.forEach { helper.addAttachment(it.name, it.inputStreamSource) } + + mailSender.send(message) + } + + private fun extractEmailTitle(html: String): String { + return REGEX_TITLE.find(html)!!.groupValues[1] + } + + companion object { + private val REGEX_TITLE = Regex("(.+?)") + } +} diff --git a/backend/data/src/main/kotlin/io/tolgee/email/EmailTemplateConfig.kt b/backend/data/src/main/kotlin/io/tolgee/email/EmailTemplateConfig.kt new file mode 100644 index 0000000000..b4b0c735b0 --- /dev/null +++ b/backend/data/src/main/kotlin/io/tolgee/email/EmailTemplateConfig.kt @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.email + +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.context.MessageSource +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.support.ResourceBundleMessageSource +import org.thymeleaf.TemplateEngine +import org.thymeleaf.spring6.SpringTemplateEngine +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver +import org.thymeleaf.templateresolver.ITemplateResolver +import java.util.* + +@Configuration +class EmailTemplateConfig { + @Bean("emailTemplateResolver") + fun templateResolver(): ClassLoaderTemplateResolver { + val templateResolver = ClassLoaderTemplateResolver() + templateResolver.characterEncoding = "UTF-8" + templateResolver.prefix = "/email-templates/" + templateResolver.suffix = ".html" + return templateResolver + } + + @Bean("emailMessageSource") + fun messageSource(): MessageSource { + val messageSource = ResourceBundleMessageSource() + messageSource.setBasename("email-i18n.messages") + messageSource.setDefaultEncoding("UTF-8") + messageSource.setDefaultLocale(Locale.ENGLISH) + println(messageSource.getMessage("powered-by", null, Locale.ENGLISH)) + println(messageSource.getMessage("powered-by", null, Locale.FRENCH)) + return messageSource + } + + @Bean("emailTemplateEngine") + fun templateEngine( + @Qualifier("emailTemplateResolver") templateResolver: ITemplateResolver, + @Qualifier("emailMessageSource") messageSource: MessageSource + ): TemplateEngine { + val templateEngine = SpringTemplateEngine() + templateEngine.templateResolvers = setOf(templateResolver) + templateEngine.setTemplateEngineMessageSource(messageSource) + return templateEngine + } +} diff --git a/backend/data/src/main/resources/email-i18n b/backend/data/src/main/resources/email-i18n new file mode 120000 index 0000000000..fb80d9d6af --- /dev/null +++ b/backend/data/src/main/resources/email-i18n @@ -0,0 +1 @@ +../../../../../email/i18n \ No newline at end of file diff --git a/backend/data/src/main/resources/email-templates b/backend/data/src/main/resources/email-templates new file mode 120000 index 0000000000..6b9d53bca5 --- /dev/null +++ b/backend/data/src/main/resources/email-templates @@ -0,0 +1 @@ +../../../../../email/out \ No newline at end of file diff --git a/backend/data/src/test/kotlin/io/tolgee/email/EmailServiceTest.kt b/backend/data/src/test/kotlin/io/tolgee/email/EmailServiceTest.kt new file mode 100644 index 0000000000..af7f63c8de --- /dev/null +++ b/backend/data/src/test/kotlin/io/tolgee/email/EmailServiceTest.kt @@ -0,0 +1,121 @@ +/** + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.tolgee.email + +import io.tolgee.configuration.tolgee.SmtpProperties +import io.tolgee.testing.assert +import jakarta.mail.internet.MimeMessage +import jakarta.mail.internet.MimeMultipart +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.context.annotation.Import +import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.JavaMailSenderImpl +import org.springframework.stereotype.Component +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.util.* + +@Component +@ExtendWith(SpringExtension::class) +@Import(EmailService::class, EmailTemplateConfig::class) +class EmailServiceTest { + @MockBean + private lateinit var smtpProperties: SmtpProperties + + @MockBean + private lateinit var mailSender: JavaMailSender + + @Autowired + private lateinit var emailService: EmailService + + @Captor + private lateinit var emailCaptor: ArgumentCaptor + + @BeforeEach + fun beforeEach() { + val sender = JavaMailSenderImpl() + whenever(smtpProperties.from).thenReturn("Tolgee Test ") + whenever(mailSender.createMimeMessage()).let { + val msg = sender.createMimeMessage() + it.thenReturn(msg) + } + } + + @Test + fun `it sends a rendered email with variables and ICU strings processed`() { + emailService.sendEmailTemplate("test@tolgee.internal", "zz-test-email", Locale.ENGLISH, TEST_PROPERTIES) + verify(mailSender).send(emailCaptor.capture()) + + val email = emailCaptor.value + email.subject.assert.isEqualTo("Test email (written with React Email)") + email.allRecipients.asList().assert.singleElement().asString().isEqualTo("test@tolgee.internal") + + email.content + .let { it as MimeMultipart } + .let { it.getBodyPart(0).content as MimeMultipart } + .let { it.getBodyPart(0).content as String } + .assert + .contains("Value of `testVar` : test!!") + .contains("Was `testVar` equal to "meow" : no") + .contains("Powered by") + .doesNotContain(" th:") + .doesNotContain(" data-th") + } + + @Test + fun `it correctly processes conditional blocks`() { + // FWIW this is very close to just testing Thymeleaf itself, but it serves as a sanity check for the template itself + emailService.sendEmailTemplate("test@tolgee.internal", "zz-test-email", Locale.ENGLISH, TEST_PROPERTIES_MEOW) + verify(mailSender).send(emailCaptor.capture()) + + val email = emailCaptor.value + email.content + .let { it as MimeMultipart } + .let { it.getBodyPart(0).content as MimeMultipart } + .let { it.getBodyPart(0).content as String } + .assert + .contains("Value of `testVar` : meow") + .contains("Was `testVar` equal to "meow" : yes") + } + + companion object { + private val TEST_PROPERTIES = mapOf( + "testVar" to "test!!", + "testList" to listOf( + mapOf("name" to "Name #1"), + mapOf("name" to "Name #2"), + mapOf("name" to "Name #3"), + ) + ) + + private val TEST_PROPERTIES_MEOW = mapOf( + "testVar" to "meow", + "testList" to listOf( + mapOf("name" to "Name #1"), + mapOf("name" to "Name #2"), + mapOf("name" to "Name #3"), + ) + ) + } +} diff --git a/build.gradle b/build.gradle index 9482b6c879..d2d65dfb70 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,7 @@ project(':server-app').afterEvaluate { } } + apply from: "./gradle/email.gradle" apply from: "./gradle/webapp.gradle" apply from: "./gradle/docker.gradle" apply from: "./gradle/e2e.gradle" @@ -66,6 +67,7 @@ project(':server-app').afterEvaluate { task packResources(type: Zip) { dependsOn "unpack" dependsOn "copyDist" + dependsOn "copyEmailResources" dependsOn "addVersionFile" from "${project.projectDir}/build/dependency" archiveFileName = "tolgee.jar" diff --git a/email/.config/extractor.ts b/email/.config/extractor.ts index 3faf4b10ec..5cc696d1ec 100644 --- a/email/.config/extractor.ts +++ b/email/.config/extractor.ts @@ -109,8 +109,8 @@ export default async function extractor( code ); - if (res.key) keys.push(res.key) - if (res.warning) warnings.push(res.warning) + if (res.key) keys.push(res.key); + if (res.warning) warnings.push(res.warning); } if ( @@ -158,8 +158,8 @@ export default async function extractor( code ); - if (res.key) keys.push(res.key) - if (res.warning) warnings.push(res.warning) + if (res.key) keys.push(res.key); + if (res.warning) warnings.push(res.warning); } }, }); diff --git a/email/.config/tolgeerc.json b/email/.config/tolgeerc.json index 4bebbcb5f5..59414f50e1 100644 --- a/email/.config/tolgeerc.json +++ b/email/.config/tolgeerc.json @@ -1,12 +1,12 @@ { "$schema": "https://docs.tolgee.io/cli-schema.json", "projectId": 1, - "format": "PROPERTIES_JAVA", + "format": "PROPERTIES_ICU", "patterns": ["./emails/**/*.ts?(x)", "./components/**/*.ts?(x)"], "extractor": "./.config/extractor.ts", "pull": { - "path": "./src/i18n", - "tags": ["email"] + "path": "./i18n", + "fileStructureTemplate": "messages_{snakeLanguageTag}.{extension}" }, "push": { "tagNewKeys": ["email"] diff --git a/email/.eslintrc.json b/email/.eslintrc.json index e28ccf80b9..ba5f201c61 100644 --- a/email/.eslintrc.json +++ b/email/.eslintrc.json @@ -33,6 +33,7 @@ ], "@typescript-eslint/no-non-null-assertion": "off", "react/prop-types": "off", - "@typescript-eslint/no-empty-interface": "off" + "@typescript-eslint/no-empty-interface": "off", + "react/no-unescaped-entities": "off" } } diff --git a/email/HACKING.md b/email/HACKING.md index 3d7990a7e1..3c9fd58740 100644 --- a/email/HACKING.md +++ b/email/HACKING.md @@ -28,6 +28,10 @@ templates in the `out` folder that the backend will be able to consume and rende The resources used by emails stored in `resources` must be served by the backend at `/static/emails`. Filenames must be preserved. +> [!NOTE] +> The backend build includes the necessary Gradle tasks to build the emails by itself. You should not need to worry +> about building them yourself or copy files around. + ### TailwindCSS For styles, React Email has a great [TailwindCSS](https://tailwindcss.com/) integration that gets turned into email-friendly inline styles. @@ -127,7 +131,7 @@ HTML node with the properties it received set to the HTML element. That's a lot Fragments, but real nodes such as a `
` or a `` etc. It receives the following properties: -- `condition` (required): the [Thymeleaf conditional expression](https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#conditional-expressions) +- `condition` (required): the [Thymeleaf conditional expression](https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#simple-conditionals-if-and-unless) - `demoValue` (optional): the demo value. Defaults to `true` ### `` @@ -140,7 +144,8 @@ This component receives the following properties: #### Note on available variables Within the for inner template, the iter variable is available as a classic Thymeleaf variable. However, within ICU -strings, if the iter variable is an object, all the fields are available as plain variables prefixed by `$it_`. +strings, if the iter variable is an object, all the fields are available as plain variables prefixed by the name of +the iteration variable and 2 underscores. If you have `product.id`, then you can access it as `product__id`. Information about the iteration can be kept by using [Thymeleaf iterator status mechanism](https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#keeping-iteration-status). All of these variables still have to be set as `demoProps` for the template to render properly in preview mode. @@ -155,18 +160,18 @@ Example: diff --git a/email/components/layouts/ClassicLayout.tsx b/email/components/layouts/ClassicLayout.tsx index 3584d43ea8..a513a03c1e 100644 --- a/email/components/layouts/ClassicLayout.tsx +++ b/email/components/layouts/ClassicLayout.tsx @@ -34,8 +34,8 @@ import LayoutCore from './LayoutCore'; type Props = { children: React.ReactNode; - subject: React.ReactElement; - sendReason: React.ReactElement; + subject: React.ReactElement | string; + sendReason: React.ReactElement | string; }; type SocialLinkProps = { diff --git a/email/components/layouts/LayoutCore.tsx b/email/components/layouts/LayoutCore.tsx index f9ec8137a6..cd2f1d377f 100644 --- a/email/components/layouts/LayoutCore.tsx +++ b/email/components/layouts/LayoutCore.tsx @@ -22,18 +22,17 @@ import { Head, Html, Tailwind } from '@react-email/components'; type Props = { children: React.ReactNode; - subject: React.ReactElement; + subject: React.ReactElement | string; }; export default function LayoutCore({ children, subject }: Props) { const subjectPlainText = convert(renderToString(subject)); + const thText = typeof subject === 'object' ? subject.props['th:text'] : null; return ( - - {subjectPlainText} - + {subjectPlainText} {process.env.NODE_ENV !== 'production' && ( // This is a hack to get line returns to behave as line returns. // The Kotlin renderer will handle these cases, but this is for the browser preview. diff --git a/email/components/translate.ts b/email/components/translate.ts index a10f459c5d..ae987c92c3 100644 --- a/email/components/translate.ts +++ b/email/components/translate.ts @@ -15,7 +15,7 @@ */ import * as React from 'react'; -import IntlMessageFormat from 'intl-messageformat'; +import { IntlMessageFormat } from 'intl-messageformat'; const GLOBALS = { isCloud: true, diff --git a/email/emails/registration-confirm.tsx b/email/emails/registration-confirm.tsx index 2f9a328202..f0b0328ce7 100644 --- a/email/emails/registration-confirm.tsx +++ b/email/emails/registration-confirm.tsx @@ -1,5 +1,5 @@ /** - * Copyright (C) 2023 Tolgee s.r.o. and contributors + * Copyright (C) 2024 Tolgee s.r.o. and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ export default function RegistrationConfirmEmail() { { instanceQualifier: 'Tolgee' } )} > - + @@ -71,7 +71,7 @@ export default function RegistrationConfirmEmail() { diff --git a/email/emails/zz-test-email.tsx b/email/emails/zz-test-email.tsx new file mode 100644 index 0000000000..2f456f68a1 --- /dev/null +++ b/email/emails/zz-test-email.tsx @@ -0,0 +1,67 @@ +import * as React from 'react'; +import { Hr, Text } from '@react-email/components'; +import ClassicLayout from '../components/layouts/ClassicLayout'; +import TolgeeLink from '../components/atoms/TolgeeLink'; +import LocalizedText from '../components/LocalizedText'; +import Var from '../components/Var'; +import If from '../components/If'; +import For from '../components/For'; + +export default function RegistrationConfirmEmail() { + return ( + + + This is a test email exclusively used internally to test email + rendering. If you received this by mistake, well... Whoops! This means + we made an oopsie and you're free to make fun of us on social media... + +
+ + ( + + {c} + + ), + testVar: 'demo', + }} + /> + + + Value of `testVar` : + + + Was `testVar` equal to "meow" : + + yes + no + + +
    + +
  • + +
      +
    • + +
    • +
    • + +
    • +
    +
  • +
    +
+
+ ); +} diff --git a/email/i18n/messages_en.properties b/email/i18n/messages_en.properties new file mode 100644 index 0000000000..78a460a070 --- /dev/null +++ b/email/i18n/messages_en.properties @@ -0,0 +1,13 @@ +email-greetings = Hello {username}, +email-signature = Happy translating,\nTolgee +footer-cloud-address = Letovická 1421/22, Řečkovice, 621 00 Brno, Czech Republic +footer-cloud-sent-by = 🐭 Sent by Tolgee - Check out blog and our socials! 🧀 +powered-by = Powered by Tolgee 🐁 +powered-by_en = Powered by Tolgee 🐁 +registration-confirm-cta = Confirm my email +registration-confirm-link = Or, copy and paste this URL into your browser:\n{confirmUrl} +registration-confirm-subject = Confirm your account +registrations_not_allowed = Registrations are not enabled +registration-welcome-enjoy-your-stay = We hope you'll enjoy your experience! +registration-welcome-text = Welcome and thank you for creating an account! To start using Tolgee, you need to confirm your email. +send-reason-created-account = You're receiving this email because you've created an account on {instanceQualifier} diff --git a/email/package-lock.json b/email/package-lock.json index 1c48827b77..49e7761f1f 100644 --- a/email/package-lock.json +++ b/email/package-lock.json @@ -21,7 +21,6 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.2", "estree-walker": "^3.0.3", - "html-to-text": "^9.0.5", "intl-messageformat": "^10.7.6", "prettier": "^3.3.3", "react": "18.3.1", diff --git a/email/package.json b/email/package.json index f9e94f65a4..ae4fa0e2a3 100644 --- a/email/package.json +++ b/email/package.json @@ -8,7 +8,10 @@ "build": "email build", "export": "cross-env NODE_ENV=production email export", "prettier": "prettier --write ./emails ./components ./.config", - "eslint": "eslint --ext .ts --ext .tsx --max-warnings 0 --report-unused-disable-directives ./emails ./components ./.config" + "eslint": "eslint --ext .ts --ext .tsx --max-warnings 0 --report-unused-disable-directives ./emails ./components ./.config", + "tg:pull": "tolgee pull", + "tg:push": "tolgee push", + "tg:sync": "tolgee sync" }, "devDependencies": { "@react-email/components": "0.0.28", @@ -24,7 +27,6 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.2", "estree-walker": "^3.0.3", - "html-to-text": "^9.0.5", "intl-messageformat": "^10.7.6", "prettier": "^3.3.3", "react": "18.3.1", diff --git a/gradle/email.gradle b/gradle/email.gradle new file mode 100644 index 0000000000..138fb787fe --- /dev/null +++ b/gradle/email.gradle @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 Tolgee s.r.o. and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply from: "$rootDir/gradle/utils.gradle" + +def emailPath = "${rootDir}/email" + +tasks.register('copyEmailResources', Copy) { + def fromDir = "${emailPath}/resources" + def toDir = "${project.projectDir}/build/dependency/BOOT-INF/classes/static/emails/." + from fromDir + into toDir + inputs.dir(fromDir) + outputs.dir(toDir) + mustRunAfter unpack +} + +tasks.register('installEmailDeps', Exec) { + onlyIf { System.getenv("SKIP_EMAIL_BUILD") != "true" } + + workingDir = emailPath + commandLine npmCommandName, "ci" + + inputs.file("${emailPath}/package.json") + inputs.file("${emailPath}/package-lock.json") + outputs.dir("${emailPath}/node_modules") +} + +tasks.register('buildEmails', Exec) { + dependsOn "installEmailDeps", "updateEmailTranslations" + onlyIf { System.getenv("SKIP_EMAIL_BUILD") != "true" } + + workingDir = emailPath + commandLine npmCommandName, "run", "export" + + inputs.dir("${emailPath}/") + outputs.dir("${emailPath}/out/") +} + +tasks.register('updateEmailTranslations', Exec) { + onlyIf { + System.getenv("SKIP_EMAIL_BUILD") != "true" && + System.getenv("TOLGEE_API_URL") != null && + System.getenv("TOLGEE_API_URL") != "" + } + + workingDir = emailPath + commandLine npmCommandName, "run", "tg:pull" +}