user blog WIP
parent
af4dd08768
commit
c1f94ff736
|
@ -8,7 +8,7 @@ import lila.ublog.UblogPost
|
|||
|
||||
final class Ublog(env: Env) extends LilaController(env) {
|
||||
|
||||
import views.html.ublog.bits.{ url => urlOf }
|
||||
import views.html.ublog.bits.urlOf
|
||||
|
||||
def index(username: String, page: Int) = Open { implicit ctx =>
|
||||
OptionFuOk(env.user.repo named username) { user =>
|
||||
|
@ -18,11 +18,19 @@ final class Ublog(env: Env) extends LilaController(env) {
|
|||
}
|
||||
}
|
||||
|
||||
def drafts(username: String, page: Int) = Auth { implicit ctx => me =>
|
||||
if (!me.is(username)) Redirect(routes.Ublog.drafts(me.username)).fuccess
|
||||
else
|
||||
env.ublog.api.draftByUser(me, page) map { posts =>
|
||||
Ok(html.ublog.index.drafts(me, 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 {
|
||||
env.ublog.api.findByAuthor(UblogPost.Id(id), user) map {
|
||||
_ ?? { post =>
|
||||
if (!user.is(post.user) || slug != post.slug) Redirect(urlOf(post))
|
||||
if (slug != post.slug) Redirect(urlOf(post))
|
||||
else {
|
||||
val markup = scalatags.Text.all.raw(env.ublog.markup(post.markdown))
|
||||
Ok(html.ublog.post(user, post, markup))
|
||||
|
@ -37,14 +45,14 @@ final class Ublog(env: Env) extends LilaController(env) {
|
|||
else Ok(html.ublog.post.create(me, env.ublog.form.create)).fuccess
|
||||
}
|
||||
|
||||
def create(username: String) = AuthBody { implicit ctx => me =>
|
||||
def create(unusedUsername: String) = AuthBody { implicit ctx => me =>
|
||||
env.ublog.form.create
|
||||
.bindFromRequest()(ctx.body, formBinding)
|
||||
.fold(
|
||||
err => BadRequest(html.ublog.post.create(me, err)).fuccess,
|
||||
data =>
|
||||
env.ublog.api.create(data, me) map { post =>
|
||||
Redirect(urlOf(post))
|
||||
Redirect(urlOf(post)).flashSuccess
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -55,7 +63,20 @@ final class Ublog(env: Env) extends LilaController(env) {
|
|||
}
|
||||
}
|
||||
|
||||
def update(username: String, id: String) = AuthBody { implicit ctx => me =>
|
||||
???
|
||||
def update(unusedUsername: String, id: String) = AuthBody { implicit ctx => me =>
|
||||
env.ublog.api.findByAuthor(UblogPost.Id(id), me) flatMap {
|
||||
_ ?? { prev =>
|
||||
env.ublog.form
|
||||
.edit(prev)
|
||||
.bindFromRequest()(ctx.body, formBinding)
|
||||
.fold(
|
||||
err => BadRequest(html.ublog.post.edit(me, prev, err)).fuccess,
|
||||
data =>
|
||||
env.ublog.api.update(data, prev) map { post =>
|
||||
Redirect(urlOf(post)).flashSuccess
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package views.html.ublog
|
||||
|
||||
import controllers.routes
|
||||
import play.api.mvc.Call
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
|
@ -9,12 +10,13 @@ import lila.ublog.UblogPost
|
|||
|
||||
object bits {
|
||||
|
||||
def mini(post: UblogPost)(implicit ctx: Context) =
|
||||
a(cls := "ublog-post-mini", href := url(post))(
|
||||
def mini(post: UblogPost, makeUrl: UblogPost => Call = urlOf)(implicit ctx: Context) =
|
||||
a(cls := "ublog-post-mini", href := makeUrl(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)
|
||||
def urlOf(post: UblogPost) = routes.Ublog.post(usernameOrId(post.user), post.slug, post.id.value)
|
||||
|
||||
def editUrlOf(post: UblogPost) = routes.Ublog.edit(usernameOrId(post.user), post.id.value)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import lila.user.User
|
|||
|
||||
object index {
|
||||
|
||||
import views.html.ublog.bits
|
||||
|
||||
def apply(user: User, posts: Paginator[UblogPost])(implicit ctx: Context) =
|
||||
views.html.base.layout(
|
||||
moreCss = frag(cssTag("ublog")),
|
||||
|
@ -18,13 +20,37 @@ object index {
|
|||
) {
|
||||
main(cls := "box box-pad page ublog-index")(
|
||||
h1(s"${user.username} blog"),
|
||||
ctx.is(user) option a(href := routes.Ublog.form(user.username))("Write a new blog post"),
|
||||
ctx.is(user) option
|
||||
div(newPostLink, a(href := routes.Ublog.drafts(user.username))("My drafts")),
|
||||
div(cls := "ublog-index__posts")(
|
||||
div(cls := "infinite-scroll")(
|
||||
posts.currentPageResults map views.html.ublog.bits.mini,
|
||||
posts.currentPageResults map { bits.mini(_) },
|
||||
pagerNext(posts, np => s"${routes.Ublog.index(user.username, np).url}")
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def drafts(user: User, posts: Paginator[UblogPost])(implicit ctx: Context) =
|
||||
views.html.base.layout(
|
||||
moreCss = frag(cssTag("ublog")),
|
||||
title = s"${user.username} drafts"
|
||||
) {
|
||||
main(cls := "box box-pad page ublog-index")(
|
||||
h1(s"${user.username} drafts"),
|
||||
newPostLink,
|
||||
div(cls := "ublog-index__posts ublog-index__posts--drafts")(
|
||||
div(cls := "infinite-scroll")(
|
||||
posts.currentPageResults map {
|
||||
bits.mini(_, bits.editUrlOf)
|
||||
},
|
||||
pagerNext(posts, np => s"${routes.Ublog.drafts(user.username, np).url}")
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private def newPostLink(implicit ctx: Context) = ctx.me map { u =>
|
||||
a(href := routes.Ublog.form(u.username))("Write a new blog post")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import lila.user.User
|
|||
|
||||
object post {
|
||||
|
||||
import views.html.ublog.bits
|
||||
|
||||
def apply(user: User, post: UblogPost, markup: Frag)(implicit ctx: Context) =
|
||||
views.html.base.layout(
|
||||
moreCss = frag(cssTag("ublog")),
|
||||
|
@ -20,7 +22,8 @@ object post {
|
|||
main(cls := "box box-pad page ublog-post")(
|
||||
h1(cls := "ublog-post__title")(post.title),
|
||||
ctx.is(user) option div(
|
||||
a(href := routes.Ublog.edit(user.username, post.id.value))("Edit your blog post")
|
||||
standardFlash(),
|
||||
a(href := bits.editUrlOf(post))("Edit your blog post")
|
||||
),
|
||||
strong(cls := "ublog-post__intro")(post.intro),
|
||||
div(cls := "ublog-post__markup")(markup)
|
||||
|
@ -45,6 +48,9 @@ object post {
|
|||
) {
|
||||
main(cls := "box box-pad page ublog-post-form")(
|
||||
h1("Edit your blog post"),
|
||||
div(cls := "ublog-post-form__publish")(
|
||||
p(if (post.live) "This post is published" else "This is a draft")
|
||||
),
|
||||
innerForm(user, f, post.some)
|
||||
)
|
||||
}
|
||||
|
@ -66,8 +72,12 @@ object post {
|
|||
"Post body",
|
||||
help = markdownAvailable.some
|
||||
)(form3.textarea(_)(rows := 30)),
|
||||
form3.checkbox(
|
||||
form("live"),
|
||||
raw("Publish this post on your blog")
|
||||
),
|
||||
form3.actions(
|
||||
a(href := post.fold(routes.Ublog.index(user.username))(bits.url))(trans.cancel()),
|
||||
a(href := post.fold(routes.Ublog.index(user.username))(bits.urlOf))(trans.cancel()),
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
|
|
|
@ -59,6 +59,7 @@ GET /@/:username/tournaments/:path controllers.UserTournament.path(username:
|
|||
|
||||
# User blog
|
||||
GET /@/:username/blog controllers.Ublog.index(username: String, page: Int ?= 1)
|
||||
GET /@/:username/blog/drafts controllers.Ublog.drafts(username: String, page: Int ?= 1)
|
||||
GET /@/:username/blog/new controllers.Ublog.form(username: String)
|
||||
POST /@/:username/blog/new controllers.Ublog.create(username: String)
|
||||
GET /@/:username/blog/$id<\w{8}>/edit controllers.Ublog.edit(username: String, id: String)
|
||||
|
|
|
@ -14,12 +14,20 @@ final class UblogApi(coll: Coll)(implicit ec: ExecutionContext) {
|
|||
import UblogBsonHandlers._
|
||||
|
||||
def create(data: UblogForm.UblogPostData, user: User): Fu[UblogPost] = {
|
||||
val post = UblogPost.make(user, data.title, data.intro, data.markdown)
|
||||
val post = data.create(user)
|
||||
coll.insert.one(post) inject post
|
||||
}
|
||||
|
||||
def update(data: UblogForm.UblogPostData, prev: UblogPost): Fu[UblogPost] = {
|
||||
val post = data.update(prev)
|
||||
coll.update.one($id(prev.id), post) inject post
|
||||
}
|
||||
|
||||
def find(id: UblogPost.Id): Fu[Option[UblogPost]] = coll.byId[UblogPost](id.value)
|
||||
|
||||
def findByAuthor(id: UblogPost.Id, author: User): Fu[Option[UblogPost]] =
|
||||
coll.one[UblogPost]($id(id) ++ $doc("user" -> author.id))
|
||||
|
||||
def liveByUser(user: User, page: Int): Fu[Paginator[UblogPost]] =
|
||||
paginatorByUser(user, true, page)
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package lila.ublog
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import play.api.data._
|
||||
import play.api.data.Forms._
|
||||
|
||||
import lila.common.Form.{ cleanNonEmptyText, cleanText }
|
||||
import lila.user.User
|
||||
|
||||
final class UblogForm {
|
||||
|
||||
|
@ -12,15 +15,43 @@ final class UblogForm {
|
|||
mapping(
|
||||
"title" -> cleanNonEmptyText(minLength = 3, maxLength = 100),
|
||||
"intro" -> cleanNonEmptyText(minLength = 0, maxLength = 2_000),
|
||||
"markdown" -> cleanNonEmptyText(minLength = 0, maxLength = 100_000)
|
||||
"markdown" -> cleanNonEmptyText(minLength = 0, maxLength = 100_000),
|
||||
"live" -> boolean
|
||||
)(UblogPostData.apply)(UblogPostData.unapply)
|
||||
)
|
||||
|
||||
def edit(post: UblogPost) =
|
||||
create.fill(UblogPostData(title = post.title, intro = post.intro, markdown = post.markdown))
|
||||
create.fill(
|
||||
UblogPostData(title = post.title, intro = post.intro, markdown = post.markdown, live = post.live)
|
||||
)
|
||||
}
|
||||
|
||||
object UblogForm {
|
||||
|
||||
case class UblogPostData(title: String, intro: String, markdown: String)
|
||||
case class UblogPostData(title: String, intro: String, markdown: String, live: Boolean) {
|
||||
|
||||
def create(user: User) = {
|
||||
val now = DateTime.now
|
||||
UblogPost(
|
||||
_id = UblogPost.Id(lila.common.ThreadLocalRandom nextString 8),
|
||||
user = user.id,
|
||||
title = title,
|
||||
intro = intro,
|
||||
markdown = markdown,
|
||||
live = false,
|
||||
createdAt = now,
|
||||
updatedAt = now,
|
||||
liveAt = live option now
|
||||
)
|
||||
}
|
||||
|
||||
def update(prev: UblogPost) =
|
||||
prev.copy(
|
||||
title = title,
|
||||
intro = intro,
|
||||
markdown = markdown,
|
||||
live = live,
|
||||
liveAt = prev.liveAt orElse live.option(DateTime.now)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,18 +28,5 @@ case class UblogPost(
|
|||
|
||||
object UblogPost {
|
||||
|
||||
def make(user: User, title: String, intro: String, markdown: String) =
|
||||
UblogPost(
|
||||
_id = Id(lila.common.ThreadLocalRandom nextString 8),
|
||||
user = user.id,
|
||||
title = title,
|
||||
intro = intro,
|
||||
markdown = markdown,
|
||||
live = false,
|
||||
createdAt = DateTime.now,
|
||||
updatedAt = DateTime.now,
|
||||
liveAt = none
|
||||
)
|
||||
|
||||
case class Id(value: String) extends AnyVal with StringValue
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue