Merge branch 'master' into crosstable3
* master: fix and restore activity truncation tweak ublog paginator max pages prevent arena berserk if inc > limit*2 separate cancel from terminate buttons Use oninput instead of onkeyup & onpaste prettier Flatten rating line to todaycrosstable3
commit
62ffcb7710
|
@ -235,7 +235,7 @@ final class Ublog(env: Env) extends LilaController(env) {
|
|||
def community(code: String, page: Int) = Open { implicit ctx =>
|
||||
NotForKids {
|
||||
val l = Lang.get(code).filter(LangList.popularNoRegion.contains)
|
||||
Reasonable(page, 20) {
|
||||
Reasonable(page, 8) {
|
||||
env.ublog.paginator.liveByCommunity(l, page) map { posts =>
|
||||
Ok(html.ublog.index.community(l, posts))
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ final class Ublog(env: Env) extends LilaController(env) {
|
|||
|
||||
def topic(str: String, page: Int) = Open { implicit ctx =>
|
||||
NotForKids {
|
||||
Reasonable(page, 15) {
|
||||
Reasonable(page, 5) {
|
||||
lila.ublog.UblogTopic.fromUrl(str) ?? { top =>
|
||||
env.ublog.paginator.liveByTopic(top, page) map { posts =>
|
||||
Ok(html.ublog.index.topic(top, posts))
|
||||
|
|
|
@ -84,6 +84,9 @@ object form {
|
|||
form3.submit(trans.save(), icon = "".some)
|
||||
)
|
||||
),
|
||||
hr,
|
||||
br,
|
||||
br,
|
||||
postForm(cls := "terminate", action := routes.Tournament.terminate(tour.id))(
|
||||
submitButton(dataIcon := "", cls := "text button button-red confirm")(
|
||||
trans.cancelTournament()
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package lila.activity
|
||||
|
||||
import reactivemongo.api.bson._
|
||||
|
||||
import lila.db.AsyncCollFailingSilently
|
||||
import lila.db.dsl._
|
||||
import lila.game.Game
|
||||
|
@ -152,9 +154,9 @@ final class ActivityWriteApi(
|
|||
!setters.isEmpty ?? {
|
||||
coll.update
|
||||
.one($id(activity.id), $set(setters), upsert = true)
|
||||
// .flatMap {
|
||||
// _.upserted.nonEmpty ?? truncateAfterInserting(coll, activity.id)
|
||||
// }
|
||||
.flatMap {
|
||||
_.upserted.nonEmpty ?? truncateAfterInserting(coll, activity.id)
|
||||
}
|
||||
.void
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +172,16 @@ final class ActivityWriteApi(
|
|||
.one[Bdoc]
|
||||
.flatMap {
|
||||
_.flatMap(_.getAsOpt[Activity.Id]("_id")) ?? { oldId =>
|
||||
coll.delete.one($doc("_id" $lte oldId)).void
|
||||
coll.delete
|
||||
.one(
|
||||
$doc(
|
||||
"_id" -> $doc(
|
||||
"$lte" -> oldId,
|
||||
"$regex" -> BSONRegex(s"^${id.userId}$idSep", "")
|
||||
)
|
||||
)
|
||||
)
|
||||
.void
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@ private object BSONHandlers {
|
|||
import activities._
|
||||
import model._
|
||||
|
||||
def regexId(userId: User.ID): Bdoc = "_id" $startsWith s"$userId:"
|
||||
val idSep = ':'
|
||||
def regexId(userId: User.ID): Bdoc = "_id" $startsWith s"$userId$idSep"
|
||||
|
||||
implicit lazy val activityIdHandler = {
|
||||
val sep = ':'
|
||||
tryHandler[Id](
|
||||
{ case BSONString(v) =>
|
||||
v split sep match {
|
||||
v split idSep match {
|
||||
case Array(userId, dayStr) => Success(Id(userId, Day(Integer.parseInt(dayStr))))
|
||||
case _ => handlerBadValue(s"Invalid activity id $v")
|
||||
}
|
||||
},
|
||||
id => BSONString(s"${id.userId}$sep${id.day.value}")
|
||||
id => BSONString(s"${id.userId}$idSep${id.day.value}")
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ final class TournamentApi(
|
|||
password = setup.password,
|
||||
variant = setup.realVariant,
|
||||
position = setup.realPosition,
|
||||
berserkable = setup.berserkable | true,
|
||||
berserkable = setup.isBerserkable,
|
||||
streakable = setup.streakable | true,
|
||||
teamBattle = setup.teamBattleByTeam map TeamBattle.init,
|
||||
description = setup.description,
|
||||
|
|
|
@ -203,6 +203,13 @@ private[tournament] case class TournamentSetup(
|
|||
|
||||
def isPrivate = password.isDefined || conditions.teamMember.isDefined
|
||||
|
||||
// prevent berserk tournament abuse with TC like 1+60,
|
||||
// where perf is Classical but berserked games are Hyperbullet.
|
||||
private def timeControlPreventsBerserk =
|
||||
clockConfig.incrementSeconds > clockConfig.limitInMinutes * 2
|
||||
|
||||
def isBerserkable = ~berserkable && !timeControlPreventsBerserk
|
||||
|
||||
// update all fields and use default values for missing fields
|
||||
// meant for HTML form updates
|
||||
def updateAll(old: Tournament): Tournament = {
|
||||
|
@ -220,7 +227,7 @@ private[tournament] case class TournamentSetup(
|
|||
if (old.isCreated || old.position.isDefined) realPosition
|
||||
else old.position
|
||||
},
|
||||
noBerserk = !(~berserkable),
|
||||
noBerserk = !isBerserkable,
|
||||
noStreak = !(~streakable),
|
||||
teamBattle = old.teamBattle,
|
||||
description = description,
|
||||
|
@ -245,7 +252,7 @@ private[tournament] case class TournamentSetup(
|
|||
if (position.isDefined && (old.isCreated || old.position.isDefined)) realPosition
|
||||
else old.position
|
||||
},
|
||||
noBerserk = berserkable.fold(old.noBerserk)(!_),
|
||||
noBerserk = berserkable.fold(old.noBerserk)(!_) || timeControlPreventsBerserk,
|
||||
noStreak = streakable.fold(old.noStreak)(!_),
|
||||
teamBattle = old.teamBattle,
|
||||
description = description.fold(old.description)(_.some.filter(_.nonEmpty)),
|
||||
|
|
|
@ -2,6 +2,14 @@ lichess.ratingHistoryChart = function (data, { singlePerfName, perfIndex }) {
|
|||
var oneDay = 86400000;
|
||||
function smoothDates(data) {
|
||||
if (!data.length) return [];
|
||||
|
||||
// If last rating wasn't today, add to the array
|
||||
var today = new Date().setUTCHours(0, 0, 0, 0);
|
||||
var lastRating = data[data.length - 1];
|
||||
if (lastRating[0] != today) {
|
||||
data.push([today, lastRating[1]]);
|
||||
}
|
||||
|
||||
var begin = data[0][0];
|
||||
var end = data[data.length - 1][0];
|
||||
var reversed = data.slice().reverse();
|
||||
|
|
|
@ -112,10 +112,7 @@ export function view(root: AnalyseCtrl): VNode {
|
|||
insert(vnode) {
|
||||
setupTextarea(vnode);
|
||||
const el = vnode.elm as HTMLInputElement;
|
||||
function onChange() {
|
||||
setTimeout(() => ctrl.submit(el.value), 50);
|
||||
}
|
||||
el.onkeyup = el.onpaste = onChange;
|
||||
el.oninput = () => setTimeout(() => ctrl.submit(el.value), 50);
|
||||
},
|
||||
postpatch: (old, vnode) => setupTextarea(vnode, old),
|
||||
},
|
||||
|
|
|
@ -102,7 +102,7 @@ function edit(ctrl: DescriptionCtrl, id: string, chapter: boolean): VNode {
|
|||
h('textarea#form-control.desc-text.' + id, {
|
||||
hook: onInsert<HTMLInputElement>(el => {
|
||||
el.value = ctrl.text === '-' ? '' : ctrl.text || '';
|
||||
el.onkeyup = el.onpaste = () => {
|
||||
el.oninput = () => {
|
||||
ctrl.save(el.value.trim());
|
||||
};
|
||||
el.focus();
|
||||
|
|
|
@ -171,7 +171,7 @@ function textareaHook(ctrl: AnalyseCtrl, field: 'deviation' | 'hint'): Hooks {
|
|||
insert(vnode: VNode) {
|
||||
const el = vnode.elm as HTMLInputElement;
|
||||
el.value = value;
|
||||
el.onkeyup = el.onpaste = () => {
|
||||
el.oninput = () => {
|
||||
const node = ctrl.node;
|
||||
node.gamebook = node.gamebook || {};
|
||||
node.gamebook[field] = el.value.trim();
|
||||
|
|
Loading…
Reference in New Issue