relay WIP
parent
a16966ad02
commit
fba3b549c6
|
@ -0,0 +1,41 @@
|
|||
package controllers
|
||||
|
||||
import play.api.mvc._
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app._
|
||||
import lila.relay.{ Relay => RelayModel }
|
||||
import views._
|
||||
|
||||
object Relay extends LilaController {
|
||||
|
||||
private val env = Env.relay
|
||||
|
||||
def index = Open { implicit ctx =>
|
||||
env.api.all map { sel =>
|
||||
Ok(html.relay.index(sel))
|
||||
}
|
||||
}
|
||||
|
||||
def form = Auth { implicit ctx => me =>
|
||||
NoLame {
|
||||
Ok(html.relay.create(env.forms.create)).fuccess
|
||||
}
|
||||
}
|
||||
|
||||
def create = AuthBody { implicit ctx => implicit me =>
|
||||
implicit val req = ctx.body
|
||||
env.forms.create.bindFromRequest.fold(
|
||||
err => BadRequest(html.relay.create(err)).fuccess,
|
||||
setup => env.api.create(setup, me) map { relay =>
|
||||
Redirect(routes.Relay.show(relay.id.value))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
def show(id: String) = Open { implicit ctx =>
|
||||
OptionOk(env.api byId RelayModel.Id(id)) { relay =>
|
||||
html.relay.show(relay)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
@(form: Form[_])(implicit ctx: Context)
|
||||
|
||||
@moreCss = {
|
||||
@cssTag("material.form.css")
|
||||
@cssTag("relay.css")
|
||||
}
|
||||
|
||||
@base.layout(
|
||||
title = "New live broadcast",
|
||||
moreCss = moreCss
|
||||
) {
|
||||
<div class="relay_form content_box small_box no_padding">
|
||||
<h1 class="lichess_title">New live broadcast</h1>
|
||||
<form class="content_box_content material form" action="@routes.Relay.create" method="POST">
|
||||
@inForm(form)
|
||||
</form>
|
||||
</div>
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
@(form: Form[_])(implicit ctx: Context)
|
||||
|
||||
@base.form.group(form("name"), Html("Event name")) {
|
||||
@base.form.input(form("name"))
|
||||
}
|
||||
@defining(form("description")) { field =>
|
||||
@base.form.group(field, Html("Event description")) {
|
||||
<textarea class="description" name="@field.name" id="@field.id">@field.value</textarea>
|
||||
}
|
||||
}
|
||||
@base.form.group(form("startsAt"), Html("Start date <strong>UTC</strong>")) {
|
||||
@base.form.flatpickr(form("startsAt"))
|
||||
}
|
||||
@base.form.group(form("pgnUrl"), Html("Live PGN URL")) {
|
||||
@base.form.input(form("pgnUrl"))
|
||||
}
|
||||
|
||||
@base.form.submit()
|
|
@ -0,0 +1,33 @@
|
|||
@(sel: lila.relay.Relay.Selection)(implicit ctx: Context)
|
||||
|
||||
@sublist(relays: List[lila.relay.Relay.WithStudy]) = {
|
||||
<div class="list">
|
||||
@relays.map { r =>
|
||||
<div class="relay">
|
||||
@widget(r)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@base.layout(
|
||||
title = "Live tournament broadcasts",
|
||||
moreCss = cssTag("relay.css")) {
|
||||
<div class="content_box no_padding relays">
|
||||
<div class="top">
|
||||
<h1>Live tournament broadcasts</h1>
|
||||
</div>
|
||||
<section>
|
||||
<h2>Ongoing</h2>
|
||||
@sublist(sel.started)
|
||||
</section>
|
||||
<section>
|
||||
<h2>Upcoming</h2>
|
||||
@sublist(sel.created)
|
||||
</section>
|
||||
<section>
|
||||
<h2>Completed</h2>
|
||||
@sublist(sel.closed)
|
||||
</section>
|
||||
</div>
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
@(r: lila.relay.Relay)(implicit ctx: Context)
|
||||
|
||||
@base.layout(
|
||||
title = r.name,
|
||||
moreCss = cssTag("relay.css")
|
||||
) {
|
||||
<h1 class="lichess_title">@r.name</h1>
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
@(r: lila.relay.Relay.WithStudy)(implicit ctx: Context)
|
||||
<a class="overlay" href="@routes.Relay.show(r.relay.id.value)"></a>
|
||||
<h2>
|
||||
<i class="icon" data-icon=""></i>
|
||||
<strong>@r.relay.name</strong>
|
||||
</h2>
|
||||
<div class="body">
|
||||
<p>@r.relay.description</p>
|
||||
@momentFromNow(r.relay.startsAt)
|
||||
</div>
|
|
@ -1,13 +1,5 @@
|
|||
@(title: String, active: String, order: lila.study.Order, pag: Paginator[lila.study.Study.WithChaptersAndLiked], url: controllers.Study.ListUrl, searchFilter: String)(titleHtml: Html)(implicit ctx: Context)
|
||||
|
||||
@moreCss = {
|
||||
@cssTag("studyList.css")
|
||||
}
|
||||
|
||||
@moreJs = {
|
||||
@jsTag("vendor/jquery.infinitescroll.min.js")
|
||||
}
|
||||
|
||||
@menu = {
|
||||
<a class="@active.active("all")" href="@routes.Study.all(order.key)">All studies</a>
|
||||
@ctx.me.map { me =>
|
||||
|
@ -19,8 +11,8 @@
|
|||
@base.layout(
|
||||
title = title,
|
||||
menu = menu.some,
|
||||
moreCss = moreCss,
|
||||
moreJs = moreJs) {
|
||||
moreCss = cssTag("studyList.css"),
|
||||
moreJs = jsTag("vendor/jquery.infinitescroll.min.js")) {
|
||||
<div class="content_box no_padding studies">
|
||||
<div class="top">
|
||||
<form class="search" action="@routes.Study.search()" method="get">
|
||||
|
|
|
@ -521,6 +521,9 @@ irwin {
|
|||
collection.report = irwin_report
|
||||
collection.request = irwin_request
|
||||
}
|
||||
relay {
|
||||
collection.relay = relay
|
||||
}
|
||||
activity {
|
||||
collection.activity = activity
|
||||
}
|
||||
|
|
|
@ -149,6 +149,12 @@ GET /study/$id<\w{8}>/$chapterId<\w{8}>/meta controllers.Study.chapterMeta(i
|
|||
GET /study/embed/$id<\w{8}>/$chapterId<\w{8}> controllers.Study.embed(id: String, chapterId: String)
|
||||
POST /study/$id<\w{8}>/clear-chat controllers.Study.clearChat(id: String)
|
||||
|
||||
# Relay
|
||||
GET /relay controllers.Relay.index
|
||||
GET /relay/new controllers.Relay.form
|
||||
POST /relay/new controllers.Relay.create
|
||||
GET /relay/$id<\w{8}> controllers.Relay.show(id: String)
|
||||
|
||||
# Learn
|
||||
GET /learn controllers.Learn.index
|
||||
POST /learn/score controllers.Learn.score
|
||||
|
|
|
@ -46,7 +46,7 @@ object HTTPRequest {
|
|||
|
||||
case class UaMatcher(regex: String) {
|
||||
val pattern = regex.r.pattern
|
||||
|
||||
|
||||
def apply(req: RequestHeader): Boolean =
|
||||
userAgent(req) ?? { ua => pattern.matcher(ua).find }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package lila.relay
|
||||
|
||||
import lila.db.dsl._
|
||||
import lila.db.BSON
|
||||
import reactivemongo.bson._
|
||||
|
||||
object BSONHandlers {
|
||||
|
||||
implicit val relayIdHandler = stringAnyValHandler[Relay.Id](_.value, Relay.Id.apply)
|
||||
|
||||
implicit val relayHandler = Macros.handler[Relay]
|
||||
}
|
|
@ -1,32 +1,41 @@
|
|||
package lila.relay
|
||||
|
||||
import akka.actor._
|
||||
import com.typesafe.config.Config
|
||||
import scala.concurrent.duration._
|
||||
|
||||
final class Env(
|
||||
config: Config,
|
||||
db: lila.db.Env,
|
||||
studyEnv: lila.study.Env,
|
||||
system: ActorSystem
|
||||
) {
|
||||
|
||||
private val relayColl = db(config getString "collection.relay")
|
||||
|
||||
private val sync = new RelaySync(
|
||||
studyApi = studyEnv.api,
|
||||
chapterRepo = studyEnv.chapterRepo
|
||||
)
|
||||
|
||||
lazy val forms = RelayForm
|
||||
|
||||
val api = new RelayApi(
|
||||
coll = relayColl,
|
||||
studyApi = studyEnv.api
|
||||
)
|
||||
|
||||
private val fetch = system.actorOf(Props(new RelayFetch(
|
||||
sync = sync,
|
||||
getCurrents = () => fuccess(List(
|
||||
Relay(
|
||||
lila.study.Study.Id("AoUZ6bOS"),
|
||||
url = "http://localhost:3000"
|
||||
)
|
||||
))
|
||||
getStarted = () => api.started
|
||||
)))
|
||||
}
|
||||
|
||||
object Env {
|
||||
|
||||
lazy val current: Env = "relay" boot new Env(
|
||||
db = lila.db.Env.current,
|
||||
config = lila.common.PlayApp loadConfig "relay",
|
||||
studyEnv = lila.study.Env.current,
|
||||
system = lila.common.PlayApp.system
|
||||
)
|
||||
|
|
|
@ -1,11 +1,39 @@
|
|||
package lila.relay
|
||||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
import lila.study.{ Study }
|
||||
import lila.user.User
|
||||
|
||||
case class Relay(
|
||||
studyId: Study.Id,
|
||||
url: String
|
||||
_id: Relay.Id,
|
||||
name: String,
|
||||
description: String,
|
||||
pgnUrl: String,
|
||||
ownerId: User.ID,
|
||||
createdAt: DateTime,
|
||||
startsAt: DateTime,
|
||||
closedAt: Option[DateTime]
|
||||
) {
|
||||
|
||||
override def toString = s"study:$studyId url:$url"
|
||||
def id = _id
|
||||
|
||||
def studyId = Study.Id(id.value)
|
||||
|
||||
override def toString = s"id:$id pgnUrl:$pgnUrl"
|
||||
}
|
||||
|
||||
object Relay {
|
||||
|
||||
case class Id(value: String) extends AnyVal with StringValue
|
||||
|
||||
def makeId = Id(ornicar.scalalib.Random nextString 8)
|
||||
|
||||
case class WithStudy(relay: Relay, study: Study)
|
||||
|
||||
case class Selection(
|
||||
created: List[WithStudy],
|
||||
started: List[WithStudy],
|
||||
closed: List[WithStudy]
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package lila.relay
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import reactivemongo.bson._
|
||||
|
||||
import lila.db.dsl._
|
||||
import lila.study.StudyApi
|
||||
import lila.user.User
|
||||
|
||||
final class RelayApi(
|
||||
coll: Coll,
|
||||
studyApi: StudyApi
|
||||
) {
|
||||
|
||||
import BSONHandlers._
|
||||
|
||||
def byId(id: Relay.Id) = coll.byId[Relay](id.value)
|
||||
|
||||
def all: Fu[Relay.Selection] =
|
||||
created.flatMap(withStudy) zip
|
||||
started.flatMap(withStudy) zip
|
||||
closed.flatMap(withStudy) map {
|
||||
case c ~ s ~ t => Relay.Selection(c, s, t)
|
||||
}
|
||||
|
||||
def created = coll.find($doc(
|
||||
"startsAt" $gt DateTime.now
|
||||
)).sort($sort asc "startsAt").list[Relay]()
|
||||
|
||||
def started = coll.find($doc(
|
||||
"startsAt" $lt DateTime.now,
|
||||
"closedAt" $exists false
|
||||
)).sort($sort asc "startsAt").list[Relay]()
|
||||
|
||||
def closed = coll.find($doc(
|
||||
"closedAt" $exists false
|
||||
)).sort($sort asc "startsAt").list[Relay]()
|
||||
|
||||
def create(data: RelayForm.Data, user: User): Fu[Relay] = {
|
||||
val relay = data make user
|
||||
coll.insert(relay) inject relay
|
||||
}
|
||||
|
||||
private def withStudy(relays: List[Relay]): Fu[List[Relay.WithStudy]] =
|
||||
studyApi byIds relays.map(_.studyId) map { studies =>
|
||||
relays.flatMap { relay =>
|
||||
studies.find(_.id == relay.studyId) map { Relay.WithStudy(relay, _) }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import scala.concurrent.duration._
|
|||
|
||||
private final class RelayFetch(
|
||||
sync: RelaySync,
|
||||
getCurrents: () => Fu[List[Relay]]
|
||||
getStarted: () => Fu[List[Relay]]
|
||||
) extends Actor {
|
||||
|
||||
override def preStart {
|
||||
|
@ -30,9 +30,9 @@ private final class RelayFetch(
|
|||
|
||||
case Tick =>
|
||||
val startAt = nowMillis
|
||||
getCurrents().flatMap {
|
||||
getStarted().flatMap {
|
||||
_.map { relay =>
|
||||
WS.url(relay.url).get().flatMap { res =>
|
||||
WS.url(relay.pgnUrl).get().flatMap { res =>
|
||||
sync(relay, res.body)
|
||||
} recover {
|
||||
case e: Exception =>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package lila.relay
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import play.api.data._
|
||||
import play.api.data.Forms._
|
||||
import play.api.data.validation.Constraints._
|
||||
|
||||
import lila.user.User
|
||||
|
||||
object RelayForm {
|
||||
|
||||
import lila.common.Form.UTCDate._
|
||||
|
||||
val form = Form(mapping(
|
||||
"name" -> nonEmptyText(minLength = 3, maxLength = 80),
|
||||
"description" -> nonEmptyText(minLength = 3, maxLength = 4000),
|
||||
"pgnUrl" -> nonEmptyText,
|
||||
"startsAt" -> utcDate
|
||||
)(Data.apply)(Data.unapply))
|
||||
|
||||
def create = form
|
||||
|
||||
case class Data(
|
||||
name: String,
|
||||
description: String,
|
||||
pgnUrl: String,
|
||||
startsAt: DateTime
|
||||
) {
|
||||
|
||||
def update(relay: Relay) = relay.copy(
|
||||
name = name,
|
||||
description = description,
|
||||
pgnUrl = pgnUrl,
|
||||
startsAt = startsAt
|
||||
)
|
||||
|
||||
def make(user: User) = Relay(
|
||||
_id = Relay.makeId,
|
||||
name = name,
|
||||
description = description,
|
||||
pgnUrl = pgnUrl,
|
||||
ownerId = user.id,
|
||||
createdAt = DateTime.now,
|
||||
startsAt = startsAt,
|
||||
closedAt = none
|
||||
)
|
||||
}
|
||||
|
||||
object Data {
|
||||
|
||||
def make(relay: Relay) = Data(
|
||||
name = relay.name,
|
||||
description = relay.description,
|
||||
pgnUrl = relay.pgnUrl,
|
||||
startsAt = relay.startsAt
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
.relay_form h1.lichess_title {
|
||||
text-align: center;
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
.relay_form textarea.description {
|
||||
height: 10em;
|
||||
}
|
Loading…
Reference in New Issue