diff --git a/modules/backend/src/main/scala/docspell/backend/ops/ONotification.scala b/modules/backend/src/main/scala/docspell/backend/ops/ONotification.scala index 992955fa..ca727af6 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/ONotification.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/ONotification.scala @@ -34,7 +34,10 @@ trait ONotification[F[_]] { def offerEvents(ev: Iterable[Event]): F[Unit] - def mkNotificationChannel(channel: Channel): F[Vector[NotificationChannel]] + def mkNotificationChannel( + channel: Channel, + userId: Ident + ): F[Vector[NotificationChannel]] def findNotificationChannel(ref: ChannelRef): F[Vector[NotificationChannel]] @@ -109,22 +112,30 @@ object ONotification { channel: Channel, account: AccountId, baseUrl: Option[LenientUri] - ): F[SendTestResult] = - (for { - ev <- sampleEvent(evt, account, baseUrl) - logbuf <- Logger.buffer() - ch <- mkNotificationChannel(channel) - _ <- notMod.send(logbuf._2.andThen(log), ev, ch) - logs <- logbuf._1.get - res = SendTestResult(true, logs) - } yield res).attempt - .map { - case Right(res) => res - case Left(ex) => - val ps = new StringWriter() - ex.printStackTrace(new PrintWriter(ps)) - SendTestResult(false, Vector(s"${ex.getMessage}\n$ps")) - } + ): F[SendTestResult] = { + def doCreate(userId: Ident) = + (for { + ev <- sampleEvent(evt, account, baseUrl) + logbuf <- Logger.buffer() + ch <- mkNotificationChannel(channel, userId) + _ <- notMod.send(logbuf._2.andThen(log), ev, ch) + logs <- logbuf._1.get + res = SendTestResult(true, logs) + } yield res).attempt + .map { + case Right(res) => res + case Left(ex) => + val ps = new StringWriter() + ex.printStackTrace(new PrintWriter(ps)) + SendTestResult(false, Vector(s"${ex.getMessage}\n$ps")) + } + + OptionT(store.transact(RUser.findIdByAccount(account))) + .semiflatMap(doCreate) + .getOrElse( + SendTestResult(false, Vector(s"No user found in db for: ${account.asString}")) + ) + } def listChannels(account: AccountId): F[Vector[Channel]] = store @@ -142,7 +153,7 @@ object ONotification { (for { newId <- OptionT.liftF(Ident.randomId[F]) userId <- OptionT(store.transact(RUser.findIdByAccount(account))) - r <- ChannelConv.makeRecord[F](store, Right(channel), newId, userId) + r <- ChannelConv.makeRecord[F](store, log, Right(channel), newId, userId) _ <- OptionT.liftF(store.transact(RNotificationChannel.insert(r))) _ <- OptionT.liftF(log.debug(s"Created channel $r for $account")) } yield AddResult.Success) @@ -151,7 +162,7 @@ object ONotification { def updateChannel(channel: Channel, account: AccountId): F[UpdateResult] = (for { userId <- OptionT(store.transact(RUser.findIdByAccount(account))) - r <- ChannelConv.makeRecord[F](store, Right(channel), channel.id, userId) + r <- ChannelConv.makeRecord[F](store, log, Right(channel), channel.id, userId) n <- OptionT.liftF(store.transact(RNotificationChannel.update(r))) } yield UpdateResult.fromUpdateRows(n)).getOrElse(UpdateResult.notFound) @@ -170,7 +181,7 @@ object ONotification { _ <- OptionT.liftF(log.debug(s"Creating new notification hook: $hook")) channelId <- OptionT.liftF(Ident.randomId[F]) userId <- OptionT(store.transact(RUser.findIdByAccount(account))) - r <- ChannelConv.makeRecord[F](store, hook.channel, channelId, userId) + r <- ChannelConv.makeRecord[F](store, log, hook.channel, channelId, userId) _ <- OptionT.liftF( if (channelId == r.id) store.transact(RNotificationChannel.insert(r)) else ().pure[F] @@ -196,7 +207,7 @@ object ONotification { r: RNotificationHook )(f: RNotificationChannel => F[UpdateResult]): F[UpdateResult] = ChannelConv - .makeRecord(store, hook.channel, r.channelId, r.uid) + .makeRecord(store, log, hook.channel, r.channelId, r.uid) .semiflatMap(f) .getOrElse(UpdateResult.notFound) @@ -221,10 +232,13 @@ object ONotification { withHook(doUpdate) } - def mkNotificationChannel(channel: Channel): F[Vector[NotificationChannel]] = + def mkNotificationChannel( + channel: Channel, + userId: Ident + ): F[Vector[NotificationChannel]] = (for { rec <- ChannelConv - .makeRecord(store, Right(channel), channel.id, Ident.unsafe("")) + .makeRecord(store, log, Right(channel), channel.id, userId) ch <- OptionT.liftF(store.transact(QNotification.readChannel(rec))) } yield ch).getOrElse(Vector.empty) @@ -249,13 +263,15 @@ object ONotification { private[ops] def makeRecord[F[_]: Sync]( store: Store[F], + logger: Logger[F], channelIn: Either[ChannelRef, Channel], id: Ident, userId: Ident ): OptionT[F, RNotificationChannel] = channelIn match { case Left(ref) => - OptionT(store.transact(RNotificationChannel.getByRef(ref))) + OptionT.liftF(logger.debug(s"Loading channel for ref: ${ref}")) *> + OptionT(store.transact(RNotificationChannel.getByRef(ref))) case Right(channel) => for { @@ -264,6 +280,11 @@ object ONotification { channel match { case Channel.Mail(_, conn, recipients) => for { + _ <- OptionT.liftF( + logger.debug( + s"Looking up user smtp for ${userId.id} and ${conn.id}" + ) + ) mailConn <- OptionT( store.transact(RUserEmail.getByUser(userId, conn)) ) diff --git a/modules/joex/src/main/scala/docspell/joex/notify/PeriodicDueItemsTask.scala b/modules/joex/src/main/scala/docspell/joex/notify/PeriodicDueItemsTask.scala index 312b80e2..9446478d 100644 --- a/modules/joex/src/main/scala/docspell/joex/notify/PeriodicDueItemsTask.scala +++ b/modules/joex/src/main/scala/docspell/joex/notify/PeriodicDueItemsTask.scala @@ -7,6 +7,7 @@ package docspell.joex.notify import cats.data.NonEmptyList +import cats.data.OptionT import cats.effect._ import cats.implicits._ @@ -23,6 +24,7 @@ import docspell.query.ItemQueryDsl._ import docspell.store.qb.Batch import docspell.store.queries.ListItem import docspell.store.queries.{QItem, Query} +import docspell.store.records.RUser object PeriodicDueItemsTask { val taskName = PeriodicDueItemsArgs.taskName @@ -49,7 +51,11 @@ object PeriodicDueItemsTask { def withChannel[F[_]: Sync](ctx: Context[F, Args], ops: ONotification[F])( cont: Vector[NotificationChannel] => F[Unit] ): F[Unit] = - TaskOperations.withChannel(ctx.logger, ctx.args.channel, ops)(cont) + OptionT(ctx.store.transact(RUser.findIdByAccount(ctx.args.account))) + .semiflatMap(userId => + TaskOperations.withChannel(ctx.logger, ctx.args.channel, userId, ops)(cont) + ) + .getOrElse(()) def withItems[F[_]: Sync](ctx: Context[F, Args], limit: Int, now: Timestamp)( cont: Vector[ListItem] => F[Unit] diff --git a/modules/joex/src/main/scala/docspell/joex/notify/PeriodicQueryTask.scala b/modules/joex/src/main/scala/docspell/joex/notify/PeriodicQueryTask.scala index 76b19be8..a21a8a0f 100644 --- a/modules/joex/src/main/scala/docspell/joex/notify/PeriodicQueryTask.scala +++ b/modules/joex/src/main/scala/docspell/joex/notify/PeriodicQueryTask.scala @@ -6,6 +6,7 @@ package docspell.joex.notify +import cats.data.OptionT import cats.effect._ import cats.implicits._ @@ -20,6 +21,7 @@ import docspell.query.ItemQueryParser import docspell.store.qb.Batch import docspell.store.queries.ListItem import docspell.store.queries.{QItem, Query} +import docspell.store.records.RUser object PeriodicQueryTask { val taskName = PeriodicQueryArgs.taskName @@ -46,7 +48,11 @@ object PeriodicQueryTask { def withChannel[F[_]: Sync](ctx: Context[F, Args], ops: ONotification[F])( cont: Vector[NotificationChannel] => F[Unit] ): F[Unit] = - TaskOperations.withChannel(ctx.logger, ctx.args.channel, ops)(cont) + OptionT(ctx.store.transact(RUser.findIdByAccount(ctx.args.account))) + .semiflatMap(userId => + TaskOperations.withChannel(ctx.logger, ctx.args.channel, userId, ops)(cont) + ) + .getOrElse(()) def withItems[F[_]: Sync](ctx: Context[F, Args], limit: Int, now: Timestamp)( cont: Vector[ListItem] => F[Unit] diff --git a/modules/joex/src/main/scala/docspell/joex/notify/TaskOperations.scala b/modules/joex/src/main/scala/docspell/joex/notify/TaskOperations.scala index e7cc7b71..788f3131 100644 --- a/modules/joex/src/main/scala/docspell/joex/notify/TaskOperations.scala +++ b/modules/joex/src/main/scala/docspell/joex/notify/TaskOperations.scala @@ -24,12 +24,13 @@ trait TaskOperations { def withChannel[F[_]: Sync]( logger: Logger[F], channel: ChannelOrRef, + userId: Ident, ops: ONotification[F] )( cont: Vector[NotificationChannel] => F[Unit] ): F[Unit] = { val channels = channel match { - case Right(ch) => ops.mkNotificationChannel(ch) + case Right(ch) => ops.mkNotificationChannel(ch, userId) case Left(ref) => ops.findNotificationChannel(ref) } channels.flatMap { ch =>