5.1 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 17-group-expansion-html-reports | 01 | services |
|
|
|
|
|
|
Phase 17 Plan 01: SharePoint Group Resolver Service Summary
One-liner: CSOM + Graph transitive member resolver with OrdinalIgnoreCase dictionary, graceful error fallback, and internal static helpers for unit testing.
What Was Built
Created the ISharePointGroupResolver service that pre-resolves SharePoint group members before HTML export. The service uses CSOM to enumerate direct group users, then calls Microsoft Graph groups/{id}/transitiveMembers/microsoft.graph.user for any nested AAD groups — satisfying the RPT-02 transitive membership requirement.
Files Created
SharepointToolbox/Core/Models/ResolvedMember.cs— Simplerecord ResolvedMember(string DisplayName, string Login)value type.SharepointToolbox/Services/ISharePointGroupResolver.cs— Interface with singleResolveGroupsAsync(ctx, clientId, groupNames, ct)method returningIReadOnlyDictionary<string, IReadOnlyList<ResolvedMember>>.SharepointToolbox/Services/SharePointGroupResolver.cs— Implementation: CSOM group user loading, AAD group detection viaIsAadGroup(), GraphTransitiveMembers.GraphUser.GetAsync()withPageIteratorpagination, per-group try/catch for graceful fallback.SharepointToolbox.Tests/Services/SharePointGroupResolverTests.cs— 14 tests (12 passing unit tests + 2 live-tenant skip-marked): coversIsAadGroup,ExtractAadGroupId,StripClaims, empty-list behavior, and OrdinalIgnoreCase comparer verification.
Files Modified
SharepointToolbox/App.xaml.cs— Addedservices.AddTransient<ISharePointGroupResolver, SharePointGroupResolver>()under Phase 17 comment.
Decisions Made
-
Internal static helpers for testability:
IsAadGroup,ExtractAadGroupId,StripClaimsareinternal static— accessible to the test project via the existingInternalsVisibleTo("SharepointToolbox.Tests")assembly attribute without exposing them as public API. -
Lazy Graph client creation:
graphClientis created on-demand only when the first AAD group is encountered in the loop. This avoids a Graph auth round-trip for sites with no nested AAD groups (common case). -
Type alias for ambiguous User:
GraphUser = Microsoft.Graph.Models.UserandGraphUserCollectionResponsealiased to resolve CS0104 ambiguity — both CSOM (Microsoft.SharePoint.Client.User) and Graph SDK (Microsoft.Graph.Models.User) are referenced in the same file.
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] CS0104 ambiguous User reference
- Found during: Task 1 GREEN phase (first build)
- Issue:
PageIterator<User, UserCollectionResponse>was ambiguous betweenMicrosoft.SharePoint.Client.UserandMicrosoft.Graph.Models.User— both namespaces imported. - Fix: Added
using GraphUser = Microsoft.Graph.Models.Userandusing GraphUserCollectionResponse = Microsoft.Graph.Models.UserCollectionResponsealiases. - Files modified:
SharepointToolbox/Services/SharePointGroupResolver.cs
2. [Rule 1 - Bug] IReadOnlyDictionary.Comparer not accessible
- Found during: Task 1 GREEN phase (test compile)
- Issue: Test cast
result.Comparerfails becauseIReadOnlyDictionary<,>does not expose.Comparer. The concreteDictionary<,>does. - Fix: Updated test to cast the result to
Dictionary<string, IReadOnlyList<ResolvedMember>>before accessing comparer behavior — works becauseSharePointGroupResolver.ResolveGroupsAsyncreturns aDictionary<>viaIReadOnlyDictionary<>. - Files modified:
SharepointToolbox.Tests/Services/SharePointGroupResolverTests.cs
Test Results
dotnet test --filter "FullyQualifiedName~SharePointGroupResolverTests"
Passed: 12, Skipped: 2 (live tenant), Failed: 0
dotnet test (full suite)
Passed: 314, Skipped: 28, Failed: 0
Self-Check
Files created: verified. Commits verified below.