['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(&$b) {
$profile = $b['profile'] ?? [];
$uid = intval($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');
}
$b['html'] .= 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 .= '
';
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']);
}