Add Tenants to Administration, and let an account be put in one

A tenant is a separate organisation on one server: its own people,
domains and limits, and an administrator who manages only what is in it.
It gets a section under Access, gated by sysTenantQuery and sysTenantGet,
with a notice on a server that does not report Enterprise, where anyone
inside a tenant is held to an ordinary user's permissions.

The panel edits the tenant's name, logo, role and limits. The logo is an
https address, drawn through the image proxy the strict image policy
requires, or an image data URL. Limits change one quotas/<name> pointer
each, so the four ihasmail does not offer keep their values, and an empty
field is no limit. The role is the most anyone inside can be allowed.

Stalwart keeps no list on a tenant -- each account, group, domain, list and
role names its own -- so what a tenant holds is counted with memberTenantId
queries and shown against its limits. Domains are added and taken out from
the tenant's panel, one memberTenantId change each; only a domain in no
tenant can be added, and its accounts stay where they are. Delete is offered
once every count reads zero.

A tenant does nothing until someone administers it, so the account panel
gains a Tenant choice for an administrator who can read tenants: an
Administrator inside a tenant administers that tenant. Nobody moves their
own account.

The mock has a tenant holding a domain and an administrator, a spare domain
to assign, memberTenantId filters on every query, and Stalwart's rule that
only an administrator outside every tenant may move things into one. A test
of taking a domain back out found that the mock's pointer handling dropped a
top-level null instead of storing it, so nothing had ever been cleared that
way; it stores null now, as the server reads it back.

Nothing about tenants has been written on a live server: production has
none. KNOWN-ISSUES says what was read from source.

Thirty-nine new strings and one plural, in all nine catalogues.
This commit is contained in:
2026-09-15 09:28:39 -07:00
parent 7e46ddeb7d
commit fd104a1f34
29 changed files with 1467 additions and 25 deletions
+40
View File
@@ -247,6 +247,45 @@ export const catalog: Catalog = {
"This role no longer exists. Someone may have deleted it.": "Цієї ролі більше немає. Можливо, її хтось видалив.",
"the default roles": "налаштування ролей за замовчуванням",
"The server did not say whether the role was created.": "Сервер не повідомив, чи створено роль.",
"No tenant": "Без орендаря",
"You can't move your own account into a tenant.": "Не можна перемістити власний обліковий запис до орендаря.",
"An account in a tenant is limited by the tenant's role and counts towards its limits, and Administrator means administrator of that tenant.": "Обліковий запис орендаря обмежений роллю орендаря й зараховується до його лімітів, а «Адміністратор» означає адміністратора цього орендаря.",
"Tenants": "Орендарі",
"Storage in GB": "Сховище, ГБ",
"Default tenant roles": "Ролі орендаря за замовчуванням",
"A tenant needs a name.": "Орендарю потрібна назва.",
"New tenant": "Новий орендар",
"{used} used": "Зайнято {used}",
"Your role lets you view tenants but not change them.": "Ваша роль дозволяє переглядати орендарів, але не змінювати їх.",
"Logo": "Логотип",
"An https address or a data URL of an image. Stalwart shows it to the tenant's people where it shows a logo.": "Адреса https або data-URL зображення. Stalwart показує його людям орендаря там, де показує логотип.",
"What it holds": "Вміст",
"{n} of {limit}": "{n} з {limit}",
"Limits": "Ліміти",
"Stalwart refuses to create more than a limit allows. An empty field is no limit.": "Stalwart не дає створити більше, ніж дозволяє ліміт. Порожнє поле — без ліміту.",
"The most anyone in this tenant can be allowed: their own roles are cut down to what these grant. Only roles whose permissions you hold yourself are offered.": "Максимум того, що може бути дозволено будь-кому в цьому орендарі: їхні власні ролі обмежуються тим, що надають ці. Пропонуються лише ролі, дозволи яких маєте ви самі.",
"Checking what is still in this tenant…": "Перевірка того, що ще є в цього орендаря…",
"It still holds accounts, domains or other things. Move them out first.": "У нього ще є облікові записи, домени чи щось інше. Спершу перенесіть їх.",
"Create tenant": "Створити орендаря",
"Added {domain} to {tenant}": "{domain} додано до {tenant}",
"Took {domain} out of {tenant}": "{domain} прибрано з {tenant}",
"Take {domain} out of the tenant": "Прибрати {domain} з орендаря",
"No domains in this tenant yet": "У цього орендаря поки немає доменів",
"Domain to add": "Домен для додавання",
"Only domains in no tenant can be added. The accounts already on a domain stay where they are; move each from its own panel.": "Додати можна лише домени, що не належать жодному орендарю. Облікові записи на домені лишаються на місці; переносьте кожен з його власної панелі.",
"An empty tenant can be deleted.": "Порожнього орендаря можна видалити.",
"Delete tenant…": "Видалити орендаря…",
"Still holds {things}. Move them out first.": "Ще містить: {things}. Спершу перенесіть їх.",
"Delete tenant": "Видалити орендаря",
"Separate organisations on one server, each with its own people, domains and limits.": "Окремі організації на одному сервері, кожна зі своїми людьми, доменами й лімітами.",
"Tenants are a Stalwart Enterprise feature. This server does not report Enterprise, so anyone inside a tenant has only an ordinary user's permissions.": "Орендарі — функція Stalwart Enterprise. Цей сервер не повідомляє про редакцію Enterprise, тож будь-хто в орендарі має лише дозволи звичайного користувача.",
"Search tenants": "Пошук орендарів",
"No tenants match": "Немає відповідних орендарів",
"No tenants yet": "Орендарів поки немає",
"Account limit": "Ліміт облікових записів",
"The server allows no more tenants.": "Сервер не дозволяє більше орендарів.",
"This tenant no longer exists. Someone may have deleted it.": "Цього орендаря більше немає. Можливо, його хтось видалив.",
"The server did not say whether the tenant was created.": "Сервер не повідомив, чи створено орендаря.",
"User": "Користувач",
"Administrator": "Адміністратор",
"Custom role": "Власна роль",
@@ -1645,6 +1684,7 @@ export const catalog: Catalog = {
"{n} recipients": { one: "{n} одержувач", few: "{n} одержувачі", many: "{n} одержувачів", other: "{n} одержувача" },
"Grants {n} permissions": { one: "Надає {n} дозвіл", few: "Надає {n} дозволи", many: "Надає {n} дозволів", other: "Надає {n} дозволу" },
"{n} roles": { one: "{n} роль", few: "{n} ролі", many: "{n} ролей", other: "{n} ролі" },
"{n} tenants": { one: "{n} орендар", few: "{n} орендарі", many: "{n} орендарів", other: "{n} орендаря" },
"{n} DKIM keys": { one: "{n} ключ DKIM", few: "{n} ключі DKIM", many: "{n} ключів DKIM", other: "{n} ключа DKIM" },
"{n} other items": { one: "{n} інший об'єкт", few: "{n} інші об'єкти", many: "{n} інших об'єктів", other: "{n} іншого об'єкта" },
// ── Administration ────────────────────────────────────────────────