Created
March 12, 2013 07:55
-
-
Save leon/5141012 to your computer and use it in GitHub Desktop.
Secure Social UserService Slick implementation (Not Working)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package service | |
import play.api._ | |
import securesocial.core._ | |
import securesocial.core.providers.Token | |
import securesocial.core.UserId | |
import models._ | |
class SlickUserService(application: Application) extends UserServicePlugin(application) { | |
def find(id: UserId): Option[Identity] = Users.findByUserId(id) | |
def findByEmailAndProvider(email: String, providerId: String): Option[Identity] = Users.findByEmailAndProvider(email, providerId) | |
def save(identity: Identity): Identity = Users.save(User.fromIdentity(identity)) | |
def save(token: Token) { Tokens.save(token) } | |
def findToken(token: String): Option[Token] = Tokens.findByUUID(token) | |
def deleteToken(uuid: String) { Tokens.delete(uuid) } | |
def deleteTokens() { Tokens.deleteAll() } | |
def deleteExpiredTokens() { Tokens.deleteExpiredTokens() } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package models | |
import play.api.db.slick.DB | |
import play.api.db.slick.Config.driver.simple._ | |
import securesocial.core._ | |
import securesocial.core.providers.Token | |
import _root_.java.sql.Date | |
import org.joda.time.DateTime | |
import play.api.Play.current | |
/* | |
Slick Table for securesocial.core.providers.Token | |
case class Token( | |
uuid: String, | |
email: String, | |
creationTime: org.joda.time.DateTime, | |
expirationTime: org.joda.time.DateTime, | |
isSignUp: Boolean | |
) | |
*/ | |
object Tokens extends Table[Token]("tokens") { | |
// Conversions for JodaTime | |
implicit def date2dateTime = MappedTypeMapper.base[DateTime, Date] ( | |
dateTime => new Date(dateTime.getMillis), | |
date => new DateTime(date) | |
) | |
def uuid = column[String]("uuid", O.PrimaryKey) | |
def email = column[String]("email") | |
def creationTime = column[DateTime]("creationTime") | |
def expirationTime = column[DateTime]("expirationTime") | |
def isSignUp = column[Boolean]("isSignUp") | |
// Projections | |
def * = { | |
uuid ~ | |
email ~ | |
creationTime ~ | |
expirationTime ~ | |
isSignUp <> (Token.apply _, Token.unapply _) | |
} | |
// Operations | |
def save(token: Token): Token = DB.withTransaction { implicit session => | |
findByUUID(token.uuid) map { t => | |
Query(Tokens).where(_.uuid is t.uuid).update(token) | |
} getOrElse { | |
this.insert(token) | |
} | |
token | |
} | |
def delete(uuid: String) = DB.withTransaction { implicit session => | |
this.where(_.uuid is uuid).mutate(_.delete) | |
} | |
def deleteAll() = DB.withTransaction { implicit session => | |
Query(Tokens).mutate(_.delete) | |
} | |
def deleteExpiredTokens() = DB.withTransaction { implicit session => | |
Query(Tokens).where(_.expirationTime <= DateTime.now).mutate(_.delete) | |
} | |
// Queries | |
def all: List[User] = DB.withSession { implicit session => | |
val q = for (user <- Users) yield user | |
q.list | |
} | |
def findByUUID(uuid: String): Option[Token] = DB.withSession { implicit session => | |
def byUUID = createFinderBy(_.uuid) | |
byUUID(uuid).firstOption | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package models | |
import play.api.libs.Codecs | |
import play.api.db.slick.DB | |
import play.api.db.slick.Config.driver.simple._ | |
import securesocial.core._ | |
import play.api.Play.current | |
case class User( | |
pid: Option[Long] = None, | |
userId: String, | |
providerId: String, | |
email: Option[String], | |
firstName: String, | |
lastName: String, | |
authMethod: AuthenticationMethod, | |
oAuth1Info: Option[OAuth1Info] = None, | |
oAuth2Info: Option[OAuth2Info] = None, | |
passwordInfo: Option[PasswordInfo] = None | |
) extends Identity { | |
def id: UserId = UserId(userId, providerId) | |
def fullName: String = s"$firstName $lastName" | |
def avatarUrl: Option[String] = email.map { e => s"http://www.gravatar.com/avatar/${Codecs.md5(e.getBytes)}.png" } | |
} | |
object User { | |
def fromIdentity(user: Identity) = { | |
User( | |
pid = None, | |
userId = user.id.id, | |
providerId = user.id.providerId, | |
email = user.email, | |
firstName = user.firstName, | |
lastName = user.lastName, | |
authMethod = user.authMethod, | |
oAuth1Info = user.oAuth1Info, | |
oAuth2Info = user.oAuth2Info, | |
passwordInfo = user.passwordInfo | |
) | |
} | |
} | |
object Users extends Table[User]("users") { | |
// Conversions for AuthenticationMethod | |
implicit def string2AuthenticationMethod = MappedTypeMapper.base[AuthenticationMethod, String] ( | |
authenticationMethod => authenticationMethod.method, | |
string => AuthenticationMethod(string) | |
) | |
def pid = column[Long]("id", O.PrimaryKey, O.AutoInc) | |
def userId = column[String]("userId") | |
def providerId = column[String]("providerId") | |
def email = column[Option[String]]("email") | |
def firstName = column[String]("firstName") | |
def lastName = column[String]("lastName") | |
def authMethod = column[AuthenticationMethod]("authMethod") | |
def oAuth1Info = { | |
def token = column[String]("token") | |
def secret = column[String]("secret") | |
token ~ secret <> (OAuth1Info.apply _, OAuth1Info.unapply _) | |
} | |
def oAuth2Info = { | |
def accessToken = column[String]("accessToken") | |
def tokenType = column[Option[String]]("tokenType") | |
def expiresIn = column[Option[Int]]("expiresIn") | |
def refreshToken = column[Option[String]]("refreshToken") | |
accessToken ~ tokenType ~ expiresIn ~ refreshToken <> (OAuth2Info.apply _, OAuth2Info.unapply _) | |
} | |
def passwordInfo = { | |
def hasher = column[String]("hasher") | |
def password = column[String]("password") | |
def salt = column[Option[String]]("salt") | |
hasher ~ password ~ salt <> (PasswordInfo.apply _, PasswordInfo.unapply _) | |
} | |
// Projections | |
def * = { | |
pid.? ~ | |
userId ~ | |
providerId ~ | |
email ~ | |
firstName ~ | |
lastName ~ | |
authMethod ~ | |
oAuth1Info.? ~ | |
oAuth2Info.? ~ | |
passwordInfo.? <> (User.apply _, User.unapply _) | |
} | |
def autoInc = * returning pid | |
// Operations | |
def save(user: User): User = DB.withTransaction { implicit session => | |
user.pid match { | |
case None | Some(0) => { | |
val pid = this.autoInc.insert(user) | |
user.copy(pid = Some(pid)) | |
} | |
case Some(pid) => { | |
Query(Users).where(_.pid is pid).update(user) | |
user | |
} | |
} | |
} | |
def delete(pid: Long) = DB.withTransaction { implicit session => | |
this.where(_.pid is pid).mutate(_.delete) | |
} | |
// Queries | |
def all: List[User] = DB.withSession { implicit session => | |
val q = for (user <- Users) yield user | |
q.list | |
} | |
def findById(pid: Long): Option[User] = DB.withSession { implicit session => | |
def byId = createFinderBy(_.pid) | |
byId(pid).firstOption | |
} | |
def findByEmail(email: String): Option[User] = DB.withSession { implicit session => | |
def byEmail = createFinderBy(_.email) | |
byEmail(email).firstOption | |
} | |
def findByUserId(userId: UserId): Option[User] = DB.withSession { implicit session => | |
val q = for { | |
user <- this if (this.userId is userId.id) && (this.providerId is userId.providerId) | |
} yield user | |
q.firstOption | |
} | |
def findByEmailAndProvider(email: String, providerId: String): Option[User] = DB.withSession { implicit session => | |
val q = for { | |
user <- this if (this.email is email) && (this.providerId is providerId) | |
} yield user | |
q.firstOption | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@damyIA Is it still available? That link 404s.