2025-06-06 02:01:54 +02:00

314 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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() =>
"Available commands:\n" +
"1. help - Show this help message\n" +
"2. exit - Exit the server\n" +
"3. user - User management\n" +
"4. settings - Server settings\n" +
"5. start - Start the server\n" +
"6. stop - Stop the server\n";
#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 <employeeCode> <4-digit PIN>");
string employeeCode = args[0];
string pinCode = args[1];
// 2) Prevent doublelogin
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<string, object> { { "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<string, object>
{
{ "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<string, object>
{
{ "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 DBside 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("Loggedin 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<Employee>(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 Employees 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 <in|out|break>");
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<string, object> { { "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<string, object>
{
{ "EmployeeState", desiredState }
};
var whereData = new Dictionary<string, object>
{
{ "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<string, object>
{
{ "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) =>
$"not implemented yet, args: {string.Join(", ", args)}";
#endregion
#region DEV-TEST
private static Employee GenerateTestEmployee()
{
return new Employee(
code: "TEST",
surname: "Musermann",
forename: "Max",
email: "max.mustermann@company.de"
);
}
#endregion
}