broadcast tournament/round WIP
parent
3670ab3820
commit
592b776fef
|
@ -19,9 +19,9 @@ final class RelayRound(
|
|||
def form(tourId: String) =
|
||||
Auth { implicit ctx => me =>
|
||||
NoLameOrBot {
|
||||
WithTour(tourId) { tour =>
|
||||
(tour.owner == me.id) ?? {
|
||||
Ok(html.relay.form.create(env.relay.roundForm.create, tour)).fuccess
|
||||
WithTourAndRounds(tourId) { trs =>
|
||||
(trs.tour.ownerId == me.id) ?? {
|
||||
Ok(html.relay.roundForm.create(env.relay.roundForm.create(trs), trs.tour)).fuccess
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +32,16 @@ final class RelayRound(
|
|||
auth = implicit ctx =>
|
||||
me =>
|
||||
NoLameOrBot {
|
||||
WithTour(tourId) { tour =>
|
||||
(tour.owner == me.id) ?? {
|
||||
env.relay.roundForm.create
|
||||
WithTourAndRounds(tourId) { trs =>
|
||||
(trs.tour.ownerId == me.id) ?? {
|
||||
env.relay.roundForm
|
||||
.create(trs)
|
||||
.bindFromRequest()(ctx.body, formBinding)
|
||||
.fold(
|
||||
err => BadRequest(html.relay.form.create(err, tour)).fuccess,
|
||||
err => BadRequest(html.relay.roundForm.create(err, trs.tour)).fuccess,
|
||||
setup =>
|
||||
env.relay.api.create(setup, me, tour) map { relay =>
|
||||
Redirect(relay.withTour(tour).path)
|
||||
env.relay.api.create(setup, me, trs.tour) map { relay =>
|
||||
Redirect(routes.RelayTour.show(trs.tour.slug, trs.tour.id.value))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -50,13 +51,16 @@ final class RelayRound(
|
|||
me =>
|
||||
env.relay.api tourById TourModel.Id(tourId) flatMap {
|
||||
_ ?? { tour =>
|
||||
!(me.isBot || me.lame) ??
|
||||
env.relay.roundForm.create
|
||||
.bindFromRequest()(req, formBinding)
|
||||
.fold(
|
||||
err => BadRequest(apiFormError(err)).fuccess,
|
||||
setup => env.relay.api.create(setup, me, tour) map env.relay.jsonView.admin map JsonOk
|
||||
)
|
||||
env.relay.api.withRounds(tour) flatMap { trs =>
|
||||
!(me.isBot || me.lame) ??
|
||||
env.relay.roundForm
|
||||
.create(trs)
|
||||
.bindFromRequest()(req, formBinding)
|
||||
.fold(
|
||||
err => BadRequest(apiFormError(err)).fuccess,
|
||||
setup => env.relay.api.create(setup, me, tour) map env.relay.jsonView.admin map JsonOk
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -64,7 +68,7 @@ final class RelayRound(
|
|||
def edit(id: String) =
|
||||
Auth { implicit ctx => me =>
|
||||
OptionFuResult(env.relay.api.byIdAndContributor(id, me)) { rt =>
|
||||
Ok(html.relay.form.edit(rt, env.relay.roundForm.edit(rt.relay))).fuccess
|
||||
Ok(html.relay.roundForm.edit(rt, env.relay.roundForm.edit(rt.relay))).fuccess
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +81,7 @@ final class RelayRound(
|
|||
case Some(res) =>
|
||||
res
|
||||
.fold(
|
||||
{ case (old, err) => BadRequest(html.relay.form.edit(old, err)) },
|
||||
{ case (old, err) => BadRequest(html.relay.roundForm.edit(old, err)) },
|
||||
rt => Redirect(rt.path)
|
||||
)
|
||||
.fuccess
|
||||
|
@ -189,6 +193,13 @@ final class RelayRound(
|
|||
)(implicit ctx: Context): Fu[Result] =
|
||||
OptionFuResult(env.relay.api tourById TourModel.Id(id))(f)
|
||||
|
||||
private def WithTourAndRounds(id: String)(
|
||||
f: TourModel.WithRounds => Fu[Result]
|
||||
)(implicit ctx: Context): Fu[Result] =
|
||||
WithTour(id) { tour =>
|
||||
env.relay.api withRounds tour flatMap f
|
||||
}
|
||||
|
||||
private def doShow(rt: RoundModel.WithTour, oldSc: lila.study.Study.WithChapter)(implicit
|
||||
ctx: Context
|
||||
): Fu[Result] =
|
||||
|
|
|
@ -10,20 +10,20 @@ import lila.relay.RelayRound.Sync.UpstreamUrl.LccRegex
|
|||
import lila.relay.RelayRoundForm.Data
|
||||
import lila.relay.{ RelayRound, RelayTour }
|
||||
|
||||
object form {
|
||||
object roundForm {
|
||||
|
||||
import trans.broadcast._
|
||||
|
||||
def create(form: Form[Data], tour: RelayTour)(implicit ctx: Context) =
|
||||
layout(newBroadcast.txt())(
|
||||
h1(newBroadcast()),
|
||||
inner(form, routes.RelayRound.create(tour.id.value))
|
||||
h1(a(href := views.html.relay.tour.url(tour))(tour.name), " • ", addRound()),
|
||||
inner(form, routes.RelayRound.create(tour.id.value), tour)
|
||||
)
|
||||
|
||||
def edit(rt: RelayRound.WithTour, form: Form[Data])(implicit ctx: Context) =
|
||||
layout(rt.fullName)(
|
||||
h1("Edit ", rt.fullName),
|
||||
inner(form, routes.RelayRound.update(rt.relay.id.value)),
|
||||
inner(form, routes.RelayRound.update(rt.relay.id.value), rt.tour),
|
||||
hr,
|
||||
postForm(action := routes.RelayRound.cloneRelay(rt.relay.id.value))(
|
||||
submitButton(
|
||||
|
@ -49,7 +49,7 @@ object form {
|
|||
main(cls := "page-small box box-pad")(body)
|
||||
)
|
||||
|
||||
private def inner(form: Form[Data], url: play.api.mvc.Call)(implicit ctx: Context) =
|
||||
private def inner(form: Form[Data], url: play.api.mvc.Call, tour: RelayTour)(implicit ctx: Context) =
|
||||
postForm(cls := "form3", action := url)(
|
||||
div(cls := "form-group")(
|
||||
a(dataIcon := "", cls := "text", href := routes.Page.loneBookmark("broadcasts"))(
|
||||
|
@ -101,7 +101,7 @@ object form {
|
|||
),
|
||||
isGranted(_.Relay) option form3.group(form("credit"), credits())(form3.input(_)),
|
||||
form3.actions(
|
||||
a(href := routes.RelayTour.index(1))(trans.cancel()),
|
||||
a(href := views.html.relay.tour.url(tour))(trans.cancel()),
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
|
@ -31,4 +31,6 @@ object tour {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
def url(t: RelayTour) = routes.RelayTour.show(t.slug, t.id.value)
|
||||
}
|
||||
|
|
|
@ -9,13 +9,16 @@ const newId = () => {
|
|||
db.relay.find().forEach(relay => {
|
||||
const tourId = newId();
|
||||
db.relay_tour.insert({
|
||||
_id: tourId,
|
||||
name: relay.name,
|
||||
description: relay.description,
|
||||
markup: relay.markup,
|
||||
ownerId: relay.ownerId,
|
||||
createdAt: relay.createdAt,
|
||||
official: relay.official,
|
||||
...{
|
||||
_id: tourId,
|
||||
order: NumberInt(0),
|
||||
name: relay.name,
|
||||
description: relay.description,
|
||||
ownerId: relay.ownerId,
|
||||
createdAt: relay.createdAt,
|
||||
official: relay.official,
|
||||
},
|
||||
...(relay.markup ? { markup: relay.markup } : {}),
|
||||
});
|
||||
db.relay.update(
|
||||
{ _id: relay._id },
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
var id = 'RWtJ4aKC';
|
||||
|
||||
var relay = db.relay.findOne({ _id: id });
|
||||
if (relay) {
|
||||
print('Removing ' + relay.games.length + ' games');
|
||||
relay.games.forEach(function (g) {
|
||||
db.game5.remove({ _id: g.id });
|
||||
});
|
||||
print('Removing relay');
|
||||
db.relay.remove({ _id: id });
|
||||
}
|
|
@ -38,7 +38,8 @@ object BSONHandlers {
|
|||
|
||||
def readRelayWithTour(doc: Bdoc): Option[RelayRound.WithTour] =
|
||||
for {
|
||||
relay <- doc.asOpt[RelayRound]
|
||||
tour <- doc.getAsOpt[RelayTour]("tour")
|
||||
_ <- Some(println(lila.db.BSON debug doc))
|
||||
relay <- doc.asOpt[RelayRound].pp
|
||||
tour <- doc.getAsTry[RelayTour]("tour").pp.toOption
|
||||
} yield RelayRound.WithTour(relay, tour)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import lila.study.{ Settings, Study, StudyApi, StudyMaker, StudyRepo }
|
|||
import lila.user.User
|
||||
|
||||
final class RelayApi(
|
||||
relayRepo: RelayRoundRepo,
|
||||
roundRepo: RelayRoundRepo,
|
||||
tourRepo: RelayTourRepo,
|
||||
studyApi: StudyApi,
|
||||
studyRepo: StudyRepo,
|
||||
|
@ -26,10 +26,10 @@ final class RelayApi(
|
|||
import BSONHandlers._
|
||||
import lila.study.BSONHandlers.StudyBSONHandler
|
||||
|
||||
def byId(id: RelayRound.Id) = relayRepo.coll.byId[RelayRound](id.value)
|
||||
def byId(id: RelayRound.Id) = roundRepo.coll.byId[RelayRound](id.value)
|
||||
|
||||
def byIdWithTour(id: RelayRound.Id): Fu[Option[RelayRound.WithTour]] =
|
||||
relayRepo.coll
|
||||
roundRepo.coll
|
||||
.aggregateOne() { framework =>
|
||||
import framework._
|
||||
Match($id(id)) -> List(
|
||||
|
@ -42,7 +42,8 @@ final class RelayApi(
|
|||
def byIdAndContributor(id: RelayRound.Id, me: User) =
|
||||
byIdWithStudy(id) map {
|
||||
_ collect {
|
||||
case RelayRound.WithTourAndStudy(relay, tour, study) if study.canContribute(me.id) => relay withTour tour
|
||||
case RelayRound.WithTourAndStudy(relay, tour, study) if study.canContribute(me.id) =>
|
||||
relay withTour tour
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +57,9 @@ final class RelayApi(
|
|||
}
|
||||
|
||||
def byTour(tour: RelayTour): Fu[List[RelayRound.WithTour]] =
|
||||
relayRepo.byTour(tour).dmap(_.map(_ withTour tour))
|
||||
roundRepo.byTour(tour).dmap(_.map(_ withTour tour))
|
||||
|
||||
def withRounds(tour: RelayTour) = roundRepo.byTour(tour).dmap(tour.withRounds)
|
||||
|
||||
def fresh(me: Option[User]): Fu[RelayRound.Fresh] = fuccess(RelayRound.Fresh(Nil, Nil))
|
||||
// relayRepo.scheduled.flatMap(withStudy andLiked me) zip
|
||||
|
@ -76,7 +79,7 @@ final class RelayApi(
|
|||
)
|
||||
|
||||
def fetchWithTours(query: Bdoc, maxDocs: Int, readPreference: ReadPreference = ReadPreference.primary) =
|
||||
relayRepo.coll
|
||||
roundRepo.coll
|
||||
.aggregateList(maxDocs, readPreference) { framework =>
|
||||
import framework._
|
||||
Match(query) -> List(
|
||||
|
@ -91,25 +94,26 @@ final class RelayApi(
|
|||
tourRepo.coll.insert.one(tour) inject tour
|
||||
}
|
||||
|
||||
def create(data: RelayRoundForm.Data, user: User, tour: RelayTour): Fu[RelayRound] = {
|
||||
val relay = data.make(user, tour)
|
||||
relayRepo.coll.insert.one(relay) >>
|
||||
studyApi.importGame(
|
||||
StudyMaker.ImportGame(
|
||||
id = relay.studyId.some,
|
||||
name = Study.Name(relay.name).some,
|
||||
settings = Settings.init
|
||||
.copy(
|
||||
chat = Settings.UserSelection.Everyone,
|
||||
sticky = false
|
||||
)
|
||||
.some,
|
||||
from = Study.From.Relay(none).some
|
||||
),
|
||||
user
|
||||
) >>
|
||||
studyApi.addTopics(relay.studyId, List("Broadcast")) inject relay
|
||||
}
|
||||
def create(data: RelayRoundForm.Data, user: User, tour: RelayTour): Fu[RelayRound] =
|
||||
roundRepo.nextOrderByTour(tour.id) flatMap { order =>
|
||||
val relay = data.make(user, tour, order)
|
||||
roundRepo.coll.insert.one(relay) >>
|
||||
studyApi.importGame(
|
||||
StudyMaker.ImportGame(
|
||||
id = relay.studyId.some,
|
||||
name = Study.Name(relay.name).some,
|
||||
settings = Settings.init
|
||||
.copy(
|
||||
chat = Settings.UserSelection.Everyone,
|
||||
sticky = false
|
||||
)
|
||||
.some,
|
||||
from = Study.From.Relay(none).some
|
||||
),
|
||||
user
|
||||
) >>
|
||||
studyApi.addTopics(relay.studyId, List("Broadcast")) inject relay
|
||||
}
|
||||
|
||||
def requestPlay(id: RelayRound.Id, v: Boolean): Funit =
|
||||
WithRelay(id) { relay =>
|
||||
|
@ -126,7 +130,7 @@ final class RelayApi(
|
|||
studyApi.rename(relay.studyId, Study.Name(relay.name)) >> {
|
||||
if (relay == from) fuccess(relay)
|
||||
else
|
||||
relayRepo.coll.update.one($id(relay.id), relay).void >> {
|
||||
roundRepo.coll.update.one($id(relay.id), relay).void >> {
|
||||
(relay.sync.playing != from.sync.playing) ?? publishRelay(relay)
|
||||
} >>- {
|
||||
relay.sync.log.events.lastOption.ifTrue(relay.sync.log != from.sync.log).foreach { event =>
|
||||
|
@ -148,7 +152,7 @@ final class RelayApi(
|
|||
)
|
||||
|
||||
def getOngoing(id: RelayRound.Id): Fu[Option[RelayRound.WithTour]] =
|
||||
relayRepo.coll.one[RelayRound]($doc("_id" -> id, "finished" -> false)) flatMap {
|
||||
roundRepo.coll.one[RelayRound]($doc("_id" -> id, "finished" -> false)) flatMap {
|
||||
_ ?? { relay =>
|
||||
tourById(relay.tourId) map2 relay.withTour
|
||||
}
|
||||
|
@ -162,7 +166,7 @@ final class RelayApi(
|
|||
// .map(jsonView.public)
|
||||
|
||||
private[relay] def autoStart: Funit =
|
||||
relayRepo.coll.list[RelayRound](
|
||||
roundRepo.coll.list[RelayRound](
|
||||
$doc(
|
||||
"startsAt" $lt DateTime.now.plusMinutes(30) // start 30 minutes early to fetch boards
|
||||
$gt DateTime.now.minusDays(1), // bit late now
|
||||
|
@ -177,7 +181,7 @@ final class RelayApi(
|
|||
}
|
||||
|
||||
private[relay] def autoFinishNotSyncing: Funit =
|
||||
relayRepo.coll.list[RelayRound](
|
||||
roundRepo.coll.list[RelayRound](
|
||||
$doc(
|
||||
"sync.until" $exists false,
|
||||
"finished" -> false,
|
||||
|
@ -198,7 +202,7 @@ final class RelayApi(
|
|||
byId(id) flatMap { _ ?? f }
|
||||
|
||||
private[relay] def onStudyRemove(studyId: String) =
|
||||
relayRepo.coll.delete.one($id(RelayRound.Id(studyId))).void
|
||||
roundRepo.coll.delete.one($id(RelayRound.Id(studyId))).void
|
||||
|
||||
private[relay] def publishRelay(relay: RelayRound): Funit =
|
||||
sendToContributors(relay.id, "relayData", jsonView admin relay)
|
||||
|
|
|
@ -39,12 +39,14 @@ final class RelayPager(roundRepo: RelayRoundRepo, tourRepo: RelayTourRepo, study
|
|||
roundRepo.coll
|
||||
.aggregateList(length, readPreference = ReadPreference.secondaryPreferred) { framework =>
|
||||
import framework._
|
||||
Match(selector) -> List(
|
||||
Sort(Descending("startedAt")),
|
||||
Sort(Descending("startedAt")) -> List(
|
||||
GroupField("tourId")("round" -> FirstField("$ROOT")),
|
||||
Skip(offset),
|
||||
Limit(length),
|
||||
ReplaceRootField("round"),
|
||||
AddFields($doc("sync.log" -> $arr())),
|
||||
PipelineOperator(tourRepo lookup "tourId"),
|
||||
Unwind("tour")
|
||||
UnwindField("tour")
|
||||
)
|
||||
}
|
||||
.map(_ flatMap readRelayWithTour)
|
||||
|
|
|
@ -8,6 +8,7 @@ import lila.user.User
|
|||
case class RelayRound(
|
||||
_id: RelayRound.Id,
|
||||
tourId: RelayTour.Id,
|
||||
order: Int,
|
||||
name: String,
|
||||
description: String,
|
||||
markup: Option[String] = None,
|
||||
|
|
|
@ -17,7 +17,7 @@ final class RelayRoundForm {
|
|||
import RelayRoundForm._
|
||||
import lila.common.Form.ISODateTimeOrTimestamp
|
||||
|
||||
val form = Form(
|
||||
val roundMapping =
|
||||
mapping(
|
||||
"name" -> cleanText(minLength = 3, maxLength = 80),
|
||||
"description" -> cleanText(minLength = 3, maxLength = 400),
|
||||
|
@ -31,11 +31,21 @@ final class RelayRoundForm {
|
|||
"throttle" -> optional(number(min = 2, max = 60))
|
||||
)(Data.apply)(Data.unapply)
|
||||
.verifying("This source requires a round number. See the new form field below.", !_.roundMissing)
|
||||
|
||||
def create(trs: RelayTour.WithRounds) = Form {
|
||||
roundMapping
|
||||
.verifying(
|
||||
s"Maximum rounds per tournament: ${RelayTour.maxRelays}",
|
||||
_ => trs.rounds.sizeIs < RelayTour.maxRelays
|
||||
)
|
||||
}.fill(
|
||||
Data(
|
||||
name = s"Round ${trs.rounds.size + 1}",
|
||||
description = ""
|
||||
)
|
||||
)
|
||||
|
||||
def create = form
|
||||
|
||||
def edit(r: RelayRound) = form fill Data.make(r)
|
||||
def edit(r: RelayRound) = Form(roundMapping) fill Data.make(r)
|
||||
}
|
||||
|
||||
object RelayRoundForm {
|
||||
|
@ -84,12 +94,12 @@ object RelayRoundForm {
|
|||
case class Data(
|
||||
name: String,
|
||||
description: String,
|
||||
markup: Option[String],
|
||||
syncUrl: Option[String],
|
||||
syncUrlRound: Option[Int],
|
||||
credit: Option[String],
|
||||
startsAt: Option[DateTime],
|
||||
throttle: Option[Int]
|
||||
markup: Option[String] = None,
|
||||
syncUrl: Option[String] = None,
|
||||
syncUrlRound: Option[Int] = None,
|
||||
credit: Option[String] = None,
|
||||
startsAt: Option[DateTime] = None,
|
||||
throttle: Option[Int] = None
|
||||
) {
|
||||
|
||||
def requiresRound = syncUrl exists RelayRound.Sync.UpstreamUrl.LccRegex.matches
|
||||
|
@ -129,10 +139,11 @@ object RelayRoundForm {
|
|||
log = SyncLog.empty
|
||||
)
|
||||
|
||||
def make(user: User, tour: RelayTour) =
|
||||
def make(user: User, tour: RelayTour, order: Int) =
|
||||
RelayRound(
|
||||
_id = RelayRound.makeId,
|
||||
tourId = tour.id,
|
||||
order = order,
|
||||
name = name,
|
||||
description = description,
|
||||
markup = markup,
|
||||
|
|
|
@ -32,14 +32,20 @@ final private class RelayRoundRepo(val coll: Coll)(implicit ec: scala.concurrent
|
|||
// .batchSize(batchSize)
|
||||
// .cursor[Relay](ReadPreference.secondaryPreferred)
|
||||
|
||||
def nextOrderByTour(tourId: RelayTour.Id): Fu[Int] =
|
||||
coll.primitiveOne[Int](selectors.tour(tourId), orderSort, "order") dmap { ~_ + 1 }
|
||||
|
||||
def byTour(tour: RelayTour): Fu[List[RelayRound]] =
|
||||
coll
|
||||
.find($doc("tourId" -> tour.id))
|
||||
.sort($sort desc "startsAt")
|
||||
.find(selectors.tour(tour.id))
|
||||
.sort(orderSort)
|
||||
.cursor[RelayRound]()
|
||||
.list(RelayTour.maxRelays)
|
||||
|
||||
private val orderSort = $sort asc "order"
|
||||
|
||||
private[relay] object selectors {
|
||||
def tour(id: RelayTour.Id) = $doc("tourId" -> id)
|
||||
// def scheduled(official: Boolean) =
|
||||
// officialOption(official) ++ $doc(
|
||||
// "startsAt" $gt DateTime.now.minusHours(1),
|
||||
|
|
|
@ -9,7 +9,7 @@ case class RelayTour(
|
|||
name: String,
|
||||
description: String,
|
||||
markup: Option[String] = None,
|
||||
owner: User.ID,
|
||||
ownerId: User.ID,
|
||||
official: Boolean,
|
||||
createdAt: DateTime
|
||||
) {
|
||||
|
@ -19,6 +19,8 @@ case class RelayTour(
|
|||
val s = lila.common.String slugify name
|
||||
if (s.isEmpty) "-" else s
|
||||
}
|
||||
|
||||
def withRounds(rounds: List[RelayRound]) = RelayTour.WithRounds(this, rounds)
|
||||
}
|
||||
|
||||
object RelayTour {
|
||||
|
@ -27,5 +29,7 @@ object RelayTour {
|
|||
|
||||
case class Id(value: String) extends AnyVal with StringValue
|
||||
|
||||
case class WithRounds(tour: RelayTour, rounds: List[RelayRound])
|
||||
|
||||
def makeId = Id(lila.common.ThreadLocalRandom nextString 8)
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ object RelayTourForm {
|
|||
name = name,
|
||||
description = description,
|
||||
markup = markup,
|
||||
owner = user.id,
|
||||
ownerId = user.id,
|
||||
official = ~official && Granter(_.Relay)(user),
|
||||
createdAt = DateTime.now
|
||||
)
|
||||
|
|
|
@ -96,15 +96,7 @@ final class ChapterRepo(val coll: AsyncColl)(implicit
|
|||
}
|
||||
|
||||
def nextOrderByStudy(studyId: Study.Id): Fu[Int] =
|
||||
coll(
|
||||
_.primitiveOne[Int](
|
||||
$studyId(studyId),
|
||||
$sort desc "order",
|
||||
"order"
|
||||
)
|
||||
) dmap { order =>
|
||||
~order + 1
|
||||
}
|
||||
coll(_.primitiveOne[Int]($studyId(studyId), $sort desc "order", "order")) dmap { ~_ + 1 }
|
||||
|
||||
def setConceal(chapterId: Chapter.Id, conceal: Chapter.Ply) =
|
||||
coll(_.updateField($id(chapterId), "conceal", conceal)).void
|
||||
|
|
Loading…
Reference in New Issue