mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-04 06:05:59 +00:00
Improve mail template
This commit is contained in:
parent
ffc1cdee51
commit
d52efdfcf0
@ -4,6 +4,7 @@ import java.time.{Instant, LocalDate, ZoneId}
|
|||||||
|
|
||||||
import cats.effect.Sync
|
import cats.effect.Sync
|
||||||
import io.circe.{Decoder, Encoder}
|
import io.circe.{Decoder, Encoder}
|
||||||
|
import java.time.temporal.ChronoUnit
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
@ -59,6 +60,9 @@ object Timestamp {
|
|||||||
def atUtc(ldt: LocalDateTime): Timestamp =
|
def atUtc(ldt: LocalDateTime): Timestamp =
|
||||||
from(ldt.atZone(UTC))
|
from(ldt.atZone(UTC))
|
||||||
|
|
||||||
|
def daysBetween(ts0: Timestamp, ts1: Timestamp): Long =
|
||||||
|
ChronoUnit.DAYS.between(ts0.toUtcDate, ts1.toUtcDate)
|
||||||
|
|
||||||
implicit val encodeTimestamp: Encoder[Timestamp] =
|
implicit val encodeTimestamp: Encoder[Timestamp] =
|
||||||
BaseJsonCodecs.encodeInstantEpoch.contramap(_.value)
|
BaseJsonCodecs.encodeInstantEpoch.contramap(_.value)
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ case class MailContext(
|
|||||||
items: List[MailContext.ItemData],
|
items: List[MailContext.ItemData],
|
||||||
more: Boolean,
|
more: Boolean,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
|
username: String,
|
||||||
itemUri: Option[LenientUri]
|
itemUri: Option[LenientUri]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,12 +21,14 @@ object MailContext {
|
|||||||
items: Vector[QItem.ListItem],
|
items: Vector[QItem.ListItem],
|
||||||
max: Int,
|
max: Int,
|
||||||
account: AccountId,
|
account: AccountId,
|
||||||
itemBaseUri: Option[LenientUri]
|
itemBaseUri: Option[LenientUri],
|
||||||
|
now: Timestamp
|
||||||
): MailContext =
|
): MailContext =
|
||||||
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,
|
items.sizeCompare(max) >= 0,
|
||||||
account,
|
account,
|
||||||
|
account.user.id.capitalize,
|
||||||
itemBaseUri
|
itemBaseUri
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,13 +37,22 @@ object MailContext {
|
|||||||
name: String,
|
name: String,
|
||||||
date: Timestamp,
|
date: Timestamp,
|
||||||
dueDate: Option[Timestamp],
|
dueDate: Option[Timestamp],
|
||||||
source: String
|
source: String,
|
||||||
|
overDue: Boolean,
|
||||||
|
dueIn: Option[String]
|
||||||
)
|
)
|
||||||
|
|
||||||
object ItemData {
|
object ItemData {
|
||||||
|
|
||||||
def apply(i: QItem.ListItem): ItemData =
|
def apply(now: Timestamp)(i: QItem.ListItem): ItemData = {
|
||||||
ItemData(i.id, i.name, i.date, i.dueDate, i.source)
|
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] =
|
implicit def yamusca: ValueConverter[ItemData] =
|
||||||
ValueConverter.deriveConverter[ItemData]
|
ValueConverter.deriveConverter[ItemData]
|
||||||
|
@ -5,24 +5,26 @@ import yamusca.implicits._
|
|||||||
object MailTemplate {
|
object MailTemplate {
|
||||||
|
|
||||||
val text = mustache"""
|
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}}
|
{{#itemUri}}
|
||||||
{{#items}}
|
{{#items}}
|
||||||
- [{{name}}]({{itemUri}}/{{id}}), due on *{{dueDate}}*
|
- {{#overDue}}**(OVERDUE)** {{/overDue}}[{{name}}]({{itemUri}}/{{id}}),
|
||||||
|
due {{dueIn}} on *{{dueDate}}*
|
||||||
(received on {{date}} via {{source}})
|
(received on {{date}} via {{source}})
|
||||||
{{/items}}
|
{{/items}}
|
||||||
{{/itemUri}}
|
{{/itemUri}}
|
||||||
{{^itemUri}}
|
{{^itemUri}}
|
||||||
{{#items}}
|
{{#items}}
|
||||||
- *{{name}}*, due on *{{dueDate}}*
|
- {{#overDue}}**(OVERDUE)** {{/overDue}}*{{name}}*,
|
||||||
|
due {{dueIn}} on *{{dueDate}}*
|
||||||
(received on {{date}} via {{source}})
|
(received on {{date}} via {{source}})
|
||||||
{{/items}}
|
{{/items}}
|
||||||
{{/itemUri}}
|
{{/itemUri}}
|
||||||
{{#more}}
|
{{#more}}
|
||||||
- (There are more due items, left out for brevity)
|
- … more have been left out for brevity
|
||||||
{{/more}}
|
{{/more}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import docspell.joex.notify.MailContext
|
|||||||
import docspell.joex.notify.MailTemplate
|
import docspell.joex.notify.MailTemplate
|
||||||
|
|
||||||
object NotifyDueItemsTask {
|
object NotifyDueItemsTask {
|
||||||
val maxItems: Long = 5
|
val maxItems: Long = 7
|
||||||
type Args = NotifyDueItemsArgs
|
type Args = NotifyDueItemsArgs
|
||||||
|
|
||||||
def apply[F[_]: Sync](emil: Emil[F]): Task[F, Args, Unit] =
|
def apply[F[_]: Sync](emil: Emil[F]): Task[F, Args, Unit] =
|
||||||
@ -83,21 +83,23 @@ object NotifyDueItemsTask {
|
|||||||
cfg: RUserEmail,
|
cfg: RUserEmail,
|
||||||
args: Args,
|
args: Args,
|
||||||
items: Vector[QItem.ListItem]
|
items: Vector[QItem.ListItem]
|
||||||
): F[Mail[F]] = Sync[F].delay {
|
): F[Mail[F]] =
|
||||||
val templateCtx =
|
Timestamp.current[F].map { now =>
|
||||||
MailContext.from(items, maxItems.toInt, args.account, args.itemDetailUrl)
|
val templateCtx =
|
||||||
val md = MailTemplate.render(templateCtx)
|
MailContext.from(items, maxItems.toInt, args.account, args.itemDetailUrl, now)
|
||||||
val recp = args.recipients
|
val md = MailTemplate.render(templateCtx)
|
||||||
.map(MailAddress.parse)
|
val recp = args.recipients
|
||||||
.map {
|
.map(MailAddress.parse)
|
||||||
case Right(ma) => ma
|
.map {
|
||||||
case Left(err) => throw new Exception(s"Unable to parse recipient address: $err")
|
case Right(ma) => ma
|
||||||
}
|
case Left(err) =>
|
||||||
MailBuilder.build(
|
throw new Exception(s"Unable to parse recipient address: $err")
|
||||||
From(cfg.mailFrom),
|
}
|
||||||
Tos(recp),
|
MailBuilder.build(
|
||||||
Subject("Next due items"),
|
From(cfg.mailFrom),
|
||||||
MarkdownBody[F](md)
|
Tos(recp),
|
||||||
)
|
Subject("Next due items"),
|
||||||
}
|
MarkdownBody[F](md)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user