This commit is contained in:
2026-06-06 19:59:32 -04:00
parent 00b56600a8
commit 6189d79cfd

View File

@@ -3,7 +3,7 @@
/** /**
* Name: VS-01 Vital Signs * Name: VS-01 Vital Signs
* Description: Public civic diagnostic — the ten structural preconditions of an HOA association. * Description: Public civic diagnostic — the ten structural preconditions of an HOA association.
* Version: 0.2.0 * Version: 0.3.0
* MinVersion: 11.0 * MinVersion: 11.0
* MaxVersion: 12.0 * MaxVersion: 12.0
*/ */
@@ -48,50 +48,73 @@ function vs01_h($value) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function vs01_access_state($association_slug = '') { function vs01_access_state($association_slug = '') {
if (!local_channel()) {
return 'public';
}
$config = vs01_load_config(); $config = vs01_load_config();
// Operator check — site owner, not association channel owner // Operator check — association channel owner (local channel only)
$channel = App::get_channel(); if (local_channel()) {
if (local_channel() === intval($channel['channel_id'])) { $channel = App::get_channel();
return 'operator'; if (local_channel() === intval($channel['channel_id'])) {
return 'operator';
}
} }
if (!$association_slug) { if (!$association_slug) {
return 'public'; return 'public';
} }
$assoc = $config['associations'][$association_slug] ?? null; $assoc = $config['associations'][$association_slug] ?? null;
if (!$assoc) return 'public'; if (!$assoc) return 'public';
// get_observer_hash() works for both local channels and guest token visitors
$observer = get_observer_hash(); $observer = get_observer_hash();
$groups = $assoc['groups'] ?? []; if (!$observer) return 'public';
$groups = $assoc['groups'] ?? [];
// Direct pgrp_member query — works for guest tokens because it does not
// call local_channel(). The group IDs come from config.json per association.
// Corpus Builder — highest participant tier // Corpus Builder — highest participant tier
$cb_gid = intval($groups['corpus_builder'] ?? 0); $cb_gid = intval($groups['corpus_builder'] ?? 0);
if ($cb_gid && in_array($observer, group_get_members_xchan($cb_gid))) { if ($cb_gid) {
return 'participant'; $r = q("SELECT xchain FROM pgrp_member WHERE gid = %d AND xchain = '%s' LIMIT 1",
intval($cb_gid),
dbesc($observer)
);
if ($r) return 'participant';
} }
// SASE Participant // SASE Participant
$sase_gid = intval($groups['sase_participant'] ?? 0); $sase_gid = intval($groups['sase_participant'] ?? 0);
if ($sase_gid && in_array($observer, group_get_members_xchan($sase_gid))) { if ($sase_gid) {
return 'participant'; $r = q("SELECT xchain FROM pgrp_member WHERE gid = %d AND xchain = '%s' LIMIT 1",
intval($sase_gid),
dbesc($observer)
);
if ($r) return 'participant';
}
// Civic Professional
$prof_gid = intval($groups['civic_professional'] ?? 0);
if ($prof_gid) {
$r = q("SELECT xchain FROM pgrp_member WHERE gid = %d AND xchain = '%s' LIMIT 1",
intval($prof_gid),
dbesc($observer)
);
if ($r) return 'participant';
} }
return 'public'; return 'public';
} }
function vs01_is_professional() { function vs01_is_professional() {
if (!local_channel()) return false; // Works for both local channels and guest token visitors via get_observer_hash()
$observer = get_observer_hash(); $observer = get_observer_hash();
if (!$observer) return false;
$listings = vs01_load_listings(); $listings = vs01_load_listings();
foreach (['tier1', 'tier2'] as $tier) { foreach (['tier1', 'tier2'] as $tier) {
foreach ($listings[$tier] ?? [] as $entry) { foreach ($listings[$tier] ?? [] as $entry) {
if (($entry['xchan'] ?? '') === $observer if (($entry['xchain'] ?? '') === $observer
&& ($entry['status'] ?? '') === 'active') { && ($entry['status'] ?? '') === 'active') {
return true; return true;
} }
@@ -211,9 +234,9 @@ function vs01_render_index() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function vs01_render_landing($association_slug, $access) { function vs01_render_landing($association_slug, $access) {
$config = vs01_load_config(); $config = vs01_load_config();
$assoc = $config['associations'][$association_slug]; $assoc = $config['associations'][$association_slug];
$name = vs01_h($assoc['name'] ?? $association_slug); $name = vs01_h($assoc['name'] ?? $association_slug);
$schemas = vs01_load_schemas(); $schemas = vs01_load_schemas();
$out = '<div class="vs01-content">'; $out = '<div class="vs01-content">';