From 7daf631f72d8fa92d1ac11ace89f7dcf98fa7ed8 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sat, 2 Sep 2023 18:46:54 +0200 Subject: [PATCH 01/15] Enter as admin to all rounds of broadcast at once --- app/controllers/RelayRound.scala | 4 ++-- app/controllers/RelayTour.scala | 10 +++++++++- conf/routes | 1 + modules/relay/src/main/RelayApi.scala | 3 +++ modules/relay/src/main/RelayRound.scala | 1 + modules/relay/src/main/RelayRoundRepo.scala | 7 +++++++ ui/analyse/src/study/studyMembers.ts | 5 ++++- 7 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/controllers/RelayRound.scala b/app/controllers/RelayRound.scala index 434cb64c1974f..d8ea77ae9b273 100644 --- a/app/controllers/RelayRound.scala +++ b/app/controllers/RelayRound.scala @@ -16,14 +16,14 @@ final class RelayRound( apiC: => Api ) extends LilaController(env): - def form(tourId: String) = Auth { ctx ?=> _ ?=> + def form(tourId: TourModel.Id) = Auth { ctx ?=> _ ?=> NoLameOrBot: WithTourAndRoundsCanUpdate(tourId): trs => Ok.page: html.relay.roundForm.create(env.relay.roundForm.create(trs), trs.tour) } - def create(tourId: String) = AuthOrScopedBody(_.Study.Write) { ctx ?=> me ?=> + def create(tourId: TourModel.Id) = AuthOrScopedBody(_.Study.Write) { ctx ?=> me ?=> NoLameOrBot: WithTourAndRoundsCanUpdate(tourId): trs => val tour = trs.tour diff --git a/app/controllers/RelayTour.scala b/app/controllers/RelayTour.scala index fe65f1b72d55e..e63614fc39515 100644 --- a/app/controllers/RelayTour.scala +++ b/app/controllers/RelayTour.scala @@ -5,7 +5,7 @@ import views.* import lila.app.{ given, * } import lila.common.config.MaxPerSecond -import lila.common.{ config, IpAddress } +import lila.common.{ config, IpAddress, HTTPRequest } import lila.relay.{ RelayTour as TourModel } final class RelayTour(env: Env, apiC: => Api, prismicC: => Prismic) extends LilaController(env): @@ -94,6 +94,14 @@ final class RelayTour(env: Env, apiC: => Api, prismicC: => Prismic) extends Lila ) } + def admin(id: TourModel.Id) = Secure(_.StudyAdmin) { ctx ?=> me ?=> + env.relay.api + .roundIdsById(id) + .flatMap(_.map(env.study.api.adminInvite).parallel) + .inject: + if HTTPRequest.isXhr(ctx.req) then NoContent else Redirect(routes.Study.show(id)) + } + def delete(id: TourModel.Id) = AuthOrScoped(_.Study.Write) { _ ?=> me ?=> WithTour(id): tour => env.relay.api.deleteTourIfOwner(tour) inject Redirect(routes.RelayTour.by(me.username)).flashSuccess diff --git a/conf/routes b/conf/routes index 6f02cbe080cc0..53749d8d0911c 100644 --- a/conf/routes +++ b/conf/routes @@ -246,6 +246,7 @@ GET /api/broadcast/$tourId<\w{8}>.pgn controllers.RelayTour.pgn(tourId) GET /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.edit(tourId) POST /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.update(tourId) POST /broadcast/$tourId<\w{8}>/delete controllers.RelayTour.delete(tourId) +POST /broadcast/$tourId<\w{8}>/admin controllers.RelayTour.admin(tourId) GET /broadcast/$tourId<\w{8}>/new controllers.RelayRound.form(tourId) POST /broadcast/$tourId<\w{8}>/new controllers.RelayRound.create(tourId) GET /broadcast/:ts/:rs/$roundId<\w{8}> controllers.RelayRound.show(ts, rs, roundId) diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala index 6b90b6dbaf22c..606362c1f36fd 100644 --- a/modules/relay/src/main/RelayApi.scala +++ b/modules/relay/src/main/RelayApi.scala @@ -58,6 +58,9 @@ final class RelayApi( def byTourOrdered(tour: RelayTour): Fu[List[RelayRound.WithTour]] = roundRepo.byTourOrdered(tour).dmap(_.map(_ withTour tour)) + def roundIdsById(tourId: RelayTour.Id): Fu[List[StudyId]] = + roundRepo.idsByTourId(tourId) + def withRounds(tour: RelayTour) = roundRepo.byTourOrdered(tour).dmap(tour.withRounds) def denormalizeTourActive(tourId: RelayTour.Id): Funit = diff --git a/modules/relay/src/main/RelayRound.scala b/modules/relay/src/main/RelayRound.scala index 8093ab1548f0e..afce443979abd 100644 --- a/modules/relay/src/main/RelayRound.scala +++ b/modules/relay/src/main/RelayRound.scala @@ -6,6 +6,7 @@ import lila.study.Study import lila.common.Seconds case class RelayRound( + /* Same as the Study id it refers to */ _id: RelayRoundId, tourId: RelayTour.Id, name: RelayRoundName, diff --git a/modules/relay/src/main/RelayRoundRepo.scala b/modules/relay/src/main/RelayRoundRepo.scala index d01d297e6c4a3..c501d08eae14f 100644 --- a/modules/relay/src/main/RelayRoundRepo.scala +++ b/modules/relay/src/main/RelayRoundRepo.scala @@ -24,6 +24,13 @@ final private class RelayRoundRepo(val coll: Coll)(using Executor): .list(RelayTour.maxRelays) .map(_.flatMap(_.getAsOpt[RelayRoundId]("_id"))) + def idsByTourId(tourId: RelayTour.Id): Fu[List[StudyId]] = + coll + .find(selectors.tour(tourId)) + .cursor[Bdoc]() + .list(RelayTour.maxRelays) + .map(_.flatMap(_.getAsOpt[StudyId]("_id"))) + def lastByTour(tour: RelayTour): Fu[Option[RelayRound]] = coll .find(selectors tour tour.id) diff --git a/ui/analyse/src/study/studyMembers.ts b/ui/analyse/src/study/studyMembers.ts index 27dd7ad60b249..50dce92d8b0bd 100644 --- a/ui/analyse/src/study/studyMembers.ts +++ b/ui/analyse/src/study/studyMembers.ts @@ -309,7 +309,10 @@ export function view(ctrl: StudyCtrl): VNode { { key: ':admin', hook: bindNonPassive('submit', () => { - xhrTextRaw(`/study/${ctrl.data.id}/admin`, { method: 'post' }).then(() => location.reload()); + const adminUrl = ctrl.relay + ? `/broadcast/${ctrl.relay.data.tour.id}/admin` + : `/study/${ctrl.data.id}/admin`; + xhrTextRaw(adminUrl, { method: 'post' }).then(() => location.reload()); return false; }), }, From baeadecb823efd29dedee09ce509132b8c4c5bae Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 3 Sep 2023 11:11:27 +0200 Subject: [PATCH 02/15] Kick from all broadcast rounds at the same time --- modules/relay/src/main/Env.scala | 3 +++ modules/relay/src/main/RelayApi.scala | 3 +++ modules/study/src/main/StudyApi.scala | 6 +++--- modules/study/src/main/StudySocket.scala | 15 +++++++++++---- modules/study/src/main/actorApi.scala | 1 + ui/analyse/src/socket.ts | 1 + ui/analyse/src/study/studyMembers.ts | 14 +++++++++++++- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index e1d8b96c22fc9..074c31c5b676d 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -75,6 +75,9 @@ final class Env( _ so api.requestPlay(id into RelayRoundId, v) } }, + "kickBroadcast" -> { case lila.study.actorApi.KickBroadcast(userId, tourId, who) => + api.kickBroadcast(userId, RelayTour.Id(tourId), who) + }, "isOfficialRelay" -> { case lila.study.actorApi.IsOfficialRelay(studyId, promise) => promise completeWith api.isOfficial(studyId) } diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala index 606362c1f36fd..cd25a4934edd3 100644 --- a/modules/relay/src/main/RelayApi.scala +++ b/modules/relay/src/main/RelayApi.scala @@ -61,6 +61,9 @@ final class RelayApi( def roundIdsById(tourId: RelayTour.Id): Fu[List[StudyId]] = roundRepo.idsByTourId(tourId) + def kickBroadcast(userId: UserId, tourId: RelayTour.Id, who: UserId): Unit = + roundIdsById(tourId).foreach(_.foreach(studyId => studyApi.kick(studyId, userId, who))) + def withRounds(tour: RelayTour) = roundRepo.byTourOrdered(tour).dmap(tour.withRounds) def denormalizeTourActive(tourId: RelayTour.Id): Funit = diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index 3e6ea60d7cbe1..9e392b72fca4e 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -362,13 +362,13 @@ final class StudyApi( ) .void - def kick(studyId: StudyId, userId: UserId)(who: Who) = + def kick(studyId: StudyId, userId: UserId, who: UserId) = sequenceStudy(studyId): study => studyRepo - .isAdminMember(study, who.u) + .isAdminMember(study, who) .flatMap: isAdmin => val allowed = study.isMember(userId) && { - (isAdmin && !study.isOwner(userId)) || (study.isOwner(who.u) ^ (who.u == userId)) + (isAdmin && !study.isOwner(userId)) || (study.isOwner(who) ^ (who == userId)) } allowed.so: studyRepo.removeMember(study, userId) andDo diff --git a/modules/study/src/main/StudySocket.scala b/modules/study/src/main/StudySocket.scala index e6233832a21ac..6a0b956a8ca50 100644 --- a/modules/study/src/main/StudySocket.scala +++ b/modules/study/src/main/StudySocket.scala @@ -113,11 +113,17 @@ final private class StudySocket( case "kick" => o.get[UserStr]("d") .foreach: username => - applyWho(api.kick(studyId, username.id)) + applyWho: w => + api.kick(studyId, username.id, w.u) + + case "kickBroadcast" => + applyWho: w => + reading[KickBroadcastData](o): data => + Bus.publish(actorApi.KickBroadcast(data.userId, data.tourId, w.u), "kickBroadcast") case "leave" => who.foreach: w => - api.kick(studyId, w.u)(w) + api.kick(studyId, w.u, w.u) case "shapes" => reading[AtPosition](o): position => @@ -237,9 +243,8 @@ final private class StudySocket( ) case "relaySync" => - who.foreach(w => + applyWho: w => Bus.publish(actorApi.RelayToggle(studyId, ~(o \ "d").asOpt[Boolean], w), "relayToggle") - ) case t => logger.warn(s"Unhandled study socket message: $t") @@ -453,6 +458,8 @@ object StudySocket: given Reads[AtPosition] = ((__ \ "path").read[UciPath] and (__ \ "ch").read[StudyChapterId])(AtPosition.apply) case class SetRole(userId: UserId, role: String) + case class KickBroadcastData(userId: UserId, tourId: String) + given Reads[KickBroadcastData] = Json.reads given Reads[SetRole] = Json.reads given Reads[ChapterMaker.Mode] = optRead(ChapterMaker.Mode.apply) given Reads[ChapterMaker.Orientation] = stringRead(ChapterMaker.Orientation.apply) diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/actorApi.scala index 0ff2871d1006e..7f89a68ff3c06 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/actorApi.scala @@ -13,4 +13,5 @@ case class ExplorerGame(ch: StudyChapterId, path: UciPath, gameId: GameId, inser case class Who(u: UserId, sri: lila.socket.Socket.Sri) case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) +case class KickBroadcast(userId: UserId, tourId: String, who: UserId) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) diff --git a/ui/analyse/src/socket.ts b/ui/analyse/src/socket.ts index 9fb06633f62c0..d8ae328a60c36 100644 --- a/ui/analyse/src/socket.ts +++ b/ui/analyse/src/socket.ts @@ -61,6 +61,7 @@ export type StudySocketSendParams = | [t: 'anaDests', d: AnaDestsReq] | [t: 'like', d: { liked: boolean }] | [t: 'kick', username: string] + | [t: 'kickBroadcast', d: { userId: string; tourId: string }] | [t: 'editStudy', d: StudyFormData] | [t: 'setTopics', topics: string[]] | [t: 'requestAnalysis', chapterId: string] diff --git a/ui/analyse/src/study/studyMembers.ts b/ui/analyse/src/study/studyMembers.ts index 50dce92d8b0bd..21a13dcc7fa90 100644 --- a/ui/analyse/src/study/studyMembers.ts +++ b/ui/analyse/src/study/studyMembers.ts @@ -24,6 +24,7 @@ export interface StudyMemberCtrl { max: number; setRole(id: string, role: string): void; kick(id: string): void; + kickBroadcast(id: string, tourId: string): void; leave(): void; ordered(): StudyMember[]; size(): number; @@ -145,6 +146,10 @@ export function ctrl(opts: Opts): StudyMemberCtrl { opts.send('kick', id); confing(null); }, + kickBroadcast(id: string, tourId: string) { + opts.send('kickBroadcast', { userId: id, tourId: tourId }); + confing(null); + }, leave() { opts.send('leave'); }, @@ -255,7 +260,14 @@ export function view(ctrl: StudyCtrl): VNode { 'a.button.button-red.button-empty.text', { attrs: dataIcon(licon.X), - hook: bind('click', _ => members.kick(member.user.id), ctrl.redraw), + hook: bind( + 'click', + _ => + ctrl.relay + ? members.kickBroadcast(member.user.id, ctrl.relay.data.tour.id) + : members.kick(member.user.id), + ctrl.redraw, + ), }, ctrl.trans.noarg('kick'), ), From c1a93c960c06c02a8a300d69ff6bacfb41b75e3d Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 17 Sep 2023 18:13:36 +0200 Subject: [PATCH 03/15] Broadcast kick: listen to study events --- modules/relay/src/main/Env.scala | 7 +++++-- modules/relay/src/main/RelayRoundRepo.scala | 3 +++ modules/study/src/main/StudySocket.scala | 6 +----- modules/study/src/main/actorApi.scala | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index 074c31c5b676d..a1180df9c6155 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -75,8 +75,11 @@ final class Env( _ so api.requestPlay(id into RelayRoundId, v) } }, - "kickBroadcast" -> { case lila.study.actorApi.KickBroadcast(userId, tourId, who) => - api.kickBroadcast(userId, RelayTour.Id(tourId), who) + "kickStudy" -> { case lila.study.actorApi.Kick(studyId, userId, who) => + roundRepo + .tourIdByStudyId(studyId) + .foreach(_.foreach: tourId => + api.kickBroadcast(userId, tourId, who)) }, "isOfficialRelay" -> { case lila.study.actorApi.IsOfficialRelay(studyId, promise) => promise completeWith api.isOfficial(studyId) diff --git a/modules/relay/src/main/RelayRoundRepo.scala b/modules/relay/src/main/RelayRoundRepo.scala index c501d08eae14f..3f148ed9c4d55 100644 --- a/modules/relay/src/main/RelayRoundRepo.scala +++ b/modules/relay/src/main/RelayRoundRepo.scala @@ -24,6 +24,9 @@ final private class RelayRoundRepo(val coll: Coll)(using Executor): .list(RelayTour.maxRelays) .map(_.flatMap(_.getAsOpt[RelayRoundId]("_id"))) + def tourIdByStudyId(studyId: StudyId): Fu[Option[RelayTour.Id]] = + coll.byId[Bdoc](studyId).map(_.flatMap(_.getAsOpt[RelayTour.Id]("tourId"))) + def idsByTourId(tourId: RelayTour.Id): Fu[List[StudyId]] = coll .find(selectors.tour(tourId)) diff --git a/modules/study/src/main/StudySocket.scala b/modules/study/src/main/StudySocket.scala index 6a0b956a8ca50..96032bf98b1cd 100644 --- a/modules/study/src/main/StudySocket.scala +++ b/modules/study/src/main/StudySocket.scala @@ -115,11 +115,7 @@ final private class StudySocket( .foreach: username => applyWho: w => api.kick(studyId, username.id, w.u) - - case "kickBroadcast" => - applyWho: w => - reading[KickBroadcastData](o): data => - Bus.publish(actorApi.KickBroadcast(data.userId, data.tourId, w.u), "kickBroadcast") + Bus.publish(actorApi.Kick(studyId, username.id, w.u), "kickStudy") case "leave" => who.foreach: w => diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/actorApi.scala index 7f89a68ff3c06..cd03fe438b061 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/actorApi.scala @@ -13,5 +13,5 @@ case class ExplorerGame(ch: StudyChapterId, path: UciPath, gameId: GameId, inser case class Who(u: UserId, sri: lila.socket.Socket.Sri) case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) -case class KickBroadcast(userId: UserId, tourId: String, who: UserId) +case class Kick(studyId: StudyId, userId: UserId, who: UserId) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) From a79014fe31912b97a04bcd0eb068068e2f885539 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 17 Sep 2023 18:36:08 +0200 Subject: [PATCH 04/15] Broadcast admin join: listen to study admin join event --- app/controllers/RelayTour.scala | 2 +- app/controllers/Study.scala | 7 ++++--- modules/relay/src/main/Env.scala | 8 ++++++++ modules/study/src/main/StudyApi.scala | 4 ++-- modules/study/src/main/StudyInvite.scala | 6 +++--- modules/study/src/main/actorApi.scala | 1 + 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/app/controllers/RelayTour.scala b/app/controllers/RelayTour.scala index e63614fc39515..ea9be162d6aa9 100644 --- a/app/controllers/RelayTour.scala +++ b/app/controllers/RelayTour.scala @@ -97,7 +97,7 @@ final class RelayTour(env: Env, apiC: => Api, prismicC: => Prismic) extends Lila def admin(id: TourModel.Id) = Secure(_.StudyAdmin) { ctx ?=> me ?=> env.relay.api .roundIdsById(id) - .flatMap(_.map(env.study.api.adminInvite).parallel) + .flatMap(_.map(studyId => env.study.api.adminInvite(studyId, me.userId)).parallel) .inject: if HTTPRequest.isXhr(ctx.req) then NoContent else Redirect(routes.Study.show(id)) } diff --git a/app/controllers/Study.scala b/app/controllers/Study.scala index 4125f8f2e1415..221ad8b35f199 100644 --- a/app/controllers/Study.scala +++ b/app/controllers/Study.scala @@ -6,8 +6,8 @@ import scala.util.chaining.* import lila.app.{ given, * } import lila.common.paginator.{ Paginator, PaginatorJson } -import lila.common.{ HTTPRequest, IpAddress } -import lila.study.actorApi.Who +import lila.common.{ Bus, HTTPRequest, IpAddress } +import lila.study.actorApi.{ AdminStudy, Who } import lila.study.JsonView.JsData import lila.study.Study.WithChapter import lila.study.{ Order, StudyForm, Study as StudyModel } @@ -314,8 +314,9 @@ final class Study( } def admin(id: StudyId) = Secure(_.StudyAdmin) { ctx ?=> me ?=> + Bus.publish(AdminStudy(id, me.userId), "adminStudy") env.study.api - .adminInvite(id) + .adminInvite(id, me.userId) .inject: if HTTPRequest.isXhr(ctx.req) then NoContent else Redirect(routes.Study.show(id)) } diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index a1180df9c6155..a09674959da75 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -81,6 +81,14 @@ final class Env( .foreach(_.foreach: tourId => api.kickBroadcast(userId, tourId, who)) }, + "adminStudy" -> { case lila.study.actorApi.AdminStudy(studyId, by) => + roundRepo + .tourIdByStudyId(studyId) + .foreach(_.foreach: tourId => + api + .roundIdsById(tourId) + .foreach(_.foreach(studyId => studyApi.adminInvite(studyId, by)))) + }, "isOfficialRelay" -> { case lila.study.actorApi.IsOfficialRelay(studyId, promise) => promise completeWith api.isOfficial(studyId) } diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index 9e392b72fca4e..119c41e1e5df9 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -777,8 +777,8 @@ final class StudyApi( Contribute(by.id, study): chapterRepo deleteByStudy study - def adminInvite(studyId: StudyId)(using Me): Funit = - sequenceStudy(studyId)(inviter.admin) + def adminInvite(studyId: StudyId, by: UserId): Funit = + sequenceStudy(studyId)(inviter.admin(by)) private def indexStudy(study: Study) = Bus.publish(actorApi.SaveStudy(study), "study") diff --git a/modules/study/src/main/StudyInvite.scala b/modules/study/src/main/StudyInvite.scala index 81a12b9cd8cd8..4826a6a8b98aa 100644 --- a/modules/study/src/main/StudyInvite.scala +++ b/modules/study/src/main/StudyInvite.scala @@ -74,12 +74,12 @@ final private class StudyInvite( .void yield invited - def admin(study: Study)(using me: Me): Funit = + def admin(by: UserId)(study: Study): Funit = studyRepo.coll: _.update .one( $id(study.id), - $set(s"members.${me.userId}" -> $doc("role" -> "w", "admin" -> true)) ++ - $addToSet("uids" -> me.userId) + $set(s"members.${by}" -> $doc("role" -> "w", "admin" -> true)) ++ + $addToSet("uids" -> by) ) .void diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/actorApi.scala index cd03fe438b061..8a9f5bb785e5a 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/actorApi.scala @@ -14,4 +14,5 @@ case class ExplorerGame(ch: StudyChapterId, path: UciPath, gameId: GameId, inser case class Who(u: UserId, sri: lila.socket.Socket.Sri) case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) case class Kick(studyId: StudyId, userId: UserId, who: UserId) +case class AdminStudy(studyId: StudyId, by: UserId) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) From 9f8764a8fb852abc33c205ddc279fa45dd2b6349 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 17 Sep 2023 18:40:37 +0200 Subject: [PATCH 05/15] partial revert of 111d7614d1b0e16bc31320b3275fb94b998a8b81 --- modules/study/src/main/StudySocket.scala | 2 -- ui/analyse/src/socket.ts | 1 - ui/analyse/src/study/studyMembers.ts | 14 +------------- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/modules/study/src/main/StudySocket.scala b/modules/study/src/main/StudySocket.scala index 96032bf98b1cd..d77c510cfc8a0 100644 --- a/modules/study/src/main/StudySocket.scala +++ b/modules/study/src/main/StudySocket.scala @@ -454,8 +454,6 @@ object StudySocket: given Reads[AtPosition] = ((__ \ "path").read[UciPath] and (__ \ "ch").read[StudyChapterId])(AtPosition.apply) case class SetRole(userId: UserId, role: String) - case class KickBroadcastData(userId: UserId, tourId: String) - given Reads[KickBroadcastData] = Json.reads given Reads[SetRole] = Json.reads given Reads[ChapterMaker.Mode] = optRead(ChapterMaker.Mode.apply) given Reads[ChapterMaker.Orientation] = stringRead(ChapterMaker.Orientation.apply) diff --git a/ui/analyse/src/socket.ts b/ui/analyse/src/socket.ts index d8ae328a60c36..9fb06633f62c0 100644 --- a/ui/analyse/src/socket.ts +++ b/ui/analyse/src/socket.ts @@ -61,7 +61,6 @@ export type StudySocketSendParams = | [t: 'anaDests', d: AnaDestsReq] | [t: 'like', d: { liked: boolean }] | [t: 'kick', username: string] - | [t: 'kickBroadcast', d: { userId: string; tourId: string }] | [t: 'editStudy', d: StudyFormData] | [t: 'setTopics', topics: string[]] | [t: 'requestAnalysis', chapterId: string] diff --git a/ui/analyse/src/study/studyMembers.ts b/ui/analyse/src/study/studyMembers.ts index 21a13dcc7fa90..50dce92d8b0bd 100644 --- a/ui/analyse/src/study/studyMembers.ts +++ b/ui/analyse/src/study/studyMembers.ts @@ -24,7 +24,6 @@ export interface StudyMemberCtrl { max: number; setRole(id: string, role: string): void; kick(id: string): void; - kickBroadcast(id: string, tourId: string): void; leave(): void; ordered(): StudyMember[]; size(): number; @@ -146,10 +145,6 @@ export function ctrl(opts: Opts): StudyMemberCtrl { opts.send('kick', id); confing(null); }, - kickBroadcast(id: string, tourId: string) { - opts.send('kickBroadcast', { userId: id, tourId: tourId }); - confing(null); - }, leave() { opts.send('leave'); }, @@ -260,14 +255,7 @@ export function view(ctrl: StudyCtrl): VNode { 'a.button.button-red.button-empty.text', { attrs: dataIcon(licon.X), - hook: bind( - 'click', - _ => - ctrl.relay - ? members.kickBroadcast(member.user.id, ctrl.relay.data.tour.id) - : members.kick(member.user.id), - ctrl.redraw, - ), + hook: bind('click', _ => members.kick(member.user.id), ctrl.redraw), }, ctrl.trans.noarg('kick'), ), From a118ab791fbc5bd4514b16a2142fbc1b5fdc8cf8 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 17 Sep 2023 18:43:33 +0200 Subject: [PATCH 06/15] partial revert of 9e6553d419e3e8b1fd4948601076d29b7646f733 --- app/controllers/RelayTour.scala | 8 -------- conf/routes | 1 - ui/analyse/src/study/studyMembers.ts | 5 +---- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/app/controllers/RelayTour.scala b/app/controllers/RelayTour.scala index ea9be162d6aa9..91da3b5e4a2c3 100644 --- a/app/controllers/RelayTour.scala +++ b/app/controllers/RelayTour.scala @@ -94,14 +94,6 @@ final class RelayTour(env: Env, apiC: => Api, prismicC: => Prismic) extends Lila ) } - def admin(id: TourModel.Id) = Secure(_.StudyAdmin) { ctx ?=> me ?=> - env.relay.api - .roundIdsById(id) - .flatMap(_.map(studyId => env.study.api.adminInvite(studyId, me.userId)).parallel) - .inject: - if HTTPRequest.isXhr(ctx.req) then NoContent else Redirect(routes.Study.show(id)) - } - def delete(id: TourModel.Id) = AuthOrScoped(_.Study.Write) { _ ?=> me ?=> WithTour(id): tour => env.relay.api.deleteTourIfOwner(tour) inject Redirect(routes.RelayTour.by(me.username)).flashSuccess diff --git a/conf/routes b/conf/routes index 53749d8d0911c..6f02cbe080cc0 100644 --- a/conf/routes +++ b/conf/routes @@ -246,7 +246,6 @@ GET /api/broadcast/$tourId<\w{8}>.pgn controllers.RelayTour.pgn(tourId) GET /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.edit(tourId) POST /broadcast/$tourId<\w{8}>/edit controllers.RelayTour.update(tourId) POST /broadcast/$tourId<\w{8}>/delete controllers.RelayTour.delete(tourId) -POST /broadcast/$tourId<\w{8}>/admin controllers.RelayTour.admin(tourId) GET /broadcast/$tourId<\w{8}>/new controllers.RelayRound.form(tourId) POST /broadcast/$tourId<\w{8}>/new controllers.RelayRound.create(tourId) GET /broadcast/:ts/:rs/$roundId<\w{8}> controllers.RelayRound.show(ts, rs, roundId) diff --git a/ui/analyse/src/study/studyMembers.ts b/ui/analyse/src/study/studyMembers.ts index 50dce92d8b0bd..27dd7ad60b249 100644 --- a/ui/analyse/src/study/studyMembers.ts +++ b/ui/analyse/src/study/studyMembers.ts @@ -309,10 +309,7 @@ export function view(ctrl: StudyCtrl): VNode { { key: ':admin', hook: bindNonPassive('submit', () => { - const adminUrl = ctrl.relay - ? `/broadcast/${ctrl.relay.data.tour.id}/admin` - : `/study/${ctrl.data.id}/admin`; - xhrTextRaw(adminUrl, { method: 'post' }).then(() => location.reload()); + xhrTextRaw(`/study/${ctrl.data.id}/admin`, { method: 'post' }).then(() => location.reload()); return false; }), }, From 0bb00fc49d905d3f827e19052b75806b1a08d44a Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 14:33:59 +0200 Subject: [PATCH 07/15] use the Me type in AdminStudy --- app/controllers/RelayTour.scala | 2 +- app/controllers/Study.scala | 4 ++-- modules/study/src/main/StudyApi.scala | 2 +- modules/study/src/main/StudyInvite.scala | 2 +- modules/study/src/main/actorApi.scala | 3 ++- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/controllers/RelayTour.scala b/app/controllers/RelayTour.scala index 91da3b5e4a2c3..fe65f1b72d55e 100644 --- a/app/controllers/RelayTour.scala +++ b/app/controllers/RelayTour.scala @@ -5,7 +5,7 @@ import views.* import lila.app.{ given, * } import lila.common.config.MaxPerSecond -import lila.common.{ config, IpAddress, HTTPRequest } +import lila.common.{ config, IpAddress } import lila.relay.{ RelayTour as TourModel } final class RelayTour(env: Env, apiC: => Api, prismicC: => Prismic) extends LilaController(env): diff --git a/app/controllers/Study.scala b/app/controllers/Study.scala index 221ad8b35f199..55613d778943e 100644 --- a/app/controllers/Study.scala +++ b/app/controllers/Study.scala @@ -314,9 +314,9 @@ final class Study( } def admin(id: StudyId) = Secure(_.StudyAdmin) { ctx ?=> me ?=> - Bus.publish(AdminStudy(id, me.userId), "adminStudy") + Bus.publish(AdminStudy(id, me), "adminStudy") env.study.api - .adminInvite(id, me.userId) + .adminInvite(id, me) .inject: if HTTPRequest.isXhr(ctx.req) then NoContent else Redirect(routes.Study.show(id)) } diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index 119c41e1e5df9..fe2ff823c0487 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -777,7 +777,7 @@ final class StudyApi( Contribute(by.id, study): chapterRepo deleteByStudy study - def adminInvite(studyId: StudyId, by: UserId): Funit = + def adminInvite(studyId: StudyId, by: Me): Funit = sequenceStudy(studyId)(inviter.admin(by)) private def indexStudy(study: Study) = diff --git a/modules/study/src/main/StudyInvite.scala b/modules/study/src/main/StudyInvite.scala index 4826a6a8b98aa..0551404eff142 100644 --- a/modules/study/src/main/StudyInvite.scala +++ b/modules/study/src/main/StudyInvite.scala @@ -74,7 +74,7 @@ final private class StudyInvite( .void yield invited - def admin(by: UserId)(study: Study): Funit = + def admin(by: Me)(study: Study): Funit = studyRepo.coll: _.update .one( diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/actorApi.scala index 8a9f5bb785e5a..7352bb1c101c1 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/actorApi.scala @@ -2,6 +2,7 @@ package lila.study package actorApi import chess.format.UciPath +import lila.user.Me case class StartStudy(studyId: StudyId) case class SaveStudy(study: Study) @@ -14,5 +15,5 @@ case class ExplorerGame(ch: StudyChapterId, path: UciPath, gameId: GameId, inser case class Who(u: UserId, sri: lila.socket.Socket.Sri) case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) case class Kick(studyId: StudyId, userId: UserId, who: UserId) -case class AdminStudy(studyId: StudyId, by: UserId) +case class AdminStudy(studyId: StudyId, by: Me) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) From 94fb08e8602d961b4cc409b706d5a451752ec251 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 14:40:00 +0200 Subject: [PATCH 08/15] some renaming related to BelongStudyAdmin --- app/controllers/Study.scala | 6 +++--- modules/relay/src/main/Env.scala | 4 ++-- modules/study/src/main/StudyApi.scala | 4 ++-- modules/study/src/main/StudyInvite.scala | 6 +++--- modules/study/src/main/actorApi.scala | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/controllers/Study.scala b/app/controllers/Study.scala index 55613d778943e..db97a7b27dbf5 100644 --- a/app/controllers/Study.scala +++ b/app/controllers/Study.scala @@ -7,7 +7,7 @@ import scala.util.chaining.* import lila.app.{ given, * } import lila.common.paginator.{ Paginator, PaginatorJson } import lila.common.{ Bus, HTTPRequest, IpAddress } -import lila.study.actorApi.{ AdminStudy, Who } +import lila.study.actorApi.{ BecomeStudyAdmin, Who } import lila.study.JsonView.JsData import lila.study.Study.WithChapter import lila.study.{ Order, StudyForm, Study as StudyModel } @@ -314,9 +314,9 @@ final class Study( } def admin(id: StudyId) = Secure(_.StudyAdmin) { ctx ?=> me ?=> - Bus.publish(AdminStudy(id, me), "adminStudy") + Bus.publish(BecomeStudyAdmin(id, me), "adminStudy") env.study.api - .adminInvite(id, me) + .becomeAdmin(id, me) .inject: if HTTPRequest.isXhr(ctx.req) then NoContent else Redirect(routes.Study.show(id)) } diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index a09674959da75..70b497a76f4cd 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -81,13 +81,13 @@ final class Env( .foreach(_.foreach: tourId => api.kickBroadcast(userId, tourId, who)) }, - "adminStudy" -> { case lila.study.actorApi.AdminStudy(studyId, by) => + "adminStudy" -> { case lila.study.actorApi.BecomeStudyAdmin(studyId, me) => roundRepo .tourIdByStudyId(studyId) .foreach(_.foreach: tourId => api .roundIdsById(tourId) - .foreach(_.foreach(studyId => studyApi.adminInvite(studyId, by)))) + .foreach(_.foreach(studyId => studyApi.becomeAdmin(studyId, me)))) }, "isOfficialRelay" -> { case lila.study.actorApi.IsOfficialRelay(studyId, promise) => promise completeWith api.isOfficial(studyId) diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index fe2ff823c0487..27243448784af 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -777,8 +777,8 @@ final class StudyApi( Contribute(by.id, study): chapterRepo deleteByStudy study - def adminInvite(studyId: StudyId, by: Me): Funit = - sequenceStudy(studyId)(inviter.admin(by)) + def becomeAdmin(studyId: StudyId, me: Me): Funit = + sequenceStudy(studyId)(inviter.becomeAdmin(me)) private def indexStudy(study: Study) = Bus.publish(actorApi.SaveStudy(study), "study") diff --git a/modules/study/src/main/StudyInvite.scala b/modules/study/src/main/StudyInvite.scala index 0551404eff142..bcbb02344bde8 100644 --- a/modules/study/src/main/StudyInvite.scala +++ b/modules/study/src/main/StudyInvite.scala @@ -74,12 +74,12 @@ final private class StudyInvite( .void yield invited - def admin(by: Me)(study: Study): Funit = + def becomeAdmin(me: Me)(study: Study): Funit = studyRepo.coll: _.update .one( $id(study.id), - $set(s"members.${by}" -> $doc("role" -> "w", "admin" -> true)) ++ - $addToSet("uids" -> by) + $set(s"members.${me}" -> $doc("role" -> "w", "admin" -> true)) ++ + $addToSet("uids" -> me) ) .void diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/actorApi.scala index 7352bb1c101c1..9ae6ec4ae5f5b 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/actorApi.scala @@ -15,5 +15,5 @@ case class ExplorerGame(ch: StudyChapterId, path: UciPath, gameId: GameId, inser case class Who(u: UserId, sri: lila.socket.Socket.Sri) case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) case class Kick(studyId: StudyId, userId: UserId, who: UserId) -case class AdminStudy(studyId: StudyId, by: Me) +case class BecomeStudyAdmin(studyId: StudyId, me: Me) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) From d1e48bc98043a4d0bc4c5577c04c65d22b7797b9 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 14:42:25 +0200 Subject: [PATCH 09/15] use coll.primitiveOne --- modules/relay/src/main/RelayRoundRepo.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/relay/src/main/RelayRoundRepo.scala b/modules/relay/src/main/RelayRoundRepo.scala index 3f148ed9c4d55..1d8e19274ed6f 100644 --- a/modules/relay/src/main/RelayRoundRepo.scala +++ b/modules/relay/src/main/RelayRoundRepo.scala @@ -25,7 +25,7 @@ final private class RelayRoundRepo(val coll: Coll)(using Executor): .map(_.flatMap(_.getAsOpt[RelayRoundId]("_id"))) def tourIdByStudyId(studyId: StudyId): Fu[Option[RelayTour.Id]] = - coll.byId[Bdoc](studyId).map(_.flatMap(_.getAsOpt[RelayTour.Id]("tourId"))) + coll.primitiveOne[RelayTour.Id]($id(studyId), "tourId") def idsByTourId(tourId: RelayTour.Id): Fu[List[StudyId]] = coll From 5ac5d4533adcbac1f103aaf4f34d9efce60e0fa9 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 14:54:12 +0200 Subject: [PATCH 10/15] move `def becomeStudyAdmin` and return its Future --- modules/relay/src/main/Env.scala | 7 +------ modules/relay/src/main/RelayApi.scala | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index 70b497a76f4cd..11bea5a8651b1 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -82,12 +82,7 @@ final class Env( api.kickBroadcast(userId, tourId, who)) }, "adminStudy" -> { case lila.study.actorApi.BecomeStudyAdmin(studyId, me) => - roundRepo - .tourIdByStudyId(studyId) - .foreach(_.foreach: tourId => - api - .roundIdsById(tourId) - .foreach(_.foreach(studyId => studyApi.becomeAdmin(studyId, me)))) + api.becomeStudyAdmin(studyId, me) }, "isOfficialRelay" -> { case lila.study.actorApi.IsOfficialRelay(studyId, promise) => promise completeWith api.isOfficial(studyId) diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala index cd25a4934edd3..2320b316ae62e 100644 --- a/modules/relay/src/main/RelayApi.scala +++ b/modules/relay/src/main/RelayApi.scala @@ -379,6 +379,13 @@ final class RelayApi( private[relay] def onStudyRemove(studyId: StudyId) = roundRepo.coll.delete.one($id(studyId into RelayRoundId)).void + private[relay] def becomeStudyAdmin(studyId: StudyId, me: Me): Funit = + roundRepo + .tourIdByStudyId(studyId) + .flatMapz: tourId => + roundIdsById(tourId).flatMap: + _.map(studyApi.becomeAdmin(_, me)).sequence.void + private def sendToContributors(id: RelayRoundId, t: String, msg: JsObject): Funit = studyApi members id.into(StudyId) map { _.map(_.contributorIds).withFilter(_.nonEmpty) foreach { userIds => From c328b67be678131c56b71a988d2c71a6ab61f659 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 15:07:04 +0200 Subject: [PATCH 11/15] use MyId type to better distinguish the 2 users --- modules/relay/src/main/RelayApi.scala | 4 ++-- modules/study/src/main/StudyApi.scala | 6 +++--- modules/study/src/main/StudySocket.scala | 7 ++++--- modules/study/src/main/actorApi.scala | 7 ++++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala index 2320b316ae62e..9195a85e1394e 100644 --- a/modules/relay/src/main/RelayApi.scala +++ b/modules/relay/src/main/RelayApi.scala @@ -12,7 +12,7 @@ import lila.db.dsl.{ *, given } import lila.memo.CacheApi import lila.study.{ Settings, Study, StudyApi, StudyId, StudyMaker, StudyMultiBoard, StudyRepo } import lila.security.Granter -import lila.user.{ User, Me } +import lila.user.{ User, Me, MyId } import lila.relay.RelayTour.ActiveWithSomeRounds final class RelayApi( @@ -61,7 +61,7 @@ final class RelayApi( def roundIdsById(tourId: RelayTour.Id): Fu[List[StudyId]] = roundRepo.idsByTourId(tourId) - def kickBroadcast(userId: UserId, tourId: RelayTour.Id, who: UserId): Unit = + def kickBroadcast(userId: UserId, tourId: RelayTour.Id, who: MyId): Unit = roundIdsById(tourId).foreach(_.foreach(studyId => studyApi.kick(studyId, userId, who))) def withRounds(tour: RelayTour) = roundRepo.byTourOrdered(tour).dmap(tour.withRounds) diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index 27243448784af..7f55d15318e83 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -13,7 +13,7 @@ import lila.security.Granter import lila.socket.Socket.Sri import lila.tree.Node.{ Comment, Gamebook, Shapes } import lila.tree.{ Branch, Branches } -import lila.user.{ Me, User } +import lila.user.{ Me, User, MyId } final class StudyApi( studyRepo: StudyRepo, @@ -362,13 +362,13 @@ final class StudyApi( ) .void - def kick(studyId: StudyId, userId: UserId, who: UserId) = + def kick(studyId: StudyId, userId: UserId, who: MyId) = sequenceStudy(studyId): study => studyRepo .isAdminMember(study, who) .flatMap: isAdmin => val allowed = study.isMember(userId) && { - (isAdmin && !study.isOwner(userId)) || (study.isOwner(who) ^ (who == userId)) + (isAdmin && !study.isOwner(userId)) || (study.isOwner(who) ^ (who is userId)) } allowed.so: studyRepo.removeMember(study, userId) andDo diff --git a/modules/study/src/main/StudySocket.scala b/modules/study/src/main/StudySocket.scala index d77c510cfc8a0..3526cf0ec32fb 100644 --- a/modules/study/src/main/StudySocket.scala +++ b/modules/study/src/main/StudySocket.scala @@ -14,6 +14,7 @@ import lila.socket.Socket.{ makeMessage, Sri } import lila.socket.{ AnaAny, AnaDests, AnaDrop, AnaMove } import lila.tree.Node.{ defaultNodeJsonWriter, Comment, Gamebook, Shape, Shapes } import lila.tree.Branch +import lila.user.MyId final private class StudySocket( api: StudyApi, @@ -114,12 +115,12 @@ final private class StudySocket( o.get[UserStr]("d") .foreach: username => applyWho: w => - api.kick(studyId, username.id, w.u) - Bus.publish(actorApi.Kick(studyId, username.id, w.u), "kickStudy") + api.kick(studyId, username.id, w.myId) + Bus.publish(actorApi.Kick(studyId, username.id, w.myId), "kickStudy") case "leave" => who.foreach: w => - api.kick(studyId, w.u, w.u) + api.kick(studyId, w.u, w.myId) case "shapes" => reading[AtPosition](o): position => diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/actorApi.scala index 9ae6ec4ae5f5b..63319541a16d3 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/actorApi.scala @@ -2,7 +2,7 @@ package lila.study package actorApi import chess.format.UciPath -import lila.user.Me +import lila.user.{ Me, MyId } case class StartStudy(studyId: StudyId) case class SaveStudy(study: Study) @@ -12,8 +12,9 @@ case class ExplorerGame(ch: StudyChapterId, path: UciPath, gameId: GameId, inser def chapterId = ch val position = Position.Ref(chapterId, path) -case class Who(u: UserId, sri: lila.socket.Socket.Sri) +case class Who(u: UserId, sri: lila.socket.Socket.Sri): + def myId = u into MyId case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) -case class Kick(studyId: StudyId, userId: UserId, who: UserId) +case class Kick(studyId: StudyId, userId: UserId, who: MyId) case class BecomeStudyAdmin(studyId: StudyId, me: Me) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) From 3f972cb24c4a563058ed27f832562c399565057a Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 15:08:24 +0200 Subject: [PATCH 12/15] return kickBroadcast future --- modules/relay/src/main/RelayApi.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala index 9195a85e1394e..b9596c8f141ca 100644 --- a/modules/relay/src/main/RelayApi.scala +++ b/modules/relay/src/main/RelayApi.scala @@ -61,8 +61,9 @@ final class RelayApi( def roundIdsById(tourId: RelayTour.Id): Fu[List[StudyId]] = roundRepo.idsByTourId(tourId) - def kickBroadcast(userId: UserId, tourId: RelayTour.Id, who: MyId): Unit = - roundIdsById(tourId).foreach(_.foreach(studyId => studyApi.kick(studyId, userId, who))) + def kickBroadcast(userId: UserId, tourId: RelayTour.Id, who: MyId): Funit = + roundIdsById(tourId).flatMap: + _.map(studyApi.kick(_, userId, who)).parallel.void def withRounds(tour: RelayTour) = roundRepo.byTourOrdered(tour).dmap(tour.withRounds) From 3e0ec2456d65b23733acf294a0018c67dc262b73 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 15:10:55 +0200 Subject: [PATCH 13/15] use coll.primitive --- modules/relay/src/main/RelayRoundRepo.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/relay/src/main/RelayRoundRepo.scala b/modules/relay/src/main/RelayRoundRepo.scala index 1d8e19274ed6f..ebb7a13bed2f1 100644 --- a/modules/relay/src/main/RelayRoundRepo.scala +++ b/modules/relay/src/main/RelayRoundRepo.scala @@ -17,12 +17,12 @@ final private class RelayRoundRepo(val coll: Coll)(using Executor): .list(RelayTour.maxRelays) def idsByTourOrdered(tour: RelayTour): Fu[List[RelayRoundId]] = - coll - .find(selectors.tour(tour.id), $id(true).some) - .sort(sort.chrono) - .cursor[Bdoc]() - .list(RelayTour.maxRelays) - .map(_.flatMap(_.getAsOpt[RelayRoundId]("_id"))) + coll.primitive[RelayRoundId]( + selector = selectors.tour(tour.id), + sort = sort.chrono, + nb = RelayTour.maxRelays, + field = "_id" + ) def tourIdByStudyId(studyId: StudyId): Fu[Option[RelayTour.Id]] = coll.primitiveOne[RelayTour.Id]($id(studyId), "tourId") From f8ade06dd25d99bbe214153bf8e023637c56d207 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 15:14:40 +0200 Subject: [PATCH 14/15] fix me typing --- modules/study/src/main/StudyApi.scala | 2 +- modules/study/src/main/StudyInvite.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index 7f55d15318e83..20cebf0af7d25 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -777,7 +777,7 @@ final class StudyApi( Contribute(by.id, study): chapterRepo deleteByStudy study - def becomeAdmin(studyId: StudyId, me: Me): Funit = + def becomeAdmin(studyId: StudyId, me: MyId): Funit = sequenceStudy(studyId)(inviter.becomeAdmin(me)) private def indexStudy(study: Study) = diff --git a/modules/study/src/main/StudyInvite.scala b/modules/study/src/main/StudyInvite.scala index bcbb02344bde8..ecaf58afa202e 100644 --- a/modules/study/src/main/StudyInvite.scala +++ b/modules/study/src/main/StudyInvite.scala @@ -5,7 +5,7 @@ import lila.notify.{ InvitedToStudy, NotifyApi } import lila.pref.Pref import lila.relation.{ Block, Follow } import lila.security.Granter -import lila.user.{ Me, User } +import lila.user.{ Me, User, MyId } final private class StudyInvite( studyRepo: StudyRepo, @@ -74,7 +74,7 @@ final private class StudyInvite( .void yield invited - def becomeAdmin(me: Me)(study: Study): Funit = + def becomeAdmin(me: MyId)(study: Study): Funit = studyRepo.coll: _.update .one( From 61c27df26d68150c63af61ed6f300b2d83b3a1de Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Mon, 18 Sep 2023 15:17:06 +0200 Subject: [PATCH 15/15] avoid discarding the future too early it is eventually discarded in this specific case, I still like it better that way --- modules/relay/src/main/Env.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index 11bea5a8651b1..033e52b0bc1c9 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -76,10 +76,7 @@ final class Env( } }, "kickStudy" -> { case lila.study.actorApi.Kick(studyId, userId, who) => - roundRepo - .tourIdByStudyId(studyId) - .foreach(_.foreach: tourId => - api.kickBroadcast(userId, tourId, who)) + roundRepo.tourIdByStudyId(studyId).flatMapz(api.kickBroadcast(userId, _, who)) }, "adminStudy" -> { case lila.study.actorApi.BecomeStudyAdmin(studyId, me) => api.becomeStudyAdmin(studyId, me)