fix(instanda): content-based dedupe, resubmit guards, PII retention
- F-01: derive the dedupe key from submission content (form id + mapped values) instead of a per-request token, so identical re-POSTs / retry-after-error collapse to the existing quote. Keeps the per-request lock; adds a content lock race guard and a 30-min recent_delivered_by_dedupe short-circuit. - F-12: refuse resubmit of an already-delivered transaction (AJAX + worker). - F-18: scope the resubmit self-recovery guard to the content dedupe key so a customer's different event is no longer skipped. - F-05: anonymize PII on stale failed/pending rows via the cron; add delete_by_email and wire WP's Erase Personal Data eraser. - F-13: exempt stranded delivered rows (no entry_id) from the retention purge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,9 @@ final class Instanda_AddOn extends \GFFeedAddOn {
|
||||
|
||||
add_action('esp_instanda_resubmit', Guard::wrap([Resubmit_Handler::class, 'run']));
|
||||
|
||||
// Data-subject erasure: wire customer transactions into WP's Erase Personal Data tool.
|
||||
add_filter('wp_privacy_personal_data_erasers', Guard::wrap([$this, 'register_privacy_erasers']));
|
||||
|
||||
// Keep Gravity Forms' scripts out of Jetpack Boost's JS concat/defer, which
|
||||
// otherwise break GF's AJAX init and the post-submit INSTANDA redirect.
|
||||
Boost_Compat::register();
|
||||
@@ -402,6 +405,27 @@ JS;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ privacy */
|
||||
|
||||
public function register_privacy_erasers($erasers) {
|
||||
$erasers['esp-instanda'] = [
|
||||
'eraser_friendly_name' => 'INSTANDA quote transactions',
|
||||
'callback' => [$this, 'privacy_erase'],
|
||||
];
|
||||
return $erasers;
|
||||
}
|
||||
|
||||
/** WP Erase Personal Data callback - deletes all INSTANDA transactions for an email. */
|
||||
public function privacy_erase($email, $page = 1) {
|
||||
$removed = (new Transaction_Store())->delete_by_email((string) $email);
|
||||
return [
|
||||
'items_removed' => $removed > 0,
|
||||
'items_retained' => false,
|
||||
'messages' => [],
|
||||
'done' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ admin pages */
|
||||
|
||||
public function register_admin_pages() {
|
||||
@@ -592,6 +616,9 @@ JS;
|
||||
if ($tx === null) {
|
||||
wp_send_json_error(['message' => 'Not found']);
|
||||
}
|
||||
if ($tx->status === Tx_Status::Delivered->value) {
|
||||
wp_send_json_error(['message' => 'Already delivered - resubmitting would create a duplicate quote']);
|
||||
}
|
||||
if ($tx->environment !== Config::environment()->value) {
|
||||
wp_send_json_error(['message' => 'Cross-environment resubmit is blocked']);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user