Files
kane-diagnostics/hubzilla/addon/assoc_profile/assoc_profile.php
2026-06-06 11:53:11 -04:00

123 lines
4.3 KiB
PHP

<?php
/**
* Name: Association Profile
* Description: Structured diagnostic identity fields for HOA association channels.
* Version: 0.3.0
* MinVersion: 11.0
* MaxVersion: 12.0
*/
function assoc_profile_module() {}
require_once 'addon/assoc_profile/assoc_profile_data.php';
require_once 'addon/assoc_profile/assoc_profile_post.php';
require_once 'addon/assoc_profile/assoc_profile_view.php';
require_once 'addon/assoc_profile/assoc_profile_manage.php';
function assoc_profile_load() {
register_hook('load_pdl', 'addon/assoc_profile/assoc_profile.php', 'assoc_profile_load_pdl');
register_hook('profile_advanced','addon/assoc_profile/assoc_profile.php', 'assoc_profile_view_hook');
register_hook('profile_edit', 'addon/assoc_profile/assoc_profile.php', 'assoc_profile_edit_hook');
}
function assoc_profile_unload() {
unregister_hook('load_pdl', 'addon/assoc_profile/assoc_profile.php', 'assoc_profile_load_pdl');
unregister_hook('profile_advanced','addon/assoc_profile/assoc_profile.php', 'assoc_profile_view_hook');
unregister_hook('profile_edit', 'addon/assoc_profile/assoc_profile.php', 'assoc_profile_edit_hook');
}
function assoc_profile_load_pdl(&$b) {
// Load PDL layout only when this module is active.
if (!is_array($b) || empty($b['module']) || $b['module'] !== 'assoc_profile') {
return;
}
$layout = @file_get_contents('addon/assoc_profile/mod_assoc_profile.pdl');
if ($layout !== false) {
$b['layout'] = $layout;
}
}
// ----------------------------------------------------------------------------
// HELPERS — used by all files in this addon
// ----------------------------------------------------------------------------
function assoc_h($v) {
// HTML-escape a value for safe output.
return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
}
function assoc_slug_from_address($addr) {
// Extract the local part of a channel@node address.
return explode('@', $addr)[0] ?? '';
}
function assoc_is_operator() {
// True only when the logged-in channel is the current page channel.
if (!local_channel()) return false;
$channel = App::get_channel();
return local_channel() === intval($channel['channel_id']);
}
// ----------------------------------------------------------------------------
// CSRF — used by manage and post handlers
// ----------------------------------------------------------------------------
function assoc_csrf_token() {
// Generate or return the session CSRF token as a hidden input.
if (empty($_SESSION['assoc_profile_csrf'])) {
$_SESSION['assoc_profile_csrf'] = bin2hex(random_bytes(16));
}
return '<input type="hidden" name="assoc_profile_csrf" value="' . assoc_h($_SESSION['assoc_profile_csrf']) . '">';
}
function assoc_verify_csrf() {
// Return true if the POST CSRF token matches the session token.
return isset($_POST['assoc_profile_csrf'], $_SESSION['assoc_profile_csrf'])
&& hash_equals($_SESSION['assoc_profile_csrf'], $_POST['assoc_profile_csrf']);
}
// ----------------------------------------------------------------------------
// CONTENT ROUTER
// ----------------------------------------------------------------------------
function assoc_profile_content() {
// Load assets and route /assoc_profile/manage/* requests.
if (function_exists('head_add_css')) {
head_add_css('/addon/assoc_profile/view/css/assoc_profile.css');
}
if (function_exists('head_add_js')) {
head_add_js('/addon/assoc_profile/view/js/assoc_profile.js');
}
$action = argv(1) ?? '';
if ($action !== 'manage') {
return '';
}
if (!assoc_is_operator()) {
return '<div class="civicinfra-notice civicinfra-warning">Operator access required.</div>';
}
$sub = argv(2) ?? '';
$slug = argv(3) ?? '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
return assoc_handle_post();
}
if (!$sub) return assoc_render_manage_index();
if ($sub === 'assoc') {
if (!$slug) return assoc_render_add_association_form();
return assoc_render_edit_association_form($slug);
}
if ($sub === 'fields') return assoc_render_fields_form();
if ($sub === 'import') return assoc_render_import_form();
return '<div class="civicinfra-notice civicinfra-warning">Unknown management action.</div>';
}