diff --git a/Library/Employee.cs b/Library/Employee.cs index 4f63d11..f34591d 100644 --- a/Library/Employee.cs +++ b/Library/Employee.cs @@ -5,7 +5,7 @@ namespace Library; public class Employee { - public string Id { get; set; } + public int Id { get; set; } public string Code { get; set; } public string Surname { get; set; } public string Forename { get; set; } @@ -23,7 +23,6 @@ public class Employee public Employee(string code, string surname, string forename, string email) { - Id = Guid.NewGuid().ToString(); Code = code; Surname = surname; Forename = forename; diff --git a/Server/Commands/CommandLibrary.cs b/Server/Commands/CommandLibrary.cs index d358e45..2570015 100644 --- a/Server/Commands/CommandLibrary.cs +++ b/Server/Commands/CommandLibrary.cs @@ -1,4 +1,5 @@ using System.Net.Sockets; +using System.Runtime.CompilerServices; using System.Text.Json; using DX86; using Library; @@ -29,30 +30,76 @@ public class CommandLibrary [Command("login")] public static string LoginCommand(string[] args, TcpClient? client, TcpServer? socket) - { - if (args.Length < 2) - throw new CommandException("Missing arguments: usage is login "); - - string username = args[0]; - string password = args[1]; - - if (socket?.LoggedInClients.ContainsKey(client) == true) - throw new CommandException("User already logged in."); - - if (username == "TEST" && password == "1234") { - if (client != null) + // 1) Argument check + if (args.Length < 2) + throw new CommandException("Missing arguments: usage is login <4-digit PIN>"); + + string employeeCode = args[0]; + string pinCode = args[1]; + + // 2) Prevent double‐login + if (client != null && socket?.LoggedInClients.ContainsKey(client) == true) + throw new CommandException("User already logged in."); + + // 3) Look up the employee by Code + var empParams = new Dictionary { { "Code", employeeCode } }; + string empResultJson = Program.mySql.Get("employees", empParams); + + using var empDoc = JsonDocument.Parse(empResultJson); + bool empError = empDoc.RootElement.GetProperty("error").GetBoolean(); + if (empError) { - socket?.LoggedInClients.Add(client, username); - return "success"; + string dbMsg = empDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; + Program.messageSender.Error($"[LoginCommand] DB error when looking up employee: {dbMsg}"); + throw new CommandException("Internal error while checking credentials."); } - throw new CommandException("No client connection detected."); + var empArray = empDoc.RootElement.GetProperty("data"); + if (empArray.GetArrayLength() == 0) + { + // No employee with that Code + throw new CommandException("Invalid employee code or PIN."); + } + + // 4) Extract Id from the first row + var empRow = empArray[0]; + int employeeId = empRow.GetProperty("Id").GetInt32(); + + // 5) Check PIN for that employeeId + var pinParams = new Dictionary + { + { "EmployeeId", employeeId }, + { "PinCode", pinCode } + }; + string pinResultJson = Program.mySql.Get("employee_pins", pinParams); + + using var pinDoc = JsonDocument.Parse(pinResultJson); + bool pinError = pinDoc.RootElement.GetProperty("error").GetBoolean(); + if (pinError) + { + string dbMsg = pinDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; + Program.messageSender.Error($"[LoginCommand] DB error when checking PIN: {dbMsg}"); + throw new CommandException("Internal error while checking credentials."); + } + + var pinArray = pinDoc.RootElement.GetProperty("data"); + if (pinArray.GetArrayLength() == 0) + { + // No matching PIN entry + throw new CommandException("Invalid employee code or PIN."); + } + + // 6) Successful login → add client to LoggedInClients + if (client == null) + throw new CommandException("No client connection detected."); + + socket!.LoggedInClients.Add(client, employeeCode); + + // 7) Return “success” (instead of full Employee JSON) + return "success"; } - - throw new CommandException("Invalid username or password."); - } - + [Command("logout")] public static string LogoutCommand(TcpClient? client, TcpServer? socket) { @@ -67,15 +114,60 @@ public class CommandLibrary [Command("getSelfUser")] public static string GetSelfUserCommand(TcpClient? client, TcpServer? socket) { + // 1) Check for a valid client/socket if (client == null || socket == null) throw new CommandException("No client connection detected."); - if (socket.LoggedInClients.TryGetValue(client, out var username)) + // 2) See if this client is logged in + if (!socket.LoggedInClients.TryGetValue(client, out var employeeCode)) + throw new CommandException("User not logged in."); + + // 3) Query the database for that employeeCode + var empParams = new Dictionary { - return GenerateTestEmployee().ToJson(); + { "Code", employeeCode } + }; + string empResultJson = Program.mySql.Get("employees", empParams); + + using var empDoc = JsonDocument.Parse(empResultJson); + bool empError = empDoc.RootElement.GetProperty("error").GetBoolean(); + if (empError) + { + // Extract the “data” field as the DB‐side error message, if any + string dbMsg = empDoc.RootElement.GetProperty("data").GetString() + ?? "Unknown DB error"; + Program.messageSender.Error($"[GetSelfUser] DB error when looking up employee: {dbMsg}"); + throw new CommandException("Internal error while fetching user data."); } - throw new CommandException("User not logged in."); + var dataArray = empDoc.RootElement.GetProperty("data"); + if (dataArray.GetArrayLength() == 0) + { + // No employee row found for this code + throw new CommandException("Logged‐in user not found in database."); + } + + // 4) We expect exactly one row. Take the first element: + var firstRow = dataArray[0]; + + // 5) Deserialize it into an Employee object. + // This requires that Employee.Id is an int (matching the DB schema), + // or you map fields manually if Id remains a string. + Employee self; + try + { + string employeeJson = firstRow.GetRawText(); + self = JsonSerializer.Deserialize(employeeJson) + ?? throw new InvalidOperationException("Deserialized Employee was null."); + } + catch (Exception ex) + { + Program.messageSender.Error($"[GetSelfUser] Failed to deserialize Employee: {ex.Message}"); + throw new CommandException("Internal error while parsing user data."); + } + + // 6) Return the Employee’s JSON via the ToJson() helper you already wrote: + return self.ToJson(); } #endregion @@ -85,6 +177,7 @@ public class CommandLibrary [Command("get")] public static string GetCommand(string[] args, TcpClient? client, TcpServer? socket) => $"not implemented yet, args: {string.Join(", ", args)}"; + #endregion diff --git a/Server/Program.cs b/Server/Program.cs index 206bebd..0206b79 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -38,7 +38,7 @@ namespace Server; { messageSender.Log("[Program] Loaded existing database configuration."); // Use existing credentials to connect (including cfg.Port) - return new MySQL(cfg.Username, cfg.Password, cfg.Server, cfg.Port, cfg.Database, messageSender); + return InitializeDatabase(cfg.Username, cfg.Password, cfg.Server, cfg.Port, cfg.Database); } else { @@ -69,15 +69,13 @@ private static MySQL InitializeDatabase( { // 1) Instantiate MySQL (will exit on failure) var db = new MySQL(username, password, server, port, database, messageSender); - - // 2) Create the 'employees' table if it does not exist: string createEmployeesTable = @" CREATE TABLE IF NOT EXISTS `employees` ( - `Id` VARCHAR(36) NOT NULL PRIMARY KEY, - `Code` VARCHAR(50) NOT NULL, - `Surname` VARCHAR(100) NOT NULL, - `Forename` VARCHAR(100) NOT NULL, - `Email` VARCHAR(150) NOT NULL, + `Id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `Code` VARCHAR(50) NOT NULL, + `Surname` VARCHAR(100) NOT NULL, + `Forename` VARCHAR(100) NOT NULL, + `Email` VARCHAR(150) NOT NULL, `Phone` VARCHAR(50), `Street` VARCHAR(200), `City` VARCHAR(100), @@ -85,39 +83,63 @@ private static MySQL InitializeDatabase( `Country` VARCHAR(100), `Department` VARCHAR(100), `Position` VARCHAR(100), - `EmployeeState` INT NOT NULL + `EmployeeState` INT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "; - messageSender.Log("[Program] Creating 'employees' table if not present…"); - var resultJson = db.ExecuteNonQuery(createEmployeesTable); - - // Parse resultJson safely using JsonDocument + messageSender.Log("[Program] Creating or verifying 'employees' table…"); + var employeesResult = db.ExecuteNonQuery(createEmployeesTable); try { - using var doc = JsonDocument.Parse(resultJson); - var root = doc.RootElement; - - // Expecting { "error": bool, "data": ... } - bool isError = root.GetProperty("error").GetBoolean(); - if (isError) + using var doc = JsonDocument.Parse(employeesResult); + bool empError = doc.RootElement.GetProperty("error").GetBoolean(); + if (empError) { - // You can inspect root.GetProperty("data").GetString() if needed - messageSender.Error("[Program] Failed to create 'employees' table: " + resultJson); + messageSender.Error("[Program] Failed to create/verify 'employees' table: " + employeesResult); Environment.Exit(1); } } catch (Exception ex) { - // If something went wrong parsing JSON, treat it as a fatal error - messageSender.Error($"[Program] Could not parse CREATE TABLE response: {ex.Message}"); - messageSender.Error("[Program] Raw response: " + resultJson); + messageSender.Error("[Program] Could not parse employees CREATE TABLE response: " + ex.Message); + messageSender.Error("[Program] Raw response: " + employeesResult); Environment.Exit(1); } - messageSender.Log("[Program] 'employees' table is ready."); - // TODO: repeat db.ExecuteNonQuery(...) for any other tables you need + // 2b) Create a new table for storing 4-digit PINs linked to EmployeeId + string createPinsTable = @" + CREATE TABLE IF NOT EXISTS `employee_pins` ( + `PinId` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `EmployeeId` INT NOT NULL, + `PinCode` CHAR(4) NOT NULL, + FOREIGN KEY (`EmployeeId`) REFERENCES `employees`(`Id`) + ON DELETE CASCADE + ON UPDATE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + "; + + messageSender.Log("[Program] Creating or verifying 'employee_pins' table…"); + var pinsResult = db.ExecuteNonQuery(createPinsTable); + try + { + using var doc2 = JsonDocument.Parse(pinsResult); + bool pinError = doc2.RootElement.GetProperty("error").GetBoolean(); + if (pinError) + { + messageSender.Error("[Program] Failed to create/verify 'employee_pins' table: " + pinsResult); + Environment.Exit(1); + } + } + catch (Exception ex) + { + messageSender.Error("[Program] Could not parse employee_pins CREATE TABLE response: " + ex.Message); + messageSender.Error("[Program] Raw response: " + pinsResult); + Environment.Exit(1); + } + messageSender.Log("[Program] 'employee_pins' table is ready."); + + // … (any further tables) … // 3) Save the new credentials (including port) into config.json: var newCfg = new DbConfig