Menue folgt auch den Schaltern des Mandanten
Bisher blendete das Menue nur aus, was der Betreiber gesperrt hatte. Hat der Mandant selbst eine Funktion abgeschaltet - etwa "PayPal anbieten" in den Mandant-Einstellungen - blieb der Menuepunkt stehen und fuehrte auf eine Seite ohne Zweck. app_feature_available() prueft nun beide Ebenen, app_feature_tenant_switch() haelt die Zuordnung Funktion -> Mandanten-Schalter. Navigation und Anleitung nutzen die neue Pruefung; paypal-zuordnung.php sperrt sich beim direkten Aufruf ebenfalls und verweist dabei auf die Mandant-Einstellungen statt auf den Betreiber. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -17,11 +17,11 @@ $istAdmin = $saasUser !== null && saas_user_has_role(['owner', 'admin'], $saasUs
|
|||||||
// Einstellungen fuer die Hinweise zu den aktivierten Zahlungswegen.
|
// Einstellungen fuer die Hinweise zu den aktivierten Zahlungswegen.
|
||||||
$settings = $saasUser !== null ? saas_fetch_tenant_settings($pdo, (int)$saasUser['tenant_id']) : null;
|
$settings = $saasUser !== null ? saas_fetch_tenant_settings($pdo, (int)$saasUser['tenant_id']) : null;
|
||||||
|
|
||||||
// Gleiche Logik wie im Menue: was der Betreiber fuer diesen Mandanten
|
// Gleiche Logik wie im Menue: was der Betreiber gesperrt oder der Mandant
|
||||||
// gesperrt hat, wird hier auch nicht erklaert.
|
// selbst abgeschaltet hat, wird hier auch nicht erklaert.
|
||||||
$anleitungTenantId = $saasUser !== null ? (int)$saasUser['tenant_id'] : 0;
|
$anleitungTenantId = $saasUser !== null ? (int)$saasUser['tenant_id'] : 0;
|
||||||
$kann = static function (string $feature) use ($pdo, $anleitungTenantId): bool {
|
$kann = static function (string $feature) use ($pdo, $anleitungTenantId): bool {
|
||||||
return $anleitungTenantId <= 0 || app_feature_enabled($pdo, $anleitungTenantId, $feature);
|
return $anleitungTenantId <= 0 || app_feature_available($pdo, $anleitungTenantId, $feature);
|
||||||
};
|
};
|
||||||
|
|
||||||
include "header.php";
|
include "header.php";
|
||||||
|
|||||||
@@ -165,3 +165,81 @@ function app_feature_notice_html(string $featureKey): string
|
|||||||
. ' ist für euren Zugang nicht freigeschaltet.</b><br>'
|
. ' ist für euren Zugang nicht freigeschaltet.</b><br>'
|
||||||
. 'Wende dich an den Betreiber der Kaffeeliste, wenn ihr diese Funktion nutzen möchtet.</p></div>';
|
. 'Wende dich an den Betreiber der Kaffeeliste, wenn ihr diese Funktion nutzen möchtet.</p></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zuordnung Betreiber-Funktion -> Schalter in den Mandant-Einstellungen.
|
||||||
|
* Manche Funktionen kann der Kunde zusaetzlich selbst abschalten; wer PayPal
|
||||||
|
* gar nicht als Zahlungsweg anbietet, braucht auch keine PayPal-Zuordnung.
|
||||||
|
* Funktionen ohne Eintrag kennen nur den Betreiber-Schalter.
|
||||||
|
*/
|
||||||
|
function app_feature_tenant_switch(string $featureKey): ?string
|
||||||
|
{
|
||||||
|
$switches = [
|
||||||
|
'paypal_inbox' => 'paypal_enabled',
|
||||||
|
'self_entry' => 'self_entry_enabled',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $switches[$featureKey] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ist eine Funktion fuer den Mandanten tatsaechlich nutzbar? Prueft beide
|
||||||
|
* Ebenen: erst die Freischaltung durch den Betreiber, dann - falls vorhanden -
|
||||||
|
* den eigenen Schalter des Kunden in den Mandant-Einstellungen.
|
||||||
|
*/
|
||||||
|
function app_feature_available(PDO $pdo, int $tenantId, string $featureKey): bool
|
||||||
|
{
|
||||||
|
if (!app_feature_enabled($pdo, $tenantId, $featureKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$switch = app_feature_tenant_switch($featureKey);
|
||||||
|
if ($switch === null || $tenantId <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return app_tenant_switch_enabled($pdo, $tenantId, $switch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einzelnen Schalter aus den Mandant-Einstellungen lesen. Wie bei den
|
||||||
|
* Betreiber-Funktionen wird das Ergebnis pro Request gehalten, damit die
|
||||||
|
* Navigation die Einstellungen nicht mehrfach laedt.
|
||||||
|
*/
|
||||||
|
function app_tenant_switch_enabled(PDO $pdo, int $tenantId, string $settingKey): bool
|
||||||
|
{
|
||||||
|
static $cache = [];
|
||||||
|
|
||||||
|
if (!array_key_exists($tenantId, $cache)) {
|
||||||
|
try {
|
||||||
|
require_once __DIR__ . '/saas-auth.php';
|
||||||
|
$cache[$tenantId] = saas_fetch_tenant_settings($pdo, $tenantId) ?? [];
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
// Lassen sich die Einstellungen nicht lesen, entscheidet allein die
|
||||||
|
// Betreiber-Freischaltung - kein stiller Funktionsverlust.
|
||||||
|
$cache[$tenantId] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array_key_exists($settingKey, $cache[$tenantId])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)$cache[$tenantId][$settingKey] === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gegenstueck zu app_feature_notice_html() fuer den Fall, dass nicht der
|
||||||
|
* Betreiber, sondern der Mandant selbst die Funktion abgeschaltet hat. Hier
|
||||||
|
* hilft kein Kontakt zum Betreiber, sondern der Weg in die eigenen
|
||||||
|
* Einstellungen.
|
||||||
|
*/
|
||||||
|
function app_feature_tenant_notice_html(string $featureKey): string
|
||||||
|
{
|
||||||
|
$label = app_feature_catalog()[$featureKey]['label'] ?? $featureKey;
|
||||||
|
|
||||||
|
return '<div class="hint-box error"><p><b>' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8')
|
||||||
|
. ' ist in euren Mandant-Einstellungen deaktiviert.</b><br>'
|
||||||
|
. 'Ein Besitzer oder Administrator kann die Funktion unter '
|
||||||
|
. '<a href="mandant-einstellungen.php">Mandant-Einstellungen</a> wieder einschalten.</p></div>';
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,6 +94,17 @@ Design-Entscheidungen:
|
|||||||
einem Hinweis statt mit einem Fehler. Die POST-Verarbeitung der
|
einem Hinweis statt mit einem Fehler. Die POST-Verarbeitung der
|
||||||
betroffenen Seiten hängt an derselben Prüfung, eine gesperrte Funktion
|
betroffenen Seiten hängt an derselben Prüfung, eine gesperrte Funktion
|
||||||
lässt sich also auch nicht per Formular-POST auslösen.
|
lässt sich also auch nicht per Formular-POST auslösen.
|
||||||
|
- **Abgeschaltet vom Kunden heißt ebenfalls unsichtbar.** Für Funktionen
|
||||||
|
mit eigenem Schalter in den Mandant-Einstellungen zieht `footer.php`
|
||||||
|
(und die Anleitung) `app_feature_available()` heran: erst die
|
||||||
|
Freischaltung durch den Betreiber, dann der Schalter des Kunden. Die
|
||||||
|
Zuordnung steht in `app_feature_tenant_switch()` – aktuell
|
||||||
|
`paypal_inbox` → `paypal_enabled` und `self_entry` →
|
||||||
|
`self_entry_enabled`. Wer PayPal nicht als Zahlungsweg anbietet, sieht
|
||||||
|
den Menüpunkt „PayPal-Zahlungen" also gar nicht erst; beim direkten
|
||||||
|
Aufruf erscheint statt des Betreiber-Hinweises
|
||||||
|
`app_feature_tenant_notice_html()` mit dem Weg zurück in die
|
||||||
|
Mandant-Einstellungen.
|
||||||
- Jede Änderung landet als `backoffice.features_updated` im Audit-Log des
|
- Jede Änderung landet als `backoffice.features_updated` im Audit-Log des
|
||||||
betroffenen Mandanten – wie jeder andere Back-Office-Zugriff auch.
|
betroffenen Mandanten – wie jeder andere Back-Office-Zugriff auch.
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -31,8 +31,10 @@ if ($saasNavUser !== null && function_exists('saas_list_user_memberships')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vom Betreiber gesperrte Funktionen erscheinen gar nicht erst im Menue -
|
// Gesperrte Funktionen erscheinen gar nicht erst im Menue - ein Menuepunkt,
|
||||||
// ein Menuepunkt, der nur zu einer Absage fuehrt, ist schlechter als keiner.
|
// der nur zu einer Absage fuehrt, ist schlechter als keiner. Geprueft werden
|
||||||
|
// beide Ebenen: die Freischaltung durch den Betreiber und der eigene Schalter
|
||||||
|
// des Mandanten in den Mandant-Einstellungen (z. B. "PayPal anbieten").
|
||||||
require_once __DIR__ . '/app/features.php';
|
require_once __DIR__ . '/app/features.php';
|
||||||
$saasNavTenantId = $saasNavUser !== null ? (int)$saasNavUser['tenant_id'] : 0;
|
$saasNavTenantId = $saasNavUser !== null ? (int)$saasNavUser['tenant_id'] : 0;
|
||||||
$saasNavFeature = static function (string $key) use ($saasNavTenantId): bool {
|
$saasNavFeature = static function (string $key) use ($saasNavTenantId): bool {
|
||||||
@@ -40,7 +42,7 @@ $saasNavFeature = static function (string $key) use ($saasNavTenantId): bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return app_feature_enabled(app_db_pdo(), $saasNavTenantId, $key);
|
return app_feature_available(app_db_pdo(), $saasNavTenantId, $key);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Das Back-Office war bisher nur ueber die direkte URL erreichbar. Es ist die
|
// Das Back-Office war bisher nur ueber die direkte URL erreichbar. Es ist die
|
||||||
|
|||||||
+13
-6
@@ -16,11 +16,18 @@ if ($saasUser !== null && saas_user_has_role(['owner', 'admin', 'treasurer'], $s
|
|||||||
$hasAccess = true;
|
$hasAccess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vom Betreiber gesperrte Funktion: $hasAccess faellt zurueck, damit auch die
|
// Gesperrte Funktion: $hasAccess faellt zurueck, damit auch die
|
||||||
// POST-Verarbeitung weiter unten nicht mehr laeuft.
|
// POST-Verarbeitung weiter unten nicht mehr laeuft. Der Menuepunkt ist in
|
||||||
$gesperrteFunktion = null;
|
// diesem Fall ausgeblendet - die Seite bleibt aber ueber die direkte URL
|
||||||
|
// erreichbar und muss deshalb selbst pruefen.
|
||||||
|
$sperrHinweis = null;
|
||||||
if ($hasAccess && !app_feature_enabled($pdo, $tenantId, 'paypal_inbox')) {
|
if ($hasAccess && !app_feature_enabled($pdo, $tenantId, 'paypal_inbox')) {
|
||||||
$gesperrteFunktion = 'paypal_inbox';
|
// Der Betreiber hat die Funktion fuer diesen Mandanten nicht freigeschaltet.
|
||||||
|
$sperrHinweis = app_feature_notice_html('paypal_inbox');
|
||||||
|
$hasAccess = false;
|
||||||
|
} elseif ($hasAccess && !app_feature_available($pdo, $tenantId, 'paypal_inbox')) {
|
||||||
|
// Der Mandant selbst bietet PayPal nicht als Zahlungsweg an.
|
||||||
|
$sperrHinweis = app_feature_tenant_notice_html('paypal_inbox');
|
||||||
$hasAccess = false;
|
$hasAccess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +137,8 @@ include "nav.php";
|
|||||||
<section id="banner">
|
<section id="banner">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
||||||
<?php if ($gesperrteFunktion !== null): ?>
|
<?php if ($sperrHinweis !== null): ?>
|
||||||
<?php echo app_feature_notice_html($gesperrteFunktion); ?>
|
<?php echo $sperrHinweis; ?>
|
||||||
<?php elseif (!$hasAccess): ?>
|
<?php elseif (!$hasAccess): ?>
|
||||||
<h2>Kein Zugriff</h2>
|
<h2>Kein Zugriff</h2>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
|||||||
Reference in New Issue
Block a user