在以下代码中,signInUser
应返回Future[Result]
。我的问题是该函数使用Future
中的Future
并避免返回Future[Future[..]]
,我必须使用map
和flatMap
的组合。这使得代码不可读并且难以调试。目前,此功能未编译。我怎么能改进这段代码?我尝试使用for
,但我无法使用for
编写逻辑。
def signInUser = silhouette.UserAwareAction.async{ implicit request => {
println(s"signupUser action called with request ${utilities.printPlayHttpRequest(request)}")
val body: AnyContent = request.body
val jsonBody: Option[JsValue] = body.asJson
jsonBody match {
case Some(json) => {
val readableString: String = Json.prettyPrint(json)
println(s"received Json ${readableString}")
val userSignin: Option[UserSignin] = json.asOpt[UserSignin] //check if json conforms with UserProfile structure
userSignin match {
case Some(signinInfo) => { //format of JSON is correct
//Get signin info from JSON (email and password)
val credentials: Credentials = Credentials(signinInfo.signinInfo.email, signinInfo.signinInfo.password) //TODOM need to check that password is not empty
// get the signin validated using the credentialsProvider. credentialsProvider has reference of PasswordRepository. It will use
//PasswordRepository's to validate the credentials
//not sure which function of passwordRepository will beused to do so
//TODOM - is this the correct place to declare these. Should these be in say UserRepository or at the beginning of the controller?
//TODOM - test case for correct, incorrect and empty password
val authInfoRepository = new DelegableAuthInfoRepository(userRepo.passwordRepo)
val passwordHasherRegistory = new PasswordHasherRegistry(userRepo.passwordHasher)
val credentialsProvider = new CredentialsProvider(authInfoRepository, passwordHasherRegistory)
//authenticate method will call PasswordRepository's find method to look for the user
//flatMap returns the result of its {} as Future
credentialsProvider.authenticate(credentials).flatMap { loginInfo => { //authenticate could find the loginInfo for the matching ID and password and has returned user's login information
//get User profile for this login Info
val userOptionFuture: Future[Option[User]] = silhouette.env.identityService.retrieve(loginInfo) //this is call to instance of fUserService class created in AppLoader??
userOptionFuture.map { userOption:Option[User] =>
userOption match {
case Some(user) if !user.profile.internalProfileDetails.get.confirmed => {
println("found user but registration isn't complete",user)
Ok(Json.toJson(JsonResultError("registration not complete")))//map will return Future{Ok}, flatMap will flatten it to Ok and then return its own Future{Ok}
}
case Some(user) => { //this should also return Ok. So any map inside it should be flattened
println("found user",user)
/*
In AppLoader, while creating the Silhouette Environment, an authenticator service was also created.
The authenticator service is responsible for creating the CookieAuthenticator. The work flow is
1) create CookieAuthenticator
2) Initialise it
3) embed the Cookie in Result (because we are using Cookie Authenticator)
*/
//create an authenticator
val cookieAuthenticatorFuture:Future[CookieAuthenticator] = silhouette.env.authenticatorService.create(loginInfo)
cookieAuthenticatorFuture.flatMap(cookieAuthenticator => { //if authenticator created successfully then init it.
val cookieFuture:Future[Cookie] = silhouette.env.authenticatorService.init(cookieAuthenticator)
cookieFuture.map(cookie => {
//embed the cookie in Result. embed results AuthenticatorResult which extends Play's Result.
silhouette.env.authenticatorService.embed(cookie,Ok(Json.toJson(JsonResultSuccess("found user"))))
})
.recover { case x => {
println("Future failed in signInUser. In recover. Returning Internal Server Error"+x)
InternalServerError(Json.toJson(JsonResultError("Internal Server Error"))) }
}
})
.recover { case x => {
println("Future failed in signInUser. In recover. Returning Internal Server Error"+x)
InternalServerError(Json.toJson(JsonResultError("Internal Server Error"))) }
}
//Ok(Json.toJson(JsonResultSuccess("found user")))
}
//TODOM - think of a design such that an error code could point to the location of the code which send the error!
case None => Ok(Json.toJson(JsonResultError("Invalid user though loginInfo was found!")))
}
}
.recover { case x => {
println("Future failed in signInUser. In recover. Returning Internal Server Error"+x)
InternalServerError(Json.toJson(JsonResultError("Internal Server Error"))) }
}
}
}
.recover { case x => {
println("Future failed in signInUser. In recover. Returning Internal Server Error"+x)
InternalServerError(Json.toJson(JsonResultError("Internal Server Error"))) }
}
}
case None => { //No signin info found
Future {
Ok(Json.toJson(JsonResultError("Invalid user. No Login info found")))
}
}
}
}
//got json in message body.
case None => { //NO JSON Body
Future { Ok(Json.toJson(JsonResultError("Invalid Body Type. Need Json"))) }/*TODOM - Standardise error messages. Use as constants*/
}
}
}
}
答案 0 :(得分:3)
你可以做的一些事情:
让框架验证正文:
silhouette.UserAwareAction.async (parse.json[User]) {implicit r =>
... // r.body will now be of type `User`
框架将向无效用户json发送400错误请求。
让框架处理错误:删除recover
,框架将发送500内部服务器错误并记录异常。
用户理解,它更容易阅读,应该替换大多数map / flatten / flatMap的调用。
将存储库移动到控制器构造函数上的注入参数。