Skip to content

Commit

Permalink
moderators can relocate forum topics
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Jun 24, 2024
1 parent e42f39c commit e6b20c9
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 22 deletions.
15 changes: 15 additions & 0 deletions app/controllers/ForumPost.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ final class ForumPost(env: Env) extends LilaController(env) with ForumController
NoContent
}

def relocate(id: ForumPostId) = SecureBody(_.ModerateForum) { ctx ?=> me ?=>
Found(postApi.getPost(id).flatMapz(postApi.viewOf)): post =>
forms.relocateTo
.bindFromRequest()
.value
.so: to =>
env.forum.topicApi
.relocate(post.topic.id, to)
.inject:
post.post.userId.foreach: op =>
val newUrl = routes.ForumTopic.show(to, post.topic.slug, 1).url
env.msg.api.systemPost(op, MsgPreset.forumRelocation(post.topic.name, newUrl))
Redirect(routes.ForumCateg.show(to)).flashSuccess
}

def react(categId: ForumCategId, id: ForumPostId, reaction: String, v: Boolean) = Auth { _ ?=> me ?=>
CategGrantWrite(categId):
FoundSnip(postApi.react(categId, id, reaction, v)): post =>
Expand Down
15 changes: 8 additions & 7 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -598,15 +598,16 @@ GET /kaladin controllers.Irwin.kaladin
# Forum
GET /forum controllers.ForumCateg.index
GET /forum/search controllers.ForumPost.search(text ?= "", page: Int ?= 1)
GET /forum/:categId controllers.ForumCateg.show(categId: ForumCategId, page: Int ?= 1)
GET /forum/:categId/form controllers.ForumTopic.form(categId: ForumCategId)
POST /forum/:categId/new controllers.ForumTopic.create(categId: ForumCategId)
GET /forum/:categId controllers.ForumCateg.show(categId: ForumCategId, page: Int ?= 1)
GET /forum/:categId/form controllers.ForumTopic.form(categId: ForumCategId)
POST /forum/:categId/new controllers.ForumTopic.create(categId: ForumCategId)
GET /forum/participants/:topicId controllers.ForumTopic.participants(topicId: ForumTopicId)
GET /forum/:categId/:slug controllers.ForumTopic.show(categId: ForumCategId, slug, page: Int ?= 1)
POST /forum/:categId/:slug/close controllers.ForumTopic.close(categId: ForumCategId, slug)
POST /forum/:categId/:slug/sticky controllers.ForumTopic.sticky(categId: ForumCategId, slug)
POST /forum/:categId/:slug/new controllers.ForumPost.create(categId: ForumCategId, slug, page: Int ?= 1)
GET /forum/:categId/:slug controllers.ForumTopic.show(categId: ForumCategId, slug, page: Int ?= 1)
POST /forum/:categId/:slug/close controllers.ForumTopic.close(categId: ForumCategId, slug)
POST /forum/:categId/:slug/sticky controllers.ForumTopic.sticky(categId: ForumCategId, slug)
POST /forum/:categId/:slug/new controllers.ForumPost.create(categId: ForumCategId, slug, page: Int ?= 1)
POST /forum/delete/:id controllers.ForumPost.delete(id: ForumPostId)
POST /forum/relocate/:id controllers.ForumPost.relocate(id: ForumPostId)
POST /forum/:categId/react/:id/:reaction/:v controllers.ForumPost.react(categId: ForumCategId, id: ForumPostId, reaction, v: Boolean)
POST /forum/post/:id controllers.ForumPost.edit(id: ForumPostId)
GET /forum/redirect/post/:id controllers.ForumPost.redirect(id: ForumPostId)
Expand Down
5 changes: 4 additions & 1 deletion modules/forum/src/main/ForumForm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package lila.forum
import play.api.data.*
import play.api.data.Forms.*

import lila.common.Form.cleanText
import lila.common.Form.{ cleanText, into }
import lila.common.Form.given

final private[forum] class ForumForm(
Expand Down Expand Up @@ -42,6 +42,9 @@ final private[forum] class ForumForm(
val deleteWithReason = Form:
single("reason" -> optional(nonEmptyText))

val relocateTo = Form:
single("categ" -> nonEmptyText.into[ForumCategId])

private def userTextMapping(inOwnTeam: Boolean, previousText: Option[String] = None)(using me: Me) =
cleanText(minLength = 3, 10_000)
.verifying(
Expand Down
12 changes: 7 additions & 5 deletions modules/forum/src/main/ForumTopicApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ final private class ForumTopicApi(
.flatMapz: topic =>
show(categId, slug, topic.lastPage(config.postMaxPerPage))

def show(
categId: ForumCategId,
slug: String,
page: Int
)(using
def show(categId: ForumCategId, slug: String, page: Int)(using
NetDomain
)(using me: Option[Me]): Fu[Option[(ForumCateg, ForumTopic, Paginator[ForumPost.WithFrag])]] =
for
Expand Down Expand Up @@ -219,3 +215,9 @@ final private class ForumTopicApi(
_ <- categRepo.coll.update
.one($id(cat.id), cat.withoutTopic(topic, lastPostId, lastPostIdTroll))
yield ()

def relocate(topic: ForumTopicId, to: ForumCategId)(using Me): Funit =
for
_ <- topicRepo.coll.update.one($id(topic), $set("categId" -> to))
_ <- postRepo.coll.update.one($doc("topicId" -> topic), $set("categId" -> to))
yield ()
6 changes: 1 addition & 5 deletions modules/forum/src/main/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ case class TopicView(
def name = topic.name
def createdAt = topic.createdAt

case class PostView(
post: ForumPost,
topic: ForumTopic,
categ: ForumCateg
):
case class PostView(post: ForumPost, topic: ForumTopic, categ: ForumCateg):
def show = post.showUserIdOrAuthor + " @ " + topic.name + " - " + post.text.take(80)
def logFormatted = "%s / %s#%s / %s".format(categ.name, topic.name, post.number, post.text)

Expand Down
8 changes: 8 additions & 0 deletions modules/forum/src/main/ui/PostUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ final class PostUi(helpers: Helpers, bits: ForumBits):
).some
else
frag(
(canModCateg && post.number == 1).option:
a(
cls := "mod mod-relocate button button-empty",
href := routes.ForumPost.relocate(post.id),
dataIcon := Icon.Forward,
title := "Relocate"
)
,
if canModCateg || topic.isUblogAuthor(me) then
a(
cls := "mod delete button button-empty",
Expand Down
28 changes: 27 additions & 1 deletion modules/forum/src/main/ui/TopicUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ final class TopicUi(helpers: Helpers, bits: ForumBits, postUi: PostUi)(
)
)
),
(canModCateg || ctx.me.exists(topic.isAuthor)).option(deleteModal)
(canModCateg || ctx.me.exists(topic.isAuthor)).option(deleteModal),
canModCateg.option(relocateModal(categ))
)
),
formWithCaptcha.map: (form, captcha) =>
Expand Down Expand Up @@ -253,3 +254,28 @@ final class TopicUi(helpers: Helpers, bits: ForumBits, postUi: PostUi)(
)
)
)

private val relocateTo = List(
"general-chess-discussion" -> "General Chess Discussion",
"lichess-feedback" -> "Lichess Feedback",
"game-analysis" -> "Game Analysis",
"off-topic-discussion" -> "Off-Topic Discussion"
)

private def relocateModal(from: lila.forum.ForumCateg) =
div(cls := "forum-relocate-modal none")(
p("Move the entire thread to another forum"),
st.form(method := "post", cls := "form3")(
st.select(
name := "categ",
cls := "form-control"
)(
relocateTo.collect:
case (slug, name) if slug != from.id.value => st.option(value := slug)(name)
),
form3.actions(
button(cls := "cancel button button-empty", tpe := "button")("Cancel"),
form3.submit(frag("Relocate the thread"))(cls := "button-red")
)
)
)
11 changes: 8 additions & 3 deletions modules/msg/src/main/MsgPreset.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ object MsgPreset:

import lila.core.msg.{ MsgPreset as Msg }

private val baseUrl = "https://lichess.org"

def maxFollow(username: UserName, max: Int) =
Msg(
name = "Follow limit reached!",
text = s"""Sorry, you can't follow more than $max players on Lichess.
To follow new players, you must first unfollow some on https://lichess.org/@/$username/following.
To follow new players, you must first unfollow some on $baseUrl/@/$username/following.

Thank you for your understanding."""
)

def forumRelocation(title: String, newUrl: String) =
s"""A moderator has moved your post "$title" to a different subforum. You can find it here: $baseUrl$newUrl."""

object forumDeletion:

val presets = List(
Expand All @@ -30,12 +35,12 @@ Thank you for your understanding."""

def byModerator = compose("A moderator")

def byTeamLeader(forumId: ForumCategId) = compose(s"A team leader of https://lichess.org/forum/$forumId")
def byTeamLeader(forumId: ForumCategId) = compose(s"A team leader of $baseUrl/forum/$forumId")

def byBlogAuthor(user: UserName) = compose(by = s"The community blog author $user")

private def compose(by: String)(reason: String, forumPost: String) =
s"""$by deleted the following of your posts for this reason: $reason. Please read Lichess' Forum-Etiquette: https://lichess.org/page/forum-etiquette
s"""$by deleted the following of your posts for this reason: $reason. Please read Lichess' Forum-Etiquette: $baseUrl/page/forum-etiquette
----
$forumPost
"""
Expand Down
14 changes: 14 additions & 0 deletions ui/bits/src/bits.forum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ site.load.then(() => {
});
return false;
})
.on('click', 'a.mod-relocate', function (this: HTMLAnchorElement) {
const link = this;
site.dialog
.dom({
cash: $('.forum-relocate-modal'),
attrs: { view: { action: link.href } },
})
.then(dlg => {
$(dlg.view).find('form').attr('action', link.href);
$(dlg.view).find('form button.cancel').on('click', dlg.close);
dlg.showModal();
});
return false;
})
.on('click', 'form.unsub button', function (this: HTMLButtonElement) {
const form = $(this).parent().toggleClass('on off')[0] as HTMLFormElement;
xhr.text(`${form.action}?unsub=${this.dataset.unsub}`, { method: 'post' });
Expand Down

0 comments on commit e6b20c9

Please sign in to comment.