Add remaining project files
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
using DeluxeBackend.Models;
|
||||
using DeluxeBackend.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using static DeluxeBackend.Enums;
|
||||
|
||||
namespace DeluxeBackend.Controllers.Accounts
|
||||
{
|
||||
[Route("Accounts/account/me")]
|
||||
[ApiController]
|
||||
public partial class MeController : ControllerBase
|
||||
{
|
||||
private readonly ILiteDbService db;
|
||||
private readonly IJwtService jwt;
|
||||
private readonly IPasswordService passwordService;
|
||||
private readonly INotificationService ws;
|
||||
|
||||
public MeController(ILiteDbService _db, IJwtService _jwtService, IPasswordService _passwordService, INotificationService _ws)
|
||||
{
|
||||
db = _db;
|
||||
jwt = _jwtService;
|
||||
passwordService = _passwordService;
|
||||
ws = _ws;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Me()
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
return Ok(account.ToDictionaryMe());
|
||||
}
|
||||
|
||||
[HttpPut("birthday")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Birthday([FromForm] string birthday)
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
if (account.Birthday.HasValue)
|
||||
{
|
||||
return Conflict(new { Success = false, Error = "Account birthday has already been set." });
|
||||
}
|
||||
|
||||
if (DateTime.TryParse(birthday, out DateTime parsedDateTime))
|
||||
{
|
||||
if (parsedDateTime > DateTime.UtcNow || parsedDateTime < DateTime.UtcNow.AddYears(-125))
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Please provide a valid birth date." });
|
||||
}
|
||||
|
||||
account.Birthday = DateOnly.FromDateTime(parsedDateTime);
|
||||
db.Accounts.Update(account);
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
|
||||
return BadRequest(new { Success = false, Error = "Invalid date format received." });
|
||||
}
|
||||
|
||||
[HttpPut("username")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Username([FromForm] string username)
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Username cannot be empty." });
|
||||
}
|
||||
|
||||
username = username.Trim();
|
||||
|
||||
if (username.Length < 3 || username.Length > 20)
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Username must be between 3 and 20 characters." });
|
||||
}
|
||||
|
||||
if (!UsernameRegex().IsMatch(username))
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Username can only contain letters, numbers, and underscores." });
|
||||
}
|
||||
|
||||
string[] reservedNames = { "admin", "administrator", "moderator", "system", "support", "staff", "deluxe" };
|
||||
if (reservedNames.Contains(username.ToLowerInvariant()))
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "This username is reserved." });
|
||||
}
|
||||
|
||||
bool isTaken = db.Accounts.Exists(a => a.Username.Equals(username, StringComparison.OrdinalIgnoreCase));
|
||||
if (isTaken)
|
||||
{
|
||||
return Conflict(new { Success = false, Error = $"The username '{username}' is already taken." });
|
||||
}
|
||||
|
||||
account.Username = username;
|
||||
account.DisplayName = username;
|
||||
db.Accounts.Update(account);
|
||||
|
||||
await ws.SendToPlayer(account.Id, "SelfAccountUpdate", account.ToDictionaryMe());
|
||||
await ws.SendToPlayerSubs(account.Id, "AccountUpdate", account.ToDictionary());
|
||||
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
|
||||
[HttpPost("/Auth/account/me/changepassword")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Changepassword([FromForm] string newPassword, [FromForm] string oldPassword = "")
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(newPassword) || newPassword.Length < 6)
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "New password must be at least 6 characters long." });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(account.PasswordHash))
|
||||
{
|
||||
if (string.IsNullOrEmpty(oldPassword))
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Old password is required." });
|
||||
}
|
||||
|
||||
var verificationResult = passwordService.VerifyPassword(account, oldPassword);
|
||||
if (verificationResult == Microsoft.AspNetCore.Identity.PasswordVerificationResult.Failed)
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Old password is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
passwordService.setPassword(account, newPassword);
|
||||
db.Accounts.Update(account);
|
||||
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
[HttpPost("/Auth/account/me/haspassword")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> HasPassword([FromForm] string newPassword, [FromForm] string oldPassword = "")
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
|
||||
|
||||
return Ok(!string.IsNullOrEmpty(account.PasswordHash));
|
||||
}
|
||||
|
||||
[HttpGet("/Accounts/parentalcontrol/me")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> ParentalControl()
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
accountId = account.Id,
|
||||
disallowInAppPurchases = false
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPut("personalpronouns")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> PersonalPronouns([FromForm] PronounsType pronounFlags)
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
account.Pronouns = pronounFlags;
|
||||
db.Accounts.Update(account);
|
||||
|
||||
await ws.SendToPlayerSubs(account.Id, "AccountUpdate", account.ToDictionary());
|
||||
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
|
||||
[HttpPut("identityflags")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> IdentityFlags([FromForm] IdentityFlagsType identityFlags)
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
account.IdentityFlags = identityFlags;
|
||||
db.Accounts.Update(account);
|
||||
|
||||
await ws.SendToPlayerSubs(account.Id, "AccountUpdate", account.ToDictionary());
|
||||
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
|
||||
[HttpPut("bio")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Bio([FromForm] string bio)
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
if (bio != null && bio.Length > 250)
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Bio cannot exceed 250 characters." });
|
||||
}
|
||||
|
||||
account.Bio = bio ?? string.Empty;
|
||||
db.Accounts.Update(account);
|
||||
|
||||
await ws.SendToPlayerSubs(account.Id, "AccountUpdate", account.ToDictionary());
|
||||
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
|
||||
[HttpPut("profileimage")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> ProfileImage([FromForm(Name = "imageName"), Required] string ImageName)
|
||||
{
|
||||
Account? account = await jwt.GetLogin(User);
|
||||
if (account == null) return Unauthorized();
|
||||
|
||||
string sanitizedPath = Path.GetFileName(ImageName);
|
||||
if (string.IsNullOrWhiteSpace(sanitizedPath) || sanitizedPath != ImageName)
|
||||
{
|
||||
return BadRequest(new { Success = false, Error = "Invalid image file name format." });
|
||||
}
|
||||
|
||||
account.ImageName = ImageName;
|
||||
db.Accounts.Update(account);
|
||||
|
||||
await ws.SendToPlayerSubs(account.Id, "AccountUpdate", account.ToDictionary());
|
||||
|
||||
return Ok(new { Success = true });
|
||||
}
|
||||
|
||||
[GeneratedRegex("^[a-zA-Z0-9_]+$")]
|
||||
private static partial Regex UsernameRegex();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user