typesafe Email
parent
3d4026346a
commit
cb3a87829f
|
@ -4,8 +4,8 @@ import play.api.mvc._
|
|||
|
||||
import lila.api.Context
|
||||
import lila.app._
|
||||
import lila.common.LilaCookie
|
||||
import lila.common.PimpedJson._
|
||||
import lila.common.{ LilaCookie, Email }
|
||||
import lila.user.{ User => UserModel, UserRepo }
|
||||
import views._
|
||||
|
||||
|
@ -80,7 +80,7 @@ object Account extends LilaController {
|
|||
|
||||
private def emailForm(user: UserModel) = UserRepo email user.id map { email =>
|
||||
Env.security.forms.changeEmail(user).fill(
|
||||
lila.security.DataForm.ChangeEmail(~email, "")
|
||||
lila.security.DataForm.ChangeEmail(email.??(_.value), "")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ object Account extends LilaController {
|
|||
FormFuResult(Env.security.forms.changeEmail(me)) { err =>
|
||||
fuccess(html.account.email(me, err))
|
||||
} { data =>
|
||||
val email = Env.security.emailAddress.validate(data.email) err s"Invalid email ${data.email}"
|
||||
val email = Env.security.emailAddress.validate(Email(data.email)) err s"Invalid email ${data.email}"
|
||||
for {
|
||||
ok ← UserRepo.authenticateById(me.id, data.passwd).map(_.isDefined)
|
||||
_ ← ok ?? UserRepo.email(me.id, email)
|
||||
|
|
|
@ -118,7 +118,7 @@ object Auth extends LilaController {
|
|||
) flatMap { mustConfirmEmail =>
|
||||
lila.mon.user.register.website()
|
||||
lila.mon.user.register.mustConfirmEmail(mustConfirmEmail)()
|
||||
val email = env.emailAddress.validate(data.email) err s"Invalid email ${data.email}"
|
||||
val email = env.emailAddress.validate(data.realEmail) err s"Invalid email ${data.email}"
|
||||
UserRepo.create(data.username, data.password, email.some, ctx.blindMode, none,
|
||||
mustConfirmEmail = mustConfirmEmail)
|
||||
.flatten(s"No user could be created for ${data.username}")
|
||||
|
@ -139,7 +139,7 @@ object Auth extends LilaController {
|
|||
val mustConfirmEmail = false
|
||||
lila.mon.user.register.mobile()
|
||||
lila.mon.user.register.mustConfirmEmail(mustConfirmEmail)()
|
||||
val email = data.email flatMap env.emailAddress.validate
|
||||
val email = data.realEmail flatMap env.emailAddress.validate
|
||||
UserRepo.create(data.username, data.password, email, false, apiVersion.some,
|
||||
mustConfirmEmail = mustConfirmEmail)
|
||||
.flatten(s"No user could be created for ${data.username}") flatMap authenticateUser
|
||||
|
@ -203,7 +203,7 @@ object Auth extends LilaController {
|
|||
BadRequest(html.auth.passwordReset(err, captcha, false.some))
|
||||
},
|
||||
data => {
|
||||
val email = env.emailAddress.validate(data.email) | data.email
|
||||
val email = env.emailAddress.validate(data.realEmail) | data.realEmail
|
||||
UserRepo enabledByEmail email flatMap {
|
||||
case Some(user) =>
|
||||
Env.security.passwordReset.send(user, email) inject Redirect(routes.Auth.passwordResetSent(data.email))
|
||||
|
|
|
@ -2,7 +2,7 @@ package controllers
|
|||
|
||||
import lila.api.Context
|
||||
import lila.app._
|
||||
import lila.common.IpAddress
|
||||
import lila.common.{ IpAddress, Email }
|
||||
import lila.user.{ UserRepo, User => UserModel }
|
||||
import views._
|
||||
|
||||
|
@ -118,7 +118,7 @@ object Mod extends LilaController {
|
|||
Env.security.forms.modEmail(user).bindFromRequest.fold(
|
||||
err => BadRequest(err.toString).fuccess,
|
||||
rawEmail => {
|
||||
val email = Env.security.emailAddress.validate(rawEmail) err s"Invalid email ${rawEmail}"
|
||||
val email = Env.security.emailAddress.validate(Email(rawEmail)) err s"Invalid email ${rawEmail}"
|
||||
modApi.setEmail(me.id, user.id, email) inject redirect(user.username, mod = true)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ import play.api.mvc._
|
|||
import lila.api.Context
|
||||
import lila.app._
|
||||
import lila.plan.{ StripeCustomer, MonthlyCustomerInfo, OneTimeCustomerInfo }
|
||||
import lila.common.Email
|
||||
import lila.user.{ User => UserModel, UserRepo }
|
||||
import views._
|
||||
|
||||
|
@ -44,7 +45,7 @@ object Plan extends LilaController {
|
|||
renderIndex(email, patron = none)
|
||||
}
|
||||
|
||||
private def renderIndex(email: Option[String], patron: Option[lila.plan.Patron])(implicit ctx: Context): Fu[Result] = for {
|
||||
private def renderIndex(email: Option[Email], patron: Option[lila.plan.Patron])(implicit ctx: Context): Fu[Result] = for {
|
||||
recentIds <- Env.plan.api.recentChargeUserIds
|
||||
bestIds <- Env.plan.api.topPatronUserIds
|
||||
_ <- Env.user.lightUserApi preloadMany { recentIds ::: bestIds }
|
||||
|
@ -59,7 +60,7 @@ object Plan extends LilaController {
|
|||
private def indexPatron(me: UserModel, patron: lila.plan.Patron, customer: StripeCustomer)(implicit ctx: Context) =
|
||||
Env.plan.api.customerInfo(me, customer) flatMap {
|
||||
case Some(info: MonthlyCustomerInfo) => Ok(html.plan.indexStripe(me, patron, info)).fuccess
|
||||
case Some(info: OneTimeCustomerInfo) => renderIndex(info.customer.email, patron.some)
|
||||
case Some(info: OneTimeCustomerInfo) => renderIndex(info.customer.email map Email.apply, patron.some)
|
||||
case None => UserRepo email me.id flatMap { email =>
|
||||
renderIndex(email, patron.some)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(email: Option[String], stripePublicKey: String, patron: Option[lila.plan.Patron], recentIds: List[String], bestIds: List[String])(implicit ctx: Context)
|
||||
@(email: Option[lila.common.Email], stripePublicKey: String, patron: Option[lila.plan.Patron], recentIds: List[String], bestIds: List[String])(implicit ctx: Context)
|
||||
|
||||
@title = @{"Become a Patron of lichess.org"}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(u: User, email: Option[String], spy: lila.security.UserSpy, optionAggregateAssessment: Option[lila.evaluation.PlayerAggregateAssessment.WithGames], bans: Map[String, Int], history: List[lila.mod.Modlog], charges: List[lila.plan.Charge], reports: lila.report.Report.ByAndAbout, pref: lila.pref.Pref, notes: List[lila.user.Note])(implicit ctx: Context)
|
||||
@(u: User, email: Option[lila.common.Email], spy: lila.security.UserSpy, optionAggregateAssessment: Option[lila.evaluation.PlayerAggregateAssessment.WithGames], bans: Map[String, Int], history: List[lila.mod.Modlog], charges: List[lila.plan.Charge], reports: lila.report.Report.ByAndAbout, pref: lila.pref.Pref, notes: List[lila.user.Note])(implicit ctx: Context)
|
||||
|
||||
@import lila.evaluation.Display
|
||||
@import lila.pref.Pref
|
||||
|
|
|
@ -26,4 +26,6 @@ object Iso {
|
|||
implicit val stringIsoIdentity: Iso[String, String] = isoIdentity[String]
|
||||
|
||||
implicit val ipAddressIso = string[IpAddress](IpAddress.apply, _.value)
|
||||
|
||||
implicit val emailIso = string[Email](Email.apply, _.value)
|
||||
}
|
||||
|
|
|
@ -19,4 +19,19 @@ object IpAddress {
|
|||
|
||||
def isv4(a: IpAddress) = ipv4Regex matches a.value
|
||||
def isv6(a: IpAddress) = ipv6Regex matches a.value
|
||||
|
||||
def from(str: String): Option[IpAddress] = {
|
||||
ipv4Regex.matches(str) || ipv6Regex.matches(str)
|
||||
} option IpAddress(str)
|
||||
}
|
||||
|
||||
case class Email(value: String) extends AnyVal with StringValue
|
||||
|
||||
object Email {
|
||||
|
||||
private val regex =
|
||||
"""^[a-zA-Z0-9\.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$""".r
|
||||
|
||||
def from(str: String): Option[Email] =
|
||||
regex.matches(str) option Email(str)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import reactivemongo.bson._
|
|||
import scalaz.NonEmptyList
|
||||
|
||||
import lila.common.Iso._
|
||||
import lila.common.{ Iso, IpAddress }
|
||||
import lila.common.{ Iso, IpAddress, Email }
|
||||
|
||||
trait Handlers {
|
||||
|
||||
|
@ -65,4 +65,6 @@ trait Handlers {
|
|||
}(breakOut)
|
||||
|
||||
implicit val ipAddressHandler = isoHandler[IpAddress, String, BSONString](ipAddressIso)
|
||||
|
||||
implicit val emailHandler = isoHandler[Email, String, BSONString](emailIso)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package lila.mod
|
||||
|
||||
import lila.common.IpAddress
|
||||
import lila.common.{ IpAddress, Email }
|
||||
import lila.security.Permission
|
||||
import lila.security.{ Firewall, UserSpy, Store => SecurityStore }
|
||||
import lila.user.{ User, UserRepo, LightUserApi }
|
||||
|
@ -105,7 +105,7 @@ final class ModApi(
|
|||
lightUserApi.invalidate(user.id)
|
||||
}
|
||||
|
||||
def setEmail(mod: String, username: String, email: String): Funit = withUser(username) { user =>
|
||||
def setEmail(mod: String, username: String, email: Email): Funit = withUser(username) { user =>
|
||||
UserRepo.email(user.id, email) >>
|
||||
UserRepo.setEmailConfirmed(user.id) >>
|
||||
logApi.setEmail(mod, user.id)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lila.mod
|
||||
|
||||
import lila.common.{ Email, IpAddress }
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
final class UserSearch(
|
||||
|
@ -7,29 +8,18 @@ final class UserSearch(
|
|||
emailAddress: lila.security.EmailAddress
|
||||
) {
|
||||
|
||||
// http://stackoverflow.com/questions/106179/regular-expression-to-match-hostname-or-ip-address
|
||||
private val ipv4Pattern = """^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$""".r.pattern
|
||||
|
||||
// ipv6 in standard form
|
||||
private val ipv6Pattern = """^((0|[1-9a-f][0-9a-f]{0,3}):){7}(0|[1-9a-f][0-9a-f]{0,3})""".r.pattern
|
||||
|
||||
// from playframework
|
||||
private val emailPattern =
|
||||
"""^[a-zA-Z0-9\.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$""".r.pattern
|
||||
|
||||
def apply(query: String): Fu[List[User]] =
|
||||
if (query.isEmpty) fuccess(Nil)
|
||||
else if (emailPattern.matcher(query).matches) searchEmail(query)
|
||||
else if (ipv4Pattern.matcher(query).matches) searchIp(query)
|
||||
else if (ipv6Pattern.matcher(query).matches) searchIp(query)
|
||||
else searchUsername(query)
|
||||
else Email.from(query).map(searchEmail) orElse
|
||||
IpAddress.from(query).map(searchIp) getOrElse
|
||||
searchUsername(query)
|
||||
|
||||
private def searchIp(ip: String) =
|
||||
private def searchIp(ip: IpAddress) =
|
||||
securityApi recentUserIdsByIp ip map (_.reverse) flatMap UserRepo.usersFromSecondary
|
||||
|
||||
private def searchUsername(username: String) = UserRepo named username map (_.toList)
|
||||
|
||||
private def searchEmail(email: String) = emailAddress.validate(email) ?? { fixed =>
|
||||
private def searchEmail(email: Email) = emailAddress.validate(email) ?? { fixed =>
|
||||
UserRepo byEmail fixed map (_.toList)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import play.api.mvc.RequestHeader
|
|||
import reactivemongo.api.ReadPreference
|
||||
import reactivemongo.bson._
|
||||
|
||||
import lila.common.{ ApiVersion, IpAddress }
|
||||
import lila.common.{ ApiVersion, IpAddress, Email }
|
||||
import lila.db.BSON.BSONJodaDateTimeHandler
|
||||
import lila.db.dsl._
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
@ -38,7 +38,7 @@ final class Api(
|
|||
.verifying("Invalid username or password", _.isDefined))
|
||||
|
||||
def loadLoginForm(str: String): Fu[Form[Option[User]]] = {
|
||||
emailAddress.validate(str) match {
|
||||
emailAddress.validate(Email(str)) match {
|
||||
case Some(email) => UserRepo.checkPasswordByEmail(email)
|
||||
case None if User.couldBeUsername(str) => UserRepo.checkPasswordById(User normalize str)
|
||||
case _ => fuccess(none)
|
||||
|
@ -114,7 +114,7 @@ final class Api(
|
|||
|
||||
def recentUserIdsByFingerprint = recentUserIdsByField("fp") _
|
||||
|
||||
def recentUserIdsByIp = recentUserIdsByField("ip") _
|
||||
def recentUserIdsByIp(ip: IpAddress) = recentUserIdsByField("ip")(ip.value)
|
||||
|
||||
private def recentUserIdsByField(field: String)(value: String): Fu[List[String]] =
|
||||
coll.distinct[String, List](
|
||||
|
|
|
@ -4,7 +4,7 @@ import play.api.data._
|
|||
import play.api.data.Forms._
|
||||
import play.api.data.validation.Constraints
|
||||
|
||||
import lila.common.LameName
|
||||
import lila.common.{ LameName, Email }
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
final class DataForm(
|
||||
|
@ -103,19 +103,27 @@ object DataForm {
|
|||
`g-recaptcha-response`: Option[String]
|
||||
) {
|
||||
def recaptchaResponse = `g-recaptcha-response`
|
||||
|
||||
def realEmail = Email(email)
|
||||
}
|
||||
|
||||
case class MobileSignupData(
|
||||
username: String,
|
||||
password: String,
|
||||
email: Option[String]
|
||||
)
|
||||
username: String,
|
||||
password: String,
|
||||
email: Option[String]
|
||||
) {
|
||||
def realEmail = email flatMap Email.from
|
||||
}
|
||||
|
||||
case class PasswordReset(
|
||||
email: String,
|
||||
gameId: String,
|
||||
move: String
|
||||
)
|
||||
email: String,
|
||||
gameId: String,
|
||||
move: String
|
||||
) {
|
||||
def realEmail = Email(email)
|
||||
}
|
||||
|
||||
case class ChangeEmail(email: String, passwd: String)
|
||||
case class ChangeEmail(email: String, passwd: String) {
|
||||
def realEmail = Email(email)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package lila.security
|
||||
|
||||
import lila.user.User
|
||||
import lila.common.Email
|
||||
|
||||
import play.api.data.validation._
|
||||
|
||||
|
@ -10,10 +11,10 @@ import play.api.data.validation._
|
|||
final class EmailAddress(disposable: DisposableEmailDomain) {
|
||||
|
||||
// email was already regex-validated at this stage
|
||||
def validate(email: String): Option[String] =
|
||||
def validate(email: Email): Option[Email] =
|
||||
|
||||
// start by lower casing the entire address
|
||||
email.toLowerCase
|
||||
email.value.toLowerCase
|
||||
// separate name from domain
|
||||
.split('@') match {
|
||||
|
||||
|
@ -22,19 +23,19 @@ final class EmailAddress(disposable: DisposableEmailDomain) {
|
|||
.replace(".", "") // remove all dots
|
||||
.takeWhile('+'!=) // skip everything after the first +
|
||||
.some.filter(_.nonEmpty) // make sure something remains
|
||||
.map(radix => s"$radix@$domain") // okay
|
||||
.map(radix => Email(s"$radix@$domain")) // okay
|
||||
|
||||
// disposable addresses
|
||||
case Array(_, domain) if disposable(domain) => none
|
||||
|
||||
// other valid addresses
|
||||
case Array(name, domain) if domain contains "." => s"$name@$domain".some
|
||||
case Array(name, domain) if domain contains "." => Email(s"$name@$domain").some
|
||||
|
||||
// invalid addresses
|
||||
case _ => none
|
||||
}
|
||||
|
||||
def isValid(email: String) = validate(email).isDefined
|
||||
def isValid(email: Email) = validate(email).isDefined
|
||||
|
||||
/**
|
||||
* Returns true if an E-mail address is taken by another user.
|
||||
|
@ -43,7 +44,7 @@ final class EmailAddress(disposable: DisposableEmailDomain) {
|
|||
* If they already have it assigned, returns false.
|
||||
* @return
|
||||
*/
|
||||
private def isTakenBySomeoneElse(email: String, forUser: Option[User]): Boolean = validate(email) ?? { e =>
|
||||
private def isTakenBySomeoneElse(email: Email, forUser: Option[User]): Boolean = validate(email) ?? { e =>
|
||||
(lila.user.UserRepo.idByEmail(e) awaitSeconds 2, forUser) match {
|
||||
case (None, _) => false
|
||||
case (Some(userId), Some(user)) => userId != user.id
|
||||
|
@ -52,12 +53,12 @@ final class EmailAddress(disposable: DisposableEmailDomain) {
|
|||
}
|
||||
|
||||
val acceptableConstraint = Constraint[String]("constraint.email_acceptable") { e =>
|
||||
if (isValid(e)) Valid
|
||||
if (isValid(Email(e))) Valid
|
||||
else Invalid(ValidationError("error.email_acceptable"))
|
||||
}
|
||||
|
||||
def uniqueConstraint(forUser: Option[User]) = Constraint[String]("constraint.email_unique") { e =>
|
||||
if (isTakenBySomeoneElse(e, forUser))
|
||||
if (isTakenBySomeoneElse(Email(e), forUser))
|
||||
Invalid(ValidationError(s"Email address is already in use by another account"))
|
||||
else Valid
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@ import play.api.Play.current
|
|||
import scala.concurrent.duration._
|
||||
|
||||
import lila.common.String.base64
|
||||
import lila.common.Email
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
trait EmailConfirm {
|
||||
|
||||
def effective: Boolean
|
||||
|
||||
def send(user: User, email: String, tryNb: Int = 1): Funit
|
||||
def send(user: User, email: Email, tryNb: Int = 1): Funit
|
||||
|
||||
def confirm(token: String): Fu[Option[User]]
|
||||
}
|
||||
|
@ -22,7 +23,7 @@ object EmailConfirmSkip extends EmailConfirm {
|
|||
|
||||
def effective = false
|
||||
|
||||
def send(user: User, email: String, tryNb: Int = 1) = UserRepo setEmailConfirmed user.id
|
||||
def send(user: User, email: Email, tryNb: Int = 1) = UserRepo setEmailConfirmed user.id
|
||||
|
||||
def confirm(token: String): Fu[Option[User]] = fuccess(none)
|
||||
}
|
||||
|
@ -41,12 +42,12 @@ final class EmailConfirmMailGun(
|
|||
|
||||
val maxTries = 3
|
||||
|
||||
def send(user: User, email: String, tryNb: Int = 1): Funit = tokener make user flatMap { token =>
|
||||
def send(user: User, email: Email, tryNb: Int = 1): Funit = tokener make user flatMap { token =>
|
||||
lila.mon.email.confirmation()
|
||||
val url = s"$baseUrl/signup/confirm/$token"
|
||||
WS.url(s"$apiUrl/messages").withAuth("api", apiKey, WSAuthScheme.BASIC).post(Map(
|
||||
"from" -> Seq(sender),
|
||||
"to" -> Seq(email),
|
||||
"to" -> Seq(email.value),
|
||||
"h:Reply-To" -> Seq(replyTo),
|
||||
"o:tag" -> Seq("registration"),
|
||||
"subject" -> Seq(s"Confirm your lichess.org account, ${user.username}"),
|
||||
|
@ -107,7 +108,7 @@ This is a service email related to your use of lichess.org. If you did not regis
|
|||
|
||||
private def makeHash(msg: String) = Algo.hmac(secret).sha1(msg).hex take 14
|
||||
private def getHashedEmail(userId: User.ID) = UserRepo email userId map { p =>
|
||||
makeHash(~p) take 6
|
||||
makeHash(p.??(_.value)) take 6
|
||||
}
|
||||
private def makePayload(userId: String, passwd: String) = s"$userId$separator$passwd"
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import play.api.libs.ws.{ WS, WSAuthScheme }
|
|||
import play.api.Play.current
|
||||
|
||||
import lila.common.String.base64
|
||||
import lila.common.Email
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
final class PasswordReset(
|
||||
|
@ -16,12 +17,12 @@ final class PasswordReset(
|
|||
secret: String
|
||||
) {
|
||||
|
||||
def send(user: User, email: String): Funit = tokener make user flatMap { token =>
|
||||
def send(user: User, email: Email): Funit = tokener make user flatMap { token =>
|
||||
lila.mon.email.resetPassword()
|
||||
val url = s"$baseUrl/password/reset/confirm/$token"
|
||||
WS.url(s"$apiUrl/messages").withAuth("api", apiKey, WSAuthScheme.BASIC).post(Map(
|
||||
"from" -> Seq(sender),
|
||||
"to" -> Seq(email),
|
||||
"to" -> Seq(email.value),
|
||||
"h:Reply-To" -> Seq(replyTo),
|
||||
"o:tag" -> Seq("password"),
|
||||
"subject" -> Seq("Reset your lichess.org password"),
|
||||
|
|
|
@ -4,6 +4,7 @@ import akka.actor._
|
|||
import com.typesafe.config.Config
|
||||
|
||||
import lila.common.PimpedConfig._
|
||||
import lila.common.Email
|
||||
|
||||
final class Env(
|
||||
config: Config,
|
||||
|
@ -52,7 +53,7 @@ final class Env(
|
|||
def cli = new lila.common.Cli {
|
||||
def process = {
|
||||
case "user" :: "email" :: userId :: email :: Nil =>
|
||||
UserRepo.email(User normalize userId, email) inject "done"
|
||||
UserRepo.email(User normalize userId, Email(email)) inject "done"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ object User {
|
|||
def glicko(perf: String) = s"$perfs.$perf.gl"
|
||||
val email = "email"
|
||||
val mustConfirmEmail = "mustConfirmEmail"
|
||||
val prevEmail = "prevEmail"
|
||||
val colorIt = "colorIt"
|
||||
val plan = "plan"
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import reactivemongo.api.commands.GetLastError
|
|||
import reactivemongo.bson._
|
||||
|
||||
import lila.common.ApiVersion
|
||||
import lila.common.Email
|
||||
import lila.db.BSON.BSONJodaDateTimeHandler
|
||||
import lila.db.dsl._
|
||||
import lila.rating.{ Perf, PerfType }
|
||||
|
@ -33,12 +34,12 @@ object UserRepo {
|
|||
|
||||
def byIdsSecondary(ids: Iterable[ID]): Fu[List[User]] = coll.byIds[User](ids, ReadPreference.secondaryPreferred)
|
||||
|
||||
def byEmail(email: String): Fu[Option[User]] = coll.uno[User]($doc(F.email -> email))
|
||||
def byEmail(email: Email): Fu[Option[User]] = coll.uno[User]($doc(F.email -> email))
|
||||
|
||||
def idByEmail(email: String): Fu[Option[String]] =
|
||||
def idByEmail(email: Email): Fu[Option[String]] =
|
||||
coll.primitiveOne[String]($doc(F.email -> email), "_id")
|
||||
|
||||
def enabledByEmail(email: String): Fu[Option[User]] = byEmail(email) map (_ filter (_.enabled))
|
||||
def enabledByEmail(email: Email): Fu[Option[User]] = byEmail(email) map (_ filter (_.enabled))
|
||||
|
||||
def pair(x: Option[ID], y: Option[ID]): Fu[(Option[User], Option[User])] =
|
||||
coll.byIds[User](List(x, y).flatten) map { users =>
|
||||
|
@ -226,7 +227,7 @@ object UserRepo {
|
|||
def authenticateById(id: ID, password: String): Fu[Option[User]] =
|
||||
checkPasswordById(id) map { _ flatMap { _(password) } }
|
||||
|
||||
def authenticateByEmail(email: String, password: String): Fu[Option[User]] =
|
||||
def authenticateByEmail(email: Email, password: String): Fu[Option[User]] =
|
||||
checkPasswordByEmail(email) map { _ flatMap { _(password) } }
|
||||
|
||||
private case class AuthData(password: String, salt: String, sha512: Option[Boolean]) {
|
||||
|
@ -238,7 +239,7 @@ object UserRepo {
|
|||
def checkPasswordById(id: ID): Fu[Option[User.LoginCandidate]] =
|
||||
checkPassword($id(id))
|
||||
|
||||
def checkPasswordByEmail(email: String): Fu[Option[User.LoginCandidate]] =
|
||||
def checkPasswordByEmail(email: Email): Fu[Option[User.LoginCandidate]] =
|
||||
checkPassword($doc(F.email -> email))
|
||||
|
||||
private def checkPassword(select: Bdoc): Fu[Option[User.LoginCandidate]] =
|
||||
|
@ -253,7 +254,7 @@ object UserRepo {
|
|||
def create(
|
||||
username: String,
|
||||
password: String,
|
||||
email: Option[String],
|
||||
email: Option[Email],
|
||||
blind: Boolean,
|
||||
mobileApiVersion: Option[ApiVersion],
|
||||
mustConfirmEmail: Boolean
|
||||
|
@ -319,8 +320,10 @@ object UserRepo {
|
|||
|
||||
def disable(user: User) = coll.update(
|
||||
$id(user.id),
|
||||
$set(F.enabled -> false) ++
|
||||
user.lameOrTroll.fold($empty, $unset("email"))
|
||||
$set(F.enabled -> false) ++ {
|
||||
if (user.lameOrTroll) $empty
|
||||
else $doc("$rename" -> $doc(F.email -> F.prevEmail))
|
||||
}
|
||||
)
|
||||
|
||||
def passwd(id: ID, password: String): Funit =
|
||||
|
@ -333,9 +336,11 @@ object UserRepo {
|
|||
}
|
||||
}
|
||||
|
||||
def email(id: ID, email: String): Funit = coll.updateField($id(id), F.email, email).void
|
||||
def email(id: ID, email: Email): Funit = coll.updateField($id(id), F.email, email).void
|
||||
def email(id: ID): Fu[Option[Email]] = coll.primitiveOne[Email]($id(id), F.email)
|
||||
|
||||
def email(id: ID): Fu[Option[String]] = coll.primitiveOne[String]($id(id), F.email)
|
||||
def prevEmail(id: ID, prevEmail: Email): Funit = coll.updateField($id(id), F.prevEmail, prevEmail).void
|
||||
def prevEmail(id: ID): Fu[Option[Email]] = coll.primitiveOne[Email]($id(id), F.prevEmail)
|
||||
|
||||
def hasEmail(id: ID): Fu[Boolean] = email(id).map(_.isDefined)
|
||||
|
||||
|
@ -416,7 +421,7 @@ object UserRepo {
|
|||
private def newUser(
|
||||
username: String,
|
||||
password: String,
|
||||
email: Option[String],
|
||||
email: Option[Email],
|
||||
blind: Boolean,
|
||||
mobileApiVersion: Option[ApiVersion],
|
||||
mustConfirmEmail: Boolean
|
||||
|
|
Loading…
Reference in New Issue