2021-08-29 03:58:31 -06:00
|
|
|
package controllers
|
|
|
|
|
2021-09-01 01:58:51 -06:00
|
|
|
import scala.concurrent.duration._
|
2021-08-29 03:58:31 -06:00
|
|
|
import views._
|
|
|
|
|
|
|
|
import lila.api.Context
|
|
|
|
import lila.app._
|
2021-09-07 04:58:35 -06:00
|
|
|
import lila.ublog.{ UblogBlog, UblogPost }
|
2021-08-31 05:10:05 -06:00
|
|
|
import lila.user.{ User => UserModel }
|
2021-09-09 13:54:42 -06:00
|
|
|
import play.api.i18n.Lang
|
|
|
|
import lila.i18n.LangList
|
2021-09-13 01:27:47 -06:00
|
|
|
import lila.report.Suspect
|
2021-08-29 03:58:31 -06:00
|
|
|
|
|
|
|
final class Ublog(env: Env) extends LilaController(env) {
|
|
|
|
|
2021-09-07 06:16:07 -06:00
|
|
|
import views.html.ublog.post.{ editUrlOfPost, urlOfPost }
|
|
|
|
import views.html.ublog.blog.{ urlOfBlog }
|
2021-08-31 05:10:05 -06:00
|
|
|
import lila.common.paginator.Paginator.zero
|
2021-08-29 04:36:52 -06:00
|
|
|
|
2021-08-29 03:58:31 -06:00
|
|
|
def index(username: String, page: Int) = Open { implicit ctx =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
2021-09-07 04:58:35 -06:00
|
|
|
OptionFuResult(env.user.repo named username) { user =>
|
|
|
|
env.ublog.api.getUserBlog(user) flatMap { blog =>
|
|
|
|
(canViewBlogOf(user, blog) ?? env.ublog.paginator.byUser(user, true, page)) map { posts =>
|
2021-09-07 06:16:07 -06:00
|
|
|
Ok(html.ublog.blog(user, blog, posts))
|
2021-09-07 04:58:35 -06:00
|
|
|
}
|
2021-09-02 03:55:50 -06:00
|
|
|
}
|
2021-08-29 03:58:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 02:05:36 -06:00
|
|
|
def drafts(username: String, page: Int) = Auth { implicit ctx => me =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
|
|
|
if (!me.is(username)) Redirect(routes.Ublog.drafts(me.username)).fuccess
|
|
|
|
else
|
2021-09-05 14:07:21 -06:00
|
|
|
env.ublog.paginator.byUser(me, false, page) map { posts =>
|
2021-09-02 03:55:50 -06:00
|
|
|
Ok(html.ublog.index.drafts(me, posts))
|
|
|
|
}
|
|
|
|
}
|
2021-08-30 02:05:36 -06:00
|
|
|
}
|
|
|
|
|
2021-08-29 03:58:31 -06:00
|
|
|
def post(username: String, slug: String, id: String) = Open { implicit ctx =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
|
|
|
OptionFuResult(env.user.repo named username) { user =>
|
2021-09-07 04:58:35 -06:00
|
|
|
env.ublog.api.getUserBlog(user) flatMap { blog =>
|
|
|
|
env.ublog.api.findByIdAndBlog(UblogPost.Id(id), blog.id) flatMap {
|
2021-09-11 04:21:23 -06:00
|
|
|
_.filter(canViewPost(user, blog)).fold(notFound) { post =>
|
2021-09-07 06:16:07 -06:00
|
|
|
if (slug != post.slug) Redirect(urlOfPost(post)).fuccess
|
2021-09-07 04:58:35 -06:00
|
|
|
else {
|
|
|
|
env.ublog.api.otherPosts(UblogBlog.Id.User(user.id), post) zip
|
2021-09-11 10:34:40 -06:00
|
|
|
ctx.me.??(env.ublog.rank.liked(post)) zip
|
|
|
|
ctx.userId.??(env.relation.api.fetchFollows(_, user.id)) map {
|
|
|
|
case ((others, liked), followed) =>
|
2021-09-28 06:06:45 -06:00
|
|
|
val viewedPost = env.ublog.viewCounter(post, ctx.ip)
|
|
|
|
val markup = scalatags.Text.all.raw(env.ublog.markup(post))
|
|
|
|
Ok(html.ublog.post(user, blog, viewedPost, markup, others, liked, followed))
|
2021-09-07 04:58:35 -06:00
|
|
|
}
|
|
|
|
}
|
2021-09-02 03:55:50 -06:00
|
|
|
}
|
2021-08-29 03:58:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-29 04:17:48 -06:00
|
|
|
|
|
|
|
def form(username: String) = Auth { implicit ctx => me =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
2021-09-05 06:10:31 -06:00
|
|
|
if (env.ublog.api.canBlog(me)) {
|
|
|
|
if (!me.is(username)) Redirect(routes.Ublog.form(me.username)).fuccess
|
|
|
|
else
|
|
|
|
env.ublog.form.anyCaptcha map { captcha =>
|
|
|
|
Ok(html.ublog.form.create(me, env.ublog.form.create, captcha))
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
Unauthorized(
|
|
|
|
html.site.message.notYet(
|
|
|
|
"Please play a few games and wait 2 days before you can create blog posts."
|
|
|
|
)
|
|
|
|
).fuccess
|
2021-09-02 03:55:50 -06:00
|
|
|
}
|
2021-08-29 04:17:48 -06:00
|
|
|
}
|
|
|
|
|
2021-09-01 01:58:51 -06:00
|
|
|
private val CreateLimitPerUser = new lila.memo.RateLimit[UserModel.ID](
|
2021-09-11 04:04:24 -06:00
|
|
|
credits = 5 * 3,
|
2021-09-01 01:58:51 -06:00
|
|
|
duration = 24.hour,
|
|
|
|
key = "ublog.create.user"
|
|
|
|
)
|
|
|
|
|
2021-09-06 12:00:07 -06:00
|
|
|
def create = AuthBody { implicit ctx => me =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
|
|
|
env.ublog.form.create
|
|
|
|
.bindFromRequest()(ctx.body, formBinding)
|
|
|
|
.fold(
|
2021-09-05 06:10:31 -06:00
|
|
|
err =>
|
|
|
|
env.ublog.form.anyCaptcha map { captcha =>
|
|
|
|
BadRequest(html.ublog.form.create(me, err, captcha))
|
|
|
|
},
|
2021-09-02 03:55:50 -06:00
|
|
|
data =>
|
|
|
|
CreateLimitPerUser(me.id, cost = if (me.isVerified) 1 else 3) {
|
|
|
|
env.ublog.api.create(data, me) map { post =>
|
2021-09-05 08:33:44 -06:00
|
|
|
lila.mon.ublog.create(me.id).increment()
|
2021-09-07 06:16:07 -06:00
|
|
|
Redirect(editUrlOfPost(post)).flashSuccess
|
2021-09-02 03:55:50 -06:00
|
|
|
}
|
|
|
|
}(rateLimitedFu)
|
|
|
|
)
|
|
|
|
}
|
2021-08-29 04:36:52 -06:00
|
|
|
}
|
|
|
|
|
2021-09-06 12:00:07 -06:00
|
|
|
def edit(id: String) = AuthBody { implicit ctx => me =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
2021-09-12 04:06:55 -06:00
|
|
|
OptionOk(env.ublog.api.findByUserBlogOrAdmin(UblogPost.Id(id), me)) { post =>
|
|
|
|
html.ublog.form.edit(post, env.ublog.form.edit(post))
|
2021-09-02 03:55:50 -06:00
|
|
|
}
|
2021-08-29 04:36:52 -06:00
|
|
|
}
|
2021-08-29 04:17:48 -06:00
|
|
|
}
|
|
|
|
|
2021-09-06 12:00:07 -06:00
|
|
|
def update(id: String) = AuthBody { implicit ctx => me =>
|
2021-09-02 03:55:50 -06:00
|
|
|
NotForKids {
|
2021-09-11 12:25:10 -06:00
|
|
|
env.ublog.api.findByUserBlogOrAdmin(UblogPost.Id(id), me) flatMap {
|
2021-09-02 03:55:50 -06:00
|
|
|
_ ?? { prev =>
|
|
|
|
env.ublog.form
|
|
|
|
.edit(prev)
|
|
|
|
.bindFromRequest()(ctx.body, formBinding)
|
|
|
|
.fold(
|
2021-09-12 04:06:55 -06:00
|
|
|
err => BadRequest(html.ublog.form.edit(prev, err)).fuccess,
|
2021-09-02 03:55:50 -06:00
|
|
|
data =>
|
2021-09-13 01:27:47 -06:00
|
|
|
env.ublog.api.update(data, prev, me) flatMap { post =>
|
|
|
|
logModAction(post, "edit") inject
|
|
|
|
Redirect(urlOfPost(post)).flashSuccess
|
2021-09-02 03:55:50 -06:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2021-08-30 02:05:36 -06:00
|
|
|
}
|
|
|
|
}
|
2021-08-29 04:17:48 -06:00
|
|
|
}
|
2021-08-30 04:32:06 -06:00
|
|
|
|
2021-09-06 12:00:07 -06:00
|
|
|
def delete(id: String) = AuthBody { implicit ctx => me =>
|
2021-09-11 12:25:10 -06:00
|
|
|
env.ublog.api.findByUserBlogOrAdmin(UblogPost.Id(id), me) flatMap {
|
2021-09-01 14:11:24 -06:00
|
|
|
_ ?? { post =>
|
2021-09-13 01:27:47 -06:00
|
|
|
env.ublog.api.delete(post) >>
|
|
|
|
logModAction(post, "delete") inject
|
|
|
|
Redirect(urlOfBlog(post.blog)).flashSuccess
|
2021-09-01 14:11:24 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-13 01:27:47 -06:00
|
|
|
private def logModAction(post: UblogPost, action: String)(implicit ctx: Context): Funit =
|
|
|
|
isGranted(_.ModerateBlog) ?? ctx.me ?? { me =>
|
|
|
|
!me.is(post.created.by) ?? {
|
|
|
|
env.user.repo.byId(post.created.by) flatMap {
|
|
|
|
_ ?? { user =>
|
|
|
|
env.mod.logApi.blogPostEdit(lila.report.Mod(me), Suspect(user), post.id.value, post.title, action)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-06 12:00:07 -06:00
|
|
|
def like(id: String, v: Boolean) = Auth { implicit ctx => me =>
|
2021-09-25 03:20:03 -06:00
|
|
|
NoBot {
|
|
|
|
NotForKids {
|
|
|
|
env.ublog.rank.like(UblogPost.Id(id), me, v) map { likes =>
|
|
|
|
Ok(likes.value)
|
|
|
|
}
|
2021-09-06 11:53:24 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-13 13:27:19 -06:00
|
|
|
def redirect(id: String) = Open { implicit ctx =>
|
|
|
|
env.ublog.api.postPreview(UblogPost.Id(id)) flatMap {
|
|
|
|
_.fold(notFound) { post =>
|
|
|
|
Redirect(urlOfPost(post)).fuccess
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 06:16:07 -06:00
|
|
|
def setTier(blogId: String) = SecureBody(_.ModerateBlog) { implicit ctx => me =>
|
|
|
|
UblogBlog.Id(blogId).??(env.ublog.api.getBlog) flatMap {
|
|
|
|
_ ?? { blog =>
|
|
|
|
implicit val body = ctx.body
|
|
|
|
lila.ublog.UblogForm.tier
|
|
|
|
.bindFromRequest()
|
|
|
|
.fold(
|
|
|
|
err => Redirect(urlOfBlog(blog)).flashFailure.fuccess,
|
|
|
|
tier =>
|
2021-09-13 01:27:47 -06:00
|
|
|
for {
|
|
|
|
user <- env.user.repo.byId(blog.userId) orFail "Missing blog user!" dmap Suspect
|
|
|
|
_ <- env.ublog.api.setTier(blog.id, tier)
|
2021-09-16 13:53:23 -06:00
|
|
|
_ <- env.ublog.rank.recomputeRankOfAllPostsOfBlog(blog.id)
|
2021-09-13 01:27:47 -06:00
|
|
|
_ <- env.mod.logApi
|
|
|
|
.blogTier(lila.report.Mod(me.user), user, blog.id.full, UblogBlog.Tier.name(tier))
|
|
|
|
} yield Redirect(urlOfBlog(blog)).flashSuccess
|
2021-09-07 06:16:07 -06:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-01 01:58:51 -06:00
|
|
|
private val ImageRateLimitPerIp = lila.memo.RateLimit.composite[lila.common.IpAddress](
|
|
|
|
key = "ublog.image.ip"
|
|
|
|
)(
|
|
|
|
("fast", 10, 2.minutes),
|
|
|
|
("slow", 60, 1.day)
|
|
|
|
)
|
|
|
|
|
2021-09-01 10:42:22 -06:00
|
|
|
def image(id: String) =
|
2021-08-30 10:57:03 -06:00
|
|
|
AuthBody(parse.multipartFormData) { implicit ctx => me =>
|
2021-09-11 12:25:10 -06:00
|
|
|
env.ublog.api.findByUserBlogOrAdmin(UblogPost.Id(id), me) flatMap {
|
2021-08-30 04:32:06 -06:00
|
|
|
_ ?? { post =>
|
|
|
|
ctx.body.body.file("image") match {
|
|
|
|
case Some(image) =>
|
2021-09-07 11:43:17 -06:00
|
|
|
ImageRateLimitPerIp(ctx.ip) {
|
2021-09-05 03:09:32 -06:00
|
|
|
env.ublog.api.uploadImage(me, post, image) map { newPost =>
|
2021-09-01 01:58:51 -06:00
|
|
|
Ok(html.ublog.form.formImage(newPost))
|
|
|
|
} recover { case e: Exception =>
|
|
|
|
BadRequest(e.getMessage)
|
|
|
|
}
|
|
|
|
}(rateLimitedFu)
|
2021-09-12 04:24:25 -06:00
|
|
|
case None =>
|
2021-09-13 01:27:47 -06:00
|
|
|
env.ublog.api.deleteImage(post) flatMap { newPost =>
|
|
|
|
logModAction(newPost, "delete image") inject
|
|
|
|
Ok(html.ublog.form.formImage(newPost))
|
2021-09-12 04:24:25 -06:00
|
|
|
}
|
2021-08-30 04:32:06 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-31 05:10:05 -06:00
|
|
|
|
2021-09-13 06:27:42 -06:00
|
|
|
def friends(page: Int) = Auth { implicit ctx => me =>
|
2021-09-05 14:07:21 -06:00
|
|
|
NotForKids {
|
|
|
|
Reasonable(page, 10) {
|
2021-09-13 06:27:42 -06:00
|
|
|
env.ublog.paginator.liveByFollowed(me, page) map { posts =>
|
|
|
|
Ok(html.ublog.index.friends(posts))
|
2021-09-05 14:07:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-09 13:54:42 -06:00
|
|
|
def community(code: String, page: Int) = Open { implicit ctx =>
|
2021-09-06 12:54:07 -06:00
|
|
|
NotForKids {
|
2021-09-09 13:54:42 -06:00
|
|
|
val l = Lang.get(code).filter(LangList.popularNoRegion.contains)
|
2021-09-18 05:04:45 -06:00
|
|
|
Reasonable(page, 8) {
|
2021-09-09 13:54:42 -06:00
|
|
|
env.ublog.paginator.liveByCommunity(l, page) map { posts =>
|
|
|
|
Ok(html.ublog.index.community(l, posts))
|
2021-09-09 12:20:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 05:44:39 -06:00
|
|
|
def liked(page: Int) = Auth { implicit ctx => me =>
|
|
|
|
NotForKids {
|
|
|
|
Reasonable(page, 15) {
|
|
|
|
ctx.me ?? { me =>
|
|
|
|
env.ublog.paginator.liveByLiked(me, page) map { posts =>
|
|
|
|
Ok(html.ublog.index.liked(posts))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-09 08:00:05 -06:00
|
|
|
def topics = Open { implicit ctx =>
|
|
|
|
NotForKids {
|
|
|
|
env.ublog.topic.withPosts map { topics =>
|
|
|
|
Ok(html.ublog.index.topics(topics))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 14:57:04 -06:00
|
|
|
def topic(str: String, page: Int) = Open { implicit ctx =>
|
|
|
|
NotForKids {
|
2021-09-18 05:04:45 -06:00
|
|
|
Reasonable(page, 5) {
|
2021-09-09 08:00:05 -06:00
|
|
|
lila.ublog.UblogTopic.fromUrl(str) ?? { top =>
|
2021-09-08 14:57:04 -06:00
|
|
|
env.ublog.paginator.liveByTopic(top, page) map { posts =>
|
|
|
|
Ok(html.ublog.index.topic(top, posts))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-10 12:05:55 -06:00
|
|
|
def userAtom(username: String) = Action.async { implicit req =>
|
2021-09-07 09:16:24 -06:00
|
|
|
env.user.repo.enabledNamed(username) flatMap {
|
|
|
|
case None => NotFound.fuccess
|
|
|
|
case Some(user) =>
|
2021-09-10 12:05:55 -06:00
|
|
|
implicit val lang = reqLang
|
2021-09-07 09:16:24 -06:00
|
|
|
env.ublog.api.getUserBlog(user) flatMap { blog =>
|
|
|
|
(isBlogVisible(user, blog) ?? env.ublog.paginator.byUser(user, true, 1)) map { posts =>
|
|
|
|
Ok(html.ublog.atom(user, blog, posts.currentPageResults)) as XML
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private def isBlogVisible(user: UserModel, blog: UblogBlog) = user.enabled && blog.visible
|
|
|
|
|
2021-09-07 04:58:35 -06:00
|
|
|
private def canViewBlogOf(user: UserModel, blog: UblogBlog)(implicit ctx: Context) =
|
2021-09-07 09:16:24 -06:00
|
|
|
ctx.is(user) || isGranted(_.ModerateBlog) || isBlogVisible(user, blog)
|
2021-09-01 11:21:01 -06:00
|
|
|
|
2021-09-07 04:58:35 -06:00
|
|
|
private def canViewPost(user: UserModel, blog: UblogBlog)(post: UblogPost)(implicit ctx: Context) =
|
|
|
|
canViewBlogOf(user, blog) && (ctx.is(user) || post.live)
|
2021-08-29 03:58:31 -06:00
|
|
|
}
|