diff --git a/Intersect.Server/Web/Controllers/Api/V1/GuildController.cs b/Intersect.Server/Web/Controllers/Api/V1/GuildController.cs index e39cb83462..bc57d4a736 100644 --- a/Intersect.Server/Web/Controllers/Api/V1/GuildController.cs +++ b/Intersect.Server/Web/Controllers/Api/V1/GuildController.cs @@ -369,19 +369,19 @@ public IActionResult GuildVariableSet(Guid guildId, Guid variableId, [FromBody] var variable = guild.GetVariable(variableDescriptor.Id, true); - var changed = false; - if (variable?.Value != null) + if (variable?.Value == null) { - if (variable.Value.Value != valueBody.Value) - { - variable.Value.Value = valueBody.Value; - changed = true; - } + return InternalServerError("Variable value storage is missing."); } - // ReSharper disable once InvertIf - if (changed) + if (!VariableValueHelper.TryConvertValue(variableDescriptor.DataType, valueBody.Value, out object convertedValue, out string error)) { + return BadRequest(error); + } + + if (!VariableValueHelper.Equals(variableDescriptor.DataType, variable.Value, convertedValue)) + { + variable.Value.Value = convertedValue; guild.StartCommonEventsWithTriggerForAll(CommonEventTrigger.GuildVariableChange, string.Empty, variableId.ToString()); _ = guild.UpdatedVariables.AddOrUpdate( variableId, diff --git a/Intersect.Server/Web/Controllers/Api/V1/PlayerController.cs b/Intersect.Server/Web/Controllers/Api/V1/PlayerController.cs index 2c4a4be6fe..6c46af7685 100644 --- a/Intersect.Server/Web/Controllers/Api/V1/PlayerController.cs +++ b/Intersect.Server/Web/Controllers/Api/V1/PlayerController.cs @@ -693,19 +693,19 @@ public IActionResult PlayerVariableSet(LookupKey lookupKey, Guid variableId, [Fr var variable = player.GetVariable(variableDescriptor.Id, true); - var changed = false; - if (variable?.Value != null) + if (variable?.Value == null) { - if (variable.Value.Value != valueBody.Value) - { - variable.Value.Value = valueBody.Value; - changed = true; - } + return InternalServerError("Variable value storage is missing."); + } + + if (!VariableValueHelper.TryConvertValue(variableDescriptor.DataType, valueBody.Value, out object convertedValue, out string error)) + { + return BadRequest(error); } - // ReSharper disable once InvertIf - if (changed) + if (!VariableValueHelper.Equals(variableDescriptor.DataType, variable.Value, convertedValue)) { + variable.Value.Value = convertedValue; player.StartCommonEventsWithTrigger(CommonEventTrigger.PlayerVariableChange, string.Empty, variableId.ToString()); using var context = DbInterface.CreatePlayerContext(false); _ = context.Update(player); diff --git a/Intersect.Server/Web/Controllers/Api/V1/UserController.cs b/Intersect.Server/Web/Controllers/Api/V1/UserController.cs index 16e05f6ddb..04b3bea5ef 100644 --- a/Intersect.Server/Web/Controllers/Api/V1/UserController.cs +++ b/Intersect.Server/Web/Controllers/Api/V1/UserController.cs @@ -626,19 +626,19 @@ public IActionResult UserVariableSet(LookupKey lookupKey, Guid variableId, [From var variable = user.GetVariable(variableDescriptor.Id, true); - var changed = false; - if (variable?.Value != null) + if (variable?.Value == null) { - if (variable.Value.Value != valueBody.Value) - { - variable.Value.Value = valueBody.Value; - changed = true; - } + return InternalServerError("Variable value storage is missing."); + } + + if (!VariableValueHelper.TryConvertValue(variableDescriptor.DataType, valueBody.Value, out object convertedValue, out string error)) + { + return BadRequest(error); } - // ReSharper disable once InvertIf - if (changed) + if (!VariableValueHelper.Equals(variableDescriptor.DataType, variable.Value, convertedValue)) { + variable.Value.Value = convertedValue; user.StartCommonEventsWithTriggerForAll(CommonEventTrigger.UserVariableChange, string.Empty, variableId.ToString()); _ = user.UpdatedVariables.AddOrUpdate( variableId, diff --git a/Intersect.Server/Web/Controllers/Api/V1/VariableValueHelper.cs b/Intersect.Server/Web/Controllers/Api/V1/VariableValueHelper.cs new file mode 100644 index 0000000000..e5cef22a98 --- /dev/null +++ b/Intersect.Server/Web/Controllers/Api/V1/VariableValueHelper.cs @@ -0,0 +1,101 @@ +using System.Globalization; +using Intersect.Enums; +using Intersect.Framework.Core.GameObjects.Variables; + +namespace Intersect.Server.Web.Controllers.Api.V1; + +internal static class VariableValueHelper +{ + private const string InvalidValueErrorFormat = "Invalid value for variable of type {0}. Received: {1}"; + + public static bool Equals(VariableDataType dataType, VariableValue variableValue, object? value) + { + if (value == null) + { + return variableValue.Value == null; + } + + return dataType switch + { + VariableDataType.Boolean => value is bool booleanValue && variableValue.Boolean == booleanValue, + VariableDataType.Integer => value is long longValue && variableValue.Integer == longValue, + VariableDataType.Number => value is double doubleValue && variableValue.Number.Equals(doubleValue), + VariableDataType.String => value is string stringValue && string.Equals(variableValue.String ?? string.Empty, stringValue, StringComparison.Ordinal), + _ => Equals(variableValue.Value, value), + }; + } + + public static bool TryConvertValue( + VariableDataType dataType, + object? value, + out object convertedValue, + out string? error + ) + { + convertedValue = string.Empty; + error = null; + + if (value == null) + { + if (dataType == VariableDataType.String) + { + return true; + } + + error = FormatError(dataType, "null"); + return false; + } + + switch (dataType) + { + case VariableDataType.Boolean: + if (value is bool booleanValue) + { + convertedValue = booleanValue; + return true; + } + + error = FormatError(dataType, value?.GetType()?.Name ?? "null"); + return false; + + case VariableDataType.Integer: + if (long.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedInt)) + { + convertedValue = parsedInt; + return true; + } + + error = FormatError(dataType, value?.GetType()?.Name ?? "null"); + return false; + + case VariableDataType.Number: + if (double.TryParse(value.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedDouble)) + { + convertedValue = parsedDouble; + return true; + } + + error = FormatError(dataType, value?.GetType()?.Name ?? "null"); + return false; + + case VariableDataType.String: + if (value is string stringValue) + { + convertedValue = stringValue; + return true; + } + + error = FormatError(dataType, value?.GetType()?.Name ?? "null"); + return false; + + default: + error = FormatError(dataType, value?.GetType()?.Name ?? "null"); + return false; + } + } + + private static string FormatError(VariableDataType dataType, string received) + { + return string.Format(CultureInfo.InvariantCulture, InvalidValueErrorFormat, dataType, received); + } +} diff --git a/Intersect.Server/Web/Controllers/Api/V1/VariablesController.cs b/Intersect.Server/Web/Controllers/Api/V1/VariablesController.cs index c738938664..37b3bd36b5 100644 --- a/Intersect.Server/Web/Controllers/Api/V1/VariablesController.cs +++ b/Intersect.Server/Web/Controllers/Api/V1/VariablesController.cs @@ -102,16 +102,19 @@ public IActionResult ServerVariableSet(Guid variableId, [FromBody] VariableValue return NotFound($@"No server variable with id '{variableId}'."); } - var changed = false; - if (variable.Value != null && variable.Value.Value != variableValue.Value) + if (variable.Value == null) { - variable.Value.Value = variableValue.Value; - changed = true; + return InternalServerError("Variable value storage is missing."); } - // ReSharper disable once InvertIf - if (changed) + if (!VariableValueHelper.TryConvertValue(variable.DataType, variableValue.Value, out object convertedValue, out string error)) { + return BadRequest(error); + } + + if (!VariableValueHelper.Equals(variable.DataType, variable.Value, convertedValue)) + { + variable.Value.Value = convertedValue; Player.StartCommonEventsWithTriggerForAll( CommonEventTrigger.ServerVariableChange, "", @@ -123,4 +126,4 @@ public IActionResult ServerVariableSet(Guid variableId, [FromBody] VariableValue return Ok(variable); } -} \ No newline at end of file +}