Kaynağa Gözat

Add mail notification & hk common holiday

tags/Baseline_30082024_BACKEND_UAT
cyril.tsui 1 yıl önce
ebeveyn
işleme
c51f55152d
17 değiştirilmiş dosya ile 886 ekleme ve 1 silme
  1. +42
    -0
      src/main/java/com/ffii/core/utils/LocaleUtils.java
  2. +38
    -0
      src/main/java/com/ffii/tsms/modules/common/MailSMTP.kt
  3. +8
    -0
      src/main/java/com/ffii/tsms/modules/common/SettingNames.java
  4. +29
    -0
      src/main/java/com/ffii/tsms/modules/common/holiday/models/HolidayRequest.kt
  5. +8
    -0
      src/main/java/com/ffii/tsms/modules/common/holiday/models/HolidayResponse.kt
  6. +60
    -0
      src/main/java/com/ffii/tsms/modules/common/holiday/service/HolidayService.kt
  7. +17
    -0
      src/main/java/com/ffii/tsms/modules/common/holiday/web/HolidayController.kt
  8. +235
    -0
      src/main/java/com/ffii/tsms/modules/common/mail/pojo/MailRequest.kt
  9. +75
    -0
      src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt
  10. +46
    -0
      src/main/java/com/ffii/tsms/modules/common/mail/service/MailSenderService.kt
  11. +207
    -0
      src/main/java/com/ffii/tsms/modules/common/mail/service/MailService.kt
  12. +38
    -0
      src/main/java/com/ffii/tsms/modules/common/mail/web/MailController.kt
  13. +21
    -0
      src/main/java/com/ffii/tsms/modules/common/mail/web/models/MailSave.kt
  14. +1
    -1
      src/main/java/com/ffii/tsms/modules/timesheet/web/TimesheetsController.kt
  15. +21
    -0
      src/main/resources/db/changelog/changes/20240807_01_cyril/01_update_settings.sql
  16. +12
    -0
      src/main/resources/db/changelog/changes/20240813_01_cyril/01_update_authority.sql
  17. +28
    -0
      src/main/resources/templates/mail/TimesheetNotification.ftl

+ 42
- 0
src/main/java/com/ffii/core/utils/LocaleUtils.java Dosyayı Görüntüle

@@ -0,0 +1,42 @@
package com.ffii.core.utils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.i18n.LocaleContextHolder;

import java.util.Locale;

/** this utils follow "-" standard ("zh-TW", no "zh_TW") */
public abstract class LocaleUtils {

public static Locale getLocale() {
return LocaleContextHolder.getLocale();
}

public static String getLocaleStr() {
return toLocaleStr(LocaleContextHolder.getLocale());
}

public static String toLocaleStr(Locale locale) {
String language = locale.getLanguage();
String country = locale.getCountry();

if (StringUtils.isNotBlank(country)) {
return language + "-" + country;
} else {
return language;
}
}

/**
* @param localeStr
* e.g. zh-TW
*/
public static Locale from(String localeStr) {
String[] localeArr = localeStr.split("-");
if (localeArr.length == 1) {
return new Locale(localeArr[0]);
} else {
return new Locale(localeArr[0], localeArr[1]);
}
}
}

+ 38
- 0
src/main/java/com/ffii/tsms/modules/common/MailSMTP.kt Dosyayı Görüntüle

@@ -0,0 +1,38 @@
package com.ffii.tsms.modules.common

import com.ffii.tsms.modules.settings.service.SettingsService
import org.apache.commons.lang3.StringUtils

open class MailSMTP(settingsService: SettingsService) {

open var host: String? = null
open var port: Int? = null
open var username: String? = null
open var password: String? = null
open var auth: Boolean? = null

init {
this.host = settingsService.getString(SettingNames.MAIL_SMTP_HOST)
this.port = settingsService.getInt(SettingNames.MAIL_SMTP_PORT)
this.username = settingsService.getString(SettingNames.MAIL_SMTP_USERNAME)
this.password = settingsService.getString(SettingNames.MAIL_SMTP_PASSWORD)
this.auth = settingsService.getBoolean(SettingNames.MAIL_SMTP_AUTH)
}

final override fun equals(other: Any?): Boolean {
if (other == null || other !is MailSMTP) return false

val o = other as MailSMTP
if (StringUtils.equals(
this.host,
o.host
) && this.port == o.port &&
StringUtils.equals(this.username, o.username) &&
StringUtils.equals(this.password, o.password)
) {
return true
}

return false
}
}

+ 8
- 0
src/main/java/com/ffii/tsms/modules/common/SettingNames.java Dosyayı Görüntüle

@@ -40,6 +40,14 @@ public abstract class SettingNames {

public static final String MAIL_SMTP_AUTH = "MAIL.smtp.auth";

public static final String TIMESHEET_MAIL_CC = "TIMESHEET.mail.cc";

public static final String TIMESHEET_MAIL_BCC = "TIMESHEET.mail.bcc";

public static final String TIMESHEET_MAIL_SUBJECT = "TIMESHEET.mail.subject";

public static final String TIMESHEET_MAIL_TEMPLATE = "TIMESHEET.mail.template";

public static final String JS_VERSION = "JS.version";

public static final String REPORT_DAILYMAINT_RECIPIENTS_MECH = "REPORT.dailyMaint.recipients.mech";


+ 29
- 0
src/main/java/com/ffii/tsms/modules/common/holiday/models/HolidayRequest.kt Dosyayı Görüntüle

@@ -0,0 +1,29 @@
package com.ffii.tsms.modules.common.holiday.models

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class VCalendarRequest(
val vcalendar: List<VCalendar>
)

@JsonClass(generateAdapter = true)
data class VCalendar(
val prodid: String,
val version: String,
val calscale: String,
@Json(name = "x-wr-timezone") val xWrTimezone: String,
@Json(name = "x-wr-calname") val xWrCalname: String,
@Json(name = "x-wr-caldesc") val xWrCaldesc: String,
val vevent: List<VEvent>
)

@JsonClass(generateAdapter = true)
data class VEvent(
val dtstart: List<Any>, // Can be a String or a Map
val dtend: List<Any>, // Can be a String or a Map
val transp: String,
val uid: String,
val summary: String
)

+ 8
- 0
src/main/java/com/ffii/tsms/modules/common/holiday/models/HolidayResponse.kt Dosyayı Görüntüle

@@ -0,0 +1,8 @@
package com.ffii.tsms.modules.common.holiday.models

import java.time.LocalDate

data class CommonHolidayResponse(
val date: LocalDate,
val name: String,
)

+ 60
- 0
src/main/java/com/ffii/tsms/modules/common/holiday/service/HolidayService.kt Dosyayı Görüntüle

@@ -0,0 +1,60 @@
package com.ffii.tsms.modules.common.holiday.service

import com.ffii.tsms.modules.common.holiday.models.CommonHolidayResponse
import com.ffii.tsms.modules.common.holiday.models.VCalendarRequest
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import okhttp3.Request
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.stereotype.Service
import java.io.IOException
import java.time.LocalDate
import java.time.format.DateTimeFormatter

@Service
open class HolidayService() {
private val logger: Log = LogFactory.getLog(javaClass)
private val HOLIDAY_URL = "https://www.1823.gov.hk/common/ical/tc.json"

open fun commonHolidayList(): List<CommonHolidayResponse> {
val client = OkHttpClient()
val request = Request.Builder()
.url(HOLIDAY_URL)
.build()

client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code: $response")

// logger.info(response.body.toString())

val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val jsonAdapter = moshi.adapter(VCalendarRequest::class.java)

val vCalendarResponse = jsonAdapter.fromJson(response.body?.string() ?: "")
val vCalendar = vCalendarResponse?.vcalendar?.get(0)

if (vCalendar != null) {
val commonHolidayResponse = mutableListOf<CommonHolidayResponse>()
val formatter = DateTimeFormatter.ofPattern("yyyyMMdd")
vCalendar.vevent.forEach {vevent ->
commonHolidayResponse.add(
CommonHolidayResponse(
date = LocalDate.parse(vevent.dtstart[0] as String, formatter),
name = vevent.summary
)
)
}

return commonHolidayResponse
} else {
return emptyList()
}
}
}
}

+ 17
- 0
src/main/java/com/ffii/tsms/modules/common/holiday/web/HolidayController.kt Dosyayı Görüntüle

@@ -0,0 +1,17 @@
package com.ffii.tsms.modules.common.holiday.web

import com.ffii.tsms.modules.common.holiday.models.CommonHolidayResponse
import com.ffii.tsms.modules.common.holiday.service.HolidayService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/holiday")
class HolidayController(private val holidayService: HolidayService) {

@GetMapping("/common")
fun commonHolidays(): List<CommonHolidayResponse>{
return holidayService.commonHolidayList()
}
}

+ 235
- 0
src/main/java/com/ffii/tsms/modules/common/mail/pojo/MailRequest.kt Dosyayı Görüntüle

@@ -0,0 +1,235 @@
package com.ffii.tsms.modules.common.mail.pojo

import jakarta.mail.internet.InternetAddress

open class MailRequest() {

val PRIORITY_HIGHEST: Int = 1
val PRIORITY_HIGH: Int = 2
val PRIORITY_NORMAL: Int = 3
val PRIORITY_LOW: Int = 4
val PRIORITY_LOWEST: Int = 5

open var from: InternetAddress? = null

open var to: List<InternetAddress> = mutableListOf()

open var subject: String? = null

open var template: String? = null

open var templateContent: String? = null

open var args: Map<String, Any?> = mapOf()

open var priority: Int? = null

open var replyTo: InternetAddress? = null

open var cc: List<InternetAddress> = mutableListOf()

open var bcc: List<InternetAddress> = mutableListOf()

open var attachments: Map<String, ByteArray> = mapOf()

open fun builder(): Builder {
return Builder()
}

open fun addAttachment(attachmentFilename: String, byteArray: ByteArray) {
this.attachments += Pair(attachmentFilename, byteArray)
}

open fun addTo(to: InternetAddress) {
this.to += to
}

open fun addCc(cc: InternetAddress) {
this.cc += cc
}

open fun addBcc(bcc: InternetAddress) {
this.bcc += bcc
}

open class Builder() {
open var mailRequest:MailRequest = MailRequest()

init {
this.mailRequest = MailRequest()
}

open fun build(): MailRequest {
return this.mailRequest
}

open fun addAttachment(attachmentFilename: String, byteArray: ByteArray): Builder {
mailRequest.addAttachment(attachmentFilename, byteArray)
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addToInternetAddress")
open fun addTo(to: InternetAddress): Builder {
mailRequest.addTo(to)
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addToString")
open fun addTo(to: String): Builder {
mailRequest.addTo(InternetAddress(to))
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addCcInternetAddress")
open fun addCc(cc: InternetAddress): Builder {
mailRequest.addCc(cc)
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addCcString")
open fun addCc(cc: String): Builder {
mailRequest.addCc(InternetAddress(cc))
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addCcStringList")
open fun addCc(cc: List<String>): Builder {
cc.forEach {
if (it.isNotEmpty()) {
mailRequest.addCc(InternetAddress(it))
}
}
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addBccInternetAddress")
open fun addBcc(bcc: InternetAddress): Builder {
mailRequest.addBcc(bcc)
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addBccString")
open fun addBcc(bcc: String): Builder {
mailRequest.addBcc(InternetAddress(bcc))
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("addBccStringList")
open fun addBcc(bcc: List<String>): Builder {
bcc.forEach {
if (it.isNotEmpty()) {
mailRequest.addBcc(InternetAddress(it))
}
}
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("fromInternetAddress")
open fun from(from: InternetAddress): Builder {
mailRequest.from = from
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("fromString")
open fun from(from: String): Builder {
mailRequest.from = InternetAddress(from)
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("toListInternetAddress")
open fun to(to: List<InternetAddress>): Builder {
mailRequest.to = to
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("toListString")
open fun to(to: List<String>): Builder {
mailRequest.to = to.map { InternetAddress(it) }
return this
}

open fun subject(subject: String?): Builder {
mailRequest.subject = subject
return this
}

open fun template(template: String?): Builder {
mailRequest.template = template
return this
}

open fun templateContent(templateContent: String?): Builder {
mailRequest.templateContent = templateContent
return this
}

open fun args(args: Map<String, Any?>): Builder {
mailRequest.args = args
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("replyToInternetAddress")
open fun replyTo(replyTo: InternetAddress?): Builder {
mailRequest.replyTo = replyTo
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("replyToString")
open fun replyTo(replyTo: String?): Builder {
mailRequest.replyTo = InternetAddress(replyTo)
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("ccListInternetAddress")
open fun cc(cc: List<InternetAddress>): Builder {
mailRequest.cc = cc
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("ccListString")
open fun cc(cc: List<String>): Builder {
mailRequest.cc = cc.map { InternetAddress(it) }
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("bccListInternetAddress")
open fun bcc(bcc: List<InternetAddress>): Builder {
mailRequest.bcc = bcc
return this
}

@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("bccListString")
open fun bcc(bcc: List<String>): Builder {
mailRequest.bcc = bcc.map { InternetAddress(it) }
return this
}

open fun attachments(attachments: Map<String, ByteArray>): Builder {
mailRequest.attachments = attachments
return this
}

open fun priority(priority: Int?): Builder {
mailRequest.priority = priority
return this
}
}
}

+ 75
- 0
src/main/java/com/ffii/tsms/modules/common/mail/service/MailReminderService.kt Dosyayı Görüntüle

@@ -0,0 +1,75 @@
package com.ffii.tsms.modules.common.mail.service

import com.ffii.tsms.modules.common.SecurityUtils
import com.ffii.tsms.modules.common.SettingNames
import com.ffii.tsms.modules.common.mail.pojo.MailRequest
import com.ffii.tsms.modules.settings.service.SettingsService
import com.ffii.tsms.modules.user.service.UserService
import jakarta.mail.internet.InternetAddress
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.stereotype.Service
import java.time.LocalDate
import java.time.format.DateTimeFormatter

@Service
open class MailReminderService (
val mailService: MailService,
val userService: UserService,
val settingsService: SettingsService,
) {
protected val logger: Log = LogFactory.getLog(javaClass)

private val dateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")

// @Scheduled(cron = "0 0 6 * * ?") // Runs at 06:00 AM every day
open fun sendTimesheetReminder() {
val inputDate = LocalDate.now().minusDays(4).format(dateFormat)

val subject = settingsService.findByName(SettingNames.TIMESHEET_MAIL_SUBJECT).orElseThrow().value
val template = settingsService.findByName(SettingNames.TIMESHEET_MAIL_TEMPLATE).orElseThrow().value
val cc = settingsService.findByName(SettingNames.TIMESHEET_MAIL_CC).orElseThrow().value.split(",")
val bcc = settingsService.findByName(SettingNames.TIMESHEET_MAIL_BCC).orElseThrow().value.split(",")
val mailRequest = MailRequest.Builder()
.subject(subject)
.template("mail/TimesheetNotification")
.args(mapOf(
Pair("date", inputDate),
Pair("template", template)
))
.addTo(InternetAddress("[email protected]"))
.addCc(cc)
.addBcc(bcc)
.build()

val mailRequestList = mutableListOf<MailRequest>()
mailRequestList += mailRequest
mailService.send(mailRequestList)
}

open fun sendTimesheetReminderTest() {
val inputDate = LocalDate.now().minusDays(4).format(dateFormat)

val subject = settingsService.findByName(SettingNames.TIMESHEET_MAIL_SUBJECT).orElseThrow().value
val template = settingsService.findByName(SettingNames.TIMESHEET_MAIL_TEMPLATE).orElseThrow().value
val cc = settingsService.findByName(SettingNames.TIMESHEET_MAIL_CC).orElseThrow().value.split(",")
logger.info(cc)
val bcc = settingsService.findByName(SettingNames.TIMESHEET_MAIL_BCC).orElseThrow().value.split(",")
val mailRequest = MailRequest.Builder()
.subject(subject)
// .template("mail/TimesheetNotification")
.templateContent(template)
.args(mapOf(
Pair("date", inputDate),
// Pair("template", template)
))
.addTo(InternetAddress(SecurityUtils.getUser().orElseThrow().email))
.addCc(cc)
.addBcc(bcc)
.build()

val mailRequestList = mutableListOf<MailRequest>()
mailRequestList += mailRequest
mailService.send(mailRequestList)
}
}

+ 46
- 0
src/main/java/com/ffii/tsms/modules/common/mail/service/MailSenderService.kt Dosyayı Görüntüle

@@ -0,0 +1,46 @@
package com.ffii.tsms.modules.common.mail.service

import com.ffii.tsms.modules.common.MailSMTP
import com.ffii.tsms.modules.settings.service.SettingsService
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.JavaMailSenderImpl
import org.springframework.stereotype.Service
import java.util.*

@Service
open class MailSenderService(private val settingsService: SettingsService) {
private var sender: JavaMailSender? = null
private var mailConfigCachs: MailSMTP? = null

open fun get(): JavaMailSender {

val config = MailSMTP(settingsService)

if (this.sender == null || (mailConfigCachs == null) || !config.equals(this.mailConfigCachs)) {

this.mailConfigCachs = config
val sender = JavaMailSenderImpl()

val props = Properties()
val auth = config.auth ?: false
if (auth) {
props["mail.smtp.timeout"] = "20000"
props["mail.smtp.connectiontimeout"] = "10000"
}
props["mail.smtp.auth"] = auth
props["mail.smtp.starttls.enable"] = "true"


sender.host = config.host
sender.port = config.port!!
if (auth) {
sender.username = config.username
sender.password = config.password
}
sender.javaMailProperties = props

this.sender = sender
}
return this.sender ?: JavaMailSenderImpl()
}
}

+ 207
- 0
src/main/java/com/ffii/tsms/modules/common/mail/service/MailService.kt Dosyayı Görüntüle

@@ -0,0 +1,207 @@
package com.ffii.tsms.modules.common.mail.service

import com.ffii.core.exception.InternalServerErrorException
import com.ffii.core.utils.LocaleUtils
import com.ffii.tsms.modules.common.ErrorCodes
import com.ffii.tsms.modules.common.SettingNames
import com.ffii.tsms.modules.common.mail.pojo.MailRequest
import com.ffii.tsms.modules.common.mail.web.models.MailSave
import com.ffii.tsms.modules.settings.entity.Settings
import com.ffii.tsms.modules.settings.entity.SettingsRepository
import com.ffii.tsms.modules.settings.service.SettingsService
import freemarker.cache.StringTemplateLoader
import freemarker.template.*
import jakarta.mail.MessagingException
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.core.io.ByteArrayResource
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.scheduling.annotation.Async
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils
import java.io.IOException
import java.text.ParseException
import java.util.*

@Service
open class MailService(
private val mailSenderService: MailSenderService,
private val freemarkerConfig: Configuration,
private val settingsService: SettingsService,
private val passwordEncoder: PasswordEncoder,
private val settingsRepository: SettingsRepository,
) {
protected val logger: Log = LogFactory.getLog(javaClass)

@Throws(
MessagingException::class,
TemplateNotFoundException::class,
MalformedTemplateNameException::class,
ParseException::class,
IOException::class,
TemplateException::class
)
open fun doSend(mailRequests: List<MailRequest>, locale: Locale) {

val sender = mailSenderService.get()

for (mailRequest in mailRequests) {
val mimeMessage = sender.createMimeMessage()

val helper = MimeMessageHelper(mimeMessage, true, "UTF-8")
mailRequest.subject?.let { helper.setSubject(it) }

var template: Template? = null
if (mailRequest.template != null) {
template = try {
freemarkerConfig
.getTemplate((mailRequest.template + "_" + LocaleUtils.toLocaleStr(locale)) + ".ftl")
} catch (e: TemplateNotFoundException) {
freemarkerConfig.getTemplate(mailRequest.template + ".ftl")
}
} else {
// Create a FreeMarker configuration
val configuration = Configuration(Configuration.VERSION_2_3_32)

// Create a template loader and add the template content
val templateLoader = StringTemplateLoader()
templateLoader.putTemplate("myTemplate", mailRequest.templateContent)
configuration.templateLoader = templateLoader

try {
// Get the template by name
template = configuration.getTemplate("myTemplate")
} catch (e: IOException) {
// Handle any IO exceptions
}
}

helper.setText(
FreeMarkerTemplateUtils.processTemplateIntoString(template!!, mailRequest.args),
true
)
if (mailRequest.from != null) {
helper.setFrom(mailRequest.from!!)
} else {
helper.setFrom(settingsService.getString(SettingNames.MAIL_SMTP_USERNAME))
}

if (mailRequest.priority != null) helper.setPriority(mailRequest.priority!!)
if (mailRequest.replyTo != null) helper.setReplyTo(mailRequest.replyTo!!)
if (mailRequest.to.isNotEmpty()) helper.setTo(
mailRequest.to.toTypedArray()
)
if (mailRequest.cc.isNotEmpty()) helper.setCc(
mailRequest.cc.toTypedArray()
)
if (mailRequest.bcc.isNotEmpty()) helper.setBcc(
mailRequest.bcc.toTypedArray()
)

if (mailRequest.attachments.isNotEmpty()) {
for ((key, value) in mailRequest.attachments.entries) {
helper.addAttachment(key, ByteArrayResource(value))
}
}
sender.send(mimeMessage)
}
}

@Throws(ParseException::class)
fun send(mailRequests: List<MailRequest>, locale: Locale) {
try {
doSend(mailRequests, locale)
} catch (e: MessagingException) {
throw InternalServerErrorException(ErrorCodes.SEND_EMAIL_ERROR, e)
} catch (e: IOException) {
throw InternalServerErrorException(ErrorCodes.SEND_EMAIL_ERROR, e)
} catch (e: TemplateException) {
throw InternalServerErrorException(ErrorCodes.SEND_EMAIL_ERROR, e)
}
}

@Throws(ParseException::class)
fun send(mailRequests: List<MailRequest>) {
send(mailRequests, LocaleUtils.getLocale())
}

@Throws(ParseException::class)
fun send(mailRequest: MailRequest, locale: Locale) {
send(mutableListOf(mailRequest), locale)
}

@Async
@Throws(ParseException::class)
open fun asyncSend(mailRequests: List<MailRequest>, locale: Locale) {
try {
doSend(mailRequests, locale)
} catch (e: MessagingException) {
logger.error("send email error", e)
} catch (e: IOException) {
logger.error("send email error", e)
} catch (e: TemplateException) {
logger.error("send email error", e)
}
}

@Async
@Throws(ParseException::class)
open fun asyncSend(mailRequest: MailRequest, locale: Locale) {
asyncSend(mutableListOf(mailRequest), locale)
}

@Async
@Throws(ParseException::class)
open fun asyncSend(mailRequests: List<MailRequest>) {
asyncSend(mailRequests, LocaleUtils.getLocale())
}

@Async
@Throws(ParseException::class)
open fun asyncSend(mailRequest: MailRequest) {
asyncSend(mutableListOf(mailRequest))
}

open fun saveMail(mailSave: MailSave): List<Settings> {
// ------------------ save mail settings ------------------ //
val settings = mutableListOf<Settings>()

mailSave.settings.forEach { setting ->
val tempSetting = settingsRepository.findById(setting.id).orElseThrow()
settings += tempSetting.apply {
value = setting.value
}
}

// ------------------ save timesheet mail details ------------------ //
val mailCc = settingsRepository.findByName("TIMESHEET.mail.cc").orElseThrow()

settings += mailCc.apply {
value = mailSave.template.cc
}

val mailBcc = settingsRepository.findByName("TIMESHEET.mail.bcc").orElseThrow()

settings += mailBcc.apply {
value = mailSave.template.bcc
}

val mailSubject = settingsRepository.findByName("TIMESHEET.mail.subject").orElseThrow()

settings += mailSubject.apply {
value = mailSave.template.subject
}

val mailTemplate = settingsRepository.findByName("TIMESHEET.mail.template").orElseThrow()

settings += mailTemplate.apply {
value = mailSave.template.template
}

// ------------------ save all ------------------ //
settingsRepository.saveAll(settings)

return settings
}
}

+ 38
- 0
src/main/java/com/ffii/tsms/modules/common/mail/web/MailController.kt Dosyayı Görüntüle

@@ -0,0 +1,38 @@
package com.ffii.tsms.modules.common.mail.web

import com.ffii.tsms.modules.common.mail.service.MailReminderService
import com.ffii.tsms.modules.common.mail.service.MailService
import com.ffii.tsms.modules.common.mail.web.models.MailSave
import com.ffii.tsms.modules.settings.entity.Settings
import com.ffii.tsms.modules.settings.entity.SettingsRepository
import com.ffii.tsms.modules.settings.service.SettingsService
import jakarta.validation.Valid
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/mails")
class MailController(
private val settingsService: SettingsService,
private val mailService: MailService,
private val mailReminderService: MailReminderService,
) {
@GetMapping("/setting")
fun mailSetting(): List<Settings> {
return settingsService.findAllByCategory("MAIL")
}

@GetMapping("/timesheet-template")
fun mailTimesheetTemplate(): List<Settings> {
return settingsService.findAllByCategory("TIMESHEET")
}

@PostMapping("/save")
fun saveMail(@Valid @RequestBody mailSave: MailSave): List<Settings> {
return mailService.saveMail(mailSave)
}

@GetMapping("/test")
fun testMail() {
mailReminderService.sendTimesheetReminderTest()
}
}

+ 21
- 0
src/main/java/com/ffii/tsms/modules/common/mail/web/models/MailSave.kt Dosyayı Görüntüle

@@ -0,0 +1,21 @@
package com.ffii.tsms.modules.common.mail.web.models

data class Setting (
val id: Long,
val name: String,
val value: String,
val category: String,
val type: String,
)

data class Template (
val cc: String?,
val bcc: String?,
val subject: String,
val template: String?,
)

data class MailSave (
val settings: List<Setting>,
val template: Template
)

+ 1
- 1
src/main/java/com/ffii/tsms/modules/timesheet/web/TimesheetsController.kt Dosyayı Görüntüle

@@ -3,7 +3,7 @@ package com.ffii.tsms.modules.timesheet.web
import com.ffii.core.exception.BadRequestException
import com.ffii.tsms.modules.timesheet.entity.LeaveType
import com.ffii.tsms.modules.timesheet.service.LeaveService
//import com.ffii.tsms.modules.timesheet.service.MailReminderService
//import com.ffii.tsms.modules.common.mail.service.MailReminderService
import com.ffii.tsms.modules.timesheet.service.TimesheetsService
import com.ffii.tsms.modules.timesheet.web.models.*
import jakarta.servlet.http.HttpServletRequest


+ 21
- 0
src/main/resources/db/changelog/changes/20240807_01_cyril/01_update_settings.sql Dosyayı Görüntüle

@@ -0,0 +1,21 @@
-- liquibase formatted sql
-- changeset cyril:settings

INSERT INTO settings (id,name,value,category,`type`)
VALUES (7,'MAIL.smtp.host','smtp.office365.com','MAIL','string');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (8,'MAIL.smtp.port','587','MAIL','integer');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (9,'MAIL.smtp.username','','MAIL','string');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (10,'MAIL.smtp.password','','MAIL','string');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (11,'MAIL.smtp.auth','false','MAIL','boolean');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (12,'TIMESHEET.mail.cc','','TIMESHEET','string');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (13,'TIMESHEET.mail.bcc','','TIMESHEET','string');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (14,'TIMESHEET.mail.subject','','TIMESHEET','string');
INSERT INTO settings (id,name,value,category,`type`)
VALUES (15,'TIMESHEET.mail.template','','TIMESHEET','string');

+ 12
- 0
src/main/resources/db/changelog/changes/20240813_01_cyril/01_update_authority.sql Dosyayı Görüntüle

@@ -0,0 +1,12 @@
-- liquibase formatted sql
-- changeset cyril:authority

INSERT INTO authority (authority,name)
VALUES ('MAINTAIN_MAIL','Maintain Mail in Master Data');
INSERT INTO authority (authority,name)
VALUES ('VIEW_MAIL','View Mail in Master Data');

INSERT INTO user_authority (userId,authId)
VALUES (1,53);
INSERT INTO user_authority (userId,authId)
VALUES (1,54);

+ 28
- 0
src/main/resources/templates/mail/TimesheetNotification.ftl Dosyayı Görüntüle

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<style>
body {
margin: 0;
}
.content {
padding-top: 2rem;
display: flex;
}

.container {
padding: 2px 16px;
}
</style>
<body>
<main class="content">
<div class="container">
${template}
</div>

</main>
</body>
</html>

Yükleniyor…
İptal
Kaydet