diff --git a/SessionZeroBackend/Controllers/DatabaseController.cs b/SessionZeroBackend/Controllers/DatabaseController.cs index 37124a0..42c6fb8 100644 --- a/SessionZeroBackend/Controllers/DatabaseController.cs +++ b/SessionZeroBackend/Controllers/DatabaseController.cs @@ -14,25 +14,35 @@ public class DatabaseController : ControllerBase _context = context; } - [HttpGet("verify-users-table")] - public async Task VerifyUsersTable() + // [HttpGet("verify-users-table")] + // public async Task VerifyUsersTable() + // { + // try + // { + // var tableExists = await _context.Users.AnyAsync(); + // return Ok(new + // { + // Message = "Users table exists and can be queried.", + // CanQuery = true + // }); + // } + // catch (Exception ex) + // { + // return StatusCode(500, new + // { + // Message = "Error accessing users table", + // Error = ex.Message + // }); + // } + // } + + [HttpGet("validate-server")] + public IActionResult ValidateServer() { - try + return Ok(new { - var tableExists = await _context.Users.AnyAsync(); - return Ok(new - { - Message = "Users table exists and can be queried.", - CanQuery = true - }); - } - catch (Exception ex) - { - return StatusCode(500, new - { - Message = "Error accessing users table", - Error = ex.Message - }); - } + IsValid = true, + Message = "SessionZero server is running.", + }); } } \ No newline at end of file diff --git a/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/libraries/GdSdk_Master.xml b/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/libraries/GdSdk_Master.xml new file mode 100644 index 0000000..e60a2f5 --- /dev/null +++ b/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/libraries/GdSdk_Master.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/vcs.xml b/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/vcs.xml index d843f34..b2bdec2 100644 --- a/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/vcs.xml +++ b/SessionZeroClient/sessionzero/.idea/.idea.SessionZero/.idea/vcs.xml @@ -1,4 +1,6 @@ - + + + \ No newline at end of file diff --git a/SessionZeroClient/sessionzero/Assets/Scripts/API/ApiHandler.cs b/SessionZeroClient/sessionzero/Assets/Scripts/API/ApiHandler.cs index e948980..7cc8a0a 100644 --- a/SessionZeroClient/sessionzero/Assets/Scripts/API/ApiHandler.cs +++ b/SessionZeroClient/sessionzero/Assets/Scripts/API/ApiHandler.cs @@ -2,7 +2,10 @@ using System; using System.Collections.Generic; using System.Net.Http; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; +using Godot; +using HttpClient = System.Net.Http.HttpClient; namespace SessionZeroClient.API; @@ -12,11 +15,67 @@ public class ApiHandler : IApiHandler public ApiHandler() { - _httpClient = new HttpClient(); + var handler = new HttpClientHandler + { + UseDefaultCredentials = true, + }; + + _httpClient = new HttpClient(handler) + { + Timeout = TimeSpan.FromSeconds(5), + }; + } + + /// + /// Returns true if the server URL is reachable valid, false otherwise. + /// + /// + /// + public async Task ValidateServerUrl(string url) + { + try + { + var apiString = $"{url}/api/Database/validate-server"; + + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + var response = await _httpClient.GetAsync(apiString, cts.Token); + + if (!response.IsSuccessStatusCode) + { + return false; + } + + var responseString = await response.Content.ReadAsStringAsync(cts.Token); + + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + var validationResponse = JsonSerializer.Deserialize(responseString, options); + + return validationResponse?.IsValid ?? false; + } + catch + { + throw new HttpRequestException($"Server {url} is invalid or not reachable."); + return false; + } } + /// + /// Register a new user with the server. + /// + /// + /// + /// + /// + /// + /// public async Task Register(string url, string username, string email, string password) { + bool isValidServer = await ValidateServerUrl(url); + if (!isValidServer) + { + throw new HttpRequestException($"Could not Register User, Server {url} is invalid or not reachable."); + } + var apiString = $"{url}/api/Auth/register"; var requestBody = new Dictionary { @@ -39,8 +98,23 @@ public class ApiHandler : IApiHandler return responseString; } + /// + /// Login to the server with the given username and password. Returns the JWT token if successful. + /// + /// + /// + /// + /// + /// public async Task Login(string url, string username, string password) { + + bool isValidServer = await ValidateServerUrl(url); + if (!isValidServer) + { + throw new HttpRequestException($"Could not Login, Server {url} is invalid or not reachable."); + } + var apiString = $"{url}/api/Auth/login"; var requestBody = new Dictionary { @@ -60,4 +134,11 @@ public class ApiHandler : IApiHandler var responseString = await response.Content.ReadAsStringAsync(); return responseString; } -} \ No newline at end of file + + public class ServerUrlValidationResponse + { + public bool IsValid { get; set; } + public string Message { get; set; } + } +} + diff --git a/SessionZeroClient/sessionzero/Assets/Scripts/API/IApiHandler.cs b/SessionZeroClient/sessionzero/Assets/Scripts/API/IApiHandler.cs index 8812a5f..e8b4c30 100644 --- a/SessionZeroClient/sessionzero/Assets/Scripts/API/IApiHandler.cs +++ b/SessionZeroClient/sessionzero/Assets/Scripts/API/IApiHandler.cs @@ -4,6 +4,7 @@ namespace SessionZeroClient.API; public interface IApiHandler { + Task ValidateServerUrl(string url); Task Register(string url, string username, string email, string password); Task Login(string url, string username, string password); } \ No newline at end of file diff --git a/SessionZeroClient/sessionzero/Assets/Scripts/AccountScreenLogic.cs b/SessionZeroClient/sessionzero/Assets/Scripts/AccountScreenLogic.cs index bbf6c79..6c3b8ba 100644 --- a/SessionZeroClient/sessionzero/Assets/Scripts/AccountScreenLogic.cs +++ b/SessionZeroClient/sessionzero/Assets/Scripts/AccountScreenLogic.cs @@ -1,6 +1,8 @@ using Godot; using System; +using System.Threading.Tasks; using SessionZeroClient; +using SessionZeroClient.API; public partial class AccountScreenLogic : Node { @@ -38,11 +40,13 @@ public partial class AccountScreenLogic : Node [Export] Button BackButton { get; set; } + private IApiHandler _apiHandler; private AccountManager _accountManager; private string _url = ""; - public void Init(AccountManager accountManager) + public void Init(IApiHandler apiHandler, AccountManager accountManager) { + _apiHandler = apiHandler; _accountManager = accountManager; SetupSignals(); InitialState(); @@ -105,16 +109,24 @@ public partial class AccountScreenLogic : Node BackButton.Pressed += BackButtonPressed; } - private void RegisterSelectionButtonPressed() + private async void RegisterSelectionButtonPressed() { - _url = UrlLineEdit.Text; // TODO: Add validation - RegisterState(); + bool isValidServer = await ValidateServerUrl(UrlLineEdit.Text); + if (isValidServer) + { + _url = UrlLineEdit.Text; + RegisterState(); + } } - private void LoginSelectionButtonPressed() + private async void LoginSelectionButtonPressed() { - _url = UrlLineEdit.Text; // TODO: Add validation - LoginState(); + bool isValidServer = await ValidateServerUrl(UrlLineEdit.Text); + if (isValidServer) + { + _url = UrlLineEdit.Text; + LoginState(); + } } private async void RegisterButtonPressed() @@ -153,6 +165,24 @@ public partial class AccountScreenLogic : Node AccountSuccessState(); } } + + private async Task ValidateServerUrl(string url) + { + if (string.IsNullOrEmpty(url)) + { + return false; + } + + try + { + return await _apiHandler.ValidateServerUrl(url); + } + catch (Exception ex) + { + GD.PrintErr($"Server validation error: {ex.Message}"); + return false; + } + } private void Logout() { diff --git a/SessionZeroClient/sessionzero/Assets/Scripts/Main.cs b/SessionZeroClient/sessionzero/Assets/Scripts/Main.cs index e72f688..502583a 100644 --- a/SessionZeroClient/sessionzero/Assets/Scripts/Main.cs +++ b/SessionZeroClient/sessionzero/Assets/Scripts/Main.cs @@ -25,7 +25,7 @@ public partial class Main : Node try { _accountScreenLogic = AccountScreenScene.Instantiate() as AccountScreenLogic; - _accountScreenLogic.Init(_accountManager); + _accountScreenLogic.Init(_apiHandler, _accountManager); MainCanvasLayer.AddChild(_accountScreenLogic); } catch (Exception e)