scala-news-reader

rss/atom news reader in scala

git clone https://9o.is/git/scala-news-reader.git

User.scala

(8477B)


      1 package com.joereader
      2 package model
      3 
      4 import org.bson.types._
      5 
      6 import net.liftweb._
      7 import util._
      8 import common._
      9 import http.{ StringField => _, BooleanField => _, _ }
     10 
     11 import net.liftweb.record._
     12 import net.liftweb.record.field._
     13 import net.liftweb.mongodb.record._
     14 import net.liftweb.mongodb.record.field._
     15 import net.liftmodules.mongoauth._
     16 import net.liftmodules.mongoauth.model._
     17 
     18 import com.joereader._
     19 import com.joereader.model.field._
     20 import config._
     21 import lib.rss._
     22 
     23 class User private () extends ProtoAuthUser[User] with ObjectIdPk[User] {
     24   def meta = User
     25 
     26   def userIdAsString: String = id.toString()
     27 
     28   object name extends StringField(this, 64)
     29 
     30   def firstName = name.get.split(" ").headOption getOrElse ""
     31 
     32   object about extends TextareaField(this, 500)
     33 
     34   object img extends StringField(this, 50)
     35 
     36   object bgImg extends StringField(this, 50)
     37 
     38   object otherVid extends MongoListField[User, String](this) with MongoListFieldExtra[User, String]
     39 
     40   object blogs extends ObjectIdRefListField(this, Blog) with ObjectIdRefListFieldExtra[User, Blog]
     41 
     42   def isWriter: Boolean = !blogs.get.isEmpty
     43 
     44   /* List of blog writer users this user follows. */
     45   object following extends BlogWriterUserListField(this)
     46 
     47   /*
     48    * Follow this user to view his shared articles
     49    * (only if this user is a writer)
     50    */
     51   object followers extends ObjectIdRefListField(this, User) with ObjectIdRefListFieldExtra[User, User]
     52 
     53   object saved extends ArticleListField(this)
     54 
     55   object shared extends ArticleSharedListField(this, this)
     56 }
     57 
     58 object User extends User with ProtoAuthUserMeta[User] with Loggable {
     59 
     60   import mongodb.BsonDSL._
     61 
     62   override def collectionName = "user.users"
     63 
     64   ensureIndex(email.name -> 1, unique = true)
     65   ensureIndex(username.name -> 1, unique = true)
     66   ensureIndex(name.name -> 1, unique = false)
     67 
     68   def defaultId = new ObjectId("0" * 24)
     69 
     70   def findByEmail(in: String): Box[User] = find(email.name, in)
     71 
     72   def findByName(in: String): Box[User] = find(name.name, in)
     73 
     74   def findByUsername(in: String): Box[User] =
     75     find(username.name, in.toLowerCase)
     76 
     77   def findByStringId(id: String): Box[User] =
     78     if (ObjectId.isValid(id) && id != "0" * 24)
     79       find(new ObjectId(id))
     80     else
     81       Empty
     82 
     83   override def onLogIn: List[User => Unit] =
     84     List(user => User.loginCredentials.remove())
     85 
     86   override def onLogOut: List[Box[User] => Unit] = List(
     87     x => logger.debug("User.onLogOut called."),
     88     boxedUser => boxedUser.foreach {
     89       u =>
     90         ExtSession.deleteExtCookie()
     91     })
     92 
     93   /*
     94    * MongoAuth vars
     95    */
     96   private lazy val siteName = MongoAuth.siteName.vend
     97   private lazy val sysUsername = MongoAuth.systemUsername.vend
     98   private lazy val indexUrl = MongoAuth.indexUrl.vend
     99   private lazy val registerUrl = MongoAuth.registerUrl.vend
    100   private lazy val loginTokenAfterUrl = MongoAuth.loginTokenAfterUrl.vend
    101 
    102   /*
    103    * LoginToken
    104    */
    105   override def handleLoginToken(): Box[LiftResponse] = {
    106     val resp = S.param("token").flatMap(LoginToken.findByStringId) match {
    107       case Full(at) if at.expires.isExpired => {
    108         at.delete_!
    109         RedirectWithState(indexUrl, RedirectState(() => {
    110           S.error("Login token has expired")
    111         }))
    112       }
    113       case Full(at) => find(at.userId.is).map(user => {
    114         if (user.validate.length == 0) {
    115           user.verified(true).save
    116           logUserIn(user)
    117           //at.delete_! (token is deleted at Password Reset)
    118           RedirectResponse(loginTokenAfterUrl)
    119         } else {
    120           at.delete_!
    121           regUser(user)
    122           RedirectWithState(registerUrl, RedirectState(() => {
    123             S.notice("Please complete the registration form")
    124           }))
    125         }
    126       }).openOr(RedirectWithState(indexUrl, RedirectState(() => {
    127         S.error("User not found")
    128       })))
    129       case _ => RedirectWithState(indexUrl, RedirectState(() => {
    130         S.warning("Login token not provided")
    131       }))
    132     }
    133 
    134     Full(resp)
    135   }
    136 
    137   // send an email to the user with a link for logging in
    138   def sendLoginToken(user: User) {
    139     import net.liftweb.util.Mailer._
    140 
    141     val token = LoginToken.createForUserId(user.id.get)
    142 
    143     val msgTxt =
    144       """
    145         |Someone requested a link to change your password on the %s website.
    146         |
    147         |If you did not request this, you can safely ignore it. It will expire 48 hours from the time this message was sent.
    148         |
    149         |Follow the link below or copy and paste it into your internet browser.
    150         |
    151         |%s
    152         |
    153         |Yours truly,
    154         |%s
    155       """.format(siteName, token.url, sysUsername).stripMargin
    156 
    157     sendMail(
    158       From(MongoAuth.systemFancyEmail),
    159       Subject("%s Password Help".format(siteName)),
    160       To(user.fancyEmail),
    161       PlainMailBodyType(msgTxt))
    162   }
    163 
    164   def handleInviteToken(): Box[LiftResponse] = {
    165     var resp: LiftResponse = DoRedirectResponse("/")
    166 
    167     S.param("token").flatMap(InviteToken.findByStringId) match {
    168       case Full(at) if at.expires.isExpired =>
    169         at.delete_!
    170         resp = RedirectWithState(indexUrl, RedirectState(() => {
    171           S.error("Invite token has expired.")
    172         }))
    173 
    174       case Full(at) =>
    175 
    176         // Find user if he is registered already else create user
    177         val userBoxed = findByEmail(at.email.is)
    178         val user: User = userBoxed openOr {
    179           createRecord.
    180             email(at.email.get).
    181             name(at.name.get).
    182             password(StringHelpers.randomString(20), true).
    183             username(StringHelpers.randomString(15))
    184         }
    185 
    186         Blog.findByStringId(at.blogId.get.toString).map {
    187           blog =>
    188             val blogWriter =
    189               BlogWriter.createRecord.user(user.id.get).name(at.name.get)
    190 
    191             blog.writers.addSafely(blogWriter).save
    192             user.blogs.add(blog).verified(true).save
    193 
    194             if (userBoxed.isDefined)
    195               resp = RedirectWithState(Site.categoriesLoc.calcHref(blog),
    196                 RedirectState(() => {
    197                   S.notice("Congratulations! You are verified with " +
    198                     blog.name.get + "!")
    199                 }))
    200             else
    201               resp = RedirectWithState(Site.signUp3.url,
    202                 RedirectState(() => {
    203                   snippet.BlogIdVar(at.blogId.get.toString)
    204                   snippet.VerifiedVar(true)
    205                   S.notice("Congratulations! You are verified with " +
    206                     blog.name.get + "!")
    207                 }))
    208         }
    209 
    210         // Remove token
    211         at.delete_!
    212 
    213         // Log user in
    214         if (isLoggedIn) logUserOut()
    215         logUserIn(user, isAuthed = true)
    216 
    217       case _ =>
    218         resp = RedirectWithState(indexUrl, RedirectState(() => {
    219           S.warning("Invite token is missing.")
    220         }))
    221     }
    222 
    223     Full(resp)
    224   }
    225 
    226   def sendInviteToken(name: String, email: String, user: User, blog: Blog) {
    227     import net.liftweb.util.Mailer._
    228 
    229     val token = InviteToken.create(email, name, blog.id.is)
    230     val msgTxt =
    231       """
    232         |Hi %s,
    233         |
    234         |%s has invited you to Read Means to become a member of your
    235         |current blog, %s.
    236         |
    237         |Click below to join:
    238         |%s
    239         |
    240         |Yours truly,
    241         |%s
    242       """.
    243         format(name, user.name.get, blog.name.get, token.url,
    244           MongoAuth.systemUsername.vend).stripMargin
    245 
    246     sendMail(
    247       From(MongoAuth.systemFancyEmail),
    248       Subject("%s invites you to %s".
    249         format(user.name.get, MongoAuth.siteName.vend)),
    250       To(email),
    251       PlainMailBodyType(msgTxt))
    252   }
    253 
    254   // used during login process (holds email address)
    255   object loginCredentials extends SessionVar[String]("")
    256 
    257   object regUser
    258     extends SessionVar[User](createRecord.email(loginCredentials.is))
    259 
    260 }
    261 
    262 object SystemUser {
    263   private val username = "julio"
    264   private val email = "j.cabrra@gmail.com"
    265 
    266   lazy val user: User = User.find("username", username) openOr {
    267     User.createRecord
    268       .name("Julio")
    269       .username(username)
    270       .email(email)
    271       .verified(true)
    272       .password("deanjoe321", isPlain = true)
    273       .save
    274   }
    275 }
    276 
    277 object TestUser {
    278   private val username = "testuser"
    279   private val email = "test@example.com"
    280 
    281   lazy val user: User = User.find("username", username) openOr {
    282     User.createRecord
    283       .name("Test Man")
    284       .username(username)
    285       .email(email)
    286       .verified(true)
    287       .password("test1234", isPlain = true)
    288       .save
    289   }
    290 
    291   def isLoggedIn = User.currentUser.
    292     exists(_.username.get == TestUser.user.username.get)
    293 }