forum post list, autolink urls
This commit is contained in:
parent
1c57aaf6dd
commit
8d801171d5
13
app/controllers/ForumPost.scala
Normal file
13
app/controllers/ForumPost.scala
Normal file
|
@ -0,0 +1,13 @@
|
|||
package controllers
|
||||
|
||||
import lila._
|
||||
import views._
|
||||
|
||||
object ForumPost extends LilaController {
|
||||
|
||||
def postApi = env.forum.postApi
|
||||
|
||||
def create(categSlug: String, slug: String) = TODO
|
||||
|
||||
def delete(id: String) = TODO
|
||||
}
|
|
@ -5,9 +5,15 @@ import views._
|
|||
|
||||
object ForumTopic extends LilaController {
|
||||
|
||||
def topicApi = env.forum.topicApi
|
||||
|
||||
def create(categ: String) = TODO
|
||||
|
||||
def show(categSlug: String, slug: String) = TODO
|
||||
def show(categSlug: String, slug: String, page: Int) = Open { implicit ctx ⇒
|
||||
IOptionOk(topicApi.show(categSlug, slug, page)) {
|
||||
case (categ, topic, posts) ⇒ html.forum.topic.show(categ, topic, posts)
|
||||
}
|
||||
}
|
||||
|
||||
def delete(id: String) = TODO
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ package lila
|
|||
package forum
|
||||
|
||||
import scalaz.effects._
|
||||
import com.github.ornicar.paginator._
|
||||
import com.github.ornicar.paginator.Paginator
|
||||
|
||||
final class CategApi(env: ForumEnv, maxPerPage: Int) {
|
||||
final class CategApi(env: ForumEnv) {
|
||||
|
||||
val list: IO[List[CategView]] = for {
|
||||
categs ← env.categRepo.all
|
||||
|
|
|
@ -19,9 +19,11 @@ final class ForumEnv(
|
|||
|
||||
lazy val postRepo = new PostRepo(mongodb(MongoCollectionForumPost))
|
||||
|
||||
lazy val categApi = new CategApi(this, ForumTopicMaxPerPage)
|
||||
lazy val categApi = new CategApi(this)
|
||||
|
||||
lazy val topicApi = new TopicApi(this, ForumPostMaxPerPage)
|
||||
lazy val topicApi = new TopicApi(this, ForumTopicMaxPerPage)
|
||||
|
||||
lazy val postApi = new PostApi(this, ForumPostMaxPerPage)
|
||||
|
||||
lazy val denormalize = topicApi.denormalize flatMap { _ ⇒ categApi.denormalize }
|
||||
}
|
||||
|
|
18
app/forum/PostApi.scala
Normal file
18
app/forum/PostApi.scala
Normal file
|
@ -0,0 +1,18 @@
|
|||
package lila
|
||||
package forum
|
||||
|
||||
import scalaz.effects._
|
||||
import com.github.ornicar.paginator._
|
||||
|
||||
final class PostApi(env: ForumEnv, maxPerPage: Int) {
|
||||
|
||||
def paginator(topic: Topic, page: Int): Paginator[Post] =
|
||||
Paginator(
|
||||
SalatAdapter(
|
||||
dao = env.postRepo,
|
||||
query = env.postRepo byTopicQuery topic,
|
||||
sort = env.postRepo.sortQuery),
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage
|
||||
) | paginator(topic, 1)
|
||||
}
|
|
@ -16,19 +16,21 @@ final class PostRepo(
|
|||
}
|
||||
|
||||
def countByTopics(topics: List[Topic]): IO[Int] = io {
|
||||
count(topicsQuery(topics)).toInt
|
||||
count(byTopicsQuery(topics)).toInt
|
||||
}
|
||||
|
||||
def lastByTopics(topics: List[Topic]): IO[Post] = io {
|
||||
find(topicsQuery(topics)).sort(sortQuery).limit(1).next
|
||||
find(byTopicsQuery(topics)).sort(sortQuery).limit(1).next
|
||||
}
|
||||
|
||||
val all: IO[List[Post]] = io {
|
||||
find(DBObject()).toList
|
||||
}
|
||||
|
||||
private val sortQuery = DBObject("createdAt" -> -1)
|
||||
val sortQuery = DBObject("createdAt" -> -1)
|
||||
|
||||
private def topicsQuery(topics: List[Topic]) =
|
||||
def byTopicQuery(topic: Topic) = DBObject("topicId" -> topic.id)
|
||||
|
||||
private def byTopicsQuery(topics: List[Topic]) =
|
||||
"topicId" $in topics.map(_.id)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,14 @@ import com.github.ornicar.paginator._
|
|||
|
||||
final class TopicApi(env: ForumEnv, maxPerPage: Int) {
|
||||
|
||||
def show(categSlug: String, slug: String, page: Int): IO[Option[(Categ, Topic, Paginator[Post])]] =
|
||||
for {
|
||||
categOption ← env.categRepo bySlug categSlug
|
||||
topicOption ← env.topicRepo.byTree(categSlug, slug)
|
||||
} yield categOption |@| topicOption apply {
|
||||
case (categ, topic) ⇒ (categ, topic, env.postApi.paginator(topic, page))
|
||||
}
|
||||
|
||||
def paginator(categ: Categ, page: Int): Paginator[TopicView] =
|
||||
Paginator(
|
||||
SalatAdapter(
|
||||
|
|
|
@ -16,6 +16,13 @@ final class TopicRepo(
|
|||
find(DBObject("categId" -> categ.slug)).toList
|
||||
}
|
||||
|
||||
def byTree(categSlug: String, slug: String): IO[Option[Topic]] = io {
|
||||
findOne(DBObject(
|
||||
"categId" -> categSlug,
|
||||
"slug" -> slug
|
||||
))
|
||||
}
|
||||
|
||||
val all: IO[List[Topic]] = io {
|
||||
find(DBObject()).toList
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package lila
|
||||
package templating
|
||||
|
||||
import scala.math._
|
||||
import java.text.SimpleDateFormat
|
||||
import java.text.Normalizer
|
||||
import java.util.Date
|
||||
import org.apache.commons.lang3.StringEscapeUtils.escapeXml
|
||||
import play.api.templates.Html
|
||||
|
||||
object StringHelper extends StringHelper
|
||||
|
||||
|
@ -22,10 +23,14 @@ trait StringHelper {
|
|||
|
||||
def pluralize(s: String, n: Int) = "%d %s%s".format(n, s, if (n > 1) "s" else "")
|
||||
|
||||
//implicit def richString(str: String) = new {
|
||||
def autoLink(text: String) = Html {
|
||||
addLinks(escapeXml(text)).replace("\n", "<br />")
|
||||
}
|
||||
|
||||
//def capitalize = str(0).toUpperCase + str.drop(1)
|
||||
//}
|
||||
private val urlRegex = """(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""".r
|
||||
|
||||
def addLinks(text: String) = urlRegex.replaceAllIn(text, m ⇒
|
||||
"<a href='%s'>%s</a>".format(m group 1, m group 1))
|
||||
|
||||
def showNumber(n: Int): String = (n > 0).fold("+" + n, n.toString)
|
||||
}
|
||||
|
|
|
@ -9,46 +9,46 @@ title = categ.name) {
|
|||
</ol>
|
||||
|
||||
<p class="description">@categ.desc</p>
|
||||
<div class="main topics">
|
||||
<div class="bar top clearfix">
|
||||
<div class="pagination">
|
||||
@forum.pagination(routes.ForumCateg.show(categ.slug, 1), topics)
|
||||
</div>
|
||||
<a href="@routes.ForumTopic.create(categ.slug)" class="action button">Create a new topic</a>
|
||||
<div class="bar top clearfix">
|
||||
<div class="pagination">
|
||||
@forum.pagination(routes.ForumCateg.show(categ.slug, 1), topics)
|
||||
</div>
|
||||
<a href="@routes.ForumTopic.create(categ.slug)" class="action button">Create a new topic</a>
|
||||
</div>
|
||||
|
||||
<table class="forum_topics_list">
|
||||
<thead>
|
||||
<tr class="thead">
|
||||
<th>Topics</th>
|
||||
<th class="right">Views</th>
|
||||
<th class="right">Replies</th>
|
||||
<th>Last Post</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@topics.currentPageResults.map { topic =>
|
||||
<tr>
|
||||
<td class="subject"><a href="@routes.ForumTopic.show(categ.slug, topic.slug)">@topic.name</a></td>
|
||||
<td class="right">@topic.views</td>
|
||||
<td class="right">@topic.nbPosts</td>
|
||||
<td class="last_post">
|
||||
@topic.lastPost.map { post =>
|
||||
<a href="@routes.ForumTopic.show(categ.slug, topic.slug)#@post.number">@showDate(post.createdAt)</a><br />by @userIdToUsername(post.userId)
|
||||
}
|
||||
</td>
|
||||
@if(isGranted(Permission.ModerateForum)) {
|
||||
<td><a class="delete" href="@routes.ForumTopic.delete(topic.id)">Delete</a></td>
|
||||
<table class="forum_topics_list">
|
||||
<thead>
|
||||
<tr class="thead">
|
||||
<th>Topics</th>
|
||||
<th class="right">Views</th>
|
||||
<th class="right">Replies</th>
|
||||
<th>Last Post</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@topics.currentPageResults.map { topic =>
|
||||
<tr>
|
||||
<td class="subject"><a href="@routes.ForumTopic.show(categ.slug, topic.slug)">@topic.name</a></td>
|
||||
<td class="right">@topic.views</td>
|
||||
<td class="right">@topic.nbPosts</td>
|
||||
<td class="last_post">
|
||||
@topic.lastPost.map { post =>
|
||||
<a href="@routes.ForumTopic.show(categ.slug, topic.slug)#@post.number">@showDate(post.createdAt)</a><br />by @userIdToUsername(post.userId)
|
||||
}
|
||||
</tr>
|
||||
</td>
|
||||
@if(isGranted(Permission.ModerateForum)) {
|
||||
<td><a class="delete" href="@routes.ForumTopic.delete(topic.id)">Delete</a></td>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="bar bottom clearfix">
|
||||
<div class="pagination">pagination</div>
|
||||
<a href="@routes.ForumTopic.create(categ.slug)" class="action button">Create a new topic</a>
|
||||
<div class="bar bottom clearfix">
|
||||
<div class="pagination">
|
||||
@forum.pagination(routes.ForumCateg.show(categ.slug, 1), topics)
|
||||
</div>
|
||||
<a href="@routes.ForumTopic.create(categ.slug)" class="action button">Create a new topic</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
46
app/views/forum/topic/show.scala.html
Normal file
46
app/views/forum/topic/show.scala.html
Normal file
|
@ -0,0 +1,46 @@
|
|||
@(categ: lila.forum.Categ, topic: lila.forum.Topic, posts: Paginator[lila.forum.Post])(implicit ctx: Context)
|
||||
|
||||
@forum.layout(
|
||||
title = topic.name) {
|
||||
<div class="topic">
|
||||
<ol class="crumbs">
|
||||
<li><a href="@routes.ForumCateg.index">Forum</a></li>
|
||||
<li><a href="@routes.ForumCateg.show(categ.slug)">@categ.name</a></li>
|
||||
<li><h1>@topic.name</h1></li>
|
||||
</ol>
|
||||
<div class="bar top clearfix">
|
||||
<div class="pagination">
|
||||
@forum.pagination(routes.ForumTopic.show(categ.slug, topic.slug, 1), posts)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="forum_posts_list">
|
||||
@for(post <- posts.currentPageResults) {
|
||||
<div class="post" id="@post.number">
|
||||
<div class="metas clearfix">
|
||||
@post.userId.map { userId =>
|
||||
<span class="authorName authenticated">@userIdLink(userId.some)</span>
|
||||
}.getOrElse {
|
||||
<span class="authorName">@post.author</span>
|
||||
}
|
||||
<span class="createdAt">@showDate(post.createdAt)</span>
|
||||
<a class="anchor" href="routes.ForumTopic.show(categ.slug, topic.slug, posts.page)">#@post.number</a>
|
||||
@if(isGranted(Permission.ModerateForum)) {
|
||||
<a class="delete" href="@routes.ForumPost.delete(post.id)">Delete</a>
|
||||
}
|
||||
</div>
|
||||
<p class="message">@autoLink(post.text)</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="bar bottom clearfix">
|
||||
<div class="pagination">
|
||||
@forum.pagination(routes.ForumTopic.show(categ.slug, topic.slug, 1), posts)
|
||||
</div>
|
||||
@if(posts.currentPage == posts.nbPages) {
|
||||
<a href="@routes.ForumPost.create(categ.slug, topic.slug)" class="action button">Reply to this topic</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
|
@ -92,8 +92,10 @@ GET /lobby/socket controllers.Lobby.socket
|
|||
GET /forum controllers.ForumCateg.index
|
||||
GET /forum/:slug controllers.ForumCateg.show(slug: String, page: Int ?= 1)
|
||||
GET /forum/:categSlug/new controllers.ForumTopic.create(categSlug: String)
|
||||
GET /forum/:categSlug/:slug controllers.ForumTopic.show(categSlug: String, slug: String)
|
||||
GET /forum/delete-topic/:id controllers.ForumTopic.delete(id: String)
|
||||
GET /forum/:categSlug/:slug controllers.ForumTopic.show(categSlug: String, slug: String, page: Int ?= 1)
|
||||
GET /forum/:categSlug/:slug/new controllers.ForumPost.create(categSlug: String, slug: String)
|
||||
GET /forum/delete/topic/:id controllers.ForumTopic.delete(id: String)
|
||||
GET /forum/delete/post/:id controllers.ForumPost.delete(id: String)
|
||||
|
||||
# Monitor
|
||||
GET /monitor controllers.Monitor.index
|
||||
|
|
|
@ -45,9 +45,9 @@ var topicIds = {};
|
|||
}
|
||||
nb ++;
|
||||
}
|
||||
coll.ensureIndex({categ: 1, slug: 1}, {unique: true});
|
||||
coll.ensureIndex({categ: 1});
|
||||
coll.ensureIndex({categ: 1, updatedAt: -1});
|
||||
coll.ensureIndex({categId: 1, slug: 1}, {unique: true});
|
||||
coll.ensureIndex({categId: 1});
|
||||
coll.ensureIndex({categId: 1, updatedAt: -1});
|
||||
print("Done topics: " + nb);
|
||||
})(db.forum_topic, db.f_topic);
|
||||
|
||||
|
@ -74,8 +74,8 @@ var topicIds = {};
|
|||
}
|
||||
nb ++;
|
||||
}
|
||||
coll.ensureIndex({topic: 1});
|
||||
coll.ensureIndex({topic: 1, createdAt: -1});
|
||||
coll.ensureIndex({topicId: 1});
|
||||
coll.ensureIndex({topicId: 1, createdAt: -1});
|
||||
print("Done posts: " + nb);
|
||||
})(db.forum_post, db.f_post);
|
||||
|
||||
|
|
Loading…
Reference in a new issue