Files
Sharepoint-Toolbox/.planning/phases/13-user-directory-viewmodel/13-01-PLAN.md
Dev df6f4949a8 docs(13-02): complete User Directory ViewModel plan
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:44:56 +02:00

9.0 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
13-user-directory-viewmodel 01 execute 1
SharepointToolbox/Core/Models/GraphDirectoryUser.cs
SharepointToolbox/Services/IGraphUserDirectoryService.cs
SharepointToolbox/Services/GraphUserDirectoryService.cs
SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs
true
UDIR-03
truths artifacts key_links
GraphDirectoryUser record includes a UserType property (string?) alongside the existing five properties
GraphUserDirectoryService.MapUser populates UserType from the Graph User object
IGraphUserDirectoryService.GetUsersAsync accepts an optional bool includeGuests parameter defaulting to false
When includeGuests is false, the Graph filter remains 'accountEnabled eq true and userType eq Member' (backward compatible)
When includeGuests is true, the Graph filter is 'accountEnabled eq true' (no userType restriction) and userType is in the select set
Existing tests continue to pass with no changes required (default parameter preserves old behavior)
path provides contains
SharepointToolbox/Core/Models/GraphDirectoryUser.cs Directory user record with UserType for client-side member/guest filtering UserType
path provides contains
SharepointToolbox/Services/IGraphUserDirectoryService.cs Interface with includeGuests parameter includeGuests
path provides contains
SharepointToolbox/Services/GraphUserDirectoryService.cs Implementation branching filter based on includeGuests includeGuests
from to via pattern
SharepointToolbox/Services/GraphUserDirectoryService.cs SharepointToolbox/Core/Models/GraphDirectoryUser.cs MapUser UserType
Extend GraphDirectoryUser with a UserType property and add an includeGuests parameter to GraphUserDirectoryService so that Phase 13-02 can load all users and filter members/guests in-memory.

Purpose: SC3 requires "Members only / Include guests" toggle that filters in-memory without a new Graph request. The service must fetch all users (members + guests) when requested, and the model must carry UserType for client-side filtering.

Output: Updated model, interface, implementation, and tests.

<execution_context> @C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/dev/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/13-user-directory-viewmodel/13-RESEARCH.md From SharepointToolbox/Core/Models/GraphDirectoryUser.cs: ```csharp public record GraphDirectoryUser( string DisplayName, string UserPrincipalName, string? Mail, string? Department, string? JobTitle); ```

From SharepointToolbox/Services/IGraphUserDirectoryService.cs:

public interface IGraphUserDirectoryService
{
    Task<IReadOnlyList<GraphDirectoryUser>> GetUsersAsync(
        string clientId,
        IProgress<int>? progress = null,
        CancellationToken ct = default);
}

From SharepointToolbox/Services/GraphUserDirectoryService.cs:

config.QueryParameters.Filter = "accountEnabled eq true and userType eq 'Member'";
config.QueryParameters.Select = new[]
{
    "displayName", "userPrincipalName", "mail", "department", "jobTitle"
};

internal static GraphDirectoryUser MapUser(User user) =>
    new(
        DisplayName: user.DisplayName ?? user.UserPrincipalName ?? string.Empty,
        UserPrincipalName: user.UserPrincipalName ?? string.Empty,
        Mail: user.Mail,
        Department: user.Department,
        JobTitle: user.JobTitle);
Task 1: Add UserType to GraphDirectoryUser SharepointToolbox/Core/Models/GraphDirectoryUser.cs - GraphDirectoryUser record has 6 positional parameters: DisplayName, UserPrincipalName, Mail, Department, JobTitle, UserType - UserType is nullable string (string?) — appended as last parameter for backward compat 1. Edit `SharepointToolbox/Core/Models/GraphDirectoryUser.cs`: Add `string? UserType` as the last parameter: ```csharp public record GraphDirectoryUser( string DisplayName, string UserPrincipalName, string? Mail, string? Department, string? JobTitle, string? UserType); ```
2. Check for any existing code that constructs GraphDirectoryUser (MapUser, tests) and add the UserType parameter.
   Search for `new GraphDirectoryUser(` and `new(` in test files to find all construction sites.
dotnet build --no-restore -warnaserror GraphDirectoryUser has UserType property. All construction sites updated. Build passes. Task 2: Add includeGuests parameter to interface and implementation SharepointToolbox/Services/IGraphUserDirectoryService.cs, SharepointToolbox/Services/GraphUserDirectoryService.cs - IGraphUserDirectoryService.GetUsersAsync has a new `bool includeGuests = false` parameter - When includeGuests=false: filter is "accountEnabled eq true and userType eq 'Member'" (unchanged) - When includeGuests=true: filter is "accountEnabled eq true" (fetches members + guests) - "userType" is always in the select set (needed for MapUser) - MapUser includes user.UserType in the mapping 1. Update `IGraphUserDirectoryService.cs`: ```csharp Task> GetUsersAsync( string clientId, bool includeGuests = false, IProgress? progress = null, CancellationToken ct = default); ```
2. Update `GraphUserDirectoryService.cs`:
   - Update method signature to match interface
   - Add `userType` to Select array
   - Branch filter based on includeGuests:
     ```csharp
     config.QueryParameters.Filter = includeGuests
         ? "accountEnabled eq true"
         : "accountEnabled eq true and userType eq 'Member'";
     config.QueryParameters.Select = new[]
     {
         "displayName", "userPrincipalName", "mail", "department", "jobTitle", "userType"
     };
     ```
   - Update MapUser:
     ```csharp
     internal static GraphDirectoryUser MapUser(User user) =>
         new(
             DisplayName: user.DisplayName ?? user.UserPrincipalName ?? string.Empty,
             UserPrincipalName: user.UserPrincipalName ?? string.Empty,
             Mail: user.Mail,
             Department: user.Department,
             JobTitle: user.JobTitle,
             UserType: user.UserType);
     ```
dotnet build --no-restore -warnaserror Interface and implementation updated. Default parameter preserves backward compat. Build passes. Task 3: Update tests SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs - Existing MapUser tests pass with UserType parameter added - New test: MapUser populates UserType from User.UserType - New test: MapUser returns null UserType when User.UserType is null 1. Read `SharepointToolbox.Tests/Services/GraphUserDirectoryServiceTests.cs` 2. Update any existing `MapUser` test assertions to include the UserType field 3. Add test: MapUser_PopulatesUserType — set User.UserType = "Member", verify GraphDirectoryUser.UserType == "Member" 4. Add test: MapUser_NullUserType — set User.UserType = null, verify GraphDirectoryUser.UserType is null 5. Run tests dotnet test SharepointToolbox.Tests --filter "FullyQualifiedName~GraphUserDirectoryService" --no-build -q All MapUser tests pass including UserType coverage. ```bash dotnet build --no-restore -warnaserror dotnet test SharepointToolbox.Tests --filter "FullyQualifiedName~GraphUserDirectoryService" --no-build -q ``` Both must pass with zero failures.

<success_criteria>

  • GraphDirectoryUser has UserType (string?) as last positional parameter
  • IGraphUserDirectoryService.GetUsersAsync has bool includeGuests = false parameter
  • When includeGuests=false, filter unchanged (backward compatible)
  • When includeGuests=true, filter omits userType restriction
  • MapUser populates UserType from Graph User object
  • userType always in select set
  • All tests pass </success_criteria>
After completion, create `.planning/phases/13-user-directory-viewmodel/13-01-SUMMARY.md`