diff --git a/src/Dfe.SignIn.Core.Contracts/Users/GetUserOrganisationService.cs b/src/Dfe.SignIn.Core.Contracts/Users/GetUserOrganisationService.cs
index d41cabe2..18492f98 100644
--- a/src/Dfe.SignIn.Core.Contracts/Users/GetUserOrganisationService.cs
+++ b/src/Dfe.SignIn.Core.Contracts/Users/GetUserOrganisationService.cs
@@ -34,7 +34,7 @@ public class GetUserOrganisationService
///
/// Gets or sets the unique identifier of the organisation.
///
- public Guid OrganisationId { get; set; }
+ public Guid? OrganisationId { get; set; }
///
/// Gets or sets the name of the organisation.
@@ -69,7 +69,7 @@ public class GetUserOrganisationService
///
/// Gets or sets the organisation status identifier.
///
- public int StatusId { get; set; }
+ public int? StatusId { get; set; }
///
/// Gets or sets the date the organisation was closed.
@@ -159,7 +159,7 @@ public class GetUserOrganisationService
///
/// Gets or sets the unique identifier of the service.
///
- public Guid ServiceId { get; set; }
+ public Guid? ServiceId { get; set; }
///
/// Gets or sets the name of the service.
@@ -184,5 +184,10 @@ public class GetUserOrganisationService
///
/// Gets or sets the organisation role identifier.
///
- public short OrgRoleId { get; set; }
+ public short? OrgRoleId { get; set; }
+
+ ///
+ /// True if the user belongs to the passed in service at any active organisation.
+ ///
+ public int IsInService { get; set; }
}
diff --git a/src/Dfe.SignIn.PublicApi/MappingExtensions/GetUserOrganisationServiceMapping.cs b/src/Dfe.SignIn.PublicApi/MappingExtensions/GetUserOrganisationServiceMapping.cs
index ea7685b4..622c9de0 100644
--- a/src/Dfe.SignIn.PublicApi/MappingExtensions/GetUserOrganisationServiceMapping.cs
+++ b/src/Dfe.SignIn.PublicApi/MappingExtensions/GetUserOrganisationServiceMapping.cs
@@ -18,10 +18,12 @@ public static class GetUserOrganisationServiceMapping
///
public static IEnumerable ToUserDtos(this IEnumerable models)
{
+ var hasService = models.Any(x => x.IsInService == 1);
+
return models
.GroupBy(x => x.UserId)
.Select(userGroup => {
- GetUserOrganisationService u = userGroup.First();
+ var u = userGroup.First();
return new GetUserOrganisationServicesResponse {
UserId = u.UserId,
@@ -29,9 +31,9 @@ public static IEnumerable ToUserDtos(this I
Email = u.Email,
FamilyName = u.FamilyName,
GivenName = u.GivenName,
-
- Organisations = userGroup.ToOrganisationDtos()
-
+ Organisations = hasService
+ ? userGroup.ToOrganisationDtos()
+ : []
};
});
}
@@ -45,12 +47,13 @@ public static IEnumerable ToOrganisationDtos(
this IGrouping userGroup)
{
return userGroup
- .GroupBy(x => x.OrganisationId)
+ .Where(x => x.OrganisationId.HasValue) // Filter out nulls
+ .GroupBy(x => x.OrganisationId!.Value) // Use ! to suppress nullable warning
.Select(static orgGroup => {
var o = orgGroup.First();
return new OrganisationDto {
- Id = o.OrganisationId,
+ Id = o.OrganisationId ?? Guid.Empty,
Name = o.OrganisationName,
Category = new CategoryDto {
@@ -63,10 +66,12 @@ public static IEnumerable ToOrganisationDtos(
Ukprn = o.Ukprn,
EstablishmentNumber = o.EstablishmentNumber,
- Status = new StatusDto {
- Id = o.StatusId,
- Name = EnumHelpers.MapEnum(o.StatusId).GetDescription()
- },
+ Status = o.StatusId.HasValue
+ ? new StatusDto {
+ Id = o.StatusId.Value,
+ Name = EnumHelpers.MapEnum(o.StatusId).GetDescription()
+ }
+ : new StatusDto(),
ClosedOn = o.ClosedOn,
Address = o.Address,
@@ -88,8 +93,8 @@ public static IEnumerable ToOrganisationDtos(
Services = orgGroup.ToServiceDtos(),
- OrgRoleId = o.OrgRoleId,
- OrgRoleName = OrganisationRoles.FromId(o.OrgRoleId)?.Name
+ OrgRoleId = o.OrgRoleId ?? 0, // Fix: Use fallback if null
+ OrgRoleName = o.OrgRoleId.HasValue ? OrganisationRoles.FromId(o.OrgRoleId.Value)?.Name : null // Fix: Only access .Value if not null
};
});
diff --git a/src/Dfe.SignIn.PublicApi/Repository/OrganisationRepository.cs b/src/Dfe.SignIn.PublicApi/Repository/OrganisationRepository.cs
index 9b307296..46717e20 100644
--- a/src/Dfe.SignIn.PublicApi/Repository/OrganisationRepository.cs
+++ b/src/Dfe.SignIn.PublicApi/Repository/OrganisationRepository.cs
@@ -89,36 +89,38 @@ u.sub AS UserId
,r.[Name] AS RoleName
,r.Code AS RoleCode
,uo.role_id AS OrgRoleId
- FROM dbo.user_organisation uo
- JOIN dbo.[user] u
- ON u.sub = uo.user_id
- JOIN dbo.organisation o
- ON o.Id = uo.organisation_id
- JOIN dbo.user_services us
+ ,CASE WHEN EXISTS (
+ SELECT *
+ FROM dbo.user_services us2
+ JOIN dbo.[service] s2
+ ON s2.id = us2.service_id
+ JOIN dbo.[organisation] o2
+ ON o2.Id = us2.organisation_id
+ WHERE
+ us2.organisation_id = uo.organisation_id
+ AND us2.user_id = uo.user_id
+ AND s2.clientId = {clientName}
+ AND o2.[Status] <> 0
+ )
+ THEN 1 ELSE 0 END AS IsInService
+ FROM dbo.[user] u
+ LEFT OUTER JOIN dbo.user_organisation uo
+ ON uo.user_id = u.sub
+ LEFT OUTER JOIN dbo.organisation o
+ ON o.Id = uo.organisation_id AND o.[Status] <> 0
+ LEFT OUTER JOIN dbo.user_services us
ON us.organisation_id = uo.organisation_id
AND us.user_id = uo.user_id
- LEFT JOIN dbo.[service] s
+ LEFT OUTER JOIN dbo.[service] s
ON s.id = us.service_id
- LEFT JOIN dbo.user_service_roles usr
+ LEFT OUTER JOIN dbo.user_service_roles usr
ON usr.organisation_id = us.organisation_id
AND usr.service_id = us.service_id
AND usr.user_id = us.user_id
- LEFT JOIN dbo.[Role] r
+ LEFT OUTER JOIN dbo.[Role] r
ON r.Id = usr.role_id
WHERE
- uo.user_id = {userId}
- AND
- o.[status] <> 0
- AND EXISTS (
- SELECT 1
- FROM dbo.user_services us2
- JOIN dbo.[service] s2
- ON s2.id = us2.service_id
- WHERE
- us2.organisation_id = uo.organisation_id
- AND us2.user_id = uo.user_id
- AND s2.clientId = {clientName}
- );
+ u.sub = {userId};
""")
.ToListAsync(cancellationToken);
diff --git a/tests/Dfe.SignIn.PublicApi.UnitTests/MappingExtensions/GetUserOrganisationServiceMappingTests.cs b/tests/Dfe.SignIn.PublicApi.UnitTests/MappingExtensions/GetUserOrganisationServiceMappingTests.cs
index 9b083675..7c9eab48 100644
--- a/tests/Dfe.SignIn.PublicApi.UnitTests/MappingExtensions/GetUserOrganisationServiceMappingTests.cs
+++ b/tests/Dfe.SignIn.PublicApi.UnitTests/MappingExtensions/GetUserOrganisationServiceMappingTests.cs
@@ -8,12 +8,13 @@ namespace Dfe.SignIn.PublicApi.UnitTests.MappingExtensions;
[TestClass]
public class GetUserOrganisationServiceMappingTests
{
- private static GetUserOrganisationService CreateModel(
+ private static GetUserOrganisationService CreateUserOrganisationServiceModel(
Guid userId,
Guid orgId,
string? serviceName,
string? roleName,
- string? roleCode)
+ string? roleCode,
+ int inService = 1)
{
return new GetUserOrganisationService {
UserId = userId,
@@ -33,10 +34,33 @@ private static GetUserOrganisationService CreateModel(
RoleName = roleName,
RoleCode = roleCode,
- OrgRoleId = OrganisationRoles.Approver.Id
+ OrgRoleId = OrganisationRoles.Approver.Id,
+ IsInService = inService
};
}
+ [TestMethod]
+ public void ToUserDtos_WhenServiceNotFound_ReturnsSingleUserWithZeroOrganisations()
+ {
+ var userId = Guid.NewGuid();
+ var orgId = Guid.NewGuid();
+
+ var models = new[]
+ {
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1", 0),
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceB", "Role2", "R2", 0)
+ };
+
+ var result = models.ToUserDtos().Single();
+
+ Assert.IsEmpty(result.Organisations);
+ Assert.AreEqual(userId, result.UserId);
+ Assert.AreEqual("test@test.com", result.Email);
+ Assert.AreEqual("Doe", result.FamilyName);
+ Assert.AreEqual("John", result.GivenName);
+ Assert.AreEqual(1, result.UserStatus);
+ }
+
[TestMethod]
public void ToUserDtos_GroupsByUser_ReturnsSingleUser()
{
@@ -44,8 +68,8 @@ public void ToUserDtos_GroupsByUser_ReturnsSingleUser()
var models = new[]
{
- CreateModel(userId, Guid.NewGuid(), "ServiceA", "Role1", "R1"),
- CreateModel(userId, Guid.NewGuid(), "ServiceB", "Role2", "R2")
+ CreateUserOrganisationServiceModel(userId, Guid.NewGuid(), "ServiceA", "Role1", "R1"),
+ CreateUserOrganisationServiceModel(userId, Guid.NewGuid(), "ServiceB", "Role2", "R2")
};
var result = models.ToUserDtos().ToList();
@@ -59,7 +83,7 @@ public void ToUserDtos_MapsUserFields_Correctly()
{
var userId = Guid.NewGuid();
- var model = CreateModel(userId, Guid.NewGuid(), "ServiceA", "Role1", "R1");
+ var model = CreateUserOrganisationServiceModel(userId, Guid.NewGuid(), "ServiceA", "Role1", "R1");
var result = new[] { model }.ToUserDtos().Single();
@@ -77,8 +101,8 @@ public void ToOrganisationDtos_GroupsByOrganisation()
var models = new[]
{
- CreateModel(userId, orgId, "ServiceA", "Role1", "R1"),
- CreateModel(userId, orgId, "ServiceB", "Role2", "R2")
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1"),
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceB", "Role2", "R2")
};
var result = models.ToUserDtos().Single();
@@ -92,7 +116,7 @@ public void ToOrganisationDtos_MapsOrganisationFields()
var userId = Guid.NewGuid();
var orgId = Guid.NewGuid();
- var model = CreateModel(userId, orgId, "ServiceA", "Role1", "R1");
+ var model = CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1");
var org = new[] { model }
.ToUserDtos()
@@ -114,8 +138,8 @@ public void ToServiceDtos_GroupsByServiceName()
var models = new[]
{
- CreateModel(userId, orgId, "ServiceA", "Role1", "R1"),
- CreateModel(userId, orgId, "ServiceA", "Role2", "R2")
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1"),
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role2", "R2")
};
var services = models
@@ -136,8 +160,8 @@ public void ToServiceDtos_OrdersServices_ByName()
var models = new[]
{
- CreateModel(userId, orgId, "BService", "Role1", "R1"),
- CreateModel(userId, orgId, "AService", "Role1", "R1")
+ CreateUserOrganisationServiceModel(userId, orgId, "BService", "Role1", "R1"),
+ CreateUserOrganisationServiceModel(userId, orgId, "AService", "Role1", "R1")
};
var services = models
@@ -160,8 +184,8 @@ public void ToRoleDtos_RemovesDuplicateRoles()
var models = new[]
{
- CreateModel(userId, orgId, "ServiceA", "Role1", "R1"),
- CreateModel(userId, orgId, "ServiceA", "Role1", "R1") // duplicate
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1"),
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1") // duplicate
};
var roles = models
@@ -184,8 +208,8 @@ public void ToRoleDtos_ExcludesNullRoleNames()
var models = new[]
{
- CreateModel(userId, orgId, "ServiceA", null, "R1"),
- CreateModel(userId, orgId, "ServiceA", "Role1", "R1")
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", null, "R1"),
+ CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1")
};
var roles = models
@@ -208,7 +232,7 @@ public void ToOrganisationDtos_ConvertsLegacyIdToString()
var userId = Guid.NewGuid();
var orgId = Guid.NewGuid();
- var model = CreateModel(userId, orgId, "ServiceA", "Role1", "R1");
+ var model = CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1");
model.LegacyId = 12345;
var org = new[] { model }
@@ -226,7 +250,7 @@ public void ToOrganisationDtos_MapsOrgRoleName_WhenExists()
var userId = Guid.NewGuid();
var orgId = Guid.NewGuid();
- var model = CreateModel(userId, orgId, "ServiceA", "Role1", "R1");
+ var model = CreateUserOrganisationServiceModel(userId, orgId, "ServiceA", "Role1", "R1");
var org = new[] { model }
.ToUserDtos()