Add Namespace Approved/Rejected Notifications#15542
Closed
smw-ms wants to merge 3 commits into
Closed
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds namespace lifecycle email notifications to APIView’s Namespace Approval flow, focusing on the Approved and Rejected scenarios from #14707.
Changes:
- Added new Razor email templates and strongly-typed models for Namespace Approved and Namespace Rejected emails.
- Wired notifications into the namespace status update endpoint so emails are sent on Approved/Rejected transitions.
- Added helper methods to locate the associated review for a project/language/namespace to build better email links/context.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/dotnet/APIView/APIViewWeb/Services/EmailTemplateService.cs | Maps template keys to the new approved/rejected email templates. |
| src/dotnet/APIView/APIViewWeb/Models/ProjectModel.cs | Adds helpers to retrieve project-linked review IDs and current package name. |
| src/dotnet/APIView/APIViewWeb/Models/NamespaceModel.cs | Adds helper to retrieve the current namespace decision entry for a language/namespace. |
| src/dotnet/APIView/APIViewWeb/Models/EmailTemplateModels.cs | Introduces new email models for approved/rejected namespace notifications. |
| src/dotnet/APIView/APIViewWeb/Models/EmailTemplateKey.cs | Adds a new template key for namespace rejection emails. |
| src/dotnet/APIView/APIViewWeb/Managers/ReviewManager.cs | Minor cleanup around manual approval flow comment. |
| src/dotnet/APIView/APIViewWeb/Managers/ProjectsManager.cs | Adds method to find the best associated review for notifications. |
| src/dotnet/APIView/APIViewWeb/Managers/NotificationManager.cs | Implements approved/rejected email notification sending and recipient selection. |
| src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IProjectsManager.cs | Exposes associated-review lookup for notification scenarios. |
| src/dotnet/APIView/APIViewWeb/Managers/Interfaces/INotificationManager.cs | Adds notification APIs for approved/rejected namespace events. |
| src/dotnet/APIView/APIViewWeb/LeanControllers/ProjectsController.cs | Triggers approved/rejected notifications after successful namespace status updates. |
| src/dotnet/APIView/APIViewWeb/EmailTemplates/NamespaceReviewApprovedEmail.cshtml | Removes legacy “namespace review approved” template in favor of the new one. |
| src/dotnet/APIView/APIViewWeb/EmailTemplates/NamespaceRejectedEmail.cshtml | Adds the new “Namespace Rejected” email template. |
| src/dotnet/APIView/APIViewWeb/EmailTemplates/NamespaceApprovedEmail.cshtml | Adds the new “Namespace Approved” email template. |
| src/dotnet/APIView/APIViewWeb/Controllers/CommentsController.cs | Updates using directives to match interface namespace changes. |
| src/dotnet/APIView/APIViewUnitTests/EmailTemplatePreviewGeneratorTests.cs | Updates preview generation to use the new models and templates. |
Comment on lines
+411
to
+423
| // Use the unified approval email template for manual approval. | ||
| // Legacy flow does not have project/namespace-tab context, so reuse the TypeSpec review URL. | ||
| var emailContent = await _emailTemplateService.RenderAsync( | ||
| EmailTemplateKey.NamespaceReviewApproved, | ||
| NamespaceReviewApprovedEmailModel.Create( | ||
| NamespaceApprovedEmailModel.Create( | ||
| review.PackageName, | ||
| review.PackageName, | ||
| review.Language, | ||
| review.PackageName, | ||
| review.CreatedBy, | ||
| DateTime.UtcNow, | ||
| typeSpecUrl, | ||
| associatedReviews ?? Enumerable.Empty<ReviewListItemModel>(), | ||
| _apiviewEndpoint)); | ||
| typeSpecUrl)); |
Member
Author
There was a problem hiding this comment.
NotifyStakeholdersOfManualApprovalAsync is still used in the old namespace page workflow, which is why I didn't outright delete it. I'm leaning towards just leaving unknown fields blank.
Comment on lines
+527
to
+531
| var usernames = new HashSet<string>( | ||
| (project?.Owners ?? Enumerable.Empty<string>()) | ||
| .Concat(new[] { associatedReview?.CreatedBy, approverUserName }) | ||
| .Where(username => !string.IsNullOrWhiteSpace(username)), | ||
| StringComparer.OrdinalIgnoreCase); |
Comment on lines
+227
to
+246
| if (request.Status == NamespaceDecisionStatus.Rejected || request.Status == NamespaceDecisionStatus.Approved) | ||
| { | ||
| string normalizedLanguage = LanguageServiceHelpers.MapLanguageAlias(language); | ||
| var associatedReview = await _projectsManager.GetAssociatedReviewForProjectAsync(result.Project, normalizedLanguage, request.Namespace); | ||
|
|
||
| NamespaceDecisionEntry decisionEntry = result.Project.NamespaceInfo?.GetCurrentEntry( | ||
| normalizedLanguage, | ||
| request.Namespace); | ||
|
|
||
| if (decisionEntry != null) | ||
| { | ||
| if (request.Status == NamespaceDecisionStatus.Rejected) | ||
| { | ||
| await _notificationManager.NotifyNamespaceRejectedAsync(result.Project, decisionEntry, associatedReview); | ||
| } | ||
| else | ||
| { | ||
| await _notificationManager.NotifyNamespaceApprovedAsync(result.Project, decisionEntry, associatedReview); | ||
| } | ||
| } |
Comment on lines
+227
to
+245
| if (request.Status == NamespaceDecisionStatus.Rejected || request.Status == NamespaceDecisionStatus.Approved) | ||
| { | ||
| string normalizedLanguage = LanguageServiceHelpers.MapLanguageAlias(language); | ||
| var associatedReview = await _projectsManager.GetAssociatedReviewForProjectAsync(result.Project, normalizedLanguage, request.Namespace); | ||
|
|
||
| NamespaceDecisionEntry decisionEntry = result.Project.NamespaceInfo?.GetCurrentEntry( | ||
| normalizedLanguage, | ||
| request.Namespace); | ||
|
|
||
| if (decisionEntry != null) | ||
| { | ||
| if (request.Status == NamespaceDecisionStatus.Rejected) | ||
| { | ||
| await _notificationManager.NotifyNamespaceRejectedAsync(result.Project, decisionEntry, associatedReview); | ||
| } | ||
| else | ||
| { | ||
| await _notificationManager.NotifyNamespaceApprovedAsync(result.Project, decisionEntry, associatedReview); | ||
| } |
Comment on lines
+27
to
+33
| if (CurrentNamespaceStatus == null || | ||
| !CurrentNamespaceStatus.TryGetValue(language, out var entries)) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| return entries?.FirstOrDefault(entry => |
| public bool IsDeleted { get; set; } | ||
|
|
||
| public List<string> GetAssociatedReviewIds(string language) | ||
| { |
Comment on lines
+118
to
+124
| public async Task<ReviewListItemModel> GetAssociatedReviewForProjectAsync(Project project, string language, string namespaceValue) | ||
| { | ||
| List<string> reviewIds = project?.GetAssociatedReviewIds(language) ?? []; | ||
| if (reviewIds.Count == 0) | ||
| { | ||
| return null; | ||
| } |
|
|
||
| <p class="section"><strong>Next Steps:</strong></p> | ||
| <ul class="list"> | ||
| <li>Review namespace status and history in the <a href="@Model.NamespaceTabUrl">namespace tab</a>.</li> |
|
|
||
| <p class="section"><strong>Next Steps:</strong></p> | ||
| <ul class="list"> | ||
| <li>Review namespace status and history in the <a href="@Model.NamespaceTabUrl">namespace tab</a>.</li> |
… apiview/add-namespace-emails
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Aims to resolve tasks 2 & 3 of this issue: #14707