From 4f2861ed36338365ec11c2c942e1792478bbd62a Mon Sep 17 00:00:00 2001 From: Leonid Vygovskiy Date: Sun, 28 Sep 2014 14:50:48 +0400 Subject: [PATCH 01/10] UserService works with trait GenericProfile instead of BasicProfile Reasons: 1. Scala doesn't allow to extends case class from case class. 2. Coding into interfaces is good OOP practices --- .../test/helpers/MockHttpService.scala | 4 +- module-code/test/helpers/package.scala | 4 +- .../test/scenarios/GoogleLoginSpec.scala | 49 ++++++++----------- module-code/test/scenarios/helpers/Api.scala | 26 +++++----- .../scenarios/helpers/TestUserService.scala | 26 +++++----- .../test/scenarios/helpers/package.scala | 8 +-- .../securesocial/core/OAuth1ClientSpec.scala | 44 ++++++++--------- .../securesocial/core/OAuth2ClientSpec.scala | 28 ++++------- .../scala/demo/test/ApplicationScenario.scala | 6 +-- samples/scala/demo/test/ApplicationSpec.scala | 8 +-- 10 files changed, 92 insertions(+), 111 deletions(-) diff --git a/module-code/test/helpers/MockHttpService.scala b/module-code/test/helpers/MockHttpService.scala index 5f5c6892b..eb1c2354b 100644 --- a/module-code/test/helpers/MockHttpService.scala +++ b/module-code/test/helpers/MockHttpService.scala @@ -1,7 +1,7 @@ package helpers import org.specs2.mock.Mockito -import play.api.http.{ContentTypeOf, Writeable, HeaderNames} +import play.api.http.{ ContentTypeOf, Writeable, HeaderNames } import play.api.libs.ws._ import play.api.http.Status._ import scala.concurrent.Future @@ -20,7 +20,7 @@ class MockHttpService extends Mockito with HttpService { val request = mock[WSRequestHolder].as(s"Request($hashCode)") val response = mock[Response].as(s"Response($hashCode") - val urls:collection.mutable.Buffer[String] = new collection.mutable.ArrayBuffer[String]() + val urls: collection.mutable.Buffer[String] = new collection.mutable.ArrayBuffer[String]() response.status returns OK response.header(HeaderNames.CONTENT_TYPE) returns Some("text/html;charset=UTF-8") diff --git a/module-code/test/helpers/package.scala b/module-code/test/helpers/package.scala index 058b17ce7..187144e5f 100644 --- a/module-code/test/helpers/package.scala +++ b/module-code/test/helpers/package.scala @@ -1,9 +1,9 @@ -import java.util.concurrent.{Executor, Executors} +import java.util.concurrent.{ Executor, Executors } import scala.concurrent.ExecutionContext package object helpers { class CurrentThreadExecutor extends Executor { - def execute(r:Runnable) { + def execute(r: Runnable) { r.run() } } diff --git a/module-code/test/scenarios/GoogleLoginSpec.scala b/module-code/test/scenarios/GoogleLoginSpec.scala index e6972fe1a..31c637fdc 100644 --- a/module-code/test/scenarios/GoogleLoginSpec.scala +++ b/module-code/test/scenarios/GoogleLoginSpec.scala @@ -2,12 +2,12 @@ package scenarios import org.specs2.mutable.Specification import org.specs2.mock.Mockito -import play.api.test.{FakeApplication, PlaySpecification, WithApplication} +import play.api.test.{ FakeApplication, PlaySpecification, WithApplication } -import scenarios.helpers.{TestGlobal, DemoUser, TestUserService} +import scenarios.helpers.{ TestGlobal, DemoUser, TestUserService } import securesocial.core.providers.GoogleProvider -import securesocial.core.{IdentityProvider, EventListener, RuntimeEnvironment} -import securesocial.core.services.{HttpService, UserService, RoutesService} +import securesocial.core.{ IdentityProvider, EventListener, RuntimeEnvironment } +import securesocial.core.services.{ HttpService, UserService, RoutesService } import play.api.libs.ws.WS.WSRequestHolder import org.specs2.matcher.Matcher import play.api.libs.ws.Response @@ -19,12 +19,11 @@ import java.io.File class GoogleLoginSpec extends PlaySpecification with Mockito { - - def hasCode:Matcher[Map[String,Seq[String]]]=(map:Map[String,Seq[String]])=>map must contain("code" -> Seq("code")) + def hasCode: Matcher[Map[String, Seq[String]]] = (map: Map[String, Seq[String]]) => map must contain("code" -> Seq("code")) "an application using secure social" should { - val testGlobal=new TestGlobal(new TestEnvironment(_httpService = mock[HttpService])) - val application: FakeApplication = FakeApplication(withGlobal = Some(testGlobal), additionalConfiguration = googleConfig ) - "log a valid google user" in new WithApplication(application){ + val testGlobal = new TestGlobal(new TestEnvironment(_httpService = mock[HttpService])) + val application: FakeApplication = FakeApplication(withGlobal = Some(testGlobal), additionalConfiguration = googleConfig) + "log a valid google user" in new WithApplication(application) { val _httpService: HttpService = mock[HttpService].as("_httpService") val userInfoHolder: WSRequestHolder = mock[WSRequestHolder].as("userInfoHolder") val userInfoResponse: Response = mock[Response].as("userInfoResponse") @@ -32,7 +31,7 @@ class GoogleLoginSpec extends PlaySpecification with Mockito { val accessTokenResponse: Response = mock[Response].as("accessTokenResponse") _httpService.url("accessTokenUrl") returns accessTokenHolder _httpService.url("https://www.googleapis.com/oauth2/v1/userinfo?access_token=accessToken") returns userInfoHolder - accessTokenHolder.post(any[Map[String,Seq[String]]])(any,any) returns Future.successful(accessTokenResponse) + accessTokenHolder.post(any[Map[String, Seq[String]]])(any, any) returns Future.successful(accessTokenResponse) userInfoHolder.get() returns Future.successful(userInfoResponse) accessTokenResponse.json returns Json.parse( """ @@ -48,43 +47,35 @@ class GoogleLoginSpec extends PlaySpecification with Mockito { |"email": "test@example.com" |} """.stripMargin) - testGlobal.runtimeEnvironment=new TestEnvironment(_httpService = _httpService) + testGlobal.runtimeEnvironment = new TestEnvironment(_httpService = _httpService) val loginResponse = authenticate(GoogleProvider.Google) status(loginResponse) === 303 val location: Option[String] = redirectLocation(loginResponse) location must beSome(startWith("authorizationUrl")) val state = "state=([^&]*)".r.findFirstMatchIn(location.get).get.group(1) - val sid=session(loginResponse).get("sid").get + val sid = session(loginResponse).get("sid").get - val authenticateResponse = callback(GoogleProvider.Google,Some(state), Some("code"), session=List(("sid",sid))) + val authenticateResponse = callback(GoogleProvider.Google, Some(state), Some("code"), session = List(("sid", sid))) status(authenticateResponse) === 303 - redirectLocation(authenticateResponse)=== Some("/") + redirectLocation(authenticateResponse) === Some("/") } } - + import scala.collection.immutable.ListMap - class TestEnvironment( _routes: => RoutesService = new RoutesService.Default(), - _userService: =>UserService[DemoUser] = new TestUserService(), - _eventListeners: => List[EventListener[DemoUser]] = Nil, - _httpService : => HttpService = new HttpService.Default() - ) extends RuntimeEnvironment.Default[DemoUser] { + class TestEnvironment(_routes: => RoutesService = new RoutesService.Default(), + _userService: => UserService[DemoUser] = new TestUserService(), + _eventListeners: => List[EventListener[DemoUser]] = Nil, + _httpService: => HttpService = new HttpService.Default()) extends RuntimeEnvironment.Default[DemoUser] { override lazy val routes: RoutesService = _routes override lazy val userService: UserService[DemoUser] = _userService override lazy val eventListeners: List[EventListener[DemoUser]] = _eventListeners - override lazy val httpService : HttpService = _httpService + override lazy val httpService: HttpService = _httpService override lazy val providers: ListMap[String, IdentityProvider] = ListMap(include(new GoogleProvider(routes, cacheService, oauth2ClientFor(GoogleProvider.Google)))) } val googleConfig = Map( - "smtp.mock"->true - , "application.secret"->"secret" - , "application.router"->"securesocial.Routes" - , "securesocial.google.clientId"->"clientid" - , "securesocial.google.clientSecret"->"clientsecret" - , "securesocial.google.authorizationUrl"->"authorizationUrl" - , "securesocial.google.accessTokenUrl"->"accessTokenUrl" - , "securesocial.google.scope"->"scope" + "smtp.mock" -> true, "application.secret" -> "secret", "application.router" -> "securesocial.Routes", "securesocial.google.clientId" -> "clientid", "securesocial.google.clientSecret" -> "clientsecret", "securesocial.google.authorizationUrl" -> "authorizationUrl", "securesocial.google.accessTokenUrl" -> "accessTokenUrl", "securesocial.google.scope" -> "scope" ) } diff --git a/module-code/test/scenarios/helpers/Api.scala b/module-code/test/scenarios/helpers/Api.scala index 4be48978d..f1bd6fbe4 100644 --- a/module-code/test/scenarios/helpers/Api.scala +++ b/module-code/test/scenarios/helpers/Api.scala @@ -1,22 +1,22 @@ package scenarios.helpers -import play.api.test.{PlayRunners, Writeables, RouteInvokers, FakeRequest} +import play.api.test.{ PlayRunners, Writeables, RouteInvokers, FakeRequest } import play.api.Logger import securesocial.Routes -trait SocialProviders{ - self:ApiExecutor => - def authenticate(provider:String, redirectTo: Option[String]=None)={ - val redirectParam = redirectTo.map(s=>s"redirectTo=$s") - val params = List(redirectParam).flatten.mkString("?","&","") - route(FakeRequest(GET,s"/authenticate/google$params")).get +trait SocialProviders { + self: ApiExecutor => + def authenticate(provider: String, redirectTo: Option[String] = None) = { + val redirectParam = redirectTo.map(s => s"redirectTo=$s") + val params = List(redirectParam).flatten.mkString("?", "&", "") + route(FakeRequest(GET, s"/authenticate/google$params")).get } - def callback(provider:String, state:Option[String]=None, code:Option[String]=None,redirectTo: Option[String]=None, session:Seq[(String, String)] = Nil)={ - val redirectParam = redirectTo.map(s=>s"redirectTo=$s") - val stateParam = state.map(s=>s"state=$s") - val codeParam = code.map(s=>s"code=$s") - val params = List(redirectParam, stateParam, codeParam).flatten.mkString("?","&","") - route(FakeRequest(GET,s"/authenticate/google$params").withSession(session:_*)).get + def callback(provider: String, state: Option[String] = None, code: Option[String] = None, redirectTo: Option[String] = None, session: Seq[(String, String)] = Nil) = { + val redirectParam = redirectTo.map(s => s"redirectTo=$s") + val stateParam = state.map(s => s"state=$s") + val codeParam = code.map(s => s"code=$s") + val params = List(redirectParam, stateParam, codeParam).flatten.mkString("?", "&", "") + route(FakeRequest(GET, s"/authenticate/google$params").withSession(session: _*)).get } } diff --git a/module-code/test/scenarios/helpers/TestUserService.scala b/module-code/test/scenarios/helpers/TestUserService.scala index 32891a377..5f525fe74 100644 --- a/module-code/test/scenarios/helpers/TestUserService.scala +++ b/module-code/test/scenarios/helpers/TestUserService.scala @@ -18,10 +18,9 @@ package scenarios.helpers import play.api.Logger import securesocial.core._ -import securesocial.core.providers.{UsernamePasswordProvider, MailToken} +import securesocial.core.providers.{ UsernamePasswordProvider, MailToken } import scala.concurrent.Future -import securesocial.core.services.{UserService, SaveMode} - +import securesocial.core.services.{ UserService, SaveMode } /** * A Sample In Memory user service in Scala @@ -38,11 +37,11 @@ class TestUserService extends UserService[DemoUser] { private var tokens = Map[String, MailToken]() def find(providerId: String, userId: String): Future[Option[BasicProfile]] = { - if ( logger.isDebugEnabled ) { + if (logger.isDebugEnabled) { logger.debug("users = %s".format(users)) } val result = for ( - user <- users.values ; + user <- users.values; basicProfile <- user.identities.find(su => su.providerId == providerId && su.userId == userId) ) yield { basicProfile @@ -51,12 +50,12 @@ class TestUserService extends UserService[DemoUser] { } def findByEmailAndProvider(email: String, providerId: String): Future[Option[BasicProfile]] = { - if ( logger.isDebugEnabled ) { + if (logger.isDebugEnabled) { logger.debug("users = %s".format(users)) } val someEmail = Some(email) val result = for ( - user <- users.values ; + user <- users.values; basicProfile <- user.identities.find(su => su.providerId == providerId && su.email == someEmail) ) yield { basicProfile @@ -74,13 +73,13 @@ class TestUserService extends UserService[DemoUser] { } // first see if there is a user with this BasicProfile already. val maybeUser = users.find { - case (key, value) if value.identities.exists(su => su.providerId == user.providerId && su.userId == user.userId ) => true + case (key, value) if value.identities.exists(su => su.providerId == user.providerId && su.userId == user.userId) => true case _ => false } maybeUser match { case Some(existingUser) => val identities = existingUser._2.identities - val updatedList = identities.patch( identities.indexWhere( i => i.providerId == user.providerId && i.userId == user.userId ), Seq(user), 1) + val updatedList = identities.patch(identities.indexWhere(i => i.providerId == user.providerId && i.userId == user.userId), Seq(user), 1) val updatedUser = existingUser._2.copy(identities = updatedList) users = users + (existingUser._1 -> updatedUser) Future.successful(updatedUser) @@ -93,7 +92,7 @@ class TestUserService extends UserService[DemoUser] { } def link(current: DemoUser, to: BasicProfile): Future[DemoUser] = { - if ( current.identities.exists(i => i.providerId == to.providerId && i.userId == to.userId)) { + if (current.identities.exists(i => i.providerId == to.providerId && i.userId == to.userId)) { Future.successful(current) } else { val added = to :: current.identities @@ -125,9 +124,9 @@ class TestUserService extends UserService[DemoUser] { } } -// def deleteTokens(): Future { -// tokens = Map() -// } + // def deleteTokens(): Future { + // tokens = Map() + // } def deleteExpiredTokens() { tokens = tokens.filter(!_._2.isExpired) @@ -163,4 +162,3 @@ class TestUserService extends UserService[DemoUser] { // a simple User class that can have multiple identities case class DemoUser(main: BasicProfile, identities: List[BasicProfile]) - diff --git a/module-code/test/scenarios/helpers/package.scala b/module-code/test/scenarios/helpers/package.scala index 00dd7a69d..7b055c2a5 100644 --- a/module-code/test/scenarios/helpers/package.scala +++ b/module-code/test/scenarios/helpers/package.scala @@ -1,14 +1,14 @@ package scenarios import java.lang.reflect.Constructor -import play.api.test.{Writeables, RouteInvokers, PlayRunners} +import play.api.test.{ Writeables, RouteInvokers, PlayRunners } import securesocial.core.RuntimeEnvironment -import securesocial.core.services.{UserService, RoutesService} +import securesocial.core.services.{ UserService, RoutesService } package object helpers { type ApiExecutor = PlayRunners with RouteInvokers with Writeables - class TestGlobal[U]( var runtimeEnvironment:RuntimeEnvironment[U]) extends play.api.GlobalSettings { + class TestGlobal[U](var runtimeEnvironment: RuntimeEnvironment[U]) extends play.api.GlobalSettings { /** * An implementation that checks if the controller expects a RuntimeEnvironment and @@ -21,7 +21,7 @@ package object helpers { * @return */ override def getControllerInstance[A](controllerClass: Class[A]): A = { - val instance = controllerClass.getConstructors.find { c => + val instance = controllerClass.getConstructors.find { c => val params = c.getParameterTypes params.length == 1 && params(0) == classOf[RuntimeEnvironment[U]] }.map { diff --git a/module-code/test/securesocial/core/OAuth1ClientSpec.scala b/module-code/test/securesocial/core/OAuth1ClientSpec.scala index bc90af068..c8d57bf7e 100644 --- a/module-code/test/securesocial/core/OAuth1ClientSpec.scala +++ b/module-code/test/securesocial/core/OAuth1ClientSpec.scala @@ -13,11 +13,11 @@ import play.api.libs.oauth.RequestToken import play.api.libs.oauth.ConsumerKey class OAuth1ClientSpec extends Specification with Mockito { - val fakeServiceInfo= new ServiceInfo("requestTokenUrl","accessTokenUrl", "authorizationUrl", ConsumerKey("consumerKey","consumerSecret")) + val fakeServiceInfo = new ServiceInfo("requestTokenUrl", "accessTokenUrl", "authorizationUrl", ConsumerKey("consumerKey", "consumerSecret")) "The default OAuth1Client" should { "provide the redirectUrl given a token" in { - val client=aDefaultClient() + val client = aDefaultClient() val token: String = "token" val expectedRedirectUrl: String = "redirectUrl" client.client.redirectUrl(token) returns expectedRedirectUrl @@ -27,9 +27,9 @@ class OAuth1ClientSpec extends Specification with Mockito { } "retrieve the requestToken when the endpoint is correct" in { implicit val ec = helpers.sequentialExecutionContext - val client=aDefaultClient() + val client = aDefaultClient() val callbackUrl: String = "callbackUrl" - val expectedRequestToken = RequestToken("token","secret") + val expectedRequestToken = RequestToken("token", "secret") client.client.retrieveRequestToken(callbackUrl) returns Right(expectedRequestToken) val actualRequestToken = client.retrieveRequestToken(callbackUrl) @@ -38,9 +38,9 @@ class OAuth1ClientSpec extends Specification with Mockito { } "fail to retrieve the requestToken with an OAuthException when the endpoint is incorrect" in { implicit val ec = helpers.sequentialExecutionContext - val client=aDefaultClient() + val client = aDefaultClient() val callbackUrl: String = "incorrectCallbackUrl" - val expectedException= new OAuthException("invalid endpoint") {} + val expectedException = new OAuthException("invalid endpoint") {} client.client.retrieveRequestToken(callbackUrl) returns Left(expectedException) val actualRequestToken = client.retrieveRequestToken(callbackUrl) @@ -49,49 +49,49 @@ class OAuth1ClientSpec extends Specification with Mockito { } "retrieve the OAuth1Info given a valid request token and a verifier" in { implicit val ec = helpers.sequentialExecutionContext - val client=aDefaultClient() + val client = aDefaultClient() val verifier: String = "verifier" - val requestToken = RequestToken("requestToken","requestSecret") + val requestToken = RequestToken("requestToken", "requestSecret") val accessToken: RequestToken = RequestToken("accessToken", "accessSecret") - client.client.retrieveAccessToken(requestToken,verifier) returns Right(accessToken) + client.client.retrieveAccessToken(requestToken, verifier) returns Right(accessToken) - val actualOAuth1Info= client.retrieveOAuth1Info(requestToken,verifier) + val actualOAuth1Info = client.retrieveOAuth1Info(requestToken, verifier) - actualOAuth1Info must beEqualTo(OAuth1Info(accessToken.token,accessToken.secret)).await + actualOAuth1Info must beEqualTo(OAuth1Info(accessToken.token, accessToken.secret)).await } "fail to retrieve the OAuth1Info given an invalid request token and a verifier" in { implicit val ec = helpers.sequentialExecutionContext - val client=aDefaultClient() + val client = aDefaultClient() val verifier: String = "verifier" - val requestToken = RequestToken("invalidRequestToken","requestSecret") - val expectedException= new OAuthException("invalid endpoint") {} + val requestToken = RequestToken("invalidRequestToken", "requestSecret") + val expectedException = new OAuthException("invalid endpoint") {} - client.client.retrieveAccessToken(requestToken,verifier) returns Left(expectedException) + client.client.retrieveAccessToken(requestToken, verifier) returns Left(expectedException) - val actualOAuth1Info= client.retrieveOAuth1Info(requestToken,verifier) + val actualOAuth1Info = client.retrieveOAuth1Info(requestToken, verifier) actualOAuth1Info must throwAn(expectedException).await } "retrieve the json profile given the profile api url and the OAuth1Info" in { implicit val ec = helpers.sequentialExecutionContext val httpService: MockHttpService = new MockHttpService() - val client=aDefaultClient(httpService) + val client = aDefaultClient(httpService) val profileApiUrl: String = "profileApiUrl" - val oauth1info = OAuth1Info("accessToken","accessSecret") - val expectedJsonProfile = Json.obj("id"->"success") + val oauth1info = OAuth1Info("accessToken", "accessSecret") + val expectedJsonProfile = Json.obj("id" -> "success") httpService.request.sign(any[OAuthCalculator]) returns httpService.request //make sure the request is signed httpService.response.json returns expectedJsonProfile - val actualJsonProfile= client.retrieveProfile(profileApiUrl, oauth1info) + val actualJsonProfile = client.retrieveProfile(profileApiUrl, oauth1info) actualJsonProfile must beEqualTo(expectedJsonProfile).await } } - private def aDefaultClient(httpService:HttpService = new MockHttpService())={ - new OAuth1Client.Default(fakeServiceInfo, httpService){ + private def aDefaultClient(httpService: HttpService = new MockHttpService()) = { + new OAuth1Client.Default(fakeServiceInfo, httpService) { override val client = mock[OAuth] } } diff --git a/module-code/test/securesocial/core/OAuth2ClientSpec.scala b/module-code/test/securesocial/core/OAuth2ClientSpec.scala index a5ad8dc04..a2b1c9907 100644 --- a/module-code/test/securesocial/core/OAuth2ClientSpec.scala +++ b/module-code/test/securesocial/core/OAuth2ClientSpec.scala @@ -5,8 +5,8 @@ import org.specs2.mutable.Specification import securesocial.core.services.HttpService import helpers.MockHttpService import scala.concurrent.Future -import play.api.libs.oauth.{ConsumerKey, ServiceInfo} -import play.api.libs.json.{JsValue, JsObject, Json} +import play.api.libs.oauth.{ ConsumerKey, ServiceInfo } +import play.api.libs.json.{ JsValue, JsObject, Json } import play.api.libs.ws.Response class OAuth2ClientSpec extends Specification with Mockito { @@ -16,16 +16,15 @@ class OAuth2ClientSpec extends Specification with Mockito { implicit val ec = helpers.sequentialExecutionContext val httpService: MockHttpService = new MockHttpService() val client = aDefaultClient(httpService) - val (code,callbackUrl)=("code", "callbackUrl") + val (code, callbackUrl) = ("code", "callbackUrl") val expectedJson: JsObject = Json.obj("expected" -> "object") val expectedToken = OAuth2Info("accessToken") httpService.request.post(any[Params])(any[ParamsWriter], any[ContentTypeOfParams]) returns Future.successful(httpService.response) httpService.response.json returns expectedJson - val builder:Response => OAuth2Info= (response:Response) => if(response.json == expectedJson) expectedToken else throw new RuntimeException(s"Expected ${response.json} to be $expectedJson") - val token: Future[OAuth2Info] = client.exchangeCodeForToken(code, callbackUrl,builder) - + val builder: Response => OAuth2Info = (response: Response) => if (response.json == expectedJson) expectedToken else throw new RuntimeException(s"Expected ${response.json} to be $expectedJson") + val token: Future[OAuth2Info] = client.exchangeCodeForToken(code, callbackUrl, builder) token must beEqualTo(expectedToken).await } @@ -33,27 +32,20 @@ class OAuth2ClientSpec extends Specification with Mockito { implicit val ec = helpers.sequentialExecutionContext val httpService: MockHttpService = new MockHttpService() val client = aDefaultClient(httpService) - val profileUrl="profileUrl" + val profileUrl = "profileUrl" val expectedJson: JsObject = Json.obj("expected" -> "object") httpService.response.json returns expectedJson val actualProfile = client.retrieveProfile(profileUrl) - actualProfile must beEqualTo(expectedJson).await } } - private def aDefaultClient(httpService:HttpService = new MockHttpService())={ - new OAuth2Client.Default(httpService,fakeOAuth2Settings){ + private def aDefaultClient(httpService: HttpService = new MockHttpService()) = { + new OAuth2Client.Default(httpService, fakeOAuth2Settings) { } } - val fakeOAuth2Settings= new OAuth2Settings( - "authorizationUrl" - ,"accessTokenUrl" - , "clientId" - , "clientSecret" - , Some("scope") - , Map.empty - , Map.empty) + val fakeOAuth2Settings = new OAuth2Settings( + "authorizationUrl", "accessTokenUrl", "clientId", "clientSecret", Some("scope"), Map.empty, Map.empty) } diff --git a/samples/scala/demo/test/ApplicationScenario.scala b/samples/scala/demo/test/ApplicationScenario.scala index 479ccbfeb..77c5036da 100644 --- a/samples/scala/demo/test/ApplicationScenario.scala +++ b/samples/scala/demo/test/ApplicationScenario.scala @@ -1,12 +1,12 @@ -import play.api.test.{FakeRequest, WithApplication, FakeApplication, PlaySpecification} +import play.api.test.{ FakeRequest, WithApplication, FakeApplication, PlaySpecification } -class ApplicationScenario extends PlaySpecification { +class ApplicationScenario extends PlaySpecification { def app = FakeApplication(additionalPlugins = Seq("securesocial.testkit.AlwaysValidIdentityProvider")) "A logged in user can view the index" in new WithApplication(app) { //Given val creds1 = cookies(route(FakeRequest(POST, "/authenticate/naive").withTextBody("user")).get) //When - val Some(response)=route(FakeRequest(GET, "/").withCookies(creds1.get("id").get)) + val Some(response) = route(FakeRequest(GET, "/").withCookies(creds1.get("id").get)) //Then status(response) must equalTo(OK) diff --git a/samples/scala/demo/test/ApplicationSpec.scala b/samples/scala/demo/test/ApplicationSpec.scala index dcde28fef..796f7435b 100644 --- a/samples/scala/demo/test/ApplicationSpec.scala +++ b/samples/scala/demo/test/ApplicationSpec.scala @@ -1,13 +1,13 @@ import controllers.Application import org.specs2.matcher.ShouldMatchers import play.api.http.HeaderNames -import play.api.mvc.{Request, AnyContent} -import play.api.test.{PlaySpecification, FakeApplication, FakeRequest} +import play.api.mvc.{ Request, AnyContent } +import play.api.test.{ PlaySpecification, FakeApplication, FakeRequest } import securesocial.testkit.WithLoggedUser class ApplicationSpec extends PlaySpecification with ShouldMatchers { import WithLoggedUser._ - def minimalApp = FakeApplication(withoutPlugins=excludedPlugins,additionalPlugins = includedPlugins) + def minimalApp = FakeApplication(withoutPlugins = excludedPlugins, additionalPlugins = includedPlugins) "Access secured index " in new WithLoggedUser(minimalApp) { val req: Request[AnyContent] = FakeRequest(). @@ -16,7 +16,7 @@ class ApplicationSpec extends PlaySpecification with ShouldMatchers { val result = Application.index.apply(req) - val actual: Int= status(result) + val actual: Int = status(result) actual must be equalTo OK } } From 6c3c80827c5741553c7dc58c90a5b39648890584 Mon Sep 17 00:00:00 2001 From: Leonid Vygovskiy Date: Tue, 30 Sep 2014 00:25:03 +0400 Subject: [PATCH 02/10] UserService works with trait GenericProfile instead of BasicProfile Reasons: 1. Scala doesn't allow to extends case class from case class. 2. Coding into interfaces is good OOP practices --- .../controllers/PasswordChange.scala | 4 +-- .../controllers/PasswordReset.scala | 2 +- .../controllers/ViewsPlugin.scala | 18 +++++----- .../securesocial/core/IdentityProvider.scala | 2 +- .../app/securesocial/core/UserProfile.scala | 31 ++++++++++------ .../core/java/BaseUserService.java | 36 +++++++++---------- .../providers/UsernamePasswordProvider.scala | 2 +- .../core/providers/utils/Mailer.scala | 18 +++++----- .../core/services/UserService.scala | 12 +++---- .../mails/alreadyRegisteredEmail.scala.html | 2 +- .../mails/passwordChangedNotice.scala.html | 2 +- .../views/mails/passwordResetEmail.scala.html | 2 +- .../views/mails/welcomeEmail.scala.html | 2 +- .../scenarios/helpers/TestUserService.scala | 18 +++++----- samples/java/demo/app/service/DemoUser.java | 7 ++-- .../demo/app/service/InMemoryUserService.java | 27 +++++++------- .../java/demo/app/views/linkResult.scala.html | 2 +- .../app/service/InMemoryUserService.scala | 18 +++++----- samples/scala/demo/app/views/index.scala.html | 2 +- 19 files changed, 109 insertions(+), 98 deletions(-) diff --git a/module-code/app/securesocial/controllers/PasswordChange.scala b/module-code/app/securesocial/controllers/PasswordChange.scala index 6b61dc7fc..3b6fba6d1 100644 --- a/module-code/app/securesocial/controllers/PasswordChange.scala +++ b/module-code/app/securesocial/controllers/PasswordChange.scala @@ -27,11 +27,11 @@ import scala.Some import scala.concurrent.{ Await, ExecutionContext, Future } /** - * A default PasswordChange controller that uses the BasicProfile as the user type + * A default PasswordChange controller that uses the GenericProfile as the user type * * @param env An environment */ -class PasswordChange(override implicit val env: RuntimeEnvironment[BasicProfile]) extends BasePasswordChange[BasicProfile] +class PasswordChange(override implicit val env: RuntimeEnvironment[GenericProfile]) extends BasePasswordChange[GenericProfile] /** * A trait that defines the password change functionality diff --git a/module-code/app/securesocial/controllers/PasswordReset.scala b/module-code/app/securesocial/controllers/PasswordReset.scala index b432b91ab..327f31a85 100644 --- a/module-code/app/securesocial/controllers/PasswordReset.scala +++ b/module-code/app/securesocial/controllers/PasswordReset.scala @@ -114,7 +114,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(profile.withPasswordInfo(Some(hashed)), SaveMode.PasswordChange); deleted <- env.userService.deleteToken(token) ) yield { env.mailer.sendPasswordChangedNotice(profile) diff --git a/module-code/app/securesocial/controllers/ViewsPlugin.scala b/module-code/app/securesocial/controllers/ViewsPlugin.scala index 29ceba36b..b459883dd 100644 --- a/module-code/app/securesocial/controllers/ViewsPlugin.scala +++ b/module-code/app/securesocial/controllers/ViewsPlugin.scala @@ -18,7 +18,7 @@ package securesocial.controllers import play.api.mvc.{ Controller, RequestHeader } import play.api.templates.{ Html, Txt } -import securesocial.core.{ BasicProfile, RuntimeEnvironment } +import securesocial.core.{ GenericProfile, RuntimeEnvironment } import play.api.data.Form import play.api.i18n.Lang @@ -88,7 +88,7 @@ trait MailTemplates extends Controller { * @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 @@ -97,7 +97,7 @@ trait MailTemplates extends Controller { * @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 @@ -116,7 +116,7 @@ trait MailTemplates extends Controller { * @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 @@ -125,7 +125,7 @@ trait MailTemplates extends Controller { * @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]) } @@ -177,11 +177,11 @@ object MailTemplates { (None, Some(securesocial.views.html.mails.signUpEmail(token)(request, lang))) } - 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)(request, lang, env))) } - 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)(request, lang, env))) } @@ -189,11 +189,11 @@ object MailTemplates { (None, Some(securesocial.views.html.mails.unknownEmailNotice()(request, lang))) } - 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)(request, lang, env))) } - 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)(request, lang, env))) } } diff --git a/module-code/app/securesocial/core/IdentityProvider.scala b/module-code/app/securesocial/core/IdentityProvider.scala index 10bd70401..242287ecc 100644 --- a/module-code/app/securesocial/core/IdentityProvider.scala +++ b/module-code/app/securesocial/core/IdentityProvider.scala @@ -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. diff --git a/module-code/app/securesocial/core/UserProfile.scala b/module-code/app/securesocial/core/UserProfile.scala index 8dec3d78b..6996582a0 100644 --- a/module-code/app/securesocial/core/UserProfile.scala +++ b/module-code/app/securesocial/core/UserProfile.scala @@ -37,23 +37,32 @@ trait GenericProfile extends UserProfile { def oAuth1Info: Option[OAuth1Info] def oAuth2Info: Option[OAuth2Info] def passwordInfo: Option[PasswordInfo] + + def withPasswordInfo(passwordInfo: Option[PasswordInfo]): GenericProfile + + def withAvatarUrl(avatarUrl: Option[String]): GenericProfile } /** * An implementation of the GenericProfile */ case class BasicProfile( - providerId: String, - userId: String, - firstName: Option[String], - lastName: Option[String], - fullName: Option[String], - email: Option[String], - avatarUrl: Option[String], - authMethod: AuthenticationMethod, - oAuth1Info: Option[OAuth1Info] = None, - oAuth2Info: Option[OAuth2Info] = None, - passwordInfo: Option[PasswordInfo] = None) extends GenericProfile + providerId: String, + userId: String, + firstName: Option[String], + lastName: Option[String], + fullName: Option[String], + email: Option[String], + avatarUrl: Option[String], + authMethod: AuthenticationMethod, + oAuth1Info: Option[OAuth1Info] = None, + oAuth2Info: Option[OAuth2Info] = None, + passwordInfo: Option[PasswordInfo] = None) extends GenericProfile { + + override def withPasswordInfo(passwordInfo: Option[PasswordInfo]) = copy(passwordInfo = passwordInfo) + + override def withAvatarUrl(avatarUrl: Option[String]) = copy(avatarUrl = avatarUrl) +} /** * The OAuth 1 details diff --git a/module-code/app/securesocial/core/java/BaseUserService.java b/module-code/app/securesocial/core/java/BaseUserService.java index 9a3a690fb..512f92d6e 100644 --- a/module-code/app/securesocial/core/java/BaseUserService.java +++ b/module-code/app/securesocial/core/java/BaseUserService.java @@ -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; @@ -45,10 +45,10 @@ protected BaseUserService() { * @return an optional user */ @Override - public Future> find(String providerId, String userId) { - return doFind(providerId, userId).map(new F.Function>() { + public Future> find(String providerId, String userId) { + return doFind(providerId, userId).map(new F.Function>() { @Override - public Option apply(BasicProfile user) throws Throwable { + public Option apply(GenericProfile user) throws Throwable { return Scala.Option(user); } }).wrapped(); @@ -65,9 +65,9 @@ public Option apply(BasicProfile user) throws Throwable { * @return */ @Override - public Future> findByEmailAndProvider(String email, String providerId) { - return doFindByEmailAndProvider(email, providerId).map(new F.Function>() { - public Option apply(BasicProfile user) throws Throwable { + public Future> findByEmailAndProvider(String email, String providerId) { + return doFindByEmailAndProvider(email, providerId).map(new F.Function>() { + public Option apply(GenericProfile user) throws Throwable { return Scala.Option(user); } }).wrapped(); @@ -80,7 +80,7 @@ public Option apply(BasicProfile user) throws Throwable { * @param user */ @Override - public Future save(BasicProfile user, SaveMode mode) { + public Future save(GenericProfile user, SaveMode mode) { return doSave(user, mode).wrapped(); } @@ -91,7 +91,7 @@ public Future save(BasicProfile user, SaveMode mode) { * @param to The Identity that needs to be linked to the current user */ @Override - public Future link(U current, BasicProfile to) { + public Future link(U current, GenericProfile to) { return doLink(current, to).wrapped(); } @@ -106,11 +106,11 @@ public Option apply(PasswordInfo passwordInfo) throws Throwable { } @Override - public Future> updatePasswordInfo(U user, PasswordInfo info) { - return doUpdatePasswordInfo(user, info).map(new F.Function>() { + public Future> updatePasswordInfo(U user, PasswordInfo info) { + return doUpdatePasswordInfo(user, info).map(new F.Function>() { @Override - public Option apply(BasicProfile basicProfile) throws Throwable { - return Scala.Option(basicProfile); + public Option apply(GenericProfile GenericProfile) throws Throwable { + return Scala.Option(GenericProfile); } }).wrapped(); } @@ -192,7 +192,7 @@ public void deleteExpiredTokens() { * * @param user */ - public abstract F.Promise doSave(BasicProfile user, SaveMode mode); + public abstract F.Promise doSave(GenericProfile user, SaveMode mode); /** * Saves a token @@ -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 doLink(U current, BasicProfile to); + public abstract F.Promise 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 doFind(String providerId, String userId); + public abstract F.Promise doFind(String providerId, String userId); public abstract F.Promise doPasswordInfoFor(U user); - public abstract F.Promise doUpdatePasswordInfo(U user, PasswordInfo info); + public abstract F.Promise doUpdatePasswordInfo(U user, PasswordInfo info); /** * Finds a token @@ -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 doFindByEmailAndProvider(String email, String providerId); + public abstract F.Promise doFindByEmailAndProvider(String email, String providerId); /** * Deletes a token diff --git a/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala b/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala index 44f39f0c5..833a965f2 100644 --- a/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala +++ b/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala @@ -79,7 +79,7 @@ class UsernamePasswordProvider[U](userService: UserService[U], email <- u.email ) yield { service.urlFor(email).map { - case avatar if avatar != u.avatarUrl => u.copy(avatarUrl = avatar) + case avatar if avatar != u.avatarUrl => u.withAvatarUrl(avatar) case _ => u } map { Authenticated diff --git a/module-code/app/securesocial/core/providers/utils/Mailer.scala b/module-code/app/securesocial/core/providers/utils/Mailer.scala index 02574c3cd..2eea2da43 100644 --- a/module-code/app/securesocial/core/providers/utils/Mailer.scala +++ b/module-code/app/securesocial/core/providers/utils/Mailer.scala @@ -16,7 +16,7 @@ */ package securesocial.core.providers.utils -import securesocial.core.BasicProfile +import securesocial.core.GenericProfile import play.api.Play import securesocial.controllers.MailTemplates import Play.current @@ -29,12 +29,12 @@ import play.api.templates.{ Html, Txt } * 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])) } @@ -55,7 +55,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) @@ -66,13 +66,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) } @@ -82,7 +82,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) } diff --git a/module-code/app/securesocial/core/services/UserService.scala b/module-code/app/securesocial/core/services/UserService.scala index 2154ecb3d..25257a83d 100644 --- a/module-code/app/securesocial/core/services/UserService.scala +++ b/module-code/app/securesocial/core/services/UserService.scala @@ -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] { @@ -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 @@ -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. @@ -47,7 +47,7 @@ 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 @@ -55,7 +55,7 @@ trait UserService[U] { * @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 @@ -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 diff --git a/module-code/app/securesocial/views/mails/alreadyRegisteredEmail.scala.html b/module-code/app/securesocial/views/mails/alreadyRegisteredEmail.scala.html index 8d8a1625b..7407922d5 100644 --- a/module-code/app/securesocial/views/mails/alreadyRegisteredEmail.scala.html +++ b/module-code/app/securesocial/views/mails/alreadyRegisteredEmail.scala.html @@ -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[_]) diff --git a/module-code/app/securesocial/views/mails/passwordChangedNotice.scala.html b/module-code/app/securesocial/views/mails/passwordChangedNotice.scala.html index c02f9f9b5..040f4bce5 100644 --- a/module-code/app/securesocial/views/mails/passwordChangedNotice.scala.html +++ b/module-code/app/securesocial/views/mails/passwordChangedNotice.scala.html @@ -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[_]) diff --git a/module-code/app/securesocial/views/mails/passwordResetEmail.scala.html b/module-code/app/securesocial/views/mails/passwordResetEmail.scala.html index 72360254e..8b0738195 100644 --- a/module-code/app/securesocial/views/mails/passwordResetEmail.scala.html +++ b/module-code/app/securesocial/views/mails/passwordResetEmail.scala.html @@ -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 diff --git a/module-code/app/securesocial/views/mails/welcomeEmail.scala.html b/module-code/app/securesocial/views/mails/welcomeEmail.scala.html index 771af954a..5f202e0e1 100644 --- a/module-code/app/securesocial/views/mails/welcomeEmail.scala.html +++ b/module-code/app/securesocial/views/mails/welcomeEmail.scala.html @@ -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[_])

Welcome @user.firstName,

diff --git a/module-code/test/scenarios/helpers/TestUserService.scala b/module-code/test/scenarios/helpers/TestUserService.scala index 5f525fe74..82db22c3f 100644 --- a/module-code/test/scenarios/helpers/TestUserService.scala +++ b/module-code/test/scenarios/helpers/TestUserService.scala @@ -33,10 +33,10 @@ class TestUserService extends UserService[DemoUser] { // var users = Map[(String, String), DemoUser]() - //private var identities = Map[String, BasicProfile]() + //private var identities = Map[String, GenericProfile]() private var tokens = Map[String, MailToken]() - def find(providerId: String, userId: String): Future[Option[BasicProfile]] = { + def find(providerId: String, userId: String): Future[Option[GenericProfile]] = { if (logger.isDebugEnabled) { logger.debug("users = %s".format(users)) } @@ -49,7 +49,7 @@ class TestUserService extends UserService[DemoUser] { Future.successful(result.headOption) } - def findByEmailAndProvider(email: String, providerId: String): Future[Option[BasicProfile]] = { + def findByEmailAndProvider(email: String, providerId: String): Future[Option[GenericProfile]] = { if (logger.isDebugEnabled) { logger.debug("users = %s".format(users)) } @@ -63,7 +63,7 @@ class TestUserService extends UserService[DemoUser] { Future.successful(result.headOption) } - def save(user: BasicProfile, mode: SaveMode): Future[DemoUser] = { + def save(user: GenericProfile, mode: SaveMode): Future[DemoUser] = { mode match { case SaveMode.SignUp => val newUser = DemoUser(user, List(user)) @@ -71,7 +71,7 @@ class TestUserService extends UserService[DemoUser] { case SaveMode.LoggedIn => } - // first see if there is a user with this BasicProfile already. + // first see if there is a user with this GenericProfile already. val maybeUser = users.find { case (key, value) if value.identities.exists(su => su.providerId == user.providerId && su.userId == user.userId) => true case _ => false @@ -91,7 +91,7 @@ class TestUserService extends UserService[DemoUser] { } } - def link(current: DemoUser, to: BasicProfile): Future[DemoUser] = { + def link(current: DemoUser, to: GenericProfile): Future[DemoUser] = { if (current.identities.exists(i => i.providerId == to.providerId && i.userId == to.userId)) { Future.successful(current) } else { @@ -132,14 +132,14 @@ class TestUserService extends UserService[DemoUser] { tokens = tokens.filter(!_._2.isExpired) } - override def updatePasswordInfo(user: DemoUser, info: PasswordInfo): Future[Option[BasicProfile]] = { + override def updatePasswordInfo(user: DemoUser, info: PasswordInfo): Future[Option[GenericProfile]] = { Future.successful { for ( found <- users.values.find(_ == user); identityWithPasswordInfo <- found.identities.find(_.providerId == UsernamePasswordProvider.UsernamePassword) ) yield { val idx = found.identities.indexOf(identityWithPasswordInfo) - val updated = identityWithPasswordInfo.copy(passwordInfo = Some(info)) + val updated = identityWithPasswordInfo.withPasswordInfo(Some(info)) val updatedIdentities = found.identities.patch(idx, Seq(updated), 1) found.copy(identities = updatedIdentities) updated @@ -160,5 +160,5 @@ class TestUserService extends UserService[DemoUser] { } // a simple User class that can have multiple identities -case class DemoUser(main: BasicProfile, identities: List[BasicProfile]) +case class DemoUser(main: GenericProfile, identities: List[GenericProfile]) diff --git a/samples/java/demo/app/service/DemoUser.java b/samples/java/demo/app/service/DemoUser.java index 99e1035b9..2fd4f3263 100644 --- a/samples/java/demo/app/service/DemoUser.java +++ b/samples/java/demo/app/service/DemoUser.java @@ -17,18 +17,19 @@ package service; import securesocial.core.BasicProfile; +import securesocial.core.GenericProfile; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class DemoUser implements Serializable { - public DemoUser(BasicProfile user) { + public DemoUser(GenericProfile user) { this.main = user; identities = new ArrayList<>(); identities.add(user); } - public BasicProfile main; - public List identities; + public GenericProfile main; + public List identities; } diff --git a/samples/java/demo/app/service/InMemoryUserService.java b/samples/java/demo/app/service/InMemoryUserService.java index af399f3c0..3e6c064c6 100644 --- a/samples/java/demo/app/service/InMemoryUserService.java +++ b/samples/java/demo/app/service/InMemoryUserService.java @@ -18,7 +18,8 @@ import play.Logger; import play.libs.F; -import securesocial.core.BasicProfile; +import scala.concurrent.Future; +import securesocial.core.GenericProfile; import securesocial.core.PasswordInfo; import securesocial.core.services.SaveMode; import securesocial.core.java.BaseUserService; @@ -42,7 +43,7 @@ public class InMemoryUserService extends BaseUserService { private HashMap tokens = new HashMap(); @Override - public F.Promise doSave(BasicProfile profile, SaveMode mode) { + public F.Promise doSave(GenericProfile profile, SaveMode mode) { DemoUser result = null; if (mode == SaveMode.SignUp()) { result = new DemoUser(profile); @@ -50,7 +51,7 @@ public F.Promise doSave(BasicProfile profile, SaveMode mode) { } else if (mode == SaveMode.LoggedIn()) { for (Iterator it = users.values().iterator() ; it.hasNext() && result == null ; ) { DemoUser user = it.next(); - for ( BasicProfile p : user.identities) { + for ( GenericProfile p : user.identities) { if ( p.userId().equals(profile.userId()) && p.providerId().equals(profile.providerId())) { user.identities.remove(p); user.identities.add(profile); @@ -62,7 +63,7 @@ public F.Promise doSave(BasicProfile profile, SaveMode mode) { } else if (mode == SaveMode.PasswordChange()) { for (Iterator it = users.values().iterator() ; it.hasNext() && result == null ; ) { DemoUser user = it.next(); - for (BasicProfile p : user.identities) { + for (GenericProfile p : user.identities) { if (p.userId().equals(profile.userId()) && p.providerId().equals(UsernamePasswordProvider.UsernamePassword())) { user.identities.remove(p); user.identities.add(profile); @@ -78,7 +79,7 @@ public F.Promise doSave(BasicProfile profile, SaveMode mode) { } @Override - public F.Promise doLink(DemoUser current, BasicProfile to) { + public F.Promise doLink(DemoUser current, GenericProfile to) { DemoUser target = null; for ( DemoUser u: users.values() ) { @@ -94,7 +95,7 @@ public F.Promise doLink(DemoUser current, BasicProfile to) { } boolean alreadyLinked = false; - for ( BasicProfile p : target.identities) { + for ( GenericProfile p : target.identities) { if ( p.userId().equals(to.userId()) && p.providerId().equals(to.providerId())) { alreadyLinked = true; break; @@ -111,14 +112,14 @@ public F.Promise doSaveToken(Token token) { } @Override - public F.Promise doFind(String providerId, String userId) { + public F.Promise doFind(String providerId, String userId) { if(logger.isDebugEnabled()){ logger.debug("Finding user " + userId); } - BasicProfile found = null; + GenericProfile found = null; for ( DemoUser u: users.values() ) { - for ( BasicProfile i : u.identities ) { + for ( GenericProfile i : u.identities ) { if ( i.providerId().equals(providerId) && i.userId().equals(userId) ) { found = i; break; @@ -135,7 +136,7 @@ public F.Promise doPasswordInfoFor(DemoUser user) { } @Override - public F.Promise doUpdatePasswordInfo(DemoUser user, PasswordInfo info) { + public F.Promise doUpdatePasswordInfo(DemoUser user, PasswordInfo info) { throw new RuntimeException("doUpdatePasswordInfo is not implemented yet in sample app"); } @@ -146,11 +147,11 @@ public F.Promise doFindToken(String tokenId) { @Override - public F.Promise doFindByEmailAndProvider(String email, String providerId) { - BasicProfile found = null; + public F.Promise doFindByEmailAndProvider(String email, String providerId) { + GenericProfile found = null; for ( DemoUser u: users.values() ) { - for ( BasicProfile i : u.identities ) { + for ( GenericProfile i : u.identities ) { if ( i.providerId().equals(providerId) && i.email().isDefined() && i.email().get().equals(email) ) { found = i; break; diff --git a/samples/java/demo/app/views/linkResult.scala.html b/samples/java/demo/app/views/linkResult.scala.html index fc91b9614..150fdb3cb 100644 --- a/samples/java/demo/app/views/linkResult.scala.html +++ b/samples/java/demo/app/views/linkResult.scala.html @@ -1,4 +1,4 @@ -@(current: service.DemoUser, linkedIdentities: java.util.List[securesocial.core.BasicProfile]) +@(current: service.DemoUser, linkedIdentities: java.util.List[securesocial.core.GenericProfile]) @main("SecureSocial - Account Link Result") {