Improve mail template

This commit is contained in:
Eike Kettner 2020-04-22 23:41:09 +02:00
parent ffc1cdee51
commit d52efdfcf0
4 changed files with 48 additions and 28 deletions

View File

@ -4,6 +4,7 @@ import java.time.{Instant, LocalDate, ZoneId}
import cats.effect.Sync
import io.circe.{Decoder, Encoder}
import java.time.temporal.ChronoUnit
import java.time.LocalDateTime
import java.time.ZonedDateTime
@ -59,6 +60,9 @@ object Timestamp {
def atUtc(ldt: LocalDateTime): Timestamp =
from(ldt.atZone(UTC))
def daysBetween(ts0: Timestamp, ts1: Timestamp): Long =
ChronoUnit.DAYS.between(ts0.toUtcDate, ts1.toUtcDate)
implicit val encodeTimestamp: Encoder[Timestamp] =
BaseJsonCodecs.encodeInstantEpoch.contramap(_.value)

View File

@ -11,6 +11,7 @@ case class MailContext(
items: List[MailContext.ItemData],
more: Boolean,
account: AccountId,
username: String,
itemUri: Option[LenientUri]
)
@ -20,12 +21,14 @@ object MailContext {
items: Vector[QItem.ListItem],
max: Int,
account: AccountId,
itemBaseUri: Option[LenientUri]
itemBaseUri: Option[LenientUri],
now: Timestamp
): MailContext =
MailContext(
items.take(max - 1).map(ItemData.apply).toList.sortBy(_.dueDate),
items.take(max - 1).map(ItemData(now)).toList.sortBy(_.dueDate),
items.sizeCompare(max) >= 0,
account,
account.user.id.capitalize,
itemBaseUri
)
@ -34,13 +37,22 @@ object MailContext {
name: String,
date: Timestamp,
dueDate: Option[Timestamp],
source: String
source: String,
overDue: Boolean,
dueIn: Option[String]
)
object ItemData {
def apply(i: QItem.ListItem): ItemData =
ItemData(i.id, i.name, i.date, i.dueDate, i.source)
def apply(now: Timestamp)(i: QItem.ListItem): ItemData = {
val dueIn = i.dueDate.map(dt => Timestamp.daysBetween(now, dt))
val dueInLabel = dueIn.map {
case 0 => "**today**"
case 1 => "**tomorrow**"
case n => s"in $n days"
}
ItemData(i.id, i.name, i.date, i.dueDate, i.source, dueIn.exists(_ < 0), dueInLabel)
}
implicit def yamusca: ValueConverter[ItemData] =
ValueConverter.deriveConverter[ItemData]

View File

@ -5,24 +5,26 @@ import yamusca.implicits._
object MailTemplate {
val text = mustache"""
## Hello {{{ account.user }}},
## Hello {{{ username }}},
this is Docspell informing you about due items coming up.
this is Docspell informing you about your next due items coming up.
{{#itemUri}}
{{#items}}
- [{{name}}]({{itemUri}}/{{id}}), due on *{{dueDate}}*
- {{#overDue}}**(OVERDUE)** {{/overDue}}[{{name}}]({{itemUri}}/{{id}}),
due {{dueIn}} on *{{dueDate}}*
(received on {{date}} via {{source}})
{{/items}}
{{/itemUri}}
{{^itemUri}}
{{#items}}
- *{{name}}*, due on *{{dueDate}}*
- {{#overDue}}**(OVERDUE)** {{/overDue}}*{{name}}*,
due {{dueIn}} on *{{dueDate}}*
(received on {{date}} via {{source}})
{{/items}}
{{/itemUri}}
{{#more}}
- (There are more due items, left out for brevity)
- more have been left out for brevity
{{/more}}

View File

@ -16,7 +16,7 @@ import docspell.joex.notify.MailContext
import docspell.joex.notify.MailTemplate
object NotifyDueItemsTask {
val maxItems: Long = 5
val maxItems: Long = 7
type Args = NotifyDueItemsArgs
def apply[F[_]: Sync](emil: Emil[F]): Task[F, Args, Unit] =
@ -83,21 +83,23 @@ object NotifyDueItemsTask {
cfg: RUserEmail,
args: Args,
items: Vector[QItem.ListItem]
): F[Mail[F]] = Sync[F].delay {
val templateCtx =
MailContext.from(items, maxItems.toInt, args.account, args.itemDetailUrl)
val md = MailTemplate.render(templateCtx)
val recp = args.recipients
.map(MailAddress.parse)
.map {
case Right(ma) => ma
case Left(err) => throw new Exception(s"Unable to parse recipient address: $err")
}
MailBuilder.build(
From(cfg.mailFrom),
Tos(recp),
Subject("Next due items"),
MarkdownBody[F](md)
)
}
): F[Mail[F]] =
Timestamp.current[F].map { now =>
val templateCtx =
MailContext.from(items, maxItems.toInt, args.account, args.itemDetailUrl, now)
val md = MailTemplate.render(templateCtx)
val recp = args.recipients
.map(MailAddress.parse)
.map {
case Right(ma) => ma
case Left(err) =>
throw new Exception(s"Unable to parse recipient address: $err")
}
MailBuilder.build(
From(cfg.mailFrom),
Tos(recp),
Subject("Next due items"),
MarkdownBody[F](md)
)
}
}