Conversation
- Add StoreId property to EmailAccount domain entity - Add GetEmailAccountsByStore(storeId) method to IEmailAccountService and EmailAccountService - Add EMAILACCOUNT_BY_STORE_KEY cache key - Update MessageProviderService to use store-specific email account as fallback - Update EmailAccountModel with StoreId and AvailableStores - Update EmailAccountProfile mapper to include StoreId - Update EmailAccountViewModelService to be async and populate available stores - Add EmailAccountController to Grand.Web.Store with CRUD + store isolation - Add EmailAccount views (List, Create, Edit, Partials/CreateOrUpdate) in Store area - Add Messages namespace to Store _ViewImports.cshtml - Update Admin EmailAccountController for async PrepareEmailAccountModel Agent-Logs-Url: https://github.com/grandnode/grandnode2/sessions/094d04cc-7d75-4a00-af14-f5bb77f05736 Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
Agent-Logs-Url: https://github.com/grandnode/grandnode2/sessions/094d04cc-7d75-4a00-af14-f5bb77f05736 Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
…vent dirty data Instead of caching per-store results separately (which could hold stale/mutated objects when an account's StoreId changes), filter directly from the already correctly-invalidated GetAllEmailAccounts cache. Also removes the now-unused EMAILACCOUNT_BY_STORE_KEY constant. Agent-Logs-Url: https://github.com/grandnode/grandnode2/sessions/5697bb0d-b979-44be-8f1a-2f8c98ad8b5e Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
|
@copilot Grand.Web.Store should not see all available store |
…lableStores/PrepareEmailAccountModel calls Agent-Logs-Url: https://github.com/grandnode/grandnode2/sessions/d1fe358f-d64b-47c9-af25-cea72fae9de0 Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
Fixed in 84fdff0. The Store controller was calling Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot check my comments |
…tEmailAccountsByStore, pass store?.Id to GetEmailAccountOfMessageTemplate callers Agent-Logs-Url: https://github.com/grandnode/grandnode2/sessions/dba495a6-918d-4de2-8bc5-ae0409bfb8ff Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
Both comments addressed in 5994a60:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot GetEmailAccountOfMessageTemplate remove param storeId |
Agent-Logs-Url: https://github.com/grandnode/grandnode2/sessions/914040a7-8e8e-4927-ac04-672c87b33506 Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com>
Done in 50dfcbc. |
There was a problem hiding this comment.
Pull request overview
Adds store-scoped email accounts across domain/service layers and exposes CRUD management in the Store area UI, while updating Admin UI to support selecting a store scope for each email account.
Changes:
- Introduces
StoreIdonEmailAccountand extendsGetAllEmailAccountswith an optional store filter. - Updates AdminShared model/mapping and view-model service to support store selection (available stores list).
- Adds Store-area
EmailAccountControllerplus corresponding views for store-isolated management.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Web/Grand.Web.Store/Controllers/EmailAccountController.cs | New Store-area CRUD controller for email accounts filtered to current staff store |
| src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml | Adds messages model namespace for Store-area views |
| src/Web/Grand.Web.Store/Areas/Store/Views/EmailAccount/Partials/CreateOrUpdate.cshtml | New create/edit partial for Store area (hidden StoreId) |
| src/Web/Grand.Web.Store/Areas/Store/Views/EmailAccount/List.cshtml | New Kendo grid list view for Store area |
| src/Web/Grand.Web.Store/Areas/Store/Views/EmailAccount/Edit.cshtml | New Store-area edit view |
| src/Web/Grand.Web.Store/Areas/Store/Views/EmailAccount/Create.cshtml | New Store-area create view |
| src/Web/Grand.Web.AdminShared/Services/EmailAccountViewModelService.cs | Makes model preparation async and populates available stores for selection |
| src/Web/Grand.Web.AdminShared/Models/Messages/EmailAccountModel.cs | Adds StoreId + AvailableStores to the model |
| src/Web/Grand.Web.AdminShared/Mapper/EmailAccountProfile.cs | Updates mapping to ignore AvailableStores |
| src/Web/Grand.Web.AdminShared/Interfaces/IEmailAccountViewModelService.cs | Makes PrepareEmailAccountModel async; adds PrepareAvailableStores |
| src/Web/Grand.Web.Admin/Controllers/EmailAccountController.cs | Uses async model preparation and populates stores on Edit GET |
| src/Web/Grand.Web.Admin/Areas/Admin/Views/EmailAccount/Partials/CreateOrUpdate.cshtml | Adds Store selector dropdown to Admin email account editor |
| src/Tests/Grand.Business.Messages.Tests/Services/MessageProviderServiceTest.cs | Updates mock setup for the new GetAllEmailAccounts signature |
| src/Core/Grand.Domain/Messages/EmailAccount.cs | Adds StoreId to the domain entity |
| src/Business/Grand.Business.Messages/Services/MessageProviderService.cs | Simplifies email account resolution for message templates |
| src/Business/Grand.Business.Messages/Services/EmailAccountService.cs | Adds optional store filter to GetAllEmailAccounts |
| src/Business/Grand.Business.Core/Interfaces/Messages/IEmailAccountService.cs | Updates interface signature/documentation for store-filtered retrieval |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (string.IsNullOrEmpty(storeId)) | ||
| return accounts; | ||
|
|
||
| return accounts.Where(ea => ea.StoreId == storeId).ToList(); | ||
| } |
| private async Task PopulateAvailableStores(EmailAccountModel model) | ||
| { | ||
| model.AvailableStores.Add(new SelectListItem { | ||
| Value = "", | ||
| Text = _translationService.GetResource("Admin.Settings.StoreScope.AllStores") | ||
| }); | ||
| foreach (var store in await _storeService.GetAllStores()) | ||
| model.AvailableStores.Add(new SelectListItem { | ||
| Value = store.Id, | ||
| Text = store.Name | ||
| }); |
| var gridModel = new DataSourceResult { | ||
| Data = emailAccountModels, | ||
| Total = emailAccountModels.Count |
| <div class="form-group"> | ||
| <admin-label asp-for="StoreId"/> | ||
| <div class="col-md-9 col-sm-9"> | ||
| <select asp-for="StoreId" asp-items="Model.AvailableStores" class="form-control"></select> | ||
| </div> |
| var emailAccounId = messageTemplate.GetTranslation(mt => mt.EmailAccountId, languageId); | ||
| var emailAccount = (await _emailAccountService.GetEmailAccountById(emailAccounId) ?? | ||
| await _emailAccountService.GetEmailAccountById(_emailAccountSettings | ||
| .DefaultEmailAccountId)) ?? | ||
| (await _emailAccountService.GetAllEmailAccounts()).FirstOrDefault(); | ||
| var emailAccount = await _emailAccountService.GetEmailAccountById(emailAccounId); | ||
| emailAccount ??= await _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); |
| /// Gets or sets the store identifier this email account belongs to. | ||
| /// An empty string means this is a global/shared email account. | ||
| /// </summary> | ||
| public string StoreId { get; set; } |
| columns: [{ | ||
| field: "Email", | ||
| title: "@Loc["Admin.Configuration.EmailAccounts.Fields.Email"]", | ||
| template: '<a class="k-link" href="Edit/#=Id#">#=Email#</a>' |
StoreIdproperty toEmailAccountdomain entityGetAllEmailAccounts(string storeId = "")with optional store filter, replacing the separateGetEmailAccountsByStoremethodStoreIdtoEmailAccountModelin AdminSharedEmailAccountProfilemapper to includeStoreIdEmailAccountViewModelServiceto be async and populate available storesEmailAccountControllerfor asyncPrepareEmailAccountModelEmailAccountControllertoGrand.Web.Storewith CRUD actions (store-isolated)Grand.Web.Store/Areas/Store/Views/EmailAccount/DefaultLanguage.xmlGetAllEmailAccountscache is the only source of truthPrepareAvailableStores/PrepareEmailAccountModelcalls from Store controller — Store area uses a hiddenStoreIdfield locked toCurrentStoreIdGetEmailAccountOfMessageTemplate— removestoreIdparameter; resolution order is template account ID → default account from settings → first available account