diff --git a/SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs b/SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs
index bfdf141..f0bef48 100644
--- a/SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs
+++ b/SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs
@@ -31,7 +31,8 @@ public class GraphUserDirectoryServiceTests
UserPrincipalName = "alice@contoso.com",
Mail = "alice@contoso.com",
Department = "Engineering",
- JobTitle = "Senior Developer"
+ JobTitle = "Senior Developer",
+ UserType = "Member"
};
var result = GraphUserDirectoryService.MapUser(user);
@@ -41,6 +42,7 @@ public class GraphUserDirectoryServiceTests
Assert.Equal("alice@contoso.com", result.Mail);
Assert.Equal("Engineering", result.Department);
Assert.Equal("Senior Developer", result.JobTitle);
+ Assert.Equal("Member", result.UserType);
}
[Fact]
@@ -52,7 +54,8 @@ public class GraphUserDirectoryServiceTests
UserPrincipalName = "bob@contoso.com",
Mail = null,
Department = null,
- JobTitle = null
+ JobTitle = null,
+ UserType = "Guest"
};
var result = GraphUserDirectoryService.MapUser(user);
@@ -62,6 +65,7 @@ public class GraphUserDirectoryServiceTests
Assert.Null(result.Mail);
Assert.Null(result.Department);
Assert.Null(result.JobTitle);
+ Assert.Equal("Guest", result.UserType);
}
[Fact]
@@ -120,6 +124,44 @@ public class GraphUserDirectoryServiceTests
Assert.Null(result.JobTitle);
}
+ // ── MapUser: UserType mapping ──────────────────────────────────────────────
+
+ [Fact]
+ public void MapUser_PopulatesUserType()
+ {
+ var user = new User
+ {
+ DisplayName = "Eve Wilson",
+ UserPrincipalName = "eve@contoso.com",
+ Mail = "eve@contoso.com",
+ Department = "Sales",
+ JobTitle = "Account Executive",
+ UserType = "Member"
+ };
+
+ var result = GraphUserDirectoryService.MapUser(user);
+
+ Assert.Equal("Member", result.UserType);
+ }
+
+ [Fact]
+ public void MapUser_NullUserType_ReturnsNull()
+ {
+ var user = new User
+ {
+ DisplayName = "Frank Lee",
+ UserPrincipalName = "frank@contoso.com",
+ Mail = null,
+ Department = null,
+ JobTitle = null,
+ UserType = null
+ };
+
+ var result = GraphUserDirectoryService.MapUser(user);
+
+ Assert.Null(result.UserType);
+ }
+
// ── GetUsersAsync: integration-level scenarios (skipped without live tenant) ──
[Fact(Skip = "Requires integration test with real Graph client — PageIterator.CreatePageIterator " +
diff --git a/SharepointToolbox/Core/Models/GraphDirectoryUser.cs b/SharepointToolbox/Core/Models/GraphDirectoryUser.cs
index 839840a..22c8890 100644
--- a/SharepointToolbox/Core/Models/GraphDirectoryUser.cs
+++ b/SharepointToolbox/Core/Models/GraphDirectoryUser.cs
@@ -9,4 +9,5 @@ public record GraphDirectoryUser(
string UserPrincipalName,
string? Mail,
string? Department,
- string? JobTitle);
+ string? JobTitle,
+ string? UserType);
diff --git a/SharepointToolbox/Services/GraphUserDirectoryService.cs b/SharepointToolbox/Services/GraphUserDirectoryService.cs
index 63772b7..b2632bf 100644
--- a/SharepointToolbox/Services/GraphUserDirectoryService.cs
+++ b/SharepointToolbox/Services/GraphUserDirectoryService.cs
@@ -22,6 +22,7 @@ public class GraphUserDirectoryService : IGraphUserDirectoryService
///
public async Task> GetUsersAsync(
string clientId,
+ bool includeGuests = false,
IProgress? progress = null,
CancellationToken ct = default)
{
@@ -29,11 +30,12 @@ public class GraphUserDirectoryService : IGraphUserDirectoryService
var response = await graphClient.Users.GetAsync(config =>
{
- // Pending real-tenant verification — see STATE.md pending todos
- config.QueryParameters.Filter = "accountEnabled eq true and userType eq 'Member'";
+ config.QueryParameters.Filter = includeGuests
+ ? "accountEnabled eq true"
+ : "accountEnabled eq true and userType eq 'Member'";
config.QueryParameters.Select = new[]
{
- "displayName", "userPrincipalName", "mail", "department", "jobTitle"
+ "displayName", "userPrincipalName", "mail", "department", "jobTitle", "userType"
};
config.QueryParameters.Top = 999;
// No ConsistencyLevel header: standard equality filter does not require eventual consistency
@@ -74,5 +76,6 @@ public class GraphUserDirectoryService : IGraphUserDirectoryService
UserPrincipalName: user.UserPrincipalName ?? string.Empty,
Mail: user.Mail,
Department: user.Department,
- JobTitle: user.JobTitle);
+ JobTitle: user.JobTitle,
+ UserType: user.UserType);
}
diff --git a/SharepointToolbox/Services/IGraphUserDirectoryService.cs b/SharepointToolbox/Services/IGraphUserDirectoryService.cs
index a3ba665..b60400b 100644
--- a/SharepointToolbox/Services/IGraphUserDirectoryService.cs
+++ b/SharepointToolbox/Services/IGraphUserDirectoryService.cs
@@ -13,6 +13,10 @@ public interface IGraphUserDirectoryService
/// Iterates through all pages using the Graph SDK PageIterator until exhausted or cancelled.
///
/// The client/tenant identifier used to obtain a Graph token.
+ ///
+ /// When false (default), only member users are returned (userType eq 'Member').
+ /// When true, both members and guests are returned (no userType filter).
+ ///
///
/// Optional progress reporter — receives the running count of users fetched so far.
/// Phase 13's ViewModel uses this to show "Loading... X users" feedback.
@@ -21,6 +25,7 @@ public interface IGraphUserDirectoryService
/// Cancellation token. Iteration stops when cancelled.
Task> GetUsersAsync(
string clientId,
+ bool includeGuests = false,
IProgress? progress = null,
CancellationToken ct = default);
}