user blog WIP

pull/9705/head
Thibault Duplessis 2021-08-29 11:58:31 +02:00
parent fb8b6de80e
commit 8585905cc3
12 changed files with 166 additions and 4 deletions

View File

@ -156,6 +156,7 @@ final class LilaComponents(ctx: ApplicationLoader.Context) extends BuiltInCompon
lazy val dgt: DgtCtrl = wire[DgtCtrl]
lazy val storm: Storm = wire[Storm]
lazy val racer: Racer = wire[Racer]
lazy val ublog: Ublog = wire[Ublog]
lazy val bulkPairing: BulkPairing = wire[BulkPairing]
// eagerly wire up all controllers

View File

@ -84,6 +84,7 @@ final class Env(
val swiss: lila.swiss.Env,
val storm: lila.storm.Env,
val racer: lila.racer.Env,
val ublog: lila.ublog.Env,
val lilaCookie: lila.common.LilaCookie,
val net: NetConfig,
val controllerComponents: ControllerComponents
@ -280,6 +281,7 @@ final class EnvBoot(
lazy val swiss: lila.swiss.Env = wire[lila.swiss.Env]
lazy val storm: lila.storm.Env = wire[lila.storm.Env]
lazy val racer: lila.racer.Env = wire[lila.racer.Env]
lazy val ublog: lila.ublog.Env = wire[lila.ublog.Env]
lazy val api: lila.api.Env = wire[lila.api.Env]
lazy val lilaCookie = wire[lila.common.LilaCookie]

View File

@ -0,0 +1,32 @@
package controllers
import views._
import lila.api.Context
import lila.app._
import lila.ublog.UblogPost
final class Ublog(env: Env) extends LilaController(env) {
def index(username: String, page: Int) = Open { implicit ctx =>
OptionFuOk(env.user.repo named username) { user =>
env.ublog.api.liveByUser(user, page) map { posts =>
html.ublog.index(user, posts)
}
}
}
def post(username: String, slug: String, id: String) = Open { implicit ctx =>
OptionFuResult(env.user.repo named username) { user =>
env.ublog.api.find(UblogPost.Id(id)) map {
_ ?? { post =>
if (!user.is(post.user) || slug != post.slug) Redirect(html.ublog.post.url(post))
else {
val markup = scalatags.Text.all.raw(env.ublog.markup(post.markdown))
Ok(html.ublog.post(user, post, markup))
}
}
}
}
}
}

View File

@ -0,0 +1,29 @@
package views.html.ublog
import controllers.routes
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.common.paginator.Paginator
import lila.ublog.UblogPost
import lila.user.User
object index {
def apply(user: User, posts: Paginator[UblogPost])(implicit ctx: Context) =
views.html.base.layout(
moreCss = frag(cssTag("ublog")),
title = s"${user.username} blog"
) {
main(cls := "box box-pad page ublog-index")(
h1(s"${user.username} blog"),
div(cls := "ublog-index__posts")(
div(cls := "infinite-scroll")(
posts.currentPageResults map views.html.ublog.post.mini,
pagerNext(posts, np => s"${routes.Ublog.index(user.username, np).url}")
)
)
)
}
}

View File

@ -0,0 +1,32 @@
package views.html.ublog
import controllers.routes
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.ublog.UblogPost
import lila.user.User
object post {
def apply(user: User, post: UblogPost, markup: Frag)(implicit ctx: Context) =
views.html.base.layout(
moreCss = frag(cssTag("ublog")),
title = s"${user.username} blog • ${post.title}"
) {
main(cls := "box box-pad page ublog-post")(
h1(cls := "ublog-post__title")(post.title),
strong(cls := "ublog-post__intro")(post.intro),
div(cls := "ublog-post__markup")(markup)
)
}
def mini(post: UblogPost)(implicit ctx: Context) =
a(cls := "ublog-post-mini", href := url(post))(
h2(cls := "ublog-post-mini__title", post.title),
strong(cls := "ublog-post-mini__intro", post.intro)
)
def url(post: UblogPost) = routes.Ublog.post(usernameOrId(post.user), post.slug, post.id.value)
}

View File

@ -57,6 +57,10 @@ GET /insights/:username/:metric/:dimension/*filters controllers.Insight.path(u
# User subpages
GET /@/:username/tournaments/:path controllers.UserTournament.path(username: String, path: String, page: Int ?= 1)
# User blog
GET /@/:username/blog controllers.Ublog.index(username: String, page: Int ?= 1)
GET /@/:username/blog/:slug/:id controllers.Ublog.post(username: String, slug: String, id: String)
# User
GET /api/stream/:username/mod controllers.User.mod(username: String)
POST /@/:username/note controllers.User.writeNote(username: String)

View File

@ -14,4 +14,6 @@ final class Env(
private val postColl = db(CollName("ublog_post"))
val api = wire[UblogApi]
val markup = wire[UblogMarkup]
}

View File

@ -1,9 +1,14 @@
package lila.ublog
import lila.db.dsl._
import lila.user.User
import reactivemongo.api._
import scala.concurrent.ExecutionContext
import lila.common.config.MaxPerPage
import lila.common.paginator.Paginator
import lila.db.dsl._
import lila.db.paginator.Adapter
import lila.user.User
final class UblogApi(coll: Coll)(implicit ec: ExecutionContext) {
import UblogBsonHandlers._
@ -12,4 +17,25 @@ final class UblogApi(coll: Coll)(implicit ec: ExecutionContext) {
val post = UblogPost.make(user, data.title, data.intro, data.markdown)
coll.insert.one(post) inject post
}
def find(id: UblogPost.Id): Fu[Option[UblogPost]] = coll.byId[UblogPost](id.value)
def liveByUser(user: User, page: Int): Fu[Paginator[UblogPost]] =
paginatorByUser(user, true, page)
def draftByUser(user: User, page: Int): Fu[Paginator[UblogPost]] =
paginatorByUser(user, false, page)
private def paginatorByUser(user: User, live: Boolean, page: Int): Fu[Paginator[UblogPost]] =
Paginator(
adapter = new Adapter[UblogPost](
collection = coll,
selector = $doc("user" -> user.id, "live" -> live),
projection = none,
sort = $doc("liveAt" -> -1, "createdAt" -> -1),
readPreference = ReadPreference.secondaryPreferred
),
currentPage = page,
maxPerPage = MaxPerPage(15)
)
}

View File

@ -0,0 +1,23 @@
package lila.ublog
import com.github.blemale.scaffeine.LoadingCache
import scala.concurrent.duration._
final class UblogMarkup {
private val renderer =
new lila.common.Markdown(
autoLink = true,
list = true,
strikeThrough = true,
header = true
)
private val cache: LoadingCache[String, String] = lila.memo.CacheApi.scaffeineNoScheduler
.expireAfterAccess(20 minutes)
.maximumSize(512)
.build(renderer.apply)
def apply(text: String): String = cache.get(text)
}

View File

@ -10,10 +10,14 @@ case class UblogPost(
title: String,
intro: String,
markdown: String,
live: Boolean,
createdAt: DateTime,
updatedAt: DateTime
updatedAt: DateTime,
liveAt: Option[DateTime]
) {
def id = _id
lazy val slug = {
val s = lila.common.String slugify title
if (s.isEmpty) "-" else s
@ -29,8 +33,10 @@ object UblogPost {
title = title,
intro = intro,
markdown = markdown,
live = false,
createdAt = DateTime.now,
updatedAt = DateTime.now
updatedAt = DateTime.now,
liveAt = none
)
case class Id(value: String) extends AnyVal with StringValue

View File

@ -0,0 +1,2 @@
@import '../../../common/css/plugin';
@import '../ublog/ublog';

View File

@ -0,0 +1,3 @@
.ublog-index {
background: red;
}