[ESME-328] Fix resend and various other stuff. About ready to merge.
git-svn-id: https://svn.apache.org/repos/asf/esme/branches/esme-328_comet_timeline_rewrite@1090382 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index b16c7b6..a02f9fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,7 +75,7 @@
</developer>
</developers>
<properties>
- <lift.version>2.2</lift.version>
+ <lift.version>2.3</lift.version>
<scala.version>2.8.1</scala.version>
<compass.version>2.1.1</compass.version>
<lucene.version>2.4.0</lucene.version>
diff --git a/project/build/EsmeProject.scala b/project/build/EsmeProject.scala
index 940e205..171c926 100644
--- a/project/build/EsmeProject.scala
+++ b/project/build/EsmeProject.scala
@@ -1,7 +1,7 @@
import sbt._
class EsmeProject(info: ProjectInfo) extends DefaultWebProject(info) {
- val liftVersion = "2.2"
+ val liftVersion = "2.3"
val compassVersion = "2.1.1"
val luceneVersion = "2.4.0"
diff --git a/src/main/scala/bootstrap/liftweb/Boot.scala b/src/main/scala/bootstrap/liftweb/Boot.scala
index 0e164d9..a2ed26e 100644
--- a/src/main/scala/bootstrap/liftweb/Boot.scala
+++ b/src/main/scala/bootstrap/liftweb/Boot.scala
@@ -197,7 +197,7 @@
LiftRules.setSiteMap(SiteMap(entries: _*))
- S.addAround(ExtSession.requestLoans)
+ LiftRules.earlyInStateful.append(ExtSession.testCookieEarlyInStateful)
// API security rules
LiftRules.dispatch.append(API2.authorizationRules)
diff --git a/src/main/scala/org/apache/esme/comet/StreamTimeline.scala b/src/main/scala/org/apache/esme/comet/StreamTimeline.scala
index c66bb0f..79fb69a 100644
--- a/src/main/scala/org/apache/esme/comet/StreamTimeline.scala
+++ b/src/main/scala/org/apache/esme/comet/StreamTimeline.scala
@@ -62,9 +62,8 @@
case _ => currentPool = StreamTimeline.PublicPool
}
- if(filterPool) {
- messages = getMessages
- clearMessages = true
+ if(filterPool) {
+ messages = getMessages
this ! ForceRender
}
}
@@ -76,30 +75,26 @@
}
if(filterResender) {
- messages = getMessages
- clearMessages = true
+ messages = getMessages
this ! ForceRender
}
}
case FilterPool(on) => {
filterPool = on
- messages = getMessages
- clearMessages = true
+ messages = getMessages
this ! ForceRender
}
case FilterResender(on) => {
filterResender = on
- messages = getMessages
- clearMessages = true
+ messages = getMessages
this ! ForceRender
}
}
override def lowPriority = {
- case ForceRender =>
-// TODO: Adapt to new timeline format
+ case ForceRender =>
reRender(true)
case Distributor.NewMessage(msg) =>
@@ -122,8 +117,7 @@
scheduled = true
ActorPing.schedule(this, ForceRender, 30000L)
}
- }
-// TODO: Adapt to new timeline format
+ }
else reRender(true)
}
diff --git a/src/main/scala/org/apache/esme/comet/Timeline.scala b/src/main/scala/org/apache/esme/comet/Timeline.scala
index 850f4a7..feea553 100644
--- a/src/main/scala/org/apache/esme/comet/Timeline.scala
+++ b/src/main/scala/org/apache/esme/comet/Timeline.scala
@@ -23,11 +23,12 @@
import net.liftweb.util._
import net.liftweb.common._
import net.liftweb.util.Helpers._
-import scala.xml._
+import scala.xml._
import js._
-import JsCmds._
+import JsCmds._
import JE._
-import net.liftweb.http.js.jquery.JqJsCmds.{PrependHtml}
+import net.liftweb.http.js.jquery.JqJsCmds.{PrependHtml,FadeOut}
+import net.liftweb.http.SHtml.{BasicElemAttr}
import org.apache.esme._
import org.apache.esme.actor._
@@ -39,7 +40,6 @@
trait Timeline extends CometActor {
protected var messages: List[(Long,MailboxReason,Boolean)] = Nil
- protected var clearMessages: Boolean = false
protected val jsId: String
override def defaultPrefix = Full("timeline")
@@ -53,71 +53,19 @@
}
def render = {
-
-// TODO - handle clearMessages = true.
-// TODO - Get resend working
-// TODO - need to escape the replyHref string so that messages with ? in them don't bomb
-
+
val msgMap = Message.findMessages(messages map {_._1})
val toDisplay = for ((id, reason, resent) <- messages;
msg <- msgMap.get(id))
yield (msg, reason, resent)
<div id={jsId}>{toDisplay.map(renderMessage(_))}</div>
- }
-
- protected def renderMessage(m: (Message,MailboxReason,Boolean)) = {
- val imageUrl = m._1.author.obj.map(_.image_url).openOr("")
- val authorNickname = m._1.author.obj.map(_.niceName).openOr("")
- val messageId = "message_" + m._1.id.is.toString
- val messageBody = m._1.digestedXHTML
- val messagePool:String = m._1.pool.obj.map("in pool \'" + _.getName + "\'").openOr("")
- val replyHref = "javascript:setReplyTo(" + m._1.id.is.toString + ", '"+ messageBody + "', " + m._1.pool.obj.map(_.id.is).openOr(0) + ", '" + authorNickname + "')"
-
- val convId = m._1.conversation.is
- val convHref = LiftRules.context.path + "/conversation/" + convId
- val convTransform:CssBindFunc = if(convId != 0) {
- ".conversation [href]" #> convHref
- } else {
- ".conversation" #> Text("")
- }
-
- val authorHref = LiftRules.context.path + "/user/" + authorNickname
-
-// TODO: Put date in the "ago" format
- val messageDateStr = toInternetDate(m._1.when)
- val messageReason = if(m._2.attr.length > 0){
- if(m._2.attr.key == "resent_from") {
- "resent by " + User.find(m._2.attr.value).map(_.nickname).openOr("")
- } else {
- "caused by " + m._2.attr.key
- }
- } else {
- "via " + m._1.source
- }
-
- val suppString = messagePool + " " + messageDateStr + " " + messageReason
-
- ("#avatar [src]" #> imageUrl &
- ".updates-box [id]" #> messageId &
- ".msgbody *" #> messageBody &
- ".supp_data *" #> suppString &
- ".reply [href]" #> replyHref &
- convTransform &
- ".author [href]" #> authorHref &
- ".author *" #> authorNickname )(messageTemplate)
}
// If we need to filter out some messages on display, override this method.
def filter(msgs:List[(Message,MailboxReason,Boolean)]):List[(Message,MailboxReason,Boolean)] = {
msgs
}
-
- protected def prependMessage(m:Message, r:MailboxReason, rs:Boolean) {
- val newMessage = renderMessage((m,r,rs))
- val update = PrependHtml(jsId, newMessage)
- partialUpdate(update)
- }
// TODO Should be factored out into a template
val messageTemplate =
@@ -130,7 +78,7 @@
<div class="msgbody"/>
<div class="supp_data"/>
<div class="actions">
- <a href="#" class="resend">
+ <a href="#" class="resend resend_link">
<lift:loc>ui_messages_message_label_resend</lift:loc>
</a><span class="resend">| </span>
<a href="#" class="reply">
@@ -142,5 +90,79 @@
</a>
</div>
</div>
- </div>
+ </div>
+
+ protected def prependMessage(m:Message, r:MailboxReason, rs:Boolean) {
+ val newMessage = renderMessage((m,r,rs))
+ val update = PrependHtml(jsId, newMessage)
+ partialUpdate(update)
+ }
+
+ private def resendMessage(m:Message):JsCmd = {
+ for (user <- User.currentUser;
+ msgId = m.id.is) {
+ Distributor ! Distributor.ResendMessage(user.id, msgId)
+ }
+
+ val resendId = "resend_" + m.id.toString
+
+ FadeOut(resendId,0,200)
+ }
+
+ protected def renderMessage(m: (Message,MailboxReason,Boolean)) = {
+ val imageUrl = m._1.author.obj.map(_.image_url).openOr("")
+ val authorNickname = m._1.author.obj.map(_.niceName).openOr("")
+ val messageId = "message_" + m._1.id.is.toString
+ val messageBody = m._1.digestedXHTML
+ val replyBody = m._1.body.replaceAll("\\'","\\\\\\'")
+ val messagePool:String = m._1.pool.obj.map("in pool \'" + _.getName + "\'").openOr("")
+ val replyHref = "javascript:setReplyTo(" + m._1.id.is.toString + ", '"+ replyBody + "', " + m._1.pool.obj.map(_.id.is).openOr(0) + ", '" + authorNickname + "')"
+
+ val convId = m._1.conversation.is
+ val convHref = LiftRules.context.path + "/conversation/" + convId
+ val convTransform:CssBindFunc = if(convId != 0) {
+ ".conversation [href]" #> convHref
+ } else {
+ ".conversation" #> Text("")
+ }
+
+ val resendId = "resend_" + m._1.id.toString
+ val resendAttrs = BasicElemAttr("id",resendId).compose(BasicElemAttr("class","resend"))
+
+ val resendTransform:CssBindFunc =
+ if(m._3 || m._1.author.is == User.currentUser.map(_.id.is).openOr(0)) {
+ ".resend" #> Text("")
+ } else {
+ ".resend_link" #> SHtml.a(
+ () => resendMessage(m._1),
+ S.loc("ui_messages_message_label_resend").openOr(Text("")),
+ resendAttrs)
+ }
+
+ val authorHref = LiftRules.context.path + "/user/" + authorNickname
+
+// TODO: Put date in the "ago" format
+ val messageDateStr = toInternetDate(m._1.when)
+ val messageReason = if(m._2.attr.length > 0){
+ if(m._2.attr.key == "resent_from") {
+ "resent by " + User.find(m._2.attr.value).map(_.nickname).openOr("")
+ } else {
+ "caused by " + m._2.attr.key
+ }
+ } else {
+ "via " + m._1.source
+ }
+
+ val suppString = messagePool + " " + messageDateStr + " " + messageReason
+
+ ("#avatar [src]" #> imageUrl &
+ ".updates-box [id]" #> messageId &
+ ".msgbody *" #> messageBody &
+ ".supp_data *" #> suppString &
+ ".reply [href]" #> replyHref &
+ convTransform &
+ ".author [href]" #> authorHref &
+ ".author *" #> authorNickname &
+ resendTransform )(messageTemplate)
+ }
}
diff --git a/src/main/scala/org/apache/esme/model/ExtSession.scala b/src/main/scala/org/apache/esme/model/ExtSession.scala
index 6d28fb0..9744f2e 100644
--- a/src/main/scala/org/apache/esme/model/ExtSession.scala
+++ b/src/main/scala/org/apache/esme/model/ExtSession.scala
@@ -24,7 +24,7 @@
import util._
import common._
-object ExtSession extends ExtSession with MetaProtoExtendedSession[ExtSession] {
+object ExtSession extends ExtSession with LongKeyedMetaMapper[ExtSession] with MetaProtoExtendedSession[ExtSession] {
override def dbTableName = "ext_session" // define the DB table name
def logUserIdIn(uid: String): Unit = User.logUserIdIn(uid)
@@ -34,7 +34,7 @@
type UserType = User
}
-class ExtSession extends ProtoExtendedSession[ExtSession] {
+class ExtSession extends LongKeyedMapper[ExtSession] with ProtoExtendedSession[ExtSession] {
def getSingleton = ExtSession // what's the "meta" server
}
diff --git a/src/main/scala/org/apache/esme/model/Mailbox.scala b/src/main/scala/org/apache/esme/model/Mailbox.scala
index db4bcf9..ada8edb 100644
--- a/src/main/scala/org/apache/esme/model/Mailbox.scala
+++ b/src/main/scala/org/apache/esme/model/Mailbox.scala
@@ -107,7 +107,7 @@
def attr = new UnprefixedAttribute("tag", tagName, Null)
}
case class ConvFollowReason(convId: Long) extends MailboxReason {
- def attr = new UnprefixedAttribute("conversation", convId, Null)
+ def attr = new UnprefixedAttribute("conversation", convId.toString, Null)
}
case class LoginReason(userId: Long) extends MailboxReason {
def attr = new UnprefixedAttribute("login", userId.toString, Null)
diff --git a/src/main/scala/org/apache/esme/snippet/UserSnip.scala b/src/main/scala/org/apache/esme/snippet/UserSnip.scala
index 04f1a7b..e33e14b 100644
--- a/src/main/scala/org/apache/esme/snippet/UserSnip.scala
+++ b/src/main/scala/org/apache/esme/snippet/UserSnip.scala
@@ -79,21 +79,6 @@
}
}
-object JsonResender extends JsonHandler{
- def apply(in: Any): JsCmd = in match {
- case JsonCmd("resend", _, map: Map[String, Any], _) =>
- for (msgId <- map.get("msg_id").map(toLong);
- user <- User.currentUser)
- Distributor ! Distributor.ResendMessage(user.id, msgId)
-
- Noop
-
- case _ => Noop
- }
-}
-
-
-
class UserSnip extends DispatchSnippet {
def dispatch: DispatchIt =
@@ -104,8 +89,7 @@
"following" -> following _,
"loginForm" -> loginForm _,
"loggedIn" -> loggedInFilter _,
- "accessPools" -> accessPools _,
- "resendScript" -> resendScript _,
+ "accessPools" -> accessPools _,
"popular" -> popular _,
"links" -> links _)
@@ -149,8 +133,6 @@
// Image of user as part of an img tag
- def logoutimage: MetaData = ("src" -> (Message.root + "/images/btn-signout.gif"))
- def searchimage: MetaData = ("src" -> (Message.root + "/images/btn-search.gif"))
def image: MetaData = ("src" -> (User.currentUser.map(_.image_url)openOr "/images/avatar.jpg"))
@@ -200,16 +182,6 @@
}
</xml:group>
- def resendScript(in: NodeSeq): NodeSeq =
- <xml:group>
- {Script(JsonResender.jsCmd)}
- {Script(Function("resend_msg", List("msg_id"),
- JsonResender.call("resend",
- JsObj("msg_id" -> JsVar("msg_id")))
- ))
- }
- </xml:group>
-
def popular(in: NodeSeq): NodeSeq =
PopStatsActor !? PopStatsActor.TopStats(ResendStat, 5, 1 week) match {
case l: List[Tuple2[Long,Int]] =>
diff --git a/src/main/webapp/templates-hidden/base.html b/src/main/webapp/templates-hidden/base.html
index c0d8498..a5b6fe3 100644
--- a/src/main/webapp/templates-hidden/base.html
+++ b/src/main/webapp/templates-hidden/base.html
@@ -32,14 +32,14 @@
<meta name="generator" content="" lang="en-US" />
<meta name="author" content="ESME Designed by Joy Reyes" lang="en-US" />
<meta name="Robots" content="index,follow,noodp" />
- <link rel="stylesheet" href="../style/style.css" type="text/css" media="screen" />
- <link rel="stylesheet" href="../style/tipTip.css" type="text/css" media="screen" />
+ <link rel="stylesheet" href="/style/style.css" type="text/css" media="screen" />
+ <link rel="stylesheet" href="/style/tipTip.css" type="text/css" media="screen" />
<script id="jquery" src="/classpath/jquery.js" type="text/javascript"/>
<script id="json" src="/classpath/json.js" type="text/javascript"/>
- <script src="../scripts/jquery.TipTip.js" type="text/javascript"/>
- <script src="../scripts/esme_tool_tip.js" type="text/javascript"/>
- <script src="../scripts/jquery.validate.js" type="text/javascript"/>
- <script src="../scripts/esme_validate.js" type="text/javascript"/>
+ <script src="/scripts/jquery.TipTip.js" type="text/javascript"/>
+ <script src="/scripts/esme_tool_tip.js" type="text/javascript"/>
+ <script src="/scripts/jquery.validate.js" type="text/javascript"/>
+ <script src="/scripts/esme_validate.js" type="text/javascript"/>
</head>
<body id="back">
<div id="messages" class="esme_message_bar" style="display: none"></div>
@@ -63,7 +63,7 @@
</ul>
<lift:Menu.item name="logout">
- <img lift:snippet="UserSnip.logoutimage" alt="" class="tipelement" title="Log out of ESME." />
+ <img src="/images/btn-signout.gif" alt="" class="tipelement" title="Log out of ESME." />
</lift:Menu.item>
</div>
</div><!--// ENDS HEADER -->
@@ -87,7 +87,7 @@
<input type="text" class="inputBox required alphanumeric nowhitespace" name="term" value=""/>
</div>
<div class="searchButton">
- <input type="image" onclick="javascript:form.submit();" lift:snippet="UserSnip.searchimage" style="padding:0;"/>
+ <input type="image" onclick="javascript:form.submit();" src="/images/btn-search.gif" style="padding:0;"/>
</div>
</div>
</form><!--search form--><h3 class ="tipelement" title="These are tags that appear often in your timeline."><lift:loc>ui_messages_message_label_tag_cloud</lift:loc></h3>