Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

158 строки
5.4KB

  1. using System.Collections.Concurrent;
  2. namespace Campaign_Tracker.Server.Municipalities;
  3. public sealed class InMemoryMunicipalityContactRepository : IMunicipalityContactRepository
  4. {
  5. private static readonly Dictionary<string, int> ContactTypeSortOrder =
  6. new(StringComparer.OrdinalIgnoreCase)
  7. {
  8. ["Primary"] = 0,
  9. ["Secondary"] = 1,
  10. };
  11. private readonly ConcurrentDictionary<string, MunicipalityContact> _contacts =
  12. new(StringComparer.OrdinalIgnoreCase);
  13. private readonly object _lock = new();
  14. private readonly TimeProvider _timeProvider;
  15. public InMemoryMunicipalityContactRepository(TimeProvider timeProvider)
  16. {
  17. _timeProvider = timeProvider;
  18. }
  19. public Task<IReadOnlyList<MunicipalityContact>> GetByProfileIdAsync(
  20. string profileId,
  21. CancellationToken cancellationToken = default)
  22. {
  23. var result = _contacts.Values
  24. .Where(c => c.ProfileId == profileId && !c.IsDeleted)
  25. .OrderBy(c => ContactTypeSortOrder.GetValueOrDefault(c.ContactType, 99))
  26. .ThenBy(c => c.Name, StringComparer.OrdinalIgnoreCase)
  27. .ToArray();
  28. return Task.FromResult<IReadOnlyList<MunicipalityContact>>(result);
  29. }
  30. public Task<MunicipalityContact?> GetByIdAsync(
  31. string contactId,
  32. CancellationToken cancellationToken = default)
  33. {
  34. _contacts.TryGetValue(contactId, out var contact);
  35. return Task.FromResult(contact is { IsDeleted: false } ? contact : null);
  36. }
  37. public Task<MunicipalityContactSaveResult> AddAsync(
  38. string profileId,
  39. string contactType,
  40. string name,
  41. string? roleTitle,
  42. string? phone,
  43. string? email,
  44. string actorIdentity,
  45. CancellationToken cancellationToken = default)
  46. {
  47. var validation = Validate(contactType, name);
  48. if (validation is not null)
  49. return Task.FromResult(MunicipalityContactSaveResult.Failure(validation));
  50. var now = _timeProvider.GetUtcNow();
  51. var contact = new MunicipalityContact(
  52. ContactId: Guid.NewGuid().ToString("N"),
  53. ProfileId: profileId,
  54. ContactType: NormalizeContactType(contactType),
  55. Name: name.Trim(),
  56. RoleTitle: NormalizeOptional(roleTitle),
  57. Phone: NormalizeOptional(phone),
  58. Email: NormalizeOptional(email),
  59. IsDeleted: false,
  60. CreatedAt: now,
  61. CreatedBy: actorIdentity,
  62. UpdatedAt: now,
  63. UpdatedBy: actorIdentity);
  64. _contacts[contact.ContactId] = contact;
  65. return Task.FromResult(MunicipalityContactSaveResult.Success(contact));
  66. }
  67. public Task<MunicipalityContactSaveResult> UpdateAsync(
  68. string contactId,
  69. string contactType,
  70. string name,
  71. string? roleTitle,
  72. string? phone,
  73. string? email,
  74. string actorIdentity,
  75. CancellationToken cancellationToken = default)
  76. {
  77. var validation = Validate(contactType, name);
  78. if (validation is not null)
  79. return Task.FromResult(MunicipalityContactSaveResult.Failure(validation));
  80. var now = _timeProvider.GetUtcNow();
  81. lock (_lock)
  82. {
  83. if (!_contacts.TryGetValue(contactId, out var existing) || existing.IsDeleted)
  84. return Task.FromResult(MunicipalityContactSaveResult.NotFound(contactId));
  85. var updated = existing with
  86. {
  87. ContactType = NormalizeContactType(contactType),
  88. Name = name.Trim(),
  89. RoleTitle = NormalizeOptional(roleTitle),
  90. Phone = NormalizeOptional(phone),
  91. Email = NormalizeOptional(email),
  92. UpdatedAt = now,
  93. UpdatedBy = actorIdentity,
  94. };
  95. _contacts[contactId] = updated;
  96. return Task.FromResult(MunicipalityContactSaveResult.Success(updated));
  97. }
  98. }
  99. public Task<MunicipalityContactSaveResult> SoftDeleteAsync(
  100. string contactId,
  101. string actorIdentity,
  102. CancellationToken cancellationToken = default)
  103. {
  104. var now = _timeProvider.GetUtcNow();
  105. lock (_lock)
  106. {
  107. if (!_contacts.TryGetValue(contactId, out var existing) || existing.IsDeleted)
  108. return Task.FromResult(MunicipalityContactSaveResult.NotFound(contactId));
  109. var deleted = existing with
  110. {
  111. IsDeleted = true,
  112. UpdatedAt = now,
  113. UpdatedBy = actorIdentity,
  114. };
  115. _contacts[contactId] = deleted;
  116. return Task.FromResult(MunicipalityContactSaveResult.Success(deleted));
  117. }
  118. }
  119. private static string? Validate(string contactType, string name)
  120. {
  121. if (string.IsNullOrWhiteSpace(name))
  122. return "Name is required.";
  123. if (string.IsNullOrWhiteSpace(contactType))
  124. return "Contact type is required.";
  125. if (!ContactTypeSortOrder.ContainsKey(contactType.Trim()))
  126. return "Contact type must be Primary or Secondary.";
  127. return null;
  128. }
  129. private static string NormalizeContactType(string contactType) =>
  130. string.Equals(contactType.Trim(), "Primary", StringComparison.OrdinalIgnoreCase)
  131. ? "Primary"
  132. : "Secondary";
  133. private static string? NormalizeOptional(string? value) =>
  134. string.IsNullOrWhiteSpace(value) ? null : value.Trim();
  135. }

Powered by TurnKey Linux.