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
@@ -251,6 +251,45 @@ export const catalog: Catalog = {
"This role no longer exists. Someone may have deleted it.": "Este rol ya no existe. Puede que alguien lo haya eliminado.",
"the default roles": "los roles predeterminados",
"The server did not say whether the role was created.": "El servidor no indicó si el rol se creó.",
"No tenant": "Sin inquilino",
"You can't move your own account into a tenant.": "No puede mover su propia cuenta a un inquilino.",
"An account in a tenant is limited by the tenant's role and counts towards its limits, and Administrator means administrator of that tenant.": "Una cuenta de un inquilino está limitada por el rol del inquilino y cuenta para sus límites, y Administrador significa administrador de ese inquilino.",
"Tenants": "Inquilinos",
"Storage in GB": "Almacenamiento en GB",
"Default tenant roles": "Roles de inquilino predeterminados",
"A tenant needs a name.": "Un inquilino necesita un nombre.",
"New tenant": "Nuevo inquilino",
"{used} used": "{used} usados",
"Your role lets you view tenants but not change them.": "Su rol le permite ver los inquilinos, pero no modificarlos.",
"Logo": "Logotipo",
"An https address or a data URL of an image. Stalwart shows it to the tenant's people where it shows a logo.": "Una dirección https o una URL data de una imagen. Stalwart la muestra a las personas del inquilino donde muestra un logotipo.",
"What it holds": "Contenido",
"{n} of {limit}": "{n} de {limit}",
"Limits": "Límites",
"Stalwart refuses to create more than a limit allows. An empty field is no limit.": "Stalwart se niega a crear más de lo que permite un límite. Un campo vacío significa sin límite.",
"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.": "Lo máximo que se puede permitir a cualquiera en este inquilino: sus propios roles se reducen a lo que estos conceden. Solo se ofrecen los roles cuyos permisos usted mismo tiene.",
"Checking what is still in this tenant…": "Comprobando lo que aún hay en este inquilino…",
"It still holds accounts, domains or other things. Move them out first.": "Aún tiene cuentas, dominios u otros elementos. Muévalos primero.",
"Create tenant": "Crear inquilino",
"Added {domain} to {tenant}": "{domain} añadido a {tenant}",
"Took {domain} out of {tenant}": "{domain} quitado de {tenant}",
"Take {domain} out of the tenant": "Quitar {domain} del inquilino",
"No domains in this tenant yet": "Aún no hay dominios en este inquilino",
"Domain to add": "Dominio para añadir",
"Only domains in no tenant can be added. The accounts already on a domain stay where they are; move each from its own panel.": "Solo se pueden añadir dominios que no estén en ningún inquilino. Las cuentas que ya están en un dominio se quedan donde están; mueva cada una desde su propio panel.",
"An empty tenant can be deleted.": "Un inquilino vacío se puede eliminar.",
"Delete tenant…": "Eliminar inquilino…",
"Still holds {things}. Move them out first.": "Aún tiene {things}. Muévalos primero.",
"Delete tenant": "Eliminar inquilino",
"Separate organisations on one server, each with its own people, domains and limits.": "Organizaciones separadas en un mismo servidor, cada una con sus propias personas, dominios y límites.",
"Tenants are a Stalwart Enterprise feature. This server does not report Enterprise, so anyone inside a tenant has only an ordinary user's permissions.": "Los inquilinos son una función de Stalwart Enterprise. Este servidor no indica Enterprise, así que cualquiera dentro de un inquilino solo tiene los permisos de un usuario normal.",
"Search tenants": "Buscar inquilinos",
"No tenants match": "Ningún inquilino coincide",
"No tenants yet": "Aún no hay inquilinos",
"Account limit": "Límite de cuentas",
"The server allows no more tenants.": "El servidor no permite más inquilinos.",
"This tenant no longer exists. Someone may have deleted it.": "Este inquilino ya no existe. Puede que alguien lo haya eliminado.",
"The server did not say whether the tenant was created.": "El servidor no indicó si el inquilino se creó.",
"User": "Usuario",
"Administrator": "Administrador",
"Custom role": "Rol personalizado",
@@ -1649,6 +1688,7 @@ export const catalog: Catalog = {
"{n} recipients": { one: "{n} destinatario", other: "{n} destinatarios" },
"Grants {n} permissions": { one: "Concede {n} permiso", other: "Concede {n} permisos" },
"{n} roles": { one: "{n} rol", other: "{n} roles" },
"{n} tenants": { one: "{n} inquilino", other: "{n} inquilinos" },
"{n} DKIM keys": { one: "{n} clave DKIM", other: "{n} claves DKIM" },
"{n} other items": { one: "{n} elemento más", other: "{n} elementos más" },
// ── Administration ────────────────────────────────────────────────