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 }