Add the ability for moderators to forcibly lock levels (#831)

* Add the ability for moderators to forcibly lock levels

* Prevent forcibly locking an already locked level

I had to rollback and re-commit this because I was getting some weird error within Rider.

* Correct moderation notice header styling & remove errant text
This commit is contained in:
koko 2023-07-07 18:44:05 -04:00 committed by GitHub
parent df4d717763
commit 25bb2ecfc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 114 additions and 13 deletions

View file

@ -240,6 +240,12 @@ public class PublishController : ControllerBase
oldSlot.MinimumPlayers = Math.Clamp(slot.MinimumPlayers, 1, 4);
oldSlot.MaximumPlayers = Math.Clamp(slot.MaximumPlayers, 1, 4);
// Check if the level has been locked by a moderator to avoid unlocking it
if (oldSlot.LockedByModerator)
{
oldSlot.InitiallyLocked = true;
}
await this.database.SaveChangesAsync();
return this.Ok(SlotBase.CreateFromEntity(oldSlot, token));

View file

@ -26,12 +26,32 @@
@if (Model.Slot!.Hidden)
{
<div class="ui inverted red segment">
<h2>This level is currently hidden.</h2>
<p><b>Only you and moderators may view this level.</b></p>
<b>Reason:</b> <span>"@Model.Slot.HiddenReason"</span>
<p><b>For more information please contact a moderator.</b></p>
<h3><i class="ban icon"></i> This level is currently hidden.</h3>
@if (Model.User != null && Model.User.IsModerator)
{
<b>Reason:</b>
<span>"@Model.Slot.HiddenReason"</span>
}
else
{
<p>This level has been hidden for violating the Terms of Service. Remember to follow the rules!</p>
}
</div>
}
@if (Model.Slot!.LockedByModerator)
{
<div class="ui inverted red segment">
<h3><i class="lock icon"></i> This level has been locked by a moderator.</h3>
@if (Model.User != null && Model.User.IsModerator)
{
<b>Reason:</b>
<span>"@Model.Slot.LockedReason"</span>
}
else
{
<p>This level has been locked for violating the Terms of Service. Remember to follow the rules!</p>
}
</div>
}
@ -208,6 +228,16 @@
</a>
}
@if (!Model.Slot!.InitiallyLocked && !Model.Slot!.LockedByModerator)
{
<a href="/moderation/newCase?type=@((int)CaseType.LevelLock)&affectedId=@Model.Slot?.SlotId">
<div class="ui yellow button">
<i class="lock icon"></i>
<span>Forcibly Lock Level</span>
</div>
</a>
}
@if (Model.Slot!.CommentsEnabled)
{
<a class="ui yellow button" href="/moderation/newCase?type=@((int)CaseType.LevelDisableComments)&affectedId=@Model.Slot?.SlotId">

View file

@ -23,14 +23,11 @@
@if (Model.ProfileUser.IsBanned)
{
<div class="ui inverted red segment">
<h3 style="margin-bottom:5px;"><i class="ban icon"></i> This user is currently banned.</h3>
<h3><i class="ban icon"></i> This user is currently banned.</h3>
@if (Model.User != null && Model.User.IsModerator)
{
<b>Reason:</b>
<span>"@Model.ProfileUser.BannedReason"</span> <br />
<p>
<i>Only you and other moderators may view the ban reason.</i>
</p>
<span>"@Model.ProfileUser.BannedReason"</span>
}
else
{

View file

@ -77,6 +77,13 @@ public class PerformCaseActionsTask : IRepeatingTask
slot!.CommentsEnabled = true;
break;
}
case CaseType.LevelLock:
{
slot!.InitiallyLocked = false;
slot.LockedByModerator = false;
slot.LockedReason = "";
break;
}
default: throw new ArgumentOutOfRangeException();
}
}
@ -121,6 +128,13 @@ public class PerformCaseActionsTask : IRepeatingTask
slot!.CommentsEnabled = false;
break;
}
case CaseType.LevelLock:
{
slot!.InitiallyLocked = true;
slot.LockedByModerator = true;
slot.LockedReason = @case.Reason;
break;
}
default: throw new ArgumentOutOfRangeException();
}
}

View file

@ -0,0 +1,41 @@
using LBPUnion.ProjectLighthouse.Database;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ProjectLighthouse.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20230707125059_AddModerationLevelLocks")]
public partial class AddModerationLevelLocks : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "LockedByModerator",
table: "Slots",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<string>(
name: "LockedReason",
table: "Slots",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "LockedByModerator",
table: "Slots");
migrationBuilder.DropColumn(
name: "LockedReason",
table: "Slots");
}
}
}

View file

@ -16,7 +16,7 @@ namespace ProjectLighthouse.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.7")
.HasAnnotation("ProductVersion", "7.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Entities.Interaction.HeartedLevelEntity", b =>
@ -406,6 +406,13 @@ namespace ProjectLighthouse.Migrations
b.Property<ulong>("LocationPacked")
.HasColumnType("bigint unsigned");
b.Property<bool>("LockedByModerator")
.HasColumnType("tinyint(1)");
b.Property<string>("LockedReason")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("MaximumPlayers")
.HasColumnType("int");

View file

@ -66,6 +66,10 @@ public class SlotEntity
public UserEntity? Creator { get; set; }
public bool InitiallyLocked { get; set; }
public bool LockedByModerator { get; set; }
public string LockedReason { get; set; } = "";
public bool SubLevel { get; set; }

View file

@ -5,7 +5,7 @@ using LBPUnion.ProjectLighthouse.Extensions;
namespace LBPUnion.ProjectLighthouse.Types.Moderation.Cases;
// Next available ID for use: 6
// Next available ID for use: 7
// PLEASE UPDATE THIS WHEN YOU ADD SOMETHING HERE!
// IF YOU DO NOT ADD THIS IN ORDER PROPERLY THEN THERE WILL BE DATA CORRUPTION!
// THE VALUE MUST ALWAYS BE EXPLICITLY SET.
@ -18,6 +18,7 @@ public enum CaseType
LevelHide = 4,
LevelDisableComments = 5,
LevelLock = 6,
}
public static class CaseTypeExtensions
@ -40,6 +41,7 @@ public static class CaseTypeExtensions
{
CaseType.LevelHide => true,
CaseType.LevelDisableComments => true,
CaseType.LevelLock => true,
_ => false,
};
}