Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Threading.Tasks;
using Microting.eFormApi.BasePn.Abstractions;
using Microting.eFormApi.BasePn.Infrastructure.Database.Entities;
using Microting.eFormApi.BasePn.Infrastructure.Models.API;
using NSubstitute;
using NUnit.Framework;
using TimePlanning.Pn.Services.TimePlanningLocalizationService;

namespace TimePlanning.Pn.Test;

/// <summary>
/// Asserts the defensive null-guard added to *ByCurrentUser methods in
/// TimePlanningWorkingHoursService. The guard returns a clean failure
/// result when <c>userService.GetCurrentUserAsync()</c> returns null,
/// instead of NRE'ing the EF Core LINQ funcletizer on
/// <c>currentUserAsync.Id</c>.
///
/// This test is <see cref="IgnoreAttribute"/>'d because instantiating the
/// real <c>TimePlanningWorkingHoursService</c> requires the full
/// constructor dependency graph (BaseDbContext, TimePlanningPnDbContext,
/// IEFormCoreService, etc.) that the existing test harness doesn't seed.
/// The same carve-out is used by <see cref="AbsenceRequestServiceTests"/>.
/// The shape below documents the expected contract; whoever fleshes out
/// the harness in a follow-up can un-ignore.
/// </summary>
[TestFixture]
[Ignore("Test fixture infrastructure for full TimePlanningWorkingHoursService instantiation pending — see file header.")]
public class TimePlanningWorkingHoursServiceNullUserTests
{
[Test]
public async Task ReadFullByCurrentUser_NullCurrentUser_ReturnsUserNotFound()
{
var userService = Substitute.For<IUserService>();
userService.GetCurrentUserAsync().Returns(Task.FromResult<EformUser>(null!));
var localizationService = Substitute.For<ITimePlanningLocalizationService>();
localizationService.GetString("UserNotFound").Returns("User not found.");

// Arrange the rest of the constructor graph here once the test
// harness can supply the dependencies.

// Expected:
// var result = await sut.ReadFullByCurrentUser(DateTime.Today, null, null, null, null);
// Assert.That(result.Success, Is.False);
// Assert.That(result.Message, Is.EqualTo("User not found."));
// And no exception bubbled.

await Task.CompletedTask;
Assert.Pass("Shape-asserting placeholder. Un-ignore once the service harness is in place.");
}
}
Comment on lines +1 to +51
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@
<data name="ShiftOverlapsExistingShift" xml:space="preserve">
<value>Den overdragne vagt overlapper en eksisterende vagt i kollegaens planlægning.</value>
</data>
<data name="HandoverSourceSlotEmpty" xml:space="preserve">
<value>Den oprindelige vagt er tom — der er intet at overdrage.</value>
</data>
<data name="CannotEditLockedPreset" xml:space="preserve">
<value>Kan ikke redigere – denne overenskomst er en låst skabelon og er skrivebeskyttet</value>
</data>
<data name="UserNotFound" xml:space="preserve">
<value>Bruger ikke fundet.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@
<data name="ShiftOverlapsExistingShift" xml:space="preserve">
<value>The transferred shift overlaps an existing shift on the coworker's planning.</value>
</data>
<data name="HandoverSourceSlotEmpty" xml:space="preserve">
<value>The source shift slot is empty — there is nothing to hand over.</value>
</data>
<data name="CannotEditLockedPreset" xml:space="preserve">
<value>Cannot edit - this overenskomst is a locked preset and is read-only</value>
</data>
<data name="UserNotFound" xml:space="preserve">
<value>User not found.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ public AbsenceRequestService(
private async Task<int> ResolveCallerSdkSiteIdAsync()
{
var currentUserAsync = await _userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return 0;
}
var currentUser = _baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ await dbContext.AssignedSites
.ToListAsync().ConfigureAwait(false);

var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return new OperationDataResult<List<TimePlanningPlanningModel>>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Include(x => x.UserRoles)
.ThenInclude(x => x.Role)
Expand Down Expand Up @@ -399,6 +404,11 @@ public async Task<OperationDataResult<TimePlanningPlanningModel>> IndexByCurrent
var sdkCore = await core.GetCore();
var sdkDbContext = sdkCore.DbContextHelper.GetDbContext();
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return new OperationDataResult<TimePlanningPlanningModel>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,11 @@ public async Task<OperationDataResult<List<Site>>> GetAvailableSitesByCurrentUse
if (baseDbContext != null)
{
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return new OperationDataResult<List<Site>>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Include(x => x.UserRoles)
.ThenInclude(x => x.Role)
Expand Down Expand Up @@ -673,6 +678,11 @@ planRegistrationForToday is
var core1 = await core.GetCore();
var sdkContext = core1.DbContextHelper.GetDbContext();
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return new OperationDataResult<Infrastructure.Models.Settings.AssignedSite>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);
var worker = await sdkContext.Workers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,11 @@ private async Task UpdatePlanning(bool first, PlanRegistration planRegistration,
public async Task<OperationDataResult<TimePlanningWorkingHourSimpleModel>> ReadSimple(DateTime dateTime, string? softwareVersion, string? model, string? manufacturer, string? osVersion)
{
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return new OperationDataResult<TimePlanningWorkingHourSimpleModel>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);
var userEmail = (currentUser.Email ?? "").Trim().ToLower();
Expand Down Expand Up @@ -737,6 +742,11 @@ public async Task<OperationDataResult<TimePlanningHoursSummaryModel>> CalculateH
var core = await coreHelper.GetCore();
var sdkContext = core.DbContextHelper.GetDbContext();
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
return new OperationDataResult<TimePlanningHoursSummaryModel>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);
var userEmail = (currentUser.Email ?? "").Trim().ToLower();
Expand Down Expand Up @@ -858,6 +868,12 @@ public async Task<OperationDataResult<TimePlanningWorkingHoursModel>> ReadFullBy
{
Console.WriteLine($"[DEBUG-GRPC-READ] ReadFullByCurrentUser called: dateTime={dateTime:yyyy-MM-dd}");
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
Console.WriteLine($"[DEBUG-GRPC-READ] EARLY RETURN: GetCurrentUserAsync returned null (JWT missing or invalid)");
return new OperationDataResult<TimePlanningWorkingHoursModel>(false,
localizationService.GetString("UserNotFound"), null!);
}
var currentUser = baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);
Console.WriteLine($"[DEBUG-GRPC-READ] Current user: Id={currentUserAsync.Id}, email={currentUser.Email}");
Expand Down Expand Up @@ -916,6 +932,11 @@ public async Task<OperationResult> UpdateWorkingHour(TimePlanningWorkingHoursUpd
var sdkCore = await coreHelper.GetCore();
var sdkDbContext = sdkCore.DbContextHelper.GetDbContext();
var currentUserAsync = await userService.GetCurrentUserAsync();
if (currentUserAsync == null)
{
Console.WriteLine($"[DEBUG-GRPC-UPDATE] EARLY RETURN: GetCurrentUserAsync returned null (JWT missing or invalid)");
return new OperationResult(false, localizationService.GetString("UserNotFound"));
}
var currentUser = baseDbContext.Users
.Single(x => x.Id == currentUserAsync.Id);
var userEmail = (currentUser.Email ?? "").Trim().ToLower();
Expand Down
Loading