Repository navigation
Move the product read-only flag from ViewBag to the model and remove unread ViewBag values - #1013
Open
KrzysztofPajak wants to merge 9 commits into
Open
KrzysztofPajak wants to merge 9 commits into
KrzysztofPajak wants to merge 9 commits into
Conversation
added 4 commits
November 1, 2026 21:10
AllLanguages, ClosePage, OrderTags' RefreshPage and the popup input names were written and never read: the popup views take the input names from the query string, which their forms keep through asp-route-*. The action parameters that only fed those writes go with them.
ViewBag.IsReadOnly decides whether a store owner sees the buttons that write to a product, yet a misspelled key compiled and turned into "editable". As a model property the compiler checks every reader; it is never bound, so a posted value cannot reach the re-rendered form.
Its ClosePage writes sit in code that another pull request changes.
added 5 commits
November 2, 2026 08:01
The Locales list is already bound from the form, so adding the languages again on the invalid path listed each language twice. The next save stored the duplicates. News and the other screens already return the bound model as it is.
A successful save re-rendered the form from the POST, which looked the same as a failed one, and a refresh submitted it again. It now behaves like the product tag screen.
A product name ending in a backslash broke the script, so the opener's field stayed empty and the popup stayed open. The name now goes in as text, the same way the required product popup passes its values.
The separator was chosen by array index, so skipping the last product because the panel has no access to it left "A, " in the field.
The test only checked that the attribute was present. It now posts a value through the binder and checks that it does not reach the model.
| // actually appended, so skipping the last product still leaves a trailing ", ". Pre-existing | ||
| // quirk in both original hosts, not introduced by this migration - characterized, not fixed. | ||
| Assert.AreEqual("Allowed, ", GetTextProperty(json.Value)); | ||
| Assert.AreEqual("Allowed", GetTextProperty(json.Value)); |
|
|
||
| var redirect = result as RedirectToActionResult; | ||
| Assert.IsNotNull(redirect); | ||
| Assert.AreEqual("Edit", redirect.ActionName); |
|
|
||
| var redirect = result as RedirectToActionResult; | ||
| Assert.IsNotNull(redirect); | ||
| Assert.AreEqual("List", redirect.ActionName); |
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.
Type: bugfix
Issue
ViewBag.IsReadOnlydecides whether a store owner sees the buttons that write to a product. It is untyped, so a misspelled key compiles and turns into "editable", and the views' real input is not visible from their@model. Every write action still checks access on the server, so this concerns the screen only.Several other
ViewBagvalues were written and read by no view.Solution
ProductModelgetsIsReadOnly, set byBaseProductController.Edit(GET). It has[BindNever], so a posted value cannot reach the re-rendered form. The product views readModel.IsReadOnly.Partials/UserFieldsin the Store panel also serves other entities, so it checksModel is ProductModel { IsReadOnly: true }.AllLanguages(Blog and News),RefreshPage(OrderTags), and the input names in the required product and course popups. Those popups read the names from the query string, which their forms keep. The action parameters that only fed these writes go too.Other
ViewBaguses stay on purpose:Title, the popups that do use it, plugins,Currency/ListandBlog/Comments(no model to move to), andIsPopupon pages, which a theme may read.ClosePageinPermissionControlleris left to a separate pull request.Review of this change also found defects on the same screens, fixed here in separate commits:
Localesalready bound from the form. The next save stored the duplicates. Fixed in Blog (post, category create and edit) and in address, customer, product and specification attributes.One new resource,
Admin.Orders.OrderTags.Updated, inDefaultLanguage.xmlandUpgrade/en_250.xml. No new settings or migrations.Breaking changes
These affect custom plugins and views only. Nothing in this repository depends on them, and URLs are unchanged.
ViewBagvalues are no longer set, so a custom plugin or view that reads them getsnull:IsReadOnly(product edit),AllLanguages(Blog and News),RefreshPage(OrderTags),productIdsInput(required product popup), andbtnId,productIdInputandproductNameInput(course product popup).BaseProductController.RequiredProductAddPopupno longer takesproductIdsInput, andCourseController.AssociateProductToCoursePopup(POST) no longer takesbtnId,productIdInputorproductNameInput.ProductModelhas a new property,IsReadOnly.OrderTagsControllerconstructor takesIRequestTranslationService, and itsEditPOST redirects after a successful save.Testing
The solution builds. Unit tests pass:
Grand.Web.Admin.Tests(1849),Grand.Web.Store.Tests(188),Grand.Web.Vendor.Tests(53),Grand.Mapping.Tests(237). The twoProduct_ToModelsnapshots gain onlyIsReadOnly: false.Steps 1-5 were run on a fresh install with sample data. Vendor was covered by unit tests only, and so were the address, customer, product and specification attribute screens. Steps 6-8 were run on a fresh install with a second language.
/Store/Product/Edit/{id}. Save, Save and continue, Delete and the user field form are gone, and Copy is still there.Foo\ <b>x</b>, then choose it in a course's product popup. The field shows that exact text and the popup closes.