Skip to content

Commit

Permalink
Edition du profil utilisateur (#858)
Browse files Browse the repository at this point in the history
Edition du profil utilisateur (#858)
  • Loading branch information
mdulac authored Nov 25, 2020
1 parent 01c112a commit c5d7cc3
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 68 deletions.
75 changes: 72 additions & 3 deletions app/controllers/UserController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@ import models.EventType.{
UserEdited,
UserIsUsed,
UserNotFound,
UserProfileShowed,
UserProfileShowedError,
UserProfileUpdated,
UserProfileUpdatedError,
UserShowed,
UsersCreated,
UsersShowed,
ViewUserUnauthorized
}
import models._
import models.formModels.ValidateSubscriptionForm
import models.formModels.{EditProfileFormData, ValidateSubscriptionForm}
import org.postgresql.util.PSQLException
import org.webjars.play.WebJarsUtil
import play.api.Configuration
Expand All @@ -53,6 +57,7 @@ import play.filters.csrf.CSRF.Token
import serializers.{Keys, UserAndGroupCsvSerializer}
import services._

import scala.concurrent.Future.successful
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try

Expand All @@ -71,9 +76,73 @@ case class UserController @Inject() (
with UserOperators
with GroupOperators {

def showEditProfile =
loginAction.async { implicit request =>
// Should be better if User could contains List[UserGroup] instead of List[UUID]
val user = request.currentUser
val profile = EditProfileFormData(
user.firstName.orEmpty,
user.lastName.orEmpty,
user.qualite,
user.phoneNumber.orEmpty
)
val form = EditProfileFormData.form.fill(profile)
groupService
.byIdsFuture(user.groupIds)
.map { groups =>
eventService.log(UserProfileShowed, "Visualise la modification de profil")
Ok(views.html.editProfile(request.currentUser, request.rights)(form, user.email, groups))
}
.recoverWith { case exception =>
val message =
s"Impossible de visualiser la modification de profil : ${exception.getMessage}"
eventService.log(UserProfileShowedError, message)
Future.successful(InternalServerError(views.html.welcome(user, request.rights)))
}
}

def editProfile =
loginAction.async { implicit request =>
val user = request.currentUser
if (user.sharedAccount) {
eventService.log(UserProfileUpdatedError, "Impossible de modifier un profil partagé")
successful(BadRequest(views.html.welcome(user, request.rights)))
} else
EditProfileFormData.form
.bindFromRequest()
.fold(
errors => {
eventService.log(UserProfileUpdatedError, "Erreur lors de la modification du profil")
groupService
.byIdsFuture(user.groupIds)
.map(groups =>
BadRequest(
views.html.editProfile(user, request.rights)(errors, user.email, groups)
)
)
},
success => {
import success._
val edited =
userService.editProfile(user.id)(firstName, lastName, qualite, phoneNumber)
successful(edited)
.map { _ =>
val message = "Votre profil a bien été modifié"
eventService.log(UserProfileUpdated, message)
Redirect(routes.UserController.editProfile()).flashing("success" -> message)
}
.recover { e =>
val errorMessage = s"Erreur lors de la modification du profil: ${e.getMessage}"
eventService.log(UserProfileUpdatedError, errorMessage)
InternalServerError(views.html.welcome(user, request.rights))
}
}
)
}

def home =
loginAction {
TemporaryRedirect(controllers.routes.UserController.all(Area.allArea.id).url)
TemporaryRedirect(routes.UserController.all(Area.allArea.id).url)
}

def all(areaId: UUID): Action[AnyContent] =
Expand Down Expand Up @@ -282,7 +351,7 @@ case class UserController @Inject() (
val message = s"Utilisateur $userId / ${user.email} a été supprimé"
eventService.log(UserDeleted, message, involvesUser = Some(user))
Future(
Redirect(controllers.routes.UserController.home()).flashing("success" -> message)
Redirect(routes.UserController.home()).flashing("success" -> message)
)
}
}
Expand Down
5 changes: 5 additions & 0 deletions app/helper/StringHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ object StringHelper {
def unapply(s: String): Option[String] = s.some.map(_.trim).filter(_.nonEmpty)
}

implicit class StringOps(s: String) {
def normalized = StringHelper.commonStringInputNormalization(s)
def capitalizeWords = StringHelper.capitalizeName(s)
}

implicit class StringListOps(list: List[String]) {

def mkStringIfNonEmpty(start: String, sep: String, end: String) = {
Expand Down
5 changes: 5 additions & 0 deletions app/models/EventType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,9 @@ object EventType {
object StatsIncorrectSetup extends Warn
object TryLoginByKey extends Info
object UnknownEmail extends Warn

object UserProfileShowed extends Info
object UserProfileShowedError extends Error
object UserProfileUpdated extends Info
object UserProfileUpdatedError extends Error
}
28 changes: 27 additions & 1 deletion app/models/formModels.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,37 @@ import java.util.UUID

import play.api.data.Form
import play.api.data.Forms._
import play.api.data.validation.Constraints.maxLength
import play.api.data.validation.Constraints.{maxLength, nonEmpty, pattern}
import play.api.data.validation.{Constraint, Invalid, Valid, ValidationError}

object formModels {

final case class EditProfileFormData(
firstName: String,
lastName: String,
qualite: String,
phoneNumber: String
)

object EditProfileFormData {

val form: Form[EditProfileFormData] =
Form(
mapping(
"firstName" -> text.verifying(maxLength(100), nonEmpty),
"lastName" -> text.verifying(maxLength(100), nonEmpty),
"qualite" -> text.verifying(maxLength(100), nonEmpty),
"phone-number" -> text.verifying(
pattern(
"""0\d \d{2} \d{2} \d{2} \d{2}""".r,
error = "Le format doit être XX XX XX XX XX"
)
)
)(EditProfileFormData.apply)(EditProfileFormData.unapply)
)

}

case class ApplicationFormData(
subject: String,
description: String,
Expand Down
29 changes: 23 additions & 6 deletions app/services/UserService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@ import java.util.UUID

import anorm._
import cats.syntax.all._
import cats.implicits.{catsKernelStdMonoidForString, catsSyntaxOption}
import helper.StringHelper.{capitalizeName, normalizeNFKC, StringOps}
import helper.{Hash, Time}
import javax.inject.Inject
import models.User
import javax.inject.Inject
import models.User
import models.formModels.ValidateSubscriptionForm
import org.postgresql.util.PSQLException
import play.api.db.Database
import play.api.db.Database
import views.html.helper.form

import scala.concurrent.Future

Expand Down Expand Up @@ -251,4 +246,26 @@ class UserService @Inject() (
""".executeUpdate()
}

def editProfile(userId: UUID)(
firstName: String,
lastName: String,
qualite: String,
phoneNumber: String
) =
db.withConnection { implicit cnx =>
val normalizedFirstName = firstName.normalized
val normalizedLastName = lastName.normalized
val normalizedQualite = qualite.normalized
val name = s"${normalizedLastName.toUpperCase} ${normalizedFirstName.capitalizeWords}"
SQL"""
UPDATE "user" SET
name = $name,
first_name = ${normalizedFirstName.capitalizeWords},
last_name = ${normalizedLastName.capitalizeWords},
qualite = $normalizedQualite,
phone_number = $phoneNumber
WHERE id = $userId::uuid
""".executeUpdate()
}

}
80 changes: 80 additions & 0 deletions app/views/editProfile.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
@import _root_.helper.MDLForms._
@import models._
@import models.formModels.EditProfileFormData
@(currentUser: User, currentUserRights: Authorization.UserRights)(form: Form[EditProfileFormData], email: String, groups: List[UserGroup])(implicit webJarsUtil: org.webjars.play.WebJarsUtil, flash: Flash, messagesProvider: MessagesProvider, request: RequestHeader)

@main(currentUser, currentUserRights)(s"Mon profil") {
<link rel="stylesheet" media="screen,print" href='@routes.Assets.versioned("stylesheets/newForm.css")'>
} {
@helper.form(action = routes.UserController.editProfile(), "method" -> "post", "class" -> "mdl-grid mdl-cell mdl-cell--12-col") {
<h4 class="mdl-cell mdl-cell--8-col mdl-cell--12-col-phone">Mon profil</h4>
<div class="mdl-cell mdl-cell--8-col mdl-cell--12-col-phone">
Vous pouvez modifier les informations vous concernant</div>
<div class="mdl-cell mdl-cell--6-col-desktop mdl-cell--12-col">
@helper.CSRF.formField

@if(form.hasGlobalErrors) {
<div class="global-errors">@form.globalErrors.mkString(", ")</div>
}
@helper.input(form("id"), "label" -> "Id", "class" -> "hidden") { (id, name, value, args) =>
<input class="mdl-textfield__input" type="text" name="@name" id="@id" value="@value" @toHtmlArgs(args)>
} <br/>
@helper.input(form("email"), "label" -> "Email") { (id, name, _, args) =>
<input class="mdl-textfield__input"
type="text"
name="@name"
id="@id"
value="@email"
readonly
@toHtmlArgs(args)>
} <br/>
@helper.input(form("lastName"), "label" -> "Nom") { (id, name, value, args) =>
<input class="mdl-textfield__input"
type="text"
name="@name"
id="@id"
value="@value"
@toHtmlArgs(args)>
} <br/>
@helper.input(form("firstName"), "label" -> "Prénom") { (id, name, value, args) =>
<input class="mdl-textfield__input"
type="text"
name="@name"
id="@id"
value="@value"
@toHtmlArgs(args)>
} <br/>
@helper.input(form("qualite"), "label" -> "Fonction / Rôle") { (id, name, value, args) =>
<input class="mdl-textfield__input"
type="text"
name="@name"
id="@id"
value="@value"
@toHtmlArgs(args)>
} <br/>
@helper.input(form("phone-number"), "label" -> "Numéro de téléphone") { (id, name, value, args) =>
<input class="mdl-textfield__input"
type="text"
name="@name"
id="@id"
value="@value"
@toHtmlArgs(args)>
} <br/>
@if(groups.isEmpty) {
<div class="mdl-cell mdl-cell--8-col mdl-cell--12-col-phone">Vous n’appartenez à aucun groupe</div>
}
@if(groups.nonEmpty) {
<div class="mdl-cell mdl-cell--8-col mdl-cell--12-col-phone">Vous appartenez aux groupes suivants :</div>
@for(group <- groups) {
<div>@group.name</div>
}
}
</div>
<div class="mdl-cell mdl-cell--12-col">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-cell">
Sauvegarder
</button>
</div>
}
} {
}
1 change: 0 additions & 1 deletion app/views/helpers/menuNav.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
<i class="material-icons" role="presentation">folder_open</i>Mes demandes
</a>


@if(Authorization.isAdmin(currentUserRights)) {
<a @linkAttrs(routes.AreaController.all())>
<i class="material-icons" role="presentation">place</i>Territoires
Expand Down
13 changes: 11 additions & 2 deletions app/views/main.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,20 @@
<div class="hidden--small-screen">
<ul class="mdl-list">
<li class="mdl-list__item mdl-list__item--two-line">
<span class="mdl-list__item-primary-content">
<span class="mdl-list__item-primary-content single--line-height-24px">
<span>@currentUser.name</span>
<span class="mdl-list__item-sub-title">@currentUser.email</span>
</span>
<span class="mdl-list__item-secondary-content single--align-items-center-important">
@if(!currentUser.sharedAccount) {
<span class="mdl-list__item-secondary-content single--align-items-center-important">
<a class="mdl-list__item-secondary-action mdl-button mdl-js-button mdl-button--icon mdl-js-ripple-effect" href="@routes.UserController.editProfile()" title="Mon profil">
<i class="fas fa-user-circle"></i>
</a>
<span class="mdl-list__item-secondary-info"><a class="mdl-typography--font-regular mdl-color-text--grey-900 mdl-typography--text-nowrap" href="@routes.UserController.editProfile()" title="Mon profil">
Mon profil</a></span>
</span>
}
<span class="mdl-list__item-secondary-content single--align-items-center-important single--padding-left-40px">
<a class="mdl-list__item-secondary-action mdl-button mdl-js-button mdl-button--icon mdl-js-ripple-effect" href="@routes.LoginController.disconnect()" title="Déconnexion">
<i class="fas fa-sign-out-alt"></i>
</a>
Expand Down
2 changes: 2 additions & 0 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ GET /validation-connexion

# Users

GET /me controllers.UserController.showEditProfile
POST /me controllers.UserController.editProfile
GET /utilisateurs controllers.UserController.home
GET /utilisateurs/:userId controllers.UserController.editUser(userId: java.util.UUID)
POST /utilisateurs/:userId controllers.UserController.editUserPost(userId: java.util.UUID)
Expand Down
Loading

0 comments on commit c5d7cc3

Please sign in to comment.