mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 15:23:12 +00:00
Copy contacts into MapInfo so slide-over round-trips create/PATCH, and require name plus phone on retained entries while dropping blank placeholders.
127 lines
4.4 KiB
C#
127 lines
4.4 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using SeaHaven.Services.DTOs;
|
|
using SeaHaven.Services.Exceptions;
|
|
|
|
namespace SeaHaven.Services.Helpers
|
|
{
|
|
public static class WorkOrderAdditionalContactsMapper
|
|
{
|
|
private const int MaxNameLength = 200;
|
|
private const int MaxPhoneLength = 50;
|
|
private const int MaxNotesLength = 2000;
|
|
private const int MaxSerializedLength = 4000;
|
|
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
PropertyNameCaseInsensitive = true,
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
};
|
|
|
|
public static List<WorkOrderAdditionalContactDto>? ParseJson(string? json)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
return null;
|
|
|
|
try
|
|
{
|
|
var parsed = JsonSerializer.Deserialize<List<WorkOrderAdditionalContactDto>>(json, JsonOptions);
|
|
return parsed is { Count: > 0 } ? parsed : null;
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static string? SerializeForStorage(IReadOnlyList<WorkOrderAdditionalContactDto>? contacts)
|
|
{
|
|
var normalized = NormalizeList(contacts);
|
|
if (normalized.Count == 0)
|
|
return null;
|
|
|
|
var json = JsonSerializer.Serialize(normalized, JsonOptions);
|
|
if (json.Length > MaxSerializedLength)
|
|
{
|
|
throw new WorkOrderBoardValidationException(
|
|
"InvalidValue",
|
|
"additionalContacts must serialize to at most 4000 characters.");
|
|
}
|
|
|
|
return json;
|
|
}
|
|
|
|
public static string? SerializeForPatch(string? jsonValue)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(jsonValue))
|
|
return null;
|
|
|
|
List<WorkOrderAdditionalContactDto>? parsed;
|
|
try
|
|
{
|
|
parsed = JsonSerializer.Deserialize<List<WorkOrderAdditionalContactDto>>(jsonValue.Trim(), JsonOptions);
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
throw new WorkOrderBoardValidationException(
|
|
"InvalidValue",
|
|
"additionalContacts must be a JSON array of { name, phone, notes? }.");
|
|
}
|
|
|
|
return SerializeForStorage(parsed);
|
|
}
|
|
|
|
public static List<WorkOrderAdditionalContactDto> NormalizeList(IReadOnlyList<WorkOrderAdditionalContactDto>? contacts)
|
|
{
|
|
var normalized = new List<WorkOrderAdditionalContactDto>();
|
|
if (contacts == null || contacts.Count == 0)
|
|
return normalized;
|
|
|
|
foreach (var raw in contacts)
|
|
{
|
|
var name = raw.Name?.Trim() ?? "";
|
|
var phone = raw.Phone?.Trim() ?? "";
|
|
var notes = raw.Notes?.Trim();
|
|
|
|
if (string.IsNullOrEmpty(name) && string.IsNullOrEmpty(phone))
|
|
continue;
|
|
|
|
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(phone))
|
|
{
|
|
throw new WorkOrderBoardValidationException(
|
|
"InvalidValue",
|
|
"Each additional contact must include a name and phone.");
|
|
}
|
|
|
|
if (name.Length > MaxNameLength)
|
|
{
|
|
throw new WorkOrderBoardValidationException(
|
|
"InvalidValue",
|
|
"Each additional contact name must be at most 200 characters.");
|
|
}
|
|
|
|
if (phone.Length > MaxPhoneLength)
|
|
{
|
|
throw new WorkOrderBoardValidationException(
|
|
"InvalidValue",
|
|
"Each additional contact phone must be at most 50 characters.");
|
|
}
|
|
|
|
if (notes != null && notes.Length > MaxNotesLength)
|
|
{
|
|
throw new WorkOrderBoardValidationException(
|
|
"InvalidValue",
|
|
"Each additional contact notes must be at most 2000 characters.");
|
|
}
|
|
|
|
normalized.Add(new WorkOrderAdditionalContactDto(
|
|
name,
|
|
phone,
|
|
string.IsNullOrEmpty(notes) ? null : notes));
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
}
|
|
}
|