This commit is contained in:
Mateusz Gruszczyński committed 2026-11-04 08:55:53 +01:00
1 parent cdca612a59
commit eb25f8de4a
56 files changed
+7848 -4345

No files matched your search

+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""End-to-end API check of a running PostfixAdmin-RS instance.
python3 scripts/api-smoke.py http://127.0.0.1:8080 admin@example.test admin123
Uses a global administrator, creates the domains rs-smoke-a.test and
rs-smoke-b.test, exercises the PostfixAdmin business rules (limits, quota,
aliases, forwarding, vacation, permissions) and deletes everything again.
Run it only against a development or staging database. With
features.emailcheck_resolve_domain = true the .test domains are rejected,
disable that check for the test instance.
"""
import http.cookiejar
import json
import sys
import urllib.error
import urllib.request
BASE = sys.argv[1].rstrip("/") if len(sys.argv) > 1 else "http://127.0.0.1:8080"
ADMIN = sys.argv[2] if len(sys.argv) > 2 else "admin@example.test"
PASSWORD = sys.argv[3] if len(sys.argv) > 3 else "admin123"
A, B = "rs-smoke-a.test", "rs-smoke-b.test"
failures = 0
class Client:
def __init__(self):
self.jar = http.cookiejar.CookieJar()
self.opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(self.jar))
self.csrf = ""
def req(self, method, path, body=None, expect=None, quiet=False, silent=False):
global failures
data = json.dumps(body).encode() if body is not None else None
request = urllib.request.Request(BASE + "/api" + path, data=data, method=method)
if data:
request.add_header("content-type", "application/json")
if self.csrf:
request.add_header("x-csrf-token", self.csrf)
try:
response = self.opener.open(request)
code, text = response.status, response.read().decode()
except urllib.error.HTTPError as error:
code, text = error.code, error.read().decode()
ok = (expect is None and code < 300) or code == expect
if silent:
return json.loads(text) if text else None
if not ok:
failures += 1
if not ok or not quiet:
detail = "" if ok and code < 300 else " " + text[:160]
print(f"{'ok ' if ok else 'FAIL'} {method:6} {path} -> {code}{detail}")
return json.loads(text) if text else None
def login(self, username, password, kind=None):
body = {"username": username, "password": password}
if kind:
body["kind"] = kind
result = self.req("POST", "/auth/login", body)
self.csrf = (result or {}).get("csrf", "")
return result
def main():
global failures
admin = Client()
admin.login(ADMIN, PASSWORD)
runtime = admin.req("GET", "/system/features", quiet=True)
features = runtime["features"]
quota = features.get("quota") and features.get("domain_quota")
# remove leftovers of an interrupted run (result ignored)
admin.req("DELETE", f"/admins/da@{A}", silent=True)
admin.req("DELETE", f"/alias-domains/{B}", silent=True)
for domain in (A, B):
admin.req("DELETE", f"/domains/{domain}", silent=True)
admin.req("POST", "/domains", {"domain": A, "description": "smoke", "aliases": 6, "mailboxes": 2,
"maxquota": 100, "quota": 150, "default_aliases": True})
admin.req("POST", "/domains", {"domain": B, "aliases": 0, "mailboxes": 0, "maxquota": 0, "quota": 0,
"default_aliases": False})
admin.req("POST", "/domains", {"domain": A}, expect=409)
admin.req("POST", "/domains", {"domain": "bad-limit.test", "aliases": -2}, expect=400)
pw = "Smoke12pass"
if quota:
admin.req("POST", "/mailboxes", {"domain": A, "local_part": "u1", "password": pw, "quota": 0}, expect=400)
admin.req("POST", "/mailboxes", {"domain": A, "local_part": "u1", "password": pw, "quota": 101}, expect=400)
admin.req("POST", "/mailboxes", {"domain": A, "local_part": "u1", "password": pw, "quota": 100, "name": "User One"})
if quota:
admin.req("POST", "/mailboxes", {"domain": A, "local_part": "u2", "password": pw, "quota": 60}, expect=400)
hint = admin.req("GET", f"/mailboxes/quota-hint?domain={A}", quiet=True)
if hint["allowed_mb"] != 50:
print("FAIL quota hint", hint)
admin.req("POST", "/mailboxes", {"domain": A, "local_part": "u2", "password": pw, "quota": 50})
admin.req("POST", "/mailboxes", {"domain": A, "local_part": "u3", "password": pw, "quota": 0}, expect=409)
admin.req("POST", "/mailboxes", {"domain": B, "local_part": "weak", "password": "abc"}, expect=400)
# aliases (4 default aliases + limit 6)
admin.req("POST", "/aliases", {"domain": A, "local_part": "info", "goto": [f"u1@{A}"]})
admin.req("POST", "/aliases", {"domain": A, "local_part": "sales", "goto": [f"u1@{A}"]})
admin.req("POST", "/aliases", {"domain": A, "local_part": "more", "goto": [f"u1@{A}"]}, expect=409)
admin.req("POST", "/aliases", {"domain": B, "local_part": "loop", "goto": [f"loop@{B}"]}, expect=400)
admin.req("POST", "/aliases", {"domain": B, "local_part": "*", "goto": [f"@{A}"]})
admin.req("POST", "/aliases", {"domain": B, "local_part": "root", "goto": ["root"]})
listing = admin.req("GET", f"/aliases?domain={A}", quiet=True)
if any(item["is_mailbox"] for item in listing["items"]):
print("FAIL mailbox aliases must not be listed for admins")
failures += 1
# forwarding / activity / search
admin.req("PUT", f"/mailboxes/u1@{A}/forwarding", {"forward_to": ["ext@example.org"], "deliver_to_mailbox": True})
mailbox = admin.req("GET", f"/mailboxes/u1@{A}", quiet=True)
if mailbox["forward_to"] != ["ext@example.org"] or not mailbox["deliver_to_mailbox"]:
print("FAIL forwarding", mailbox)
admin.req("POST", f"/aliases/sales@{A}/active", {"active": False})
admin.req("POST", f"/aliases/delete-inactive/{A}")
found = admin.req("GET", f"/mailboxes?domain={A}&q=one", quiet=True)
if found["total"] != 1:
print("FAIL search", found)
if features.get("vacation"):
admin.req("PUT", f"/vacation/u1@{A}", {"email": f"u1@{A}", "subject": "Away", "body": "Back soon",
"interval_time": (runtime["defaults"].get("vacation_choice_of_reply") or [0])[0],
"active_from": "2026-01-01", "active_until": "2026-01-31", "active": True})
mailbox = admin.req("GET", f"/mailboxes/u1@{A}", quiet=True)
if not mailbox["vacation_active"]:
print("FAIL vacation flag")
admin.req("DELETE", f"/vacation/u1@{A}")
# domain administrator
admin.req("POST", "/admins", {"username": f"da@{A}", "password": pw, "domains": [A]})
dadmin = Client()
dadmin.login(f"da@{A}", pw)
dadmin.req("POST", "/domains", {"domain": "x.test"}, expect=403)
dadmin.req("GET", f"/mailboxes?domain={B}", expect=403)
dadmin.req("POST", f"/mailboxes/u2@{A}/active", {"active": False})
admin.req("PUT", f"/admins/da@{A}", {"username": f"da@{A}", "password": "Changed12pw", "domains": [A], "active": True})
dadmin.req("GET", "/domains", expect=401)
# mailbox user
user = Client()
user.login(f"u1@{A}", pw)
user.req("GET", f"/mailboxes/u2@{A}", expect=403)
user.req("PUT", f"/mailboxes/u1@{A}/forwarding", {"forward_to": [], "deliver_to_mailbox": True})
user.req("POST", "/security/password", {"current_password": pw, "new_password": pw}, expect=400)
user.req("POST", "/security/password", {"current_password": pw, "new_password": "Newer12pass"})
# alias domain + deletion rules
admin.req("POST", "/alias-domains", {"alias_domain": B, "target_domain": A})
admin.req("DELETE", f"/domains/{A}", expect=409)
admin.req("DELETE", f"/alias-domains/{B}")
admin.req("DELETE", f"/admins/da@{A}")
admin.req("DELETE", f"/domains/{B}")
admin.req("DELETE", f"/domains/{A}")
print(f"\n{failures} failure(s)")
sys.exit(1 if failures else 0)
if __name__ == "__main__":
main()
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Build src/web/i18n/pl.json from scripts/i18n/pl_messages.py and report
UI strings that have no Polish translation."""
import json, re, sys
from pathlib import Path
root = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(Path(__file__).parent))
import pl_messages as pl # noqa: E402
src = "".join((root / "src/web/js" / f).read_text() for f in ("00-core.js", "10-pages.js"))
keys = set(m.group(1).replace("\\'", "'") for m in re.finditer(r"\bte?\(\s*'((?:[^'\\]|\\.)*)'", src))
for m in re.finditer(r"\['\w+', '([^']+)', '(Management|Services|Account|Mailbox)'", src):
keys.update(m.groups())
for m in re.finditer(r"(?:STATUS_LABELS|STATUS_HINTS|INTERVAL_LABELS) = \{([^}]*)\}", src):
keys.update(re.findall(r":\s*'([^']+)'", m.group(1)))
for m in re.finditer(r"(?:showToast\(|message: )'((?:[^'\\]|\\.)*)'", src):
keys.add(m.group(1))
messages = {**pl.SERVER, **pl.UI}
missing = sorted(k for k in keys if k not in messages)
catalog = {
"language": "pl",
"messages": dict(sorted(messages.items())),
"patterns": [{"match": m, "replace": r} for m, r in pl.PATTERNS],
}
(root / "src/web/i18n/pl.json").write_text(json.dumps(catalog, ensure_ascii=False, indent=1) + "\n")
(root / "src/web/i18n/en.json").write_text(json.dumps({"language": "en", "messages": {}, "patterns": []}, indent=1) + "\n")
print(f"pl.json: {len(messages)} messages, {len(pl.PATTERNS)} patterns")
if missing:
print("MISSING translations:")
for k in missing:
print(" ", k)
sys.exit(1)
+593
View File
@@ -0,0 +1,593 @@
# Polish UI catalog source. Run scripts/i18n/build.py to regenerate
# src/web/i18n/pl.json. Keys are the English source strings used in the UI
# (t('...')) and the English API error messages.
UI = {
"-1 = disabled, 0 = unlimited": "-1 = wyłączone, 0 = bez limitu",
"0 = passwords never expire": "0 = hasła nie wygasają",
"0 = unlimited": "0 = bez limitu",
"6-digit code": "Kod 6-cyfrowy",
"6-digit code from your authenticator app": "6-cyfrowy kod z aplikacji uwierzytelniającej",
"@{domain} — use * for a catch-all alias": "@{domain} — wpisz *, aby utworzyć alias catch-all",
"A catch-all may forward to a whole domain: @otherdomain.tld": "Alias catch-all może przekazywać na całą domenę: @innadomena.pl",
"A one-time code will be sent to the alternative e-mail address stored for the account.": "Jednorazowy kod zostanie wysłany na alternatywny adres e-mail zapisany dla konta.",
"Account": "Konto",
"Account (empty = all your accounts)": "Konto (puste = wszystkie Twoje konta)",
"Account type": "Typ konta",
"Action": "Akcja",
"Activate": "Aktywuj",
"Active": "Aktywne",
"Add": "Dodaj",
"Add alias": "Dodaj alias",
"Add alias domain": "Dodaj domenę aliasową",
"Add alias to {domain}": "Nowy alias w {domain}",
"Add default aliases": "Dodaj domyślne aliasy",
"Add mailbox": "Dodaj skrzynkę",
"Add mailbox to {domain}": "Nowa skrzynka w {domain}",
"Add rule": "Dodaj regułę",
"Add the key to your authenticator app (e.g. by opening the link on your phone), then enter the code it shows.": "Dodaj klucz do aplikacji uwierzytelniającej (np. otwierając link na telefonie), a następnie wpisz wyświetlony kod.",
"Administrator": "Administrator",
"Administrator saved": "Administrator zapisany",
"Administrators": "Administratorzy",
"Alias": "Alias",
"Alias created": "Alias utworzony",
"Alias domain": "Domena aliasowa",
"Alias domain saved": "Domena aliasowa zapisana",
"Alias domains": "Domeny aliasowe",
"Alias updated": "Alias zaktualizowany",
"Aliases": "Aliasy",
"All": "Wszystkie",
"All domains": "Wszystkie domeny",
"Allow sending mail (SMTP)": "Zezwalaj na wysyłanie poczty (SMTP)",
"Alternative e-mail (password recovery)": "Alternatywny e-mail (odzyskiwanie hasła)",
"Application password": "Hasło aplikacji",
"Application password created": "Hasło aplikacji utworzone",
"Application passwords": "Hasła aplikacji",
"At least one local destination does not exist": "Co najmniej jeden lokalny adres docelowy nie istnieje",
"At least {n} characters, {l} letters and {d} digits": "Co najmniej {n} znaków, w tym {l} litery i {d} cyfry",
"Authentication": "Uwierzytelnianie",
"Author (domain or address)": "Nadawca (domena lub adres)",
"Auto-reply": "Autoresponder",
"Auto-reply activated": "Autoresponder włączony",
"Auto-reply is active": "Autoresponder jest aktywny",
"Auto-reply is switched off": "Autoresponder jest wyłączony",
"Auto-reply is switched on": "Autoresponder jest włączony",
"Auto-reply switched off": "Autoresponder wyłączony",
"Automatic": "Automatycznie",
"Automatic reply while you are away": "Automatyczna odpowiedź podczas Twojej nieobecności",
"Back": "Wstecz",
"Backup MX": "Zapasowy MX",
"Broadcast message": "Wiadomość do wszystkich",
"Cancel": "Anuluj",
"Change name": "Zmień nazwę",
"Change password": "Zmień hasło",
"Changes made through the administration interface": "Zmiany wprowadzone w panelu administracyjnym",
"Check": "Sprawdź",
"Check DNS now": "Sprawdź DNS teraz",
"Choose the mailbox whose auto-reply (vacation) you want to edit": "Wybierz skrzynkę, której autoresponder chcesz edytować",
"Close": "Zamknij",
"Coming back": "Wracam",
"Configure maps": "Skonfiguruj mapy",
"Continue": "Dalej",
"Copied": "Skopiowano",
"Copy": "Kopiuj",
"Copy to folder": "Kopiuj do folderu",
"Could not copy to the clipboard": "Nie udało się skopiować do schowka",
"Create": "Utwórz",
"Create a DKIM key first.": "Najpierw utwórz klucz DKIM.",
"Create a script to start filtering your mail.": "Utwórz skrypt, aby zacząć filtrować pocztę.",
"Current password": "Obecne hasło",
"Currently stored: {v}": "Obecnie zapisane: {v}",
"DKIM": "DKIM",
"DKIM DNS records of your domain (read-only)": "Rekordy DNS DKIM Twojej domeny (tylko do odczytu)",
"DKIM key saved": "Klucz DKIM zapisany",
"DNS check failed": "Sprawdzenie DNS nie powiodło się",
"DNS check passed": "Sprawdzenie DNS zakończone powodzeniem",
"DNS record": "Rekord DNS",
"Data": "Dane",
"Database": "Baza danych",
"Database connection is read-only": "Połączenie z bazą jest tylko do odczytu",
"Database schema and runtime configuration": "Schemat bazy danych i konfiguracja",
"Deactivate all": "Dezaktywuj wszystkie",
"Default alias": "Alias domyślny",
"Delete": "Usuń",
"Delete DKIM key": "Usuń klucz DKIM",
"Delete administrator": "Usuń administratora",
"Delete alias": "Usuń alias",
"Delete alias domain": "Usuń domenę aliasową",
"Delete all inactive aliases of {domain}? Mailbox aliases and protected aliases are skipped.": "Usunąć wszystkie nieaktywne aliasy domeny {domain}? Aliasy skrzynek i aliasy chronione zostaną pominięte.",
"Delete application password": "Usuń hasło aplikacji",
"Delete domain": "Usuń domenę",
"Delete exception": "Usuń wyjątek",
"Delete fetchmail entry": "Usuń wpis fetchmail",
"Delete inactive": "Usuń nieaktywne",
"Delete inactive aliases": "Usuń nieaktywne aliasy",
"Delete key": "Usuń klucz",
"Delete mailbox": "Usuń skrzynkę",
"Delete script": "Usuń skrypt",
"Delete signing entry": "Usuń wpis podpisywania",
"Delete the administrator {a}?": "Usunąć administratora {a}?",
"Delete the alias domain {a} → {b}?": "Usunąć domenę aliasową {a} → {b}?",
"Delete the alias {a}?": "Usunąć alias {a}?",
"Delete the application password “{d}”?": "Usunąć hasło aplikacji „{d}”?",
"Delete the exception for {ip}?": "Usunąć wyjątek dla {ip}?",
"Delete the fetchmail entry {u}@{s}?": "Usunąć wpis fetchmail {u}@{s}?",
"Delete the key {d} / {s}?": "Usunąć klucz {d} / {s}?",
"Delete the mailbox {m}? Its alias, auto-reply, fetchmail entries and quota data are removed as well. Mail files on the server are only removed by a configured deletion hook.": "Usunąć skrzynkę {m}? Zostaną usunięte także jej alias, autoresponder, wpisy fetchmail i dane quota. Pliki poczty na serwerze usuwa tylko skonfigurowany hook usuwania.",
"Delete the script {s}?": "Usunąć skrypt {s}?",
"Delete the signing entry for {a}?": "Usunąć wpis podpisywania dla {a}?",
"Delete {domain} together with all mailboxes, aliases, alias domains and log entries? This cannot be undone.": "Usunąć {domain} razem ze wszystkimi skrzynkami, aliasami, domenami aliasowymi i wpisami dziennika? Tej operacji nie można cofnąć.",
"Deleted: {d}, skipped: {s}": "Usunięto: {d}, pominięto: {s}",
"Delivered to the mailbox (POP/IMAP)": "Dostarczane do skrzynki (POP/IMAP)",
"Delivery": "Dostarczanie",
"Description": "Opis",
"Description (e.g. phone)": "Opis (np. telefon)",
"Disable": "Wyłącz",
"Disable two-factor authentication": "Wyłącz uwierzytelnianie dwuskładnikowe",
"Disabled": "Wyłączone",
"Discard": "Odrzuć",
"Domain": "Domena",
"Domain administrator": "Administrator domen",
"Domain deleted": "Domena usunięta",
"Domain quota": "Quota domeny",
"Domain quota (MB)": "Quota domeny (MB)",
"Domains": "Domeny",
"Download backup": "Pobierz kopię zapasową",
"E-mail address": "Adres e-mail",
"Edit": "Edytuj",
"Edit DKIM key": "Edytuj klucz DKIM",
"Edit administrator": "Edytuj administratora",
"Edit alias": "Edytuj alias",
"Edit alias domain": "Edytuj domenę aliasową",
"Edit auto-reply": "Edytuj autoresponder",
"Edit domain": "Edytuj domenę",
"Edit fetchmail entry": "Edytuj wpis fetchmail",
"Edit mailbox": "Edytuj skrzynkę",
"Edit signing entry": "Edytuj wpis podpisywania",
"Empty = protocol default": "Puste = domyślny port protokołu",
"Enabled": "Włączone",
"Enabled features": "Włączone funkcje",
"Enter a search term in the search field above.": "Wpisz szukaną frazę w polu wyszukiwania powyżej.",
"Enter a valid header name": "Podaj poprawną nazwę nagłówka",
"Enter a value for the condition": "Podaj wartość warunku",
"Enter the forwarding address": "Podaj adres przekierowania",
"Enter the target folder": "Podaj folder docelowy",
"Error": "Błąd",
"External": "Zewnętrzny",
"Extra options": "Dodatkowe opcje",
"Fetch all messages (also already seen)": "Pobieraj wszystkie wiadomości (także przeczytane)",
"Fetchmail": "Fetchmail",
"Fetchmail entry saved": "Wpis fetchmail zapisany",
"File": "Plik",
"Filter": "Filtruj",
"Filters": "Filtry",
"Filter…": "Filtruj…",
"Folder": "Folder",
"Folder or address": "Folder lub adres",
"Forgot password": "Nie pamiętam hasła",
"Forgot password?": "Nie pamiętasz hasła?",
"Forward incoming mail to other addresses": "Przekazuj przychodzącą pocztę na inne adresy",
"Forward only": "Tylko przekazywanie",
"Forward to (one address per line)": "Przekazuj na (jeden adres w wierszu)",
"Forwarding": "Przekierowanie",
"Forwarding for {m}": "Przekierowanie dla {m}",
"Forwarding saved": "Przekierowanie zapisane",
"Forwards to a domain outside your administration": "Przekazuje do domeny spoza Twojej administracji",
"From": "Od",
"Generate": "Generuj",
"Generate DKIM key": "Wygeneruj klucz DKIM",
"Generate key": "Wygeneruj klucz",
"Global administrator": "Administrator globalny",
"Global administrator (all domains)": "Administrator globalny (wszystkie domeny)",
"Global and domain administrators": "Administratorzy globalni i administratorzy domen",
"Header name (for “Other header”)": "Nazwa nagłówka (dla „Inny nagłówek”)",
"I am currently out of the office and will reply after my return.": "Jestem obecnie poza biurem i odpowiem po powrocie.",
"I have a code": "Mam kod",
"IP address": "Adres IP",
"If": "Jeżeli",
"If the account is eligible, a recovery code has been sent to its alternative e-mail address.": "Jeśli konto spełnia warunki, kod odzyskiwania został wysłany na jego alternatywny adres e-mail.",
"Import": "Importuj",
"Import Rspamd configuration": "Import konfiguracji Rspamd",
"Import existing configuration": "Importuj istniejącą konfigurację",
"Import result": "Wynik importu",
"Imported: {n}": "Zaimportowano: {n}",
"Inactive": "Nieaktywne",
"Interval": "Interwał",
"Keep a copy in my mailbox (forward and store)": "Zachowaj kopię w mojej skrzynce (przekaż i zachowaj)",
"Keep a copy in the mailbox (forward and store)": "Zachowaj kopię w skrzynce (przekaż i zachowaj)",
"Keep in inbox": "Zostaw w skrzynce odbiorczej",
"Keep messages on the server": "Pozostaw wiadomości na serwerze",
"Key": "Klucz",
"Key mapped": "Klucz podłączony",
"Key size": "Długość klucza",
"Keys": "Klucze",
"Keys and signing table stored in the PostfixAdmin database (OpenDKIM)": "Klucze i tabela podpisywania w bazie PostfixAdmin (OpenDKIM)",
"Language": "Język",
"Last result": "Ostatni wynik",
"Leave empty to generate a password": "Pozostaw puste, aby wygenerować hasło",
"Legacy domain blocks found: {d}. Import them so that the maps can manage these domains.": "Znaleziono stare bloki domain: {d}. Zaimportuj je, aby mapy mogły obsługiwać te domeny.",
"Link for the authenticator app": "Link dla aplikacji uwierzytelniającej",
"Loading…": "Ładowanie…",
"Log": "Dziennik",
"Mail server administration": "Administracja serwerem poczty",
"Mail server is backup MX": "Serwer jest zapasowym MX",
"Mail to any address of this domain is delivered to the same address in the target domain.": "Poczta na dowolny adres tej domeny trafia na ten sam adres w domenie docelowej.",
"Mailbox": "Skrzynka",
"Mailbox created": "Skrzynka utworzona",
"Mailbox deleted": "Skrzynka usunięta",
"Mailbox is disabled": "Skrzynka jest wyłączona",
"Mailbox name": "Nazwa skrzynki",
"Mailbox updated": "Skrzynka zaktualizowana",
"Mailbox user": "Użytkownik skrzynki",
"Mailbox {m} created": "Utworzono skrzynkę {m}",
"Mailboxes": "Skrzynki",
"Mailboxes, aliases and alias domains": "Skrzynki, aliasy i domeny aliasowe",
"Management": "Zarządzanie",
"Maps active": "Mapy aktywne",
"Mark as read": "Oznacz jako przeczytane",
"Match": "Dopasowanie",
"Max. mailbox quota": "Maks. quota skrzynki",
"Max. mailbox quota (MB)": "Maks. quota skrzynki (MB)",
"Maximum: {n} MB": "Maksymalnie: {n} MB",
"Menu": "Menu",
"Message": "Treść",
"Message sent": "Wiadomość wysłana",
"Modified": "Zmieniono",
"Move to folder": "Przenieś do folderu",
"Move valid domain { path/selector } blocks into the managed maps? A backup is created and the change is rolled back if the configuration test fails.": "Przenieść poprawne bloki domain { path/selector } do zarządzanych map? Zostanie utworzona kopia zapasowa, a zmiana zostanie wycofana, jeśli test konfiguracji się nie powiedzie.",
"My mailbox": "Moja skrzynka",
"Name": "Nazwa",
"Name changed": "Nazwa zmieniona",
"Negate the condition": "Zaneguj warunek",
"Never": "Nigdy",
"New DKIM key": "Nowy klucz DKIM",
"New administrator": "Nowy administrator",
"New application password": "Nowe hasło aplikacji",
"New domain": "Nowa domena",
"New entry": "Nowy wpis",
"New fetchmail entry": "Nowy wpis fetchmail",
"New key": "Nowy klucz",
"New name": "Nowa nazwa",
"New password": "Nowe hasło",
"New password (leave empty to keep)": "Nowe hasło (puste = bez zmian)",
"New private key (leave empty to keep)": "Nowy klucz prywatny (puste = bez zmian)",
"New public key (leave empty to keep)": "Nowy klucz publiczny (puste = bez zmian)",
"New script": "Nowy skrypt",
"New signing entry": "Nowy wpis podpisywania",
"No": "Nie",
"No DKIM keys.": "Brak kluczy DKIM.",
"No DKIM record is configured for your domain.": "Dla Twojej domeny nie skonfigurowano rekordu DKIM.",
"No Rspamd DKIM keys.": "Brak kluczy DKIM Rspamd.",
"No administrators.": "Brak administratorów.",
"No aliases found.": "Nie znaleziono aliasów.",
"No aliases match the search.": "Żaden alias nie pasuje do wyszukiwania.",
"No application passwords.": "Brak haseł aplikacji.",
"No domains are assigned to you.": "Nie masz przypisanych domen.",
"No domains found.": "Nie znaleziono domen.",
"No domains yet.": "Brak domen.",
"No exceptions.": "Brak wyjątków.",
"No fetchmail entries.": "Brak wpisów fetchmail.",
"No log entries.": "Brak wpisów w dzienniku.",
"No mailboxes found.": "Nie znaleziono skrzynek.",
"No mailboxes match the search.": "Żadna skrzynka nie pasuje do wyszukiwania.",
"No scripts yet.": "Brak skryptów.",
"No signing entries.": "Brak wpisów podpisywania.",
"None": "Brak",
"Not configured": "Nieskonfigurowane",
"Nothing to select.": "Brak pozycji do wyboru.",
"Nothing to show.": "Brak danych.",
"Only after the new DNS record has been published.": "Dopiero po opublikowaniu nowego rekordu DNS.",
"Only mailboxes (not alias destinations)": "Tylko skrzynki (bez celów aliasów)",
"Other header": "Inny nagłówek",
"Out of office": "Poza biurem",
"Overview": "Przegląd",
"POP/IMAP": "POP/IMAP",
"Password": "Hasło",
"Password (leave empty to keep)": "Hasło (puste = bez zmian)",
"Password changed": "Hasło zmienione",
"Password expired": "Hasło wygasło",
"Password expires": "Hasło wygasa",
"Password expiry": "Wygasanie hasła",
"Password expiry (days)": "Ważność hasła (dni)",
"Password scheme": "Schemat haseł",
"Password – copy it now, it will not be shown again.": "Hasło – skopiuj je teraz, nie zostanie pokazane ponownie.",
"Password, two-factor authentication and application passwords": "Hasło, uwierzytelnianie dwuskładnikowe i hasła aplikacji",
"Path of the private key": "Ścieżka klucza prywatnego",
"Poll every (minutes)": "Sprawdzaj co (minuty)",
"Port": "Port",
"Private key": "Klucz prywatny",
"Private key (leave empty to generate)": "Klucz prywatny (puste = wygeneruj)",
"Protect the sign-in with a one-time code from an authenticator app.": "Zabezpiecz logowanie jednorazowym kodem z aplikacji uwierzytelniającej.",
"Protocol": "Protokół",
"Public key": "Klucz publiczny",
"Public key (leave empty to generate)": "Klucz publiczny (puste = wygeneruj)",
"Publish this DNS record.": "Opublikuj ten rekord DNS.",
"Quota": "Quota",
"Quota (MB)": "Quota (MB)",
"Quota is disabled for this domain (use -1)": "Quota jest wyłączona dla tej domeny (użyj -1)",
"Recipient (To/Cc)": "Odbiorca (To/Cc)",
"Recovery code": "Kod odzyskiwania",
"Recovery e-mail": "E-mail do odzyskiwania",
"Redirect to": "Przekieruj na",
"Reload Rspamd": "Przeładuj Rspamd",
"Reload Rspamd afterwards": "Przeładuj Rspamd po zapisie",
"Remember these destinations for new aliases": "Zapamiętaj te adresy dla nowych aliasów",
"Remove the mapping and delete the private key {d} / {s} from disk?": "Usunąć mapowanie i skasować z dysku klucz prywatny {d} / {s}?",
"Remove {d} from the Rspamd maps? The key file stays on disk.": "Usunąć {d} z map Rspamd? Plik klucza pozostanie na dysku.",
"Rename": "Zmień nazwę",
"Rename script": "Zmień nazwę skryptu",
"Repeat password": "Powtórz hasło",
"Replace an existing mapping": "Zastąp istniejące mapowanie",
"Reply at most every {n} seconds": "Odpowiadaj nie częściej niż co {n} s",
"Reply once (per sender)": "Odpowiedz raz (każdemu nadawcy)",
"Reply once per day": "Odpowiadaj raz dziennie",
"Reply once per week": "Odpowiadaj raz w tygodniu",
"Reply to every message": "Odpowiadaj na każdą wiadomość",
"Reply type": "Sposób odpowiedzi",
"Retrieve mail from remote POP3/IMAP accounts": "Pobieranie poczty ze zdalnych kont POP3/IMAP",
"Role": "Rola",
"Rspamd maps configured": "Mapy Rspamd skonfigurowane",
"Rule added – check and save the script": "Reguła dodana – sprawdź i zapisz skrypt",
"Rule name": "Nazwa reguły",
"Run “postfixadmin-rs --init-schema” on the server to create missing tables and columns.": "Uruchom na serwerze „postfixadmin-rs --init-schema”, aby utworzyć brakujące tabele i kolumny.",
"Save": "Zapisz",
"Saved": "Zapisano",
"Schema": "Schemat",
"Schema check": "Kontrola schematu",
"Script name": "Nazwa skryptu",
"Script saved": "Skrypt zapisany",
"Scripts": "Skrypty",
"Search": "Szukaj",
"Search in this domain…": "Szukaj w tej domenie…",
"Search mailboxes and aliases…": "Szukaj skrzynek i aliasów…",
"Search results for “{q}”": "Wyniki wyszukiwania „{q}”",
"Searches addresses, names and forwarding targets in your domains": "Przeszukuje adresy, nazwy i cele przekierowań w Twoich domenach",
"Secret key": "Klucz tajny",
"Security": "Bezpieczeństwo",
"Select at least one domain": "Wybierz co najmniej jedną domenę",
"Selector": "Selektor",
"Send": "Wyślij",
"Send a copy to": "Wyślij kopię na",
"Send a message through the configured SMTP server": "Wysyłanie wiadomości przez skonfigurowany serwer SMTP",
"Send code": "Wyślij kod",
"Send e-mail": "Wyślij e-mail",
"Send mail": "Wyślij pocztę",
"Send this message to all recipients in {n} domain(s)?": "Wysłać tę wiadomość do wszystkich odbiorców w domenach: {n}?",
"Send to all": "Wyślij do wszystkich",
"Send welcome e-mail": "Wyślij wiadomość powitalną",
"Sender": "Nadawca",
"Sender domain": "Domena nadawcy",
"Sender name": "Nazwa nadawcy",
"Sending (SMTP)": "Wysyłanie (SMTP)",
"Sending disabled": "Wysyłanie wyłączone",
"Sent: {s}, failed: {f}": "Wysłano: {s}, błędy: {f}",
"Server": "Serwer",
"Server-side mail filters (Sieve)": "Filtry poczty po stronie serwera (Sieve)",
"Services": "Usługi",
"Set a new password": "Ustaw nowe hasło",
"Set up": "Skonfiguruj",
"Set up two-factor authentication": "Konfiguracja uwierzytelniania dwuskładnikowego",
"Show": "Pokaż",
"Show all ({n})": "Pokaż wszystkie ({n})",
"Show password": "Pokaż hasło",
"Sign in": "Zaloguj",
"Sign out": "Wyloguj",
"Signed in as {user}": "Zalogowano jako {user}",
"Signing entry saved": "Wpis podpisywania zapisany",
"Signing keys used by Rspamd on this host": "Klucze podpisujące używane przez Rspamd na tym serwerze",
"Signing table": "Tabela podpisywania",
"Skipped: {n}": "Pominięto: {n}",
"Source": "Źródło",
"Status": "Status",
"Stop processing further rules": "Zatrzymaj przetwarzanie kolejnych reguł",
"Stored in mailbox": "Zapisywana w skrzynce",
"Subject": "Temat",
"System": "System",
"TOTP exception": "Wyjątek TOTP",
"TOTP exceptions (trusted IP addresses)": "Wyjątki TOTP (zaufane adresy IP)",
"Target domain": "Domena docelowa",
"Target mailbox": "Skrzynka docelowa",
"Test configuration": "Testuj konfigurację",
"The database schema is complete.": "Schemat bazy danych jest kompletny.",
"The mailbox password has expired": "Hasło skrzynki wygasło",
"The password has been changed. You can sign in now.": "Hasło zostało zmienione. Możesz się zalogować.",
"The passwords do not match.": "Hasła nie są identyczne.",
"The script contains an error": "Skrypt zawiera błąd",
"The script is valid": "Skrypt jest poprawny",
"Then": "Wtedy",
"This domain has no alias domains.": "Ta domena nie ma domen aliasowych.",
"This domain has no aliases.": "Ta domena nie ma aliasów.",
"This domain has no mailboxes.": "Ta domena nie ma skrzynek.",
"Time": "Czas",
"To": "Do",
"To (one address per line)": "Do (jeden adres w wierszu)",
"Transport": "Transport",
"Two-factor authentication": "Uwierzytelnianie dwuskładnikowe",
"Two-factor authentication (TOTP)": "Uwierzytelnianie dwuskładnikowe (TOTP)",
"Two-factor authentication disabled": "Uwierzytelnianie dwuskładnikowe wyłączone",
"Two-factor authentication enabled": "Uwierzytelnianie dwuskładnikowe włączone",
"Undeliverable": "Niedostarczalny",
"Unmap": "Odłącz",
"Unmap key": "Odłącz klucz",
"Until": "Do",
"Use SSL/TLS": "Użyj SSL/TLS",
"Use existing key": "Użyj istniejącego klucza",
"Use this password in the application instead of your mailbox password.": "Użyj tego hasła w aplikacji zamiast hasła do skrzynki.",
"User": "Użytkownik",
"Vacation": "Autoresponder",
"Value": "Wartość",
"Verify": "Zweryfikuj",
"Verify the server certificate": "Weryfikuj certyfikat serwera",
"Version": "Wersja",
"Virtual list": "Lista wirtualna",
"Warnings": "Ostrzeżenia",
"Yes": "Tak",
"Your domains": "Twoje domeny",
"Your session has ended. Please sign in again.": "Sesja wygasła. Zaloguj się ponownie.",
"active": "aktywny",
"all": "wszystkie",
"catch-all": "catch-all",
"contains": "zawiera",
"disabled": "wyłączone",
"expired": "wygasło",
"forward only": "tylko przekazywanie",
"is exactly": "jest równe",
"matches (wildcards)": "pasuje do wzorca (*, ?)",
"max. {q}": "maks. {q}",
"missing": "brak",
"system": "systemowy",
"unlimited": "bez limitu",
"{from}–{to} of {total}": "{from}–{to} z {total}",
"{n} address(es)": "Adresy: {n}",
"{n} days": "{n} dni",
"{n} domain(s)": "Domeny: {n}",
"{n} min": "{n} min",
"Going away": "Wyjeżdżam",
"Switch to dark theme": "Przełącz na ciemny motyw",
"Switch to light theme": "Przełącz na jasny motyw",
"Click to activate": "Kliknij, aby aktywować",
"Click to deactivate": "Kliknij, aby dezaktywować",
"Two-factor authentication enabled ": "Uwierzytelnianie dwuskładnikowe włączone",
"The mailbox password script failed": "Skrypt hasła skrzynki zakończył się błędem",
"The mailbox post-creation script failed": "Skrypt po utworzeniu skrzynki zakończył się błędem",
"Mailbox folders could not be created": "Nie udało się utworzyć folderów skrzynki",
"Rspamd reloaded": "Rspamd przeładowany",
}
SERVER = {
"A stale alias-domain entry with this name exists; remove it first": "Istnieje osierocony wpis domeny aliasowej o tej nazwie; najpierw go usuń",
"Account is disabled or no longer exists": "Konto jest wyłączone lub już nie istnieje",
"Account no longer exists": "Konto już nie istnieje",
"Account not found": "Nie znaleziono konta",
"Administrator already exists": "Administrator już istnieje",
"Administrator not found": "Nie znaleziono administratora",
"Administrator role required": "Wymagana rola administratora",
"Alias does not exist": "Alias nie istnieje",
"Alias domain does not exist": "Domena aliasowa nie istnieje",
"Alias domains are disabled": "Domeny aliasowe są wyłączone",
"Alias is outside this account": "Alias nie należy do tego konta",
"Aliases are disabled for this domain": "Aliasy są wyłączone dla tej domeny",
"An alias domain cannot point to itself": "Domena aliasowa nie może wskazywać na samą siebie",
"Application password not found": "Nie znaleziono hasła aplikacji",
"Application passwords are created by mailbox users": "Hasła aplikacji tworzą użytkownicy skrzynek",
"Application passwords are disabled": "Hasła aplikacji są wyłączone",
"At least one destination is required": "Wymagany jest co najmniej jeden adres docelowy",
"Backup is disabled": "Kopia zapasowa jest wyłączona",
"Broadcast is restricted to global administrators": "Wiadomości do wszystkich mogą wysyłać tylko administratorzy globalni",
"Broadcast mail is disabled": "Wiadomości do wszystkich są wyłączone",
"Changing the display name is not enabled": "Zmiana nazwy nie jest włączona",
"Current password is incorrect": "Obecne hasło jest nieprawidłowe",
"DKIM key not found": "Nie znaleziono klucza DKIM",
"DKIM management is disabled": "Zarządzanie DKIM jest wyłączone",
"DNS status checks are disabled": "Sprawdzanie DNS jest wyłączone",
"Database is read-only in this development session": "Baza danych jest w tej sesji tylko do odczytu",
"Default/special aliases can only be edited by a global administrator": "Aliasy domyślne/specjalne może edytować tylko administrator globalny",
"Description is required": "Opis jest wymagany",
"Description is too long": "Opis jest za długi",
"Domain already exists": "Domena już istnieje",
"Domain does not exist": "Domena nie istnieje",
"Domain is outside this administrator's scope": "Domena jest poza zakresem tego administratora",
"Editing mailbox aliases is disabled for your role (alias_control / alias_control_admin)": "Edycja aliasów skrzynek jest wyłączona dla Twojej roli (alias_control / alias_control_admin)",
"Editing the forwarding is not allowed": "Edycja przekierowania jest niedozwolona",
"Enter at least one forwarding address or keep delivery to the mailbox": "Podaj co najmniej jeden adres przekierowania albo pozostaw dostarczanie do skrzynki",
"Fetchmail is disabled": "Fetchmail jest wyłączony",
"Fetchmail record not found": "Nie znaleziono wpisu fetchmail",
"Global administrator role required": "Wymagana rola administratora globalnego",
"Invalid CSRF token": "Nieprawidłowy token CSRF – odśwież stronę",
"Invalid IP address": "Nieprawidłowy adres IP",
"Invalid TOTP code": "Nieprawidłowy kod TOTP",
"Invalid address": "Nieprawidłowy adres",
"Invalid alias destination": "Nieprawidłowy adres docelowy aliasu",
"Invalid catch-all alias address": "Nieprawidłowy adres aliasu catch-all",
"Invalid credentials": "Nieprawidłowy login lub hasło",
"Invalid domain": "Nieprawidłowa domena",
"Invalid email address": "Nieprawidłowy adres e-mail",
"Invalid email local part": "Nieprawidłowa część lokalna adresu e-mail",
"Invalid mailbox/alias local part": "Nieprawidłowa nazwa skrzynki/aliasu",
"Invalid or expired recovery code": "Nieprawidłowy lub wygasły kod odzyskiwania",
"Invalid phone number": "Nieprawidłowy numer telefonu",
"Login required": "Wymagane logowanie",
"MFA challenge expired": "Weryfikacja dwuskładnikowa wygasła – zaloguj się ponownie",
"Mailbox does not exist": "Skrzynka nie istnieje",
"Mailbox domain does not match domain": "Domena skrzynki nie zgadza się z domeną",
"Mailbox is outside this account": "Skrzynka nie należy do tego konta",
"Mailbox not found": "Nie znaleziono skrzynki",
"Mailboxes are disabled for this domain": "Skrzynki są wyłączone dla tej domeny",
"ManageSieve credentials are not available; sign in again": "Dane logowania ManageSieve są niedostępne – zaloguj się ponownie",
"ManageSieve is disabled": "ManageSieve jest wyłączony",
"ManageSieve is read-only": "ManageSieve jest tylko do odczytu",
"Missing CSRF token": "Brak tokenu CSRF – odśwież stronę",
"Only mailbox users can use this endpoint": "Funkcja dostępna tylko dla użytkowników skrzynek",
"Password is required": "Hasło jest wymagane",
"Password recovery is disabled": "Odzyskiwanie hasła jest wyłączone",
"Passwords are managed by the mailbox_postpassword hook and cannot be changed here": "Hasła są zarządzane przez hook mailbox_postpassword i nie można ich tu zmienić",
"Pipe/file alias destinations are disabled by the Rust security profile": "Cele aliasów typu potok/plik są wyłączone ze względów bezpieczeństwa",
"Quota -1 (disabled) is only allowed when the domain maximum quota is disabled": "Quota -1 (wyłączona) jest dozwolona tylko, gdy maks. quota domeny jest wyłączona",
"Quota must be -1 or greater": "Quota musi wynosić co najmniej -1",
"Renaming administrators is not supported": "Zmiana nazwy administratora nie jest obsługiwana",
"Renaming alias domains is not supported": "Zmiana nazwy domeny aliasowej nie jest obsługiwana",
"Renaming aliases is not supported": "Zmiana nazwy aliasu nie jest obsługiwana",
"Renaming domains is not supported; create a new domain instead": "Zmiana nazwy domeny nie jest obsługiwana; utwórz nową domenę",
"Renaming mailboxes is not supported": "Zmiana nazwy skrzynki nie jest obsługiwana",
"Select at least one domain": "Wybierz co najmniej jedną domenę",
"Send mail is disabled": "Wysyłanie poczty jest wyłączone",
"Send mail is restricted to global administrators": "Wysyłanie poczty jest dostępne tylko dla administratorów globalnych",
"Session expired": "Sesja wygasła",
"Source password is required": "Hasło źródłowe jest wymagane",
"Source server and user are required": "Serwer i użytkownik źródłowy są wymagani",
"TOTP is disabled": "TOTP jest wyłączone",
"TOTP is not configured": "TOTP nie jest skonfigurowane",
"Target mailbox does not exist": "Skrzynka docelowa nie istnieje",
"The alias name (local part) is required": "Nazwa aliasu jest wymagana",
"The alias of a mailbox can only be deleted together with the mailbox": "Alias skrzynki można usunąć tylko razem ze skrzynką",
"The alias of a mailbox is activated together with the mailbox": "Alias skrzynki jest aktywowany razem ze skrzynką",
"The local part must not contain an @ sign": "Nazwa nie może zawierać znaku @",
"The mailbox name (local part) is required": "Nazwa skrzynki jest wymagana",
"The maximum mailbox quota cannot be larger than the domain quota": "Maks. quota skrzynki nie może być większa niż quota domeny",
"The name may contain up to 255 characters and no control characters": "Nazwa może mieć do 255 znaków i nie może zawierać znaków sterujących",
"The new password must differ from the current password": "Nowe hasło musi być inne niż obecne",
"The target domain is itself an alias domain; chained alias domains are not supported": "Domena docelowa sama jest domeną aliasową; łańcuchy domen aliasowych nie są obsługiwane",
"This address already exists": "Ten adres już istnieje",
"This domain is already an alias domain": "Ta domena jest już domeną aliasową",
"This domain is already the target of another alias domain": "Ta domena jest już celem innej domeny aliasowej",
"This domain is configured as the vacation (autoreply) domain": "Ta domena jest skonfigurowana jako domena autorespondera",
"Too many login attempts": "Zbyt wiele prób logowania – spróbuj później",
"Too many password change attempts": "Zbyt wiele prób zmiany hasła – spróbuj później",
"Too many recovery requests": "Zbyt wiele próśb o odzyskanie hasła – spróbuj później",
"Too many reset attempts": "Zbyt wiele prób – spróbuj później",
"Unlimited quota is not allowed because the domain has a total quota": "Quota bez limitu jest niedozwolona, ponieważ domena ma quotę całkowitą",
"Unsupported vacation reply interval": "Nieobsługiwany interwał odpowiedzi",
"Vacation control is disabled for domain administrators": "Zarządzanie autoresponderem jest wyłączone dla administratorów domen",
"Vacation control is disabled for this user": "Zarządzanie autoresponderem jest wyłączone dla tego użytkownika",
"Vacation end date cannot be before start date": "Data końcowa nie może być wcześniejsza niż początkowa",
"Vacation is disabled": "Autoresponder jest wyłączony",
"Vacation message is too long": "Treść autorespondera jest za długa",
"You cannot deactivate yourself": "Nie możesz dezaktywować własnego konta",
"You cannot deactivate yourself or remove your own global administrator role": "Nie możesz dezaktywować własnego konta ani odebrać sobie roli administratora globalnego",
"You cannot delete the currently logged-in administrator": "Nie możesz usunąć zalogowanego administratora",
"fetchmail extra options/MDA are disabled": "Dodatkowe opcje fetchmail/MDA są wyłączone",
"poll_time must be positive": "Interwał musi być dodatni",
}
# Server messages that contain values.
PATTERNS = [
(r"^The mailbox limit of this domain has been reached \((\d+)\)$", "Osiągnięto limit skrzynek tej domeny ($1)"),
(r"^The alias limit of this domain has been reached \((\d+)\)$", "Osiągnięto limit aliasów tej domeny ($1)"),
(r"^Unlimited quota is not allowed – the maximum mailbox quota of this domain is (\d+) MB$", "Quota bez limitu jest niedozwolona – maks. quota skrzynki w tej domenie to $1 MB"),
(r"^The quota exceeds the maximum mailbox quota of this domain \((\d+) MB\)$", "Quota przekracza maks. quotę skrzynki tej domeny ($1 MB)"),
(r"^The domain quota would be exceeded \((\d+) MB of (\d+) MB already allocated\)$", "Quota domeny zostałaby przekroczona (przydzielono już $1 MB z $2 MB)"),
(r"^(.+): an alias must not point to itself$", "$1: alias nie może wskazywać na samego siebie"),
(r"^Invalid destination address: (.+)$", "Nieprawidłowy adres docelowy: $1"),
(r"^You may only make aliases to domains hosted on this server\. (.+) is a remote domain name\.$", "Aliasy mogą wskazywać tylko na domeny obsługiwane przez ten serwer. $1 jest domeną zewnętrzną."),
(r"^Domain does not exist: (.+)$", "Domena nie istnieje: $1"),
(r"^Unknown domain: (.+)$", "Nieznana domena: $1"),
(r"^Unsupported transport: (.+)$", "Nieobsługiwany transport: $1"),
(r"^Password must contain at least (\d+) characters$", "Hasło musi mieć co najmniej $1 znaków"),
(r"^Password must contain at least (\d+) letters$", "Hasło musi zawierać co najmniej $1 litery"),
(r"^Password must contain at least (\d+) digits$", "Hasło musi zawierać co najmniej $1 cyfry"),
(r"^(.+) must be -1 \(disabled\), 0 \(unlimited\) or a positive number$", "$1: dozwolone -1 (wyłączone), 0 (bez limitu) lub liczba dodatnia"),
(r"^Password expiration must be between 0 \(never\) and (\d+) days$", "Ważność hasła musi wynosić od 0 (nigdy) do $1 dni"),
(r"^The domain is the target of the alias domain (.+); delete that alias domain first$", "Domena jest celem domeny aliasowej $1; najpierw ją usuń"),
(r"^Domain has no A, AAAA, MX or NS record: (.+)$", "Domena nie ma rekordu A, AAAA, MX ani NS: $1"),
(r"^Invalid vacation (start|end) date$", "Nieprawidłowa data autorespondera"),
]
+17 -13
View File
@@ -138,9 +138,13 @@ for marker in ['/rspamd-dkim/generate', 'selector_map', 'path_map', 'RspamdDkimC
fail(f'missing Rspamd DKIM integration marker: {marker}')
compatibility_regression_markers = {
'src/routes/vacation.rs': ['sync_vacation_alias', 'vacation_address', 'validate_dates'],
'src/routes/aliases.rs': ['technical', 'internal_vacation', 'can_edit_description'],
'src/web/js/10-pages.js': ['vacationMailboxPicker', 'Aliasy techniczne', 'local_part'],
'src/routes/vacation.rs': ['sync_vacation_alias', 'vacation_address', 'normalize_dates'],
'src/routes/aliases.rs': ['technical', 'internal_vacation', 'require_mailbox_alias_control', 'recipient_delimiter_base'],
'src/routes/mailboxes.rs': ['check_quota', 'allowed_quota', 'set_forwarding', 'set_own_name'],
'src/limits.rs': ['ensure_mailbox_allowed', 'ensure_alias_allowed'],
'src/schema.rs': ['PFA_SCHEMA_VERSION', 'integrity_check'],
'src/routes/fetchmail.rs': ['encode_src_password'],
'src/web/js/10-pages.js': ['vacationEditor', 'technical', 'local_part'],
'packaging/postfixadmin-rs-rspamd-setup': ['postfixadmin-rspamd', 'systemctl restart postfixadmin-rs rspamd'],
}
for relative, markers in compatibility_regression_markers.items():
@@ -151,14 +155,14 @@ for relative, markers in compatibility_regression_markers.items():
domain_ui_regression_markers = {
'src/web/js/10-pages.js': [
'aliasRows.filter(item => !item.is_mailbox)',
'regularAliases = indexedAliases.filter(({ item }) => !item.technical)',
'technicalAliases = indexedAliases.filter(({ item }) => item.technical)',
'Aliasy użytkowników',
'Aliasy techniczne',
"['Adres', 'Cel', 'Opis', 'Status', 'Aktywny', '']",
'aliasDestinations',
'aliasTargetsCell',
'async function virtualPage(',
'row.catch_all',
'function aliasForm(',
'function mailboxForm(',
'function forwardingForm(',
'pager(aliases.total',
'pager(mailboxes.total',
'deleteInactive',
],
'src/web/css/20-app.css': ['.workspace-grid{display:grid;grid-template-columns:1fr;'],
'src/routes/aliases.rs': ['a.goto AS goto_value', 'row_string(row, "goto_value")'],
@@ -248,7 +252,7 @@ core_js = (ROOT / 'src/web/js/00-core.js').read_text(encoding='utf-8')
for marker in ['/sieve/status', '/sieve/scripts/{name}', '/sieve/check']:
if marker not in routes_mod:
fail(f'missing ManageSieve route: {marker}')
for marker in ['openSieveRuleBuilder', 'buildSieveRule', 'mergeSieveRequirements']:
for marker in ['newRule', 'buildSieveRule', 'mergeSieveRequirements']:
if marker not in pages_js:
fail(f'missing ManageSieve visual rule builder marker: {marker}')
for marker in ['SieveConfig', 'allow_insecure_auth', 'timeout_secs', 'read_only']:
@@ -275,7 +279,7 @@ else:
result = subprocess.run([sys.executable, '-m', 'py_compile', str(sync_script)], capture_output=True, text=True)
if result.returncode:
fail(f'{sync_script.relative_to(ROOT)}: py_compile failed: {result.stderr.strip()}')
for marker in ["['mailboxes', 'mail', 'Skrzynki', S.me.kind === 'admin']", "S.me.kind === 'user'", 'readonlyDomain(selected)', "api('/mailboxes')", "api('/aliases')", 'vacationUserForm', 'passwordForm']:
for marker in ['const isUser = ', 'async function userOverview(', 'async function forwardingPage(', "['forwarding', 'Forwarding', 'Mailbox'", 'passwordForm', 'edit_own_name']:
if marker not in core_js + '\n' + pages_js:
fail(f'missing mailbox-user UX marker: {marker}')
if 'Sesja: HttpOnly' in branding_text or 'Session: HttpOnly' in branding_text or 'SameSite=Strict, Secure w produkcji' in branding_text: