Skip to content

Commit

Permalink
Merge branch 'master' into more-trans-on-blog-page
Browse files Browse the repository at this point in the history
* master: (43 commits)
  simplify and redesign challenge page QR code
  fix /video 404 page - closes lichess-org#14262
  Move classification flairs (fixes lichess-org#14264 ) (lichess-org#14265)
  add puzzle theme translation keys to the streak page - closes lichess-org#14273
  fix ui storage must remove the birthday key on expiration
  rename and factor ui storage birthday key
  New Crowdin updates (lichess-org#14271)
  hard coded ttl always
  remove unused function
  persistent log ws failures
  switch from xz to zstd for artifacts
  fix deploy after artifacts v4 update
  update to potentially much faster upload-artifact v4
  scala tweak, use form3.submit
  remove code duplication in ublog post ranking
  make it a bit clearer which fields are required when recomputing upost rank
  fix ublog post ranking when there is no rankAdjustDays
  don't confuse user with mod in mod log
  simplify using post.created.by
  tweak default broadcast pull periods
  ...
  • Loading branch information
ornicar committed Dec 23, 2023
2 parents c108c3b + 3754b00 commit 5afc0bf
Show file tree
Hide file tree
Showing 90 changed files with 710 additions and 340 deletions.
9 changes: 4 additions & 5 deletions .github/workflows/assets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@ jobs:
- run: ./ui/build --no-install -p
- run: cd ui && pnpm run test && cd -
- run: mkdir assets && mv public assets/ && cp bin/download-lifat LICENSE COPYING.md README.md assets/ && git log -n 1 --pretty=oneline > assets/commit.txt
- run: cd assets && tar -cvpJf ../assets.tar.xz . && cd -
env:
XZ_OPT: '-0'
- uses: actions/upload-artifact@v3
- run: cd assets && tar --zstd -cvpf ../assets.tar.zst . && cd -
- uses: actions/upload-artifact@v4
with:
name: lila-assets
path: assets.tar.xz
path: assets.tar.zst
compression-level: 0 # already compressed
9 changes: 5 additions & 4 deletions .github/workflows/server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ jobs:
- run: TZ=UTC git log -1 --date=iso-strict-local --pretty='format:app.version.commit = "%H"%napp.version.date = "%ad"%napp.version.message = """%s"""%n' | tee conf/version.conf
- run: ./lila -Depoll=true "test;stage"
- run: cp LICENSE COPYING.md README.md target/universal/stage && git log -n 1 --pretty=oneline > target/universal/stage/commit.txt
- run: cd target/universal/stage && tar -cvpJf ../../../lila-3.0.tar.xz . && cd -
- run: cd target/universal/stage && tar --zstd -cvpf ../../../lila-3.0.tar.zst . && cd -
env:
XZ_OPT: '-0'
- uses: actions/upload-artifact@v3
ZSTD_LEVEL: 1 # most files are already zipped
- uses: actions/upload-artifact@v4
with:
name: lila-server
path: lila-3.0.tar.xz
path: lila-3.0.tar.zst
compression-level: 0 # already compressed
5 changes: 4 additions & 1 deletion app/controllers/Dev.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ final class Dev(env: Env) extends LilaController(env):
env.tutor.nbAnalysisSetting,
env.tutor.parallelismSetting,
env.firefoxOriginTrial,
env.credentiallessUaRegex
env.credentiallessUaRegex,
env.relay.proxyDomainRegex,
env.relay.proxyHostPort,
env.relay.proxyCredentials
)

def settings = Secure(_.Settings) { _ ?=> _ ?=>
Expand Down
19 changes: 19 additions & 0 deletions app/controllers/Ublog.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package controllers

import play.api.i18n.Lang
import play.api.data.Form
import play.api.data.Forms.*
import views.*

import lila.app.{ given, * }
Expand Down Expand Up @@ -188,6 +190,23 @@ final class Ublog(env: Env) extends LilaController(env):
)
}

def rankAdjust(postId: String) = SecureBody(_.ModerateBlog) { ctx ?=> me ?=>
Found(env.ublog.api.getPost(UblogPostId(postId))): post =>
Form:
single:
"value" -> optional(number)
.bindFromRequest()
.fold(
_ => Redirect(urlOfPost(post)).flashFailure,
rankAdjustDays =>
for
_ <- env.ublog.api.setRankAdjust(post.id, ~rankAdjustDays)
_ <- env.mod.logApi.ublogRankAdjust(post.created.by, post.id, ~rankAdjustDays)
_ <- env.ublog.rank.recomputePostRank(post)
yield Redirect(urlOfPost(post)).flashSuccess
)
}

private val ImageRateLimitPerIp = lila.memo.RateLimit.composite[lila.common.IpAddress](
key = "ublog.image.ip"
)(
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/Video.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ final class Video(env: Env) extends LilaController(env):

def show(id: String) = Open:
WithUserControl: control =>
api.video.find(id) flatMap {
api.video.find(id) flatMap:
case None => NotFound.page(html.video.bits.notFound(control))
case Some(video) =>
api.video.similar(ctx.me, video, 9) zip
Expand All @@ -46,7 +46,6 @@ final class Video(env: Env) extends LilaController(env):
} flatMap { (similar, _) =>
Ok.page(html.video.show(video, similar, control))
}
}

def author(author: String) = Open:
WithUserControl: control =>
Expand Down
9 changes: 8 additions & 1 deletion app/views/challenge/mine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object mine:
else
div(cls := "invite")(
div(
h2(cls := "ninja-title", trans.toInviteSomeoneToPlayGiveThisUrl(), ": "),
h2(cls := "ninja-title", trans.toInviteSomeoneToPlayGiveThisUrl()),
br,
p(cls := "challenge-id-form")(
input(
Expand Down Expand Up @@ -83,6 +83,13 @@ object mine:
),
error.map { p(cls := "error")(_) }
)
),
div(cls := "qr-code-invite")(
h2(cls := "ninja-title", trans.orLetYourOpponentScanQrCode()),
img(
src := s"https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=$challengeLink",
alt := "QR Code"
)
)
)
},
Expand Down
8 changes: 5 additions & 3 deletions app/views/puzzle/bits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ object bits:
)
)

private val themeI18nKeys =
PuzzleTheme.visible.map(_.name) ::: PuzzleTheme.visible.map(_.description)

private val baseI18nKeys = List(
trans.puzzle.bestMove,
trans.puzzle.keepGoing,
Expand Down Expand Up @@ -102,8 +105,7 @@ object bits:
trans.puzzle.nbPointsBelowYourPuzzleRating,
trans.puzzle.nbPointsAboveYourPuzzleRating
) :::
PuzzleTheme.visible.map(_.name) :::
PuzzleTheme.visible.map(_.description) :::
themeI18nKeys :::
PuzzleDifficulty.all.map(_.name)

private val streakI18nKeys = baseI18nKeys ::: List(
Expand All @@ -113,4 +115,4 @@ object bits:
trans.puzzle.streakSkipExplanation,
trans.puzzle.continueTheStreak,
trans.puzzle.newStreak
)
) ::: themeI18nKeys
20 changes: 20 additions & 0 deletions app/views/ublog/post.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ object post:
dataIcon := licon.CautionTriangle
)
),
!ctx.is(user) && isGranted(_.ModerateBlog) option rankAdjust(blog, post),
div(cls := "ublog-post__topics")(
post.topics.map: topic =>
a(href := routes.Ublog.topic(topic.url, 1))(topic.value)
Expand All @@ -123,6 +124,25 @@ object post:
)
)

private def rankAdjust(blog: UblogBlog, post: UblogPost)(using PageContext) =
env.ublog.rank.computeRank(blog, post) map: rank =>
postForm(cls := "ublog-post__meta", action := routes.Ublog.rankAdjust(post.id))(
"Rank date:",
span(cls := "ublog-post__meta__date")(semanticDate(rank.value)),
s"adjust${post.rankAdjustDays.nonEmpty so "ed"} by",
span(
input(
tpe := "number",
name := "value",
min := -180,
max := 180,
placeholder := "Days",
value := post.rankAdjustDays.so(_.toString)
),
form3.submit("Submit")(cls := "button-empty")
)
)

private def editButton(post: UblogPost)(using PageContext) = a(
href := editUrlOfPost(post),
cls := "button button-empty text",
Expand Down
17 changes: 8 additions & 9 deletions app/views/video/bits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,14 @@ object bits:

def notFound(control: lila.video.UserControl)(using PageContext) =
layout(title = "Video not found", control = control)(
div(cls := "content_box_top")(
a(cls := "is4 text", dataIcon := licon.Back, href := routes.Video.index)("Video library")
),
div(cls := "not_found")(
h1("Video Not Found!"),
br,
br,
a(cls := "big button text", dataIcon := licon.Back, href := routes.Video.index)(
"Return to the video library"
boxTop(
h1(
a(
cls := "is4 text",
dataIcon := licon.Back,
href := s"${routes.Video.index}"
),
"Video Not Found!"
)
)
)
Expand Down
3 changes: 1 addition & 2 deletions app/views/video/layout.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ object layout:
moreJs = infiniteScrollTag,
wrapClass = "full-screen-force",
openGraph = openGraph
) {
):
main(cls := "video page-menu force-ltr")(
st.aside(cls := "page-menu__menu")(
views.html.site.bits.subnav(
Expand All @@ -44,4 +44,3 @@ object layout:
),
div(cls := "page-menu__content box")(body)
)
}
14 changes: 9 additions & 5 deletions bin/deploy
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,13 @@ def artifact_url(session, run, name):
for artifact in session.get(run["artifacts_url"]).json()["artifacts"]:
if artifact["name"] == name:
if artifact["expired"]:
print("Artifact expired.")
return artifact["archive_download_url"]
raise DeployError("Artifact expired.")

# Will redirect to URL containing a short-lived authorization
# token.
resolved = session.head(artifact["archive_download_url"], allow_redirects=False)
resolved.raise_for_status()
return resolved.headers["Location"]

raise DeployError(f"Did not find artifact {name}.")

Expand All @@ -248,7 +253,6 @@ def tmux(ssh, script, *, dry_run=False):


def deploy_script(profile, session, run, url):
auth_header = f"Authorization: {session.headers['Authorization']}"
ua_header = f"User-Agent: {session.headers['User-Agent']}"
deploy_dir = profile["deploy_dir"]
artifact_unzipped = f"{ARTIFACT_DIR}/{profile['artifact_name']}-{run['id']:d}"
Expand All @@ -259,12 +263,12 @@ def deploy_script(profile, session, run, url):
"echo \\# Downloading ...",
f"mkdir -p {ARTIFACT_DIR}",
f"mkdir -p {deploy_dir}/logs",
f"[ -f {artifact_zip} ] || wget --header={shlex.quote(auth_header)} --header={shlex.quote(ua_header)} --no-clobber -O {artifact_zip} {shlex.quote(url)}",
f"[ -f {artifact_zip} ] || wget --header={shlex.quote(ua_header)} --no-clobber -O {artifact_zip} {shlex.quote(url)}",
"echo",
"echo \\# Unpacking ...",
f"unzip -q -o {artifact_zip} -d {artifact_unzipped}",
f"mkdir -p {artifact_unzipped}/d",
f"tar -xf {artifact_unzipped}/*.tar.xz -C {artifact_unzipped}/d",
f"tar -xf {artifact_unzipped}/*.tar.zst -C {artifact_unzipped}/d",
f"cat {artifact_unzipped}/d/commit.txt",
"echo",
"echo \\# Preparing lifat ...",
Expand Down
1 change: 1 addition & 0 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ POST /ublog/$id<\w{8}>/edit controllers.Ublog.update(id)
POST /ublog/$id<\w{8}>/del controllers.Ublog.delete(id)
POST /ublog/$id<\w{8}>/like controllers.Ublog.like(id, v: Boolean)
POST /ublog/:blogId/tier controllers.Ublog.setTier(blogId)
POST /ublog/$id<\w{8}>/adjust controllers.Ublog.rankAdjust(id)
POST /upload/image/ublog/$id<\w{8}> controllers.Ublog.image(id)

# User
Expand Down
7 changes: 7 additions & 0 deletions modules/common/src/main/base/LilaModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import java.time.Instant

trait LilaModel:

type Update[A] = A => A
def UpdateOf[A](f: A => A): Update[A] = f
// apply updates to a value, and keep track of the updates
// so they can all be replayed on another value
case class Updating[A](current: A, reRun: Update[A] = (a: A) => a):
def apply(up: Update[A]) = Updating(up(current), up compose reRun)

trait OpaqueInstant[A](using A =:= Instant) extends TotalWrapper[A, Instant]

trait Percent[A]:
Expand Down
14 changes: 14 additions & 0 deletions modules/common/src/main/config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ object config:
opaque type EndpointUrl = String
object EndpointUrl extends OpaqueString[EndpointUrl]

case class Credentials(user: String, password: Secret):
def show = s"$user:${password.value}"
object Credentials:
def read(str: String): Option[Credentials] = str.split(":") match
case Array(user, password) => Credentials(user, Secret(password)).some
case _ => none

case class HostPort(host: String, port: Int):
def show = s"$host:$port"
object HostPort:
def read(str: String): Option[HostPort] = str.split(":") match
case Array(host, port) => port.toIntOption.map(HostPort(host, _))
case _ => none

case class NetConfig(
domain: NetDomain,
prodDomain: NetDomain,
Expand Down
3 changes: 2 additions & 1 deletion modules/common/src/main/mon.scala
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ object mon:
def moves(official: Boolean, slug: String) = counter("relay.moves").withTags(relay(official, slug))
def fetchTime(official: Boolean, slug: String) = timer("relay.fetch.time").withTags(relay(official, slug))
def syncTime(official: Boolean, slug: String) = timer("relay.sync.time").withTags(relay(official, slug))
def httpGet(host: String) = future("relay.http.get", tags("host" -> host))
def httpGet(host: String, proxy: Option[String]) =
future("relay.http.get", tags("host" -> host, "proxy" -> proxy.getOrElse("none")))
object bot:
def moves(username: String) = counter("bot.moves").withTag("name", username)
def chats(username: String) = counter("bot.chats").withTag("name", username)
Expand Down
1 change: 1 addition & 0 deletions modules/i18n/src/main/I18nKeys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ object I18nKeys:
val `toInviteSomeoneToPlayGiveThisUrl` = I18nKey("toInviteSomeoneToPlayGiveThisUrl")
val `gameOver` = I18nKey("gameOver")
val `waitingForOpponent` = I18nKey("waitingForOpponent")
val `orLetYourOpponentScanQrCode` = I18nKey("orLetYourOpponentScanQrCode")
val `waiting` = I18nKey("waiting")
val `yourTurn` = I18nKey("yourTurn")
val `aiNameLevelAiLevel` = I18nKey("aiNameLevelAiLevel")
Expand Down
1 change: 1 addition & 0 deletions modules/i18n/src/main/LangList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ object LangList:
Lang("sa", "IN") -> "संस्कृत",
Lang("sk", "SK") -> "Slovenčina",
Lang("sl", "SI") -> "Slovenščina",
Lang("so", "SO") -> "Af Soomaali",
Lang("sq", "AL") -> "Shqip",
Lang("sr", "SP") -> "Српски језик",
Lang("sv", "SE") -> "Svenska",
Expand Down
22 changes: 19 additions & 3 deletions modules/memo/src/main/SettingStore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import reactivemongo.api.bson.BSONHandler

import lila.db.dsl.*
import play.api.data.*, Forms.*
import lila.common.{ Ints, Iso, Strings, UserIds }
import lila.common.{ Ints, Iso, Strings, UserIds, config }

final class SettingStore[A: BSONHandler: SettingStore.StringReader: SettingStore.Formable] private (
coll: Coll,
Expand Down Expand Up @@ -60,16 +60,18 @@ object SettingStore:
final class StringReader[A](val read: String => Option[A])

object StringReader:
given StringReader[Boolean] = StringReader[Boolean]({
given StringReader[Boolean] = StringReader[Boolean]:
case "on" | "yes" | "true" | "1" => true.some
case "off" | "no" | "false" | "0" => false.some
case _ => none
})
given StringReader[Int] = StringReader[Int](_.toIntOption)
given StringReader[Float] = StringReader[Float](_.toFloatOption)
given StringReader[String] = StringReader[String](some)
def fromIso[A](using iso: Iso.StringIso[A]) = StringReader[A](v => iso.from(v).some)

private type CredOption = Option[lila.common.config.Credentials]
private type HostOption = Option[lila.common.config.HostPort]

object Strings:
val stringsIso = Iso.strings(",")
given BSONHandler[Strings] = lila.db.dsl.isoHandler(using stringsIso)
Expand All @@ -86,6 +88,14 @@ object SettingStore:
val regexIso = Iso.string[Regex](_.r, _.toString)
given BSONHandler[Regex] = lila.db.dsl.isoHandler(using regexIso)
given StringReader[Regex] = StringReader.fromIso(using regexIso)
object CredentialsOption:
val credentialsIso = Iso.string[CredOption](lila.common.config.Credentials.read, _.so(_.show))
given BSONHandler[CredOption] = lila.db.dsl.isoHandler(using credentialsIso)
given StringReader[CredOption] = StringReader.fromIso(using credentialsIso)
object HostPortOption:
val hostPortIso = Iso.string[HostOption](lila.common.config.HostPort.read, _.so(_.show))
given BSONHandler[HostOption] = lila.db.dsl.isoHandler(using hostPortIso)
given StringReader[HostOption] = StringReader.fromIso(using hostPortIso)

final class Formable[A](val form: A => Form[?])
object Formable:
Expand All @@ -97,5 +107,11 @@ object SettingStore:
given Formable[String] = Formable[String](v => Form(single("v" -> text)) fill v)
given Formable[Strings] = Formable[Strings](v => Form(single("v" -> text)) fill Strings.stringsIso.to(v))
given Formable[UserIds] = Formable[UserIds](v => Form(single("v" -> text)) fill UserIds.userIdsIso.to(v))
given Formable[CredOption] = stringPair(using CredentialsOption.credentialsIso)
given Formable[HostOption] = stringPair(using HostPortOption.hostPortIso)
private def stringPair[A](using iso: Iso.StringIso[A]): Formable[A] = Formable[A]: v =>
Form(
single("v" -> text.verifying(t => t.isEmpty || t.count(_ == ':') == 1))
) fill iso.to(v)

private val dbField = "setting"
2 changes: 2 additions & 0 deletions modules/mod/src/main/Modlog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ case class Modlog(
case Modlog.setKidMode => "set kid mode"
case Modlog.weakPassword => "log in with weak password"
case Modlog.blankedPassword => "log in with blanked password"
case Modlog.ublogRankAdjust => "adjust ublog post rank"
case a => a

override def toString = s"$mod $showAction $user $details"
Expand Down Expand Up @@ -162,6 +163,7 @@ object Modlog:
val setKidMode = "setKidMode"
val weakPassword = "weakPassword"
val blankedPassword = "blankedPassword"
val ublogRankAdjust = "ublogRankAdjust"

private val explainRegex = """^[\w-]{3,}+: (.++)$""".r
def explain(e: Modlog) = (e.index has "team") so ~e.details match
Expand Down
Loading

0 comments on commit 5afc0bf

Please sign in to comment.