implement user tournament custom start date - closes #4353

pull/4366/head
Thibault Duplessis 2018-05-11 18:47:45 -05:00
parent babf2c5819
commit 680759f946
11 changed files with 56 additions and 22 deletions

View File

@ -226,7 +226,9 @@ object Tournament extends LilaController {
html = env.forms(me).bindFromRequest.fold(
err => BadRequest(html.tournament.form(err, env.forms, me)).fuccess,
setup => {
val cost = if (me.hasTitle || Env.streamer.liveStreamApi.isStreaming(me.id)) 1 else 4
val cost = if (me.hasTitle ||
Env.streamer.liveStreamApi.isStreaming(me.id) ||
isGranted(_.ManageTournament)) 1 else 4
CreateLimitPerUser(me.id, cost = 1) {
CreateLimitPerIP(HTTPRequest lastRemoteAddress ctx.req, cost = 1) {
env.api.createTournament(setup, me) map { tour =>

View File

@ -7,7 +7,7 @@
}
@moreJs = {
@jsAt("vendor/flatpickr/dist/flatpickr.min.js")
@flatpickrTag
@embedJs {
$(".flatpickr").flatpickr();
}

View File

@ -7,7 +7,7 @@
}
@moreJs = {
@jsAt("vendor/flatpickr/dist/flatpickr.min.js")
@flatpickrTag
@embedJs {
$(".flatpickr").flatpickr();
}

View File

@ -1,15 +1,15 @@
@(title: String)(body: Html)(implicit ctx: Context)
@moreCss = {
@cssAt("vendor/flatpickr/dist/flatpickr.min.css")
@cssTag("flatpickr.css")
@cssTag("material.form.css")
@cssTag("tournament.crud.css")
}
@moreJs = {
@jsAt("vendor/flatpickr/dist/flatpickr.min.js")
@flatpickrTag
@embedJs {
$(".flatpickr").flatpickr();
$(function() { $(".flatpickr").flatpickr(); })
}
}

View File

@ -4,11 +4,13 @@
@import lila.tournament.DataForm._
@moreJs = {
@flatpickrTag
@jsTag("tournamentForm.js")
}
@moreCss = {
@cssTag("tournament.form.css")
@cssTag("flatpickr.css")
@cssTag("material.form.css")
@cssTag("tournament.form.css")
}
@tournament.layout(
@ -40,7 +42,7 @@ moreJs = moreJs) {
@base.form.input(form("name")) Arena<br />
@errMsg(form("name"))
<strong>@trans.safeTournamentName()<br />
@trans.inappropriateNameWarning()</strong><br />
@trans.inappropriateNameWarning()</strong><br />
@trans.emptyTournamentName()
</td>
</tr>
@ -85,6 +87,9 @@ moreJs = moreJs) {
</p>
<div class="material form">
@tournament.conditionForm(form, auto = true)
@base.form.group(form("startDate"), Html("Custom start date"), help = Html("""This overrides the "Time before tournament starts" setting""").some) { field =>
@base.form.flatpickr(field)
}
</div>
</fieldset>
<button type="submit" class="submit button" data-icon="g">

View File

@ -7,34 +7,36 @@ import play.api.data.Forms._
object Form {
def options(it: Iterable[Int], pattern: String) = it map { d =>
type Options[A] = Iterable[(A, String)]
def options(it: Iterable[Int], pattern: String): Options[Int] = it map { d =>
d -> (pluralize(pattern, d) format d)
}
def options(it: Iterable[Int], transformer: Int => Int, pattern: String) = it map { d =>
def options(it: Iterable[Int], transformer: Int => Int, pattern: String): Options[Int] = it map { d =>
d -> (pluralize(pattern, transformer(d)) format transformer(d))
}
def options(it: Iterable[Int], code: String, pattern: String) = it map { d =>
def options(it: Iterable[Int], code: String, pattern: String): Options[String] = it map { d =>
(d + code) -> (pluralize(pattern, d) format d)
}
def optionsDouble(it: Iterable[Double], format: Double => String) = it map { d =>
def optionsDouble(it: Iterable[Double], format: Double => String): Options[Double] = it map { d =>
d -> format(d)
}
def numberIn(choices: Iterable[(Int, String)]) =
def numberIn(choices: Options[Int]) =
number.verifying(hasKey(choices, _))
def numberInDouble(choices: Iterable[(Double, String)]) =
def numberInDouble(choices: Options[Double]) =
of[Double].verifying(hasKey(choices, _))
def stringIn(choices: Iterable[(String, String)]) =
def stringIn(choices: Options[String]) =
text.verifying(hasKey(choices, _))
def tolerantBoolean = of[Boolean](formatter.tolerantBooleanFormatter)
def hasKey[A](choices: Iterable[(A, _)], key: A) =
def hasKey[A](choices: Options[A], key: A) =
choices.map(_._1).toList contains key
def trueish(v: Any) = v == 1 || v == "1" || v == "true" || v == "on" || v == "yes"
@ -66,4 +68,9 @@ object Form {
val utcDate = jodaDate(dateTimePattern, DateTimeZone.UTC)
implicit val dateTimeFormat = jodaDateTimeFormat(dateTimePattern)
}
object ISODate {
val dateTimePattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
val isoDate = jodaDate(dateTimePattern, DateTimeZone.UTC)
implicit val dateTimeFormat = jodaDateTimeFormat(dateTimePattern)
}
}

View File

@ -1,5 +1,6 @@
package lila.tournament
import org.joda.time.DateTime
import play.api.data._
import play.api.data.Forms._
import play.api.data.validation.Constraints
@ -7,6 +8,7 @@ import play.api.data.validation.Constraints
import chess.Mode
import chess.StartingPosition
import lila.common.Form._
import lila.common.Form.ISODate._
import lila.user.User
final class DataForm {
@ -19,6 +21,7 @@ final class DataForm {
clockIncrement = clockIncrementDefault,
minutes = minuteDefault,
waitMinutes = waitMinuteDefault.some,
startDate = none,
variant = chess.variant.Standard.key.some,
position = StartingPosition.initial.fen.some,
`private` = false,
@ -43,6 +46,7 @@ final class DataForm {
"clockIncrement" -> numberIn(clockIncrementPrivateChoices),
"minutes" -> numberIn(minutePrivateChoices),
"waitMinutes" -> optional(numberIn(waitMinuteChoices)),
"startDate" -> optional(isoDate),
"variant" -> optional(nonEmptyText.verifying(v => guessVariant(v).isDefined)),
"position" -> optional(nonEmptyText),
"mode" -> optional(number.verifying(Mode.all map (_.id) contains _)),
@ -114,6 +118,7 @@ private[tournament] case class TournamentSetup(
clockIncrement: Int,
minutes: Int,
waitMinutes: Option[Int],
startDate: Option[DateTime],
variant: Option[String],
position: Option[String],
mode: Option[Int],

View File

@ -143,6 +143,7 @@ object Tournament {
`private`: Boolean,
password: Option[String],
waitMinutes: Int,
startDate: Option[DateTime],
berserkable: Boolean
) = Tournament(
id = Random nextString 8,
@ -165,7 +166,9 @@ object Tournament {
conditions = Condition.All.empty,
noBerserk = !berserkable,
schedule = None,
startsAt = DateTime.now plusMinutes waitMinutes
startsAt = startDate | {
DateTime.now plusMinutes waitMinutes
}
)
def schedule(sched: Schedule, minutes: Int) = Tournament(

View File

@ -51,6 +51,7 @@ final class TournamentApi(
clock = setup.clockConfig,
minutes = setup.minutes,
waitMinutes = setup.waitMinutes | DataForm.waitMinuteDefault,
startDate = setup.startDate,
mode = setup.realMode,
`private` = setup.`private`,
password = setup.password ifTrue setup.`private`,

View File

@ -47,6 +47,7 @@ final class CrudApi {
`private` = false,
password = None,
waitMinutes = 0,
startDate = none,
berserkable = true
)

View File

@ -4,11 +4,11 @@ $(function() {
var $minutes = $('#tournament tr.minutes td');
function replace($el, $paste) {
var prvVal = $el.children().first().val();
$el.html($paste.html());
if (prvVal) {
$el.children().first().val(prvVal);
}
var prvVal = $el.children().first().val();
$el.html($paste.html());
if (prvVal) {
$el.children().first().val(prvVal);
}
}
function showPrivate() {
@ -38,4 +38,14 @@ $(function() {
$(this).remove();
$('.conditions .form').show();
});
$('.conditions .form').show();
$(".flatpickr").flatpickr({
enableTime: true,
minDate: 'today',
maxDate: new Date().fp_incr(31),
dateFormat: 'Z',
altInput: true,
altFormat: 'Y-m-d h:i K'
});
});