allow editing unstarted simuls
parent
c9f014ddd4
commit
7d8bde0195
|
@ -138,7 +138,7 @@ final class Simul(
|
|||
Auth { implicit ctx => me =>
|
||||
NoLameOrBot {
|
||||
apiC.teamsIBelongTo(me) map { teams =>
|
||||
Ok(html.simul.form(forms.create(me), teams))
|
||||
Ok(html.simul.form.create(forms.create(me), teams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ final class Simul(
|
|||
.fold(
|
||||
err =>
|
||||
apiC.teamsIBelongTo(me) map { teams =>
|
||||
BadRequest(html.simul.form(err, teams))
|
||||
BadRequest(html.simul.form.create(err, teams))
|
||||
},
|
||||
setup =>
|
||||
env.simul.api.create(setup, me) map { simul =>
|
||||
|
@ -181,10 +181,44 @@ final class Simul(
|
|||
}
|
||||
}
|
||||
|
||||
def edit(id: String) =
|
||||
Auth { implicit ctx => me =>
|
||||
WithEditableSimul(id, me) { simul =>
|
||||
apiC.teamsIBelongTo(me) map { teams =>
|
||||
Ok(html.simul.form.edit(forms.edit(me, simul), teams, simul))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def update(id: String) =
|
||||
AuthBody { implicit ctx => me =>
|
||||
WithEditableSimul(id, me) { simul =>
|
||||
implicit val req = ctx.body
|
||||
forms
|
||||
.edit(me, simul)
|
||||
.bindFromRequest()
|
||||
.fold(
|
||||
err =>
|
||||
apiC.teamsIBelongTo(me) map { teams =>
|
||||
BadRequest(html.simul.form.edit(err, teams, simul))
|
||||
},
|
||||
data => env.simul.api.update(simul, data) inject Redirect(routes.Simul.show(id))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def AsHost(simulId: Sim.ID)(f: Sim => Fu[Result])(implicit ctx: Context): Fu[Result] =
|
||||
env.simul.repo.find(simulId) flatMap {
|
||||
case None => notFound
|
||||
case Some(simul) if ctx.userId.exists(simul.hostId ==) => f(simul)
|
||||
case _ => fuccess(Unauthorized)
|
||||
case None => notFound
|
||||
case Some(simul) if ctx.userId.has(simul.hostId) || isGranted(_.ManageSimul) => f(simul)
|
||||
case _ => fuccess(Unauthorized)
|
||||
}
|
||||
|
||||
private def WithEditableSimul(id: String, me: lila.user.User)(
|
||||
f: Sim => Fu[Result]
|
||||
)(implicit ctx: Context): Fu[Result] =
|
||||
AsHost(id) { sim =>
|
||||
if (sim.isStarted) Redirect(routes.Simul.show(sim.id)).fuccess
|
||||
else f(sim)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
package views.html.simul
|
||||
|
||||
import controllers.routes
|
||||
import play.api.data.Form
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.app.ui.ScalatagsTemplate._
|
||||
|
||||
import controllers.routes
|
||||
import lila.simul.Simul
|
||||
import lila.hub.LightTeam
|
||||
import lila.simul.SimulForm
|
||||
|
||||
object form {
|
||||
|
||||
def apply(form: Form[lila.simul.SimulForm.Setup], teams: List[lila.hub.LightTeam])(implicit
|
||||
def create(form: Form[SimulForm.Setup], teams: List[LightTeam])(implicit
|
||||
ctx: Context
|
||||
) = {
|
||||
|
||||
import lila.simul.SimulForm._
|
||||
|
||||
) =
|
||||
views.html.base.layout(
|
||||
title = trans.hostANewSimul.txt(),
|
||||
moreCss = cssTag("simul.form")
|
||||
|
@ -27,89 +26,7 @@ object form {
|
|||
p(trans.whenCreateSimul()),
|
||||
br,
|
||||
br,
|
||||
globalError(form),
|
||||
form3.group(form("name"), trans.name()) { f =>
|
||||
div(
|
||||
form3.input(f),
|
||||
" Simul",
|
||||
br,
|
||||
small(cls := "form-help")(trans.inappropriateNameWarning())
|
||||
)
|
||||
},
|
||||
form3.group(form("variant"), trans.simulVariantsHint()) { f =>
|
||||
frag(
|
||||
div(cls := "variants")(
|
||||
views.html.setup.filter.renderCheckboxes(
|
||||
form,
|
||||
"variants",
|
||||
translatedVariantChoicesWithVariants,
|
||||
checks = form.value.??(_.variants.map(_.toString).toSet)
|
||||
)
|
||||
),
|
||||
errMsg(f)
|
||||
)
|
||||
},
|
||||
form3.split(
|
||||
form3.group(
|
||||
form("clockTime"),
|
||||
raw("Clock initial time"),
|
||||
help = trans.simulClockHint().some,
|
||||
half = true
|
||||
)(form3.select(_, clockTimeChoices)),
|
||||
form3.group(form("clockIncrement"), raw("Clock increment"), half = true)(
|
||||
form3.select(_, clockIncrementChoices)
|
||||
)
|
||||
),
|
||||
form3.split(
|
||||
form3.group(
|
||||
form("clockExtra"),
|
||||
trans.simulHostExtraTime(),
|
||||
help = trans.simulAddExtraTime().some,
|
||||
half = true
|
||||
)(
|
||||
form3.select(_, clockExtraChoices)
|
||||
),
|
||||
form3.group(form("color"), raw("Host color for each game"), half = true)(
|
||||
form3.select(_, colorChoices)
|
||||
)
|
||||
),
|
||||
form3.split(
|
||||
(teams.size > 0) ?? {
|
||||
form3.group(form("team"), raw("Only members of team"), half = true)(
|
||||
form3.select(_, List(("", "No Restriction")) ::: teams.map(_.pair))
|
||||
)
|
||||
},
|
||||
form3.group(
|
||||
form("position"),
|
||||
trans.startPosition(),
|
||||
klass = "position",
|
||||
half = true,
|
||||
help = frag("Custom starting position only works with the standard variant.").some
|
||||
) { field =>
|
||||
st.select(
|
||||
id := form3.id(field),
|
||||
st.name := field.name,
|
||||
cls := "form-control"
|
||||
)(
|
||||
option(
|
||||
value := chess.StartingPosition.initial.fen,
|
||||
field.value.has(chess.StartingPosition.initial.fen) option selected
|
||||
)(chess.StartingPosition.initial.name),
|
||||
chess.StartingPosition.categories.map { categ =>
|
||||
optgroup(attr("label") := categ.name)(
|
||||
categ.positions.map { v =>
|
||||
option(value := v.fen, field.value.has(v.fen) option selected)(v.fullName)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
form3.group(
|
||||
form("text"),
|
||||
raw("Simul description"),
|
||||
help = frag("Anything you want to tell the participants?").some
|
||||
)(form3.textarea(_)(rows := 10)),
|
||||
formContent(form, teams, none),
|
||||
form3.actions(
|
||||
a(href := routes.Simul.home())(trans.cancel()),
|
||||
form3.submit(trans.hostANewSimul(), icon = "g".some)
|
||||
|
@ -117,5 +34,114 @@ object form {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
def edit(form: Form[SimulForm.Setup], teams: List[LightTeam], simul: Simul)(implicit
|
||||
ctx: Context
|
||||
) =
|
||||
views.html.base.layout(
|
||||
title = s"Edit ${simul.fullName}",
|
||||
moreCss = cssTag("simul.form")
|
||||
) {
|
||||
main(cls := "box box-pad page-small simul-form")(
|
||||
h1(s"Edit ${simul.fullName}"),
|
||||
postForm(cls := "form3", action := routes.Simul.update(simul.id))(
|
||||
formContent(form, teams, simul.some),
|
||||
form3.actions(
|
||||
a(href := routes.Simul.show(simul.id))(trans.cancel()),
|
||||
form3.submit(trans.save(), icon = "g".some)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private def formContent(form: Form[SimulForm.Setup], teams: List[LightTeam], simul: Option[Simul])(implicit
|
||||
ctx: Context
|
||||
) = {
|
||||
import lila.simul.SimulForm._
|
||||
frag(
|
||||
globalError(form),
|
||||
form3.group(form("name"), trans.name()) { f =>
|
||||
div(
|
||||
form3.input(f),
|
||||
" Simul",
|
||||
br,
|
||||
small(cls := "form-help")(trans.inappropriateNameWarning())
|
||||
)
|
||||
},
|
||||
form3.group(form("variant"), trans.simulVariantsHint()) { f =>
|
||||
frag(
|
||||
div(cls := "variants")(
|
||||
views.html.setup.filter.renderCheckboxes(
|
||||
form,
|
||||
"variants",
|
||||
translatedVariantChoicesWithVariants,
|
||||
checks = form.value.??(_.variants.map(_.toString).toSet)
|
||||
)
|
||||
),
|
||||
errMsg(f)
|
||||
)
|
||||
},
|
||||
form3.split(
|
||||
form3.group(
|
||||
form("clockTime"),
|
||||
raw("Clock initial time"),
|
||||
help = trans.simulClockHint().some,
|
||||
half = true
|
||||
)(form3.select(_, clockTimeChoices)),
|
||||
form3.group(form("clockIncrement"), raw("Clock increment"), half = true)(
|
||||
form3.select(_, clockIncrementChoices)
|
||||
)
|
||||
),
|
||||
form3.split(
|
||||
form3.group(
|
||||
form("clockExtra"),
|
||||
trans.simulHostExtraTime(),
|
||||
help = trans.simulAddExtraTime().some,
|
||||
half = true
|
||||
)(
|
||||
form3.select(_, clockExtraChoices)
|
||||
),
|
||||
form3.group(form("color"), raw("Host color for each game"), half = true)(
|
||||
form3.select(_, colorChoices)
|
||||
)
|
||||
),
|
||||
form3.split(
|
||||
(teams.size > 0) ?? {
|
||||
form3.group(form("team"), raw("Only members of team"), half = true)(
|
||||
form3.select(_, List(("", "No Restriction")) ::: teams.map(_.pair))
|
||||
)
|
||||
},
|
||||
form3.group(
|
||||
form("position"),
|
||||
trans.startPosition(),
|
||||
klass = "position",
|
||||
half = true,
|
||||
help = frag("Custom starting position only works with the standard variant.").some
|
||||
) { field =>
|
||||
st.select(
|
||||
id := form3.id(field),
|
||||
st.name := field.name,
|
||||
cls := "form-control"
|
||||
)(
|
||||
option(
|
||||
value := chess.StartingPosition.initial.fen,
|
||||
field.value.has(chess.StartingPosition.initial.fen) option selected
|
||||
)(chess.StartingPosition.initial.name),
|
||||
chess.StartingPosition.categories.map { categ =>
|
||||
optgroup(attr("label") := categ.name)(
|
||||
categ.positions.map { v =>
|
||||
option(value := v.fen, field.value.has(v.fen) option selected)(v.fullName)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
form3.group(
|
||||
form("text"),
|
||||
raw("Simul description"),
|
||||
help = frag("Anything you want to tell the participants?").some
|
||||
)(form3.textarea(_)(rows := 10))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package views.html.simul
|
||||
|
||||
import controllers.routes
|
||||
import play.api.libs.json.Json
|
||||
|
||||
import lila.api.Context
|
||||
|
@ -7,8 +8,6 @@ import lila.app.templating.Environment._
|
|||
import lila.app.ui.ScalatagsTemplate._
|
||||
import lila.common.String.html.safeJsonValue
|
||||
|
||||
import controllers.routes
|
||||
|
||||
object show {
|
||||
|
||||
def apply(
|
||||
|
@ -59,7 +58,11 @@ object show {
|
|||
div(cls := "setup")(
|
||||
sim.variants.map(_.name).mkString(", "),
|
||||
" • ",
|
||||
trans.casual()
|
||||
trans.casual(),
|
||||
ctx.userId.has(sim.hostId) option frag(
|
||||
" • ",
|
||||
a(href := routes.Simul.edit(sim.id), title := "Edit simul")(iconTag("%"))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -267,6 +267,8 @@ GET /simul/new controllers.Simul.form
|
|||
POST /simul/new controllers.Simul.create
|
||||
GET /simul/reload controllers.Simul.homeReload
|
||||
GET /simul/$id<\w{8}> controllers.Simul.show(id: String)
|
||||
GET /simul/$id<\w{8}>/edit controllers.Simul.edit(id: String)
|
||||
POST /simul/$id<\w{8}>/edit controllers.Simul.update(id: String)
|
||||
POST /simul/$id<\w{8}>/host-ping controllers.Simul.hostPing(id: String)
|
||||
POST /simul/$id<\w{8}>/accept/:user controllers.Simul.accept(id: String, user: String)
|
||||
POST /simul/$id<\w{8}>/reject/:user controllers.Simul.reject(id: String, user: String)
|
||||
|
@ -274,7 +276,6 @@ POST /simul/$id<\w{8}>/start controllers.Simul.start(id: String
|
|||
POST /simul/$id<\w{8}>/abort controllers.Simul.abort(id: String)
|
||||
POST /simul/$id<\w{8}>/join/:variant controllers.Simul.join(id: String, variant: String)
|
||||
POST /simul/$id<\w{8}>/withdraw controllers.Simul.withdraw(id: String)
|
||||
POST /simul/$id<\w{8}>/set-text controllers.Simul.setText(id: String)
|
||||
|
||||
# Team
|
||||
GET /team controllers.Team.home(page: Int ?= 1)
|
||||
|
|
|
@ -39,6 +39,7 @@ object Permission {
|
|||
case object ManageTeam extends Permission("MANAGE_TEAM", "Manage teams")
|
||||
case object ManageTournament extends Permission("MANAGE_TOURNAMENT", "Manage tournaments")
|
||||
case object ManageEvent extends Permission("MANAGE_EVENT", "Manage events")
|
||||
case object ManageSimul extends Permission("MANAGE_SIMUL", "Manage simuls")
|
||||
case object ChangePermission extends Permission("CHANGE_PERMISSION", "Change permissions")
|
||||
case object PublicMod extends Permission("PUBLIC_MOD", "Mod badge")
|
||||
case object Developer extends Permission("DEVELOPER", "Developer badge")
|
||||
|
@ -131,6 +132,7 @@ object Permission {
|
|||
SetEmail,
|
||||
ManageTeam,
|
||||
ManageTournament,
|
||||
ManageSimul,
|
||||
ManageEvent,
|
||||
PracticeConfig,
|
||||
RemoveRanking,
|
||||
|
@ -199,6 +201,7 @@ object Permission {
|
|||
Relay,
|
||||
ManageEvent,
|
||||
ManageTournament,
|
||||
ManageSimul,
|
||||
StudyAdmin,
|
||||
PracticeConfig
|
||||
),
|
||||
|
|
|
@ -50,16 +50,9 @@ final class SimulApi(
|
|||
def create(setup: SimulForm.Setup, me: User): Fu[Simul] = {
|
||||
val simul = Simul.make(
|
||||
name = setup.name,
|
||||
clock = SimulClock(
|
||||
config = chess.Clock.Config(setup.clockTime * 60, setup.clockIncrement),
|
||||
hostExtraTime = setup.clockExtra * 60
|
||||
),
|
||||
variants = setup.variants.flatMap { chess.variant.Variant(_) },
|
||||
position = setup.position
|
||||
.map {
|
||||
SimulForm.startingPosition(_, chess.variant.Standard)
|
||||
}
|
||||
.filterNot(_.initial),
|
||||
clock = setup.clock,
|
||||
variants = setup.actualVariants,
|
||||
position = setup.actualPosition,
|
||||
host = me,
|
||||
color = setup.color,
|
||||
text = setup.text,
|
||||
|
@ -70,6 +63,19 @@ final class SimulApi(
|
|||
} inject simul
|
||||
}
|
||||
|
||||
def update(prev: Simul, setup: SimulForm.Setup): Fu[Simul] = {
|
||||
val simul = prev.copy(
|
||||
name = setup.name,
|
||||
clock = setup.clock,
|
||||
variants = setup.actualVariants,
|
||||
position = setup.actualPosition,
|
||||
color = setup.color.some,
|
||||
text = setup.text,
|
||||
team = setup.team
|
||||
)
|
||||
repo.update(simul) >>- publish() inject simul
|
||||
}
|
||||
|
||||
def addApplicant(simulId: Simul.ID, user: User, variantKey: String): Funit =
|
||||
WithSimul(repo.findCreated, simulId) { simul =>
|
||||
if (simul.nbAccepted >= Game.maxPlayingRealtime) simul
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package lila.simul
|
||||
|
||||
import chess.StartingPosition
|
||||
import play.api.data._
|
||||
import play.api.data.Forms._
|
||||
import play.api.data.validation.{ Constraint, Constraints }
|
||||
import lila.user.User
|
||||
|
||||
import chess.StartingPosition
|
||||
import lila.common.Form._
|
||||
import lila.user.User
|
||||
|
||||
object SimulForm {
|
||||
|
||||
|
@ -60,6 +60,32 @@ object SimulForm {
|
|||
)
|
||||
|
||||
def create(host: User) =
|
||||
baseForm(host) fill Setup(
|
||||
name = host.titleUsername,
|
||||
clockTime = clockTimeDefault,
|
||||
clockIncrement = clockIncrementDefault,
|
||||
clockExtra = clockExtraDefault,
|
||||
variants = List(chess.variant.Standard.id),
|
||||
position = StartingPosition.initial.fen.some,
|
||||
color = colorDefault,
|
||||
text = "",
|
||||
team = none
|
||||
)
|
||||
|
||||
def edit(host: User, simul: Simul) =
|
||||
baseForm(host) fill Setup(
|
||||
name = simul.name,
|
||||
clockTime = simul.clock.config.limitInMinutes.toInt,
|
||||
clockIncrement = simul.clock.config.increment.roundSeconds,
|
||||
clockExtra = simul.clock.hostExtraMinutes,
|
||||
variants = simul.variants.map(_.id),
|
||||
position = simul.position.map(_.fen),
|
||||
color = simul.color | "random",
|
||||
text = simul.text,
|
||||
team = simul.team
|
||||
)
|
||||
|
||||
private def baseForm(host: User) =
|
||||
Form(
|
||||
mapping(
|
||||
"name" -> nameType(host),
|
||||
|
@ -86,16 +112,6 @@ object SimulForm {
|
|||
"text" -> clean(text),
|
||||
"team" -> optional(nonEmptyText)
|
||||
)(Setup.apply)(Setup.unapply)
|
||||
) fill Setup(
|
||||
name = host.titleUsername,
|
||||
clockTime = clockTimeDefault,
|
||||
clockIncrement = clockIncrementDefault,
|
||||
clockExtra = clockExtraDefault,
|
||||
variants = List(chess.variant.Standard.id),
|
||||
position = StartingPosition.initial.fen.some,
|
||||
color = colorDefault,
|
||||
text = "",
|
||||
team = none
|
||||
)
|
||||
|
||||
val positions = StartingPosition.allWithInitial.map(_.fen)
|
||||
|
@ -119,5 +135,20 @@ object SimulForm {
|
|||
color: String,
|
||||
text: String,
|
||||
team: Option[String]
|
||||
)
|
||||
) {
|
||||
def clock =
|
||||
SimulClock(
|
||||
config = chess.Clock.Config(clockTime * 60, clockIncrement),
|
||||
hostExtraTime = clockExtra * 60
|
||||
)
|
||||
|
||||
def actualPosition =
|
||||
position
|
||||
.map {
|
||||
startingPosition(_, chess.variant.Standard)
|
||||
}
|
||||
.filterNot(_.initial)
|
||||
|
||||
def actualVariants = variants.flatMap { chess.variant.Variant(_) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ $chat-height: calc(90vh - 300px);
|
|||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
i {
|
||||
> i {
|
||||
font-size: 2.5em;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
var socket = require('./socket');
|
||||
var simul = require('./simul');
|
||||
var text = require('./text');
|
||||
var xhr = require('./xhr');
|
||||
|
||||
module.exports = function(env) {
|
||||
|
@ -12,7 +11,6 @@ module.exports = function(env) {
|
|||
this.userId = env.userId;
|
||||
|
||||
this.socket = new socket(env.socketSend, this);
|
||||
this.text = text.ctrl();
|
||||
|
||||
this.reload = function(data) {
|
||||
if (this.data.isCreated && !data.isCreated) {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
var m = require('mithril');
|
||||
var simul = require('./simul');
|
||||
var xhr = require('./xhr');
|
||||
|
||||
function enrichText(text) {
|
||||
return m.trust(autolink(lichess.escapeHtml(text), toLink).replace(newLineRegex, '<br>'));
|
||||
|
@ -15,43 +13,8 @@ function toLink(url) {
|
|||
var linkRegex = /(^|[\s\n]|<[A-Za-z]*\/?>)((?:https?|ftp):\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/gi;
|
||||
var newLineRegex = /\n/g;
|
||||
|
||||
function editor(ctrl) {
|
||||
return m('div.editor', [
|
||||
m('button.button.button-empty.open', {
|
||||
onclick: ctrl.text.toggle
|
||||
}, 'Edit'),
|
||||
ctrl.text.editing () ? m('form', {
|
||||
onsubmit: function(e) {
|
||||
xhr.setText(ctrl, e.target.querySelector('textarea').value);
|
||||
ctrl.text.toggle();
|
||||
return false;
|
||||
}
|
||||
}, [
|
||||
m('textarea', ctrl.data.text),
|
||||
m('button.button.save', {
|
||||
type: 'submit'
|
||||
}, 'Save')
|
||||
]) : null
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ctrl: function() {
|
||||
var editing = false;
|
||||
return {
|
||||
toggle: function() {
|
||||
editing = !editing;
|
||||
},
|
||||
editing: function() {
|
||||
return editing;
|
||||
}
|
||||
};
|
||||
},
|
||||
view: function(ctrl) {
|
||||
return ctrl.data.text || simul.createdByMe(ctrl) ?
|
||||
m('div.simul-text' + (ctrl.text.editing() ? '.editing' : ''), [
|
||||
m('p', enrichText(ctrl.data.text)),
|
||||
simul.createdByMe(ctrl) ? editor(ctrl) : null
|
||||
]) : null;
|
||||
return ctrl.data.text ? m('div.simul-text', m('p', enrichText(ctrl.data.text))) : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,15 +35,5 @@ module.exports = {
|
|||
},
|
||||
reject: function(user) {
|
||||
return partial(simulAction, 'reject/' + user)
|
||||
},
|
||||
setText: function(ctrl, text) {
|
||||
return m.request({
|
||||
method: 'POST',
|
||||
url: '/simul/' + ctrl.data.id + '/set-text',
|
||||
config: xhrConfig,
|
||||
data: {
|
||||
text: text
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue