Add a name to notification channels

This name is supposed to be used by users to distinguish multiple channels.
This commit is contained in:
eikek
2022-01-17 14:15:07 +01:00
parent 44e599dc86
commit d41490dd88
13 changed files with 140 additions and 40 deletions

View File

@ -254,11 +254,18 @@ object ONotification {
private[ops] def makeChannel(r: RNotificationChannel): Channel = private[ops] def makeChannel(r: RNotificationChannel): Channel =
r.fold( r.fold(
mail => mail =>
Channel.Mail(mail.id, mail.connection, Nel.fromListUnsafe(mail.recipients)), Channel.Mail(
gotify => Channel.Gotify(r.id, gotify.url, gotify.appKey, gotify.priority), mail.id,
mail.name,
mail.connection,
Nel.fromListUnsafe(mail.recipients)
),
gotify =>
Channel.Gotify(r.id, gotify.name, gotify.url, gotify.appKey, gotify.priority),
matrix => matrix =>
Channel.Matrix(r.id, matrix.homeServer, matrix.roomId, matrix.accessToken), Channel
http => Channel.Http(r.id, http.url) .Matrix(r.id, matrix.name, matrix.homeServer, matrix.roomId, matrix.accessToken),
http => Channel.Http(r.id, http.name, http.url)
) )
private[ops] def makeRecord[F[_]: Sync]( private[ops] def makeRecord[F[_]: Sync](
@ -278,7 +285,7 @@ object ONotification {
time <- OptionT.liftF(Timestamp.current[F]) time <- OptionT.liftF(Timestamp.current[F])
r <- r <-
channel match { channel match {
case Channel.Mail(_, conn, recipients) => case Channel.Mail(_, name, conn, recipients) =>
for { for {
_ <- OptionT.liftF( _ <- OptionT.liftF(
logger.debug( logger.debug(
@ -291,20 +298,30 @@ object ONotification {
rec = RNotificationChannelMail( rec = RNotificationChannelMail(
id, id,
userId, userId,
name,
mailConn.id, mailConn.id,
recipients.toList, recipients.toList,
time time
).vary ).vary
} yield rec } yield rec
case Channel.Gotify(_, url, appKey, prio) => case Channel.Gotify(_, name, url, appKey, prio) =>
OptionT.pure[F]( OptionT.pure[F](
RNotificationChannelGotify(id, userId, url, appKey, prio, time).vary RNotificationChannelGotify(
id,
userId,
name,
url,
appKey,
prio,
time
).vary
) )
case Channel.Matrix(_, homeServer, roomId, accessToken) => case Channel.Matrix(_, name, homeServer, roomId, accessToken) =>
OptionT.pure[F]( OptionT.pure[F](
RNotificationChannelMatrix( RNotificationChannelMatrix(
id, id,
userId, userId,
name,
homeServer, homeServer,
roomId, roomId,
accessToken, accessToken,
@ -312,8 +329,10 @@ object ONotification {
time time
).vary ).vary
) )
case Channel.Http(_, url) => case Channel.Http(_, name, url) =>
OptionT.pure[F](RNotificationChannelHttp(id, userId, url, time).vary) OptionT.pure[F](
RNotificationChannelHttp(id, userId, name, url, time).vary
)
} }
} yield r } yield r
} }

View File

@ -33,6 +33,7 @@ object Channel {
final case class Mail( final case class Mail(
id: Ident, id: Ident,
name: Option[String],
connection: Ident, connection: Ident,
recipients: Nel[MailAddress] recipients: Nel[MailAddress]
) extends Channel { ) extends Channel {
@ -55,6 +56,7 @@ object Channel {
final case class Gotify( final case class Gotify(
id: Ident, id: Ident,
name: Option[String],
url: LenientUri, url: LenientUri,
appKey: Password, appKey: Password,
priority: Option[Int] priority: Option[Int]
@ -77,6 +79,7 @@ object Channel {
final case class Matrix( final case class Matrix(
id: Ident, id: Ident,
name: Option[String],
homeServer: LenientUri, homeServer: LenientUri,
roomId: String, roomId: String,
accessToken: Password accessToken: Password
@ -95,7 +98,7 @@ object Channel {
implicit val jsonEncoder: Encoder[Matrix] = deriveConfiguredEncoder implicit val jsonEncoder: Encoder[Matrix] = deriveConfiguredEncoder
} }
final case class Http(id: Ident, url: LenientUri) extends Channel { final case class Http(id: Ident, name: Option[String], url: LenientUri) extends Channel {
val channelType = ChannelType.Http val channelType = ChannelType.Http
def fold[A]( def fold[A](
f1: Mail => A, f1: Mail => A,

View File

@ -5491,6 +5491,8 @@ components:
id: id:
type: string type: string
format: ident format: ident
name:
type: string
channelType: channelType:
type: string type: string
format: channeltype format: channeltype
@ -5514,6 +5516,8 @@ components:
id: id:
type: string type: string
format: ident format: ident
name:
type: string
channelType: channelType:
type: string type: string
format: channeltype format: channeltype
@ -5539,6 +5543,8 @@ components:
id: id:
type: string type: string
format: ident format: ident
name:
type: string
channelType: channelType:
type: string type: string
format: channeltype format: channeltype
@ -5557,6 +5563,8 @@ components:
id: id:
type: string type: string
format: ident format: ident
name:
type: string
channelType: channelType:
type: string type: string
format: channeltype format: channeltype

View File

@ -73,15 +73,24 @@ object NotificationChannel {
.map(NonEmptyList.fromList) .map(NonEmptyList.fromList)
.flatMap(_.toRight("No recipients given!")) .flatMap(_.toRight("No recipients given!"))
.leftMap(new IllegalArgumentException(_)) .leftMap(new IllegalArgumentException(_))
.map(rec => Channel.Mail(mail.id, mail.connection, rec)), .map(rec => Channel.Mail(mail.id, mail.name, mail.connection, rec)),
gotify => gotify =>
Right(Channel.Gotify(gotify.id, gotify.url, gotify.appKey, gotify.priority)), Right(
Channel
.Gotify(gotify.id, gotify.name, gotify.url, gotify.appKey, gotify.priority)
),
matrix => matrix =>
Right( Right(
Channel Channel
.Matrix(matrix.id, matrix.homeServer, matrix.roomId, matrix.accessToken) .Matrix(
matrix.id,
matrix.name,
matrix.homeServer,
matrix.roomId,
matrix.accessToken
)
), ),
http => Right(Channel.Http(http.id, http.url)) http => Right(Channel.Http(http.id, http.name, http.url))
) )
def convert(c: Channel): NotificationChannel = def convert(c: Channel): NotificationChannel =
@ -90,24 +99,35 @@ object NotificationChannel {
mail { mail {
NotificationMail( NotificationMail(
m.id, m.id,
m.name,
ChannelType.Mail, ChannelType.Mail,
m.connection, m.connection,
m.recipients.toList.map(_.displayString) m.recipients.toList.map(_.displayString)
) )
}, },
g => g =>
gotify(NotificationGotify(g.id, ChannelType.Gotify, g.url, g.appKey, g.priority)), gotify(
NotificationGotify(
g.id,
g.name,
ChannelType.Gotify,
g.url,
g.appKey,
g.priority
)
),
m => m =>
matrix( matrix(
NotificationMatrix( NotificationMatrix(
m.id, m.id,
m.name,
ChannelType.Matrix, ChannelType.Matrix,
m.homeServer, m.homeServer,
m.roomId, m.roomId,
m.accessToken m.accessToken
) )
), ),
h => http(NotificationHttp(h.id, ChannelType.Http, h.url)) h => http(NotificationHttp(h.id, h.name, ChannelType.Http, h.url))
) )
implicit val jsonDecoder: Decoder[NotificationChannel] = implicit val jsonDecoder: Decoder[NotificationChannel] =

View File

@ -0,0 +1,11 @@
alter table "notification_channel_mail"
add column "name" varchar(254);
alter table "notification_channel_gotify"
add column "name" varchar(254);
alter table "notification_channel_matrix"
add column "name" varchar(254);
alter table "notification_channel_http"
add column "name" varchar(254);

View File

@ -0,0 +1,11 @@
alter table `notification_channel_mail`
add column `name` varchar(254);
alter table `notification_channel_gotify`
add column `name` varchar(254);
alter table `notification_channel_matrix`
add column `name` varchar(254);
alter table `notification_channel_http`
add column `name` varchar(254);

View File

@ -0,0 +1,11 @@
alter table "notification_channel_mail"
add column "name" varchar(254);
alter table "notification_channel_gotify"
add column "name" varchar(254);
alter table "notification_channel_matrix"
add column "name" varchar(254);
alter table "notification_channel_http"
add column "name" varchar(254);

View File

@ -70,7 +70,7 @@ trait MigrationTasks {
.map { rec => .map { rec =>
PeriodicDueItemsArgs( PeriodicDueItemsArgs(
old.account, old.account,
Right(Channel.Mail(Ident.unsafe(""), old.smtpConnection, rec)), Right(Channel.Mail(Ident.unsafe(""), None, old.smtpConnection, rec)),
old.remindDays, old.remindDays,
old.daysBack, old.daysBack,
old.tagsInclude, old.tagsInclude,

View File

@ -16,7 +16,9 @@ import doobie._
sealed trait RNotificationChannel { sealed trait RNotificationChannel {
def id: Ident def id: Ident = fold(_.id, _.id, _.id, _.id)
def name: Option[String] = fold(_.name, _.name, _.name, _.name)
def fold[A]( def fold[A](
f1: RNotificationChannelMail => A, f1: RNotificationChannelMail => A,
@ -24,7 +26,6 @@ sealed trait RNotificationChannel {
f3: RNotificationChannelMatrix => A, f3: RNotificationChannelMatrix => A,
f4: RNotificationChannelHttp => A f4: RNotificationChannelHttp => A
): A ): A
} }
object RNotificationChannel { object RNotificationChannel {
@ -37,8 +38,6 @@ object RNotificationChannel {
f3: RNotificationChannelMatrix => A, f3: RNotificationChannelMatrix => A,
f4: RNotificationChannelHttp => A f4: RNotificationChannelHttp => A
): A = f1(r) ): A = f1(r)
val id = r.id
} }
final case class Gotify(r: RNotificationChannelGotify) extends RNotificationChannel { final case class Gotify(r: RNotificationChannelGotify) extends RNotificationChannel {
@ -48,8 +47,6 @@ object RNotificationChannel {
f3: RNotificationChannelMatrix => A, f3: RNotificationChannelMatrix => A,
f4: RNotificationChannelHttp => A f4: RNotificationChannelHttp => A
): A = f2(r) ): A = f2(r)
val id = r.id
} }
final case class Matrix(r: RNotificationChannelMatrix) extends RNotificationChannel { final case class Matrix(r: RNotificationChannelMatrix) extends RNotificationChannel {
@ -59,8 +56,6 @@ object RNotificationChannel {
f3: RNotificationChannelMatrix => A, f3: RNotificationChannelMatrix => A,
f4: RNotificationChannelHttp => A f4: RNotificationChannelHttp => A
): A = f3(r) ): A = f3(r)
val id = r.id
} }
final case class Http(r: RNotificationChannelHttp) extends RNotificationChannel { final case class Http(r: RNotificationChannelHttp) extends RNotificationChannel {
@ -70,8 +65,6 @@ object RNotificationChannel {
f3: RNotificationChannelMatrix => A, f3: RNotificationChannelMatrix => A,
f4: RNotificationChannelHttp => A f4: RNotificationChannelHttp => A
): A = f4(r) ): A = f4(r)
val id = r.id
} }
def insert(r: RNotificationChannel): ConnectionIO[Int] = def insert(r: RNotificationChannel): ConnectionIO[Int] =

View File

@ -18,6 +18,7 @@ import doobie.implicits._
final case class RNotificationChannelGotify( final case class RNotificationChannelGotify(
id: Ident, id: Ident,
uid: Ident, uid: Ident,
name: Option[String],
url: LenientUri, url: LenientUri,
appKey: Password, appKey: Password,
priority: Option[Int], priority: Option[Int],
@ -34,13 +35,14 @@ object RNotificationChannelGotify {
val id = Column[Ident]("id", this) val id = Column[Ident]("id", this)
val uid = Column[Ident]("uid", this) val uid = Column[Ident]("uid", this)
val name = Column[String]("name", this)
val url = Column[LenientUri]("url", this) val url = Column[LenientUri]("url", this)
val appKey = Column[Password]("app_key", this) val appKey = Column[Password]("app_key", this)
val priority = Column[Int]("priority", this) val priority = Column[Int]("priority", this)
val created = Column[Timestamp]("created", this) val created = Column[Timestamp]("created", this)
val all: NonEmptyList[Column[_]] = val all: NonEmptyList[Column[_]] =
NonEmptyList.of(id, uid, url, appKey, priority, created) NonEmptyList.of(id, uid, name, url, appKey, priority, created)
} }
val T: Table = Table(None) val T: Table = Table(None)
@ -54,7 +56,7 @@ object RNotificationChannelGotify {
DML.insert( DML.insert(
T, T,
T.all, T.all,
sql"${r.id},${r.uid},${r.url},${r.appKey},${r.priority},${r.created}" sql"${r.id},${r.uid},${r.name},${r.url},${r.appKey},${r.priority},${r.created}"
) )
def update(r: RNotificationChannelGotify): ConnectionIO[Int] = def update(r: RNotificationChannelGotify): ConnectionIO[Int] =
@ -64,7 +66,8 @@ object RNotificationChannelGotify {
DML.set( DML.set(
T.url.setTo(r.url), T.url.setTo(r.url),
T.appKey.setTo(r.appKey), T.appKey.setTo(r.appKey),
T.priority.setTo(r.priority) T.priority.setTo(r.priority),
T.name.setTo(r.name)
) )
) )

View File

@ -18,6 +18,7 @@ import doobie.implicits._
final case class RNotificationChannelHttp( final case class RNotificationChannelHttp(
id: Ident, id: Ident,
uid: Ident, uid: Ident,
name: Option[String],
url: LenientUri, url: LenientUri,
created: Timestamp created: Timestamp
) { ) {
@ -32,11 +33,12 @@ object RNotificationChannelHttp {
val id = Column[Ident]("id", this) val id = Column[Ident]("id", this)
val uid = Column[Ident]("uid", this) val uid = Column[Ident]("uid", this)
val name = Column[String]("name", this)
val url = Column[LenientUri]("url", this) val url = Column[LenientUri]("url", this)
val created = Column[Timestamp]("created", this) val created = Column[Timestamp]("created", this)
val all: NonEmptyList[Column[_]] = val all: NonEmptyList[Column[_]] =
NonEmptyList.of(id, uid, url, created) NonEmptyList.of(id, uid, name, url, created)
} }
val T: Table = Table(None) val T: Table = Table(None)
@ -47,10 +49,14 @@ object RNotificationChannelHttp {
run(select(T.all), from(T), T.id === id).query[RNotificationChannelHttp].option run(select(T.all), from(T), T.id === id).query[RNotificationChannelHttp].option
def insert(r: RNotificationChannelHttp): ConnectionIO[Int] = def insert(r: RNotificationChannelHttp): ConnectionIO[Int] =
DML.insert(T, T.all, sql"${r.id},${r.uid},${r.url},${r.created}") DML.insert(T, T.all, sql"${r.id},${r.uid},${r.name},${r.url},${r.created}")
def update(r: RNotificationChannelHttp): ConnectionIO[Int] = def update(r: RNotificationChannelHttp): ConnectionIO[Int] =
DML.update(T, T.id === r.id && T.uid === r.uid, DML.set(T.url.setTo(r.url))) DML.update(
T,
T.id === r.id && T.uid === r.uid,
DML.set(T.url.setTo(r.url), T.name.setTo(r.name))
)
def getByAccount(account: AccountId): ConnectionIO[Vector[RNotificationChannelHttp]] = { def getByAccount(account: AccountId): ConnectionIO[Vector[RNotificationChannelHttp]] = {
val user = RUser.as("u") val user = RUser.as("u")

View File

@ -19,6 +19,7 @@ import emil.MailAddress
final case class RNotificationChannelMail( final case class RNotificationChannelMail(
id: Ident, id: Ident,
uid: Ident, uid: Ident,
name: Option[String],
connection: Ident, connection: Ident,
recipients: List[MailAddress], recipients: List[MailAddress],
created: Timestamp created: Timestamp
@ -34,12 +35,13 @@ object RNotificationChannelMail {
val id = Column[Ident]("id", this) val id = Column[Ident]("id", this)
val uid = Column[Ident]("uid", this) val uid = Column[Ident]("uid", this)
val name = Column[String]("name", this)
val connection = Column[Ident]("conn_id", this) val connection = Column[Ident]("conn_id", this)
val recipients = Column[List[MailAddress]]("recipients", this) val recipients = Column[List[MailAddress]]("recipients", this)
val created = Column[Timestamp]("created", this) val created = Column[Timestamp]("created", this)
val all: NonEmptyList[Column[_]] = val all: NonEmptyList[Column[_]] =
NonEmptyList.of(id, uid, connection, recipients, created) NonEmptyList.of(id, uid, name, connection, recipients, created)
} }
val T: Table = Table(None) val T: Table = Table(None)
@ -49,7 +51,7 @@ object RNotificationChannelMail {
DML.insert( DML.insert(
T, T,
T.all, T.all,
sql"${r.id},${r.uid},${r.connection},${r.recipients},${r.created}" sql"${r.id},${r.uid},${r.name},${r.connection},${r.recipients},${r.created}"
) )
def update(r: RNotificationChannelMail): ConnectionIO[Int] = def update(r: RNotificationChannelMail): ConnectionIO[Int] =
@ -58,7 +60,8 @@ object RNotificationChannelMail {
T.id === r.id && T.uid === r.uid, T.id === r.id && T.uid === r.uid,
DML.set( DML.set(
T.connection.setTo(r.connection), T.connection.setTo(r.connection),
T.recipients.setTo(r.recipients.toList) T.recipients.setTo(r.recipients.toList),
T.name.setTo(r.name)
) )
) )

View File

@ -18,6 +18,7 @@ import doobie.implicits._
final case class RNotificationChannelMatrix( final case class RNotificationChannelMatrix(
id: Ident, id: Ident,
uid: Ident, uid: Ident,
name: Option[String],
homeServer: LenientUri, homeServer: LenientUri,
roomId: String, roomId: String,
accessToken: Password, accessToken: Password,
@ -34,6 +35,7 @@ object RNotificationChannelMatrix {
val id = Column[Ident]("id", this) val id = Column[Ident]("id", this)
val uid = Column[Ident]("uid", this) val uid = Column[Ident]("uid", this)
val name = Column[String]("name", this)
val homeServer = Column[LenientUri]("home_server", this) val homeServer = Column[LenientUri]("home_server", this)
val roomId = Column[String]("room_id", this) val roomId = Column[String]("room_id", this)
val accessToken = Column[Password]("access_token", this) val accessToken = Column[Password]("access_token", this)
@ -41,7 +43,16 @@ object RNotificationChannelMatrix {
val created = Column[Timestamp]("created", this) val created = Column[Timestamp]("created", this)
val all: NonEmptyList[Column[_]] = val all: NonEmptyList[Column[_]] =
NonEmptyList.of(id, uid, homeServer, roomId, accessToken, messageType, created) NonEmptyList.of(
id,
uid,
name,
homeServer,
roomId,
accessToken,
messageType,
created
)
} }
val T: Table = Table(None) val T: Table = Table(None)
def as(alias: String): Table = Table(Some(alias)) def as(alias: String): Table = Table(Some(alias))
@ -50,7 +61,7 @@ object RNotificationChannelMatrix {
DML.insert( DML.insert(
T, T,
T.all, T.all,
sql"${r.id},${r.uid},${r.homeServer},${r.roomId},${r.accessToken},${r.messageType},${r.created}" sql"${r.id},${r.uid},${r.name},${r.homeServer},${r.roomId},${r.accessToken},${r.messageType},${r.created}"
) )
def update(r: RNotificationChannelMatrix): ConnectionIO[Int] = def update(r: RNotificationChannelMatrix): ConnectionIO[Int] =
@ -61,7 +72,8 @@ object RNotificationChannelMatrix {
T.homeServer.setTo(r.homeServer), T.homeServer.setTo(r.homeServer),
T.roomId.setTo(r.roomId), T.roomId.setTo(r.roomId),
T.accessToken.setTo(r.accessToken), T.accessToken.setTo(r.accessToken),
T.messageType.setTo(r.messageType) T.messageType.setTo(r.messageType),
T.name.setTo(r.name)
) )
) )