Please select at least one category.'; $out .= dsc01_render_landing($association_slug, $access, $codes, $narrative); return $out; } // Build spool envelope $cfg_raw = @file_get_contents('addon/vs01/config.json'); $cfg = $cfg_raw ? json_decode($cfg_raw, true) : []; $assoc = $cfg['associations'][$association_slug] ?? []; $envelope = dsc01_build_spool_envelope( $codes, $narrative, $association_slug, $assoc['channel_id'] ?? '', $access ); $result = dsc01_post_to_orchestrator($envelope); if ($result === true) { $assoc_name = dsc01_h($assoc['name'] ?? $association_slug); return '
Your checklist for ' . $assoc_name . ' has been submitted. Return to ' . $assoc_name . '
'; } $out = '
Submission failed. Please try again or contact the operator.
' . dsc01_h($result) . '
'; $out .= dsc01_render_landing($association_slug, $access, $codes, $narrative); return $out; } // --------------------------------------------------------------------------- // SPOOL ENVELOPE // --------------------------------------------------------------------------- function dsc01_build_spool_envelope($dsc_codes, $narrative, $association_slug, $channel_id, $standing) { return [ 'addon' => 'dsc01', 'contract_version' => '1.0', 'association_slug' => $association_slug, 'association_channel_id' => (string) $channel_id, 'submitted_at' => date('c'), 'standing' => $standing, 'dsc_codes' => $dsc_codes, 'narrative' => $narrative, ]; } // --------------------------------------------------------------------------- // ORCHESTRATOR POST // --------------------------------------------------------------------------- function dsc01_post_to_orchestrator($envelope) { $config = dsc01_load_config(); $receiver_url = $config['receiver_url'] ?? ''; $node_token = $config['node_token'] ?? ''; if (!$receiver_url) { logger('dsc01_spool: receiver_url not configured'); return 'Orchestrator receiver URL not configured.'; } $payload = json_encode($envelope); if ($payload === false) { logger('dsc01_spool: failed to encode envelope'); return 'Failed to encode submission.'; } $ch = curl_init($receiver_url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Node-Token: ' . $node_token, ], ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curl_error = curl_error($ch); curl_close($ch); if ($curl_error) { logger('dsc01_spool: curl error: ' . $curl_error); return 'Network error: ' . $curl_error; } if ($http_code === 200 || $http_code === 201) { return true; } logger('dsc01_spool: orchestrator returned HTTP ' . $http_code . ': ' . $response); return 'Orchestrator error (HTTP ' . $http_code . ').'; } // --------------------------------------------------------------------------- // CONFIG // --------------------------------------------------------------------------- function dsc01_load_config() { $path = 'addon/dsc01/config.json'; $raw = @file_get_contents($path); if ($raw === false) return []; $data = json_decode($raw, true); return (json_last_error() === JSON_ERROR_NONE) ? $data : []; }