more streamer approval process

This commit is contained in:
Thibault Duplessis 2017-12-31 10:05:15 -05:00
parent 6c61ad850f
commit 2f844e6f8a
10 changed files with 68 additions and 41 deletions

View file

@ -25,10 +25,11 @@ object Report extends LilaController {
private def renderList(room: String)(implicit ctx: Context) =
api.openAndRecentWithFilter(20, Room(room)) zip
api.countOpenByRooms flatMap {
case reports ~ counts =>
api.countOpenByRooms zip
Env.streamer.api.approval.countRequests flatMap {
case reports ~ counts ~ streamers =>
(Env.user.lightUserApi preloadMany reports.flatMap(_.report.userIds)) inject
Ok(html.report.list(reports, room, counts))
Ok(html.report.list(reports, room, counts, streamers))
}
def inquiry(id: String) = Secure(_.SeeReport) { implicit ctx => me =>

View file

@ -12,8 +12,9 @@ object Streamer extends LilaController {
private def api = Env.streamer.api
def index(page: Int) = Open { implicit ctx =>
Env.streamer.pager(page) map { pager =>
Ok(html.streamer.index(pager))
val requests = getBool("requests") && isGranted(_.Streamers)
Env.streamer.pager(page, requests) map { pager =>
Ok(html.streamer.index(pager, requests))
}
}

View file

@ -36,5 +36,5 @@ trait FormHelper { self: I18nHelper =>
Html(s"""<div class="form-group has-error">${errMsg(msg)}</div>""")
}
val booleanChoices = Seq("true" -> "Yes", "false" -> "No")
val booleanChoices = Seq("true" -> "Yes", "false" -> "No")
}

View file

@ -1,4 +1,4 @@
@(reports: List[lila.report.Report.WithSuspect], filter: String, counts: lila.report.Room.Counts)(implicit ctx: Context)
@(reports: List[lila.report.Report.WithSuspect], filter: String, counts: lila.report.Room.Counts, streamers: Int)(implicit ctx: Context)
@import lila.report.Report.WithSuspect
@ -25,6 +25,11 @@ moreCss = cssTag("report.css")) {
@lila.report.Room.all.map { r =>
@tab(reports, r)
}
@if(streamers > 0) {
<a href="@routes.Streamer.index()?requests=1" class="new">
<count>@streamers</count>Streamers
</a>
}
</span>
</div>
<table class="slist see">

View file

@ -66,17 +66,17 @@ side = side.some) {
<form class="content_box_content material form" action="@routes.Streamer.edit" method="POST">
@errMsgMaterial(form.errors)
@if(isGranted(_.Streamers)) {
@base.form.group(form("mod.approved"), Html("Publish on the streamers list"), help = Html("Moderation").some, half = true) {
@base.form.select(form("mod.approved"), booleanChoices)
@base.form.group(form("approval.granted"), Html("Publish on the streamers list"), help = Html("Moderators only").some, half = true) {
@base.form.select(form("approval.granted"), booleanChoices)
}
@if(granted) {
@base.form.group(form("mod.featured"), Html("Feature on lichess homepage"), help = Html("Moderation").some, half = true) {
@base.form.select(form("mod.featured"), booleanChoices)
@base.form.group(form("approval.featured"), Html("Feature on lichess homepage"), help = Html("Moderators only").some, half = true) {
@base.form.select(form("approval.featured"), booleanChoices)
}
} else {
@base.form.group(form("mod.ignored"), Html("Ignore further approval requests"), help = Html("Moderation").some, half = true) {
@base.form.select(form("mod.ignored"), booleanChoices)
@base.form.group(form("approval.requested"), Html("Active approval request"), help = Html("Moderators only").some, half = true) {
@base.form.select(form("approval.requested"), booleanChoices)
}
@base.form.group(form("approval.ignored"), Html("Ignore further approval requests"), help = Html("Moderators only").some, half = true) {
@base.form.select(form("approval.ignored"), booleanChoices)
}
}
@base.form.group(form("twitch"), Html("Your Twitch username or URL"), help = Html("Optional. Leave empty if none").some) {

View file

@ -1,14 +1,17 @@
@(pager: Paginator[lila.streamer.Streamer.WithUser])(implicit ctx: Context)
@(pager: Paginator[lila.streamer.Streamer.WithUser], requests: Boolean)(implicit ctx: Context)
@base.layout(title = "Lichess streamers",
@title = @{ if (requests) "Streamer approval requests" else "Lichess streamers" }
@base.layout(title = title,
moreCss = cssTag("streamer.list.css"),
moreJs = jsTag("vendor/jquery.infinitescroll.min.js")) {
<div class="content_box no_padding streamers">
<div class="top"><h1 data-icon="" class="text">Streamers</h1></div>
<div class="top"><h1 data-icon="" class="text">@title</h1></div>
<div class="list infinitescroll">
@pager.currentPageResults.map { c =>
<div class="streamer paginated_element" data-dedup="@c.streamer.id">
@widget(c)
@widget(c, edit = requests)
</div>
}
@pager.nextPage.map { np =>

View file

@ -1,5 +1,5 @@
@(s: lila.streamer.Streamer.WithUser)(implicit ctx: Context)
<a class="overlay" href="@routes.Streamer.show(s.user.username)"></a>
@(s: lila.streamer.Streamer.WithUser, edit: Boolean = false)(implicit ctx: Context)
<a class="overlay" href="@if(edit){@routes.Streamer.edit?u=@s.user.username}else{@routes.Streamer.show(s.user.username)}"></a>
@pic(s, 250)
@defining(s.user.profileOrDefault) { profile =>
<div class="overview">

View file

@ -64,6 +64,11 @@ final class StreamerApi(
coll.updateField($id(s.streamer.id), "approval.requested", true).void
}
}
def countRequests: Fu[Int] = coll.countSel($doc(
"approval.requested" -> true,
"approval.ignored" -> false
))
}
private def withUser(user: User)(streamer: Streamer) = Streamer.WithUser(streamer, user)

View file

@ -13,11 +13,12 @@ object StreamerForm {
"description" -> optional(description),
"twitch" -> optional(nonEmptyText.verifying("Invalid Twitch username", s => Streamer.Twitch.parseUserId(s).isDefined)),
"youTube" -> optional(nonEmptyText.verifying("Invalid YouTube channel", s => Streamer.YouTube.parseChannelId(s).isDefined)),
"mod" -> optional(mapping(
"approved" -> boolean,
"ignored" -> boolean,
"featured" -> boolean
)(ModData.apply)(ModData.unapply))
"approval" -> optional(mapping(
"granted" -> boolean,
"featured" -> boolean,
"requested" -> boolean,
"ignored" -> boolean
)(ApprovalData.apply)(ApprovalData.unapply))
)(UserData.apply)(UserData.unapply))
def userForm(streamer: Streamer) = emptyUserForm fill UserData(
@ -25,10 +26,11 @@ object StreamerForm {
description = streamer.description,
twitch = streamer.twitch.map(_.userId),
youTube = streamer.youTube.map(_.channelId),
mod = ModData(
approved = streamer.approval.granted,
ignored = streamer.approval.ignored,
featured = streamer.approval.autoFeatured
approval = ApprovalData(
granted = streamer.approval.granted,
featured = streamer.approval.autoFeatured,
requested = streamer.approval.requested,
ignored = streamer.approval.ignored
).some
)
@ -37,7 +39,7 @@ object StreamerForm {
description: Option[Description],
twitch: Option[String],
youTube: Option[String],
mod: Option[ModData]
approval: Option[ApprovalData]
) {
def apply(streamer: Streamer, asMod: Boolean) = {
@ -53,11 +55,15 @@ object StreamerForm {
updatedAt = DateTime.now
)
newStreamer.copy(
approval = mod match {
approval = approval match {
case Some(m) if asMod => streamer.approval.copy(
granted = m.approved,
ignored = m.ignored && !m.approved,
autoFeatured = m.featured && m.approved
granted = m.granted,
autoFeatured = m.featured && m.granted,
requested = !m.granted && {
if (streamer.approval.requested != m.requested) m.requested
else streamer.approval.requested || m.requested
},
ignored = m.ignored && !m.granted
)
case None if streamer.twitch != newStreamer.twitch || streamer.youTube != newStreamer.youTube =>
streamer.approval.copy(granted = false, autoFeatured = false)
@ -67,10 +73,11 @@ object StreamerForm {
}
}
case class ModData(
approved: Boolean,
ignored: Boolean,
featured: Boolean
case class ApprovalData(
granted: Boolean,
featured: Boolean,
requested: Boolean,
ignored: Boolean
)
private implicit val descriptionFormat = lila.common.Form.formatter.stringFormatter[Description](_.value, Description.apply)

View file

@ -14,10 +14,15 @@ final class StreamerPager(
import BsonHandlers._
def apply(page: Int): Fu[Paginator[Streamer.WithUser]] = {
def apply(page: Int, approvalRequested: Boolean = false): Fu[Paginator[Streamer.WithUser]] = {
val adapter = new Adapter[Streamer](
collection = coll,
selector = $doc("listed" -> Streamer.Listed(true)),
selector =
if (approvalRequested) $doc(
"approval.requested" -> true,
"approval.ignored" -> false
)
else $doc("listed" -> Streamer.Listed(true)),
projection = $empty,
sort = $doc(
"sorting.streaming" -> -1,