pyc-website

main website for pyc inc.

git clone https://9o.is/git/pyc-website.git

User.scala

(7446B)


      1 package inc.pyc
      2 package model
      3 
      4 import lib._
      5 import config._
      6 import field._
      7 import lib.RogueMetaRecord
      8 import org.bson.types.ObjectId
      9 import org.joda.time.DateTime
     10 import net.liftweb._
     11 import common._
     12 import http.{StringField => _, BooleanField => _, _}
     13 import mongodb.record.field._
     14 import record.field._
     15 import net.liftmodules.mongoauth._
     16 import net.liftmodules.mongoauth.field._
     17 import net.liftmodules.mongoauth.model._
     18 import java.util.regex.Pattern
     19 import scala.concurrent._
     20 import ExecutionContext.Implicits.global
     21 
     22 class User private () extends ProtoAuthUser[User] with ObjectIdPk[User] with USAUserVerification[User] {
     23   def meta = User
     24   
     25   def userIdAsString: String = id.toString
     26 
     27   /**
     28    * User's first name.
     29    */
     30   object fname extends StringField(this, 32) {
     31     override def validations =
     32       valMaxLen(32, "First Name must be 32 characters or less") _ ::
     33       super.validations
     34   }
     35   
     36   /**
     37    * User's last name.
     38    */
     39   object lname extends StringField(this, 32) {
     40     override def validations =
     41       valMaxLen(32, "Last Name must be 32 characters or less") _ ::
     42       super.validations
     43   }
     44   
     45   /**
     46    * User's phone number.
     47    */
     48   object phone extends OptionalStringField(this, 10) {
     49     override def validations =
     50       valRegex(Pattern.compile("[0-9]{10}"), "Phone number must be 10 digits long") _ ::
     51       super.validations
     52   }
     53   
     54   /**
     55    * User's driver's license.
     56    */
     57   object driversLicense extends OptionalStringField(this, 50)
     58   
     59   /**
     60    * User's date of birth.
     61    */
     62   object dob extends OptionalStringField(this, 6) {
     63     override def validations =
     64       valRegex(Pattern.compile("[0-9]{6}"), "Date of Birth should be 6 digits long (xx/xx/xx)") _ ::
     65       super.validations
     66   }
     67   
     68   /**
     69    * User's one-time password.
     70    */
     71   object verifypass extends StringField(this, 15) {
     72     
     73     def reset = {
     74       set(StringUtils.randomString(7))
     75       owner
     76     }
     77     
     78     override def defaultValue = StringUtils.randomString(7)
     79   }
     80 
     81   /**
     82    * When user's account was created.
     83    */
     84   def whenCreated: DateTime = new DateTime(id.get.getTime)
     85   
     86   /**
     87    * Country the user is located (primarily)
     88    */
     89   object country extends CountryField(this) {
     90     override def defaultValue = Countries.USA
     91   }
     92   
     93   /**
     94    * Bitcoin addresses the user has used to buy bitcoin.
     95    */
     96   object addresses extends MongoListField[User, String](this) with MongoListFieldExtra[User, String]
     97 }
     98 
     99 object User extends User with ProtoAuthUserMeta[User] with RogueMetaRecord[User] with Loggable {
    100   import mongodb.BsonDSL._
    101 
    102   override def collectionName = "user.users"
    103 
    104   ensureIndex((email.name -> 1), ("unique" -> true))
    105   ensureIndex((phone.name -> 1), ("unique" -> true) ~ ("sparse" -> true))
    106   
    107   // look at https://jira.mongodb.org/browse/SERVER-3934
    108   ensureIndex((addresses.name -> 1), ("unique" -> true) ~ ("sparse" -> true) ~ ("v" -> 0))
    109 
    110   def findByEmail(in: String): Box[User] = find(email.name, in)
    111   
    112   def findByAddress(in: String): Box[User] = find(addresses.name, in)
    113   
    114   def findByPhone(in: String): Box[User] = find(phone.name, in)
    115 
    116   def findByStringId(id: String): Box[User] =
    117     if (ObjectId.isValid(id)) find(new ObjectId(id))
    118     else Empty
    119     
    120   override def onLogIn: List[User => Unit] = List(user => User.loginCredentials.remove())
    121   override def onLogOut: List[Box[User] => Unit] = List(
    122     x => logger.debug("User.onLogOut called."),
    123     boxedUser => boxedUser.foreach { u =>
    124       ExtSession.deleteExtCookie()
    125     }
    126   )
    127 
    128   /*
    129    * MongoAuth vars
    130    */
    131   private lazy val siteName = MongoAuth.siteName.vend
    132   private lazy val sysUsername = MongoAuth.systemUsername.vend
    133   private lazy val indexUrl = MongoAuth.indexUrl.vend
    134   private lazy val registerUrl = MongoAuth.registerUrl.vend
    135   private lazy val loginTokenAfterUrl = MongoAuth.loginTokenAfterUrl.vend
    136 
    137   /*
    138    * LoginToken
    139    */
    140   override def handleLoginToken: Box[LiftResponse] = {
    141     val resp = S.param("token").flatMap(LoginToken.findByStringId) match {
    142       case Full(at) if (at.expires.isExpired) => {
    143         at.delete_!
    144         RedirectWithState(indexUrl, RedirectState(() => { S.error("Login token has expired") }))
    145       }
    146       case Full(at) => find(at.userId.get).map(user => {
    147         if (user.validate.length == 0) {
    148           user.verified(true)
    149           user.save()
    150           logUserIn(user)
    151           at.delete_!
    152           RedirectResponse(loginTokenAfterUrl)
    153         }
    154         else {
    155           at.delete_!
    156           regUser(user)
    157           RedirectWithState(registerUrl, RedirectState(() => { S.notice("Please complete the registration form") }))
    158         }
    159       }).openOr(RedirectWithState(indexUrl, RedirectState(() => { S.error("User not found") })))
    160       case _ => RedirectWithState(indexUrl, RedirectState(() => { S.warning("Login token not provided") }))
    161     }
    162 
    163     Full(resp)
    164   }
    165 
    166   /**
    167    * Sends an email to the user with a link for logging in.
    168    */
    169   def sendLoginToken(user: User): Future[Unit] = Future {
    170     import net.liftweb.util.Mailer._
    171     
    172       val token = LoginToken.createRecord.userId(user.id.get).save()
    173       val url = "%s%s?token=%s".format(Site.host, MongoAuth.loginTokenUrl.vend, token.id.toString)
    174       val title = "Account Login"
    175       val btn = "Complete "+title
    176       val msg = "Hello, someone requested a link to log in to your account."
    177 
    178       HtmlEmail.createToken(false, "", msg, btn, url, false) map {
    179         sendMail(
    180           From(MongoAuth.systemFancyEmail),
    181           Subject("%s: %s".format(siteName, title)),
    182           To(user.fancyEmail),
    183           _
    184         )
    185       }
    186   }
    187   
    188   /**
    189    * Sends registration token.
    190    */
    191   def sendRegistrationToken(user: User): Future[Unit] = Future {
    192     import net.liftweb.util.Mailer._
    193 
    194       val token = LoginToken.createRecord.userId(user.id.get).save()
    195       val url = "%s%s?token=%s".format(Site.host, MongoAuth.loginTokenUrl.vend, token.id.toString)
    196       val title = "Account Registration"
    197       val btn = "Complete "+title
    198       val msg = "Thank you for using bitcoin. Please follow the link to complete your registration."
    199 
    200       HtmlEmail.createToken(false, "", msg, btn, url, false) map {
    201         sendMail(
    202           From(MongoAuth.systemFancyEmail),
    203           Subject("%s: %s".format(siteName, title)),
    204           To(user.fancyEmail),
    205           _
    206         )
    207       }
    208   }
    209 
    210   /*
    211    * ExtSession
    212    */
    213   def createExtSession(uid: ObjectId) = ExtSession.createExtSessionBox(uid)
    214 
    215   /*
    216   * Test for active ExtSession.
    217   */
    218   def testForExtSession: Box[Req] => Unit = {
    219     ignoredReq => {
    220       if (currentUserId.isEmpty) {
    221         ExtSession.handleExtSession match {
    222           case Full(es) => find(es.userId.get).foreach { user => logUserIn(user, false) }
    223           case Failure(msg, _, _) =>
    224             logger.warn("Error logging user in with ExtSession: %s".format(msg))
    225           case Empty =>
    226         }
    227       }
    228     }
    229   }
    230 
    231   // used during login process
    232   object loginCredentials extends SessionVar[LoginCredentials](LoginCredentials(""))
    233   object regUser extends SessionVar[User](createRecord.email(loginCredentials.is.email))
    234 }
    235 
    236 case class LoginCredentials(email: String, isRememberMe: Boolean = false)
    237 
    238 object SystemUser {
    239   private val username = "pyc"
    240   private val email = "noreply@pycbitcoin.com"
    241 
    242   lazy val user: User = User.find("username", username) openOr {
    243     User.createRecord
    244       .fname("PYC")
    245       .username(username)
    246       .email(email)
    247       .verified(true)
    248       .password("abc123", true)
    249       .save()
    250   }
    251 }