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]
|
[project]
|
||||||
name = "tesm-license"
|
name = "tesm-license"
|
||||||
version = "2.8.14"
|
version = "2.8.15"
|
||||||
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -78,9 +78,11 @@ def detail(license_id: str):
|
|||||||
"license/license_detail.html",
|
"license/license_detail.html",
|
||||||
license=row,
|
license=row,
|
||||||
state=issuance.display_state(row),
|
state=issuance.display_state(row),
|
||||||
# Bis wohin traegt das Ticket? Die Seite zeigt eine Abweichung an,
|
# Bis wohin traegt das Ticket, und weicht die Lizenz davon ab? Die
|
||||||
# statt sie erst in einer Fehlermeldung auftauchen zu lassen.
|
# Seite zeigt es an, statt es erst in einer Fehlermeldung auftauchen zu
|
||||||
|
# lassen.
|
||||||
ticket_grenze=issuance.ticket_grenze(conn, license_id),
|
ticket_grenze=issuance.ticket_grenze(conn, license_id),
|
||||||
|
abweichung=issuance.ticket_abweichung(conn, license_id),
|
||||||
document=document,
|
document=document,
|
||||||
document_json=json.dumps(document, indent=2, ensure_ascii=False, sort_keys=True),
|
document_json=json.dumps(document, indent=2, ensure_ascii=False, sort_keys=True),
|
||||||
deliveries=Database.all(
|
deliveries=Database.all(
|
||||||
@@ -214,8 +216,13 @@ def align_ticket(license_id: str):
|
|||||||
log_event(
|
log_event(
|
||||||
"license.resigned",
|
"license.resigned",
|
||||||
target=license_id[:12],
|
target=license_id[:12],
|
||||||
detail=f"Revision {neu['seq']}: Laufzeit auf die Ticketlaufzeit gesetzt",
|
detail=(
|
||||||
severity="warning",
|
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())
|
reporting.report_soon(core())
|
||||||
flash(
|
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(
|
def lizenz_auf_ticket_setzen(
|
||||||
conn: sqlite3.Connection, license_id: str, *, master_private_key: str
|
conn: sqlite3.Connection, license_id: str, *, master_private_key: str
|
||||||
) -> dict[str, Any] | None:
|
) -> dict[str, Any] | None:
|
||||||
@@ -913,21 +961,27 @@ def lizenz_auf_ticket_setzen(
|
|||||||
row = get_license(conn, license_id)
|
row = get_license(conn, license_id)
|
||||||
if row is None:
|
if row is None:
|
||||||
raise IssuanceError("Diese Lizenz existiert nicht.")
|
raise IssuanceError("Diese Lizenz existiert nicht.")
|
||||||
if bool(row["lifetime"]):
|
abweichung = ticket_abweichung(conn, license_id)
|
||||||
raise IssuanceError("Diese Lizenz ist unbefristet.")
|
if abweichung is None:
|
||||||
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:
|
|
||||||
return 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(
|
return resign_license(
|
||||||
conn,
|
conn,
|
||||||
license_id,
|
license_id,
|
||||||
master_private_key=master_private_key,
|
master_private_key=master_private_key,
|
||||||
changes={"expires_at": grenze},
|
changes=changes,
|
||||||
ueber_ticket=True,
|
ueber_ticket=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -141,14 +141,18 @@
|
|||||||
{# Anspruch und Urkunde wieder zur Deckung bringen. In beide Richtungen --
|
{# Anspruch und Urkunde wieder zur Deckung bringen. In beide Richtungen --
|
||||||
und wenn es verkürzt, ist das eine Rücknahme von Laufzeit: deshalb mit
|
und wenn es verkürzt, ist das eine Rücknahme von Laufzeit: deshalb mit
|
||||||
Rückfrage und eigener Zeile im Änderungsprotokoll. #}
|
Rückfrage und eigener Zeile im Änderungsprotokoll. #}
|
||||||
{% if ticket_grenze and ticket_grenze != license.expires_at %}
|
{% if abweichung %}
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<div class="card__header">
|
<div class="card__header">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="card__title">{{ icon('shield', size=17) }} Laufzeit weicht vom Ticket ab</div>
|
<div class="card__title">{{ icon('shield', size=17) }} Laufzeit weicht vom Ticket ab</div>
|
||||||
<div class="card__sub">
|
<div class="card__sub">
|
||||||
Diese Lizenz läuft bis <strong>{{ license.expires_at | dt }}</strong>, das Ticket
|
Diese Lizenz läuft
|
||||||
gewährt bis <strong>{{ ticket_grenze | dt }}</strong>.
|
{% 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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -157,10 +161,10 @@
|
|||||||
<input type="hidden" name="{{ csrf_field_name }}" value="{{ csrf_token() }}">
|
<input type="hidden" name="{{ csrf_field_name }}" value="{{ csrf_token() }}">
|
||||||
<div class="card__footer">
|
<div class="card__footer">
|
||||||
<button class="btn" type="submit"
|
<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-title="Auf die Ticketlaufzeit setzen"
|
||||||
data-confirm-ok="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
|
Auf die Ticketlaufzeit setzen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user