Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
c2574ac1d4 |
|||
|
dcd6ad3592 |
3 changed files with 76 additions and 2 deletions
|
|
@ -112,4 +112,35 @@ public sealed class RdvQueryApiControllerTests : IClassFixture<ApiWebServerFixtu
|
|||
Assert.NotNull(created);
|
||||
Assert.Equal("alice", created!.ClientId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostQuery_accepts_local_datetime_and_persists_as_utc()
|
||||
{
|
||||
_fixture.ResetAndSeedRdvQueryGraph();
|
||||
using var http = NewClient(subject: "alice");
|
||||
|
||||
var localEventDate = DateTime.Now.AddDays(2);
|
||||
var createPayload = new
|
||||
{
|
||||
ActivityCode = "dev",
|
||||
PerformerId = "alice",
|
||||
Consent = true,
|
||||
EventDate = localEventDate,
|
||||
Location = new
|
||||
{
|
||||
Address = "3 rue du Test",
|
||||
Latitude = 48.8568,
|
||||
Longitude = 2.3524,
|
||||
},
|
||||
Reason = "Rendez-vous date locale",
|
||||
Status = QueryStatus.Inserted,
|
||||
};
|
||||
|
||||
var createResponse = await http.PostAsJsonAsync("/api/v1/billing/Rdv", createPayload, TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode);
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<RdvQuery>(TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(created);
|
||||
Assert.Equal(DateTimeKind.Utc, created!.EventDate.Kind);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public class RdvQueryApiController : Controller
|
|||
var uid = User.GetUserId();
|
||||
// Security: the caller always posts for themselves.
|
||||
query.ClientId = uid;
|
||||
query.EventDate = EnsureUtc(query.EventDate);
|
||||
|
||||
ModelState.Remove("Client");
|
||||
ModelState.Remove("ClientId");
|
||||
|
|
@ -140,7 +141,7 @@ public class RdvQueryApiController : Controller
|
|||
existing.ActivityCode = query.ActivityCode;
|
||||
existing.PerformerId = query.PerformerId;
|
||||
existing.Consent = query.Consent;
|
||||
existing.EventDate = query.EventDate;
|
||||
existing.EventDate = EnsureUtc(query.EventDate);
|
||||
existing.LocationType = query.LocationType;
|
||||
existing.Reason = query.Reason;
|
||||
existing.Status = query.Status;
|
||||
|
|
@ -206,4 +207,14 @@ public class RdvQueryApiController : Controller
|
|||
{
|
||||
return _context.RdvQueries.Any(e => e.Id == id);
|
||||
}
|
||||
|
||||
private static DateTime EnsureUtc(DateTime value)
|
||||
{
|
||||
return value.Kind switch
|
||||
{
|
||||
DateTimeKind.Utc => value,
|
||||
DateTimeKind.Local => value.ToUniversalTime(),
|
||||
_ => DateTime.SpecifyKind(value, DateTimeKind.Utc)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -467,8 +467,25 @@ IHtmlLocalizerFactory htmlLocalizerFactory,
|
|||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var existingUser = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (existingUser is not null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(model.Email), _localizer["DuplicateEmail"]);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
IdentityResult result;
|
||||
try
|
||||
{
|
||||
result = await _userManager.CreateAsync(user, model.Password);
|
||||
}
|
||||
catch (DbUpdateException ex) when (IsDuplicateEmailViolation(ex))
|
||||
{
|
||||
_logger.LogWarning(ex, "Registration rejected: duplicate email '{Email}'.", model.Email);
|
||||
ModelState.AddModelError(nameof(model.Email), _localizer["DuplicateEmail"]);
|
||||
return View(model);
|
||||
}
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation(3, "User created a new account with password.");
|
||||
|
|
@ -517,6 +534,21 @@ IHtmlLocalizerFactory htmlLocalizerFactory,
|
|||
return View(model);
|
||||
}
|
||||
|
||||
private static bool IsDuplicateEmailViolation(Exception exception)
|
||||
{
|
||||
for (var current = exception; current is not null; current = current.InnerException)
|
||||
{
|
||||
if (current is PostgresException pg
|
||||
&& pg.SqlState == PostgresErrorCodes.UniqueViolation
|
||||
&& string.Equals(pg.ConstraintName, "AK_AspNetUsers_Email", StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Authorize, HttpPost, ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SendConfirationEmail()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue