Org-Ressourcen: Seite Organisation > Ressourcen und Admin-Reiter
Kunden-Admins pflegen Mail, Nextcloud, ownCloud, WebDAV, SMB und Web-Proxy ihrer Organisation (Formulare aus den Typ-Definitionen des Servers, keine Zugangsdaten), Wirkung fuer die ganze Org, OEs oder Gruppen. Unterseite erscheint nur fuer freigeschaltete Organisationen; root pflegt immer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a104a026c0
commit
ccf7b547a7
9 files changed
+341
No files matched your search
@@ -0,0 +1,90 @@
|
||||
# Org-Ressourcen (15.10.2026, platform-docs roadmap/org-ressourcen-konzept.md):
|
||||
# gemeinsamer Teil von Kunden-Seite (/organisation/ressourcen) und Admin-
|
||||
# Reiter (/admin/kunden/<org>/ressourcen). Die Typen und ihre Felder
|
||||
# definiert allein der Server (ORG_RESSOURCEN_TYPEN in provisioning-server),
|
||||
# das Formular wird daraus erzeugt.
|
||||
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from anode_client import anode_request
|
||||
|
||||
|
||||
def lade_ressourcen_kontext(organization_id: str) -> dict:
|
||||
"""Alles, was templates/_ressourcen.html braucht."""
|
||||
|
||||
typen = anode_request("GET", "/api/v1/org-ressourcen/typen").get("typen", {})
|
||||
liste = anode_request("GET", f"/api/v1/organizations/{organization_id}/ressourcen")
|
||||
|
||||
oes_result = anode_request("GET", f"/api/v1/organizations/{organization_id}/organisationseinheiten")
|
||||
oes = oes_result.get("organisationseinheiten", []) if oes_result.get("success") else []
|
||||
gruppen_result = anode_request("GET", f"/api/v1/organizations/{organization_id}/gruppen")
|
||||
gruppen = gruppen_result.get("gruppen", []) if gruppen_result.get("success") else []
|
||||
|
||||
# OE-Pfad statt nur Name ("Schule › Haus A"), sortiert wie der Baum.
|
||||
by_id = {oe["id"]: oe for oe in oes}
|
||||
|
||||
def pfad(oe):
|
||||
teile, current, gesehen = [], oe, set()
|
||||
while current is not None and current["id"] not in gesehen:
|
||||
gesehen.add(current["id"])
|
||||
teile.append(current["name"])
|
||||
current = by_id.get(current.get("parent_id"))
|
||||
return " › ".join(reversed(teile))
|
||||
|
||||
oe_auswahl = sorted(({"id": oe["id"], "name": pfad(oe)} for oe in oes), key=lambda o: o["name"].lower())
|
||||
|
||||
return {
|
||||
"ressourcen_typen": typen,
|
||||
"ressourcen": liste.get("ressourcen", []) if liste.get("success") else [],
|
||||
"ressourcen_freigeschaltet": bool(liste.get("freigeschaltet")),
|
||||
"ressourcen_oes": oe_auswahl,
|
||||
"ressourcen_gruppen": gruppen,
|
||||
}
|
||||
|
||||
|
||||
def ressourcen_freigeschaltet(organization_id: str) -> bool:
|
||||
liste = anode_request("GET", f"/api/v1/organizations/{organization_id}/ressourcen")
|
||||
return bool(liste.get("success") and liste.get("freigeschaltet"))
|
||||
|
||||
|
||||
def payload_aus_formular(form, typen: dict) -> dict:
|
||||
"""Formularfelder (typ, name, daten.<key>, ganze_organisation,
|
||||
oe_ids, gruppe_ids) in die Server-Anfrage übersetzen. Nur Felder, die der
|
||||
Typ kennt; prüfen tut der Server."""
|
||||
|
||||
typ = form.get("typ", "")
|
||||
felder = typen.get(typ, {}).get("felder", [])
|
||||
daten = {f["key"]: form.get(f"daten.{f['key']}", "") for f in felder}
|
||||
ganze_organisation = form.get("ganze_organisation") == "on"
|
||||
|
||||
return {
|
||||
"typ": typ,
|
||||
"name": form.get("name", ""),
|
||||
"daten": daten,
|
||||
"ganze_organisation": ganze_organisation,
|
||||
"oe_ids": [] if ganze_organisation else form.getlist("oe_ids"),
|
||||
"gruppe_ids": [] if ganze_organisation else form.getlist("gruppe_ids"),
|
||||
}
|
||||
|
||||
|
||||
def speichern(organization_id: str, ressource_id: str | None, form, ziel: str) -> str:
|
||||
"""Anlegen oder ändern, liefert die Weiterleitungs-URL (mit ?fehler=…
|
||||
bei einer Ablehnung durch den Server)."""
|
||||
|
||||
typen = anode_request("GET", "/api/v1/org-ressourcen/typen").get("typen", {})
|
||||
payload = payload_aus_formular(form, typen)
|
||||
if ressource_id is None:
|
||||
result = anode_request("POST", f"/api/v1/organizations/{organization_id}/ressourcen", json=payload)
|
||||
else:
|
||||
result = anode_request("PUT", f"/api/v1/organizations/{organization_id}/ressourcen/{ressource_id}", json=payload)
|
||||
|
||||
if not result.get("success"):
|
||||
return ziel + "?" + urlencode({"fehler": result.get("message", "Die Ressource konnte nicht gespeichert werden.")})
|
||||
return ziel
|
||||
|
||||
|
||||
def loeschen(organization_id: str, ressource_id: str, ziel: str) -> str:
|
||||
result = anode_request("DELETE", f"/api/v1/organizations/{organization_id}/ressourcen/{ressource_id}")
|
||||
if not result.get("success"):
|
||||
return ziel + "?" + urlencode({"fehler": result.get("message", "Die Ressource konnte nicht gelöscht werden.")})
|
||||
return ziel
|
||||
@@ -8,6 +8,7 @@ from pydantic import EmailStr, TypeAdapter, ValidationError
|
||||
from anode_client import anode_request
|
||||
from auth import UserCreate, UserManager, fetch_benutzer_fuer_organisation, get_user_manager, require_admin
|
||||
from diagnosezugang import aktiviere_diagnosezugang, deaktiviere_diagnosezugang, fetch_diagnosezugang
|
||||
import ressourcen_formular
|
||||
from templating import templates
|
||||
|
||||
|
||||
@@ -188,6 +189,34 @@ def detail_gruppen(request: Request, organization_id: str, user: dict = Depends(
|
||||
return _render_detail_tab(request, organization_id, user, "gruppen", gruppen=gruppen)
|
||||
|
||||
|
||||
@router.get("/{organization_id}/ressourcen")
|
||||
def detail_ressourcen(request: Request, organization_id: str, fehler: str = "", user: dict = Depends(require_admin)):
|
||||
return _render_detail_tab(
|
||||
request, organization_id, user, "ressourcen", fehler=fehler,
|
||||
**ressourcen_formular.lade_ressourcen_kontext(organization_id),
|
||||
)
|
||||
|
||||
|
||||
# root pflegt Ressourcen auch für noch nicht freigeschaltete Organisationen
|
||||
# (Ersteinrichtung); verteilt werden sie erst nach der Freischaltung.
|
||||
@router.post("/{organization_id}/ressourcen")
|
||||
async def ressource_anlegen(request: Request, organization_id: str, user: dict = Depends(require_admin)):
|
||||
ziel = ressourcen_formular.speichern(organization_id, None, await request.form(), f"/admin/kunden/{organization_id}/ressourcen")
|
||||
return RedirectResponse(ziel, status_code=303)
|
||||
|
||||
|
||||
@router.post("/{organization_id}/ressourcen/{ressource_id}")
|
||||
async def ressource_aendern(request: Request, organization_id: str, ressource_id: str, user: dict = Depends(require_admin)):
|
||||
ziel = ressourcen_formular.speichern(organization_id, ressource_id, await request.form(), f"/admin/kunden/{organization_id}/ressourcen")
|
||||
return RedirectResponse(ziel, status_code=303)
|
||||
|
||||
|
||||
@router.post("/{organization_id}/ressourcen/{ressource_id}/loeschen")
|
||||
def ressource_loeschen(organization_id: str, ressource_id: str, user: dict = Depends(require_admin)):
|
||||
ziel = ressourcen_formular.loeschen(organization_id, ressource_id, f"/admin/kunden/{organization_id}/ressourcen")
|
||||
return RedirectResponse(ziel, status_code=303)
|
||||
|
||||
|
||||
@router.get("/{organization_id}/struktur")
|
||||
def detail_struktur(request: Request, organization_id: str, user: dict = Depends(require_admin)):
|
||||
oes_result = anode_request("GET", f"/api/v1/organizations/{organization_id}/organisationseinheiten")
|
||||
|
||||
@@ -5,6 +5,7 @@ from fastapi.responses import RedirectResponse
|
||||
from fastapi_users import exceptions
|
||||
|
||||
from anode_client import anode_request
|
||||
import ressourcen_formular
|
||||
from auth import (
|
||||
UserCreate,
|
||||
UserManager,
|
||||
@@ -55,6 +56,42 @@ def konten_ansicht(request: Request, user=Depends(get_current_user)):
|
||||
)
|
||||
|
||||
|
||||
@router.get("/organisation/ressourcen")
|
||||
def ressourcen_ansicht(request: Request, fehler: str = "", user=Depends(get_current_user)):
|
||||
kontext = ressourcen_formular.lade_ressourcen_kontext(str(user.organization_id))
|
||||
return templates.TemplateResponse(
|
||||
request, "organisation_ressourcen.html", {"user": user, "fehler": fehler, **kontext}
|
||||
)
|
||||
|
||||
|
||||
def _ressourcen_freigeschaltet_oder_404(user):
|
||||
# Solange die Org nicht freigeschaltet ist (ORG_RESSOURCEN_NUR_VORAB im
|
||||
# Server), auch keine Änderungen per direktem POST.
|
||||
if not ressourcen_formular.ressourcen_freigeschaltet(str(user.organization_id)):
|
||||
raise HTTPException(status_code=404, detail="Nicht verfügbar.")
|
||||
|
||||
|
||||
@router.post("/organisation/ressourcen")
|
||||
async def ressource_anlegen(request: Request, user=Depends(require_org_admin)):
|
||||
_ressourcen_freigeschaltet_oder_404(user)
|
||||
ziel = ressourcen_formular.speichern(str(user.organization_id), None, await request.form(), "/organisation/ressourcen")
|
||||
return RedirectResponse(ziel, status_code=303)
|
||||
|
||||
|
||||
@router.post("/organisation/ressourcen/{ressource_id}")
|
||||
async def ressource_aendern(ressource_id: str, request: Request, user=Depends(require_org_admin)):
|
||||
_ressourcen_freigeschaltet_oder_404(user)
|
||||
ziel = ressourcen_formular.speichern(str(user.organization_id), ressource_id, await request.form(), "/organisation/ressourcen")
|
||||
return RedirectResponse(ziel, status_code=303)
|
||||
|
||||
|
||||
@router.post("/organisation/ressourcen/{ressource_id}/loeschen")
|
||||
def ressource_loeschen(ressource_id: str, user=Depends(require_org_admin)):
|
||||
_ressourcen_freigeschaltet_oder_404(user)
|
||||
ziel = ressourcen_formular.loeschen(str(user.organization_id), ressource_id, "/organisation/ressourcen")
|
||||
return RedirectResponse(ziel, status_code=303)
|
||||
|
||||
|
||||
@router.post("/organisation")
|
||||
def organisation_speichern(
|
||||
name: str = Form(...),
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
{# Org-Ressourcen (15.10.2026): gemeinsam für die Kunden-Seite
|
||||
(organisation_ressourcen.html) und den Admin-Reiter (admin/kunden_detail.html).
|
||||
Erwartet: ressourcen, ressourcen_typen, ressourcen_oes, ressourcen_gruppen,
|
||||
basis_url, darf_bearbeiten, fehler. Formularfelder erzeugt aus den
|
||||
Typ-Definitionen des Servers, ohne JavaScript: je Typ ein eigenes
|
||||
"Neu anlegen"-Formular. #}
|
||||
|
||||
{% macro felder(typ_key, typ, ressource=None) %}
|
||||
<input type="hidden" name="typ" value="{{ typ_key }}">
|
||||
<label>Name (zur Unterscheidung, z. B. „Schulcloud“)
|
||||
<input type="text" name="name" value="{{ ressource.name if ressource else '' }}" required>
|
||||
</label>
|
||||
{% for feld in typ.felder %}
|
||||
{% set wert = ressource.daten.get(feld.key) if ressource else none %}
|
||||
{% if wert is none %}{% set wert = feld.standard if feld.standard is defined else '' %}{% endif %}
|
||||
<label>{{ feld.label }}{% if feld.pflicht %} *{% endif %}
|
||||
{% if feld.typ == "auswahl" %}
|
||||
<select name="daten.{{ feld.key }}">
|
||||
{% for w in feld.werte %}
|
||||
<option value="{{ w }}" {% if w == wert %}selected{% endif %}>{{ {"ssl": "SSL/TLS", "starttls": "STARTTLS", "mailadresse": "vollständige Mailadresse", "lokalteil": "nur der Teil vor dem @"}.get(w, w) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% elif feld.typ == "port" %}
|
||||
<input type="number" min="1" max="65535" name="daten.{{ feld.key }}" value="{{ wert }}">
|
||||
{% elif feld.typ == "liste" %}
|
||||
<input type="text" name="daten.{{ feld.key }}" value="{{ wert | join(', ') if wert is iterable and wert is not string else wert }}">
|
||||
{% else %}
|
||||
<input type="{{ 'url' if feld.typ == 'url' else 'text' }}" name="daten.{{ feld.key }}" value="{{ wert }}" {% if feld.pflicht %}required{% endif %}>
|
||||
{% endif %}
|
||||
</label>
|
||||
{% endfor %}
|
||||
|
||||
<fieldset>
|
||||
<legend>Wirkt auf</legend>
|
||||
<label>
|
||||
<input type="checkbox" name="ganze_organisation" {% if not ressource or ressource.ganze_organisation %}checked{% endif %}>
|
||||
alle Geräte der Organisation
|
||||
</label>
|
||||
{% if ressourcen_oes or ressourcen_gruppen %}
|
||||
<small>Sonst nur auf die gewählten Organisationseinheiten (samt untergeordneten) und Gruppen:</small>
|
||||
{% for oe in ressourcen_oes %}
|
||||
<label>
|
||||
<input type="checkbox" name="oe_ids" value="{{ oe.id }}" {% if ressource and oe.id in ressource.oes | map(attribute='id') | list %}checked{% endif %}>
|
||||
OE: {{ oe.name }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% for gruppe in ressourcen_gruppen %}
|
||||
<label>
|
||||
<input type="checkbox" name="gruppe_ids" value="{{ gruppe.id }}" {% if ressource and gruppe.id in ressource.gruppen | map(attribute='id') | list %}checked{% endif %}>
|
||||
Gruppe: {{ gruppe.name }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
{% endmacro %}
|
||||
|
||||
<p>
|
||||
Dienste Ihrer Organisation wie Mailserver, Cloud, Dateifreigaben oder
|
||||
Web-Proxy. Die Geräte tragen sie in die passenden Programme ein; Benutzer
|
||||
melden sich dann nur noch mit ihrem eigenen Namen und Passwort an.
|
||||
<strong>Hier werden keine Zugangsdaten gespeichert.</strong>
|
||||
</p>
|
||||
|
||||
{% if fehler %}
|
||||
<p role="alert"><mark>{{ fehler }}</mark></p>
|
||||
{% endif %}
|
||||
|
||||
{% if not ressourcen %}
|
||||
<p>Noch keine Ressourcen eingetragen.</p>
|
||||
{% else %}
|
||||
<figure>
|
||||
<table>
|
||||
<thead><tr><th>Name</th><th>Art</th><th>Angaben</th><th>Wirkt auf</th>{% if darf_bearbeiten %}<th></th>{% endif %}</tr></thead>
|
||||
<tbody>
|
||||
{% for r in ressourcen %}
|
||||
<tr>
|
||||
<td>{{ r.name }}</td>
|
||||
<td>{{ r.typ_name }}</td>
|
||||
<td><small>
|
||||
{% for feld in ressourcen_typen.get(r.typ, {}).get("felder", []) %}
|
||||
{% set w = r.daten.get(feld.key) %}
|
||||
{% if w not in (none, "", []) %}{{ feld.label.split(" (")[0] }}: {{ w | join(", ") if w is iterable and w is not string else w }}<br>{% endif %}
|
||||
{% endfor %}
|
||||
</small></td>
|
||||
<td><small>
|
||||
{% if r.ganze_organisation %}ganze Organisation
|
||||
{% elif not r.oes and not r.gruppen %}<em>nirgends (nicht verteilt)</em>
|
||||
{% else %}
|
||||
{% for oe in r.oes %}OE {{ oe.name }}<br>{% endfor %}
|
||||
{% for g in r.gruppen %}Gruppe {{ g.name }}<br>{% endfor %}
|
||||
{% endif %}
|
||||
</small></td>
|
||||
{% if darf_bearbeiten %}
|
||||
<td>
|
||||
<details>
|
||||
<summary role="button" class="outline">Bearbeiten</summary>
|
||||
{% if r.typ in ressourcen_typen %}
|
||||
<form method="post" action="{{ basis_url }}/{{ r.id }}">
|
||||
{{ felder(r.typ, ressourcen_typen[r.typ], r) }}
|
||||
<button type="submit">Speichern</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="{{ basis_url }}/{{ r.id }}/loeschen">
|
||||
<button type="submit" class="outline secondary">Löschen</button>
|
||||
</form>
|
||||
</details>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
{% endif %}
|
||||
|
||||
{% if darf_bearbeiten %}
|
||||
<h4>Neue Ressource</h4>
|
||||
{% for typ_key, typ in ressourcen_typen.items() %}
|
||||
<details>
|
||||
<summary role="button" class="secondary outline">{{ typ.name }} anlegen</summary>
|
||||
<form method="post" action="{{ basis_url }}">
|
||||
{{ felder(typ_key, typ) }}
|
||||
<button type="submit">Anlegen</button>
|
||||
</form>
|
||||
</details>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
@@ -10,6 +10,7 @@
|
||||
<li><a href="/admin/kunden/{{ organization_id }}/konten">{% if aktiver_tab == "konten" %}<strong>Kundenkonten</strong>{% else %}Kundenkonten{% endif %}</a></li>
|
||||
<li><a href="/admin/kunden/{{ organization_id }}/struktur">{% if aktiver_tab == "struktur" %}<strong>Struktur & Workspaces</strong>{% else %}Struktur & Workspaces{% endif %}</a></li>
|
||||
<li><a href="/admin/kunden/{{ organization_id }}/gruppen">{% if aktiver_tab == "gruppen" %}<strong>Gruppen</strong>{% else %}Gruppen{% endif %}</a></li>
|
||||
<li><a href="/admin/kunden/{{ organization_id }}/ressourcen">{% if aktiver_tab == "ressourcen" %}<strong>Ressourcen</strong>{% else %}Ressourcen{% endif %}</a></li>
|
||||
<li><a href="/admin/kunden/{{ organization_id }}/diagnosezugang">{% if aktiver_tab == "diagnosezugang" %}<strong>Diagnosezugang</strong>{% else %}Diagnosezugang{% endif %}</a></li>
|
||||
<li><a href="/admin/kunden/{{ organization_id }}/aktivitaeten">{% if aktiver_tab == "aktivitaeten" %}<strong>Aktivitäten</strong>{% else %}Aktivitäten{% endif %}</a></li>
|
||||
<li><a href="/admin/flows/{{ organization_id }}">{% if aktiver_tab == "flows" %}<strong>Flows</strong>{% else %}Flows{% endif %}</a></li>
|
||||
|
||||
@@ -419,4 +419,14 @@
|
||||
</details>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% if aktiver_tab == "ressourcen" %}
|
||||
<section>
|
||||
{% if not ressourcen_freigeschaltet %}
|
||||
<p><mark>Für diese Organisation noch nicht freigeschaltet</mark> (Ausrollstufe „stabil“): die Ressourcen werden gespeichert, aber nicht an Geräte verteilt, und die Kunden-Seite ist ausgeblendet.</p>
|
||||
{% endif %}
|
||||
{% set basis_url = "/admin/kunden/" ~ organization_id ~ "/ressourcen" %}
|
||||
{% set darf_bearbeiten = true %}
|
||||
{% include "_ressourcen.html" %}
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -209,6 +209,7 @@
|
||||
else "" %}
|
||||
{% set aktive_unterseite =
|
||||
"konten" if pfad.startswith("/organisation/konten")
|
||||
else "ressourcen" if pfad.startswith("/organisation/ressourcen")
|
||||
else "organisation" if pfad.startswith("/organisation")
|
||||
else "struktur" if pfad.startswith("/struktur")
|
||||
else "gruppen" if pfad.startswith("/gruppen")
|
||||
@@ -257,6 +258,9 @@
|
||||
<ul>
|
||||
<li><a href="/organisation" {% if aktive_unterseite == "organisation" %}class="active"{% endif %}>Organisation</a></li>
|
||||
<li><a href="/organisation/konten" {% if aktive_unterseite == "konten" %}class="active"{% endif %}>Konten</a></li>
|
||||
{% if user and user.organization_id and org_ressourcen_freigeschaltet(user.organization_id) %}
|
||||
<li><a href="/organisation/ressourcen" {% if aktive_unterseite == "ressourcen" %}class="active"{% endif %}>Ressourcen</a></li>
|
||||
{% endif %}
|
||||
<li><a href="/struktur" {% if aktive_unterseite == "struktur" %}class="active"{% endif %}>Struktur</a></li>
|
||||
<li><a href="/gruppen" {% if aktive_unterseite == "gruppen" %}class="active"{% endif %}>Gruppen</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Ressourcen — Tuxflotte{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Ressourcen</h2>
|
||||
|
||||
{% if not ressourcen_freigeschaltet %}
|
||||
<p>Diese Funktion wird gerade vorbereitet und steht Ihrer Organisation bald zur Verfügung.</p>
|
||||
{% else %}
|
||||
{% set basis_url = "/organisation/ressourcen" %}
|
||||
{% set darf_bearbeiten = user.is_superuser or user.ist_organisationsadmin %}
|
||||
{% include "_ressourcen.html" %}
|
||||
{% if not darf_bearbeiten %}
|
||||
<p><small>Nur Organisations-Admins können Ressourcen eintragen oder ändern.</small></p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -98,3 +98,30 @@ def ring_segmente(teile: list[dict], radius: float = 54, staerke: float = 16) ->
|
||||
|
||||
|
||||
templates.env.globals["ring_segmente"] = ring_segmente
|
||||
|
||||
|
||||
# Org-Ressourcen (15.10.2026): die Kunden-Unterseite "Ressourcen" erscheint
|
||||
# nur, wenn der Server sie für die Organisation freigeschaltet hat
|
||||
# (ORG_RESSOURCEN_NUR_VORAB). Kurz zwischengespeichert, damit nicht jede
|
||||
# Seite der Organisation-Navigation eine zusätzliche Anfrage auslöst.
|
||||
_ressourcen_freigabe_cache: dict = {}
|
||||
|
||||
|
||||
def org_ressourcen_freigeschaltet(organization_id) -> bool:
|
||||
import time
|
||||
|
||||
from ressourcen_formular import ressourcen_freigeschaltet
|
||||
|
||||
schluessel = str(organization_id)
|
||||
eintrag = _ressourcen_freigabe_cache.get(schluessel)
|
||||
if eintrag and time.monotonic() - eintrag[1] < 60:
|
||||
return eintrag[0]
|
||||
try:
|
||||
wert = ressourcen_freigeschaltet(schluessel)
|
||||
except Exception:
|
||||
wert = False
|
||||
_ressourcen_freigabe_cache[schluessel] = (wert, time.monotonic())
|
||||
return wert
|
||||
|
||||
|
||||
templates.env.globals["org_ressourcen_freigeschaltet"] = org_ressourcen_freigeschaltet
|
||||
Reference in new issue
Block a user