mirror of
https://github.com/ysoftdevs/odc-analyzer.git
synced 2026-03-21 00:29:38 +01:00
Added support for mail digests
This commit is contained in:
@@ -6,7 +6,10 @@ import com.mohiva.play.silhouette.api.LoginInfo
|
||||
import com.ysoft.odc.SetDiff
|
||||
import controllers.{ProjectsWithReports, ReportInfo}
|
||||
import models._
|
||||
import models.tables._
|
||||
import play.api.Logger
|
||||
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
|
||||
import slick.dbio.FutureAction
|
||||
import slick.jdbc.TransactionIsolation
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
@@ -30,8 +33,25 @@ class VulnerabilityNotificationService @Inject() (protected val dbConfigProvider
|
||||
import dbConfig.driver.api._
|
||||
import models.tables._
|
||||
|
||||
def subscribers = db.run(vulnerabilitySubscriptions.result).map(_.groupBy(_.user))
|
||||
def watchedProjectsByUser(identity: LoginInfo) = db.run(vulnerabilitySubscriptions.filter(_.user === identity).result)
|
||||
def subscribe(user: LoginInfo, project: String) = db.run(vulnerabilitySubscriptions += VulnerabilitySubscription(user = user, project = project))
|
||||
|
||||
def subscribe(user: LoginInfo, project: String) = db.run(
|
||||
DBIO.seq(
|
||||
ensureUserHasNotificationDigestStatus(user),
|
||||
vulnerabilitySubscriptions += VulnerabilitySubscription(user = user, project = project)
|
||||
)
|
||||
)
|
||||
|
||||
private def ensureUserHasNotificationDigestStatus(user: LoginInfo): DBIOAction[Unit, slick.dbio.NoStream, Effect.Read with Effect.Write] = (
|
||||
notificationDigestStatuses.filter(_.user === user).result.map(_.nonEmpty) flatMap {
|
||||
case true => DBIO.seq()
|
||||
case false => for{
|
||||
changelogTopIdOption <- changelogTopIdOptionQuery
|
||||
(res: Int) <- notificationDigestStatuses += NotificationDigestStatus(user = user, lastChangelogIdOption = changelogTopIdOption)
|
||||
} yield ()
|
||||
}
|
||||
).withTransactionIsolation(TransactionIsolation.Serializable)
|
||||
|
||||
def unsubscribe(user: LoginInfo, project: String) = db.run(vulnerabilitySubscriptions.filter(vs => vs.user === user && vs.project === project).delete)
|
||||
|
||||
@@ -85,7 +105,13 @@ class VulnerabilityNotificationService @Inject() (protected val dbConfigProvider
|
||||
|
||||
def changeAffectedProjects(vulnerabilityName: String, affectedProjectsDiff: SetDiff[String]): Future[Unit] = {
|
||||
val time = DateTime.now()
|
||||
def createRecord(projectName: String, direction: Change.Direction) = Change(time, vulnerabilityName, projectName, direction)
|
||||
def createRecord(projectName: String, direction: Change.Direction) = Change(
|
||||
time = time,
|
||||
vulnerabilityName = vulnerabilityName,
|
||||
projectName = projectName,
|
||||
direction = direction,
|
||||
notifiedToSomebody = false
|
||||
)
|
||||
val recordsToAdd = affectedProjectsDiff.added.map(projectName => createRecord(projectName, Change.Direction.Added)) ++
|
||||
affectedProjectsDiff.removed.map(projectName => createRecord(projectName, Change.Direction.Removed))
|
||||
/*
|
||||
@@ -98,6 +124,34 @@ class VulnerabilityNotificationService @Inject() (protected val dbConfigProvider
|
||||
).map(_ => ()))
|
||||
}
|
||||
|
||||
private def changelogTopIdOptionQuery = changelog.map(_.id).max.result
|
||||
|
||||
def sendDigestToSubscriber(subscriber: LoginInfo, subscriptions: Seq[VulnerabilitySubscription])(sendDigest: Seq[Change] => Future[Unit]): Future[Unit] = {
|
||||
def subscriptionCondition(change: Changes, subscription: VulnerabilitySubscription): Rep[Boolean] = {
|
||||
//noinspection ScalaUnnecessaryParentheses – because it looks less confusing
|
||||
(change.projectName === subscription.project) ||
|
||||
(if (subscription.project contains '/') (false: Rep[Boolean]) else change.projectName.startsWith(subscription.project + "/"))
|
||||
}
|
||||
val projectCondition: Changes => Rep[Boolean] = (change) =>
|
||||
subscriptions.foldLeft(false: Rep[Boolean])((cond, subscription) => cond || subscriptionCondition(change, subscription))
|
||||
val notificationDigestStatusSelection = notificationDigestStatuses.filter(_.user === subscriber)
|
||||
db.run(
|
||||
(
|
||||
for{
|
||||
oldStatus <- notificationDigestStatusSelection.result.map(_.head)
|
||||
_ = println(oldStatus.lastChangelogIdOption.fold(changelog.filter(_ => true: Rep[Boolean]))(lastChangelogId => changelog.filter(_.id > lastChangelogId)).filter(projectCondition).result.statements.mkString("\n"))
|
||||
changelogSinceLastNotified <- oldStatus.lastChangelogIdOption.fold(changelog.filter(_ => true: Rep[Boolean]))(lastChangelogId => changelog.filter(_.id > lastChangelogId)).filter(projectCondition).result
|
||||
changelogIds = changelogSinceLastNotified.map(_._1)
|
||||
changelogTopIdOption <- changelogTopIdOptionQuery
|
||||
newLastChangelogIdOption = changelogTopIdOption.orElse(oldStatus.lastChangelogIdOption)
|
||||
(_: Unit) <- FutureAction(sendDigest(changelogSinceLastNotified.map(_._2))) // Yes, we are waiting for user to be notified over some slow I/O when having an open transaction
|
||||
(_: Int) <- notificationDigestStatusSelection.map(_.lastChangelogId).update(newLastChangelogIdOption)
|
||||
(_: Int) <- changelog.filter(_.id inSet changelogIds).map(_.notifiedToSomebody).update(true)
|
||||
} yield ()
|
||||
).withTransactionIsolation(TransactionIsolation.Serializable)
|
||||
)
|
||||
}
|
||||
|
||||
val issueTrackerExport = new ExportPlatform(tables.issueTrackerExportTables)
|
||||
|
||||
val mailExport = new ExportPlatform(tables.mailExportTables)
|
||||
|
||||
Reference in New Issue
Block a user