From 8630c4c346277ecedb936b5ff60d94e54e047b51 Mon Sep 17 00:00:00 2001 From: "Tim G. | SnapixLP" Date: Fri, 6 Jun 2025 09:06:59 +0200 Subject: [PATCH] added clockhistory and get command --- Library/EmployeeState.cs | 13 +++ Library/Server.cs | 6 +- Server/Commands/CommandLibrary.cs | 155 +++++++++++++++++++++++++++++- TestClient/Program.cs | 5 + 4 files changed, 175 insertions(+), 4 deletions(-) diff --git a/Library/EmployeeState.cs b/Library/EmployeeState.cs index a5fc30b..662af34 100644 --- a/Library/EmployeeState.cs +++ b/Library/EmployeeState.cs @@ -5,4 +5,17 @@ public enum EmployeeState OUT, IN, BREAK, +} +public static class EmployeeStateExtensions +{ + public static string ToFriendlyString(this EmployeeState state) + { + return state switch + { + EmployeeState.OUT => "Clocked Out", + EmployeeState.IN => "Clocked In", + EmployeeState.BREAK => "On Break", + _ => state.ToString() + }; + } } \ No newline at end of file diff --git a/Library/Server.cs b/Library/Server.cs index e39349d..38981f8 100644 --- a/Library/Server.cs +++ b/Library/Server.cs @@ -139,9 +139,9 @@ public class Server // Implement logic to get a worker by ID or code if (id != null) - commandResult = ExecuteCommandAsync("get worker byid " + id).Result; + commandResult = ExecuteCommandAsync("get employee byid " + id).Result; else - commandResult = ExecuteCommandAsync("get worker bycode " + id).Result; + commandResult = ExecuteCommandAsync("get employee bycode " + code).Result; // Deserialize the command result to an Employee object try @@ -233,4 +233,6 @@ public class Server return Task.FromException(new Exception("Failed to clock break.")); } } + + } \ No newline at end of file diff --git a/Server/Commands/CommandLibrary.cs b/Server/Commands/CommandLibrary.cs index 32cdcd9..a558dfc 100644 --- a/Server/Commands/CommandLibrary.cs +++ b/Server/Commands/CommandLibrary.cs @@ -295,8 +295,159 @@ public class CommandLibrary #region Administration Commands [Command("get")] - public static string GetCommand(string[] args, TcpClient? client, TcpServer? socket) => - $"not implemented yet, args: {string.Join(", ", args)}"; + public static string GetCommand(string[] args, TcpClient? client, TcpServer? socket) + { + // Usage: get employee byid + // get employee bycode + if (args.Length < 3) + throw new CommandException("Usage: get employee byid OR get employee bycode "); + + string entity = args[0].ToLowerInvariant(); + string mode = args[1].ToLowerInvariant(); + string key = args[2]; + + if (entity != "employee") + throw new CommandException("Usage: get employee byid OR get employee bycode "); + + var filter = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (mode == "byid") + { + if (!int.TryParse(key, out var id)) + throw new CommandException("Invalid id format. Must be an integer."); + + filter["Id"] = id; + } + else if (mode == "bycode") + { + filter["Code"] = key; + } + else + { + throw new CommandException("Usage: get employee byid OR get employee bycode "); + } + + // Query the database + string empResultJson = Program.mySql.Get("employees", filter); + + using var doc = JsonDocument.Parse(empResultJson); + bool dbError = doc.RootElement.GetProperty("error").GetBoolean(); + if (dbError) + { + string dbMsg = doc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; + Program.messageSender.Error($"[GetCommand] DB error: {dbMsg}"); + throw new CommandException("Internal error while fetching employee."); + } + + var dataArray = doc.RootElement.GetProperty("data"); + if (dataArray.GetArrayLength() == 0) + throw new CommandException("Employee not found."); + + // Return the first (and expected single) matching employee as JSON object + var firstEmp = dataArray[0]; + return firstEmp.GetRawText(); + } + + [Command("clockHistory")] + public static string ClockHistoryCommand(string[] args, TcpClient? client, TcpServer? socket) + { + // 1) Argument check + if (args.Length < 1) + throw new CommandException("Missing argument: usage is clockHistory "); + + string employeeCode = args[0]; + + // 2) 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) + { + string dbMsg = empDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; + Program.messageSender.Error($"[ClockHistoryCommand] DB error when looking up employee: {dbMsg}"); + throw new CommandException("Internal error while fetching employee data."); + } + + var empArray = empDoc.RootElement.GetProperty("data"); + if (empArray.GetArrayLength() == 0) + throw new CommandException("Employee not found in database."); + + // 3) Extract Id from the first row + var empRow = empArray[0]; + int employeeId = empRow.GetProperty("Id").GetInt32(); + + // 4) Query the history for that employeeId + var histParams = new Dictionary { { "EmployeeId", employeeId } }; + string histResultJson = Program.mySql.Get("employee_state_history", histParams); + + using var histDoc = JsonDocument.Parse(histResultJson); + bool histError = histDoc.RootElement.GetProperty("error").GetBoolean(); + if (histError) + { + string dbMsg = histDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; + Program.messageSender.Error($"[ClockHistoryCommand] DB error when fetching history: {dbMsg}"); + throw new CommandException("Internal error while fetching clock history."); + } + + return histDoc.RootElement.GetProperty("data").GetRawText(); + } + + [Command("fullClockHistory")] + public static string FullClockHistoryCommand(string[] args, TcpClient? client, TcpServer? socket) + { + // 1) Determine maxHistoryLength (default = 50) + int maxHistoryLength; + if (args.Length >= 1 && int.TryParse(args[0], out var parsed)) + { + maxHistoryLength = parsed; + } + else + { + maxHistoryLength = 50; + } + + // 2) Verify client/socket + if (client == null || socket == null) + throw new CommandException("No client connection detected."); + + if (!socket.LoggedInClients.TryGetValue(client, out var employeeCode)) + throw new CommandException("User not logged in."); + + // 3) Look up the employee to get its Id + 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) + { + string dbMsg = empDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; + Program.messageSender.Error($"[FullClockHistory] DB error when looking up employee: {dbMsg}"); + throw new CommandException("Internal error while fetching user data."); + } + + var empArray = empDoc.RootElement.GetProperty("data"); + if (empArray.GetArrayLength() == 0) + throw new CommandException("Logged-in user not found in database."); + + int employeeId = empArray[0].GetProperty("Id").GetInt32(); + + // 4) Query the history table for this employeeId, ordered by ChangeTime DESC, limited to maxHistoryLength + string sql = @" + SELECT `EmployeeId`, `NewState`, `ChangeTime` + FROM `employee_state_history` + WHERE `EmployeeId` = ? + ORDER BY `ChangeTime` DESC + LIMIT ? + "; + var values = new List { employeeId, maxHistoryLength }; + string historyJson = Program.mySql.Query(sql, null, values); + + // 5) Return the JSON from Query (the client will receive {"error":…, "data":[…]} ) + return historyJson; + } #endregion diff --git a/TestClient/Program.cs b/TestClient/Program.cs index 8eacacb..f808900 100644 --- a/TestClient/Program.cs +++ b/TestClient/Program.cs @@ -15,6 +15,10 @@ public class Tester Console.Write("Enter the server IP address: "); string ip = Console.ReadLine(); + if (ip == "devsrv") + ip = "185.113.120.99"; + else if (ip == "local") + ip = "127.0.0.1"; Console.Write("Enter the port: "); int port = int.Parse(Console.ReadLine()); @@ -77,6 +81,7 @@ public class Tester $"Code: {employee.Code}", $"Surname: {employee.Surname}", $"Forename: {employee.Forename}", + $"clocked: {employee.EmployeeState.ToFriendlyString()}", }); } else if (command == "clock in")