1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2025-09-14 12:32:11 +02:00

2 Commits

Author SHA1 Message Date
35ca896849 Add "servermods" folder to ignored folders in backups 2024-07-14 10:40:49 +02:00
30b3ba60cd WIP 2024-07-14 10:40:49 +02:00
254 changed files with 1711 additions and 1679 deletions

View File

@@ -1,4 +1,5 @@
using System.Text; using System.Collections.ObjectModel;
using System.Text;
using Phantom.Agent.Minecraft.Instance; using Phantom.Agent.Minecraft.Instance;
using Phantom.Agent.Minecraft.Java; using Phantom.Agent.Minecraft.Java;
using Phantom.Agent.Minecraft.Server; using Phantom.Agent.Minecraft.Server;
@@ -11,6 +12,7 @@ public abstract class BaseLauncher : IServerLauncher {
private readonly InstanceProperties instanceProperties; private readonly InstanceProperties instanceProperties;
protected string MinecraftVersion => instanceProperties.ServerVersion; protected string MinecraftVersion => instanceProperties.ServerVersion;
protected string InstanceFolder => instanceProperties.InstanceFolder;
private protected BaseLauncher(InstanceProperties instanceProperties) { private protected BaseLauncher(InstanceProperties instanceProperties) {
this.instanceProperties = instanceProperties; this.instanceProperties = instanceProperties;
@@ -51,16 +53,14 @@ public abstract class BaseLauncher : IServerLauncher {
var processConfigurator = new ProcessConfigurator { var processConfigurator = new ProcessConfigurator {
FileName = javaRuntimeExecutable.ExecutablePath, FileName = javaRuntimeExecutable.ExecutablePath,
WorkingDirectory = instanceProperties.InstanceFolder, WorkingDirectory = InstanceFolder,
RedirectInput = true, RedirectInput = true,
UseShellExecute = false UseShellExecute = false
}; };
var processArguments = processConfigurator.ArgumentList; var processArguments = processConfigurator.ArgumentList;
PrepareJvmArguments(serverJar).Build(processArguments); PrepareJvmArguments(serverJar).Build(processArguments);
processArguments.Add("-jar"); PrepareJavaProcessArguments(processArguments, serverJar.FilePath);
processArguments.Add(serverJar.FilePath);
processArguments.Add("nogui");
var process = processConfigurator.CreateProcess(); var process = processConfigurator.CreateProcess();
var instanceProcess = new InstanceProcess(instanceProperties, process); var instanceProcess = new InstanceProcess(instanceProperties, process);
@@ -99,13 +99,19 @@ public abstract class BaseLauncher : IServerLauncher {
private protected virtual void CustomizeJvmArguments(JvmArgumentBuilder arguments) {} private protected virtual void CustomizeJvmArguments(JvmArgumentBuilder arguments) {}
protected virtual void PrepareJavaProcessArguments(Collection<string> processArguments, string serverJarFilePath) {
processArguments.Add("-jar");
processArguments.Add(serverJarFilePath);
processArguments.Add("nogui");
}
private protected virtual Task<ServerJarInfo> PrepareServerJar(ILogger logger, string serverJarPath, CancellationToken cancellationToken) { private protected virtual Task<ServerJarInfo> PrepareServerJar(ILogger logger, string serverJarPath, CancellationToken cancellationToken) {
return Task.FromResult(new ServerJarInfo(serverJarPath)); return Task.FromResult(new ServerJarInfo(serverJarPath));
} }
private static async Task AcceptEula(InstanceProperties instanceProperties) { private static async Task AcceptEula(InstanceProperties instanceProperties) {
var eulaFilePath = Path.Combine(instanceProperties.InstanceFolder, "eula.txt"); var eulaFilePath = Path.Combine(instanceProperties.InstanceFolder, "eula.txt");
await File.WriteAllLinesAsync(eulaFilePath, new[] { "# EULA", "eula=true" }, Encoding.UTF8); await File.WriteAllLinesAsync(eulaFilePath, new [] { "# EULA", "eula=true" }, Encoding.UTF8);
} }
private static async Task UpdateServerProperties(InstanceProperties instanceProperties) { private static async Task UpdateServerProperties(InstanceProperties instanceProperties) {

View File

@@ -0,0 +1,29 @@
using System.Collections.ObjectModel;
using Phantom.Agent.Minecraft.Instance;
using Phantom.Agent.Minecraft.Java;
using Serilog;
namespace Phantom.Agent.Minecraft.Launcher.Types;
public sealed class ForgeLauncher : BaseLauncher {
public ForgeLauncher(InstanceProperties instanceProperties) : base(instanceProperties) {}
private protected override void CustomizeJvmArguments(JvmArgumentBuilder arguments) {
arguments.AddProperty("terminal.ansi", "true"); // TODO
}
protected override void PrepareJavaProcessArguments(Collection<string> processArguments, string serverJarFilePath) {
if (OperatingSystem.IsWindows()) {
processArguments.Add("@libraries/net/minecraftforge/forge/1.20.1-47.2.0/win_args.txt");
}
else {
processArguments.Add("@libraries/net/minecraftforge/forge/1.20.1-47.2.0/unix_args.txt");
}
processArguments.Add("nogui");
}
private protected override Task<ServerJarInfo> PrepareServerJar(ILogger logger, string serverJarPath, CancellationToken cancellationToken) {
return Task.FromResult(new ServerJarInfo(Path.Combine(InstanceFolder, "run.sh")));
}
}

View File

@@ -25,7 +25,7 @@ sealed class BackupArchiver {
} }
private bool IsFolderSkipped(ImmutableList<string> relativePath) { private bool IsFolderSkipped(ImmutableList<string> relativePath) {
return relativePath is ["cache" or "crash-reports" or "debug" or "libraries" or "logs" or "mods" or "versions"]; return relativePath is ["cache" or "crash-reports" or "debug" or "libraries" or "logs" or "mods" or "servermods" or "versions"];
} }
[SuppressMessage("ReSharper", "ConvertIfStatementToReturnStatement")] [SuppressMessage("ReSharper", "ConvertIfStatementToReturnStatement")]

View File

@@ -102,6 +102,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
IServerLauncher launcher = configuration.MinecraftServerKind switch { IServerLauncher launcher = configuration.MinecraftServerKind switch {
MinecraftServerKind.Vanilla => new VanillaLauncher(properties), MinecraftServerKind.Vanilla => new VanillaLauncher(properties),
MinecraftServerKind.Fabric => new FabricLauncher(properties), MinecraftServerKind.Fabric => new FabricLauncher(properties),
MinecraftServerKind.Forge => new ForgeLauncher(properties),
_ => InvalidLauncher.Instance _ => InvalidLauncher.Instance
}; };

View File

@@ -5,6 +5,7 @@ using Phantom.Common.Data.Instance;
using Phantom.Common.Data.Replies; using Phantom.Common.Data.Replies;
using Phantom.Common.Messages.Agent.ToController; using Phantom.Common.Messages.Agent.ToController;
using Phantom.Utils.Logging; using Phantom.Utils.Logging;
using Phantom.Utils.Tasks;
using Serilog; using Serilog;
namespace Phantom.Agent.Services.Instances; namespace Phantom.Agent.Services.Instances;

View File

@@ -2,5 +2,6 @@
public enum MinecraftServerKind : ushort { public enum MinecraftServerKind : ushort {
Vanilla = 1, Vanilla = 1,
Fabric = 2 Fabric = 2,
Forge = 3
} }

View File

@@ -1,7 +1,6 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using Phantom.Common.Data; using Phantom.Common.Data;
using Phantom.Common.Data.Web.Users; using Phantom.Common.Data.Web.Users;
using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults;
using Phantom.Controller.Database; using Phantom.Controller.Database;
using Phantom.Controller.Database.Entities; using Phantom.Controller.Database.Entities;
using Phantom.Controller.Database.Repositories; using Phantom.Controller.Database.Repositories;
@@ -57,12 +56,12 @@ sealed class UserManager {
wasCreated = true; wasCreated = true;
} }
else { else {
return new CreationFailed(result.Error); return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.CreationFailed(result.Error);
} }
} }
else { else {
if (userRepository.SetUserPassword(user, password).TryGetError(out var error)) { if (userRepository.SetUserPassword(user, password).TryGetError(out var error)) {
return new UpdatingFailed(error); return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(error);
} }
auditLogWriter.AdministratorUserModified(user); auditLogWriter.AdministratorUserModified(user);
@@ -71,7 +70,7 @@ sealed class UserManager {
var role = await new RoleRepository(db).GetByGuid(Role.Administrator.Guid); var role = await new RoleRepository(db).GetByGuid(Role.Administrator.Guid);
if (role == null) { if (role == null) {
return new AddingToRoleFailed(); return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.AddingToRoleFailed();
} }
await new UserRoleRepository(db).Add(user, role); await new UserRoleRepository(db).Add(user, role);
@@ -85,10 +84,10 @@ sealed class UserManager {
Logger.Information("Updated administrator user \"{Username}\" (GUID {Guid}).", username, user.UserGuid); Logger.Information("Updated administrator user \"{Username}\" (GUID {Guid}).", username, user.UserGuid);
} }
return new Success(user.ToUserInfo()); return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.Success(user.ToUserInfo());
} catch (Exception e) { } catch (Exception e) {
Logger.Error(e, "Could not create or update administrator user \"{Username}\".", username); Logger.Error(e, "Could not create or update administrator user \"{Username}\".", username);
return new UnknownError(); return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UnknownError();
} }
} }

View File

@@ -1,8 +1,8 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<LangVersion>13</LangVersion> <LangVersion>11</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View File

@@ -1,7 +1,7 @@
# +---------------+ # +---------------+
# | Prepare build | # | Prepare build |
# +---------------+ # +---------------+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/nightly/sdk:9.0 AS phantom-builder FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/nightly/sdk:8.0 AS phantom-builder
ARG TARGETARCH ARG TARGETARCH
ADD . /app ADD . /app
@@ -19,7 +19,7 @@ RUN find .artifacts/publish/*/* -maxdepth 0 -execdir mv '{}' 'release' \;
# +---------------------+ # +---------------------+
# | Phantom Agent image | # | Phantom Agent image |
# +---------------------+ # +---------------------+
FROM mcr.microsoft.com/dotnet/nightly/runtime:9.0 AS phantom-agent FROM mcr.microsoft.com/dotnet/nightly/runtime:8.0 AS phantom-agent
RUN mkdir /data && chmod 777 /data RUN mkdir /data && chmod 777 /data
WORKDIR /data WORKDIR /data
@@ -46,7 +46,7 @@ ENTRYPOINT ["dotnet", "/app/Phantom.Agent.dll"]
# +--------------------------+ # +--------------------------+
# | Phantom Controller image | # | Phantom Controller image |
# +--------------------------+ # +--------------------------+
FROM mcr.microsoft.com/dotnet/nightly/runtime:9.0 AS phantom-controller FROM mcr.microsoft.com/dotnet/nightly/runtime:8.0 AS phantom-controller
RUN mkdir /data && chmod 777 /data RUN mkdir /data && chmod 777 /data
WORKDIR /data WORKDIR /data
@@ -59,7 +59,7 @@ ENTRYPOINT ["dotnet", "/app/Phantom.Controller.dll"]
# +-------------------+ # +-------------------+
# | Phantom Web image | # | Phantom Web image |
# +-------------------+ # +-------------------+
FROM mcr.microsoft.com/dotnet/nightly/aspnet:9.0 AS phantom-web FROM mcr.microsoft.com/dotnet/nightly/aspnet:8.0 AS phantom-web
RUN mkdir /data && chmod 777 /data RUN mkdir /data && chmod 777 /data
WORKDIR /data WORKDIR /data

View File

@@ -59,25 +59,25 @@ public sealed class RingBufferTests {
[Test] [Test]
public void AddOneItemAndEnumerateOne() { public void AddOneItemAndEnumerateOne() {
var buffer = PrepareRingBuffer(10, "a"); var buffer = PrepareRingBuffer(10, "a");
Assert.That(buffer.EnumerateLast(1), Is.EquivalentTo(new[] { "a" })); Assert.That(buffer.EnumerateLast(1), Is.EquivalentTo(new [] { "a" }));
} }
[Test] [Test]
public void AddOneItemAndEnumerateMaxValue() { public void AddOneItemAndEnumerateMaxValue() {
var buffer = PrepareRingBuffer(10, "a"); var buffer = PrepareRingBuffer(10, "a");
Assert.That(buffer.EnumerateLast(uint.MaxValue), Is.EquivalentTo(new[] { "a" })); Assert.That(buffer.EnumerateLast(uint.MaxValue), Is.EquivalentTo(new [] { "a" }));
} }
[Test] [Test]
public void AddMultipleItemsWithinCapacityAndEnumerateFewer() { public void AddMultipleItemsWithinCapacityAndEnumerateFewer() {
var buffer = PrepareRingBuffer(10, "a", "b", "c"); var buffer = PrepareRingBuffer(10, "a", "b", "c");
Assert.That(buffer.EnumerateLast(2), Is.EquivalentTo(new[] { "b", "c" })); Assert.That(buffer.EnumerateLast(2), Is.EquivalentTo(new [] { "b", "c" }));
} }
[Test] [Test]
public void AddMultipleItemsWithinCapacityAndEnumerateMaxValue() { public void AddMultipleItemsWithinCapacityAndEnumerateMaxValue() {
var buffer = PrepareRingBuffer(10, "a", "b", "c"); var buffer = PrepareRingBuffer(10, "a", "b", "c");
Assert.That(buffer.EnumerateLast(uint.MaxValue), Is.EquivalentTo(new[] { "a", "b", "c" })); Assert.That(buffer.EnumerateLast(uint.MaxValue), Is.EquivalentTo(new [] { "a", "b", "c" }));
} }
[TestCase(3)] [TestCase(3)]
@@ -85,12 +85,12 @@ public sealed class RingBufferTests {
[TestCase(5)] [TestCase(5)]
public void AddMultipleItemsOverflowingCapacityAndEnumerateFewer(int capacity) { public void AddMultipleItemsOverflowingCapacityAndEnumerateFewer(int capacity) {
var buffer = PrepareRingBuffer(capacity, "a", "b", "c", "d", "e", "f"); var buffer = PrepareRingBuffer(capacity, "a", "b", "c", "d", "e", "f");
Assert.That(buffer.EnumerateLast(2), Is.EquivalentTo(new[] { "e", "f" })); Assert.That(buffer.EnumerateLast(2), Is.EquivalentTo(new [] { "e", "f" }));
} }
[TestCase(3, ExpectedResult = new[] { "d", "e", "f" })] [TestCase(3, ExpectedResult = new [] { "d", "e", "f" })]
[TestCase(4, ExpectedResult = new[] { "c", "d", "e", "f" })] [TestCase(4, ExpectedResult = new [] { "c", "d", "e", "f" })]
[TestCase(5, ExpectedResult = new[] { "b", "c", "d", "e", "f" })] [TestCase(5, ExpectedResult = new [] { "b", "c", "d", "e", "f" })]
public string[] AddMultipleItemsOverflowingCapacityAndEnumerateMaxValue(int capacity) { public string[] AddMultipleItemsOverflowingCapacityAndEnumerateMaxValue(int capacity) {
var buffer = PrepareRingBuffer(capacity, "a", "b", "c", "d", "e", "f"); var buffer = PrepareRingBuffer(capacity, "a", "b", "c", "d", "e", "f");
return buffer.EnumerateLast(uint.MaxValue).ToArray(); return buffer.EnumerateLast(uint.MaxValue).ToArray();

View File

@@ -9,12 +9,12 @@ public abstract class FormCustomValidationAttribute<TModel, TValue> : Validation
protected sealed override ValidationResult? IsValid(object? value, ValidationContext validationContext) { protected sealed override ValidationResult? IsValid(object? value, ValidationContext validationContext) {
if (value is not TValue typedValue) { if (value is not TValue typedValue) {
return new ValidationResult(null, new[] { FieldName }); return new ValidationResult(null, new [] { FieldName });
} }
var model = (TModel) validationContext.ObjectInstance; var model = (TModel) validationContext.ObjectInstance;
var result = Validate(model, typedValue); var result = Validate(model, typedValue);
return result == ValidationResult.Success ? result : new ValidationResult(result?.ErrorMessage, new[] { FieldName }); return result == ValidationResult.Success ? result : new ValidationResult(result?.ErrorMessage, new [] { FieldName });
} }
protected abstract string FieldName { get; } protected abstract string FieldName { get; }

View File

@@ -9,7 +9,7 @@ public abstract class FormValidationAttribute<TModel, TValue> : ValidationAttrib
protected sealed override ValidationResult? IsValid(object? value, ValidationContext validationContext) { protected sealed override ValidationResult? IsValid(object? value, ValidationContext validationContext) {
var model = (TModel) validationContext.ObjectInstance; var model = (TModel) validationContext.ObjectInstance;
return value is TValue typedValue && IsValid(model, typedValue) ? ValidationResult.Success : new ValidationResult(null, new[] { FieldName }); return value is TValue typedValue && IsValid(model, typedValue) ? ValidationResult.Success : new ValidationResult(null, new [] { FieldName });
} }
protected abstract string FieldName { get; } protected abstract string FieldName { get; }

View File

@@ -1,6 +1,6 @@
@using Phantom.Common.Data.Web.Users @using Phantom.Web.Services.Authentication
@using Phantom.Web.Services @using Phantom.Web.Services
@using Phantom.Web.Services.Authentication @using Phantom.Common.Data.Web.Users
@inject ApplicationProperties ApplicationProperties @inject ApplicationProperties ApplicationProperties
<div class="navbar navbar-dark"> <div class="navbar navbar-dark">

View File

@@ -3,8 +3,8 @@
@using System.Collections.Immutable @using System.Collections.Immutable
@using Phantom.Common.Data.Web.AuditLog @using Phantom.Common.Data.Web.AuditLog
@using Phantom.Common.Data.Web.Users @using Phantom.Common.Data.Web.Users
@using Phantom.Web.Services.Instances
@using Phantom.Web.Services.Users @using Phantom.Web.Services.Users
@using Phantom.Web.Services.Instances
@inherits PhantomComponent @inherits PhantomComponent
@inject AuditLogManager AuditLogManager @inject AuditLogManager AuditLogManager
@inject InstanceManager InstanceManager @inject InstanceManager InstanceManager

View File

@@ -6,7 +6,7 @@
@using Phantom.Web.Services.Agents @using Phantom.Web.Services.Agents
@using Phantom.Web.Services.Events @using Phantom.Web.Services.Events
@using Phantom.Web.Services.Instances @using Phantom.Web.Services.Instances
@inherits PhantomComponent @inherits Phantom.Web.Components.PhantomComponent
@inject AgentManager AgentManager @inject AgentManager AgentManager
@inject EventLogManager EventLogManager @inject EventLogManager EventLogManager
@inject InstanceManager InstanceManager @inject InstanceManager InstanceManager

View File

@@ -1,5 +1,5 @@
@page "/" @page "/"
@inherits PhantomComponent @inherits Phantom.Web.Components.PhantomComponent
<h1>Home</h1> <h1>Home</h1>

View File

@@ -1,7 +1,7 @@
@page "/login" @page "/login"
@using System.ComponentModel.DataAnnotations
@using Phantom.Web.Services @using Phantom.Web.Services
@using Phantom.Web.Services.Authentication @using Phantom.Web.Services.Authentication
@using System.ComponentModel.DataAnnotations
@attribute [AllowAnonymous] @attribute [AllowAnonymous]
@inject Navigation Navigation @inject Navigation Navigation
@inject UserLoginManager LoginManager @inject UserLoginManager LoginManager

View File

@@ -1,6 +1,4 @@
@page "/setup" @page "/setup"
@using System.ComponentModel.DataAnnotations
@using System.Security.Cryptography
@using Phantom.Common.Data @using Phantom.Common.Data
@using Phantom.Common.Data.Web.Users @using Phantom.Common.Data.Web.Users
@using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults @using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults
@@ -9,6 +7,8 @@
@using Phantom.Web.Services @using Phantom.Web.Services
@using Phantom.Web.Services.Authentication @using Phantom.Web.Services.Authentication
@using Phantom.Web.Services.Rpc @using Phantom.Web.Services.Rpc
@using System.ComponentModel.DataAnnotations
@using System.Security.Cryptography
@attribute [AllowAnonymous] @attribute [AllowAnonymous]
@inject ApplicationProperties ApplicationProperties @inject ApplicationProperties ApplicationProperties
@inject UserLoginManager LoginManager @inject UserLoginManager LoginManager
@@ -44,7 +44,7 @@
@code { @code {
private readonly CreateAdministratorAccountFormModel form = new (); private readonly CreateAdministratorAccountFormModel form = new();
private sealed class CreateAdministratorAccountFormModel : FormModel { private sealed class CreateAdministratorAccountFormModel : FormModel {
[Required] [Required]

View File

@@ -1,11 +1,11 @@
@page "/users" @page "/users"
@attribute [Authorize(Permission.ViewUsersPolicy)] @attribute [Authorize(Permission.ViewUsersPolicy)]
@using System.Collections.Immutable @using System.Collections.Immutable
@using Phantom.Common.Data.Web.Users
@using Phantom.Web.Services.Authentication @using Phantom.Web.Services.Authentication
@using Phantom.Web.Services.Authorization @using Phantom.Web.Services.Authorization
@using Phantom.Web.Services.Users @using Phantom.Web.Services.Users
@inherits PhantomComponent @using Phantom.Common.Data.Web.Users
@inherits Phantom.Web.Components.PhantomComponent
@inject UserManager UserManager @inject UserManager UserManager
@inject RoleManager RoleManager @inject RoleManager RoleManager
@inject UserRoleManager UserRoleManager @inject UserRoleManager UserRoleManager

View File

@@ -1,6 +1,6 @@
@using Phantom.Common.Data.Instance @using Phantom.Common.Data.Instance
<nobr> <nobr>
@switch (Status) { @switch (Status) {
case InstanceIsOffline: case InstanceIsOffline:
<span class="fw-semibold">Offline</span> <span class="fw-semibold">Offline</span>
break; break;
@@ -50,7 +50,7 @@
default: default:
<span class="fw-semibold">Unknown</span> <span class="fw-semibold">Unknown</span>
break; break;
} }
</nobr> </nobr>
@code { @code {

View File

@@ -27,7 +27,7 @@
@code { @code {
private ImmutableDictionary<Guid, RoleInfo> allRolesByGuid = ImmutableDictionary<Guid, RoleInfo>.Empty; private ImmutableDictionary<Guid, RoleInfo> allRolesByGuid = ImmutableDictionary<Guid, RoleInfo>.Empty;
private List<RoleItem> items = new (); private List<RoleItem> items = new();
protected override async Task BeforeShown(UserInfo user) { protected override async Task BeforeShown(UserInfo user) {
var allRoles = await RoleManager.GetAll(CancellationToken); var allRoles = await RoleManager.GetAll(CancellationToken);

View File

@@ -2,27 +2,22 @@
using Phantom.Common.Data.Replies; using Phantom.Common.Data.Replies;
using Phantom.Common.Data.Web.Minecraft; using Phantom.Common.Data.Web.Minecraft;
using Phantom.Common.Data.Web.Users; using Phantom.Common.Data.Web.Users;
using Phantom.Common.Data.Web.Users.AddUserErrors;
using Phantom.Common.Data.Web.Users.PasswordRequirementViolations;
using Phantom.Common.Data.Web.Users.SetUserPasswordErrors;
using Phantom.Common.Data.Web.Users.UsernameRequirementViolations;
using PasswordIsInvalid = Phantom.Common.Data.Web.Users.AddUserErrors.PasswordIsInvalid;
namespace Phantom.Web.Utils; namespace Phantom.Web.Utils;
static class Messages { static class Messages {
public static string ToSentences(this AddUserError error, string delimiter) { public static string ToSentences(this AddUserError error, string delimiter) {
return error switch { return error switch {
NameIsInvalid e => e.Violation.ToSentence(), Common.Data.Web.Users.AddUserErrors.NameIsInvalid e => e.Violation.ToSentence(),
PasswordIsInvalid e => string.Join(delimiter, e.Violations.Select(static v => v.ToSentence())), Common.Data.Web.Users.AddUserErrors.PasswordIsInvalid e => string.Join(delimiter, e.Violations.Select(static v => v.ToSentence())),
NameAlreadyExists => "Username is already occupied.", Common.Data.Web.Users.AddUserErrors.NameAlreadyExists => "Username is already occupied.",
_ => "Unknown error." _ => "Unknown error."
}; };
} }
public static string ToSentences(this SetUserPasswordError error, string delimiter) { public static string ToSentences(this SetUserPasswordError error, string delimiter) {
return error switch { return error switch {
UserNotFound => "User not found.", Common.Data.Web.Users.SetUserPasswordErrors.UserNotFound => "User not found.",
Common.Data.Web.Users.SetUserPasswordErrors.PasswordIsInvalid e => string.Join(delimiter, e.Violations.Select(static v => v.ToSentence())), Common.Data.Web.Users.SetUserPasswordErrors.PasswordIsInvalid e => string.Join(delimiter, e.Violations.Select(static v => v.ToSentence())),
_ => "Unknown error." _ => "Unknown error."
}; };
@@ -30,18 +25,18 @@ static class Messages {
public static string ToSentence(this UsernameRequirementViolation violation) { public static string ToSentence(this UsernameRequirementViolation violation) {
return violation switch { return violation switch {
IsEmpty => "Username must not be empty.", Common.Data.Web.Users.UsernameRequirementViolations.IsEmpty => "Username must not be empty.",
TooLong v => "Username must not be longer than " + v.MaxLength + " character(s).", Common.Data.Web.Users.UsernameRequirementViolations.TooLong v => "Username must not be longer than " + v.MaxLength + " character(s).",
_ => "Unknown error." _ => "Unknown error."
}; };
} }
public static string ToSentence(this PasswordRequirementViolation violation) { public static string ToSentence(this PasswordRequirementViolation violation) {
return violation switch { return violation switch {
TooShort v => "Password must be at least " + v.MinimumLength + " character(s) long.", Common.Data.Web.Users.PasswordRequirementViolations.TooShort v => "Password must be at least " + v.MinimumLength + " character(s) long.",
MustContainLowercaseLetter => "Password must contain a lowercase letter.", Common.Data.Web.Users.PasswordRequirementViolations.MustContainLowercaseLetter => "Password must contain a lowercase letter.",
MustContainUppercaseLetter => "Password must contain an uppercase letter.", Common.Data.Web.Users.PasswordRequirementViolations.MustContainUppercaseLetter => "Password must contain an uppercase letter.",
MustContainDigit => "Password must contain a digit.", Common.Data.Web.Users.PasswordRequirementViolations.MustContainDigit => "Password must contain a digit.",
_ => "Unknown error." _ => "Unknown error."
}; };
} }

View File

@@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "9.0.0", "version": "8.0.0",
"rollForward": "latestMinor", "rollForward": "latestMinor",
"allowPrerelease": true "allowPrerelease": true
} }