Skip to content

feat(mgr-api): category-scoped PUT для inline-edit product data - #474

Open
Ibochkarev wants to merge 2 commits into
betafrom
feat/issue-455-category-scoped-product-data
Open

feat(mgr-api): category-scoped PUT для inline-edit product data#474
Ibochkarev wants to merge 2 commits into
betafrom
feat/issue-455-category-scoped-product-data

Conversation

@Ibochkarev

Copy link
Copy Markdown
Member

Описание

Category-scoped маршрут для inline-edit в гриде «Товары категории»: scope берётся из URL, а не из body category_id.

  • PUT /api/mgr/categories/{categoryId}/products/{productId}/data + PermissionMiddleware(msproduct_save)
  • Scope через CategoryProductsListService::isProductInCategoryScope() (общий helper CategoryProductScopePolicy::allowedParentCategoryIds с фильтром списка)
  • 403 + lexicon ms3_err_product_not_in_category_scope при товаре вне scope (direct / nested)
  • Vue: useCategoryProductsInlineEdit → новый URL; ProductDataFields.vue — без изменений (PUT /product-data/{id})

Closes #455

Тип изменений

  • Исправление бага (non-breaking change)
  • Новая функциональность (non-breaking change)
  • Breaking change
  • Рефакторинг
  • Документация

Связанные Issues

Closes #455

Follow-up к #444 / #454. Дополняет #418 (scope policy, другой endpoint).

Как это было протестировано?

cd core/components/minishop3
composer ci:php   # exit 0

cd ../../../vueManager
npm run lint -- --no-error-on-unmatched-pattern \
  src/composables/useCategoryProductsInlineEdit.js \
  src/components/CategoryProductsGrid.vue   # exit 0
  • php -l — все PHP под src/migrations/tests

  • Smoke: CategoryProductScopePolicyTest.php + 18 существующих тестов — exit 0

  • Ручное тестирование

  • Автоматические тесты

  • Тестирование на разных версиях PHP/MODX

Чеклист

  • Код соответствует стилю проекта
  • Лексиконы en/ru (ms3_err_product_not_in_category_scope)
  • Global PUT /product-data/{id} не изменён
  • CHANGELOG (release-time)

Дополнительные заметки

  • nested принимается из query или body; URL-параметры {id} / {productId} не перебиваются body (array_merge($data, $_GET, $params)).
  • Отдельной Manager API документации в репо нет — пункт AC «документация» n/a.
  • После merge fix(product-data): category scope для inline-edit PUT #454 body category_id на /product-data/{id} можно deprecate отдельно (out of scope).

@Ibochkarev Ibochkarev added the enhancement New feature or request label Jul 29, 2026
@Ibochkarev
Ibochkarev requested a review from biz87 July 29, 2026 03:31
@Ibochkarev
Ibochkarev force-pushed the feat/issue-455-category-scoped-product-data branch from 3fe9853 to 87a6c43 Compare July 29, 2026 11:36
Add PUT /categories/{id}/products/{productId}/data with URL-bound scope
check; switch CategoryProductsGrid to the new route (#455).
Apply CategoryProductDocumentPolicy save check on the updateProductData
inline-edit path (#473 pattern) and resolve scope via
CategoryProductScopePolicy through findInCategory() instead of the
separate isProductInCategoryScope() bool-only getObject round-trip.

- Import CategoryProductDocumentPolicy (cherry-picked from #473)
- Refactor CategoryProductScopeService::findInCategory nested branch to
  delegate to CategoryProductScopePolicy::isParentInScope
- Replace isProductInCategoryScope() call in updateProductData with
  scopeService()->findInCategory() (single lookup, yields product for ACL)
- Add 403 save-policy guard + logDocumentPolicyDenied helper
- Tests: CategoryProductDocumentPolicyTest + ACL denial / out-of-scope
  cases in CategoryProductsControllerScopeTest; stubs support per-product
  policies and lexicon
@Ibochkarev
Ibochkarev force-pushed the feat/issue-455-category-scoped-product-data branch from 508df77 to fed58c0 Compare July 29, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Category-scoped PUT для inline-edit product data (вместо body category_id)

1 participant