Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into ui-remove-site-di…
Browse files Browse the repository at this point in the history
…alog
  • Loading branch information
schlawg committed Jul 5, 2024
2 parents 6d523c9 + f970239 commit d6c08c2
Show file tree
Hide file tree
Showing 533 changed files with 2,301 additions and 2,273 deletions.
6 changes: 2 additions & 4 deletions app/controllers/Auth.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,21 @@ final class Auth(
): Fu[Result] =
api
.saveAuthentication(u.id, ctx.mobileApiVersion)
.flatMap { sessionId =>
.flatMap: sessionId =>
negotiate(
result.fold(Redirect(getReferrer))(_(getReferrer)),
mobileUserOk(u, sessionId)
).map(authenticateCookie(sessionId, remember))
}
.recoverWith(authRecovery)

private def authenticateAppealUser(u: UserModel, redirect: String => Result)(using
ctx: Context
): Fu[Result] =
api.appeal
.saveAuthentication(u.id)
.flatMap { sessionId =>
.flatMap: sessionId =>
authenticateCookie(sessionId, remember = false):
redirect(routes.Appeal.landing.url)
}
.recoverWith(authRecovery)

private def authenticateCookie(sessionId: String, remember: Boolean)(
Expand Down
21 changes: 20 additions & 1 deletion app/controllers/BulkPairing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import play.api.libs.json.*
import lila.app.*
import lila.common.Json.given
import lila.challenge.ChallengeBulkSetup
import lila.api.GameApiV2

final class BulkPairing(env: Env) extends LilaController(env):
final class BulkPairing(gameC: => Game, apiC: => Api, env: Env) extends LilaController(env):

def list = ScopedBody(_.Challenge.Bulk) { _ ?=> me ?=>
env.challenge.bulk
Expand All @@ -23,6 +24,24 @@ final class BulkPairing(env: Env) extends LilaController(env):
JsonOk(ChallengeBulkSetup.toJson(bulk))
}

def games(id: String) = ScopedBody(_.Challenge.Bulk) { _ ?=> me ?=>
env.challenge.bulk
.findBy(id, me)
.map:
_.fold(notFoundText()): bulk =>
val config = GameApiV2.ByIdsConfig(
ids = bulk.games.map(_.id),
format = GameApiV2.Format.byRequest(req),
flags = gameC
.requestPgnFlags(extended = false)
.copy(delayMoves = false),
perSecond = MaxPerSecond(50)
)
apiC.GlobalConcurrencyLimitPerIP
.download(req.ipAddress)(env.api.gameApiV2.exportByIds(config)): source =>
noProxyBuffer(Ok.chunked(source)).as(gameC.gameContentType(config))
}

def delete(id: String) = ScopedBody(_.Challenge.Bulk) { _ ?=> me ?=>
env.challenge.bulk
.deleteBy(id, me)
Expand Down
9 changes: 9 additions & 0 deletions app/controllers/ForumCateg.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@ final class ForumCateg(env: Env) extends LilaController(env) with ForumControlle
if canRead then Ok.page(views.forum.categ.show(categ, topics, canWrite, stickyPosts))
else notFound
yield res

def modFeed(slug: ForumCategId, page: Int) = Secure(_.ModerateForum) { ctx ?=> _ ?=>
Found(env.forum.categRepo.byId(slug)): categ =>
for
posts <- env.forum.paginator.recent(categ, page)
postViews <- posts.mapFutureList(env.forum.postApi.views)
page <- renderPage(views.forum.categ.modFeed(categ, postViews))
yield Ok(page)
}
12 changes: 5 additions & 7 deletions app/controllers/Mod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,14 @@ final class Mod(
bindForm(lila.user.UserForm.title)(
_ => redirect(username, mod = true),
title =>
doSetTitle(username.id, title, public = true).inject:
doSetTitle(username.id, title).inject:
redirect(username, mod = false)
)
}

protected[controllers] def doSetTitle(userId: UserId, title: Option[chess.PlayerTitle], public: Boolean)(
using Me
) = for
_ <- (public || title.isEmpty).so(modApi.setTitle(userId, title))
_ <- title.so(env.mailer.automaticEmail.onTitleSet(userId, _, public))
protected[controllers] def doSetTitle(userId: UserId, title: Option[chess.PlayerTitle])(using Me) = for
_ <- modApi.setTitle(userId, title)
_ <- title.so(env.mailer.automaticEmail.onTitleSet(userId, _))
yield ()

def setEmail(username: UserStr) = SecureBody(_.SetEmail) { ctx ?=> me ?=>
Expand Down Expand Up @@ -470,7 +468,7 @@ final class Mod(
} >> {
Permission
.ofDbKeys(permissions)
.exists(_.grants(Permission.SeeReport))
.exists(p => p.grants(Permission.SeeReport) || p.grants(Permission.Developer))
.so(env.plan.api.setLifetime(user))
}).inject(Redirect(routes.Mod.permissions(user.username)).flashSuccess)
)
Expand Down
9 changes: 6 additions & 3 deletions app/controllers/RelayRound.scala
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,12 @@ final class RelayRound(
Found(env.study.studyRepo.byId(rt.round.studyId)): study =>
studyC.CanView(study)(
for
group <- env.relay.api.withTours.get(rt.tour.id)
previews <- env.study.preview.jsonList.withoutInitialEmpty(study.id)
yield JsonOk(env.relay.jsonView.withUrlAndPreviews(rt.withStudy(study), previews, group))
group <- env.relay.api.withTours.get(rt.tour.id)
previews <- env.study.preview.jsonList.withoutInitialEmpty(study.id)
targetRound <- env.relay.api.officialTarget(rt.round)
yield JsonOk(
env.relay.jsonView.withUrlAndPreviews(rt.withStudy(study), previews, group, targetRound)
)
)(studyC.privateUnauthorizedJson, studyC.privateForbiddenJson)

def pgn(ts: String, rs: String, id: RelayRoundId) = Open:
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/Report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ final class Report(env: Env, userC: => User, modC: => Mod) extends LilaControlle
text = s"$pid\n\n"
)
case _ => form
views.report.form(filledForm, user)
views.report.ui.form(filledForm, user)
}
}

Expand All @@ -162,7 +162,7 @@ final class Report(env: Env, userC: => User, modC: => Mod) extends LilaControlle
err =>
for
user <- getUserStr("username").so(env.user.repo.byId)
page <- renderPage(views.report.form(err, user))
page <- renderPage(views.report.ui.form(err, user))
yield BadRequest(page),
data =>
if me.is(data.user.id) then BadRequest("You cannot report yourself")
Expand Down
11 changes: 6 additions & 5 deletions app/controllers/Study.scala
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,12 @@ final class Study(

def delete(id: StudyId) = Auth { _ ?=> me ?=>
Found(env.study.api.byIdAndOwnerOrAdmin(id, me)): study =>
env.study.api.delete(study) >> env.relay.api
.deleteRound(id.into(RelayRoundId))
.map:
case None => Redirect(routes.Study.mine(Order.hot))
case Some(tour) => Redirect(routes.RelayTour.show(tour.slug, tour.id))
for
round <- env.relay.api.deleteRound(id.into(RelayRoundId))
_ <- env.study.api.delete(study)
yield round match
case None => Redirect(routes.Study.mine(Order.hot))
case Some(tour) => Redirect(routes.RelayTour.show(tour.slug, tour.id))
}

def apiChapterDelete(id: StudyId, chapterId: StudyChapterId) = ScopedBody(_.Study.Write) { _ ?=> me ?=>
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/TitleVerify.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,12 @@ final class TitleVerify(env: Env, cmsC: => Cms, reportC: => report.Report, userC
private def onApproved(req: TitleRequest)(using Context, Me) =
for
user <- env.user.api.byId(req.userId).orFail(s"User ${req.userId} not found")
_ <- modC.doSetTitle(user.id, req.data.title.some, req.data.public)
_ <- modC.doSetTitle(user.id, req.data.title.some)
url = s"${env.net.baseUrl}${routes.TitleVerify.show(req.id)}"
note = s"Title verified: ${req.data.title}. Public: ${if req.data.public then "Yes" else "No"}. $url"
_ <- env.user.noteApi.write(user.id, note, modOnly = true, dox = false)
_ <- req.data.public.so:
env.user.repo.setRealName(user.id, req.data.realName)
_ <- req.data.coach.so:
env.user.repo.addPermission(user.id, lila.core.perm.Permission.Coach)
_ <- req.data.coach.so:
Expand Down
6 changes: 6 additions & 0 deletions app/controllers/User.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ final class User(
apiGames(u, GameFilter.All.name, 1)
)

def search(term: String) = Open: _ ?=>
UserStr.read(term) match
case Some(username) => Redirect(routes.User.show(username)).toFuccess
case _ if isGrantedOpt(_.UserSearch) => Redirect(s"${routes.Mod.search}?q=$term").toFuccess
case _ => notFound

private def renderShow(u: UserModel, status: Results.Status = Results.Ok)(using Context): Fu[Result] =
if HTTPRequest.isSynchronousHttp(ctx.req)
then
Expand Down
2 changes: 1 addition & 1 deletion app/http/CtrlFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ trait CtrlFilters(using Executor) extends ControllerHelpers with ResponseBuilder
max: Max = Max(40),
errorPage: => Fu[Result] = BadRequest("resource too old")
)(result: => Fu[Result]): Fu[Result] =
if page < max.value && page > 0 then result else errorPage
if page <= max.value && page > 0 then result else errorPage

def NotForKids(f: => Fu[Result])(using ctx: Context): Fu[Result] =
if ctx.kid.no then f else notFound
Expand Down
75 changes: 0 additions & 75 deletions app/views/report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -160,78 +160,3 @@ def layout(filter: String, scores: Room.Scores, pending: PendingCounts)(using
body
)
)

def form(form: Form[?], reqUser: Option[User] = None)(using ctx: Context) =
Page(trans.site.reportAUser.txt())
.css("bits.form3")
.js(
embedJsUnsafeLoadThen(
"""$('#form3-reason').on('change', function() {
$('.report-reason').addClass('none').filter('.report-reason-' + this.value).removeClass('none');
})"""
)
):
val defaultReason = form("reason").value.orElse(translatedReasonChoices.headOption.map(_._1))
main(cls := "page-small box box-pad report")(
h1(cls := "box__top")(trans.site.reportAUser()),
postForm(
cls := "form3",
action := s"${routes.Report.create}${reqUser.so(u => "?username=" + u.username)}"
)(
div(cls := "form-group")(
p(
a(
href := routes.Cms.lonePage(lila.core.id.CmsPageKey("report-faq")),
dataIcon := Icon.InfoCircle,
cls := "text"
):
"Read more about Lichess reports"
),
ctx.req.queryString
.contains("postUrl")
.option(
p(
"Here for DMCA or Intellectual Property Take Down Notice? ",
a(href := lila.web.ui.contact.dmcaUrl)("Complete this form instead"),
"."
)
)
),
form3.globalError(form),
form3.group(form("username"), trans.site.user(), klass = "field_to complete-parent"): f =>
reqUser
.map: user =>
frag(userLink(user), form3.hidden(f, user.id.value.some))
.getOrElse:
div(form3.input(f, klass = "user-autocomplete")(dataTag := "span", autofocus))
,
if ctx.req.queryString contains "reason"
then form3.hidden(form("reason"))
else
form3.group(form("reason"), trans.site.reason()): f =>
form3.select(f, translatedReasonChoices, trans.site.whatIsIheMatter.txt().some)
,
form3.group(form("text"), trans.site.description(), help = descriptionHelp(~defaultReason).some):
form3.textarea(_)(rows := 8)
,
form3.actions(
a(href := routes.Lobby.home)(trans.site.cancel()),
form3.submit(trans.site.send())
)
)
)

private def descriptionHelp(default: String)(using ctx: Context) = frag:
import lila.report.Reason.*
val englishPlease = " Your report will be processed faster if written in English."
translatedReasonChoices
.map(_._1)
.distinct
.map: key =>
span(cls := List(s"report-reason report-reason-$key" -> true, "none" -> (default != key))):
if key == Cheat.key || key == Boost.key then trans.site.reportDescriptionHelp()
else if key == Username.key then
"Please explain briefly what about this username is offensive." + englishPlease
else if key == Comm.key || key == Sexism.key then
"Please explain briefly what that user said that was abusive." + englishPlease
else "Please explain briefly what happened." + englishPlease
3 changes: 2 additions & 1 deletion app/views/title.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ object mod:
" ",
player.name
),
p(player.ratingsStr)
p(player.ratingsStr),
p("Year of birth: ", player.year.fold("unknown")(_.toString))
)
modUi.show(req, data.user, fide, similar, modZone)

Expand Down
4 changes: 4 additions & 0 deletions bin/mongodb/indexes.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ db.relay.createIndex({ startsAt: 1 }, { partialFilterExpression: { startsAt: { $
db.relay.createIndex({ startedAt: 1 }, { partialFilterExpression: { startedAt: { $exists: 1 } } });
db.relay.createIndex({ 'sync.until': 1 }, { partialFilterExpression: { 'sync.until': { $exists: 1 } } });
db.relay.createIndex({ tourId: 1 });
db.relay.createIndex(
{ 'sync.upstream.roundIds': 1 },
{ partialFilterExpression: { 'sync.upstream.roundIds': { $exists: 1 } } },
);
db.oauth2_access_token.createIndex({ userId: 1 });
db.oauth2_access_token.createIndex({ expires: 1 }, { expireAfterSeconds: 0 });
db.cache.createIndex({ e: 1 }, { expireAfterSeconds: 0 });
Expand Down
17 changes: 17 additions & 0 deletions bin/mongodb/real-name-migrate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const sel = { $or: [{ 'profile.firstName': { $exists: true } }, { 'profile.lastName': { $exists: true } }] };

db.user4
.find(sel, { profile: 1 })
.limit(1000)
.forEach(function (user) {
const fullName = ((user.profile.firstName || '') + ' ' + (user.profile.lastName || ''))
.trim()
.replace(/\s+/g, ' ');
db.user4.updateOne(
{ _id: user._id },
{
$set: { 'profile.realName': fullName },
$unset: { 'profile.firstName': true, 'profile.lastName': true },
},
);
});
32 changes: 32 additions & 0 deletions bin/mongodb/relay-dates-migrate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// db.relay.aggregate([{$match:{tourId:'KNfeoWE'}},{$project:{name:1,at:{$ifNull:['$startsAt','$startedAt']}}},{$sort:{at:1}},{$group:{_id:null,at:{$push:'$at'}}},{$project:{start:{$first:'$at'},end:{$last:'$at'}}}])

const fetchDates = tourId =>
db.relay
.aggregate([
{ $match: { tourId } },
{ $project: { name: 1, at: { $ifNull: ['$startsAt', '$startedAt'] } } },
{ $sort: { at: 1 } },
{ $group: { _id: null, at: { $push: '$at' } } },
{ $project: { start: { $first: '$at' }, end: { $last: '$at' } } },
])
.next();

const cmp = (a, b) => (a ? a.getTime() : 0) == (b ? b.getTime() : 0);

db.relay_tour
.find()
.sort({ $natural: -1 })
.limit(200)
.forEach(tour => {
const dates = fetchDates(tour._id);
if (dates) {
if (!cmp(dates?.start, tour.dates?.start)) {
console.log(tour._id + ' ' + tour.dates?.start + ' -> ' + dates.start);
db.relay_tour.updateOne({ _id: tour._id }, { $set: { 'dates.start': dates.start } });
}
if (!cmp(dates?.end, tour.dates?.end)) {
console.log(tour._id + ' ' + tour.dates?.end + ' -> ' + dates.end);
db.relay_tour.updateOne({ _id: tour._id }, { $set: { 'dates.end': dates.end } });
}
}
});
24 changes: 24 additions & 0 deletions bin/mongodb/relay-tour-info-migrate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
db.relay_tour
.find({
description: { $exists: true },
'info.dates': { $exists: false },
'info.format': { $exists: false },
'info.tc': { $exists: false },
'info.players': { $exists: false },
})
.forEach(function (tour) {
if (!tour.description.includes('|')) {
return;
}
const split = tour.description.split('|').map(x => x.trim());
const info = {};
const dates = split.shift();
if (dates && /\d/.test(dates)) info.dates = dates;
const format = split.shift();
if (format) info.format = format;
const tc = split.shift();
if (tc) info.tc = tc.replace(/time control/i, '').trim();
const players = split.shift();
if (players) info.players = players;
db.relay_tour.updateOne({ _id: tour._id }, { $set: { info: info } });
});
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ lazy val practice = module("practice",

lazy val playban = module("playban",
Seq(memo),
Seq()
tests.bundle
)

lazy val push = module("push",
Expand Down
Loading

0 comments on commit d6c08c2

Please sign in to comment.