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?
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 :)