Repository navigation
[5.8] GraphQL: settings queries, Commerce element queries/mutations, product drafts, and authenticated requests - #4397
Draft
brandonkelly wants to merge 15 commits into
Draft
brandonkelly wants to merge 15 commits into
brandonkelly wants to merge 15 commits into
Conversation
Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
Follows craftcms/cms#20055: each gets a settings.* schema component that adds plural/singular queries. Product types also add a productType field to products. Also fixes the product/variant field layout fixtures, which had the wrong element types, so product GraphQL queries can run in tests. Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
Adds orders/order/orderCount queries, enabled per store via orders.<storeUid>:read schema components. Orders expose their line items, addresses, and (when the schema allows) their store and order status. Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
Follows craftcms/cms#20147: Commerce's schema components now declare an `authenticated` key, so OAuth-authenticated requests get access based on the user's permissions. - Product types map to the “View products” permission for each product type - “Query for product types” requires control panel access, like CMS sections - Stores and order statuses are available to everyone - Orders are available to everyone, but limited to the user's own orders unless they have the “Manage orders” permission Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
The craftcms/cms update pulled in addressing 2.3.2, whose updated GB subdivisions break StoreTest. Nothing here needs the newer version. Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
- save_<productType>_Product creates/updates products. Its `variants` argument sets the full list of variants, like saving the product in the control panel, which is needed to create a product (live products require a variant). - save_<productType>_Variant saves an individual variant, and deleteProduct and deleteVariant delete them. - New per-product-type create/save/delete schema components, mapped to the matching product type permissions for authenticated requests. The product and variant type generators now implement SingleGeneratorInterface so mutations can return a specific product type's GraphQL type. Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
save_Order follows the control panel's order save: it sets the customer (by ID, or by email, creating a user if needed), status, coupon, shipping method, addresses, custom fields, and the full list of line items, and `isCompleted: true` marks the order as complete after saving. New orders get the `remote` origin. deleteOrder deletes an order. Per-store create/save/delete schema components map to the “Edit orders” and “Delete orders” permissions for authenticated requests. Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
…fers These element types had no GraphQL support, so each gets a type, queries, and mutations: - Subscriptions: query, save custom fields, and delete (without canceling on the gateway, like the control panel's default). Authenticated users only see their own subscriptions unless they can manage subscriptions. - Donation: query, and save its SKU, availability, and status. Donation now implements canSave() based on “Manage donation settings”. - Inventory transfers: query, create/save drafts with their items, mark them as pending, and delete drafts. Pending transfers' locations and items are locked, since marking them pending updates inventory. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d
Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d Co-authored-by: Amp <amp@ampcode.com>
Subscriptions are more or less deprecated, so they don’t get GraphQL queries or mutations after all. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d
Product save mutations now take a `sortOrder` argument, which determines the product's variants and their order, and a `variants` argument with data for new and updated variants, keyed by ID or `new:N`, like Matrix fields' `sortOrder` and `entries`. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d
Products get the same draft support as entries: - `save_<productType>_ProductDraft` saves existing drafts (by `draftId`) or creates unpublished drafts (`asUnpublishedDraft`). - `createProductDraft` and `publishProductDraft` create and apply drafts. - Products' GraphQL data includes the draft and revision fields. Variants changed via a draft are duplicated as drafts first, like Matrix entries, so the canonical product's variants stay untouched until the draft is published. Authenticated requests always create drafts for the authenticated user, and only see their own provisional drafts. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d
Transfer::canView(), canSave(), and canDelete() checked `commerce-manageTransfers`, but the registered permission (also checked by TransfersController) is `commerce-manageInventoryTransfers`. Only users who had the permission before the m240815_035618_fix_transfer_permission migration had both, so authenticated GraphQL requests couldn't manage transfers. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d
It shipped via 5.x (#4399), so it's already in CHANGELOG.md. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1850a-a3a4-7642-a937-0ac503e1d04d
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.
Summary
Requires
craftcms/cmsdev-feature/authenticated-graphql(aliased as 5.12.0 so ckeditor/redactor resolve).commerceguys/addressingstays at 2.2.5.Non-element queries (following craftcms/cms#20055):
settings.producttypes:readproductTypes,productTypeproductTypeon productssettings.stores:readstores,storestoreon orders and order statusessettings.orderstatuses:readorderStatuses,orderStatusorderStatuson ordersElement queries and mutations:
save_<type>_Product(withsortOrder+variants),save_<type>_ProductDraft,createProductDraft,publishProductDraft,save_<type>_Variant,deleteProduct,deleteVariantorders,order,orderCountsave_Order(customer, status, coupon, shipping method, addresses,lineItems: [...],isCompleted),deleteOrderdonationsave_Donationtransfers,transfer,transferCountsave_Transfer(locations,details: [...],markAsPending),deleteTransferSubscriptions are intentionally left out, since they're more or less deprecated.
Notes for review:
sortOrderlists the variant IDs the product should have, in order, withnew:1,new:2… for new ones.variantsholds data for new and changed variants only. Variants missing fromsortOrderare deleted; withoutsortOrder, the existing variants are kept and only updated.draftId,provisional,asUnpublishedDraft,draftName,draftNotes), and the same draft mutations under product-specific names. Variants changed through a draft are duplicated as drafts first, like Matrix's nested entries, so the live product is untouched until the draft is published. Authenticated requests always create drafts as the authenticated user and only see their own provisional drafts.Product::canCreateDrafts()returnstruefor everyone, so any user with the product type's save permission can edit another user's saved draft. The control panel behaves the same way.lineItemsanddetailsstill take a full list: items with anidare updated, items without one are created, and the rest are removed.save_OrderwithisCompleted: truecallsmarkAsComplete()after saving, likeOrdersController::actionSave().emailcreates a user viaensureUserByEmail(), so user authorization is checked before anything is changed. New orders get theremoteorigin.markAsPendingupdates inventory inTransfer::afterSave(). Receiving stays in the control panel.Transfer::canView/canSave/canDeletecheckedcommerce-manageTransfers, but the registered permission (andTransfersController) iscommerce-manageInventoryTransfers. This blocked authenticated transfer mutations, so they now check the registered permission.Donation::canSave()is new (“Manage donation settings”), so element authorization works for authenticated requests.productType(products) andlineItems,orderStatus,store(orders) are now reserved field handles.SingleGeneratorInterface(generateType()), so mutations can return a specific product type's type.craft\elements\Product/Variant, so product GraphQL queries can run in tests.Evidence
tests/unit/gql/AuthenticatedSchemaTest.phpandtests/unit/gql/MutationsTest.php(fixtures,Gql::executeQuery):commerce-viewProductTypeon T-Shirts only gets T-shirt products/variants;orderCountis 3 for the owner, 0 for another customer, 3 withcommerce-manageOrders.save_tShirts_Product(sortOrder: ["new:2", "new:1"], variants: [...])creates the variants in that order.variantswithoutsortOrderupdates one variant and ignores the unlisted new one.sortOrder: [$large]deletes the other variant.accessCp+ save permission:createProductDraftignorescreatorId;save_tShirts_ProductDraftchanges the title and a variant's price while the live product and variant stay unchanged;products(drafts: true)returns the draft;publishProductDraftapplies both.saveProductTypebut notcreateProductTypecan update a product but getsUnable to perform the action.when creating one.save_Order(email, lineItems)→ cart; thenlineItems: [{purchasableId: blue, qty: 3}], isCompleted: true→ completed,dateOrderedset, onlyhct-blueremains. A customer without “Edit orders” gets noorders.*:savescope; with it,save_Ordersaves.3 is identical to 0), the variant draft duplication (Failed asserting that 99.0 matches expected 19.99), the pending-transfer lock, or the transfer permission fix (save_Transfer→Unable to perform the action.) each fails its test. With them: all pass.Scratch checks (not committed):
save_tShirts_ProductDraft(asUnpublishedDraft: true, …)with a new variant, thenpublishProductDraft, gives a live product with that variant.accessCp, andsave_Donationneeds “Manage donation settings”.