Skip to content

Commit

Permalink
Merge branch 'master' into orientation-dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
johndoknjas committed Nov 4, 2024
2 parents 27fa16a + 7d395ed commit 3500a10
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 31 deletions.
5 changes: 2 additions & 3 deletions modules/relay/src/main/RelayFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ final private class RelayFormatApi(
cache.invalidate(url -> proxy)

private def guessFormat(url: URL)(using CanProxy): Fu[RelayFormat] =
RelayRound.Sync.Upstream
.Url(url)
.lcc
import RelayRound.Sync.url.*
url.lcc
.match
case Some(lcc) =>
looksLikeJson(lcc.indexUrl).flatMapz:
Expand Down
24 changes: 14 additions & 10 deletions modules/relay/src/main/RelayRound.scala
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,28 @@ object RelayRound:
override def toString = upstream.toString

object Sync:

object url:
private val lccRegex = """view\.livechesscloud\.com/?#?([0-9a-f\-]+)/(\d+)""".r.unanchored
extension (url: URL)
def lcc: Option[Lcc] = url.toString match
case lccRegex(id, round) => round.toIntOption.map(Lcc(id, _))
case _ => none
def looksLikeLcc = url.host.toString.endsWith("livechesscloud.com")
import url.*

enum Upstream:
case Url(url: URL) extends Upstream
case Urls(urls: List[URL]) extends Upstream
case Ids(ids: List[GameId]) extends Upstream
def asUrl: Option[URL] = this match
case Url(url) => url.some
case _ => none
def isUrl = asUrl.isDefined
def lcc: Option[Lcc] = asUrl.flatMap:
_.toString match
case lccRegex(id, round) => round.toIntOption.map(Lcc(id, _))
case _ => none
def isUrl = asUrl.isDefined
def lcc: Option[Lcc] = asUrl.flatMap(_.lcc)
def hasLcc = this match
case Url(url) => Sync.looksLikeLcc(url)
case Urls(urls) => urls.exists(Sync.looksLikeLcc)
case Url(url) => url.looksLikeLcc
case Urls(urls) => urls.exists(_.looksLikeLcc)
case _ => false

def roundId: Option[RelayRoundId] = this match
Expand All @@ -164,9 +171,6 @@ object RelayRound:
def indexUrl = URL.parse(s"http://1.pool.livechesscloud.com/get/$id/round-$round/index.json")
def gameUrl(g: Int) = URL.parse(s"http://1.pool.livechesscloud.com/get/$id/round-$round/game-$g.json")

private val lccRegex = """view\.livechesscloud\.com/?#?([0-9a-f\-]+)/(\d+)""".r.unanchored
private def looksLikeLcc(url: URL) = url.toString.contains(".livechesscloud.com/")

trait AndTour:
val tour: RelayTour
def display: RelayRound
Expand Down
36 changes: 18 additions & 18 deletions modules/relay/src/main/RelayRoundForm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ import lila.common.Form.{ cleanText, formatter, into, stringIn, LocalDateTimeOrT
import lila.core.perm.Granter
import lila.relay.RelayRound.Sync
import lila.relay.RelayRound.Sync.Upstream
import lila.relay.RelayRound.Sync.url.*
import lila.common.Form.PrettyDateTime

final class RelayRoundForm(using mode: Mode):

import RelayRoundForm.*
import lila.common.Form.ISOInstantOrTimestamp

private given Formatter[Upstream.Url] =
private given (using Me): Formatter[Upstream.Url] =
formatter.stringTryFormatter(str => validateUpstreamUrl(str).map(Upstream.Url.apply), _.url.toString)
private given Formatter[Upstream.Urls] = formatter.stringTryFormatter(

private given (using Me): Formatter[Upstream.Urls] = formatter.stringTryFormatter(
_.linesIterator.toList
.map(_.trim)
.filter(_.nonEmpty)
Expand All @@ -42,22 +44,12 @@ final class RelayRoundForm(using mode: Mode):
_.ids.mkString(" ")
)

private def lccIsComplete(url: Upstream.Url) =
url.lcc.isDefined || !url.url.host.toString.endsWith("livechesscloud.com")

def roundMapping(tour: RelayTour)(using Me) =
def roundMapping(tour: RelayTour)(using Me): Mapping[Data] =
mapping(
"name" -> cleanText(minLength = 3, maxLength = 80).into[RelayRound.Name],
"caption" -> optional(cleanText(minLength = 3, maxLength = 80).into[RelayRound.Caption]),
"syncSource" -> optional(stringIn(sourceTypes.map(_._1).toSet)),
"syncUrl" -> optional(
of[Upstream.Url]
.verifying("LCC URLs must end with /{round-number}, e.g. /5 for round 5", lccIsComplete)
.verifying(
"Invalid source URL",
u => !u.url.host.toString.endsWith("lichess.org") || Granter(_.Relay)
)
),
"name" -> cleanText(minLength = 3, maxLength = 80).into[RelayRound.Name],
"caption" -> optional(cleanText(minLength = 3, maxLength = 80).into[RelayRound.Caption]),
"syncSource" -> optional(stringIn(sourceTypes.map(_._1).toSet)),
"syncUrl" -> optional(of[Upstream.Url]),
"syncUrls" -> optional(of[Upstream.Urls]),
"syncIds" -> optional(of[Upstream.Ids]),
"startsAt" -> optional(LocalDateTimeOrTimestamp(tour.info.timeZoneOrDefault).mapping),
Expand Down Expand Up @@ -155,9 +147,17 @@ object RelayRoundForm:
if !subdomain(host, "chess.com") || url.toString.startsWith("https://api.chess.com/pub")
yield url

private def validateUpstreamUrl(s: String)(using Mode): Either[String, URL] = for
private def validateUpstreamUrl(s: String)(using Me, Mode): Either[String, URL] = for
url <- cleanUrl(s).toRight("Invalid source URL")
url <- if !validSourcePort(url) then Left("The source URL cannot specify a port") else Right(url)
url <-
if url.looksLikeLcc && !url.lcc.isDefined
then Left("LCC URLs must end with /{round-number}, e.g. /5 for round 5")
else Right(url)
url <-
if url.host.toString.endsWith("lichess.org") && !Granter(_.Relay)
then Left("Invalid source URL")
else Right(url)
yield url

private val validPorts = Set(-1, 80, 443, 8080, 8491)
Expand Down

0 comments on commit 3500a10

Please sign in to comment.