From 934e529eca603bdad73ee69572f99dcec0236b54 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sat, 7 Jun 2025 22:51:13 +0100 Subject: [PATCH 1/3] Always allow a map's user-tags to be read --- .../Visual/Ranking/TestSceneUserTagControl.cs | 2 +- .../Ranking/Statistics/StatisticsPanel.cs | 26 ++++++++++++--- osu.Game/Screens/Ranking/UserTagControl.cs | 32 +++++++++++++------ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs b/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs index c546c9727c..fb6be1daed 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs @@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.Ranking Child = new PopoverContainer { RelativeSizeAxes = Axes.Both, - Child = new UserTagControl(Beatmap.Value.BeatmapInfo) + Child = new UserTagControl(Beatmap.Value.BeatmapInfo, true) { Width = 700, Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index c33514e343..169a8b4f12 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -265,7 +265,7 @@ namespace osu.Game.Screens.Ranking.Statistics if (preventTaggingReason == null) { - yield return new StatisticItem("Tag the beatmap!", () => new UserTagControl(newScore.BeatmapInfo) + yield return new StatisticItem("Tag the beatmap!", () => new UserTagControl(newScore.BeatmapInfo, true) { RelativeSizeAxes = Axes.X, Anchor = Anchor.Centre, @@ -274,12 +274,30 @@ namespace osu.Game.Screens.Ranking.Statistics } else { - yield return new StatisticItem("Tag the beatmap!", () => new OsuTextFlowContainer(cp => cp.Font = OsuFont.GetFont(size: StatisticItem.FONT_SIZE, weight: FontWeight.SemiBold)) + yield return new StatisticItem("Tag the beatmap!", () => new FillFlowContainer { + Children = new CompositeDrawable[] + { + new OsuTextFlowContainer(cp => cp.Font = OsuFont.GetFont(size: StatisticItem.FONT_SIZE, weight: FontWeight.SemiBold)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.Centre, + Text = preventTaggingReason, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new UserTagControl(newScore.BeatmapInfo, false) + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - TextAnchor = Anchor.Centre, - Text = preventTaggingReason, + Direction = FillDirection.Vertical, + Spacing = new Vector2(4), }); } } diff --git a/osu.Game/Screens/Ranking/UserTagControl.cs b/osu.Game/Screens/Ranking/UserTagControl.cs index e323107783..b61ed4dcda 100644 --- a/osu.Game/Screens/Ranking/UserTagControl.cs +++ b/osu.Game/Screens/Ranking/UserTagControl.cs @@ -42,14 +42,20 @@ namespace osu.Game.Screens.Ranking private readonly Bindable apiBeatmap = new Bindable(); - private AddNewTagUserTag addNewTagUserTag = null!; + private AddNewTagUserTag? addNewTagUserTag; + + /// + /// Determines whether the user can modify the contained tags + /// + private readonly bool writable; [Resolved] private IAPIProvider api { get; set; } = null!; - public UserTagControl(BeatmapInfo beatmapInfo) + public UserTagControl(BeatmapInfo beatmapInfo, bool writable) { this.beatmapInfo = beatmapInfo; + this.writable = writable; } [BackgroundDependencyLoader] @@ -88,12 +94,17 @@ namespace osu.Game.Screens.Ranking AutoSizeAxes = Axes.Y, Direction = FillDirection.Full, Spacing = new Vector2(4), - Child = addNewTagUserTag = new AddNewTagUserTag - { - AvailableTags = { BindTarget = relevantTagsById }, - OnTagSelected = toggleVote, - }, - }, + Children = writable + ? + [ + addNewTagUserTag = new AddNewTagUserTag + { + AvailableTags = { BindTarget = relevantTagsById }, + OnTagSelected = toggleVote, + } + ] + : [] + } }, }, } @@ -191,7 +202,7 @@ namespace osu.Game.Screens.Ranking case NotifyCollectionChangedAction.Reset: { tagFlow.Clear(); - tagFlow.Add(addNewTagUserTag); + if (writable) tagFlow.Add(addNewTagUserTag!); break; } } @@ -199,6 +210,9 @@ namespace osu.Game.Screens.Ranking private void toggleVote(UserTag tag) { + if (!writable) + return; + if (tag.Updating.Value) return; From 33905f2e7022f91c7c6d7da6bd69df596c941ac1 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Wed, 11 Jun 2025 04:34:13 +0100 Subject: [PATCH 2/3] Address review comments --- .../Visual/Ranking/TestSceneStatisticsPanel.cs | 2 ++ .../Visual/Ranking/TestSceneUserTagControl.cs | 3 ++- .../Screens/Ranking/Statistics/StatisticsPanel.cs | 6 ++++-- osu.Game/Screens/Ranking/UserTagControl.cs | 11 +++++------ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs index f92dc0313e..b682ec7265 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs @@ -256,6 +256,7 @@ namespace osu.Game.Tests.Visual.Ranking var score = TestResources.CreateTestScoreInfo(); score.Rank = ScoreRank.D; + setUpTaggingRequests(() => score.BeatmapInfo); AddStep("load panel", () => { Child = new PopoverContainer @@ -278,6 +279,7 @@ namespace osu.Game.Tests.Visual.Ranking var score = TestResources.CreateTestScoreInfo(); score.Ruleset = new ManiaRuleset().RulesetInfo; + setUpTaggingRequests(() => score.BeatmapInfo); AddStep("load panel", () => { Child = new PopoverContainer diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs b/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs index fb6be1daed..a3ffe0dba2 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs @@ -100,8 +100,9 @@ namespace osu.Game.Tests.Visual.Ranking Child = new PopoverContainer { RelativeSizeAxes = Axes.Both, - Child = new UserTagControl(Beatmap.Value.BeatmapInfo, true) + Child = new UserTagControl(Beatmap.Value.BeatmapInfo) { + Writable = true, Width = 700, Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 169a8b4f12..3c1aec745d 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -265,8 +265,9 @@ namespace osu.Game.Screens.Ranking.Statistics if (preventTaggingReason == null) { - yield return new StatisticItem("Tag the beatmap!", () => new UserTagControl(newScore.BeatmapInfo, true) + yield return new StatisticItem("Tag the beatmap!", () => new UserTagControl(newScore.BeatmapInfo) { + Writable = true, RelativeSizeAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -287,8 +288,9 @@ namespace osu.Game.Screens.Ranking.Statistics Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new UserTagControl(newScore.BeatmapInfo, false) + new UserTagControl(newScore.BeatmapInfo) { + Writable = false, RelativeSizeAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/UserTagControl.cs b/osu.Game/Screens/Ranking/UserTagControl.cs index b61ed4dcda..a66721782e 100644 --- a/osu.Game/Screens/Ranking/UserTagControl.cs +++ b/osu.Game/Screens/Ranking/UserTagControl.cs @@ -47,15 +47,14 @@ namespace osu.Game.Screens.Ranking /// /// Determines whether the user can modify the contained tags /// - private readonly bool writable; + public bool Writable { get; init; } [Resolved] private IAPIProvider api { get; set; } = null!; - public UserTagControl(BeatmapInfo beatmapInfo, bool writable) + public UserTagControl(BeatmapInfo beatmapInfo) { this.beatmapInfo = beatmapInfo; - this.writable = writable; } [BackgroundDependencyLoader] @@ -94,7 +93,7 @@ namespace osu.Game.Screens.Ranking AutoSizeAxes = Axes.Y, Direction = FillDirection.Full, Spacing = new Vector2(4), - Children = writable + Children = Writable ? [ addNewTagUserTag = new AddNewTagUserTag @@ -202,7 +201,7 @@ namespace osu.Game.Screens.Ranking case NotifyCollectionChangedAction.Reset: { tagFlow.Clear(); - if (writable) tagFlow.Add(addNewTagUserTag!); + if (Writable) tagFlow.Add(addNewTagUserTag!); break; } } @@ -210,7 +209,7 @@ namespace osu.Game.Screens.Ranking private void toggleVote(UserTag tag) { - if (!writable) + if (!Writable) return; if (tag.Updating.Value) From 988f1a4e7639a2d050f3dcdd8184bbaf843c21a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Jul 2025 16:46:07 +0900 Subject: [PATCH 3/3] Add test coverage of read-only scenario --- .../Visual/Ranking/TestSceneUserTagControl.cs | 33 +++++++++++++++++-- osu.Game/Screens/Ranking/UserTagControl.cs | 2 +- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs b/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs index 600f96eccc..03730c59ee 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneUserTagControl.cs @@ -28,11 +28,14 @@ namespace osu.Game.Tests.Visual.Ranking private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + private int writeRequestCount = 0; + [SetUpSteps] public void SetUpSteps() { AddStep("set up network requests", () => { + writeRequestCount = 0; dummyAPI.HandleRequest = request => { switch (request) @@ -77,6 +80,7 @@ namespace osu.Game.Tests.Visual.Ranking case AddBeatmapTagRequest: case RemoveBeatmapTagRequest: { + writeRequestCount++; Scheduler.AddDelayed(request.TriggerSuccess, 500); return true; } @@ -107,6 +111,31 @@ namespace osu.Game.Tests.Visual.Ranking }); } + [Test] + public void TestNotWritable() + { + AddStep("show", () => + { + var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); + working.BeatmapInfo.OnlineID = 42; + Beatmap.Value = working; + recreateControl(writable: false); + }); + + AddUntilStep("click tag", () => + { + var tag = this.ChildrenOfType().FirstOrDefault(t => t.UserTag.Id == 2); + if (tag == null) + return false; + + InputManager.MoveMouseTo(tag); + InputManager.Click(MouseButton.Left); + return true; + }); + + AddAssert("no vote requests send", () => writeRequestCount, () => Is.Zero); + } + [Test] public void TestTagsDoNotMoveUntilMouseMovesAway() { @@ -148,14 +177,14 @@ namespace osu.Game.Tests.Visual.Ranking UserTagControl.DrawableUserTag getDrawableTagById(long id) => getTagFlow().Single(t => t.UserTag.Id == id); } - private void recreateControl() + private void recreateControl(bool writable = true) { Child = new PopoverContainer { RelativeSizeAxes = Axes.Both, Child = new UserTagControl(Beatmap.Value.BeatmapInfo) { - Writable = true, + Writable = writable, Width = 700, Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/UserTagControl.cs b/osu.Game/Screens/Ranking/UserTagControl.cs index cc6ebe929a..1005e7ea2c 100644 --- a/osu.Game/Screens/Ranking/UserTagControl.cs +++ b/osu.Game/Screens/Ranking/UserTagControl.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Ranking /// /// Determines whether the user can modify the contained tags /// - public bool Writable { get; init; } + public bool Writable { private get; init; } private InputManager inputManager = null!;