1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2025-08-21 06:54:07 +02:00
Files
.config
.run
.workdir
Agent
Common
Controller
Phantom.Controller
Phantom.Controller.Database
Converters
Entities
Factories
Repositories
AuditLogRepository.Writer.cs
AuditLogRepository.cs
EventLogRepository.cs
PermissionRepository.cs
RoleRepository.cs
UserRepository.cs
UserRoleRepository.cs
ApplicationDbContext.cs
DatabaseMigrator.cs
IDbContextProvider.cs
ILazyDbContext.cs
Phantom.Controller.Database.csproj
Phantom.Controller.Database.Postgres
Phantom.Controller.Minecraft
Phantom.Controller.Services
Docker
Utils
Web
.dockerignore
.gitattributes
.gitignore
AddMigration.bat
AddMigration.sh
Directory.Build.props
Directory.Build.targets
Dockerfile
LICENSE
Packages.props
PhantomPanel.sln
README.md
global.json

110 lines
3.3 KiB
C#

using System.Collections.Immutable;
using Microsoft.EntityFrameworkCore;
using Phantom.Common.Data;
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.UsernameRequirementViolations;
using Phantom.Controller.Database.Entities;
using Phantom.Utils.Collections;
namespace Phantom.Controller.Database.Repositories;
public sealed class UserRepository {
private const int MaxUserNameLength = 40;
private const int MinimumPasswordLength = 16;
private static UsernameRequirementViolation? CheckUsernameRequirements(string username) {
if (string.IsNullOrWhiteSpace(username)) {
return new IsEmpty();
}
else if (username.Length > MaxUserNameLength) {
return new TooLong(MaxUserNameLength);
}
else {
return null;
}
}
private static ImmutableArray<PasswordRequirementViolation> CheckPasswordRequirements(string password) {
var violations = ImmutableArray.CreateBuilder<PasswordRequirementViolation>();
if (password.Length < MinimumPasswordLength) {
violations.Add(new TooShort(MinimumPasswordLength));
}
if (!password.Any(char.IsLower)) {
violations.Add(new MustContainLowercaseLetter());
}
if (!password.Any(char.IsUpper)) {
violations.Add(new MustContainUppercaseLetter());
}
if (!password.Any(char.IsDigit)) {
violations.Add(new MustContainDigit());
}
return violations.ToImmutable();
}
private readonly ILazyDbContext db;
public UserRepository(ILazyDbContext db) {
this.db = db;
}
public Task<ImmutableArray<UserEntity>> GetAll() {
return db.Ctx.Users.AsAsyncEnumerable().ToImmutableArrayAsync();
}
public Task<Dictionary<Guid, T>> GetAllByGuid<T>(Func<UserEntity, T> valueSelector, CancellationToken cancellationToken = default) {
return db.Ctx.Users.ToDictionaryAsync(static user => user.UserGuid, valueSelector, cancellationToken);
}
public async Task<UserEntity?> GetByGuid(Guid guid) {
return await db.Ctx.Users.FindAsync(guid);
}
public Task<UserEntity?> GetByName(string username) {
return db.Ctx.Users.FirstOrDefaultAsync(user => user.Name == username);
}
public async Task<Result<UserEntity, AddUserError>> CreateUser(string username, string password) {
var usernameRequirementViolation = CheckUsernameRequirements(username);
if (usernameRequirementViolation != null) {
return new NameIsInvalid(usernameRequirementViolation);
}
var passwordRequirementViolations = CheckPasswordRequirements(password);
if (!passwordRequirementViolations.IsEmpty) {
return new PasswordIsInvalid(passwordRequirementViolations);
}
if (await db.Ctx.Users.AnyAsync(user => user.Name == username)) {
return new NameAlreadyExists();
}
var user = new UserEntity(Guid.NewGuid(), username, UserPasswords.Hash(password));
db.Ctx.Users.Add(user);
return user;
}
public Result<SetUserPasswordError> SetUserPassword(UserEntity user, string password) {
var requirementViolations = CheckPasswordRequirements(password);
if (!requirementViolations.IsEmpty) {
return new Common.Data.Web.Users.SetUserPasswordErrors.PasswordIsInvalid(requirementViolations);
}
user.PasswordHash = UserPasswords.Hash(password);
return Result.Ok;
}
public void DeleteUser(UserEntity user) {
db.Ctx.Users.Remove(user);
}
}