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

Change UserService trait to use the GenericProfile trait as the user type, instead of locking in the BasicProfile case class #545

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ trait BasePasswordReset[U] extends MailTokenBasedOperations[U] {
case Some(profile) =>
val hashed = env.currentHasher.hash(p._1)
for (
updated <- env.userService.save(profile.copy(passwordInfo = Some(hashed)), SaveMode.PasswordChange);
updated <- env.userService.save(BasicProfile.from(profile).copy(passwordInfo = Some(hashed)), SaveMode.PasswordChange);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the extent of real code changes. Since you can't enforce that a GenericProfile has a copy constructor, I'm using the BasicProfile to affect this change.

deleted <- env.userService.deleteToken(token)
) yield {
env.mailer.sendPasswordChangedNotice(profile)
Expand Down
18 changes: 9 additions & 9 deletions module-code/app/securesocial/controllers/ViewsPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import play.api.data.Form
import play.api.i18n.Lang
import play.api.mvc.RequestHeader
import play.twirl.api.{ Html, Txt }
import securesocial.core.{ BasicProfile, RuntimeEnvironment }
import securesocial.core.{ GenericProfile, RuntimeEnvironment }

/**
* A trait that provides the pages for SecureSocial
Expand Down Expand Up @@ -88,7 +88,7 @@ trait MailTemplates {
* @param request the current request
* @return a tuple with the text and/or html body for the email
*/
def getAlreadyRegisteredEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])
def getAlreadyRegisteredEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])

/**
* Returns the welcome email sent when the user finished the sign up process
Expand All @@ -97,7 +97,7 @@ trait MailTemplates {
* @param request the current request
* @return a String with the text and/or html body for the email
*/
def getWelcomeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])
def getWelcomeEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])

/**
* Returns the email sent when a user tries to reset the password but there is no account for
Expand All @@ -116,7 +116,7 @@ trait MailTemplates {
* @param request the current http request
* @return a String with the text and/or html body for the email
*/
def getSendPasswordResetEmail(user: BasicProfile, token: String)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])
def getSendPasswordResetEmail(user: GenericProfile, token: String)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])

/**
* Returns the email sent as a confirmation of a password change
Expand All @@ -125,7 +125,7 @@ trait MailTemplates {
* @param request the current http request
* @return a String with the text and/or html body for the email
*/
def getPasswordChangedNoticeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])
def getPasswordChangedNoticeEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html])

}

Expand Down Expand Up @@ -177,23 +177,23 @@ object MailTemplates {
(None, Some(securesocial.views.html.mails.signUpEmail(token)))
}

def getAlreadyRegisteredEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
def getAlreadyRegisteredEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
(None, Some(securesocial.views.html.mails.alreadyRegisteredEmail(user)))
}

def getWelcomeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
def getWelcomeEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
(None, Some(securesocial.views.html.mails.welcomeEmail(user)))
}

def getUnknownEmailNotice()(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
(None, Some(securesocial.views.html.mails.unknownEmailNotice()))
}

def getSendPasswordResetEmail(user: BasicProfile, token: String)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
def getSendPasswordResetEmail(user: GenericProfile, token: String)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
(None, Some(securesocial.views.html.mails.passwordResetEmail(user, token)))
}

def getPasswordChangedNoticeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
def getPasswordChangedNoticeEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = {
(None, Some(securesocial.views.html.mails.passwordChangedNotice(user)))
}
}
Expand Down
2 changes: 1 addition & 1 deletion module-code/app/securesocial/core/IdentityProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ object AuthenticationResult {
* Returned when the user was succesfully authenticated
* @param profile the authenticated user profile
*/
case class Authenticated(profile: BasicProfile) extends AuthenticationResult
case class Authenticated(profile: GenericProfile) extends AuthenticationResult

/**
* Returned when the authentication process failed for some reason.
Expand Down
14 changes: 14 additions & 0 deletions module-code/app/securesocial/core/UserProfile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ case class BasicProfile(
oAuth2Info: Option[OAuth2Info] = None,
passwordInfo: Option[PasswordInfo] = None) extends GenericProfile

object BasicProfile {
def from(p: GenericProfile) = BasicProfile(
providerId = p.providerId,
userId = p.userId,
firstName = p.firstName,
lastName = p.lastName,
fullName = p.fullName,
email = p.email,
avatarUrl = p.avatarUrl,
authMethod = p.authMethod,
oAuth1Info = p.oAuth1Info,
oAuth2Info = p.oAuth2Info,
passwordInfo = p.passwordInfo)
}
/**
* The OAuth 1 details
*
Expand Down
36 changes: 18 additions & 18 deletions module-code/app/securesocial/core/java/BaseUserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import scala.*;
import scala.Option;
import scala.concurrent.Future;
import securesocial.core.BasicProfile;
import securesocial.core.GenericProfile;
import securesocial.core.PasswordInfo;
import securesocial.core.providers.MailToken;
import securesocial.core.services.SaveMode;
Expand All @@ -45,10 +45,10 @@ protected BaseUserService() {
* @return an optional user
*/
@Override
public Future<Option<BasicProfile>> find(String providerId, String userId) {
return doFind(providerId, userId).map(new F.Function<BasicProfile, Option<BasicProfile>>() {
public Future<Option<GenericProfile>> find(String providerId, String userId) {
return doFind(providerId, userId).map(new F.Function<GenericProfile, Option<GenericProfile>>() {
@Override
public Option<BasicProfile> apply(BasicProfile user) throws Throwable {
public Option<GenericProfile> apply(GenericProfile user) throws Throwable {
return Scala.Option(user);
}
}).wrapped();
Expand All @@ -65,9 +65,9 @@ public Option<BasicProfile> apply(BasicProfile user) throws Throwable {
* @return
*/
@Override
public Future<Option<BasicProfile>> findByEmailAndProvider(String email, String providerId) {
return doFindByEmailAndProvider(email, providerId).map(new F.Function<BasicProfile, Option<BasicProfile>>() {
public Option<BasicProfile> apply(BasicProfile user) throws Throwable {
public Future<Option<GenericProfile>> findByEmailAndProvider(String email, String providerId) {
return doFindByEmailAndProvider(email, providerId).map(new F.Function<GenericProfile, Option<GenericProfile>>() {
public Option<GenericProfile> apply(GenericProfile user) throws Throwable {
return Scala.Option(user);
}
}).wrapped();
Expand All @@ -80,7 +80,7 @@ public Option<BasicProfile> apply(BasicProfile user) throws Throwable {
* @param user
*/
@Override
public Future<U> save(BasicProfile user, SaveMode mode) {
public Future<U> save(GenericProfile user, SaveMode mode) {
return doSave(user, mode).wrapped();
}

Expand All @@ -91,7 +91,7 @@ public Future<U> save(BasicProfile user, SaveMode mode) {
* @param to The Identity that needs to be linked to the current user
*/
@Override
public Future<U> link(U current, BasicProfile to) {
public Future<U> link(U current, GenericProfile to) {
return doLink(current, to).wrapped();
}

Expand All @@ -106,11 +106,11 @@ public Option<PasswordInfo> apply(PasswordInfo passwordInfo) throws Throwable {
}

@Override
public Future<scala.Option<BasicProfile>> updatePasswordInfo(U user, PasswordInfo info) {
return doUpdatePasswordInfo(user, info).map(new F.Function<BasicProfile, Option<BasicProfile>>() {
public Future<scala.Option<GenericProfile>> updatePasswordInfo(U user, PasswordInfo info) {
return doUpdatePasswordInfo(user, info).map(new F.Function<GenericProfile, Option<GenericProfile>>() {
@Override
public Option<BasicProfile> apply(BasicProfile basicProfile) throws Throwable {
return Scala.Option(basicProfile);
public Option<GenericProfile> apply(GenericProfile GenericProfile) throws Throwable {
return Scala.Option(GenericProfile);
}
}).wrapped();
}
Expand Down Expand Up @@ -192,7 +192,7 @@ public void deleteExpiredTokens() {
*
* @param user
*/
public abstract F.Promise<U> doSave(BasicProfile user, SaveMode mode);
public abstract F.Promise<U> doSave(GenericProfile user, SaveMode mode);

/**
* Saves a token
Expand All @@ -210,17 +210,17 @@ public void deleteExpiredTokens() {
* @param current The Identity of the current user
* @param to The Identity that needs to be linked to the current user
*/
public abstract F.Promise<U> doLink(U current, BasicProfile to);
public abstract F.Promise<U> doLink(U current, GenericProfile to);

/**
* Finds the user in the backing store.
* @return an Identity instance or null if no user matches the specified id
*/
public abstract F.Promise<BasicProfile> doFind(String providerId, String userId);
public abstract F.Promise<GenericProfile> doFind(String providerId, String userId);

public abstract F.Promise<PasswordInfo> doPasswordInfoFor(U user);

public abstract F.Promise<BasicProfile> doUpdatePasswordInfo(U user, PasswordInfo info);
public abstract F.Promise<GenericProfile> doUpdatePasswordInfo(U user, PasswordInfo info);

/**
* Finds a token
Expand All @@ -244,7 +244,7 @@ public void deleteExpiredTokens() {
* @param providerId - the provider id
* @return an Identity instance or null if no user matches the specified id
*/
public abstract F.Promise<BasicProfile> doFindByEmailAndProvider(String email, String providerId);
public abstract F.Promise<GenericProfile> doFindByEmailAndProvider(String email, String providerId);

/**
* Deletes a token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class GoogleProvider(routesService: RoutesService,
(me \ Error).asOpt[JsObject] match {
case Some(error) =>
val message = (error \ Message).as[String]
val errorCode = (error \ Code).as[String]
val errorCode = (error \ Code).as[Int]
logger.error(s"[securesocial] error retrieving profile information from Google. Error type = $errorCode, message = $message")
throw new AuthenticationException()
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class UsernamePasswordProvider[U](userService: UserService[U],
doAuthentication()
}

private def profileForCredentials(userId: String, password: String): Future[Option[BasicProfile]] = {
private def profileForCredentials(userId: String, password: String): Future[Option[GenericProfile]] = {
userService.find(id, userId).map { maybeUser =>
for (
user <- maybeUser;
Expand All @@ -71,10 +71,10 @@ class UsernamePasswordProvider[U](userService: UserService[U],
NavigationFlow(badRequest(UsernamePasswordProvider.loginForm, Some(InvalidCredentials)))
}

protected def withUpdatedAvatar(profile: BasicProfile): Future[BasicProfile] = {
protected def withUpdatedAvatar(profile: GenericProfile): Future[GenericProfile] = {
(avatarService, profile.email) match {
case (Some(service), Some(e)) => service.urlFor(e).map {
case url if url != profile.avatarUrl => profile.copy(avatarUrl = url)
case url if url != profile.avatarUrl => BasicProfile.from(profile).copy(avatarUrl = url)
case _ => profile
}
case _ => Future.successful(profile)
Expand Down
18 changes: 9 additions & 9 deletions module-code/app/securesocial/core/providers/utils/Mailer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ import play.api.libs.concurrent.Akka
import play.api.mvc.RequestHeader
import play.twirl.api.{ Txt, Html }
import securesocial.controllers.MailTemplates
import securesocial.core.BasicProfile
import securesocial.core.GenericProfile
/**
* A helper trait to send email notifications
*/
trait Mailer {
def sendAlreadyRegisteredEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang)
def sendAlreadyRegisteredEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang)
def sendSignUpEmail(to: String, token: String)(implicit request: RequestHeader, lang: Lang)
def sendWelcomeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang)
def sendPasswordResetEmail(user: BasicProfile, token: String)(implicit request: RequestHeader, lang: Lang)
def sendWelcomeEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang)
def sendPasswordResetEmail(user: GenericProfile, token: String)(implicit request: RequestHeader, lang: Lang)
def sendUnkownEmailNotice(email: String)(implicit request: RequestHeader, lang: Lang)
def sendPasswordChangedNotice(user: BasicProfile)(implicit request: RequestHeader, lang: Lang)
def sendPasswordChangedNotice(user: GenericProfile)(implicit request: RequestHeader, lang: Lang)
def sendEmail(subject: String, recipient: String, body: (Option[Txt], Option[Html]))
}

Expand All @@ -53,7 +53,7 @@ object Mailer {
val UnknownEmailNoticeSubject = "mails.unknownEmail.subject"
val PasswordResetOkSubject = "mails.passwordResetOk.subject"

override def sendAlreadyRegisteredEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) {
override def sendAlreadyRegisteredEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang) {
val txtAndHtml = mailTemplates.getAlreadyRegisteredEmail(user)
sendEmail(Messages(AlreadyRegisteredSubject), user.email.get, txtAndHtml)

Expand All @@ -64,13 +64,13 @@ object Mailer {
sendEmail(Messages(SignUpEmailSubject), to, txtAndHtml)
}

override def sendWelcomeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) {
override def sendWelcomeEmail(user: GenericProfile)(implicit request: RequestHeader, lang: Lang) {
val txtAndHtml = mailTemplates.getWelcomeEmail(user)
sendEmail(Messages(WelcomeEmailSubject), user.email.get, txtAndHtml)

}

override def sendPasswordResetEmail(user: BasicProfile, token: String)(implicit request: RequestHeader, lang: Lang) {
override def sendPasswordResetEmail(user: GenericProfile, token: String)(implicit request: RequestHeader, lang: Lang) {
val txtAndHtml = mailTemplates.getSendPasswordResetEmail(user, token)
sendEmail(Messages(PasswordResetSubject), user.email.get, txtAndHtml)
}
Expand All @@ -80,7 +80,7 @@ object Mailer {
sendEmail(Messages(UnknownEmailNoticeSubject), email, txtAndHtml)
}

override def sendPasswordChangedNotice(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) {
override def sendPasswordChangedNotice(user: GenericProfile)(implicit request: RequestHeader, lang: Lang) {
val txtAndHtml = mailTemplates.getPasswordChangedNoticeEmail(user)
sendEmail(Messages(PasswordResetOkSubject), user.email.get, txtAndHtml)
}
Expand Down
12 changes: 6 additions & 6 deletions module-code/app/securesocial/core/services/UserService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package securesocial.core.services

import scala.concurrent.Future
import securesocial.core.{ PasswordInfo, BasicProfile }
import securesocial.core.{ PasswordInfo, GenericProfile }
import securesocial.core.providers.MailToken

trait UserService[U] {
Expand All @@ -29,7 +29,7 @@ trait UserService[U] {
* @param userId the user id
* @return an optional profile
*/
def find(providerId: String, userId: String): Future[Option[BasicProfile]]
def find(providerId: String, userId: String): Future[Option[GenericProfile]]

/**
* Finds a profile by email and provider
Expand All @@ -38,7 +38,7 @@ trait UserService[U] {
* @param providerId - the provider id
* @return an optional profile
*/
def findByEmailAndProvider(email: String, providerId: String): Future[Option[BasicProfile]]
def findByEmailAndProvider(email: String, providerId: String): Future[Option[GenericProfile]]

/**
* Saves a profile. This method gets called when a user logs in, registers or changes his password.
Expand All @@ -47,15 +47,15 @@ trait UserService[U] {
* @param profile the user profile
* @param mode a mode that tells you why the save method was called
*/
def save(profile: BasicProfile, mode: SaveMode): Future[U]
def save(profile: GenericProfile, mode: SaveMode): Future[U]

/**
* Links the current user to another profile
*
* @param current The current user instance
* @param to the profile that needs to be linked to
*/
def link(current: U, to: BasicProfile): Future[U]
def link(current: U, to: GenericProfile): Future[U]

/**
* Returns an optional PasswordInfo instance for a given user
Expand All @@ -72,7 +72,7 @@ trait UserService[U] {
* @param info the password info
* @return
*/
def updatePasswordInfo(user: U, info: PasswordInfo): Future[Option[BasicProfile]]
def updatePasswordInfo(user: U, info: PasswordInfo): Future[Option[GenericProfile]]

/**
* Saves a mail token. This is needed for users that
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@(user: securesocial.core.BasicProfile)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])
@(user: securesocial.core.GenericProfile)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])

<html>
<body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@(user: securesocial.core.BasicProfile)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])
@(user: securesocial.core.GenericProfile)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])

<html>
<body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@(user: securesocial.core.BasicProfile, mailToken: String)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])
@(user: securesocial.core.GenericProfile, mailToken: String)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])
@import securesocial.core.IdentityProvider
<html>
<body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@(user: securesocial.core.BasicProfile)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])
@(user: securesocial.core.GenericProfile)(implicit request: RequestHeader, lang: Lang, env: securesocial.core.RuntimeEnvironment[_])
<html>
<body>
<p>Welcome @user.firstName,</p>
Expand Down
Loading