Question

I'm using Play Framework (Scala) and SecureSocial to authenticate users.

I'd like my site to allow non-logged-in users to browse and populate certain user data (e.g. email address) during their session.

I have a custom UserService implementation that persists logged in users to the DB (and my own User model object that implements the securesocial.core.Identity Trait)

I have an UnregisteredUser subclass which I'd like to persist in the session while the user isn't logged in.

What's the best practise for this, please?

Was it helpful?

Solution

I imagine your particular goal is to efficiently gather the whole data relative to an unregistered user in each of your interested controller's action. Problem: We want to retrieve a build UnregisteredUser directly gathering all these data in session.

First, persist the UnregisteredUser data whenever you want in the session using the basic Play 2's api Sessions:

Ok("Welcome Guest User!").withSession(
  "email" -> "unregisteredUserEmail"  //  assuming a randomly chosen Id since not logged yet
  // many other data here
)

Then, you may simply write a trait extending your actual SecureSocial trait containing:

case class GuestRequest[A](optUnregisteredUser: Option[UnregisteredUser], request: Request[A]) extends WrappedRequest(request)

def GuestAction(f: GuestRequest[AnyContent] => Result): Action[AnyContent] = {
    implicit request => {
      val optUnregisteredUserEmail = session.get("currentUnregisteredUser")
      val unregisteredUser = UnregisteredUser(optUnregisteredUserEmail) 
      f(GuestRequest(optUnregisteredUser, request))
}

In each of your concerned controller, you would simply do:

def addToCard = GuestAction {
    implicit request =>
      val currentUnregisteredUser: UnregisteredUser = optUnregisteredUser.getOrElse(.....)
      //remaining instructions here
  }

--------------UPDATE-------------

Indeed, you could use UserAwareAction from existing SecureSocial trait for both User styles. Thus, you have to override UserAwareAction in your trait extending SecureSocial, in order to combine features:

    override def UserAwareAction[A](p: BodyParser[A])(f: RequestWithUser[A] => Result) = Action(p) {
        implicit request => {
          val user = for (
            authenticator <- authenticatorFromRequest;
            user <- userServices.findByUserName(authenticator.userName)
          ) yield {
            touch(authenticator)
            user
          }
          if(user.isEmpty){  //meaning user is not logged
            f(RequestWithUser(tryToBuildUnRegisteredUser, request))  //setting your unregisteredUser
          }
          else{
            f(RequestWithUser(user, request))
          }
        }
      }

 private def tryToBuildUnregisteredUser = {
    val optUnregisteredUserEmail = session.get("currentUnregisteredUser")
    optUnregisteredUserEmail match {
      case Some(e) => Some(UnregisteredUser(e)) 
      case _ => None
    }
 }

Of course, you are free to refactor it :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top