Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.18.1 - Mise en prod 28/3/2021 #1355

Merged
merged 15 commits into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Build image
run: docker build .
2 changes: 1 addition & 1 deletion .github/workflows/dockerpublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
if: github.event_name == 'push'

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
name: Scala
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v2
with:
Expand Down
24 changes: 14 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
name: Scala Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v2
with:
Expand All @@ -26,21 +26,25 @@ jobs:
node-version: '14'
- name: Install npm dependencies
run: npm install
- name: Hack TS source to please HTMLUnit
run: sed -e "/autolinker/s/^/\/\/ /" -i typescript/src/index.ts
# Note that the polyfill commented below is needed for IE...
- name: Hack TS source to please HTMLUnit (again)
run: sed -e "/es2015-promise/s/^/\/\/ /" -i typescript/src/index.ts
- name: Build the JS blob
run: npm run build

- name: Display geckodriver and firefox versions
run: |
which geckodriver
geckodriver --version
which firefox
firefox --version

# We compile the tests here so the test command can run faster
- name: Compile tests
run: "sbt Test/compile"
# Due to transient errors thrown by HTMLUnit, we try
# to run the tests a few times

- name: Run tests
run: "sbt coverage test coverageReport || sbt coverage test coverageReport || sbt coverage test coverageReport"
run: "sbt coverage test coverageReport"
env:
GECKO_DRIVER: /usr/bin/geckodriver

- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@v1
env:
Expand All @@ -54,7 +58,7 @@ jobs:
name: TypeScript Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v2
with:
Expand Down
122 changes: 71 additions & 51 deletions app/controllers/ApplicationController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import play.api.cache.AsyncCacheApi
import play.api.data.Forms._
import play.api.data._
import play.api.data.validation.Constraints._
import play.api.libs.json.Json
import play.api.libs.ws.WSClient
import play.api.mvc._
import play.twirl.api.Html
import serializers.Keys
import serializers.ApiModel.{ApplicationMetadata, ApplicationMetadataResult}
import services._
import views.stats.StatsData

Expand Down Expand Up @@ -419,17 +421,28 @@ case class ApplicationController @Inject() (
applicationService.allForAreas(List(area.id), numOfMonthsDisplayed.some)
case (false, None) if user.groupAdmin =>
val userIds = userService.byGroupIds(user.groupIds, includeDisabled = true).map(_.id)
applicationService.allForUserIds(userIds)
applicationService.allForUserIds(userIds, numOfMonthsDisplayed.some)
case (false, Some(area)) if user.groupAdmin =>
val userGroupIds =
userGroupService.byIds(user.groupIds).filter(_.areaIds.contains[UUID](area.id)).map(_.id)
val userIds = userService.byGroupIds(userGroupIds, includeDisabled = true).map(_.id)
applicationService.allForUserIds(userIds)
val userIds = userService.byGroupIds(user.groupIds, includeDisabled = true).map(_.id)
applicationService
.allForUserIds(userIds, numOfMonthsDisplayed.some)
.map(_.filter(application => application.area === area.id))
case _ =>
Future(Nil)
Future.successful(Nil)
}

def all(areaId: UUID): Action[AnyContent] =
private def extractApplicationsAdminQuery(implicit
request: RequestWithUserData[_]
): (Option[Area], Int) = {
val areaOpt = areaInQueryString.filterNot(_.id === Area.allArea.id)
val numOfMonthsDisplayed: Int = request
.getQueryString(Keys.QueryParam.numOfMonthsDisplayed)
.flatMap(s => Try(s.toInt).toOption)
.getOrElse(3)
(areaOpt, numOfMonthsDisplayed)
}

def applicationsAdmin: Action[AnyContent] =
loginAction.async { implicit request =>
(request.currentUser.admin, request.currentUser.groupAdmin) match {
case (false, false) =>
Expand All @@ -443,29 +456,60 @@ case class ApplicationController @Inject() (
)
)
case _ =>
val numOfMonthsDisplayed: Int = request
.getQueryString(Keys.QueryParam.numOfMonthsDisplayed)
.flatMap(s => Try(s.toInt).toOption)
.getOrElse(3)
val area = if (areaId === Area.allArea.id) None else Area.fromId(areaId)
allApplicationVisibleByUserAdmin(request.currentUser, area, numOfMonthsDisplayed).map {
unfilteredApplications =>
val filteredApplications =
request.getQueryString(Keys.QueryParam.filterIsOpen) match {
case Some(_) => unfilteredApplications.filterNot(_.closed)
case None => unfilteredApplications
}
val (areaOpt, numOfMonthsDisplayed) = extractApplicationsAdminQuery
eventService.log(
AllApplicationsShowed,
s"Accède à la page des métadonnées des demandes [$areaOpt ; $numOfMonthsDisplayed]"
)
Future(
Ok(
views.applicationsAdmin
.page(request.currentUser, request.rights, areaOpt, numOfMonthsDisplayed)
)
)
}
}

def applicationsMetadata: Action[AnyContent] =
loginAction.async { implicit request =>
(request.currentUser.admin, request.currentUser.groupAdmin) match {
case (false, false) =>
eventService.log(
AllApplicationsUnauthorized,
"Liste des metadata des demandes non autorisée"
)
Future.successful(Unauthorized(Json.toJson(ApplicationMetadataResult(Nil))))
case _ =>
val (areaOpt, numOfMonthsDisplayed) = extractApplicationsAdminQuery
allApplicationVisibleByUserAdmin(request.currentUser, areaOpt, numOfMonthsDisplayed).map {
applications =>
eventService.log(
AllApplicationsShowed,
s"Visualise la liste des demandes de $areaId - taille = ${filteredApplications.size}"
"Accède à la liste des metadata des demandes " +
s"[territoire ${areaOpt.map(_.name).getOrElse("tous")} ; " +
s"taille : ${applications.size}]"
)
Ok(
views.html
.allApplications(request.currentUser, request.rights)(
filteredApplications,
area.getOrElse(Area.allArea)
val userIds: List[UUID] = (applications.flatMap(_.invitedUsers.keys) ++
applications.map(_.creatorUserId)).toList.distinct
val users = userService.byIds(userIds, includeDisabled = true)
val groupIds =
(users.flatMap(_.groupIds) ::: applications.flatMap(application =>
application.invitedGroupIdsAtCreation ::: application.answers.flatMap(
_.invitedGroupIds
)
)).distinct
val groups = userGroupService.byIds(groupIds)
val idToUser = users.map(user => (user.id, user)).toMap
val idToGroup = groups.map(group => (group.id, group)).toMap
val metadata = applications.map(application =>
ApplicationMetadata.fromApplication(
application,
request.rights,
idToUser,
idToGroup
)
)
Ok(Json.toJson(ApplicationMetadataResult(metadata)))
}
}
}
Expand Down Expand Up @@ -532,7 +576,7 @@ case class ApplicationController @Inject() (
): Future[(List[User], List[Application])] =
for {
users <- userService.byGroupIdsAnonymous(groups.map(_.id))
applications <- applicationService.allForUserIds(users.map(_.id))
applications <- applicationService.allForUserIds(users.map(_.id), none)
} yield (users, applications)

private def generateStats(
Expand Down Expand Up @@ -562,7 +606,7 @@ case class ApplicationController @Inject() (
.map(_.filter(_.areaIds.intersect(areaIds).nonEmpty))
users <- userService.byGroupIdsAnonymous(groups.map(_.id))
applications <- applicationService
.allForUserIds(users.map(_.id))
.allForUserIds(users.map(_.id), none)
.map(_.filter(application => areaIds.contains(application.area)))
} yield (users, applications)
case (_, _ :: _, _) =>
Expand Down Expand Up @@ -824,30 +868,6 @@ case class ApplicationController @Inject() (
.as("text/csv")
}

def allCSV(areaId: UUID): Action[AnyContent] =
loginAction.async { implicit request =>
val area = if (areaId === Area.allArea.id) Option.empty else Area.fromId(areaId)
val exportedApplicationsFuture =
if (request.currentUser.admin || request.currentUser.groupAdmin) {
allApplicationVisibleByUserAdmin(request.currentUser, area, 24)
} else {
Future(Nil)
}

exportedApplicationsFuture.map { exportedApplications =>
val date = Time.formatPatternFr(Time.nowParis(), "YYY-MM-dd-HH'h'mm")
val csvContent = applicationsToCSV(exportedApplications)

eventService.log(AllCSVShowed, s"Visualise un CSV pour la zone $area")
val filenameAreaPart: String = area.map(_.name.stripSpecialChars).getOrElse("tous")
Ok(csvContent)
.withHeaders(
"Content-Disposition" -> s"""attachment; filename="aplus-demandes-$date-$filenameAreaPart.csv""""
)
.as("text/csv")
}
}

private def usersWhoCanBeInvitedOn(application: Application, currentAreaId: UUID)(implicit
request: RequestWithUserData[_]
): Future[List[User]] =
Expand Down
7 changes: 3 additions & 4 deletions app/controllers/GroupController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ case class GroupController @Inject() (
applicationService: ApplicationService,
loginAction: LoginAction,
groupService: UserGroupService,
notificationService: NotificationService,
eventService: EventService,
configuration: Configuration,
ws: WSClient,
Expand Down Expand Up @@ -83,7 +82,7 @@ case class GroupController @Inject() (
},
data =>
userService
.byEmailFuture(data.email)
.byEmailFuture(data.email, includeDisabled = true)
.zip(userService.byGroupIdsFuture(List(groupId), includeDisabled = true))
.flatMap {
case (None, _) =>
Expand Down Expand Up @@ -408,7 +407,7 @@ case class GroupController @Inject() (
for {
groups <- groupService.byIdsFuture(user.groupIds)
users <- userService.byGroupIdsFuture(groups.map(_.id), includeDisabled = true)
applications <- applicationService.allForUserIds(users.map(_.id))
applications <- applicationService.allForUserIds(users.map(_.id), none)
} yield {
eventService.log(EventType.EditMyGroupShowed, "Visualise la modification de ses groupes")
Ok(
Expand All @@ -432,7 +431,7 @@ case class GroupController @Inject() (
eventService.log(EditGroupShowed, s"Visualise la vue de modification du groupe")
val isEmpty = groupService.isGroupEmpty(group.id)
applicationService
.allForUserIds(groupUsers.map(_.id))
.allForUserIds(groupUsers.map(_.id), none)
.map(applications =>
Ok(
views.html.editGroup(request.currentUser, request.rights)(
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/JavascriptController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class JavascriptController() extends InjectedController {
routes.javascript.ApiController.deploymentData,
routes.javascript.GroupController.deleteUnusedGroupById,
routes.javascript.GroupController.editGroup,
routes.javascript.ApplicationController.all,
routes.javascript.ApplicationController.applicationsAdmin,
routes.javascript.ApplicationController.applicationsMetadata,
routes.javascript.ApplicationController.show,
routes.javascript.UserController.all,
routes.javascript.UserController.deleteUnusedUserById,
routes.javascript.UserController.editUser,
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/LoginController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class LoginController @Inject() (
tmpPath
}
}
notificationService.newMagicLinkEmail(
val smtpHost = notificationService.newMagicLinkEmail(
requestWithUserData.map(_.currentUser.name),
email,
requestWithUserData.map(_.currentUser.timeZone).getOrElse(Time.timeZoneParis),
Expand All @@ -127,7 +127,7 @@ class LoginController @Inject() (
request.body.asFormUrlEncoded.flatMap(_.get("email")).nonEmpty
val emailInFlash = request.flash.get("email").nonEmpty
val logMessage =
s"Génère un token pour une connexion par email"
s"Génère un token pour une connexion par email via '$smtpHost'"
val data = s"Body '$emailInBody' Flash '$emailInFlash'"
requestWithUserData.fold(
eventService.logSystem(GenerateToken, logMessage, data.some)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/MandatController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ case class MandatController @Inject() (
.fold(
errors => {
val errorMessage = helper.PlayFormHelper.prettifyJsonFormInvalidErrors(errors)
eventService.log(EventType.MandatInitiationBySmsInvalid, s"$errorMessage")
eventService.log(EventType.MandatInitiationBySmsFormValidationError, s"$errorMessage")
Future(
BadRequest(
Json.obj("message" -> JsString(errorMessage), "errors" -> JsError.toJson(errors))
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/PathValidator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object PathValidator {
routes.AreaController.all,
routes.AreaController.deploymentDashboard,
routes.AreaController.franceServiceDeploymentDashboard,
routes.ApplicationController.all(placeholderUUID),
routes.ApplicationController.applicationsAdmin,
routes.UserController.all(placeholderUUID),
)
val uuidRegex = "([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})"
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/SignupController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,10 @@ case class SignupController @Inject() (
}
if (!form.dryRun) {
successes.foreach { signup =>
notificationsService.newSignup(signup)
val host = notificationsService.newSignup(signup)
eventService.log(
EventType.SignupCreated,
s"Préinscription ${signup.id} créée",
s"Préinscription ${signup.id} créée [email envoyé via '$host']",
s"${signup.toLogString}".some
)
}
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/UserController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -660,10 +660,10 @@ case class UserController @Inject() (
},
{ _ =>
users.foreach { user =>
notificationsService.newUser(user)
val host = notificationsService.newUser(user)
eventService.log(
EventType.UserCreated,
s"Utilisateur ${user.id} ajouté",
s"Utilisateur ${user.id} ajouté [email envoyé via '$host']",
s"Utilisateur ${user.toLogString}".some,
involvesUser = Some(user.id)
)
Expand Down
3 changes: 1 addition & 2 deletions app/filters/SentryFilter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ class SentryFilter @Inject() (implicit val mat: Materializer, ec: ExecutionConte
val queryParamsWhitelist = List(
Keys.QueryParam.vue,
Keys.QueryParam.uniquementFs,
Keys.QueryParam.numOfMonthsDisplayed,
Keys.QueryParam.filterIsOpen
Keys.QueryParam.numOfMonthsDisplayed
)

def apply(
Expand Down
Loading