Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions apps-rps/rps-game-server/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public AdminController(ITournamentService tournamentService, IQuestionService qu

public IActionResult Login()
{
// If already authenticated, redirect to admin index
// If already authenticated, redirect to settings
if (IsAuthenticated())
{
return RedirectToAction("Index");
return RedirectToAction("Settings");
}

return View();
Expand All @@ -36,7 +36,7 @@ public IActionResult Login(string passcode)
if (passcode == AdminPasscode)
{
HttpContext.Session.SetString(AdminSessionKey, "true");
return RedirectToAction("Index");
return RedirectToAction("Settings");
}

TempData["Error"] = "Invalid passcode. Please try again.";
Expand All @@ -50,6 +50,16 @@ public IActionResult Index()
return RedirectToAction("Login");
}

return RedirectToAction("Settings");
}

public IActionResult Settings()
{
if (!IsAuthenticated())
{
return RedirectToAction("Login");
}

var tournament = _tournamentService.GetTournament();
return View(tournament);
}
Expand All @@ -72,7 +82,7 @@ public IActionResult UnregisterPlayer(int playerId)
TempData["Error"] = "Failed to unregister player.";
}

return RedirectToAction("Index");
return RedirectToAction("Settings");
}

[HttpPost]
Expand All @@ -93,7 +103,7 @@ public IActionResult UnregisterAllPlayers()
TempData["Error"] = "No players to unregister or operation failed.";
}

return RedirectToAction("Index");
return RedirectToAction("Settings");
}

[HttpPost]
Expand All @@ -114,7 +124,7 @@ public IActionResult ResetCurrentRound()
TempData["Error"] = "Failed to reset current round.";
}

return RedirectToAction("Index");
return RedirectToAction("Settings");
}

[HttpPost]
Expand All @@ -135,7 +145,7 @@ public IActionResult ResetTournament()
TempData["Error"] = "Failed to reset tournament.";
}

return RedirectToAction("Index");
return RedirectToAction("Settings");
}

[HttpPost]
Expand Down
44 changes: 44 additions & 0 deletions apps-rps/rps-game-server/Controllers/AzureLoginController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using RpsGameServer.Services;

namespace RpsGameServer.Controllers;

public class AzureLoginController : Controller
{
private readonly ILoginService _loginService;

public AzureLoginController(ILoginService loginService)
{
_loginService = loginService;
}

public async Task<IActionResult> Index()
{
var logins = await _loginService.GetAllLoginsAsync();
return View(logins);
}

[HttpPost]
public async Task<IActionResult> ClaimLogin(string claimedBy)
{
if (string.IsNullOrWhiteSpace(claimedBy))
{
TempData["Error"] = "Please enter your name to claim a login.";
return RedirectToAction("Index");
}

var login = await _loginService.ClaimLoginAsync(claimedBy);
if (login == null)
{
TempData["Error"] = "No available logins to claim. All entries have been claimed.";
return RedirectToAction("Index");
}

TempData["Success"] = $"Login claimed successfully!";
TempData["LoginEmail"] = login.LoginEmail;
TempData["LoginPassword"] = login.LoginPassword;
TempData["ClaimedBy"] = login.ClaimedBy;

return RedirectToAction("Index");
}
}
15 changes: 15 additions & 0 deletions apps-rps/rps-game-server/Models/LoginEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;

namespace RpsGameServer.Models;

public class LoginEntry
{
[JsonPropertyName("loginEmail")]
public string LoginEmail { get; set; } = string.Empty;

[JsonPropertyName("loginPassword")]
public string LoginPassword { get; set; } = string.Empty;

[JsonPropertyName("claimedBy")]
public string? ClaimedBy { get; set; }
}
1 change: 1 addition & 0 deletions apps-rps/rps-game-server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
builder.Services.AddSingleton<IQuestionService, QuestionService>();
builder.Services.AddScoped<ITournamentHistoryService, TournamentHistoryService>();
builder.Services.AddSingleton<ITournamentService, TournamentService>();
builder.Services.AddSingleton<ILoginService, LoginService>();

var app = builder.Build();

Expand Down
9 changes: 9 additions & 0 deletions apps-rps/rps-game-server/Services/ILoginService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using RpsGameServer.Models;

namespace RpsGameServer.Services;

public interface ILoginService
{
Task<List<LoginEntry>> GetAllLoginsAsync();
Task<LoginEntry?> ClaimLoginAsync(string claimedBy);
}
88 changes: 88 additions & 0 deletions apps-rps/rps-game-server/Services/LoginService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Text.Json;
using RpsGameServer.Models;

namespace RpsGameServer.Services;

public class LoginService : ILoginService
{
private readonly string _loginFilePath;
private readonly SemaphoreSlim _lock = new(1, 1);

public LoginService(IWebHostEnvironment environment)
{
_loginFilePath = Path.Combine(environment.ContentRootPath, "login.json");
}

public async Task<List<LoginEntry>> GetAllLoginsAsync()
{
await _lock.WaitAsync();
try
{
if (!File.Exists(_loginFilePath))
{
return new List<LoginEntry>();
}

var json = await File.ReadAllTextAsync(_loginFilePath);
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var logins = JsonSerializer.Deserialize<List<LoginEntry>>(json, options) ?? new List<LoginEntry>();
return logins;
}
finally
{
_lock.Release();
}
}

public async Task<LoginEntry?> ClaimLoginAsync(string claimedBy)
{
await _lock.WaitAsync();
try
{
var logins = await GetAllLoginsWithoutLockAsync();
var availableLogin = logins.FirstOrDefault(l => string.IsNullOrEmpty(l.ClaimedBy));

if (availableLogin == null)
{
return null;
}

availableLogin.ClaimedBy = claimedBy;
await SaveLoginsAsync(logins);
return availableLogin;
}
finally
{
_lock.Release();
}
}

private async Task<List<LoginEntry>> GetAllLoginsWithoutLockAsync()
{
if (!File.Exists(_loginFilePath))
{
return new List<LoginEntry>();
}

var json = await File.ReadAllTextAsync(_loginFilePath);
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var logins = JsonSerializer.Deserialize<List<LoginEntry>>(json, options) ?? new List<LoginEntry>();
return logins;
}

private async Task SaveLoginsAsync(List<LoginEntry> logins)
{
var options = new JsonSerializerOptions
{
WriteIndented = true
};
var json = JsonSerializer.Serialize(logins, options);
await File.WriteAllTextAsync(_loginFilePath, json);
}
}
Loading