Compare commits

..
3 changed files with 2 additions and 76 deletions

View file

@ -112,35 +112,4 @@ 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);
}
}

View file

@ -67,7 +67,6 @@ 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");
@ -141,7 +140,7 @@ public class RdvQueryApiController : Controller
existing.ActivityCode = query.ActivityCode;
existing.PerformerId = query.PerformerId;
existing.Consent = query.Consent;
existing.EventDate = EnsureUtc(query.EventDate);
existing.EventDate = query.EventDate;
existing.LocationType = query.LocationType;
existing.Reason = query.Reason;
existing.Status = query.Status;
@ -207,14 +206,4 @@ 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)
};
}
}

View file

@ -467,25 +467,8 @@ 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 };
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);
}
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_logger.LogInformation(3, "User created a new account with password.");
@ -534,21 +517,6 @@ 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()
{