Manage notification channels separately and migrate

It's more convenient to manage notification channels separately, as it
is done with email settings. Notification hook and other forms are
adopted to only select channels. Hooks can now use more than one
channel.
This commit is contained in:
eikek
2022-01-19 21:51:18 +01:00
parent d41490dd88
commit 23cb34a6ff
78 changed files with 2583 additions and 1422 deletions

View File

@ -19,13 +19,14 @@ import io.circe.{Decoder, Encoder}
sealed trait Channel {
def id: Ident
def channelType: ChannelType
def name: Option[String]
def fold[A](
f1: Channel.Mail => A,
f2: Channel.Gotify => A,
f3: Channel.Matrix => A,
f4: Channel.Http => A
): A
def asRef: ChannelRef = ChannelRef(id, channelType)
def asRef: ChannelRef = ChannelRef(id, channelType, name)
}
object Channel {
@ -98,7 +99,8 @@ object Channel {
implicit val jsonEncoder: Encoder[Matrix] = deriveConfiguredEncoder
}
final case class Http(id: Ident, name: Option[String], url: LenientUri) extends Channel {
final case class Http(id: Ident, name: Option[String], url: LenientUri)
extends Channel {
val channelType = ChannelType.Http
def fold[A](
f1: Mail => A,

View File

@ -12,7 +12,7 @@ import io.circe.Decoder
import io.circe.Encoder
import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder}
final case class ChannelRef(id: Ident, channelType: ChannelType)
final case class ChannelRef(id: Ident, channelType: ChannelType, name: Option[String])
object ChannelRef {

View File

@ -6,9 +6,10 @@
package docspell.notification.api
import cats.data.NonEmptyList
import docspell.common._
import emil.MailAddress
import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
@ -21,7 +22,7 @@ import io.circe.{Decoder, Encoder}
*/
final case class PeriodicDueItemsArgs(
account: AccountId,
channel: ChannelOrRef,
channels: NonEmptyList[ChannelRef],
remindDays: Int,
daysBack: Option[Int],
tagsInclude: List[Ident],
@ -30,19 +31,11 @@ final case class PeriodicDueItemsArgs(
)
object PeriodicDueItemsArgs {
val taskName = Ident.unsafe("periodic-due-items-notify")
val taskName = Ident.unsafe("periodic-due-items-notify2")
implicit def jsonDecoder(implicit
mc: Decoder[MailAddress]
): Decoder[PeriodicDueItemsArgs] = {
implicit val x = ChannelOrRef.jsonDecoder
implicit val jsonDecoder: Decoder[PeriodicDueItemsArgs] =
semiauto.deriveDecoder
}
implicit def jsonEncoder(implicit
mc: Encoder[MailAddress]
): Encoder[PeriodicDueItemsArgs] = {
implicit val x = ChannelOrRef.jsonEncoder
implicit val jsonEncoder: Encoder[PeriodicDueItemsArgs] =
semiauto.deriveEncoder
}
}

View File

@ -6,15 +6,16 @@
package docspell.notification.api
import cats.data.NonEmptyList
import docspell.common._
import emil.MailAddress
import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
final case class PeriodicQueryArgs(
account: AccountId,
channel: ChannelOrRef,
channels: NonEmptyList[ChannelRef],
query: Option[ItemQueryString],
bookmark: Option[String],
baseUrl: Option[LenientUri],
@ -22,19 +23,11 @@ final case class PeriodicQueryArgs(
)
object PeriodicQueryArgs {
val taskName = Ident.unsafe("periodic-query-notify")
val taskName = Ident.unsafe("periodic-query-notify2")
implicit def jsonDecoder(implicit
mc: Decoder[MailAddress]
): Decoder[PeriodicQueryArgs] = {
implicit val x = ChannelOrRef.jsonDecoder
implicit val jsonDecoder: Decoder[PeriodicQueryArgs] =
semiauto.deriveDecoder
}
implicit def jsonEncoder(implicit
mc: Encoder[MailAddress]
): Encoder[PeriodicQueryArgs] = {
implicit val x = ChannelOrRef.jsonEncoder
implicit def jsonEncoder: Encoder[PeriodicQueryArgs] =
semiauto.deriveEncoder
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package docspell.notification
import emil.MailAddress
import io.circe.{Decoder, Encoder}
package object api {
type ChannelOrRef = Either[ChannelRef, Channel]
object ChannelOrRef {
implicit def jsonDecoder(implicit mc: Decoder[MailAddress]): Decoder[ChannelOrRef] =
Channel.jsonDecoder.either(ChannelRef.jsonDecoder).map(_.swap)
implicit def jsonEncoder(implicit mc: Encoder[MailAddress]): Encoder[ChannelOrRef] =
Encoder.instance(_.fold(ChannelRef.jsonEncoder.apply, Channel.jsonEncoder.apply))
implicit class ChannelOrRefOpts(cr: ChannelOrRef) {
def channelType: ChannelType =
cr.fold(_.channelType, _.channelType)
}
}
}