scala-news-reader

rss/atom news reader in scala

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

FollowSnip.scala

(6239B)


      1 package com.joereader.snippet
      2 
      3 import net.liftweb._
      4 import common._
      5 import http._, js._
      6 import JsCmds._
      7 import SHtml._
      8 import util._, Helpers._
      9 
     10 import com.joereader._
     11 import model._
     12 import config._
     13 
     14 import scala.xml._
     15 
     16 /**
     17  * Allow users to follow blog writers and other users. (BlogWriterUser)
     18  */
     19 trait FollowSnip extends BlogWriterUserSnip {
     20 
     21   val btnPrefix = "follow-btn"
     22 
     23   private def test: Boolean =
     24     (for {
     25       bwu <- bwu
     26       user <- bwu.user
     27     } yield
     28       User.currentUser.exists(_.id.is != user.id.is) && user.isWriter).
     29       getOrElse(User.isLoggedIn)
     30 
     31   def followButton: NodeSeq =
     32     if(bwu.exists(_.user.isDefined)) userFollowButton(bwu)
     33     else blogWriterFollowButton(bwu)
     34 
     35   def followButton(bwu: Box[BlogWriterUser]): NodeSeq =
     36     if(bwu.exists(_.user.isDefined)) userFollowButton(bwu)
     37     else blogWriterFollowButton(bwu)
     38 
     39   def userFollowButton(bwu: Box[BlogWriterUser]): NodeSeq =
     40     if(test) bwu.flatMap(_.user.map {
     41       user =>
     42         val btnId = btnPrefix + "-" + user.id.get
     43 
     44         def isFollowing: Boolean =
     45           User.currentUser.exists(_.following.exists(user))
     46 
     47         def unFollowBtn: NodeSeq =
     48           ajaxButton("Unfollow", () => unFollow,
     49             "class" -> "btn btn-info btn-large",
     50             "id" -> btnId)
     51 
     52         def followBtn =
     53           ajaxButton("Follow", () => follow,
     54             "class" -> "btn btn-primary btn-large",
     55             "id" -> btnId)
     56 
     57         def follow: JsCmd = {
     58           for {
     59             loggedInUser <- User.currentUser
     60             user <- User.find(user.id.get)
     61           } yield {
     62             loggedInUser.following.add(
     63                 new BlogWriterUser(user)).update
     64             user.followers.add(loggedInUser).update
     65             user.blogs.objs.map {
     66               blog =>
     67                 blog.writers.find(user).map { writer => 
     68                   writer.followers.add(loggedInUser)
     69                   loggedInUser.following.add(
     70                       new BlogWriterUser(blog, writer)).update
     71                 }
     72                 blog.save
     73             }
     74           }
     75           Replace(btnId, unFollowBtn)
     76         }
     77 
     78         def unFollow: JsCmd = {
     79           for {
     80             loggedInUser <- User.currentUser
     81             user <- User.find(user.id.get)
     82           } yield {
     83             loggedInUser.following.remove(
     84                 new BlogWriterUser(user)).update
     85             user.followers.remove(loggedInUser).update
     86             user.blogs.objs.map {
     87               blog =>
     88                 blog.writers.find(user).map { writer => 
     89                   writer.followers.remove(loggedInUser)
     90                   loggedInUser.following.remove(
     91                       new BlogWriterUser(blog, writer)).update
     92                 }
     93                 blog.save
     94             }
     95           }
     96           Replace(btnId, followBtn)
     97         }
     98 
     99         if (isFollowing) unFollowBtn else followBtn
    100   }) else NodeSeq.Empty
    101 
    102   /*
    103    * Note: We search for blog even though we have the record already
    104    * because it might be unsynchronised due to having multiple
    105    * BlogWriterUser's, hence multiple unsynchronised blogs.
    106    *
    107    */
    108   def blogWriterFollowButton(bwu: Box[BlogWriterUser]): NodeSeq = {
    109     if(test)
    110       for {
    111         bwu <- bwu
    112         blog <- bwu.blog
    113         blogWriter <- bwu.blogWriter
    114       } yield {
    115         val btnId = btnPrefix + "-" + bwu.dashName
    116 
    117         def isFollowing: Boolean =
    118           User.currentUser.exists(_.following.exists(blogWriter, blog))
    119 
    120         def unFollowBtn: NodeSeq =
    121           ajaxButton("Unfollow", () => unFollow,
    122             "class" -> "btn btn-info btn-large",
    123             "id" -> btnId)
    124 
    125         def followBtn =
    126           ajaxButton("Follow", () => follow,
    127             "class" -> "btn btn-primary btn-large",
    128             "id" -> btnId)
    129 
    130         def follow: JsCmd = {
    131           for {
    132             user <- User.currentUser
    133             blog <- Blog.find(blog.id.get)
    134             blogWriter <- blog.writers.findStr(blogWriter.name.get)
    135           } yield {
    136             user.following.add(
    137                 new BlogWriterUser(blog, blogWriter)).update
    138             blogWriter.followers.add(user)
    139             blog.save
    140           }
    141           Replace(btnId, unFollowBtn)
    142         }
    143 
    144         def unFollow: JsCmd = {
    145           for {
    146             user <- User.currentUser
    147             blog <- Blog.find(blog.id.get)
    148             blogWriter <- blog.writers.findStr(blogWriter.name.get)
    149           } yield {
    150             user.following.remove(
    151                 new BlogWriterUser(blog, blogWriter)).update
    152             blogWriter.followers.remove(user)
    153             blog.save
    154           }
    155           Replace(btnId, followBtn)
    156         }
    157 
    158         if (isFollowing) unFollowBtn else followBtn
    159       }
    160     else NodeSeq.Empty
    161   }
    162 
    163   def followersAmount: NodeSeq =
    164     if(bwu.exists(_.user.isDefined)) userFollowersAmount
    165     else blogWriterFollowersAmount
    166 
    167   def blogWriterFollowersAmount: NodeSeq = serve {
    168     (blog, blogWriter) =>
    169       Text(blogWriter.followers.get.size.toString + " followers")
    170   }(test = true, NodeSeq.Empty)
    171 
    172   def userFollowersAmount: NodeSeq = bwu.flatMap(_.user.map {
    173     user =>
    174 
    175       val blogFollowers =
    176         (for {
    177           blog <- user.blogs.objs
    178           blogWriter <- blog.writers.find(user)
    179         } yield blogWriter.followers.get).flatten
    180 
    181       val followers = (blogFollowers ::: user.followers.get).distinct
    182 
    183       Text(followers.size.toString + " followers")
    184   })
    185 
    186   /*
    187    * Subclasses must override this user to see the list
    188    * of following for that user.
    189    */
    190   protected def followingUser: Box[User] = Empty
    191 
    192   def following: CssSel = followingUser.map {
    193     user: User =>
    194       val following = user.following.allUsers
    195       
    196       if(following.isEmpty)
    197         ".writer *" #> Text("No one is being followed here")
    198       else  
    199       ".writer *" #> following.map {
    200         bwu =>
    201           ".writer-link [href]" #> bwu.link &
    202             ".name .writer-link [href]" #> bwu.link &
    203             ".writer-link img [src]" #> bwu.image &
    204             ".name a *" #> bwu.name &
    205             ".categories *" #> bwu.categories &
    206             ".url a *" #> bwu.url &
    207             ".url a [href]" #> bwu.blog.map(Site.blogProfileLoc.calcHref) &
    208             "#follow-btn" #> followButton(Full(bwu))
    209       }
    210   }
    211 }