mailu: gate sync to approved users

This commit is contained in:
Brad Stein 2026-01-18 00:47:38 -03:00
parent f753f114c7
commit 418d201da0
4 changed files with 42 additions and 5 deletions

View File

@ -144,8 +144,18 @@ def test_main_generates_password_and_upserts(monkeypatch):
sync = load_sync_module(monkeypatch)
monkeypatch.setattr(sync.bcrypt_sha256, "hash", lambda password: f"hash:{password}")
users = [
{"id": "u1", "username": "user1", "email": "user1@example.com", "attributes": {}},
{"id": "u2", "username": "user2", "email": "user2@example.com", "attributes": {"mailu_app_password": ["keepme"]}},
{
"id": "u1",
"username": "user1",
"email": "user1@example.com",
"attributes": {"mailu_enabled": ["true"]},
},
{
"id": "u2",
"username": "user2",
"email": "user2@example.com",
"attributes": {"mailu_app_password": ["keepme"], "mailu_enabled": ["true"]},
},
{"id": "u3", "username": "user3", "email": "user3@other.com", "attributes": {}},
]
updated = []
@ -185,6 +195,6 @@ def test_main_generates_password_and_upserts(monkeypatch):
sync.main()
# Always backfill mailu_email, even if Keycloak recovery email is external.
assert len(updated) == 3
assert conns and len(conns[0]._cursor.executions) == 3
# Only mail-enabled users are synced and backfilled.
assert len(updated) == 2
assert conns and len(conns[0]._cursor.executions) == 2

View File

@ -6,6 +6,7 @@ declare(strict_types=1);
use FireflyIII\Console\Commands\Correction\CreatesGroupMemberships;
use FireflyIII\Models\Role;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Contracts\Console\Kernel as ConsoleKernel;
@ -70,6 +71,12 @@ $app = require $app_bootstrap;
$kernel = $app->make(ConsoleKernel::class);
$kernel->bootstrap();
try {
FireflyConfig::set('single_user_mode', true);
} catch (Throwable $exc) {
error_line('failed to enforce single_user_mode: '.$exc->getMessage());
}
$repository = $app->make(UserRepositoryInterface::class);
$existing_user = User::where('email', $email)->first();

View File

@ -220,6 +220,14 @@ spec:
"permissions": {"view": ["admin"], "edit": ["admin"]},
"validations": {"length": {"max": 255}},
},
{
"name": "mailu_enabled",
"displayName": "Atlas Mailbox Enabled",
"multivalued": False,
"annotations": {"group": "user-metadata"},
"permissions": {"view": ["admin"], "edit": ["admin"]},
"validations": {"length": {"max": 16}},
},
{
"name": "nextcloud_mail_primary_email",
"displayName": "Nextcloud Mail Primary Email",

View File

@ -25,6 +25,7 @@ KC_CLIENT_SECRET = os.environ["KEYCLOAK_CLIENT_SECRET"]
MAILU_DOMAIN = os.environ["MAILU_DOMAIN"]
MAILU_DEFAULT_QUOTA = int(os.environ.get("MAILU_DEFAULT_QUOTA", "20000000000"))
MAILU_ENABLED_ATTR = os.environ.get("MAILU_ENABLED_ATTR", "mailu_enabled")
DB_CONFIG = {
"host": os.environ["MAILU_DB_HOST"],
@ -141,6 +142,13 @@ def get_attribute_value(attributes, key):
return None
def mailu_enabled(attributes) -> bool:
raw = get_attribute_value(attributes, MAILU_ENABLED_ATTR)
if raw is None:
return False
return str(raw).strip().lower() in {"1", "true", "yes", "y", "on"}
def resolve_mailu_email(user, attributes):
explicit = get_attribute_value(attributes, "mailu_email")
if explicit:
@ -209,6 +217,10 @@ def main():
for user in users:
attrs = user.get("attributes", {}) or {}
if user.get("enabled") is False:
continue
if not mailu_enabled(attrs):
continue
app_pw = get_attribute_value(attrs, "mailu_app_password")
mailu_email = resolve_mailu_email(user, attrs)