Merge remote-tracking branch 'origin/main' into feature/372-groups-management
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
3eb4cde0b7
17 changed files with 330 additions and 38 deletions
|
|
@ -2252,3 +2252,13 @@ msgid "Total: %{count} member"
|
|||
msgid_plural "Total: %{count} members"
|
||||
msgstr[0] "Insgesamt: %{count} Mitglied"
|
||||
msgstr[1] "Insgesamt: %{count} Mitglieder"
|
||||
|
||||
#: lib/mv_web/live/user_live/form.ex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This user cannot be edited."
|
||||
msgstr "Dieser Benutzer kann nicht bearbeitet werden."
|
||||
|
||||
#: lib/mv_web/live/user_live/show.ex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This user cannot be viewed."
|
||||
msgstr "Dieser Benutzer kann nicht angezeigt werden."
|
||||
|
|
|
|||
|
|
@ -2253,3 +2253,13 @@ msgid "Total: %{count} member"
|
|||
msgid_plural "Total: %{count} members"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: lib/mv_web/live/user_live/form.ex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This user cannot be edited."
|
||||
msgstr ""
|
||||
|
||||
#: lib/mv_web/live/user_live/show.ex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This user cannot be viewed."
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -2253,3 +2253,13 @@ msgid "Total: %{count} member"
|
|||
msgid_plural "Total: %{count} members"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: lib/mv_web/live/user_live/form.ex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This user cannot be edited."
|
||||
msgstr ""
|
||||
|
||||
#: lib/mv_web/live/user_live/show.ex
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "This user cannot be viewed."
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
defmodule Mv.Repo.Migrations.EnsureSystemActorUserExists do
|
||||
@moduledoc """
|
||||
Ensures the system actor user always exists.
|
||||
|
||||
The system actor is used for systemic operations (email sync, cycle generation,
|
||||
background jobs). It is created by seeds in development; in production seeds
|
||||
may not run, so this migration guarantees the user exists.
|
||||
|
||||
Creates a user with email "system@mila.local" (default from Mv.Helpers.SystemActor)
|
||||
and the Admin role. The user has no password and no OIDC ID, so it cannot log in.
|
||||
"""
|
||||
use Ecto.Migration
|
||||
import Ecto.Query
|
||||
|
||||
@system_user_email "system@mila.local"
|
||||
|
||||
def up do
|
||||
admin_role_id = ensure_admin_role_exists()
|
||||
ensure_system_actor_user_exists(admin_role_id)
|
||||
end
|
||||
|
||||
def down do
|
||||
# Not reversible - do not delete system user on rollback
|
||||
:ok
|
||||
end
|
||||
|
||||
defp ensure_admin_role_exists do
|
||||
case repo().one(from(r in "roles", where: r.name == "Admin", select: r.id)) do
|
||||
nil ->
|
||||
execute("""
|
||||
INSERT INTO roles (id, name, description, permission_set_name, is_system_role, inserted_at, updated_at)
|
||||
VALUES (uuid_generate_v7(), 'Admin', 'Administrator with full access', 'admin', false, (now() AT TIME ZONE 'utc'), (now() AT TIME ZONE 'utc'))
|
||||
""")
|
||||
|
||||
role_id = repo().one(from(r in "roles", where: r.name == "Admin", select: r.id))
|
||||
IO.puts("✅ Created 'Admin' role (was missing)")
|
||||
role_id
|
||||
|
||||
role_id ->
|
||||
role_id
|
||||
end
|
||||
end
|
||||
|
||||
defp ensure_system_actor_user_exists(_admin_role_id) do
|
||||
case repo().one(from(u in "users", where: u.email == ^@system_user_email, select: u.id)) do
|
||||
nil ->
|
||||
# Use subquery for role_id to avoid nil/empty-string UUID (CI can lag after role insert)
|
||||
execute("""
|
||||
INSERT INTO users (id, email, hashed_password, oidc_id, member_id, role_id)
|
||||
SELECT uuid_generate_v7(), '#{@system_user_email}', NULL, NULL, NULL, r.id
|
||||
FROM roles r
|
||||
WHERE r.name = 'Admin'
|
||||
LIMIT 1
|
||||
""")
|
||||
|
||||
IO.puts("✅ Created system actor user (#{@system_user_email})")
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -268,9 +268,9 @@ case Accounts.User
|
|||
|> Ash.read_one(domain: Mv.Accounts, authorize?: false) do
|
||||
{:ok, existing_system_user} when not is_nil(existing_system_user) ->
|
||||
# System user already exists - ensure it has admin role
|
||||
# Use authorize?: false for bootstrap
|
||||
# Use authorize?: false for bootstrap; :update_internal bypasses system-user modification block
|
||||
existing_system_user
|
||||
|> Ash.Changeset.for_update(:update, %{})
|
||||
|> Ash.Changeset.for_update(:update_internal, %{})
|
||||
|> Ash.Changeset.manage_relationship(:role, admin_role, type: :append_and_remove)
|
||||
|> Ash.update!(authorize?: false)
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ case Accounts.User
|
|||
upsert_identity: :unique_email,
|
||||
authorize?: false
|
||||
)
|
||||
|> Ash.Changeset.for_update(:update, %{})
|
||||
|> Ash.Changeset.for_update(:update_internal, %{})
|
||||
|> Ash.Changeset.manage_relationship(:role, admin_role, type: :append_and_remove)
|
||||
|> Ash.update!(authorize?: false)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue