broadcast tier system - MIGRATION NEEDED - closes #9938
parent
4f48e2bd1c
commit
b123acf9bc
|
@ -35,7 +35,7 @@ object tour {
|
||||||
),
|
),
|
||||||
st.section(
|
st.section(
|
||||||
active.map { tr =>
|
active.map { tr =>
|
||||||
div(cls := "relay-widget relay-widget--active", dataIcon := "")(
|
div(cls := s"relay-widget relay-widget--active ${tierClass(tr.tour)}", dataIcon := "")(
|
||||||
a(cls := "overlay", href := tr.path),
|
a(cls := "overlay", href := tr.path),
|
||||||
div(
|
div(
|
||||||
h2(tr.tour.name),
|
h2(tr.tour.name),
|
||||||
|
@ -54,7 +54,7 @@ object tour {
|
||||||
),
|
),
|
||||||
st.section(cls := "infinite-scroll")(
|
st.section(cls := "infinite-scroll")(
|
||||||
pager.currentPageResults map { rt =>
|
pager.currentPageResults map { rt =>
|
||||||
div(cls := "relay-widget paginated", dataIcon := "")(
|
div(cls := s"relay-widget ${tierClass(rt.tour)} paginated", dataIcon := "")(
|
||||||
a(cls := "overlay", href := rt.path),
|
a(cls := "overlay", href := rt.path),
|
||||||
div(
|
div(
|
||||||
h2(rt.tour.name),
|
h2(rt.tour.name),
|
||||||
|
@ -70,4 +70,5 @@ object tour {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def tierClass(tour: RelayTour) = s"tour-tier--${tour.tier | RelayTour.Tier.NORMAL}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,11 +62,11 @@ object tourForm {
|
||||||
).some
|
).some
|
||||||
)(form3.textarea(_)(rows := 10)),
|
)(form3.textarea(_)(rows := 10)),
|
||||||
if (isGranted(_.Relay))
|
if (isGranted(_.Relay))
|
||||||
form3.checkbox(
|
form3.group(
|
||||||
form("official"),
|
form("tier"),
|
||||||
raw("Official Lichess broadcast"),
|
raw("Official Lichess broadcast tier"),
|
||||||
help = raw("Feature on /broadcast - for admins only").some
|
help = raw("Feature on /broadcast - for admins only").some
|
||||||
)
|
)(form3.select(_, RelayTour.Tier.options))
|
||||||
else form3.hidden(form("official"))
|
else form3.hidden(form("tier"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
db.relay_tour.update({ official: true }, { $set: { tier: NumberInt(3) }, $unset: { official: true } }, { multi: 1 });
|
||||||
|
db.relay_tour.dropIndex('active_1_official_1_syncedAt_-1');
|
||||||
|
db.relay_tour.createIndex(
|
||||||
|
{ active: 1, tier: 1 },
|
||||||
|
{ partialFilterExpression: { active: true, tier: { $exists: true } } }
|
||||||
|
);
|
||||||
|
db.relay_tour.createIndex({ syncedAt: -1 }, { partialFilterExpression: { tier: { $exists: true } } });
|
|
@ -85,6 +85,7 @@ final class RelayApi(
|
||||||
.aggregateList(20) { framework =>
|
.aggregateList(20) { framework =>
|
||||||
import framework._
|
import framework._
|
||||||
Match(tourRepo.selectors.official ++ tourRepo.selectors.active) -> List(
|
Match(tourRepo.selectors.official ++ tourRepo.selectors.active) -> List(
|
||||||
|
Sort(Descending("tier")),
|
||||||
PipelineOperator(
|
PipelineOperator(
|
||||||
$doc(
|
$doc(
|
||||||
"$lookup" -> $doc(
|
"$lookup" -> $doc(
|
||||||
|
|
|
@ -11,9 +11,9 @@ case class RelayTour(
|
||||||
markup: Option[String] = None,
|
markup: Option[String] = None,
|
||||||
ownerId: User.ID,
|
ownerId: User.ID,
|
||||||
createdAt: DateTime,
|
createdAt: DateTime,
|
||||||
official: Boolean,
|
tier: Option[RelayTour.Tier], // if present, it's an official broadcast
|
||||||
active: Boolean, // a round is scheduled or ongoing
|
active: Boolean, // a round is scheduled or ongoing
|
||||||
syncedAt: Option[DateTime] // last time a round was synced
|
syncedAt: Option[DateTime] // last time a round was synced
|
||||||
) {
|
) {
|
||||||
def id = _id
|
def id = _id
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ case class RelayTour(
|
||||||
}
|
}
|
||||||
|
|
||||||
def withRounds(rounds: List[RelayRound]) = RelayTour.WithRounds(this, rounds)
|
def withRounds(rounds: List[RelayRound]) = RelayTour.WithRounds(this, rounds)
|
||||||
|
|
||||||
|
def official = tier.isDefined
|
||||||
}
|
}
|
||||||
|
|
||||||
object RelayTour {
|
object RelayTour {
|
||||||
|
@ -31,6 +33,23 @@ object RelayTour {
|
||||||
|
|
||||||
case class Id(value: String) extends AnyVal with StringValue
|
case class Id(value: String) extends AnyVal with StringValue
|
||||||
|
|
||||||
|
type Tier = Int
|
||||||
|
object Tier {
|
||||||
|
val NORMAL = 3
|
||||||
|
val HIGH = 4
|
||||||
|
val BEST = 5
|
||||||
|
|
||||||
|
val options = List(
|
||||||
|
"" -> "Non official",
|
||||||
|
NORMAL.toString -> "Official: normal tier",
|
||||||
|
HIGH.toString -> "Official: high tier",
|
||||||
|
BEST.toString -> "Official: best tier"
|
||||||
|
)
|
||||||
|
def name(tier: Tier) = options.collectFirst {
|
||||||
|
case (t, n) if t == tier => n
|
||||||
|
} | "???"
|
||||||
|
}
|
||||||
|
|
||||||
case class WithRounds(tour: RelayTour, rounds: List[RelayRound])
|
case class WithRounds(tour: RelayTour, rounds: List[RelayRound])
|
||||||
|
|
||||||
case class ActiveWithNextRound(tour: RelayTour, round: RelayRound) extends RelayRound.AndTour {
|
case class ActiveWithNextRound(tour: RelayTour, round: RelayRound) extends RelayRound.AndTour {
|
||||||
|
|
|
@ -21,7 +21,7 @@ final class RelayTourForm {
|
||||||
"name" -> cleanText(minLength = 3, maxLength = 80),
|
"name" -> cleanText(minLength = 3, maxLength = 80),
|
||||||
"description" -> cleanText(minLength = 3, maxLength = 400),
|
"description" -> cleanText(minLength = 3, maxLength = 400),
|
||||||
"markup" -> optional(cleanText(maxLength = 20_000)),
|
"markup" -> optional(cleanText(maxLength = 20_000)),
|
||||||
"official" -> optional(boolean)
|
"tier" -> optional(number(min = RelayTour.Tier.NORMAL, max = RelayTour.Tier.BEST))
|
||||||
)(Data.apply)(Data.unapply)
|
)(Data.apply)(Data.unapply)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ object RelayTourForm {
|
||||||
name: String,
|
name: String,
|
||||||
description: String,
|
description: String,
|
||||||
markup: Option[String],
|
markup: Option[String],
|
||||||
official: Option[Boolean]
|
tier: Option[RelayTour.Tier]
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def update(tour: RelayTour, user: User) =
|
def update(tour: RelayTour, user: User) =
|
||||||
|
@ -44,7 +44,7 @@ object RelayTourForm {
|
||||||
name = name,
|
name = name,
|
||||||
description = description,
|
description = description,
|
||||||
markup = markup,
|
markup = markup,
|
||||||
official = ~official && Granter(_.Relay)(user)
|
tier = tier ifTrue Granter(_.Relay)(user)
|
||||||
)
|
)
|
||||||
|
|
||||||
def make(user: User) =
|
def make(user: User) =
|
||||||
|
@ -54,7 +54,7 @@ object RelayTourForm {
|
||||||
description = description,
|
description = description,
|
||||||
markup = markup,
|
markup = markup,
|
||||||
ownerId = user.id,
|
ownerId = user.id,
|
||||||
official = ~official && Granter(_.Relay)(user),
|
tier = tier ifTrue Granter(_.Relay)(user),
|
||||||
active = false,
|
active = false,
|
||||||
createdAt = DateTime.now,
|
createdAt = DateTime.now,
|
||||||
syncedAt = none
|
syncedAt = none
|
||||||
|
@ -68,7 +68,7 @@ object RelayTourForm {
|
||||||
name = tour.name,
|
name = tour.name,
|
||||||
description = tour.description,
|
description = tour.description,
|
||||||
markup = tour.markup,
|
markup = tour.markup,
|
||||||
official = tour.official option true
|
tier = tour.tier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ final private class RelayTourRepo(val coll: Coll)(implicit ec: scala.concurrent.
|
||||||
def lookup(local: String) = $lookup.simple(coll, "tour", local, "_id")
|
def lookup(local: String) = $lookup.simple(coll, "tour", local, "_id")
|
||||||
|
|
||||||
private[relay] object selectors {
|
private[relay] object selectors {
|
||||||
val official = $doc("official" -> true)
|
val official = $doc("tier" $exists true)
|
||||||
val active = $doc("active" -> true)
|
val active = $doc("active" -> true)
|
||||||
val inactive = $doc("active" -> false)
|
val inactive = $doc("active" -> false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
@extend %flex-center-nowrap, %break-word;
|
@extend %flex-center-nowrap, %break-word;
|
||||||
|
|
||||||
border-bottom: $border;
|
border-bottom: $border;
|
||||||
padding: 2em var(--box-padding);
|
padding: 2em var(--box-padding) 2em 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@include transition;
|
@include transition;
|
||||||
|
@ -10,13 +10,19 @@
|
||||||
&::before {
|
&::before {
|
||||||
color: $c-font-dimmer;
|
color: $c-font-dimmer;
|
||||||
font-size: 5em;
|
font-size: 5em;
|
||||||
margin-right: 0.4em;
|
width: 12rem;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
@include transition;
|
@include transition;
|
||||||
@include breakpoint($mq-not-xx-small) {
|
}
|
||||||
|
|
||||||
|
@include breakpoint($mq-not-xx-small) {
|
||||||
|
&::before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
padding-left: var(--box-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
&--active::before {
|
&--active::before {
|
||||||
color: mix($c-link, $c-bg-box, 80%);
|
color: mix($c-link, $c-bg-box, 80%);
|
||||||
}
|
}
|
||||||
|
@ -55,4 +61,22 @@
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.tour-tier {
|
||||||
|
&--3 {
|
||||||
|
&::before {
|
||||||
|
font-size: 3.5em;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
@include fluid-size('font-size', 13px, 23px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&--5 {
|
||||||
|
@extend %box-neat;
|
||||||
|
border: 3px solid $c-border;
|
||||||
|
&.relay-widget--active {
|
||||||
|
border-color: $c-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue