mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-08-10 22:08:39 +00:00
Merge branch 'main' into mod-panel
This commit is contained in:
commit
ea25751e71
136 changed files with 4358 additions and 161 deletions
|
@ -46,4 +46,17 @@ public class RoomVisualizerController : ControllerBase
|
|||
return this.Redirect("/debug/roomVisualizer");
|
||||
#endif
|
||||
}
|
||||
|
||||
[HttpGet("createRoomsWithDuplicatePlayers")]
|
||||
public async Task<IActionResult> CreateRoomsWithDuplicatePlayers()
|
||||
{
|
||||
#if !DEBUG
|
||||
return this.NotFound();
|
||||
#else
|
||||
List<int> users = await this.database.Users.OrderByDescending(_ => EF.Functions.Random()).Take(1).Select(u => u.UserId).ToListAsync();
|
||||
RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2, Platform.PS3);
|
||||
RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2, Platform.PS3);
|
||||
return this.Redirect("/debug/roomVisualizer");
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using LBPUnion.ProjectLighthouse.Files;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IOFile = System.IO.File;
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
@page "/admin/keys"
|
||||
|
||||
@using LBPUnion.ProjectLighthouse.PlayerData
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin.AdminAPIKeyPageModel
|
||||
@{
|
||||
Layout = "Layouts/BaseLayout";
|
||||
Model.Title = "API Keys";
|
||||
}
|
||||
|
||||
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
|
||||
@{
|
||||
var token = Antiforgery.GetAndStoreTokens(HttpContext).RequestToken;
|
||||
}
|
||||
|
||||
<script>function deleteKey(keyID) {
|
||||
document.getElementById("trashbutton-".concat(keyID)).classList.add('loading');
|
||||
fetch("@Url.RouteUrl(ViewContext.RouteData.Values)", {
|
||||
method: 'post',
|
||||
headers: {
|
||||
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: 'keyID='.concat(keyID).concat("&__RequestVerificationToken=@token")
|
||||
})
|
||||
.then(function (data) {
|
||||
document.getElementById("keyitem-".concat(keyID)).remove();
|
||||
window.location.reload(true);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('Request failed', error);
|
||||
});
|
||||
|
||||
}</script>
|
||||
|
||||
<p>There are <b>@Model.KeyCount</b> API keys registered.</p>
|
||||
@if (Model.KeyCount == 0)
|
||||
{
|
||||
<p>To create one, you can use the "Create API key" command in the admin panel.</p>
|
||||
}
|
||||
|
||||
<div class="ui four column grid">
|
||||
@foreach (APIKey key in Model.APIKeys)
|
||||
{
|
||||
<div id="keyitem-@key.Id" class="five wide column">
|
||||
<div class="ui blue segment">
|
||||
<div class="ui tiny bottom left attached label">
|
||||
Created at: @key.Created.ToString()
|
||||
</div>
|
||||
<button id="trashbutton-@key.Id" class="right floated circular ui icon button" onclick="deleteKey(@key.Id);">
|
||||
<i class="trash can icon"></i>
|
||||
</button>
|
||||
<h2>@key.Description</h2>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
|
@ -0,0 +1,43 @@
|
|||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin
|
||||
{
|
||||
public class AdminAPIKeyPageModel : BaseLayout
|
||||
{
|
||||
public List<APIKey> APIKeys = new();
|
||||
public int KeyCount;
|
||||
|
||||
public AdminAPIKeyPageModel(Database database) : base(database)
|
||||
{ }
|
||||
|
||||
public async Task<IActionResult> OnGet()
|
||||
{
|
||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
if (!user.IsAdmin) return this.NotFound();
|
||||
|
||||
this.APIKeys = await this.Database.APIKeys.OrderByDescending(k => k.Id).ToListAsync();
|
||||
this.KeyCount = this.APIKeys.Count;
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPost(string keyID)
|
||||
{
|
||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||
|
||||
APIKey? apiKey = await this.Database.APIKeys.FirstOrDefaultAsync(k => k.Id == int.Parse(keyID));
|
||||
if (apiKey == null) return this.NotFound();
|
||||
this.Database.APIKeys.Remove(apiKey);
|
||||
await this.Database.SaveChangesAsync();
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ public class AdminPanelPage : BaseLayout
|
|||
{
|
||||
public List<ICommand> Commands = MaintenanceHelper.Commands;
|
||||
public AdminPanelPage(Database database) : base(database)
|
||||
{}
|
||||
{ }
|
||||
|
||||
public List<AdminPanelStatistic> Statistics = new();
|
||||
|
||||
|
@ -30,6 +30,8 @@ public class AdminPanelPage : BaseLayout
|
|||
this.Statistics.Add(new AdminPanelStatistic("Users", await StatisticsHelper.UserCount(), "/admin/users"));
|
||||
this.Statistics.Add(new AdminPanelStatistic("Slots", await StatisticsHelper.SlotCount()));
|
||||
this.Statistics.Add(new AdminPanelStatistic("Photos", await StatisticsHelper.PhotoCount()));
|
||||
this.Statistics.Add(new AdminPanelStatistic("Reports", await StatisticsHelper.ReportCount(), "/admin/reports/0"));
|
||||
this.Statistics.Add(new AdminPanelStatistic("API Keys", await StatisticsHelper.APIKeyCount(), "/admin/keys"));
|
||||
|
||||
if (!string.IsNullOrEmpty(command))
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<form action="/moderation/reports/0">
|
||||
<div class="ui icon input">
|
||||
<input type="text" name="name" placeholder="Search reports..." value="@Model.SearchValue">
|
||||
<input type="text" autocomplete="off" name="name" placeholder="Search reports..." value="@Model.SearchValue">
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
<div class="ui blue button">Create Fake Room</div>
|
||||
</a>
|
||||
|
||||
<a href="/debug/roomVisualizer/createRoomsWithDuplicatePlayers">
|
||||
<div class="ui blue button">Create Rooms With Duplicate Players</div>
|
||||
</a>
|
||||
|
||||
<a href="/debug/roomVisualizer/deleteRooms">
|
||||
<div class="ui red button">Nuke all rooms</div>
|
||||
</a>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
@using LBPUnion.ProjectLighthouse.Extensions
|
||||
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
|
||||
@using LBPUnion.ProjectLighthouse.Levels
|
||||
@using LBPUnion.ProjectLighthouse.Localization.StringLists
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LandingPage
|
||||
|
||||
@{
|
||||
|
@ -10,22 +11,22 @@
|
|||
Model.ShowTitleInPage = false;
|
||||
bool isMobile = this.Request.IsMobile();
|
||||
}
|
||||
<h1>Welcome to <b>@ServerConfiguration.Instance.Customization.ServerName</b>!</h1>
|
||||
<h1>@Model.Translate(LandingPageStrings.Welcome, ServerConfiguration.Instance.Customization.ServerName)</h1>
|
||||
|
||||
@if (Model.User != null)
|
||||
{
|
||||
<p>You are currently logged in as <b>@Model.User.Username</b>.</p>
|
||||
if (ServerConfiguration.Instance.Authentication.UseExternalAuth && Model.AuthenticationAttemptsCount > 0)
|
||||
<p>@Model.Translate(LandingPageStrings.LoggedInAs, Model.User.Username)</p>
|
||||
if (ServerConfiguration.Instance.Authentication.UseExternalAuth && Model.PendingAuthAttempts > 0)
|
||||
{
|
||||
<p>
|
||||
<b>You have @Model.AuthenticationAttemptsCount authentication attempts pending. Click <a href="/authentication">here</a> to view them.</b>
|
||||
<b><a href="/authentication">@Model.Translate(LandingPageStrings.AuthAttemptsPending, Model.PendingAuthAttempts)</a></b>
|
||||
</p>
|
||||
}
|
||||
}
|
||||
|
||||
@if (Model.PlayersOnlineCount == 1)
|
||||
{
|
||||
<p>There is 1 user currently online:</p>
|
||||
<p>@Model.Translate(LandingPageStrings.UsersSingle)</p>
|
||||
@foreach (User user in Model.PlayersOnline)
|
||||
{
|
||||
<a href="/user/@user.UserId" title="@user.Status.ToString()">@user.Username</a>
|
||||
|
@ -34,11 +35,11 @@
|
|||
|
||||
else if (Model.PlayersOnlineCount == 0)
|
||||
{
|
||||
<p>There are no users online. Why not hop on?</p>
|
||||
<p>@Model.Translate(LandingPageStrings.UsersNone)</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>There are currently @Model.PlayersOnlineCount users online:</p>
|
||||
<p>@Model.Translate(LandingPageStrings.UsersMultiple, Model.PlayersOnlineCount)</p>
|
||||
@foreach (User user in Model.PlayersOnline)
|
||||
{
|
||||
<a href="/user/@user.UserId" title="@user.Status.ToString()">@user.Username</a>
|
||||
|
@ -50,7 +51,7 @@ else
|
|||
<div class="@(isMobile ? "" : "ui center aligned grid")">
|
||||
<div class="eight wide column">
|
||||
<div class="ui pink segment">
|
||||
<h1><i class="ribbon icon"></i>Latest Team Picks</h1>
|
||||
<h1><i class="ribbon icon"></i>@Model.Translate(LandingPageStrings.LatestTeamPicks)</h1>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui left aligned segment">
|
||||
@foreach (Slot slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@
|
||||
|
@ -67,7 +68,7 @@ else
|
|||
}
|
||||
<div class="eight wide column">
|
||||
<div class="ui blue segment">
|
||||
<h1><i class="certificate icon"></i>Newest Levels</h1>
|
||||
<h1><i class="certificate icon"></i>@Model.Translate(LandingPageStrings.NewestLevels)</h1>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui left aligned segment">
|
||||
@foreach (Slot slot in Model.NewestLevels!) @* Can't reach a point where this is null *@
|
||||
|
|
|
@ -15,7 +15,7 @@ public class LandingPage : BaseLayout
|
|||
public LandingPage(Database database) : base(database)
|
||||
{}
|
||||
|
||||
public int AuthenticationAttemptsCount;
|
||||
public int PendingAuthAttempts;
|
||||
public List<User> PlayersOnline = new();
|
||||
|
||||
public int PlayersOnlineCount;
|
||||
|
@ -32,7 +32,7 @@ public class LandingPage : BaseLayout
|
|||
this.PlayersOnlineCount = await StatisticsHelper.RecentMatches();
|
||||
|
||||
if (user != null)
|
||||
this.AuthenticationAttemptsCount = await this.Database.AuthenticationAttempts.Include
|
||||
this.PendingAuthAttempts = await this.Database.AuthenticationAttempts.Include
|
||||
(a => a.GameToken)
|
||||
.CountAsync(a => a.GameToken.UserId == user.UserId);
|
||||
|
||||
|
|
|
@ -1,31 +1,32 @@
|
|||
@using LBPUnion.ProjectLighthouse.Configuration
|
||||
@using LBPUnion.ProjectLighthouse.Extensions
|
||||
@using LBPUnion.ProjectLighthouse.Helpers
|
||||
@using LBPUnion.ProjectLighthouse.Localization.StringLists
|
||||
@using LBPUnion.ProjectLighthouse.Types
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts.BaseLayout
|
||||
|
||||
@{
|
||||
if (Model!.User == null)
|
||||
{
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Login / Register", "/login", "sign in"));
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderLoginRegister, "/login", "sign in"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ServerConfiguration.Instance.Authentication.UseExternalAuth)
|
||||
{
|
||||
Model.NavigationItems.Add(new PageNavigationItem("Authentication", "/authentication", "key"));
|
||||
Model.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderAuthentication, "/authentication", "key"));
|
||||
}
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Profile", "/user/" + Model.User.UserId, "user alternate"));
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderProfile, "/user/" + Model.User.UserId, "user alternate"));
|
||||
|
||||
@if (Model.User.IsAdmin)
|
||||
{
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Admin Panel", "/admin", "cogs"));
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderAdminPanel, "/admin", "cogs"));
|
||||
}
|
||||
else if(Model.User.IsModerator)
|
||||
else if (Model.User.IsModerator)
|
||||
{
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Mod Panel", "/moderation", "user shield"));
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderModPanel, "/moderation", "user shield"));
|
||||
}
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Log out", "/logout", "user alternate slash")); // should always be last
|
||||
Model.NavigationItemsRight.Add(new PageNavigationItem(BaseLayoutStrings.HeaderLogout, "/logout", "user alternate slash")); // should always be last
|
||||
}
|
||||
|
||||
Model.IsMobile = Model.Request.IsMobile();
|
||||
|
@ -99,7 +100,7 @@
|
|||
|
||||
@if (!Model.IsMobile)
|
||||
{
|
||||
@navigationItem.Name
|
||||
@Model.Translate(navigationItem.Name)
|
||||
}
|
||||
</a>
|
||||
}
|
||||
|
@ -114,7 +115,7 @@
|
|||
|
||||
@if (!Model.IsMobile)
|
||||
{
|
||||
@navigationItem.Name
|
||||
@Model.Translate(navigationItem.Name)
|
||||
}
|
||||
</a>
|
||||
}
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Localization;
|
||||
using LBPUnion.ProjectLighthouse.Localization.StringLists;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||
|
||||
public class BaseLayout : PageModel
|
||||
{
|
||||
|
||||
public readonly Database Database;
|
||||
|
||||
public readonly List<PageNavigationItem> NavigationItems = new()
|
||||
{
|
||||
new PageNavigationItem("Home", "/", "home"),
|
||||
new PageNavigationItem("Users", "/users/0", "user friends"),
|
||||
new PageNavigationItem("Photos", "/photos/0", "camera"),
|
||||
new PageNavigationItem("Levels", "/slots/0", "certificate"),
|
||||
};
|
||||
public readonly List<PageNavigationItem> NavigationItems = new();
|
||||
|
||||
public readonly List<PageNavigationItem> NavigationItemsRight = new();
|
||||
public string Description = string.Empty;
|
||||
|
@ -31,6 +30,11 @@ public class BaseLayout : PageModel
|
|||
public BaseLayout(Database database)
|
||||
{
|
||||
this.Database = database;
|
||||
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderHome, "/", "home"));
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderUsers, "/users/0", "user friends"));
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderPhotos, "/photos/0", "camera"));
|
||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "certificate"));
|
||||
}
|
||||
|
||||
public new User? User {
|
||||
|
@ -41,4 +45,17 @@ public class BaseLayout : PageModel
|
|||
}
|
||||
set => this.user = value;
|
||||
}
|
||||
|
||||
private string getLanguage()
|
||||
{
|
||||
if (ServerStatics.IsUnitTesting) return "en-US";
|
||||
|
||||
IRequestCultureFeature? requestCulture = Request.HttpContext.Features.Get<IRequestCultureFeature>();
|
||||
|
||||
if (requestCulture == null) return LocalizationManager.DefaultLang;
|
||||
return requestCulture.RequestCulture.UICulture.Name;
|
||||
}
|
||||
|
||||
public string Translate(TranslatableString translatableString) => translatableString.Translate(this.getLanguage());
|
||||
public string Translate(TranslatableString translatableString, params object?[] format) => translatableString.Translate(this.getLanguage(), format);
|
||||
}
|
|
@ -1,21 +1,27 @@
|
|||
@page "/login"
|
||||
@using LBPUnion.ProjectLighthouse.Configuration
|
||||
@using LBPUnion.ProjectLighthouse.Localization.StringLists
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LoginForm
|
||||
|
||||
@{
|
||||
Layout = "Layouts/BaseLayout";
|
||||
Model.Title = "Log in";
|
||||
Model.Title = Model.Translate(GeneralStrings.LogIn);
|
||||
}
|
||||
|
||||
<script src="https://geraintluff.github.io/sha256/sha256.min.js"></script>
|
||||
|
||||
<script>
|
||||
function onSubmit(form) {
|
||||
if (document.referrer !== null && document.referrer !== "") {
|
||||
const url = new URL(document.referrer);
|
||||
if (url.pathname !== "/logout" && url.pathname !== "/login")
|
||||
document.getElementById("redirect").value = url.pathname;
|
||||
}
|
||||
|
||||
const passwordInput = document.getElementById("password");
|
||||
const passwordSubmit = document.getElementById("password-submit");
|
||||
|
||||
passwordSubmit.value = sha256(passwordInput.value);
|
||||
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
|
@ -24,7 +30,7 @@
|
|||
{
|
||||
<div class="ui negative message">
|
||||
<div class="header">
|
||||
Uh oh!
|
||||
@Model.Translate(GeneralStrings.Error)
|
||||
</div>
|
||||
<p style="white-space: pre-line">@Model.Error</p>
|
||||
</div>
|
||||
|
@ -32,19 +38,20 @@
|
|||
|
||||
<form class="ui form" onsubmit="return onSubmit(this)" method="post">
|
||||
@Html.AntiForgeryToken()
|
||||
<input type="hidden" id="redirect" name="redirect">
|
||||
|
||||
<div class="field">
|
||||
<label>Username</label>
|
||||
<label>@Model.Translate(GeneralStrings.Username)</label>
|
||||
<div class="ui left icon input">
|
||||
<input type="text" name="username" id="text" placeholder="Username">
|
||||
<input type="text" name="username" id="text" placeholder="@Model.Translate(GeneralStrings.Username)">
|
||||
<i class="user icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>Password</label>
|
||||
<label>@Model.Translate(GeneralStrings.Password)</label>
|
||||
<div class="ui left icon input">
|
||||
<input type="password" id="password" placeholder="Password">
|
||||
<input type="password" id="password" placeholder="@Model.Translate(GeneralStrings.Password)">
|
||||
<input type="hidden" id="password-submit" name="password">
|
||||
<i class="lock icon"></i>
|
||||
</div>
|
||||
|
@ -54,15 +61,23 @@
|
|||
{
|
||||
@await Html.PartialAsync("Partials/CaptchaPartial")
|
||||
}
|
||||
|
||||
<input type="submit" value="Log in" id="submit" class="ui blue button">
|
||||
@if (ServerConfiguration.Instance.Authentication.RegistrationEnabled)
|
||||
{
|
||||
<a href="/register">
|
||||
|
||||
<div class="row">
|
||||
<input type="submit" value="@Model.Translate(GeneralStrings.LogIn)" id="submit" class="ui blue button">
|
||||
@if (ServerConfiguration.Instance.Authentication.RegistrationEnabled)
|
||||
{
|
||||
<a href="/register">
|
||||
<div class="ui button">
|
||||
<i class="user alternate add icon"></i>
|
||||
@Model.Translate(GeneralStrings.Register)
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<br/>
|
||||
<a href="/passwordResetRequest">
|
||||
<div class="ui button">
|
||||
<i class="user alternate add icon"></i>
|
||||
Register
|
||||
@Model.Translate(GeneralStrings.ForgotPassword)
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
</form>
|
|
@ -22,7 +22,7 @@ public class LoginForm : BaseLayout
|
|||
public string? Error { get; private set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
public async Task<IActionResult> OnPost(string username, string password)
|
||||
public async Task<IActionResult> OnPost(string username, string password, string redirect)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
|
@ -105,9 +105,19 @@ public class LoginForm : BaseLayout
|
|||
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
||||
if (ServerConfiguration.Instance.Mail.MailEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
||||
|
||||
return this.RedirectToPage(nameof(LandingPage));
|
||||
if (string.IsNullOrWhiteSpace(redirect))
|
||||
{
|
||||
return this.RedirectToPage(nameof(LandingPage));
|
||||
}
|
||||
return this.Redirect(redirect);
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public IActionResult OnGet() => this.Page();
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
if (this.Database.UserFromWebRequest(this.Request) != null)
|
||||
return this.RedirectToPage(nameof(LandingPage));
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,16 @@
|
|||
@page "/logout"
|
||||
@using LBPUnion.ProjectLighthouse.Localization.StringLists
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LogoutPage
|
||||
|
||||
@{
|
||||
Layout = "Layouts/BaseLayout";
|
||||
Model.Title = "Logged out";
|
||||
Model.Title = Model.Translate(LoggedOutStrings.LoggedOut);
|
||||
}
|
||||
|
||||
<p>You have been successfully logged out. You will be redirected in 5 seconds, or you may click <a href="/">here</a> to do so manually.</p>
|
||||
<p>@Model.Translate(LoggedOutStrings.LoggedOutInfo)</p>
|
||||
|
||||
<a href="/" class="ui blue button">
|
||||
@Model.Translate(LoggedOutStrings.Redirect)
|
||||
</a>
|
||||
|
||||
<meta http-equiv="refresh" content="5; url=/"/>
|
|
@ -1,6 +1,17 @@
|
|||
@using LBPUnion.ProjectLighthouse.Configuration
|
||||
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
|
||||
{
|
||||
<div class="h-captcha" data-sitekey="@ServerConfiguration.Instance.Captcha.SiteKey"></div>
|
||||
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||
@switch (ServerConfiguration.Instance.Captcha.Type)
|
||||
{
|
||||
case CaptchaType.HCaptcha:
|
||||
<div class="h-captcha" data-sitekey="@ServerConfiguration.Instance.Captcha.SiteKey"></div>
|
||||
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||
break;
|
||||
case CaptchaType.ReCaptcha:
|
||||
<div class="g-recaptcha" data-sitekey="@ServerConfiguration.Instance.Captcha.SiteKey"></div>
|
||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
@using System.Web
|
||||
@using System.IO
|
||||
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
|
||||
<div class="ui yellow segment" id="comments">
|
||||
<h2>Comments</h2>
|
||||
|
@ -47,7 +48,14 @@
|
|||
int rating = comment.ThumbsUp - comment.ThumbsDown;
|
||||
|
||||
<div style="display: flex" id="@comment.CommentId">
|
||||
<div class="voting">
|
||||
@{
|
||||
string style = "";
|
||||
if (Model.User?.UserId == comment.PosterUserId)
|
||||
{
|
||||
style = "visibility: hidden";
|
||||
}
|
||||
}
|
||||
<div class="voting" style="@(style)">
|
||||
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == 1 ? 0 : 1)">
|
||||
<i class="fitted @(comment.YourThumb == 1 ? "green" : "grey") arrow up link icon" style="display: block"></i>
|
||||
</a>
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
}
|
||||
<div>
|
||||
<img src="~/assets/slotCardOverlay.png" style="min-width: @(size)px; width: @(size)px; height: @(size)px; pointer-events: none; position: absolute">
|
||||
<img class="cardIcon slotCardIcon" src="/gameAssets/@iconHash" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
||||
<img src="~/assets/slotCardBackground.png" style="min-width: @(size)px; width: @(size)px; height: @(size)px; position: absolute; z-index: -1;">
|
||||
<img class="cardIcon slotCardIcon" src="/gameAssets/@iconHash" style="min-width: @(size)px; width: @(size)px; height: @(size)px;"
|
||||
onerror="this.onerror='';this.src='/gameAssets/@ServerConfiguration.Instance.WebsiteConfiguration.MissingIconHash'">
|
||||
</div>
|
||||
<div class="cardStats">
|
||||
@if (!mini)
|
||||
|
@ -80,7 +82,7 @@
|
|||
@if (Model.GameVersion == GameVersion.LittleBigPlanet1)
|
||||
{
|
||||
<i class="yellow star icon" title="LBP1 Stars"></i>
|
||||
<span>@Model.RatingLBP1</span>
|
||||
<span>@(Math.Round(Model.RatingLBP1 * 10) / 10)</span>
|
||||
}
|
||||
</div>
|
||||
<p>
|
||||
|
|
|
@ -4,7 +4,6 @@ using LBPUnion.ProjectLighthouse.Configuration;
|
|||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
|
||||
|
@ -19,8 +18,21 @@ public class PasswordResetPage : BaseLayout
|
|||
[UsedImplicitly]
|
||||
public async Task<IActionResult> OnPost(string password, string confirmPassword)
|
||||
{
|
||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
User? user;
|
||||
if (Request.Query.ContainsKey("token"))
|
||||
{
|
||||
user = await this.Database.UserFromPasswordResetToken(Request.Query["token"][0]);
|
||||
if (user == null)
|
||||
{
|
||||
this.Error = "This password reset link either is invalid or has expired. Please try again.";
|
||||
return this.Page();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
|
@ -48,6 +60,8 @@ public class PasswordResetPage : BaseLayout
|
|||
[UsedImplicitly]
|
||||
public IActionResult OnGet()
|
||||
{
|
||||
if (this.Request.Query.ContainsKey("token")) return this.Page();
|
||||
|
||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
@page "/passwordResetRequest"
|
||||
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.PasswordResetRequestForm
|
||||
|
||||
@{
|
||||
Layout = "Layouts/BaseLayout";
|
||||
Model.Title = "Password Reset";
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(Model.Error))
|
||||
{
|
||||
<div class="ui negative message">
|
||||
<div class="header">
|
||||
Uh oh!
|
||||
</div>
|
||||
<p style="white-space: pre-line">@Model.Error</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(Model.Status))
|
||||
{
|
||||
<div class="ui positive message">
|
||||
<div class="header">
|
||||
Success!
|
||||
</div>
|
||||
<p style="white-space: pre-line">@Model.Status</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<form class="ui form" method="post">
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
<input type="text" autocomplete="no" id="username" placeholder="Username" name="username"/><br/><br/>
|
||||
<input type="submit" value="Request Password Reset" class="ui blue button"/>
|
||||
</form>
|
|
@ -0,0 +1,67 @@
|
|||
using JetBrains.Annotations;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
|
||||
|
||||
public class PasswordResetRequestForm : BaseLayout
|
||||
{
|
||||
|
||||
public string? Error { get; private set; }
|
||||
|
||||
public string? Status { get; private set; }
|
||||
|
||||
public PasswordResetRequestForm(Database database) : base(database)
|
||||
{ }
|
||||
|
||||
[UsedImplicitly]
|
||||
public async Task<IActionResult> OnPost(string username)
|
||||
{
|
||||
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
this.Error = "Email is not configured on this server, so password resets cannot be issued. Please contact your instance administrator for more details.";
|
||||
return this.Page();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
this.Error = "The username field is required.";
|
||||
return this.Page();
|
||||
}
|
||||
|
||||
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
this.Error = "User does not exist.";
|
||||
return this.Page();
|
||||
}
|
||||
|
||||
PasswordResetToken token = new()
|
||||
{
|
||||
Created = DateTime.Now,
|
||||
UserId = user.UserId,
|
||||
ResetToken = CryptoHelper.GenerateAuthToken(),
|
||||
};
|
||||
|
||||
string messageBody = $"Hello, {user.Username}.\n\n" +
|
||||
"A request to reset your account's password was issued. If this wasn't you, this can probably be ignored.\n\n" +
|
||||
$"If this was you, your {ServerConfiguration.Instance.Customization.ServerName} password can be reset at the following link:\n" +
|
||||
$"{ServerConfiguration.Instance.ExternalUrl}/passwordReset?token={token.ResetToken}";
|
||||
|
||||
SMTPHelper.SendEmail(user.EmailAddress, $"Project Lighthouse Password Reset Request for {user.Username}", messageBody);
|
||||
|
||||
this.Database.PasswordResetTokens.Add(token);
|
||||
await this.Database.SaveChangesAsync();
|
||||
|
||||
this.Status = $"Password reset email sent to {CensorHelper.MaskEmail(user.EmailAddress)}.";
|
||||
return this.Page();
|
||||
}
|
||||
public void OnGet() => this.Page();
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<form action="/photos/0">
|
||||
<div class="ui icon input">
|
||||
<input type="text" name="name" placeholder="Search photos..." value="@Model.SearchValue">
|
||||
<input type="text" autocomplete="off" name="name" placeholder="Search photos..." value="@Model.SearchValue">
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
|
|||
public class RegisterForm : BaseLayout
|
||||
{
|
||||
public RegisterForm(Database database) : base(database)
|
||||
{}
|
||||
{ }
|
||||
|
||||
public string? Error { get; private set; }
|
||||
|
||||
|
@ -23,7 +23,22 @@ public class RegisterForm : BaseLayout
|
|||
[SuppressMessage("ReSharper", "SpecifyStringComparison")]
|
||||
public async Task<IActionResult> OnPost(string username, string password, string confirmPassword, string emailAddress)
|
||||
{
|
||||
if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) return this.NotFound();
|
||||
if (ServerConfiguration.Instance.Authentication.PrivateRegistration)
|
||||
{
|
||||
if (this.Request.Query.ContainsKey("token"))
|
||||
{
|
||||
if (!this.Database.IsRegistrationTokenValid(this.Request.Query["token"]))
|
||||
return this.StatusCode(403, "Invalid Token");
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.NotFound();
|
||||
}
|
||||
}
|
||||
else if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled)
|
||||
{
|
||||
return this.NotFound();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
|
@ -68,6 +83,11 @@ public class RegisterForm : BaseLayout
|
|||
return this.Page();
|
||||
}
|
||||
|
||||
if (this.Request.Query.ContainsKey("token"))
|
||||
{
|
||||
await Database.RemoveRegistrationToken(this.Request.Query["token"]);
|
||||
}
|
||||
|
||||
User user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress);
|
||||
|
||||
WebToken webToken = new()
|
||||
|
@ -91,7 +111,22 @@ public class RegisterForm : BaseLayout
|
|||
public IActionResult OnGet()
|
||||
{
|
||||
this.Error = string.Empty;
|
||||
if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled) return this.NotFound();
|
||||
if (ServerConfiguration.Instance.Authentication.PrivateRegistration)
|
||||
{
|
||||
if (this.Request.Query.ContainsKey("token"))
|
||||
{
|
||||
if (!this.Database.IsRegistrationTokenValid(this.Request.Query["token"]))
|
||||
return this.StatusCode(403, "Invalid Token");
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.NotFound();
|
||||
}
|
||||
}
|
||||
else if (!ServerConfiguration.Instance.Authentication.RegistrationEnabled)
|
||||
{
|
||||
return this.NotFound();
|
||||
}
|
||||
|
||||
return this.Page();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<form action="/slots/0">
|
||||
<div class="ui icon input">
|
||||
<input type="text" name="name" placeholder="Search levels..." value="@Model.SearchValue">
|
||||
<input type="text" autocomplete="off" name="name" placeholder="Search levels..." value="@Model.SearchValue">
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<form action="/users/0">
|
||||
<div class="ui icon input">
|
||||
<input type="text" name="name" placeholder="Search users..." value="@Model.SearchValue">
|
||||
<input type="text" autocomplete="off" name="name" placeholder="Search users..." value="@Model.SearchValue">
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ProjectLighthouse.Localization\ProjectLighthouse.Localization.csproj" />
|
||||
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -32,7 +33,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
using System.Globalization;
|
||||
using LBPUnion.ProjectLighthouse.Localization;
|
||||
using LBPUnion.ProjectLighthouse.Middlewares;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
|
||||
#if !DEBUG
|
||||
using Microsoft.Extensions.Hosting.Internal;
|
||||
|
@ -38,6 +41,16 @@ public class WebsiteStartup
|
|||
}
|
||||
);
|
||||
|
||||
services.Configure<RequestLocalizationOptions>(config =>
|
||||
{
|
||||
List<CultureInfo> languages = LocalizationManager.GetAvailableLanguages().Select(l => new CultureInfo(LocalizationManager.MapLanguage(l))).ToList();
|
||||
|
||||
config.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"));
|
||||
|
||||
config.SupportedCultures = languages;
|
||||
config.SupportedUICultures = languages;
|
||||
});
|
||||
|
||||
#if DEBUG
|
||||
services.AddSingleton<IHostLifetime, DebugWarmupLifetime>();
|
||||
#else
|
||||
|
@ -63,6 +76,8 @@ public class WebsiteStartup
|
|||
ServeUnknownFileTypes = true,
|
||||
});
|
||||
|
||||
app.UseRequestLocalization();
|
||||
|
||||
app.UseEndpoints(endpoints => endpoints.MapControllers());
|
||||
app.UseEndpoints(endpoints => endpoints.MapRazorPages());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue