App side: - Per-route CSP: /staff/report now sets frame-ancestors 'self' <CIVI_BASE_URL origin> and drops X-Frame-Options so the CiviCRM extension can iframe it. All other routes keep frame-ancestors 'none' + X-Frame-Options: DENY via a path-negation source. - Staff page recognises ?frame=1 and renders without SiteHeader/ SiteFooter so it fills the iframe cleanly. - StaffReportView posts its scrollHeight to the parent window via postMessage when framed; the Civi tab listens and auto-resizes the iframe (no nested scrollbar). Anchor strip drops its sticky positioning in frame mode since there's no internal scroll. CiviCRM extension (civi-extension/webform-mw/, key webform-mw): - info.xml + main hook file (webform_mw.php) implementing hook_civicrm_tabset to add an 'Engagement Report' tab to Organization contact-view pages. - CRM/WebformMw/Page/Tab.php + Smarty template render an iframe pointing at <WEBFORM_MW_APP_URL>/staff/report?org=<cid>&key=&frame=1, with a postMessage listener that validates event.origin against the configured app URL before resizing. - Config via PHP constants in civicrm.settings.php (WEBFORM_MW_APP_URL, WEBFORM_MW_STAFF_KEY) or matching env vars. Help banner shown when unconfigured. - README documents install, config, behaviour, security caveats.
104 lines
4.4 KiB
Markdown
104 lines
4.4 KiB
Markdown
# WebForm-mw — CiviCRM extension
|
|
|
|
Adds an **Engagement Report** tab to Organization contact-view pages that
|
|
embeds the FCI Co-op Survey staff report
|
|
(`https://survey.fci.coop/staff/report`) in an iframe. The tab shows the
|
|
report for the current organization, scoped by the contact id in the URL.
|
|
|
|
The embedded app handles its own auth via a shared staff secret. The
|
|
extension is otherwise read-only and adds no Civi tables, custom fields,
|
|
or scheduled jobs.
|
|
|
|
## Install
|
|
|
|
1. Copy the entire `webform-mw/` directory to your CiviCRM extensions
|
|
directory (typically `<civi-root>/sites/default/ext/` or wherever
|
|
`[civicrm.extensionsDir]` points in your `civicrm.settings.php`).
|
|
- The directory name on disk must be `webform-mw` (matching `<key>` in
|
|
`info.xml`).
|
|
2. In CiviCRM:
|
|
`Administer → System Settings → Extensions → Add new → Refresh`,
|
|
then click **Install** next to "WebForm-mw".
|
|
3. Configure (see next section). The tab will be hidden until both
|
|
settings are present.
|
|
|
|
## Configuration
|
|
|
|
The extension reads two values, in this order:
|
|
|
|
1. Constants in `civicrm.settings.php` (preferred):
|
|
|
|
```php
|
|
define('WEBFORM_MW_APP_URL', 'https://survey.fci.coop');
|
|
define('WEBFORM_MW_STAFF_KEY', '...the STAFF_REPORT_KEY shared with the app...');
|
|
```
|
|
|
|
2. Or environment variables (`WEBFORM_MW_APP_URL`, `WEBFORM_MW_STAFF_KEY`)
|
|
set wherever PHP-FPM / the web server reads its environment from.
|
|
|
|
`WEBFORM_MW_STAFF_KEY` must match the `STAFF_REPORT_KEY` configured on the
|
|
Next.js app (Amplify environment / SSM Parameter Store). The two are the
|
|
same shared secret; rotate them together.
|
|
|
|
`WEBFORM_MW_APP_URL` is the public base URL of the WebForm-mw deployment
|
|
(no trailing slash). Production: `https://survey.fci.coop`.
|
|
|
|
When either value is missing, the tab body shows a help banner with the
|
|
exact configuration snippet to paste, so anyone installing the extension
|
|
without prior context can self-serve.
|
|
|
|
## Behaviour
|
|
|
|
- Tab title: **Engagement Report**.
|
|
- Visible only on **Organization** contacts (Individuals and Households
|
|
see no tab). The check happens server-side in the tabset hook.
|
|
- Tab body is an iframe pointing at
|
|
`${WEBFORM_MW_APP_URL}/staff/report?org=<cid>&key=<secret>&frame=1`.
|
|
- `frame=1` tells the embedded app to suppress its site header/footer
|
|
and emit a `postMessage({type:"webform-mw-height", height})` payload
|
|
on render and on resize. The tab's small inline script listens for
|
|
this message and auto-sizes the iframe so there's no nested scrollbar.
|
|
- The script validates the postMessage `event.origin` against the
|
|
configured `WEBFORM_MW_APP_URL` origin before resizing.
|
|
|
|
## Security notes
|
|
|
|
- The staff secret travels with each tab render inside the iframe `src`.
|
|
Anyone permitted to view the Engagement Report tab (i.e., anyone with
|
|
CiviCRM access) can read the URL in their browser's DevTools and reuse
|
|
the secret to view any org's report. Acceptable model if "CiviCRM
|
|
access" and "should view any staff report" overlap; otherwise consider
|
|
upgrading the embedded app to per-user signed tokens and minting them
|
|
in the page controller.
|
|
- The extension uses `access CiviCRM` as its access argument — anyone
|
|
with that permission sees the tab on Organization contacts. Tighten by
|
|
changing the `<access_arguments>` value in `xml/Menu/webform_mw.xml`
|
|
to a more specific permission (e.g., `view all contacts`) and
|
|
reinstalling.
|
|
- The embedded app's CSP (`frame-ancestors`) must include the CiviCRM
|
|
origin or the iframe will refuse to render. The Next app reads
|
|
`CIVI_BASE_URL` at build time and adds its origin to the staff route's
|
|
CSP automatically. Confirm with `curl -I <app>/staff/report` after
|
|
deploy — you should see `Content-Security-Policy: ... frame-ancestors
|
|
'self' https://<your-civi-host> ...`.
|
|
|
|
## Files
|
|
|
|
- `info.xml` — extension manifest. Key `webform-mw`, type `module`.
|
|
- `webform_mw.php` — `hook_civicrm_tabset` + config readers.
|
|
- `CRM/WebformMw/Page/Tab.php` — page controller for the tab snippet.
|
|
- `templates/CRM/WebformMw/Page/Tab.tpl` — iframe + height-listener.
|
|
- `xml/Menu/webform_mw.xml` — registers the
|
|
`civicrm/contact/view/engagement-report` URL.
|
|
|
|
## Versions tested
|
|
|
|
- CiviCRM 5.50+
|
|
- PHP 7.4+ / 8.x
|
|
- Tested against Backdrop-as-host and Drupal-as-host CiviCRM deployments.
|
|
|
|
## Uninstalling
|
|
|
|
`Administer → Extensions → Disable`, then `Uninstall`. Removes nothing
|
|
from the database; the extension stores no Civi data of its own.
|