first commit
This commit is contained in:
@@ -0,0 +1,407 @@
|
||||
using Fitness_core_BE.DTOs.Auth;
|
||||
using System.Text.Json;
|
||||
using Fitness_core_BE.Exceptions;
|
||||
|
||||
namespace Fitness_core_BE.Helpers
|
||||
{
|
||||
public class DataExtractor
|
||||
{
|
||||
public static string GetRequiredString(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new BadRequestException($"Missing required field '{key}'.");
|
||||
|
||||
if (element.ValueKind != JsonValueKind.String)
|
||||
throw new BadRequestException($"Field '{key}' must be a string.");
|
||||
|
||||
var value = element.GetString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return "";
|
||||
//throw new BadRequestException($"Field '{key}' cannot be empty.");
|
||||
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string? GetOptionalString(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
var value = element.GetString();
|
||||
return string.IsNullOrWhiteSpace(value) ? null : value;
|
||||
}
|
||||
|
||||
if (element.ValueKind == JsonValueKind.Number)
|
||||
return element.GetRawText();
|
||||
|
||||
throw new ArgumentException($"Field '{key}' must be a string.");
|
||||
}
|
||||
|
||||
public static string? GetOptionalStringByKeys(
|
||||
Dictionary<string, JsonElement> data,
|
||||
params string[] keys)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (data.ContainsKey(key))
|
||||
return GetOptionalString(data, key);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetRequiredStringByKeys(
|
||||
Dictionary<string, JsonElement> data,
|
||||
params string[] keys)
|
||||
{
|
||||
var value = GetOptionalStringByKeys(data, keys);
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
return value;
|
||||
|
||||
throw new BadRequestException($"Missing required field '{keys[0]}'.");
|
||||
}
|
||||
|
||||
// ===================== INT =====================
|
||||
|
||||
public static int GetRequiredInt(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new BadRequestException($"Missing required field '{key}'.");
|
||||
|
||||
if (element.TryGetInt32(out var value))
|
||||
return value;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
int.TryParse(element.GetString(), out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid integer.");
|
||||
}
|
||||
|
||||
public static int? GetNullableInt(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.TryGetInt32(out var value))
|
||||
return value;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
int.TryParse(element.GetString(), out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid integer.");
|
||||
}
|
||||
|
||||
// ===================== FLOAT =====================
|
||||
|
||||
public static float GetRequiredFloat(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new BadRequestException($"Missing required field '{key}'.");
|
||||
|
||||
if (element.TryGetSingle(out var value))
|
||||
return value;
|
||||
|
||||
// Allow numeric strings: "12.5"
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
float.TryParse(element.GetString(), out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid float.");
|
||||
}
|
||||
|
||||
// ===================== DECIMAL =====================
|
||||
public static decimal GetRequiredDecimal(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new ArgumentException($"Missing required field '{key}'.");
|
||||
if (element.TryGetDecimal(out var value))
|
||||
return value;
|
||||
// Allow numeric strings: "12.5"
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
decimal.TryParse(element.GetString(), out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
throw new ArgumentException($"Field '{key}' must be a valid decimal.");
|
||||
}
|
||||
|
||||
public static decimal? GetOptionalDecimal(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.TryGetDecimal(out var value))
|
||||
return value;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
decimal.TryParse(element.GetString(), out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Field '{key}' must be a valid decimal.");
|
||||
}
|
||||
|
||||
public static decimal? GetOptionalDecimalByKeys(
|
||||
Dictionary<string, JsonElement> data,
|
||||
params string[] keys)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (data.ContainsKey(key))
|
||||
return GetOptionalDecimal(data, key);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ===================== BOOLEAN =====================
|
||||
|
||||
public static bool GetRequiredBool(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new BadRequestException($"Missing required field '{key}'.");
|
||||
|
||||
if (element.ValueKind == JsonValueKind.True) return true;
|
||||
if (element.ValueKind == JsonValueKind.False) return false;
|
||||
|
||||
// Allow string values: "true" / "false"
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
bool.TryParse(element.GetString(), out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid boolean.");
|
||||
}
|
||||
|
||||
public static bool? GetOptionalBool(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.True) return true;
|
||||
if (element.ValueKind == JsonValueKind.False) return false;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
bool.TryParse(element.GetString(), out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid boolean.");
|
||||
}
|
||||
|
||||
// ===================== GUID =====================
|
||||
|
||||
public static Guid GetRequiredGuid(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
var value = GetRequiredString(data, key);
|
||||
|
||||
if (!Guid.TryParse(value, out var guid))
|
||||
throw new BadRequestException($"Field '{key}' must be a valid GUID.");
|
||||
|
||||
return guid;
|
||||
}
|
||||
|
||||
/// <summary>A JSON array of GUID strings, or null if the key is absent/null. An
|
||||
/// empty array is returned as an empty list (distinct from "field not sent"),
|
||||
/// which matters for "clear this plan's places" updates.</summary>
|
||||
public static List<Guid>? GetOptionalGuidList(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.ValueKind != JsonValueKind.Array)
|
||||
throw new BadRequestException($"Field '{key}' must be an array.");
|
||||
|
||||
var result = new List<Guid>();
|
||||
foreach (var item in element.EnumerateArray())
|
||||
{
|
||||
if (item.ValueKind != JsonValueKind.String || !Guid.TryParse(item.GetString(), out var guid))
|
||||
throw new BadRequestException($"Field '{key}' must contain only GUID strings.");
|
||||
result.Add(guid);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================== DATETIME =====================
|
||||
|
||||
public static DateTime GetRequiredDateTime(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new BadRequestException($"Missing required field '{key}'.");
|
||||
|
||||
if (element.ValueKind == JsonValueKind.Null)
|
||||
throw new BadRequestException($"Field '{key}' cannot be null.");
|
||||
|
||||
// ISO 8601 string
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
DateTime.TryParse(element.GetString(), out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
// Native JSON DateTime
|
||||
if (element.TryGetDateTime(out date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid DateTime.");
|
||||
}
|
||||
|
||||
public static DateTime? GetOptionalDateTime(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
DateTime.TryParse(element.GetString(), out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
if (element.TryGetDateTime(out date))
|
||||
return date;
|
||||
|
||||
throw new ArgumentException($"Field '{key}' must be a valid DateTime.");
|
||||
}
|
||||
|
||||
// ===================== DATEONLY =====================
|
||||
|
||||
public static DateOnly GetRequiredDateOnly(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element))
|
||||
throw new BadRequestException($"Missing required field '{key}'.");
|
||||
|
||||
if (element.ValueKind == JsonValueKind.Null)
|
||||
throw new BadRequestException($"Field '{key}' cannot be null.");
|
||||
|
||||
DateTime date;
|
||||
|
||||
// ISO 8601 string (e.g., "2025-02-25")
|
||||
if (element.ValueKind == JsonValueKind.String &&
|
||||
DateTime.TryParse(element.GetString(), out date))
|
||||
{
|
||||
return DateOnly.FromDateTime(date);
|
||||
}
|
||||
|
||||
|
||||
if (element.TryGetDateTime(out date))
|
||||
{
|
||||
return DateOnly.FromDateTime(date);
|
||||
}
|
||||
|
||||
throw new BadRequestException($"Field '{key}' must be a valid date.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A date of birth, rejected if it is today or in the future. Progress predictions
|
||||
/// divide by the member's age, so a zero age has to be stopped at the write rather
|
||||
/// than surfacing later as a failure in an unrelated screen.
|
||||
/// </summary>
|
||||
public static DateOnly GetRequiredDateOfBirth(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
var birthDate = GetRequiredDateOnly(data, key);
|
||||
|
||||
if (birthDate >= DateOnly.FromDateTime(DateTime.UtcNow))
|
||||
throw new BadRequestException(
|
||||
$"Field '{key}' must be a date in the past.");
|
||||
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as GetRequiredDateOfBirth, but missing/null/blank is allowed and returns null
|
||||
/// instead of throwing -- a birthday isn't needed to run a subscription, so gyms that
|
||||
/// don't collect it at signup shouldn't be blocked from adding a member.
|
||||
/// </summary>
|
||||
public static DateOnly? GetOptionalDateOfBirth(
|
||||
Dictionary<string, JsonElement> data,
|
||||
string key)
|
||||
{
|
||||
if (!data.TryGetValue(key, out var element) || element.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
|
||||
if (element.ValueKind == JsonValueKind.String && string.IsNullOrWhiteSpace(element.GetString()))
|
||||
return null;
|
||||
|
||||
return GetRequiredDateOfBirth(data, key);
|
||||
}
|
||||
|
||||
// ===================== USER ID FROM HttpContext =====================
|
||||
public static Guid GetUserIdFromContext(HttpContext httpContext)
|
||||
{
|
||||
|
||||
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
|
||||
|
||||
var userIdFromContext = httpContext.Items["UserId"]?.ToString()
|
||||
?? httpContext.User?.FindFirst("UserId")?.Value;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(userIdFromContext) || !Guid.TryParse(userIdFromContext, out var userId))
|
||||
{
|
||||
throw new UnauthorizedAccessException("User is not authenticated. Please login and send cookie.");
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
//============================AuthResponce EXtractor============
|
||||
public static AuthResponse GetRequiredAuthResponse(Dictionary<string, JsonElement> data)
|
||||
{
|
||||
AuthResponse authResponse = new AuthResponse
|
||||
{
|
||||
StatusCode = GetRequiredInt(data, "StatusCode"),
|
||||
Success = GetRequiredBool(data, "success"),
|
||||
Message = GetRequiredString(data, "message"),
|
||||
Data = data
|
||||
};
|
||||
|
||||
return authResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user