This commit is contained in:
onysd 2026-08-04 02:03:59 +03:00
parent 1757ba7266
commit 6ade34970c
2 changed files with 95 additions and 21 deletions

View file

@ -221,6 +221,24 @@ TELESRV_BUSINESS_AI_PROVIDER=echo
# Master switch for in-app message/chat translation. # Master switch for in-app message/chat translation.
TELESRV_TRANSLATION_ENABLED=true TELESRV_TRANSLATION_ENABLED=true
## Moderation, Verification & Rating -- Toggles for the report-review queue, official/third-party verification, and the account-rating score.
# Reports and moderation-case review are always on; this only gates the
# official platform-checkmark flow applicants file through @verifybot. Rate
# limits and cooldowns for it live in the Advanced section below.
TELESRV_VERIFICATION_ENABLED=true
# Plain user accounts as verification subjects. Off by default: the official
# process verifies a public presence (bot, public channel, public supergroup).
TELESRV_VERIFICATION_ALLOW_USER_TARGETS=false
# Third-party bot verification marks (an icon + description shown before a
# peer's name) -- a separate mechanism from the checkmark above, not the
# platform badge. Its tuning lives in the Advanced section below.
TELESRV_BOT_VERIFICATION_ENABLED=true
# Local composite account-rating score (stars/activity/moderation-based).
# Shown to every viewer via userFull.stars_rating, not admin-only. Scoring
# weights and recompute timing live in the Advanced section below.
TELESRV_RATING_ENABLED=true
# ============================================================================== # ==============================================================================
# Advanced / internal tuning # Advanced / internal tuning
@ -377,11 +395,10 @@ TELESRV_STARGIFT_RESELL_DELAY=0s
TELESRV_STARGIFT_CRAFT_DELAY=0s TELESRV_STARGIFT_CRAFT_DELAY=0s
TELESRV_STARGIFT_CRAFT_CHANCE_PERMILLE=250 TELESRV_STARGIFT_CRAFT_CHANCE_PERMILLE=250
# Local admin-only composite account rating. It is not projected into Telegram's # Tuning for the account-rating score; the on/off switch
# userFull.stars_rating fields. Disabling it refuses local rating writes. # (TELESRV_RATING_ENABLED) is in the Moderation/Verification/Rating section above.
TELESRV_RATING_ENABLED=true
# A local rating increase is parked for this long before it becomes the visible # A local rating increase is parked for this long before it becomes the visible
# admin level; a decrease always applies immediately. 0 applies every change at once. # level; a decrease always applies immediately. 0 applies every change at once.
TELESRV_RATING_PENDING_DELAY=24h TELESRV_RATING_PENDING_DELAY=24h
# Background recompute worker: the rating derives from signals owned by other # Background recompute worker: the rating derives from signals owned by other
# subsystems, so freshness is a worker property rather than a write-path one. # subsystems, so freshness is a worker property rather than a write-path one.
@ -410,15 +427,10 @@ TELESRV_RATING_ACTIVITY_CAP=5000
# segment. No external marketplace is contacted. # segment. No external marketplace is contacted.
TELESRV_COLLECTIBLE_USERNAME_URL_TEMPLATE= TELESRV_COLLECTIBLE_USERNAME_URL_TEMPLATE=
# Official platform verification: applications filed through the built-in # Tuning for official platform verification (applications filed through
# @verifybot and decided in the admin panel. An approval flips the platform # @verifybot); the on/off switch (TELESRV_VERIFICATION_ENABLED) and the
# verified flag on the target peer and nothing else; it is not the third-party # user-target toggle (TELESRV_VERIFICATION_ALLOW_USER_TARGETS) are in the
# bot verification icon. Disabling refuses every verification use case, while # Moderation/Verification/Rating section above.
# peers already carrying the badge keep it.
TELESRV_VERIFICATION_ENABLED=true
# Plain user accounts as verification subjects. Off by default: the official
# process verifies a public presence (bot, public channel, public supergroup).
TELESRV_VERIFICATION_ALLOW_USER_TARGETS=false
# How long an applicant must wait before filing the same target again after a # How long an applicant must wait before filing the same target again after a
# rejection, measured from the decision so a slow review never shortens it. # rejection, measured from the decision so a slow review never shortens it.
# 0 disables the cooldown; must be 0..8760h. # 0 disables the cooldown; must be 0..8760h.
@ -440,14 +452,9 @@ TELESRV_VERIFICATION_NOTIFY_BATCH=50
# is 50. # is 50.
TELESRV_VERIFICATION_MAX_ACTIVE_PER_USER=3 TELESRV_VERIFICATION_MAX_ACTIVE_PER_USER=3
# Third-party bot verification (core.telegram.org/api/bots/verification): a # Tuning for third-party bot verification; the on/off switch
# verifier bot marks peers with its OWN icon and description, which clients render # (TELESRV_BOT_VERIFICATION_ENABLED) is in the Moderation/Verification/Rating
# before the name. This is NOT the platform checkmark above: the operator grants # section above.
# verifier status to a bot, and the two mechanisms never read each other's state.
# Disabling refuses every third-party mutation (grants, revocations, applications,
# icon catalogue edits) while the marks already granted keep rendering -- blanking
# one verifier's badges is what its per-verifier kill switch is for.
TELESRV_BOT_VERIFICATION_ENABLED=true
# Peers one verifier bot may mark. Verifier status is granted per deployment rather # Peers one verifier bot may mark. Verifier status is granted per deployment rather
# than earned per peer, so an unbounded verifier would be an unbounded badge # than earned per peer, so an unbounded verifier would be an unbounded badge
# printer. 0 disables the service bound and leaves only the storage bound, which is # printer. 0 disables the service bound and leaves only the storage bound, which is

View file

@ -486,6 +486,55 @@ def save_env(values: dict[str, str]) -> None:
ENV_FILE.write_text("\n".join(out_lines) + "\n", encoding="utf-8") ENV_FILE.write_text("\n".join(out_lines) + "\n", encoding="utf-8")
def missing_env_fields() -> list[tuple[str, str]]:
"""(key, default_value) pairs for every *active* (uncommented) field
.env.example defines that .env doesn't have at all -- e.g. after a git
pull brought in new TELESRV_* settings for features that didn't exist
when this install's .env was first created.
Deliberately scans the whole file, not just parse_env_template()'s
panel-visible groups, so an Advanced-section field missing from .env
gets caught too. Deliberately skips template-commented (disabled by
default) fields -- those are meant to stay absent/off unless a self-hoster
opts in, and the server already falls back to the same default shown in
the comment when the key isn't set at all, so there's nothing to fix.
A key already present in .env is never touched, even if blank -- clearing
a field on purpose must never get silently reintroduced."""
if not ENV_FILE.exists() or not ENV_EXAMPLE_FILE.exists():
return []
existing_keys: set[str] = set()
for line in ENV_FILE.read_text(encoding="utf-8", errors="replace").splitlines():
m = _ACTIVE_FIELD_RE.match(line.strip())
if m:
existing_keys.add(m.group(1))
missing: list[tuple[str, str]] = []
seen: set[str] = set()
for line in ENV_EXAMPLE_FILE.read_text(encoding="utf-8", errors="replace").splitlines():
m = _ACTIVE_FIELD_RE.match(line.strip())
if m and m.group(1) not in existing_keys and m.group(1) not in seen:
seen.add(m.group(1))
missing.append((m.group(1), m.group(2)))
return missing
def append_missing_env_fields(missing: list[tuple[str, str]]) -> None:
"""Appends (key, default_value) pairs to .env in one clearly-labeled,
timestamped block, so a self-hoster immediately sees what was added and
why. Purely additive -- never rewrites, reorders, or removes a single
existing line, unlike save_env()'s full rewrite-from-template."""
if not missing:
return
block = [
"",
f"# --- Added automatically by server-panel.py on "
f"{time.strftime('%Y-%m-%d %H:%M')}: new fields found in .env.example "
f"that this .env didn't have yet ---",
]
block += [f"{key}={value}" for key, value in missing]
with ENV_FILE.open("a", encoding="utf-8") as f:
f.write("\n".join(block) + "\n")
def admin_ui_info() -> tuple[str, str | None] | None: def admin_ui_info() -> tuple[str, str | None] | None:
"""Returns (url, password) for the admin UI, or None if it isn't """Returns (url, password) for the admin UI, or None if it isn't
configured at all. password is None when TELESRV_ADMIN_UI_PASSWORD is configured at all. password is None when TELESRV_ADMIN_UI_PASSWORD is
@ -1155,6 +1204,7 @@ class MainScreen(Screen):
def on_mount(self) -> None: def on_mount(self) -> None:
self.query_one("#services-table", DataTable).add_columns("Service", "Type", "Status") self.query_one("#services-table", DataTable).add_columns("Service", "Type", "Status")
self._sync_missing_env_fields()
self.refresh_status() self.refresh_status()
self.refresh_stats() self.refresh_stats()
self.refresh_config_widgets() self.refresh_config_widgets()
@ -1164,6 +1214,23 @@ class MainScreen(Screen):
if self._auto_start: if self._auto_start:
self.action_start() self.action_start()
def _sync_missing_env_fields(self) -> None:
"""Catches .env falling behind .env.example -- e.g. a git pull that
added new TELESRV_* settings for a feature this install predates.
Runs once per panel launch, before Start, so a missing field never
surprises the server at startup instead. A no-op on a fresh install
(Setup already writes every field at once) and a no-op once .env has
caught up."""
missing = missing_env_fields()
if not missing:
return
append_missing_env_fields(missing)
keys = ", ".join(key for key, _ in missing)
self.notify(
f"Added {len(missing)} new field(s) to .env from .env.example: {keys}",
timeout=10,
)
def refresh_status(self) -> None: def refresh_status(self) -> None:
status = MANAGER.status() status = MANAGER.status()
table = self.query_one("#services-table", DataTable) table = self.query_one("#services-table", DataTable)