using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Text.Json; using DX86; using Library; namespace Server; public class CommandLibrary { [Command("example")] public static string ExampleCommand(string[] args, TcpClient? client, TcpServer? socket) => $"Example command executed with arguments: {string.Join(", ", args)}"; #region Basic Commands /*[Command("help")] public static string HelpCommand(string[] args, TcpClient? client, TcpServer? socket) { throw new CommandException("Available commands:%break" + "1. help - Show this help message%break" + "2. exit - Exit the server%break" + "3. user - User management%break" + "4. settings - Server settings%break" + "5. start - Start the server%break" + "6. stop - Stop the server%break"); }*/ #endregion #region Client Commands [Command("login")] public static string LoginCommand(string[] args, TcpClient? client, TcpServer? socket) { // 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) { 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."); } 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"; } [Command("logout")] public static string LogoutCommand(TcpClient? client, TcpServer? socket) { if (client != null && socket?.LoggedInClients.ContainsKey(client) == true) { socket.LoggedInClients.Remove(client); return "success"; } throw new CommandException("No client provided or not logged in"); } [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."); // 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 { { "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."); } 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(); } [Command("clock")] public static string ClockCommand(string[] args, TcpClient? client, TcpServer? socket) { // 1) Argument check if (args.Length < 1) throw new CommandException("Missing argument: usage is clock "); string desired = args[0].ToLowerInvariant(); int desiredState; switch (desired) { case "in": desiredState = 1; break; case "out": desiredState = 0; break; case "break": desiredState = 2; break; default: throw new CommandException("Invalid argument. Use in, out, or break."); } // 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 by Code to get Id and current state 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($"[ClockCommand] 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("Logged-in user not found in database."); var empRow = empArray[0]; int employeeId = empRow.GetProperty("Id").GetInt32(); int currentState = empRow.GetProperty("EmployeeState").GetInt32(); // 4) Validate state transition if (currentState == desiredState) throw new CommandException($"Already {(desiredState == 0 ? "OUT" : desiredState == 1 ? "IN" : "on BREAK")}."); bool valid = false; switch (currentState) { case 0: // OUT → only IN valid = (desiredState == 1); break; case 1: // IN → OUT or BREAK valid = (desiredState == 0 || desiredState == 2); break; case 2: // BREAK → only IN valid = (desiredState == 1); break; } if (!valid) throw new CommandException("Invalid transition from current status."); // 5) Update employees.EmployeeState to desiredState var updateData = new Dictionary { { "EmployeeState", desiredState } }; var whereData = new Dictionary { { "Id", employeeId } }; string updateJson = Program.mySql.Update("employees", updateData, whereData); using (var updateDoc = JsonDocument.Parse(updateJson)) { bool updError = updateDoc.RootElement.GetProperty("error").GetBoolean(); if (updError) { string dbMsg = updateDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; Program.messageSender.Error($"[ClockCommand] DB error when updating state: {dbMsg}"); throw new CommandException("Internal error while updating status."); } } // 6) Insert into employee_state_history var historyData = new Dictionary { { "EmployeeId", employeeId }, { "NewState", desiredState } }; string historyJson = Program.mySql.Insert("employee_state_history", historyData); using (var histDoc = JsonDocument.Parse(historyJson)) { bool histError = histDoc.RootElement.GetProperty("error").GetBoolean(); if (histError) { string dbMsg = histDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error"; Program.messageSender.Error($"[ClockCommand] DB error when logging history: {dbMsg}"); throw new CommandException("Internal error while logging status change."); } } // 7) Return success return "success"; } #endregion #region Administration Commands [Command("get")] 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 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(); } [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` ORDER BY `ChangeTime` DESC LIMIT ? "; var values = new List {maxHistoryLength }; // Pass an empty string ("") for 'types' so that parameters get bound correctly string historyJson = Program.mySql.Query(sql, /*types:*/ "", /*values:*/ values); // 5) Return the JSON from Query (the client will receive {"error":…, "data":[…]} ) return historyJson; } #endregion #region DEV-TEST private static Employee GenerateTestEmployee() { return new Employee( code: "TEST", surname: "Musermann", forename: "Max", email: "max.mustermann@company.de" ); } #endregion }