Skip to content

Instantly share code, notes, and snippets.

@dungvn3000
Created May 13, 2014 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dungvn3000/d9c68125ee54f0dfdabc to your computer and use it in GitHub Desktop.
Save dungvn3000/d9c68125ee54f0dfdabc to your computer and use it in GitHub Desktop.
package controllers
import play.api.mvc._
import play.api.Play
import play.api.Play.current
import play.api.libs.ws.WS
import scala.util.matching.Regex
import scala.concurrent.{Promise, Future, ExecutionContext}
import ExecutionContext.Implicits.global
import org.apache.commons.lang3.{RandomStringUtils, StringUtils}
import jp.t2v.lab.play2.auth.LoginLogout
import jp.t2v.lab.play2.stackc.{StackableController, RequestWithAttributes}
import controllers.element.{TransactionElement, AuthConfigImpl}
import com.restfb.DefaultFacebookClient
import models.{Users, User}
import scala.util.{Failure, Success}
import utils.HttpUtil
/**
* The Class FacebookCtr.
*
* @author Nguyen Duc Dung
* @since 1/12/14 6:23 PM
*
*/
class FacebookCtr extends Controller with StackableController with LoginLogout with AuthConfigImpl with TransactionElement {
lazy val app_id = Play.configuration.getString("facebook.app.id").getOrElse(throw new Exception("Please add facebook.app.id to application.conf"))
lazy val app_secret = Play.configuration.getString("facebook.app.secret").getOrElse(throw new Exception("Please add facebook.app.secret to application.conf"))
lazy val redirect_url = Play.configuration.getString("application.facebook.redirect.url").getOrElse(throw new Exception("Please add application.facebook.redirect.url to application.conf"))
lazy val regex = new Regex("access_token=(.*)&expires=(.*)")
def profilePictureUrl(facebookId: String) = s"http://graph.facebook.com/$facebookId/picture?type=normal"
def login = Action(implicit request => {
val url = s"https://www.facebook.com/dialog/oauth?client_id=$app_id&redirect_uri=$redirect_url&scope=email,public_profile,user_friends"
Redirect(url)
})
def auth = AsyncStack(implicit request => {
request.getQueryString("code").map(code => {
val accessTokenUrl = s"https://graph.facebook.com/oauth/access_token?client_id=$app_id&client_secret=$app_secret&code=$code&redirect_uri=$redirect_url"
WS.url(accessTokenUrl).get().flatMap(response => response.body match {
case regex(accessToken, expires) => processToken(accessToken)
case _ => Future.successful(BadRequest)
})
}).getOrElse(Future.successful(BadRequest))
})
def authorize(accessToken: String) = AsyncStack(implicit request => {
processToken(accessToken)
})
private def processToken(accessToken: String)(implicit request: RequestWithAttributes[_]): Future[SimpleResult] = {
val promise = Promise[SimpleResult]()
def getUserProfile = Future {
val facebookClient = new DefaultFacebookClient(accessToken)
val fbUser = facebookClient.fetchObject("me", classOf[com.restfb.types.User])
fbUser
}
def getUserAvatar(fbId: String) = HttpUtil.safeDownload(profilePictureUrl(fbId))
getUserProfile.onComplete {
case Success(fbUser) =>
//Make sure email is not null
if (fbUser != null && StringUtils.isNotBlank(fbUser.getEmail)) {
Users.findByEmail(fbUser.getEmail)
.map(user => promise.completeWith(gotoLoginSucceeded(user.email)))
.getOrElse {
val newPassword = RandomStringUtils.randomAlphanumeric(6)
val fullName = if (StringUtils.isNotBlank(fbUser.getName)) Some(fbUser.getName) else None
getUserAvatar(fbUser.getId).onComplete {
case Success(avatar) =>
val newUser = User(
email = fbUser.getEmail,
fullName = fullName,
avatar = avatar.getOrElse(Array.empty),
password = newPassword
)
Users.save(newUser)
promise.completeWith(gotoLoginSucceeded(newUser.email))
case Failure(ex) => promise.failure(ex)
}
}
} else {
promise.success(Redirect("/user/register"))
}
case Failure(ex) => promise.failure(ex)
}
promise.future
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment