diff --git a/app/controllers/ApplicationController.scala b/app/controllers/ApplicationController.scala
index 22ce8458d..ac1660464 100644
--- a/app/controllers/ApplicationController.scala
+++ b/app/controllers/ApplicationController.scala
@@ -19,7 +19,6 @@ import models._
import models.formModels.{AnswerFormData, ApplicationFormData, InvitationFormData}
import modules.AppConfig
import org.webjars.play.WebJarsUtil
-import play.api.cache.AsyncCacheApi
import play.api.data.Forms._
import play.api.data._
import play.api.data.format.{Formats, Formatter}
@@ -31,7 +30,6 @@ import play.twirl.api.Html
import serializers.Keys
import serializers.ApiModel.{ApplicationMetadata, ApplicationMetadataResult}
import services._
-import views.stats.StatsData
import java.nio.file.{Files, Path, Paths}
import java.time.{LocalDate, ZonedDateTime}
@@ -47,7 +45,6 @@ import scala.util.{Failure, Success, Try}
@Singleton
case class ApplicationController @Inject() (
applicationService: ApplicationService,
- cache: AsyncCacheApi,
config: AppConfig,
eventService: EventService,
fileService: FileService,
@@ -569,143 +566,6 @@ case class ApplicationController @Inject() (
).withHeaders(CACHE_CONTROL -> "no-store")
}
- private def statsAggregates(applications: List[Application], users: List[User]): StatsData = {
- val now = Time.nowParis()
- val applicationsByArea: Map[Area, List[Application]] =
- applications
- .groupBy(_.area)
- .flatMap { case (areaId: UUID, applications: Seq[Application]) =>
- Area.all
- .find(area => area.id === areaId)
- .map(area => (area, applications))
- }
-
- val firstDate: ZonedDateTime =
- if (applications.isEmpty) now else applications.map(_.creationDate).min
- val months = Time.monthsBetween(firstDate, now)
- val allApplications = applicationsByArea.flatMap(_._2).toList
- val allApplicationsByArea = applicationsByArea.map { case (area, applications) =>
- StatsData.AreaAggregates(
- area = area,
- StatsData.ApplicationAggregates(
- applications = applications,
- months = months,
- usersRelatedToApplications = users
- )
- )
- }.toList
- val data = StatsData(
- all = StatsData.ApplicationAggregates(
- applications = allApplications,
- months = months,
- usersRelatedToApplications = users
- ),
- aggregatesByArea = allApplicationsByArea
- )
- data
- }
-
- private def anonymousGroupsAndUsers(
- groups: List[UserGroup]
- ): Future[(List[User], List[Application])] =
- for {
- users <- userService.byGroupIdsAnonymous(groups.map(_.id))
- applications <- applicationService.allForUserIds(users.map(_.id), none)
- } yield (users, applications)
-
- private def generateStats(
- areaIds: List[UUID],
- organisationIds: List[Organisation.Id],
- groupIds: List[UUID],
- creationMinDate: LocalDate,
- creationMaxDate: LocalDate,
- rights: Authorization.UserRights
- )(implicit request: RequestWithUserData[_]): Future[Html] = {
- eventService.log(
- StatsShowed,
- "Génère les stats pour les paramètres [Territoires '" + areaIds.mkString(",") +
- "' ; Organismes '" + organisationIds.mkString(",") +
- "' ; Groupes '" + groupIds.mkString(",") +
- "' ; Date début '" + creationMinDate +
- "' ; Date fin '" + creationMaxDate + "']"
- )
-
- val usersAndApplications: Future[(List[User], List[Application])] =
- (areaIds, organisationIds, groupIds) match {
- case (Nil, Nil, Nil) =>
- userService.allNoNameNoEmail.zip(applicationService.all())
- case (_ :: _, Nil, Nil) =>
- for {
- groups <- userGroupService.byAreas(areaIds)
- users <- (
- userService.byGroupIdsAnonymous(groups.map(_.id)),
- applicationService.allForAreas(areaIds, None)
- ).mapN(Tuple2.apply)
- } yield users
- case (_ :: _, _ :: _, Nil) =>
- for {
- groups <- userGroupService
- .byOrganisationIds(organisationIds)
- .map(_.filter(_.areaIds.intersect(areaIds).nonEmpty))
- users <- userService.byGroupIdsAnonymous(groups.map(_.id))
- applications <- applicationService
- .allForUserIds(users.map(_.id), none)
- .map(_.filter(application => areaIds.contains(application.area)))
- } yield (users, applications)
- case (_, _ :: _, _) =>
- userGroupService.byOrganisationIds(organisationIds).flatMap(anonymousGroupsAndUsers)
- case (_, Nil, _) =>
- userGroupService
- .byIdsFuture(groupIds)
- .flatMap(anonymousGroupsAndUsers)
- .map { case (users, allApplications) =>
- val applications = allApplications.filter { application =>
- application.isWithoutInvitedGroupIdsLegacyCase ||
- application.invitedGroups.intersect(groupIds.toSet).nonEmpty ||
- users.exists(user => user.id === application.creatorUserId)
- }
- (users, applications)
- }
- }
-
- // Filter creation dates
- def isBeforeOrEqual(d1: LocalDate, d2: LocalDate): Boolean = !d1.isAfter(d2)
-
- val applicationsFuture = usersAndApplications.map { case (_, applications) =>
- applications.filter(application =>
- isBeforeOrEqual(creationMinDate, application.creationDate.toLocalDate) &&
- isBeforeOrEqual(application.creationDate.toLocalDate, creationMaxDate)
- )
- }
-
- // Users whose id is in the `Application`
- val relatedUsersFuture: Future[List[User]] = applicationsFuture.flatMap { applications =>
- val ids: Set[UUID] = applications.flatMap { application =>
- application.creatorUserId :: application.invitedUsers.keys.toList
- }.toSet
- if (ids.size > 1000) {
- // We don't want to send a giga-query to PG
- // it fails with
- // IOException
- // Tried to send an out-of-range integer as a 2-byte value: 33484
- userService.all.map(_.filter(user => ids.contains(user.id)))
- } else {
- userService.byIdsFuture(ids.toList, includeDisabled = true)
- }
- }
-
- // Note: `users` are Users on which we make stats (count, ...)
- // `relatedUsers` are Users to help Applications stats (linked orgs, ...)
- for {
- users <- usersAndApplications.map { case (users, _) => users }
- applications <- applicationsFuture
- relatedUsers <- relatedUsersFuture
- } yield views.html.stats.charts(Authorization.isAdmin(rights))(
- statsAggregates(applications, relatedUsers),
- users
- )
- }
-
// Handles some edge cases from browser compatibility
private val localDateMapping: Mapping[LocalDate] = {
val formatter = new Formatter[LocalDate] {
@@ -734,9 +594,6 @@ case class ApplicationController @Inject() (
)
)
- private val statsCSP =
- "connect-src 'self' https://stats.data.gouv.fr; base-uri 'none'; img-src 'self' data: stats.data.gouv.fr; form-action 'self'; frame-src 'self' *.aplus.beta.gouv.fr; style-src 'self' 'unsafe-inline' stats.data.gouv.fr; object-src 'none'; script-src 'self' 'unsafe-inline' stats.data.gouv.fr; default-src 'none'; font-src 'self'; frame-ancestors 'self'"
-
val statsAction = loginAction.withPublicPage(Ok(views.publicStats.page))
def stats: Action[AnyContent] =
@@ -786,56 +643,33 @@ case class ApplicationController @Inject() (
userGroupService.byIdsFuture(allGroupsIds).flatMap { groups =>
val groupsThatCanBeFilteredBy =
groups.filter(group => dropdownGroupIds.contains[UUID](group.id))
- val charts: Future[Html] =
- if (
- (Authorization.isAdmin(rights) && request.getQueryString("oldstats").isEmpty) ||
- request.getQueryString("newstats").nonEmpty
- ) {
- val validQueryGroups = groups.filter(group => validQueryGroupIds.contains[UUID](group.id))
- val creatorGroupIds = validQueryGroups
- .filter(group =>
- group.organisationId
- .map(id => Organisation.organismesAidants.map(_.id).contains[Organisation.Id](id))
- .getOrElse(false)
- )
- .map(_.id)
- val invitedGroupIds =
- validQueryGroupIds.filterNot(id => creatorGroupIds.contains[UUID](id))
-
- Future.successful(
- views.internalStats.charts(
- views.internalStats.Filters(
- startDate = creationMinDate,
- endDate = creationMaxDate,
- areaIds,
- organisationIds,
- creatorGroupIds,
- invitedGroupIds,
- ),
- config
- )
+ val charts: Future[Html] = {
+ val validQueryGroups = groups.filter(group => validQueryGroupIds.contains[UUID](group.id))
+ val creatorGroupIds = validQueryGroups
+ .filter(group =>
+ group.organisationId
+ .map(id => Organisation.organismesAidants.map(_.id).contains[Organisation.Id](id))
+ .getOrElse(false)
)
- } else {
- val cacheKey =
- Authorization.isAdmin(rights).toString +
- ".stats." +
- Hash.sha256(
- areaIds.toString + organisationIds.toString + validQueryGroupIds.toString +
- creationMinDate.toString + creationMaxDate.toString
- )
+ .map(_.id)
+ val invitedGroupIds =
+ validQueryGroupIds.filterNot(id => creatorGroupIds.contains[UUID](id))
+
+ Future.successful(
+ views.internalStats.charts(
+ views.internalStats.Filters(
+ startDate = creationMinDate,
+ endDate = creationMaxDate,
+ areaIds,
+ organisationIds,
+ creatorGroupIds,
+ invitedGroupIds,
+ ),
+ config
+ )
+ )
+ }
- cache
- .getOrElseUpdate[Html](cacheKey, 1.hours)(
- generateStats(
- areaIds,
- organisationIds,
- validQueryGroupIds,
- creationMinDate,
- creationMaxDate,
- rights
- )
- )
- }
charts
.map { html =>
eventService.log(
@@ -857,7 +691,7 @@ case class ApplicationController @Inject() (
creationMinDate,
creationMaxDate
)
- ).withHeaders(CONTENT_SECURITY_POLICY -> statsCSP)
+ )
}
}
}
diff --git a/app/helper/Time.scala b/app/helper/Time.scala
index e95b1339f..c3b3c5274 100644
--- a/app/helper/Time.scala
+++ b/app/helper/Time.scala
@@ -1,10 +1,9 @@
package helper
import cats.Order
-import java.time.{Instant, LocalDate, YearMonth, ZoneId, ZonedDateTime}
+import java.time.{Instant, LocalDate, ZoneId, ZonedDateTime}
import java.time.format.DateTimeFormatter
import java.util.Locale
-import scala.collection.immutable.ListMap
object Time {
@@ -30,12 +29,7 @@ object Time {
def formatPatternFr(date: LocalDate, pattern: String): String =
date.format(DateTimeFormatter.ofPattern(pattern, Locale.FRANCE))
- // Note that .atDay(1) will yield incorrect format value
- def formatMonthYearAllLetters(month: YearMonth): String =
- month.atDay(15).format(monthYearAllLettersFormatter)
-
val adminsFormatter = DateTimeFormatter.ofPattern("dd/MM/YY-HH:mm", Locale.FRANCE)
- private val monthYearAllLettersFormatter = DateTimeFormatter.ofPattern("MMMM YYYY", Locale.FRANCE)
// Note: we use an Instant here to make clear that we will set our own TZ
def formatForAdmins(date: Instant): String =
@@ -45,32 +39,6 @@ object Time {
val dateWithHourFormatter = DateTimeFormatter.ofPattern("dd/MM/YYYY H'h'", Locale.FRANCE)
- def weeksMap(fromDate: ZonedDateTime, toDate: ZonedDateTime): ListMap[String, String] = {
- val keyFormatter = DateTimeFormatter.ofPattern("YYYY/ww", Locale.FRANCE)
- val valueFormatter = DateTimeFormatter.ofPattern("E dd MMM YYYY", Locale.FRANCE)
- val weekFieldISO = java.time.temporal.WeekFields.of(Locale.FRANCE).dayOfWeek()
- def recursion(date: ZonedDateTime): ListMap[String, String] =
- if (date.isBefore(fromDate)) {
- ListMap()
- } else {
- recursion(date.minusWeeks(1)) +
- (date.format(keyFormatter) -> date.format(valueFormatter))
- }
- val toDateFirstDayOfWeek = toDate.`with`(weekFieldISO, 1)
- recursion(toDateFirstDayOfWeek)
- }
-
- def monthsBetween(fromDate: ZonedDateTime, toDate: ZonedDateTime): List[YearMonth] = {
- val beginning = fromDate.withDayOfMonth(1)
- def recursion(date: ZonedDateTime): Vector[YearMonth] =
- if (date.isBefore(beginning)) {
- Vector.empty[YearMonth]
- } else {
- recursion(date.minusMonths(1)) :+ YearMonth.from(date)
- }
- recursion(toDate).toList
- }
-
implicit final val zonedDateTimeInstance: Order[ZonedDateTime] =
new Order[ZonedDateTime] {
override def compare(x: ZonedDateTime, y: ZonedDateTime): Int = x.compareTo(y)
diff --git a/app/models/Application.scala b/app/models/Application.scala
index 0368369a1..de4200da4 100644
--- a/app/models/Application.scala
+++ b/app/models/Application.scala
@@ -41,10 +41,6 @@ case class Application(
personalDataWiped: Boolean = false,
) extends AgeModel {
- // Legacy case, can be removed once data has been cleaned up.
- val isWithoutInvitedGroupIdsLegacyCase: Boolean =
- invitedGroupIdsAtCreation.isEmpty
-
val invitedGroups: Set[UUID] =
(invitedGroupIdsAtCreation ::: answers.flatMap(_.invitedGroupIds)).toSet
@@ -119,9 +115,6 @@ case class Application(
def invitedUsers(users: List[User]): List[User] =
invitedUsers.keys.flatMap(userId => users.find(_.id === userId)).toList
- def creatorUserQualite(users: List[User]): Option[String] =
- users.find(_.id === creatorUserId).map(_.qualite)
-
def allUserInfos = userInfos ++ answers.flatMap(_.userInfos.getOrElse(Map()))
lazy val anonymousApplication = {
@@ -169,13 +162,6 @@ case class Application(
// TODO: remove
def haveUserInvitedOn(user: User) = invitedUsers.keys.toList.contains(user.id)
- // Stats
- lazy val estimatedClosedDate = (closedDate, closed) match {
- case (Some(date), _) => Some(date)
- case (_, true) => Some(answers.lastOption.map(_.creationDate).getOrElse(creationDate))
- case _ => None
- }
-
lazy val resolutionTimeInMinutes: Option[Int] = if (closed) {
val lastDate = answers.lastOption.map(_.creationDate).orElse(closedDate).getOrElse(creationDate)
Some(MINUTES.between(creationDate, lastDate).toInt)
diff --git a/app/services/NotificationService.scala b/app/services/NotificationService.scala
index b5288df94..6960bbf2b 100644
--- a/app/services/NotificationService.scala
+++ b/app/services/NotificationService.scala
@@ -84,25 +84,15 @@ class NotificationService @Inject() (
// Retrieve data
val userIds = (application.invitedUsers ++ answer.invitedUsers).keys
val users = userService.byIds(userIds.toList)
- val (allGroups, alreadyPresentGroupIds): (List[UserGroup], Set[UUID]) =
- // This legacy case can be removed once data has been fixed
- if (application.isWithoutInvitedGroupIdsLegacyCase) {
- (
- groupService
- .byIds(users.flatMap(_.groupIds))
- .filter(_.email.nonEmpty)
- .filter(_.areaIds.contains(application.area)),
- users.filter(user => application.invitedUsers.contains(user.id)).flatMap(_.groupIds).toSet
- )
- } else {
- val allGroupIds = application.invitedGroups.union(answer.invitedGroupIds.toSet)
- (
- groupService
- .byIds(allGroupIds.toList)
- .filter(_.email.nonEmpty),
- application.invitedGroups
- )
- }
+ val (allGroups, alreadyPresentGroupIds): (List[UserGroup], Set[UUID]) = {
+ val allGroupIds = application.invitedGroups.union(answer.invitedGroupIds.toSet)
+ (
+ groupService
+ .byIds(allGroupIds.toList)
+ .filter(_.email.nonEmpty),
+ application.invitedGroups
+ )
+ }
// Send emails to users
users
diff --git a/app/services/UserService.scala b/app/services/UserService.scala
index ec50a25b4..cf1fc88e2 100644
--- a/app/services/UserService.scala
+++ b/app/services/UserService.scala
@@ -115,19 +115,6 @@ class UserService @Inject() (
.as(simpleUser.*)
}.map(_.toUser)
- // Note: this function is used in the stats,
- // pseudonymization is possible (removing name, etc.)
- def byGroupIdsAnonymous(ids: List[UUID]): Future[List[User]] =
- Future {
- db.withConnection { implicit connection =>
- SQL(s"""SELECT $fieldsInSelect, '' as name, '' as email, '' as qualite
- FROM "user"
- WHERE ARRAY[{ids}]::uuid[] && group_ids""")
- .on("ids" -> ids.distinct)
- .as(simpleUser.*)
- }.map(_.toUser)
- }
-
def byId(id: UUID, includeDisabled: Boolean = false): Option[User] = {
val results = byIds(List(id), includeDisabled)
assert(results.length <= 1)
diff --git a/app/views/internalStats.scala b/app/views/internalStats.scala
index cc11c0dd8..643b80dd4 100644
--- a/app/views/internalStats.scala
+++ b/app/views/internalStats.scala
@@ -1,6 +1,7 @@
package views
import cats.syntax.all._
+import helper.Time
import java.time.LocalDate
import java.util.UUID
import models.Organisation
@@ -68,6 +69,19 @@ object internalStats {
config.statisticsPercentOfRelevantApplicationsUrl.map(iframe6Cols),
config.statisticsNumberOfApplicationsByUsefulnessUrl.map(iframe12Cols),
config.statisticsTimeToProcessApplicationsUrl.map(iframe12Cols),
+ (filters.endDate
+ .isAfter(LocalDate.now().minusDays(2)))
+ .some
+ .filter(identity)
+ .map(_ =>
+ p(
+ "Attention, certaines demandes du ",
+ Time.formatPatternFr(LocalDate.now().minusDays(1), "dd/MM/YY"),
+ " et du ",
+ Time.formatPatternFr(LocalDate.now(), "dd/MM/YY"),
+ " peuvent ne pas être comptabilisées."
+ )
+ )
)
}
diff --git a/app/views/stats/StatsData.scala b/app/views/stats/StatsData.scala
deleted file mode 100644
index 151f645f7..000000000
--- a/app/views/stats/StatsData.scala
+++ /dev/null
@@ -1,139 +0,0 @@
-package views.stats
-
-import cats.kernel.Eq
-import cats.syntax.all._
-import java.time.YearMonth
-import helper.Time
-import models.{Application, Area, User}
-
-object StatsData {
-
- case class Label(label: String) extends AnyVal
-
- object Label {
- implicit val Eq: Eq[Label] = (x: Label, y: Label) => x.label === y.label
- }
-
- case class TimeSeries(points: List[(Label, Int)])
-
- case class ConditionalTimeSeries(series: List[(Label, TimeSeries)], timeAxis: List[Label]) {
-
- lazy val conditions: List[Label] = series.map(_._1)
-
- /** For HTML tables */
- lazy val transpose: List[(String, List[(String, Int)])] =
- timeAxis.map(timePoint =>
- (
- timePoint.label,
- series.map { case (condition, singleTimeSeries) =>
- (
- condition.label,
- singleTimeSeries.points
- .find(t => t._1 === timePoint)
- .map(_._2)
- // not pretty, maybe figure out how to have some Option / NaN
- .getOrElse[Int](0)
- )
- }
- )
- )
-
- }
-
- case class AreaAggregates(area: Area, aggregates: ApplicationAggregates)
-
- case class ApplicationAggregates(
- applications: List[Application],
- months: List[YearMonth],
- private val usersRelatedToApplications: List[User]
- ) {
- def count: Int = applications.size
- lazy val countLast30Days: Int = applications.count(_.ageInDays <= 30)
- lazy val countClosedLast30Days: Int = applications.count(a => a.ageInDays <= 30 && a.closed)
- lazy val countRelevant: Int = applications.count(!_.irrelevant)
- lazy val countIrrelevant: Int = applications.count(_.irrelevant)
-
- lazy val countIrrelevantLast30Days: Int =
- applications.count(a => a.ageInDays <= 30 && a.irrelevant)
-
- lazy val applicationsByStatus: Map[String, List[Application]] =
- applications.groupBy(_.status.show)
-
- lazy val applicationsGroupedByMonth: List[(String, List[Application])] = {
- val grouped = applications.groupBy(application => YearMonth.from(application.creationDate))
- months.map { month =>
- Time.formatMonthYearAllLetters(month) -> grouped.getOrElse(month, List.empty[Application])
- }
- }
-
- lazy val closedApplicationsGroupedByMonth: List[(String, List[Application])] = {
- val grouped =
- applications.groupBy(application => application.estimatedClosedDate.map(YearMonth.from))
- months.map { month =>
- Time.formatMonthYearAllLetters(month) -> grouped.getOrElse(
- month.some,
- List.empty[Application]
- )
- }
- }
-
- private def applicationsCountByMandat(mandatType: Application.MandatType): List[Int] =
- applicationsGroupedByMonth.map(
- _._2.count(application => application.mandatType === mandatType.some)
- )
-
- lazy val applicationsCountByMandatPaper: List[Int] =
- applicationsGroupedByMonth.map(
- _._2
- .count(application =>
- application.mandatType.isEmpty ||
- application.mandatType === Application.MandatType.Paper.some
- )
- )
-
- lazy val applicationsCountByMandatSms: List[Int] =
- applicationsCountByMandat(Application.MandatType.Sms)
-
- lazy val applicationsCountByMandatPhone: List[Int] =
- applicationsCountByMandat(Application.MandatType.Phone)
-
- // Conditional Series
-
- lazy val creatorQualitees: List[String] =
- applicationsGroupedByMonth
- .flatMap(_._2)
- .flatMap(_.creatorUserQualite(usersRelatedToApplications))
- .distinct
-
- lazy val applicationsCountGroupedByCreatorQualiteThenByMonth: ConditionalTimeSeries =
- ConditionalTimeSeries(
- series = creatorQualitees.map(qualite =>
- (
- Label(qualite),
- TimeSeries(
- applicationsGroupedByMonth
- .map { case (month, applications) =>
- (
- Label(month),
- applications.count(
- _.creatorUserQualite(usersRelatedToApplications).contains(qualite)
- )
- )
- }
- )
- )
- ),
- timeAxis = months.map(month => Label(Time.formatMonthYearAllLetters(month)))
- )
-
- }
-
-}
-
-/** This class (and its subclasses) should have all "computation" methods, such that the template do
- * not have calculations in it.
- */
-case class StatsData(
- all: StatsData.ApplicationAggregates,
- aggregatesByArea: List[StatsData.AreaAggregates]
-)
diff --git a/app/views/stats/applicationsByAreaTable.scala.html b/app/views/stats/applicationsByAreaTable.scala.html
deleted file mode 100644
index 0bafbd105..000000000
--- a/app/views/stats/applicationsByAreaTable.scala.html
+++ /dev/null
@@ -1,30 +0,0 @@
-@(data: views.stats.StatsData)
-
-
-
-
- Territoire |
- Total |
- Total archivées |
- Total non pertinentes |
- Oui |
- Je ne sais pas |
- Non |
- ? |
-
-
-
- @for(areaData <- data.aggregatesByArea) {
-
- @areaData.area.name |
- @areaData.aggregates.applications.length |
- @areaData.aggregates.applications.count(_.closed) |
- @areaData.aggregates.applications.count(_.irrelevant) |
- @areaData.aggregates.applications.count(_.usefulness.contains("Oui")) |
- @areaData.aggregates.applications.count(_.usefulness.contains("Je ne sais pas")) |
- @areaData.aggregates.applications.count(_.usefulness.contains("Non")) |
- @areaData.aggregates.applications.count(_.usefulness.isEmpty) ? |
-
- }
-
-
diff --git a/app/views/stats/applicationsRelevantPieChart.scala.html b/app/views/stats/applicationsRelevantPieChart.scala.html
deleted file mode 100644
index ed9506274..000000000
--- a/app/views/stats/applicationsRelevantPieChart.scala.html
+++ /dev/null
@@ -1,30 +0,0 @@
-@(data: views.stats.StatsData.ApplicationAggregates)
-
-
-
diff --git a/app/views/stats/applicationsResolutionTimeBarChart.scala.html b/app/views/stats/applicationsResolutionTimeBarChart.scala.html
deleted file mode 100644
index 819950d0b..000000000
--- a/app/views/stats/applicationsResolutionTimeBarChart.scala.html
+++ /dev/null
@@ -1,69 +0,0 @@
-@import _root_.helper.Math
-
-@(data: views.stats.StatsData.ApplicationAggregates)
-
-
-
diff --git a/app/views/stats/applicationsStatusPieChart.scala.html b/app/views/stats/applicationsStatusPieChart.scala.html
deleted file mode 100644
index 6b0a78af8..000000000
--- a/app/views/stats/applicationsStatusPieChart.scala.html
+++ /dev/null
@@ -1,32 +0,0 @@
-@(data: views.stats.StatsData.ApplicationAggregates)
-
-
-
diff --git a/app/views/stats/applicationsUsefulnessFeedbackBarChart.scala.html b/app/views/stats/applicationsUsefulnessFeedbackBarChart.scala.html
deleted file mode 100644
index 129ccf43b..000000000
--- a/app/views/stats/applicationsUsefulnessFeedbackBarChart.scala.html
+++ /dev/null
@@ -1,48 +0,0 @@
-@(data: views.stats.StatsData.ApplicationAggregates)
-
-
-
diff --git a/app/views/stats/charts.scala.html b/app/views/stats/charts.scala.html
deleted file mode 100644
index 99cda097b..000000000
--- a/app/views/stats/charts.scala.html
+++ /dev/null
@@ -1,96 +0,0 @@
-@import java.util.UUID
-
-@import _root_.helper.Time
-@(isAdmin: Boolean)(data: views.stats.StatsData, users: List[User])
-
-
-
-
- Dernière mise à jour : @{Time.formatPatternFr(Time.nowParis(), "dd MMM YYYY - HH:mm:ss")}
-
-
-
-
-
Total de demandes
- @data.all.count
- @data.all.countLast30Days sur les 30 derniers jours
-
-
-
Total d’utilisateurs
- @users.length
- @users.count(_.ageInDays <= 30) sur les 30 derniers jours
-
-
-
Répartition des demandes
- @applicationsStatusPieChart(data.all)
- @data.all.countClosedLast30Days archivées sur les 30 derniers jours
-
-
-
Pertinence des demandes
- @applicationsRelevantPieChart(data.all)
- @data.all.countIrrelevantLast30Days non pertinentes sur les 30 derniers jours
-
-
-
-
Est-ce que la réponse vous semble utile pour l’usager ?
- @applicationsUsefulnessFeedbackBarChart(data.all)
-
-
-
-
Temps de résolution
- @applicationsResolutionTimeBarChart(data.all)
-
-
-
-
Demandes déposées et archivées
-
- @newAndClosedApplicationsBarChart(data.all, "all")
-
-
-
-@if(isAdmin) {
-
-
Demandes déposées par type de mandat
-
- @mandatTypeBarChart(data.all, "mandat-type")
-
-
-}
-
-@if(isAdmin) {
-
-
-
Demandes par territoire
-
- @applicationsByAreaTable(data)
-
-
-
-
-
- @for(areaData <- data.aggregatesByArea) {
-
@areaData.area.name
-
- @stats.newAndClosedApplicationsBarChart(areaData.aggregates, areaData.area.id.toString)
-
- Détail des demandes faites par des structures aidantes
-
- @conditionalTimeSeriesPlot(
- areaData.aggregates.applicationsCountGroupedByCreatorQualiteThenByMonth,
- s"toto-helper-admin-chart-${areaData.area.id}"
- )
-
- @conditionalTimeSeriesTransposedTable(
- areaData.aggregates.applicationsCountGroupedByCreatorQualiteThenByMonth,
- "Mois",
- "Total"
- )
-
-
- Détail des demandes archivées
- @closedApplicationsTable(areaData.aggregates)
-
-
- }
-
-}
diff --git a/app/views/stats/closedApplicationsTable.scala.html b/app/views/stats/closedApplicationsTable.scala.html
deleted file mode 100644
index 34fb0097b..000000000
--- a/app/views/stats/closedApplicationsTable.scala.html
+++ /dev/null
@@ -1,28 +0,0 @@
-@(data: views.stats.StatsData.ApplicationAggregates)
-
-
-
-
- Semaine |
- Archivées |
- Non Pertinentes |
- Oui |
- Je ne sais pas |
- Non |
- ? |
-
-
-
- @for((month, applications) <- data.closedApplicationsGroupedByMonth.reverse) {
-
- @month |
- @applications.length |
- @applications.count(_.irrelevant) |
- @applications.count(_.usefulness.contains("Oui")) |
- @applications.count(_.usefulness.contains("Je ne sais pas")) |
- @applications.count(_.usefulness.contains("Non")) |
- @applications.count(_.usefulness.isEmpty) ? |
-
- }
-
-
diff --git a/app/views/stats/conditionalTimeSeriesPlot.scala.html b/app/views/stats/conditionalTimeSeriesPlot.scala.html
deleted file mode 100644
index c891b6cf0..000000000
--- a/app/views/stats/conditionalTimeSeriesPlot.scala.html
+++ /dev/null
@@ -1,37 +0,0 @@
-@(allSeries: views.stats.StatsData.ConditionalTimeSeries, chartId: String)
-
-
-
diff --git a/app/views/stats/conditionalTimeSeriesTransposedTable.scala.html b/app/views/stats/conditionalTimeSeriesTransposedTable.scala.html
deleted file mode 100644
index 3f08de7a7..000000000
--- a/app/views/stats/conditionalTimeSeriesTransposedTable.scala.html
+++ /dev/null
@@ -1,24 +0,0 @@
-@(allSeries: views.stats.StatsData.ConditionalTimeSeries, timeColumnHeader: String, sumColumnHeader: String)
-
-
-
-
- @timeColumnHeader |
- @sumColumnHeader |
- @for(condition <- allSeries.conditions) {
- @condition.label |
- }
-
-
-
- @for((timePoint, valuesByCondition) <- allSeries.transpose.reverse) {
-
- @timePoint |
- @valuesByCondition.map(_._2).sum |
- @for((_, count) <- valuesByCondition) {
- @count |
- }
-
- }
-
-
diff --git a/app/views/stats/mandatTypeBarChart.scala.html b/app/views/stats/mandatTypeBarChart.scala.html
deleted file mode 100644
index 16b2a549e..000000000
--- a/app/views/stats/mandatTypeBarChart.scala.html
+++ /dev/null
@@ -1,51 +0,0 @@
-@(data: views.stats.StatsData.ApplicationAggregates, chartId: String)
-
-
-
diff --git a/app/views/stats/newAndClosedApplicationsBarChart.scala.html b/app/views/stats/newAndClosedApplicationsBarChart.scala.html
deleted file mode 100644
index e53a42aca..000000000
--- a/app/views/stats/newAndClosedApplicationsBarChart.scala.html
+++ /dev/null
@@ -1,69 +0,0 @@
-@(data: views.stats.StatsData.ApplicationAggregates, chartId: String)
-
-
-
diff --git a/app/views/stats/page.scala.html b/app/views/stats/page.scala.html
index 4f753baed..d02349fb8 100644
--- a/app/views/stats/page.scala.html
+++ b/app/views/stats/page.scala.html
@@ -4,7 +4,6 @@
@(currentUser: User, currentUserRights: Authorization.UserRights)(formUrl: Call, result: Html, groupsThatCanBeFilteredBy: List[UserGroup], selectedAreaIds: List[UUID], selectedOrganisationIds: List[Organisation.Id], selectedGroupIds: List[UUID], creationMinDate: LocalDate, creationMaxDate: LocalDate)(implicit webJarsUtil: org.webjars.play.WebJarsUtil, flash: Flash, request: RequestHeader, mainInfos: MainInfos)
@main(currentUser, currentUserRights)(s"Stats") {
- @webJarsUtil.locate("Chart.bundle.min.js").script()
}{
@helper.form(formUrl, "method" -> "post") {
diff --git a/build.sbt b/build.sbt
index a2936020a..65d9966ce 100644
--- a/build.sbt
+++ b/build.sbt
@@ -81,7 +81,6 @@ libraryDependencies ++= Seq(
ws,
jdbc,
evolutions,
- ehcache
)
pipelineStages := Seq(digest, gzip)
@@ -109,7 +108,6 @@ libraryDependencies ++= Seq(
"org.webjars.bower" % "material-design-lite" % "1.3.0",
"org.webjars" % "material-design-icons" % "4.0.0",
"org.webjars.npm" % "roboto-fontface" % "0.10.0",
- "org.webjars" % "chartjs" % "2.9.4",
"org.webjars" % "font-awesome" % "6.4.2",
)
diff --git a/conf/routes b/conf/routes
index 62603c464..ab812d381 100644
--- a/conf/routes
+++ b/conf/routes
@@ -36,13 +36,9 @@ POST /mandats/sms/webhook
# Stats
-+ nocsp
GET /stats controllers.ApplicationController.stats
-+ nocsp
GET /as/:userId/stats controllers.ApplicationController.statsAs(userId: java.util.UUID)
-+ nocsp
POST /stats controllers.ApplicationController.stats
-+ nocsp
POST /as/:userId/stats controllers.ApplicationController.statsAs(userId: java.util.UUID)