mirror of
				https://github.com/TheAnachronism/docspell.git
				synced 2025-10-31 09:30:12 +00:00 
			
		
		
		
	Remove obsolete code
This commit is contained in:
		| @@ -170,13 +170,6 @@ object JoexAppImpl extends MailAddressCodec { | ||||
|             ReProcessItem.onCancel[F] | ||||
|           ) | ||||
|         ) | ||||
|         .withTask( | ||||
|           JobTask.json( | ||||
|             NotifyDueItemsArgs.taskName, | ||||
|             NotifyDueItemsTask[F](cfg.sendMail, javaEmil), | ||||
|             NotifyDueItemsTask.onCancel[F] | ||||
|           ) | ||||
|         ) | ||||
|         .withTask( | ||||
|           JobTask.json( | ||||
|             ScanMailboxArgs.taskName, | ||||
|   | ||||
| @@ -1,83 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2020 Eike K. & Contributors | ||||
|  * | ||||
|  * SPDX-License-Identifier: AGPL-3.0-or-later | ||||
|  */ | ||||
|  | ||||
| package docspell.joex.notify | ||||
|  | ||||
| import docspell.common._ | ||||
| import docspell.joex.notify.YamuscaConverter._ | ||||
| import docspell.store.queries.ListItem | ||||
|  | ||||
| import yamusca.implicits._ | ||||
| import yamusca.imports._ | ||||
|  | ||||
| /** The context for rendering the e-mail template. */ | ||||
| case class MailContext( | ||||
|     items: List[MailContext.ItemData], | ||||
|     more: Boolean, | ||||
|     account: AccountId, | ||||
|     username: String, | ||||
|     itemUri: Option[LenientUri] | ||||
| ) | ||||
|  | ||||
| object MailContext { | ||||
|  | ||||
|   def from( | ||||
|       items: Vector[ListItem], | ||||
|       max: Int, | ||||
|       account: AccountId, | ||||
|       itemBaseUri: Option[LenientUri], | ||||
|       now: Timestamp | ||||
|   ): MailContext = | ||||
|     MailContext( | ||||
|       items.take(max - 1).map(ItemData(now)).toList.sortBy(_.dueDate), | ||||
|       items.sizeCompare(max) >= 0, | ||||
|       account, | ||||
|       account.user.id.capitalize, | ||||
|       itemBaseUri | ||||
|     ) | ||||
|  | ||||
|   case class ItemData( | ||||
|       id: Ident, | ||||
|       name: String, | ||||
|       date: Timestamp, | ||||
|       dueDate: Option[Timestamp], | ||||
|       source: String, | ||||
|       overDue: Boolean, | ||||
|       dueIn: Option[String], | ||||
|       corrOrg: Option[String] | ||||
|   ) | ||||
|  | ||||
|   object ItemData { | ||||
|  | ||||
|     def apply(now: Timestamp)(i: ListItem): ItemData = { | ||||
|       val dueIn = i.dueDate.map(dt => Timestamp.daysBetween(now, dt)) | ||||
|       val dueInLabel = dueIn.map { | ||||
|         case 0          => "**today**" | ||||
|         case 1          => "**tomorrow**" | ||||
|         case -1         => s"**yesterday**" | ||||
|         case n if n > 0 => s"in $n days" | ||||
|         case n          => s"${n * -1} days ago" | ||||
|       } | ||||
|       ItemData( | ||||
|         i.id, | ||||
|         i.name, | ||||
|         i.date, | ||||
|         i.dueDate, | ||||
|         i.source, | ||||
|         dueIn.exists(_ < 0), | ||||
|         dueInLabel, | ||||
|         i.corrOrg.map(_.name) | ||||
|       ) | ||||
|     } | ||||
|  | ||||
|     implicit def yamusca: ValueConverter[ItemData] = | ||||
|       ValueConverter.deriveConverter[ItemData] | ||||
|   } | ||||
|  | ||||
|   implicit val yamusca: ValueConverter[MailContext] = | ||||
|     ValueConverter.deriveConverter[MailContext] | ||||
|  | ||||
| } | ||||
| @@ -1,44 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2020 Eike K. & Contributors | ||||
|  * | ||||
|  * SPDX-License-Identifier: AGPL-3.0-or-later | ||||
|  */ | ||||
|  | ||||
| package docspell.joex.notify | ||||
|  | ||||
| import yamusca.implicits._ | ||||
|  | ||||
| object MailTemplate { | ||||
|  | ||||
|   val text = mustache""" | ||||
| Hello {{{ username }}}, | ||||
|  | ||||
| this is Docspell informing you about your next due items coming up. | ||||
|  | ||||
| {{#itemUri}} | ||||
| {{#items}} | ||||
| - {{#overDue}}**(OVERDUE)** {{/overDue}}[{{name}}]({{itemUri}}/{{id}}), | ||||
|   {{#overDue}}was {{/overDue}}due {{dueIn}} on *{{dueDate}}*; {{#corrOrg}}from {{corrOrg}}{{/corrOrg}} | ||||
|   received on {{date}} via {{source}} | ||||
| {{/items}} | ||||
| {{/itemUri}} | ||||
| {{^itemUri}} | ||||
| {{#items}} | ||||
| - {{#overDue}}**(OVERDUE)** {{/overDue}}*{{name}}*, | ||||
|   {{#overDue}}was {{/overDue}}due {{dueIn}} on *{{dueDate}}*; {{#corrOrg}}from {{corrOrg}}{{/corrOrg}} | ||||
|   received on {{date}} via {{source}} | ||||
| {{/items}} | ||||
| {{/itemUri}} | ||||
| {{#more}} | ||||
| - … more have been left out for brevity | ||||
| {{/more}} | ||||
|  | ||||
|  | ||||
| Sincerely yours, | ||||
|  | ||||
| Docspell | ||||
| """ | ||||
|  | ||||
|   def render(mc: MailContext): String = | ||||
|     mc.render(text) | ||||
| } | ||||
| @@ -1,140 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2020 Eike K. & Contributors | ||||
|  * | ||||
|  * SPDX-License-Identifier: AGPL-3.0-or-later | ||||
|  */ | ||||
|  | ||||
| package docspell.joex.notify | ||||
|  | ||||
| import cats.data.{NonEmptyList => Nel, OptionT} | ||||
| import cats.effect._ | ||||
| import cats.implicits._ | ||||
|  | ||||
| import docspell.backend.ops.OItemSearch.{Batch, ListItem, Query} | ||||
| import docspell.common._ | ||||
| import docspell.joex.mail.EmilHeader | ||||
| import docspell.joex.scheduler.{Context, Task} | ||||
| import docspell.query.Date | ||||
| import docspell.query.ItemQuery._ | ||||
| import docspell.query.ItemQueryDsl._ | ||||
| import docspell.store.queries.QItem | ||||
| import docspell.store.records._ | ||||
|  | ||||
| import emil._ | ||||
| import emil.builder._ | ||||
| import emil.javamail.syntax._ | ||||
| import emil.markdown._ | ||||
|  | ||||
| object NotifyDueItemsTask { | ||||
|   val maxItems: Int = 7 | ||||
|   type Args = NotifyDueItemsArgs | ||||
|  | ||||
|   def apply[F[_]: Sync](cfg: MailSendConfig, emil: Emil[F]): Task[F, Args, Unit] = | ||||
|     Task { ctx => | ||||
|       for { | ||||
|         _ <- ctx.logger.info("Getting mail configuration") | ||||
|         mailCfg <- getMailSettings(ctx) | ||||
|         _ <- ctx.logger.info( | ||||
|           s"Searching for items due in ${ctx.args.remindDays} days…." | ||||
|         ) | ||||
|         _ <- createMail(cfg, mailCfg, ctx) | ||||
|           .semiflatMap { mail => | ||||
|             for { | ||||
|               _ <- ctx.logger.info(s"Sending notification mail to ${ctx.args.recipients}") | ||||
|               res <- emil(mailCfg.toMailConfig).send(mail).map(_.head) | ||||
|               _ <- ctx.logger.info(s"Sent mail with id: $res") | ||||
|             } yield () | ||||
|           } | ||||
|           .getOrElseF(ctx.logger.info("No items found")) | ||||
|       } yield () | ||||
|     } | ||||
|  | ||||
|   def onCancel[F[_]]: Task[F, NotifyDueItemsArgs, Unit] = | ||||
|     Task.log(_.warn("Cancelling notify-due-items task")) | ||||
|  | ||||
|   def getMailSettings[F[_]: Sync](ctx: Context[F, Args]): F[RUserEmail] = | ||||
|     ctx.store | ||||
|       .transact(RUserEmail.getByName(ctx.args.account, ctx.args.smtpConnection)) | ||||
|       .flatMap { | ||||
|         case Some(c) => c.pure[F] | ||||
|         case None => | ||||
|           Sync[F].raiseError( | ||||
|             new Exception( | ||||
|               s"No smtp configuration found for: ${ctx.args.smtpConnection.id}" | ||||
|             ) | ||||
|           ) | ||||
|       } | ||||
|  | ||||
|   def createMail[F[_]: Sync]( | ||||
|       sendCfg: MailSendConfig, | ||||
|       cfg: RUserEmail, | ||||
|       ctx: Context[F, Args] | ||||
|   ): OptionT[F, Mail[F]] = | ||||
|     for { | ||||
|       items <- OptionT.liftF(findItems(ctx)).filter(_.nonEmpty) | ||||
|       mail <- OptionT.liftF(makeMail(sendCfg, cfg, ctx.args, items)) | ||||
|     } yield mail | ||||
|  | ||||
|   def findItems[F[_]: Sync](ctx: Context[F, Args]): F[Vector[ListItem]] = | ||||
|     for { | ||||
|       now <- Timestamp.current[F] | ||||
|       rightDate = Date((now + Duration.days(ctx.args.remindDays.toLong)).toMillis) | ||||
|       q = | ||||
|         Query | ||||
|           .all(ctx.args.account) | ||||
|           .withOrder(orderAsc = _.dueDate) | ||||
|           .withFix(_.copy(query = Expr.ValidItemStates.some)) | ||||
|           .withCond(_ => | ||||
|             Query.QueryExpr( | ||||
|               Attr.DueDate <= rightDate &&? | ||||
|                 ctx.args.daysBack.map(back => | ||||
|                   Attr.DueDate >= Date((now - Duration.days(back.toLong)).toMillis) | ||||
|                 ) &&? | ||||
|                 Nel | ||||
|                   .fromList(ctx.args.tagsInclude) | ||||
|                   .map(ids => Q.tagIdsEq(ids.map(_.id))) &&? | ||||
|                 Nel | ||||
|                   .fromList(ctx.args.tagsExclude) | ||||
|                   .map(ids => Q.tagIdsIn(ids.map(_.id)).negate) | ||||
|             ) | ||||
|           ) | ||||
|       res <- | ||||
|         ctx.store | ||||
|           .transact( | ||||
|             QItem | ||||
|               .findItems(q, now.toUtcDate, 0, Batch.limit(maxItems)) | ||||
|               .take(maxItems.toLong) | ||||
|           ) | ||||
|           .compile | ||||
|           .toVector | ||||
|     } yield res | ||||
|  | ||||
|   def makeMail[F[_]: Sync]( | ||||
|       sendCfg: MailSendConfig, | ||||
|       cfg: RUserEmail, | ||||
|       args: Args, | ||||
|       items: Vector[ListItem] | ||||
|   ): 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), | ||||
|         XMailer.emil, | ||||
|         Subject("[Docspell] Next due items"), | ||||
|         EmilHeader.listId(sendCfg.listId), | ||||
|         MarkdownBody[F](md).withConfig( | ||||
|           MarkdownConfig("body { font-size: 10pt; font-family: sans-serif; }") | ||||
|         ) | ||||
|       ) | ||||
|     } | ||||
| } | ||||
| @@ -12,6 +12,13 @@ import emil.MailAddress | ||||
| import io.circe.generic.semiauto | ||||
| import io.circe.{Decoder, Encoder} | ||||
|  | ||||
| /** Arguments to the notification task. | ||||
|   * | ||||
|   * This tasks queries items with a due date and informs the user via mail. | ||||
|   * | ||||
|   * If the structure changes, there must be some database migration to update or remove | ||||
|   * the json data of the corresponding task. | ||||
|   */ | ||||
| final case class PeriodicDueItemsArgs( | ||||
|     account: AccountId, | ||||
|     channel: ChannelOrRef, | ||||
|   | ||||
| @@ -17,6 +17,9 @@ import io.circe.generic.semiauto._ | ||||
|   * | ||||
|   * If the structure changes, there must be some database migration to update or remove | ||||
|   * the json data of the corresponding task. | ||||
|   * | ||||
|   * @deprecated note: This has been removed and copied to this place to be able to | ||||
|   * migrate away from this structure. Replaced by PeriodicDueItemsArgs | ||||
|   */ | ||||
| case class NotifyDueItemsArgs( | ||||
|     account: AccountId, | ||||
		Reference in New Issue
	
	Block a user