Repository navigation
feat(quant_webform): Quant Forms for Webform, managed in Drupal (2.3.0) - #264
Merged
Merged
Conversation
…and search page setup
Adds quant_api.credentials (settings.php override, then the OAuth connection, then the typed token), the platform and auth_method settings with schema, and an update hook that sets the platform from an existing endpoint. The client, quant_search and the seed form no longer read api_token from config.
The editor approves the site in the Quant dashboard (client drupal-quant, S256 PKCE, state bound to the session and user) and picks a project. The module limits the token to that project, reads the project's write token and keeps both outside config. Change project starts a new login; the old project stays until the new choice. Cron refreshes the token with the portal's rotation rules; a database copy never refreshes the original site's tokens. Multi-domain sites stay on token connect. Adds drush quant:auth-status, kernel tests for the refresh rules and a functional test against a fake dashboard.
…ort fetches The content push passes form_enabled and form_config from the event metadata, and the client gets sendFormConfig() for POST /v1/form. The export fetch now always sends the signed quant-token (before, only with content drafts on), so a render can tell that Quant is exporting it.
A page that shows a Webform publishes with its Quant Forms config: mandatory fields that are always required, Drupal's own fields removed, honeypot and reCAPTCHA, the confirmation message without tokens, the first email handler and an optional Slack webhook kept outside config. Saving a Webform publishes its pages; closing or deleting it turns Quant Forms off. Adds a per-form Quant Forms setting with a support report, a Forms settings page with Register all forms, drush quant:webform-register and the support matrix.
…atic site On a Quant export render every wizard page is in the page. The script shows one step at a time, checks each step (HTML validation, required checkbox groups, #states), builds the review step, and posts once to Quant Forms with Accept: application/json. Repeated multipart names are renamed so that every file of a multi-file field is kept. Confirmations show in place; url confirmations redirect. Without JavaScript the form posts as one page.
An unconnected site sent requests with empty credentials, for example a PATCH /v1/unpublish when a search page was deleted. Every call now fails closed before any request, with one log line that says why. (cherry picked from commit 7c2edb2)
An unconnected site sent requests with empty credentials, for example a PATCH /v1/unpublish when a search page was deleted. Every call now fails closed before any request, with one log line that says why.
A newsletter Webform in the footer was on every page, and a page with two Webforms registered only the first, so the second form's submissions went to the wrong config. On an export render a Webform with its own page now posts there from any page that embeds it, and Quant Forms is registered only on the page a form posts to.
…d endpoint, and a rotated write token recovers - A copy of the database (fingerprint mismatch) gets no write token in login mode, and the settings page says to log in on the copy. - The platform chosen for a login is saved only when the login completes, so a cancelled login never re-points a working token connection. - In login mode the endpoint is the platform's own host; a custom endpoint (a settings.php override aside) no longer receives the hidden token. - Cron re-reads the project write token with the login after a refresh and at least daily, so a token rotated in the dashboard recovers.
…ache context The static form behaviour switched on whenever the quant-token header was present, and with content drafts off that header is never validated. It now needs a token this site signed that has not expired (TokenManager::isGenuine). The render cache varies by a two-value context (quant_export: export or live) instead of the header value, which changed on every fetch. The purger records no traffic with content drafts off, as before the export fetch always sent the token.
- Opt-in: every Webform is off until ticked (update hook changes nothing), so an upgrade never replaces settings made by hand in the dashboard. Register the ticked forms acts only on ticked forms. - A Quant Forms section in each Webform's settings: notification email (from the handler, set in Drupal, or none), Slack with a per-form webhook, a honeypot field, reCAPTCHA v2, the spam check, country and IP blocklists, and what shows after a submit. Secrets are in KeyValue, masked, never in config. Features Quant cannot do are listed greyed out with the reason. The pushed config carries notification_settings.managed_by = drupal. - mandatory_fields lists only element types that post their own key and that anonymous visitors see (not likert, datetime, email_confirm, select_other, radios_other, #private, #access_create_roles). - The module turns Quant Forms off on a page it registered when the page loses its form, the form is opted out, unsupported, closed (also by its schedule, on cron) or deleted, using a map of the pages it registered. Pages that never had a ticked form are left alone. - Release notes for 2.3.0 with the upgrade note.
Found on the demo site: "[webform:title]: [webform_submission:values:topic]"
became ": {{topic}}".
…rite token - A copy (fingerprint mismatch) logs an error that names the differing components, shows on the status report and the settings page, and offers "This is the same site" (configure quant), which stores the fingerprint again so the site publishes. The fingerprint docblock is corrected. - A 401 from the content API re-reads the project write token with the login, at most once every 15 minutes, so a token rotated in the dashboard recovers on the next publish.
…and tighten secrets - N2: turning Quant Forms off sends a config without managed_by (released_by drupal), so the dashboard can manage the page again. - N4: the open state is stored when a page registers; cron turns off every registered form that is closed, opted out or deleted, and a failed turn-off stays registered and runs again on the next cron. - N5: reCAPTCHA cannot be on without a secret key; the report says so. - N6: deleting a Webform deletes its secrets. - N7: secret changes are held from validation and stored in presave, so only a successful save stores them; Remove works on an unticked form. - N8: only a genuine signed token skips the page cache.
…ver-side dashboard - $settings['quant_api_endpoint_url'] names the content API endpoint in every mode (for example a stage host behind basic auth). It is never editable in the UI; the settings page and drush show it without its userinfo, and an HTTP middleware moves userinfo from any request URI into an Authorization header before the request is sent, so it never reaches a message or a log. - $settings['quant_api_dashboard_internal_url'] is the dashboard address for server-to-server calls (token, refresh, projects, limit, write token); the browser redirect keeps quant_api_dashboard_url. Default: the same.
The dashboard token response names the user but not the organisations, so a real login found no projects. The test dashboard now answers like the real one. A dashboard fixed in settings.php also sets the starting platform.
Without the Redirect module, a changed alias (for example Pathauto after a title change) left a 404 at the old URL on the static site. The old alias now gets a 301 to the new one, for published nodes and terms only. With the Redirect module on, its own redirect entity is pushed as before.
Installing the module failed strict config schema checks for views.view.quant_metadata_node.
…leted A deleted published node or term sent its internal-path redirect again, because the entity is still published during delete. /node/N kept a 301 to a page that no longer exists. Deleted content now unpublishes its internal paths (the prefixed one only, for one deleted translation).
The file_link formatter settings of views.view.quant_metadata_file carried a copy of Views UI options, which fails strict config schema checks.
Log out deleted the token only in Drupal, so it stayed valid on the portal until it expired. The module now calls POST /api/oauth/revoke first (best effort: an older dashboard or a failed call is logged, and the local connection is deleted in every case).
The core schema fixes from fix/content-paths make the shipped views valid.
…s; review fixes From the release review: - Log out (or a token save) on a copy of another site's database revoked the original site's login. A copy now only forgets the login locally. - Change project and a failed project pick now end the login they replace or discard, instead of leaving it valid at the dashboard. - An expired access token with a refresh token stored no longer shows "The Quant login needs renewing": the next request renews it. - The settings page decides on its success and error messages from a session flag and the client's own unreachable flag, not from other queued messages, so a token save shows "Connected" again. - The endpoint override warning no longer shows credentials in the URL.
…cting a renamed page
…p, not escaped text
isGenuine() accepted a signed export token on any path, so one token switched on the static-form render of every page until it expired. It now needs the path that the token was made for, like validate() in strict mode.
With a dashboard override outside quantgov.cloud (for example a local QuantGov dashboard), the platform radio defaulted to QuantCDN while the saved platform was QuantGov, so saving the settings form for another reason logged the site out.
Pushes run after the response is sent (and from the queue on cron), so a failed push was only in the log. Each failure is now kept for the site, with a short reason and never the error text, until a later push of the same page succeeds. Editors (configure quant or access content overview) see a warning on their next page view, and the status report lists the pages. Also: a blank or invalid pagination selector no longer raises PHP warnings.
From review: a cached editor page did not show a new failure (the list now has a cache tag, invalidated when it changes); a file that Quant already had (MD5 matches) never cleared its failure; concurrent queue workers could lose entries (the list changes under a lock); the message pointed editors without access to the status report.
The export fetch signs the route with the base path (/drupal/contact) while the request path is /contact, so a site in a subdirectory lost the static form render after the token was bound to its path.
…ts in CI CI (Drupal 11.1) failed: config/install/quant.settings.yml held 0/1 for keys the schema types as boolean. Drupal 11.1 installs module config as trusted data, without casting it, so the strict schema check saw integers. Drupal 11.4 casts on save, which is why a local 11.4 run passed. The install config now holds true/false, and update 9009 casts integers that existing sites stored. CI now starts a PHP web server and sets SIMPLETEST_BASE_URL, so the functional tests run instead of failing on the missing base URL.
CI (Drupal 11.1, which installs module config without casting it) still failed on quant.token_settings. A new kernel test checks every config/install and config/optional file of quant and its submodules against its schema, as the files are on disk, and lists every mismatch in one run. It found: - quant.token_settings disable/strict and the Quant Search entity settings stored 0/1 for booleans: now true/false; update 9009 casts them on existing sites. - The quant_metadata Views field option kept 0 for each unticked key (from checkboxes), against its list-of-strings schema: the shipped views keep only the ticked keys, the field drops unticked keys on save, and update 9010 filters saved views. CI also installs drupal/webform, so the Quant Forms tests can run.
… save happened The settings test loaded the webform through the entity cache of the test process, so after the browser saved it, the second load could return the copy from before the save (seen on Drupal 11.1 in CI: no 'enabled' key). The test now resets that cache before each load and first checks the "has been saved" message, so a failed save and a stale read are told apart.
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.
Part of 2.3.0. Based on #263 (
feat/oauth-connect), which includes #262; merge those first.Quant Forms for Webform: an opted-in Webform takes submissions on the static site through Quant Forms (multi-page wizards, conditions, composites, files), with its notifications and spam settings managed in Drupal. Opt-in is per Webform; nothing changes on upgrade.
Changes from the staging rehearsal
webform.webform.third_party.quant_webform; Webform readswebform.settings.third_party.*.sendFormConfig()catches every Guzzle error, like the rest of the client.RELEASE-NOTES-2.3.0.md).How it was tested