Initial import into Gitea
This commit is contained in:
186
Registration/Mock/MockDataService.cs
Normal file
186
Registration/Mock/MockDataService.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using Registration.Data;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Registration.Mock;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory mock registration data for development.
|
||||
/// Persists across requests within a single Function host lifecycle.
|
||||
/// State resets on cold start (by design — it's mock data).
|
||||
///
|
||||
/// Swap to SqlDataService in Program.cs when dbRegistration is ready.
|
||||
/// </summary>
|
||||
public class MockDataService : IRegistrationDataService
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Applicant> _store;
|
||||
private readonly ILogger<MockDataService> _log;
|
||||
|
||||
public MockDataService(ILogger<MockDataService> log)
|
||||
{
|
||||
_log = log;
|
||||
_store = new ConcurrentDictionary<string, Applicant>(SeedData());
|
||||
_log.LogInformation("[Mock] Initialized with {Count} applicants", _store.Count);
|
||||
}
|
||||
|
||||
public Task<RegistrationListResult> GetPendingAsync(CancellationToken ct)
|
||||
{
|
||||
var pending = _store.Values
|
||||
.Where(a => a.Status == "Pending")
|
||||
.OrderBy(a => a.RegisteredUtc)
|
||||
.ToList();
|
||||
|
||||
return Task.FromResult(new RegistrationListResult
|
||||
{
|
||||
Ok = true,
|
||||
Applicants = pending,
|
||||
TotalCount = pending.Count
|
||||
});
|
||||
}
|
||||
|
||||
public Task<Applicant?> GetByIdAsync(string registrationId, CancellationToken ct)
|
||||
{
|
||||
_store.TryGetValue(registrationId, out var applicant);
|
||||
return Task.FromResult(applicant);
|
||||
}
|
||||
|
||||
public Task<RegistrationResult> RegisterAsync(RegisterRequest request, CancellationToken ct)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.BusinessName))
|
||||
return Task.FromResult(new RegistrationResult { Ok = false, Error = "Business name is required" });
|
||||
|
||||
// Check for duplicate business name
|
||||
if (_store.Values.Any(a => string.Equals(a.BusinessName, request.BusinessName, StringComparison.OrdinalIgnoreCase)
|
||||
&& a.Status != "Rejected"))
|
||||
return Task.FromResult(new RegistrationResult { Ok = false, Error = "A registration with this name already exists" });
|
||||
|
||||
var id = Guid.NewGuid().ToString("D");
|
||||
var applicant = new Applicant
|
||||
{
|
||||
RegistrationId = id,
|
||||
BusinessName = request.BusinessName!.Trim(),
|
||||
WebsiteUrl = request.WebsiteUrl,
|
||||
BusinessCategory = request.BusinessCategory,
|
||||
BusinessDescription = request.BusinessDescription,
|
||||
ContactName = request.ContactName,
|
||||
ContactEmail = request.ContactEmail,
|
||||
ContactPhone = request.ContactPhone,
|
||||
EntraSubjectId = request.EntraSubjectId,
|
||||
Status = "Pending",
|
||||
PaymentVerified = false,
|
||||
RegisteredUtc = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_store[id] = applicant;
|
||||
_log.LogInformation("[Mock] New registration: {Name} ({Id})", applicant.BusinessName, id);
|
||||
|
||||
return Task.FromResult(new RegistrationResult { Ok = true, RegistrationId = id });
|
||||
}
|
||||
|
||||
public Task<RegistrationResult> RejectAsync(string registrationId, string? reason, string? rejectedBy, CancellationToken ct)
|
||||
{
|
||||
if (!_store.TryGetValue(registrationId, out var applicant))
|
||||
return Task.FromResult(new RegistrationResult { Ok = false, Error = "Registration not found" });
|
||||
|
||||
if (applicant.Status != "Pending")
|
||||
return Task.FromResult(new RegistrationResult { Ok = false, Error = $"Cannot reject — status is {applicant.Status}" });
|
||||
|
||||
applicant.Status = "Rejected";
|
||||
applicant.RejectionReason = reason;
|
||||
applicant.ReviewedBy = rejectedBy;
|
||||
applicant.ReviewedUtc = DateTime.UtcNow;
|
||||
|
||||
_log.LogInformation("[Mock] Rejected: {Name} ({Id}) reason={Reason}", applicant.BusinessName, registrationId, reason);
|
||||
|
||||
return Task.FromResult(new RegistrationResult { Ok = true, RegistrationId = registrationId });
|
||||
}
|
||||
|
||||
public Task<RegistrationResult> CompleteAsync(string registrationId, string? platformClientId, CancellationToken ct)
|
||||
{
|
||||
if (!_store.TryGetValue(registrationId, out var applicant))
|
||||
return Task.FromResult(new RegistrationResult { Ok = false, Error = "Registration not found" });
|
||||
|
||||
if (applicant.Status != "Pending")
|
||||
return Task.FromResult(new RegistrationResult { Ok = false, Error = $"Cannot complete — status is {applicant.Status}" });
|
||||
|
||||
applicant.Status = "Approved";
|
||||
applicant.PlatformClientId = platformClientId;
|
||||
applicant.ReviewedUtc = DateTime.UtcNow;
|
||||
|
||||
_log.LogInformation("[Mock] Approved: {Name} ({Id}) → platform client {PlatformId}",
|
||||
applicant.BusinessName, registrationId, platformClientId);
|
||||
|
||||
return Task.FromResult(new RegistrationResult { Ok = true, RegistrationId = registrationId });
|
||||
}
|
||||
|
||||
// ── Seed Data ───────────────────────────────────
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, Applicant>> SeedData()
|
||||
{
|
||||
var applicants = new[]
|
||||
{
|
||||
new Applicant
|
||||
{
|
||||
RegistrationId = "reg-001",
|
||||
BusinessName = "Bella's Boutique",
|
||||
WebsiteUrl = "https://bellasboutique.com",
|
||||
BusinessCategory = "retail",
|
||||
BusinessDescription = "Women's fashion and accessories boutique in Orange County. Looking to expand online presence through targeted social and search ads.",
|
||||
ContactName = "Bella Rodriguez",
|
||||
ContactEmail = "bella@bellasboutique.com",
|
||||
ContactPhone = "(714) 555-0142",
|
||||
EntraSubjectId = "entra-mock-bella-001",
|
||||
Status = "Pending",
|
||||
PaymentVerified = true,
|
||||
RegisteredUtc = DateTime.UtcNow.AddDays(-3)
|
||||
},
|
||||
new Applicant
|
||||
{
|
||||
RegistrationId = "reg-002",
|
||||
BusinessName = "Pacific Coast Plumbing",
|
||||
WebsiteUrl = "https://pacificcoastplumbing.com",
|
||||
BusinessCategory = "home_services",
|
||||
BusinessDescription = "Full-service plumbing company serving LA and OC. Need help with Google Local Services ads and Maps visibility.",
|
||||
ContactName = "Mike Chen",
|
||||
ContactEmail = "mike@pcplumbing.com",
|
||||
ContactPhone = "(562) 555-0198",
|
||||
EntraSubjectId = "entra-mock-mike-002",
|
||||
Status = "Pending",
|
||||
PaymentVerified = true,
|
||||
RegisteredUtc = DateTime.UtcNow.AddDays(-1)
|
||||
},
|
||||
new Applicant
|
||||
{
|
||||
RegistrationId = "reg-003",
|
||||
BusinessName = "Sunrise Dental Group",
|
||||
WebsiteUrl = "https://sunrisedental.care",
|
||||
BusinessCategory = "healthcare",
|
||||
BusinessDescription = "Multi-location dental practice. Interested in running awareness campaigns for new patient acquisition across Google and Meta.",
|
||||
ContactName = "Dr. Sarah Kim",
|
||||
ContactEmail = "sarah@sunrisedental.care",
|
||||
ContactPhone = "(949) 555-0267",
|
||||
EntraSubjectId = "entra-mock-sarah-003",
|
||||
Status = "Pending",
|
||||
PaymentVerified = false,
|
||||
RegisteredUtc = DateTime.UtcNow.AddHours(-6)
|
||||
},
|
||||
new Applicant
|
||||
{
|
||||
RegistrationId = "reg-004",
|
||||
BusinessName = "FreshBite Meal Prep",
|
||||
WebsiteUrl = "https://freshbitemealprep.com",
|
||||
BusinessCategory = "food_beverage",
|
||||
BusinessDescription = "Healthy meal prep delivery service. $2k/month budget for Instagram and TikTok ads targeting health-conscious millennials.",
|
||||
ContactName = "Jordan Williams",
|
||||
ContactEmail = "jordan@freshbitemealprep.com",
|
||||
ContactPhone = "(310) 555-0334",
|
||||
EntraSubjectId = "entra-mock-jordan-004",
|
||||
Status = "Pending",
|
||||
PaymentVerified = true,
|
||||
RegisteredUtc = DateTime.UtcNow.AddHours(-2)
|
||||
},
|
||||
};
|
||||
|
||||
return applicants.Select(a => new KeyValuePair<string, Applicant>(a.RegistrationId, a));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user