['Condominium','Master','CIC','Unincorporated','UNK','Disputed'], 'assoc_mgmt_certified' => ['Yes','No','UNK'], 'assoc_sos_standing' => ['Active','Dissolved','UNK'], 'assoc_declaration_recorded' => ['Yes','No','UNK'], ]; } function assoc_validate_select($field, $value) { $allowed = assoc_allowed_values(); if (!isset($allowed[$field])) return true; return in_array($value, $allowed[$field], true); } function assoc_field_names() { return [ 'assoc_legal_name', 'assoc_type', 'assoc_statute', 'assoc_street', 'assoc_city', 'assoc_county', 'assoc_state', 'assoc_zip', 'assoc_placekey', 'assoc_website', 'assoc_buildings', 'assoc_units', 'assoc_year_built', 'assoc_stories', 'assoc_mgmt_company', 'assoc_mgmt_contact', 'assoc_mgmt_certified', 'assoc_sos_id', 'assoc_sos_standing', 'assoc_declaration_recorded', 'assoc_declaration_instrument', 'assoc_registered', 'assoc_updated', ]; } // ---------------------------------------------------------------------------- // PROFILE EDIT HOOK // ---------------------------------------------------------------------------- function assoc_profile_edit_hook(&$b) { if (!local_channel()) return; $channel = App::get_channel(); $slug = assoc_slug_from_address($channel['channel_address'] ?? ''); if (!$slug) return; $entry = assoc_get($slug); if (!$entry) return; // Only channel owner may edit if (local_channel() !== intval($channel['channel_id'])) return; if (function_exists('head_add_css')) { head_add_css('/addon/assoc_profile/view/css/assoc_profile.css'); } $b['html'] .= assoc_render_edit_form($slug, $entry); } // ---------------------------------------------------------------------------- // PROFILE VIEW HOOK // ---------------------------------------------------------------------------- function assoc_profile_view_hook(&$o) { $uid = intval(App::$profile['profile_uid'] ?? 0); if (!$uid) return; $r = q("SELECT channel_address FROM channel WHERE channel_id = %d LIMIT 1", intval($uid)); if (!$r) return; $slug = assoc_slug_from_address($r[0]['channel_address']); $entry = assoc_get($slug); if (!$entry) return; if (function_exists('head_add_css')) { head_add_css('/addon/assoc_profile/view/css/assoc_profile.css'); } $o .= assoc_render_view($entry); } // ---------------------------------------------------------------------------- // RENDER — VIEW // ---------------------------------------------------------------------------- function assoc_render_view($entry) { $labels = assoc_field_labels(); $groups = assoc_field_groups(); $out = '
'; $out .= '

Association Diagnostic Profile

'; foreach ($groups as $group_label => $fields) { $out .= '
'; $out .= '
' . assoc_h($group_label) . '
'; foreach ($fields as $field) { $val = $entry[$field] ?? ''; if ($val === '') $val = '—'; if (in_array($val, ['UNK'])) $val = 'Unknown — not yet verified'; $out .= '
'; $out .= '' . assoc_h($labels[$field] ?? $field) . ': '; $out .= '' . assoc_h($val) . ''; $out .= '
'; } $out .= '
'; } $out .= '
'; return $out; } // ---------------------------------------------------------------------------- // RENDER — EDIT FORM // ---------------------------------------------------------------------------- function assoc_render_edit_form($slug, $entry) { $labels = assoc_field_labels(); $groups = assoc_field_groups(); $allowed = assoc_allowed_values(); $out = '
'; $out .= '

Association Diagnostic Profile

'; $out .= '
'; $out .= ''; $out .= assoc_csrf_token(); foreach ($groups as $group_label => $fields) { $out .= '
'; $out .= '
' . assoc_h($group_label) . '
'; foreach ($fields as $field) { if (in_array($field, ['assoc_registered', 'assoc_updated'])) continue; $val = $entry[$field] ?? ''; $label = $labels[$field] ?? $field; if (isset($allowed[$field])) { $out .= assoc_render_select($field, $label, $val, $allowed[$field]); } else { $out .= assoc_render_text($field, $label, $val); } } $out .= '
'; } $out .= '
'; $out .= ''; $out .= '
'; $out .= '
'; return $out; } function assoc_render_text($field, $label, $value) { $id = assoc_h($field); return '
'; } function assoc_render_select($field, $label, $value, $options) { $id = assoc_h($field); $out = '
'; $out .= ''; $out .= '
'; return $out; } // ---------------------------------------------------------------------------- // SAVE HANDLER // ---------------------------------------------------------------------------- function assoc_profile_content() { if (argv(1) !== 'save') return ''; if ($_SERVER['REQUEST_METHOD'] !== 'POST') return ''; if (!local_channel()) return ''; if (!assoc_verify_csrf()) { return '
Invalid form token.
'; } $slug = substr(strip_tags($_POST['assoc_slug'] ?? ''), 0, 128); if (!$slug) return '
Missing association slug.
'; $registry = assoc_load_registry(); if (!isset($registry[$slug])) { return '
Association not found in registry.
'; } // Verify caller is channel owner for this slug $channel = App::get_channel(); if (assoc_slug_from_address($channel['channel_address'] ?? '') !== $slug) { return '
Not authorized.
'; } $allowed = assoc_allowed_values(); $fields = assoc_field_names(); foreach ($fields as $field) { if (in_array($field, ['assoc_registered', 'assoc_updated'])) continue; if (!isset($_POST[$field])) continue; $val = substr(strip_tags((string) $_POST[$field]), 0, 512); if (isset($allowed[$field]) && !assoc_validate_select($field, $val)) continue; $registry[$slug][$field] = $val; } $registry[$slug]['assoc_updated'] = date('Y-m-d'); if (assoc_write_registry($registry)) { goaway(z_root() . '/profile/' . $slug); } return '
Failed to save. Check server logs.
'; } // ---------------------------------------------------------------------------- // FIELD METADATA // ---------------------------------------------------------------------------- function assoc_field_labels() { return [ 'assoc_legal_name' => 'Legal Name', 'assoc_type' => 'Association Type', 'assoc_statute' => 'Governing Statute', 'assoc_street' => 'Street Address', 'assoc_city' => 'City', 'assoc_county' => 'County', 'assoc_state' => 'State', 'assoc_zip' => 'ZIP Code', 'assoc_placekey' => 'Placekey', 'assoc_website' => 'Association Website', 'assoc_buildings' => 'Number of Buildings', 'assoc_units' => 'Number of Units', 'assoc_year_built' => 'Year Built', 'assoc_stories' => 'Stories Per Building', 'assoc_mgmt_company' => 'Management Company', 'assoc_mgmt_contact' => 'Management Contact', 'assoc_mgmt_certified' => 'Manager IDFPR Certified', 'assoc_sos_id' => 'SOS Entity File Number', 'assoc_sos_standing' => 'Corporate Standing', 'assoc_declaration_recorded' => 'Declaration Recorded', 'assoc_declaration_instrument' => 'Declaration Instrument No.', 'assoc_registered' => 'Registered Date', 'assoc_updated' => 'Last Updated', ]; } function assoc_field_groups() { return [ 'Identity' => [ 'assoc_legal_name','assoc_type','assoc_statute', 'assoc_street','assoc_city','assoc_county', 'assoc_state','assoc_zip','assoc_placekey','assoc_website', ], 'Physical Structure' => [ 'assoc_buildings','assoc_units','assoc_year_built','assoc_stories', ], 'Governance and Management' => [ 'assoc_mgmt_company','assoc_mgmt_contact','assoc_mgmt_certified', 'assoc_sos_id','assoc_sos_standing', 'assoc_declaration_recorded','assoc_declaration_instrument', ], 'Record' => [ 'assoc_registered','assoc_updated', ], ]; } // ---------------------------------------------------------------------------- // CSRF // ---------------------------------------------------------------------------- function assoc_csrf_token() { if (empty($_SESSION['assoc_profile_csrf'])) { $_SESSION['assoc_profile_csrf'] = bin2hex(random_bytes(16)); } return ''; } function assoc_verify_csrf() { return isset($_POST['assoc_profile_csrf'], $_SESSION['assoc_profile_csrf']) && hash_equals($_SESSION['assoc_profile_csrf'], $_POST['assoc_profile_csrf']); }