Lizenzserver 2.8.15: auch eine unbefristete Lizenz laesst sich zurueckholen
This commit is contained in:
1 parent
34a4923304
commit
0024a116ce
4 files changed
+85
-20
No files matched your search
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "tesm-license"
|
||||
version = "2.8.14"
|
||||
version = "2.8.15"
|
||||
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -78,9 +78,11 @@ def detail(license_id: str):
|
||||
"license/license_detail.html",
|
||||
license=row,
|
||||
state=issuance.display_state(row),
|
||||
# Bis wohin traegt das Ticket? Die Seite zeigt eine Abweichung an,
|
||||
# statt sie erst in einer Fehlermeldung auftauchen zu lassen.
|
||||
# Bis wohin traegt das Ticket, und weicht die Lizenz davon ab? Die
|
||||
# Seite zeigt es an, statt es erst in einer Fehlermeldung auftauchen zu
|
||||
# lassen.
|
||||
ticket_grenze=issuance.ticket_grenze(conn, license_id),
|
||||
abweichung=issuance.ticket_abweichung(conn, license_id),
|
||||
document=document,
|
||||
document_json=json.dumps(document, indent=2, ensure_ascii=False, sort_keys=True),
|
||||
deliveries=Database.all(
|
||||
@@ -214,8 +216,13 @@ def align_ticket(license_id: str):
|
||||
log_event(
|
||||
"license.resigned",
|
||||
target=license_id[:12],
|
||||
detail=f"Revision {neu['seq']}: Laufzeit auf die Ticketlaufzeit gesetzt",
|
||||
severity="warning",
|
||||
detail=(
|
||||
f"Revision {neu['seq']}: Laufzeit auf die Ticketlaufzeit gesetzt "
|
||||
f"({'unbefristet' if neu.get('lifetime') else neu.get('expires_at')})"
|
||||
),
|
||||
# Was etwas wegnimmt, steht als Warnung im Protokoll -- was etwas gibt,
|
||||
# als Notiz. Beides ist derselbe Knopf, aber nicht dasselbe Ereignis.
|
||||
severity="notice" if neu.get("lifetime") else "warning",
|
||||
)
|
||||
reporting.report_soon(core())
|
||||
flash(
|
||||
|
||||
@@ -893,6 +893,54 @@ def lizenz_dem_ticket_nachziehen(
|
||||
)
|
||||
|
||||
|
||||
def ticket_abweichung(conn: sqlite3.Connection, license_id: str) -> dict[str, Any] | None:
|
||||
"""Weicht die Laufzeit dieser Lizenz von ihrem Ticket ab? Sonst ``None``.
|
||||
|
||||
Vier Faelle, und sie sind nicht symmetrisch:
|
||||
|
||||
=================== =================== ====================================
|
||||
Ticket Lizenz Abgleich
|
||||
=================== =================== ====================================
|
||||
unbefristet unbefristet nichts zu tun
|
||||
unbefristet befristet wird unbefristet -- ein Gewinn
|
||||
befristet unbefristet wird befristet -- eine **Ruecknahme**
|
||||
befristet befristet auf den Tag des Tickets
|
||||
=================== =================== ====================================
|
||||
|
||||
``verkuerzt`` sagt, ob der Abgleich etwas wegnimmt. Die Oberflaeche faerbt
|
||||
danach ihre Rueckfrage, und das Aenderungsprotokoll seine Stufe: eine
|
||||
unbefristete Zusage zu befristen ist die schaerfste Form davon.
|
||||
|
||||
Testlizenzen bleiben aussen vor -- sie leben nach eigenen Regeln.
|
||||
"""
|
||||
row = get_license(conn, license_id)
|
||||
if row is None or not row["ticket_id"] or str(row["type"]) == "trial":
|
||||
return None
|
||||
ticket = get_ticket(conn, str(row["ticket_id"]))
|
||||
if ticket is None:
|
||||
return None
|
||||
|
||||
ticket_unbefristet = bool(ticket["lifetime"])
|
||||
lizenz_unbefristet = bool(row["lifetime"])
|
||||
if ticket_unbefristet and lizenz_unbefristet:
|
||||
return None
|
||||
if ticket_unbefristet:
|
||||
return {"grenze": None, "unbefristet": True, "verkuerzt": False}
|
||||
|
||||
grenze = ticket_grenze(conn, license_id)
|
||||
if grenze is None:
|
||||
return None
|
||||
if not lizenz_unbefristet and str(row["expires_at"]) == grenze:
|
||||
return None
|
||||
return {
|
||||
"grenze": grenze,
|
||||
"unbefristet": False,
|
||||
# Unbefristet zu befristen nimmt immer etwas weg; sonst entscheidet
|
||||
# das Datum.
|
||||
"verkuerzt": lizenz_unbefristet or grenze < str(row["expires_at"]),
|
||||
}
|
||||
|
||||
|
||||
def lizenz_auf_ticket_setzen(
|
||||
conn: sqlite3.Connection, license_id: str, *, master_private_key: str
|
||||
) -> dict[str, Any] | None:
|
||||
@@ -913,21 +961,27 @@ def lizenz_auf_ticket_setzen(
|
||||
row = get_license(conn, license_id)
|
||||
if row is None:
|
||||
raise IssuanceError("Diese Lizenz existiert nicht.")
|
||||
if bool(row["lifetime"]):
|
||||
raise IssuanceError("Diese Lizenz ist unbefristet.")
|
||||
grenze = ticket_grenze(conn, license_id)
|
||||
if grenze is None:
|
||||
raise IssuanceError(
|
||||
"Zu dieser Lizenz gibt es keine begrenzte Ticketlaufzeit, an der sie "
|
||||
"auszurichten wäre."
|
||||
)
|
||||
if str(row["expires_at"]) == grenze:
|
||||
abweichung = ticket_abweichung(conn, license_id)
|
||||
if abweichung is None:
|
||||
return None
|
||||
|
||||
if abweichung["unbefristet"]:
|
||||
# Das Ticket gewaehrt unbefristet, die Lizenz laeuft ab. Der Abgleich
|
||||
# gibt etwas -- hier ist nichts zurueckzunehmen.
|
||||
changes: dict[str, Any] = {"lifetime": True}
|
||||
else:
|
||||
# Auch aus einer unbefristeten Lizenz wird hier wieder eine befristete.
|
||||
# Das ist die schaerfste Ruecknahme, die dieses System kennt, und
|
||||
# genau deshalb hat sie einen eigenen Knopf mit eigener Rueckfrage --
|
||||
# statt unmoeglich zu sein. Unmoeglich hiesse: eine unbefristete
|
||||
# Zusage, die versehentlich entstanden ist, bleibt fuer immer stehen.
|
||||
changes = {"lifetime": False, "expires_at": abweichung["grenze"]}
|
||||
|
||||
return resign_license(
|
||||
conn,
|
||||
license_id,
|
||||
master_private_key=master_private_key,
|
||||
changes={"expires_at": grenze},
|
||||
changes=changes,
|
||||
ueber_ticket=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -141,14 +141,18 @@
|
||||
{# Anspruch und Urkunde wieder zur Deckung bringen. In beide Richtungen --
|
||||
und wenn es verkürzt, ist das eine Rücknahme von Laufzeit: deshalb mit
|
||||
Rückfrage und eigener Zeile im Änderungsprotokoll. #}
|
||||
{% if ticket_grenze and ticket_grenze != license.expires_at %}
|
||||
{% if abweichung %}
|
||||
<section class="card">
|
||||
<div class="card__header">
|
||||
<div class="flex-1">
|
||||
<div class="card__title">{{ icon('shield', size=17) }} Laufzeit weicht vom Ticket ab</div>
|
||||
<div class="card__sub">
|
||||
Diese Lizenz läuft bis <strong>{{ license.expires_at | dt }}</strong>, das Ticket
|
||||
gewährt bis <strong>{{ ticket_grenze | dt }}</strong>.
|
||||
Diese Lizenz läuft
|
||||
{% if license.lifetime %}<strong>unbefristet</strong>
|
||||
{% else %}bis <strong>{{ license.expires_at | dt }}</strong>{% endif %},
|
||||
das Ticket gewährt
|
||||
{% if abweichung.unbefristet %}<strong>unbefristet</strong>
|
||||
{% else %}bis <strong>{{ abweichung.grenze | dt }}</strong>{% endif %}.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -157,10 +161,10 @@
|
||||
<input type="hidden" name="{{ csrf_field_name }}" value="{{ csrf_token() }}">
|
||||
<div class="card__footer">
|
||||
<button class="btn" type="submit"
|
||||
data-confirm="Die Laufzeit dieser Lizenz auf {{ ticket_grenze | dt }} setzen? {% if ticket_grenze < license.expires_at %}Das nimmt bereits zugesagte Laufzeit zurück -- der Client übernimmt es beim nächsten Heartbeat.{% endif %}"
|
||||
data-confirm="Die Laufzeit dieser Lizenz auf {% if abweichung.unbefristet %}unbefristet{% else %}{{ abweichung.grenze | dt }}{% endif %} setzen?{% if abweichung.verkuerzt %} Das nimmt bereits zugesagte Laufzeit zurück{% if license.lifetime %} -- aus einer unbefristeten Lizenz wird eine befristete{% endif %}. Der Client übernimmt es beim nächsten Heartbeat.{% endif %}"
|
||||
data-confirm-title="Auf die Ticketlaufzeit setzen"
|
||||
data-confirm-ok="Setzen"
|
||||
data-confirm-style="{{ 'danger' if ticket_grenze < license.expires_at else 'primary' }}">
|
||||
data-confirm-style="{{ 'danger' if abweichung.verkuerzt else 'primary' }}">
|
||||
Auf die Ticketlaufzeit setzen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user