mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-04-19 19:14:51 +00:00
Implement read-only mode (#1001)
* Implement read-only mode * Use localized string under default language for announce text * Redirect to user page rather than returning blank 400 * Protect call to `ParseBase64Image` * Add protections to SlotSettingsPage and nitpick format * Display the latest announcement (if any) on the landing page * Fix a kokoism Accidentally tried to use markdown within the landing page... I'm rather smart aren't I * Prevent possible XSS * Separate truncated announcement text and link with "..." * Apply suggestion from code review * Add read-only check to /postComment in slot page controller * Fix inconsistent tabbing
This commit is contained in:
parent
975fcab100
commit
0ee8970c64
20 changed files with 176 additions and 18 deletions
|
@ -87,4 +87,10 @@
|
|||
<data name="license_warn_3" xml:space="preserve">
|
||||
<value>If not, please publish the source code somewhere accessible to your users.</value>
|
||||
</data>
|
||||
<data name="read_only_warn_title" xml:space="preserve">
|
||||
<value>Read-Only Mode</value>
|
||||
</data>
|
||||
<data name="read_only_warn" xml:space="preserve">
|
||||
<value>This instance is currently in read-only mode. Level and photo uploads, comments, reviews, and certain profile changes will be restricted until read-only mode is disabled.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -23,5 +23,8 @@ public static class BaseLayoutStrings
|
|||
public static readonly TranslatableString LicenseWarn2 = create("license_warn_2");
|
||||
public static readonly TranslatableString LicenseWarn3 = create("license_warn_3");
|
||||
|
||||
public static readonly TranslatableString ReadOnlyWarnTitle = create("read_only_warn_title");
|
||||
public static readonly TranslatableString ReadOnlyWarn = create("read_only_warn");
|
||||
|
||||
private static TranslatableString create(string key) => new(TranslationAreas.BaseLayout, key);
|
||||
}
|
|
@ -119,6 +119,9 @@ public class CommentController : ControllerBase
|
|||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
GameComment? comment = await this.DeserializeBody<GameComment>();
|
||||
if (comment?.Message == null) return this.BadRequest();
|
||||
|
||||
|
@ -159,6 +162,9 @@ public class CommentController : ControllerBase
|
|||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
||||
|
||||
CommentEntity? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
||||
|
|
|
@ -3,6 +3,8 @@ using LBPUnion.ProjectLighthouse.Configuration;
|
|||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Localization;
|
||||
using LBPUnion.ProjectLighthouse.Localization.StringLists;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Notifications;
|
||||
|
@ -59,6 +61,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
|||
announceText.Replace("%user", username);
|
||||
announceText.Replace("%id", token.UserId.ToString());
|
||||
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
{
|
||||
announceText.Insert(0, BaseLayoutStrings.ReadOnlyWarn.Translate(LocalizationManager.DefaultLang));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
announceText.Append("\n\n---DEBUG INFO---\n" +
|
||||
$"user.UserId: {token.UserId}\n" +
|
||||
|
|
|
@ -37,6 +37,9 @@ public class PhotosController : ControllerBase
|
|||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
int photoCount = await this.database.Photos.CountAsync(p => p.CreatorId == token.UserId);
|
||||
if (photoCount >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
|
||||
|
||||
|
@ -90,7 +93,7 @@ public class PhotosController : ControllerBase
|
|||
case SlotType.Developer:
|
||||
{
|
||||
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.Type == photoSlot.SlotType && s.InternalSlotId == photoSlot.SlotId);
|
||||
if (slot != null)
|
||||
if (slot != null)
|
||||
photoSlot.SlotId = slot.SlotId;
|
||||
else
|
||||
photoSlot.SlotId = await SlotHelper.GetPlaceholderSlotId(this.database, photoSlot.SlotId, photoSlot.SlotType);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#nullable enable
|
||||
using System.Text;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Files;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
@ -58,10 +59,14 @@ public class ResourcesController : ControllerBase
|
|||
string fullPath = Path.GetFullPath(path);
|
||||
|
||||
FileHelper.EnsureDirectoryCreated(assetsDirectory);
|
||||
// lbp treats code 409 as success and as an indicator that the file is already present
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
// LBP treats code 409 as success and as an indicator that the file is already present
|
||||
if (FileHelper.ResourceExists(hash)) return this.Conflict();
|
||||
|
||||
// theoretically shouldn't be possible because of hash check but handle anyways
|
||||
// Theoretically shouldn't be possible because of hash check but handle anyways
|
||||
if (!fullPath.StartsWith(FileHelper.FullResourcePath)) return this.BadRequest();
|
||||
|
||||
Logger.Info($"Processing resource upload (hash: {hash})", LogArea.Resources);
|
||||
|
|
|
@ -43,6 +43,9 @@ public class PublishController : ControllerBase
|
|||
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||
if (user == null) return this.Forbid();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
GameUserSlot? slot = await this.DeserializeBody<GameUserSlot>();
|
||||
if (slot == null)
|
||||
{
|
||||
|
@ -116,6 +119,9 @@ public class PublishController : ControllerBase
|
|||
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||
if (user == null) return this.Forbid();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
GameUserSlot? slot = await this.DeserializeBody<GameUserSlot>();
|
||||
|
||||
if (slot == null)
|
||||
|
@ -335,6 +341,9 @@ public class PublishController : ControllerBase
|
|||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
if (slot == null) return this.NotFound();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#nullable enable
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
@ -92,6 +93,9 @@ public class ReviewController : ControllerBase
|
|||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
GameReview? newReview = await this.DeserializeBody<GameReview>();
|
||||
if (newReview == null) return this.BadRequest();
|
||||
|
||||
|
@ -115,7 +119,7 @@ public class ReviewController : ControllerBase
|
|||
}
|
||||
review.Thumb = Math.Clamp(newReview.Thumb, -1, 1);
|
||||
review.LabelCollection = LabelHelper.RemoveInvalidLabels(newReview.LabelCollection);
|
||||
|
||||
|
||||
review.Text = newReview.Text;
|
||||
review.Deleted = false;
|
||||
review.Timestamp = TimeHelper.TimestampMillis;
|
||||
|
@ -239,6 +243,9 @@ public class ReviewController : ControllerBase
|
|||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
int creatorId = await this.database.Slots.Where(s => s.SlotId == slotId).Select(s => s.CreatorId).FirstOrDefaultAsync();
|
||||
if (creatorId == 0) return this.BadRequest();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Text.Json;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Files;
|
||||
|
@ -73,6 +74,9 @@ public class UserController : ControllerBase
|
|||
|
||||
if (update.Biography != null)
|
||||
{
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
if (update.Biography.Length > 512) return this.BadRequest();
|
||||
|
||||
user.Biography = update.Biography;
|
||||
|
@ -85,6 +89,9 @@ public class UserController : ControllerBase
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(resource)) continue;
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest();
|
||||
|
||||
if (!FileHelper.ResourceExists(resource) && !resource.StartsWith('g')) return this.BadRequest();
|
||||
|
||||
if (!GameResourceHelper.IsValidTexture(resource)) return this.BadRequest();
|
||||
|
|
|
@ -10,7 +10,7 @@ using LBPUnion.ProjectLighthouse.Types.Logging;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
// I would like to apologize in advance for anyone dealing with this file.
|
||||
// I would like to apologize in advance for anyone dealing with this file.
|
||||
// Theres probably a better way to do this with delegates but I'm tired.
|
||||
// TODO: Clean up this file
|
||||
// - jvyden
|
||||
|
@ -63,6 +63,9 @@ public class SlotPageController : ControllerBase
|
|||
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||
if (token == null) return this.Redirect("~/login");
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.Redirect("~/slot/" + id);
|
||||
|
||||
if (msg == null)
|
||||
{
|
||||
Logger.Error($"Refusing to post comment from {token.UserId} on level {id}, {nameof(msg)} is null", LogArea.Comments);
|
||||
|
|
|
@ -39,6 +39,9 @@ public class UserPageController : ControllerBase
|
|||
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||
if (token == null) return this.Redirect("~/login");
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.Redirect("~/user/" + id);
|
||||
|
||||
if (msg == null)
|
||||
{
|
||||
Logger.Error($"Refusing to post comment from {token.UserId} on user {id}, {nameof(msg)} is null", LogArea.Comments);
|
||||
|
|
|
@ -60,7 +60,42 @@
|
|||
}
|
||||
}
|
||||
|
||||
<br><br>
|
||||
@if (Model.LatestAnnouncement != null)
|
||||
{
|
||||
<div class="ui blue segment" style="position: relative;">
|
||||
<div>
|
||||
<h3>@Model.LatestAnnouncement.Title</h3>
|
||||
<div style="padding-bottom: 2em;">
|
||||
@if (Model.LatestAnnouncement.Content.Length > 250)
|
||||
{
|
||||
<span style="white-space: pre-line">
|
||||
@Model.LatestAnnouncement.Content[..250]...
|
||||
<a href="@ServerConfiguration.Instance.ExternalUrl/notifications">read more</a>
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span style="white-space: pre-line">
|
||||
@Model.LatestAnnouncement.Content
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
@if (Model.LatestAnnouncement.Publisher != null)
|
||||
{
|
||||
<div class="ui tiny bottom left attached label">
|
||||
Posted by
|
||||
<a style="color: black" href="~/user/@Model.LatestAnnouncement.Publisher.UserId">
|
||||
@Model.LatestAnnouncement.Publisher.Username
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<br /><br />
|
||||
}
|
||||
|
||||
<div class="@(isMobile ? "" : "ui center aligned grid")">
|
||||
<div class="eight wide column">
|
||||
|
|
|
@ -5,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Helpers;
|
|||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||
using LBPUnion.ProjectLighthouse.Types.Entities.Website;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -19,6 +20,8 @@ public class LandingPage : BaseLayout
|
|||
public int PendingAuthAttempts;
|
||||
public List<UserEntity> PlayersOnline = new();
|
||||
|
||||
public WebsiteAnnouncementEntity? LatestAnnouncement;
|
||||
|
||||
public LandingPage(DatabaseContext database) : base(database)
|
||||
{ }
|
||||
|
||||
|
@ -54,6 +57,10 @@ public class LandingPage : BaseLayout
|
|||
.Include(s => s.Creator)
|
||||
.ToListAsync();
|
||||
|
||||
this.LatestAnnouncement = await this.Database.WebsiteAnnouncements.Include(a => a.Publisher)
|
||||
.OrderByDescending(a => a.AnnouncementId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
}
|
|
@ -178,6 +178,18 @@
|
|||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
{
|
||||
<div class="ui bottom attached red message large">
|
||||
<div class="ui container">
|
||||
<i class="warning icon"></i>
|
||||
<span style="font-size: 1.2rem;">@Model.Translate(BaseLayoutStrings.ReadOnlyWarnTitle)</span>
|
||||
<p>
|
||||
@Html.Raw(Model.Translate(BaseLayoutStrings.ReadOnlyWarn))
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</header>
|
||||
<div class="main">
|
||||
<div class="ui container">
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@using System.Web
|
||||
@using LBPUnion.ProjectLighthouse.Configuration
|
||||
@using LBPUnion.ProjectLighthouse.Database
|
||||
@using LBPUnion.ProjectLighthouse.Localization
|
||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
||||
|
@ -31,18 +32,32 @@
|
|||
@if (Model.CommentsEnabled && Model.User != null)
|
||||
{
|
||||
<div class="ui divider"></div>
|
||||
<form class="ui reply form" action="postComment" method="post">
|
||||
<div class="field">
|
||||
<textarea style="min-height: 70px; height: 70px; max-height:120px" maxlength="100" name="msg"></textarea>
|
||||
@if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
{
|
||||
<div class="ui red segment">
|
||||
<p>
|
||||
<i>
|
||||
@ServerConfiguration.Instance.Customization.ServerName is currently in read-only mode.
|
||||
You will not be able to post comments until read-only mode is disabled.
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
<input type="submit" class="ui blue button">
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form class="ui reply form" action="postComment" method="post">
|
||||
<div class="field">
|
||||
<textarea style="min-height: 70px; height: 70px; max-height:120px" maxlength="100" name="msg"></textarea>
|
||||
</div>
|
||||
<input type="submit" class="ui blue button">
|
||||
</form>
|
||||
}
|
||||
@if (Model.Comments.Count > 0)
|
||||
{
|
||||
<div class="ui divider"></div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@{
|
||||
int i = 0;
|
||||
foreach (KeyValuePair<CommentEntity, RatedCommentEntity?> commentAndReaction in Model.Comments)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
@using LBPUnion.ProjectLighthouse.Helpers
|
||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
||||
@using LBPUnion.ProjectLighthouse.Types.Serialization
|
||||
|
||||
@{
|
||||
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
||||
bool canDelete = (bool?)ViewData["CanDelete"] ?? false;
|
||||
|
@ -29,6 +28,18 @@
|
|||
<div class="ui divider"></div>
|
||||
}
|
||||
|
||||
@if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
{
|
||||
<div class="ui red segment">
|
||||
<p>
|
||||
<i>
|
||||
@ServerConfiguration.Instance.Customization.ServerName is currently in read-only mode.
|
||||
You will not be able to post reviews in-game until read-only mode is disabled.
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@for(int i = 0; i < Model.Reviews.Count; i++)
|
||||
{
|
||||
ReviewEntity review = Model.Reviews[i];
|
||||
|
@ -36,7 +47,7 @@
|
|||
-1 => review.Reviewer?.BooHash,
|
||||
0 => review.Reviewer?.MehHash,
|
||||
1 => review.Reviewer?.YayHash,
|
||||
|
||||
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
}) ?? "";
|
||||
|
||||
|
@ -49,7 +60,7 @@
|
|||
-1 => "Boo!",
|
||||
0 => "Meh.",
|
||||
1 => "Yay!",
|
||||
|
||||
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
|
@ -114,7 +125,7 @@
|
|||
if (window.confirm("Are you sure you want to delete this?\nThis action cannot be undone.")){
|
||||
window.location.hash = "reviews";
|
||||
window.location.href = "/moderation/deleteReview/" + reviewId + "?callbackUrl=" + this.window.location;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#nullable enable
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
using LBPUnion.ProjectLighthouse.Files;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
@ -25,6 +26,10 @@ public class SlotSettingsPage : BaseLayout
|
|||
|
||||
if (!this.User.IsModerator && this.User != this.Slot.Creator) return this.Redirect("~/slot/" + slotId);
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
return this.Redirect($"~/slot/{slotId}");
|
||||
|
||||
string? avatarHash = await FileHelper.ParseBase64Image(avatar);
|
||||
|
||||
if (avatarHash != null) this.Slot.IconHash = avatarHash;
|
||||
|
@ -46,7 +51,7 @@ public class SlotSettingsPage : BaseLayout
|
|||
if (labels != null)
|
||||
{
|
||||
labels = LabelHelper.RemoveInvalidLabels(labels);
|
||||
if (this.Slot.AuthorLabels != labels)
|
||||
if (this.Slot.AuthorLabels != labels)
|
||||
this.Slot.AuthorLabels = labels;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ public class UserSettingsPage : BaseLayout
|
|||
|
||||
if (!this.User.IsModerator && this.User != this.ProfileUser) return this.Redirect("~/user/" + userId);
|
||||
|
||||
// Deny request if in read-only mode
|
||||
if (avatar != null && ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
return this.Redirect($"~/user/{userId}");
|
||||
|
||||
string? avatarHash = await FileHelper.ParseBase64Image(avatar);
|
||||
|
||||
if (avatarHash != null) this.ProfileUser.IconHash = avatarHash;
|
||||
|
@ -47,6 +51,10 @@ public class UserSettingsPage : BaseLayout
|
|||
|
||||
if (biography != null)
|
||||
{
|
||||
// Deny request if in read-only mode
|
||||
if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode)
|
||||
return this.Redirect($"~/user/{userId}");
|
||||
|
||||
biography = CensorHelper.FilterMessage(biography);
|
||||
if (this.ProfileUser.Biography != biography && biography.Length <= 512)
|
||||
this.ProfileUser.Biography = biography;
|
||||
|
|
|
@ -11,6 +11,12 @@ public class UserGeneratedContentLimitConfiguration
|
|||
|
||||
public int PhotosQuota { get; set; } = 500;
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, all UGC uploads are disabled. This includes levels, photos, reviews,
|
||||
/// comments, and certain profile settings.
|
||||
/// </summary>
|
||||
public bool ReadOnlyMode { get; set; } = false;
|
||||
|
||||
public bool ProfileCommentsEnabled { get; set; } = true;
|
||||
|
||||
public bool LevelCommentsEnabled { get; set; } = true;
|
||||
|
|
|
@ -11,7 +11,7 @@ public class ServerConfiguration : ConfigurationBase<ServerConfiguration>
|
|||
// This is so Lighthouse can properly identify outdated configurations and update them with newer settings accordingly.
|
||||
// If you are modifying anything here, this value MUST be incremented.
|
||||
// Thanks for listening~
|
||||
public override int ConfigVersion { get; set; } = 25;
|
||||
public override int ConfigVersion { get; set; } = 26;
|
||||
|
||||
public override string ConfigName { get; set; } = "lighthouse.yml";
|
||||
public string WebsiteListenUrl { get; set; } = "http://localhost:10060";
|
||||
|
|
Loading…
Add table
Reference in a new issue