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.
36 lines
1.1 KiB
PHP
36 lines
1.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Engagement Report tab page.
|
|
*
|
|
* Loaded as an AJAX snippet by the contact-view tabset (snippet=1). The
|
|
* template emits a single iframe pointing at the WebForm-mw staff report
|
|
* plus a small postMessage listener that auto-sizes the iframe to the
|
|
* report's content height.
|
|
*/
|
|
class CRM_WebformMw_Page_Tab extends CRM_Core_Page {
|
|
|
|
public function run() {
|
|
$cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
|
|
|
|
$appUrl = _webform_mw_app_url();
|
|
$key = _webform_mw_staff_key();
|
|
$configured = ($appUrl !== '' && $key !== '');
|
|
|
|
if ($configured) {
|
|
$src = $appUrl . '/staff/report'
|
|
. '?org=' . urlencode((string) $cid)
|
|
. '&key=' . urlencode($key)
|
|
. '&frame=1';
|
|
$this->assign('iframeSrc', $src);
|
|
// Expose just the app origin so the parent-side postMessage
|
|
// listener can validate event.origin without leaking the secret.
|
|
$this->assign('appOrigin', parse_url($appUrl, PHP_URL_SCHEME)
|
|
. '://' . parse_url($appUrl, PHP_URL_HOST));
|
|
}
|
|
$this->assign('configured', $configured);
|
|
|
|
parent::run();
|
|
}
|
|
}
|