Mechanical cleanup, quick fixes & deduplication closes #531 #543

Merged
moritz merged 17 commits from issue/mitgliederverwaltung-531 into main 2026-06-16 16:06:52 +02:00
88 changed files with 225 additions and 155 deletions
Showing only changes of commit fe534319ee - Show all commits

View file

@ -8,7 +8,6 @@ defmodule Mv.Accounts.User do
extensions: [AshAuthentication],
authorizers: [Ash.Policy.Authorizer]
require Ash.Query
import Ash.Expr
alias Ash.Resource.Preparation.Builtins
@ -16,6 +15,8 @@ defmodule Mv.Accounts.User do
alias Mv.Helpers.SystemActor
alias Mv.OidcRoleSync
require Ash.Query
postgres do
table "users"
repo Mv.Repo

View file

@ -24,12 +24,13 @@ defmodule Mv.Accounts.User.Validations.OidcEmailCollision do
- Allow (new user will be created)
"""
use Ash.Resource.Validation
require Logger
alias Mv.Accounts.User
alias Mv.Accounts.User.Errors.PasswordVerificationRequired
alias Mv.Helpers.SystemActor
require Logger
@impl true
def init(opts), do: {:ok, opts}

View file

@ -38,6 +38,10 @@ defmodule Mv.Membership.Email do
@min_length 5
@max_length 254
# These compile-time constants are referenced by the `use` options below, so
# they must be declared first; StrictModuleLayout cannot be satisfied by
# reordering here without breaking the macro expansion.
# credo:disable-for-next-line Credo.Check.Readability.StrictModuleLayout
use Ash.Type.NewType,
subtype_of: :string,
constraints: [

View file

@ -39,9 +39,10 @@ defmodule Mv.Membership.Group do
data_layer: AshPostgres.DataLayer,
authorizers: [Ash.Policy.Authorizer]
require Ash.Query
alias Mv.Helpers
alias Mv.Helpers.SystemActor
require Ash.Query
require Logger
postgres do

View file

@ -37,9 +37,9 @@ defmodule Mv.Membership.Member do
data_layer: AshPostgres.DataLayer,
authorizers: [Ash.Policy.Authorizer]
import Bitwise
require Ash.Query
import Ash.Expr
import Bitwise
alias Ecto.Adapters.SQL, as: EctoSQL
alias Mv.Helpers
alias Mv.Helpers.SystemActor
@ -49,6 +49,7 @@ defmodule Mv.Membership.Member do
alias Mv.MembershipFees.MembershipFeeCycle
alias Mv.Repo
require Ash.Query
require Logger
@typedoc "An `Mv.Membership.Member` resource record."

View file

@ -26,13 +26,15 @@ defmodule Mv.Membership do
use Ash.Domain,
extensions: [AshAdmin.Domain, AshPhoenix]
require Ash.Query
import Ash.Expr
alias Ash.Error.Query.NotFound, as: NotFoundError
alias Mv.Helpers.SystemActor
alias Mv.Membership.JoinRequest
alias Mv.Membership.Member
alias Mv.Membership.SettingsCache
require Ash.Query
require Logger
admin do

View file

@ -65,12 +65,12 @@ defmodule Mv.Membership.Setting do
data_layer: AshPostgres.DataLayer,
primary_read_warning?: false
alias Ash.Resource.Info, as: ResourceInfo
# Used in join_form_field_ids validation (compile-time to avoid recompiling regex and list on every validation)
@uuid_pattern ~r/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
@valid_join_form_member_fields Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)
alias Ash.Resource.Info, as: ResourceInfo
postgres do
table "settings"
repo Mv.Repo

View file

@ -1,4 +1,5 @@
defmodule Mix.Tasks.JoinRequests.CleanupExpired do
@shortdoc "Deletes join requests in pending_confirmation with expired confirmation token"
@moduledoc """
Hard-deletes JoinRequests in status `pending_confirmation` whose confirmation link has expired.
@ -16,12 +17,10 @@ defmodule Mix.Tasks.JoinRequests.CleanupExpired do
"""
use Mix.Task
require Ash.Query
require Logger
alias Mv.Membership.JoinRequest
@shortdoc "Deletes join requests in pending_confirmation with expired confirmation token"
require Ash.Query
require Logger
@impl Mix.Task
def run(_args) do

View file

@ -13,13 +13,14 @@ defmodule Mv.Accounts.User.Senders.SendNewUserConfirmationEmail do
layout: {MvWeb.EmailLayoutView, "layout.html"}
use MvWeb, :verified_routes
import Swoosh.Email
use Gettext, backend: MvWeb.Gettext, otp_app: :mv
require Logger
import Swoosh.Email
alias Mv.Mailer
require Logger
@doc """
Sends a confirmation email to a new user.

View file

@ -13,13 +13,14 @@ defmodule Mv.Accounts.User.Senders.SendPasswordResetEmail do
layout: {MvWeb.EmailLayoutView, "layout.html"}
use MvWeb, :verified_routes
import Swoosh.Email
use Gettext, backend: MvWeb.Gettext, otp_app: :mv
require Logger
import Swoosh.Email
alias Mv.Mailer
require Logger
@doc """
Sends a password reset email to a user.

View file

@ -49,10 +49,10 @@ defmodule Mv.Authorization.Actor do
adds complexity and potential for inconsistency.
"""
require Logger
alias Mv.Helpers.SystemActor
require Logger
@doc """
Ensures the actor (User) has their `:role` relationship loaded.

View file

@ -79,10 +79,13 @@ defmodule Mv.Authorization.Checks.HasPermission do
"""
use Ash.Policy.Check
require Ash.Query
import Ash.Expr
alias Mv.Authorization.Actor
alias Mv.Authorization.PermissionSets
require Ash.Query
require Logger
@impl true

View file

@ -6,9 +6,10 @@ defmodule Mv.EmailSync.Helpers do
provides clean abstractions for email updates within transactions.
"""
require Logger
import Ecto.Changeset
require Logger
@doc """
Extracts the record from an Ash action result.

View file

@ -48,10 +48,10 @@ defmodule Mv.Helpers.SystemActor do
use Agent
require Ash.Query
alias Mv.Config
require Ash.Query
@doc """
Starts the SystemActor Agent.

View file

@ -27,11 +27,12 @@ defmodule Mv.Mailer do
ENV takes priority over Settings (same pattern as OIDC and Vereinfacht).
"""
use Swoosh.Mailer, otp_app: :mv
import Swoosh.Email
use Gettext, backend: MvWeb.Gettext, otp_app: :mv
import Swoosh.Email
alias Mv.Smtp.ConfigBuilder
require Logger
# Simple format check for test-email recipient only (e.g. allows a@b.c). Not for strict RFC validation.

View file

@ -15,10 +15,10 @@ defmodule Mv.Membership.Import.ColumnResolver do
This module has no Phoenix or web dependencies.
"""
require Logger
alias Mv.Membership.Import.HeaderMapper
require Logger
@preview_row_limit 3
@type numbered_row :: {pos_integer(), [String.t()]}

View file

@ -53,6 +53,14 @@ defmodule Mv.Membership.Import.MemberCSV do
MemberCSV.process_chunk(chunk, import_state.column_map, import_state.custom_field_map, [])
"""
use Gettext, backend: MvWeb.Gettext
alias Mv.Helpers.SystemActor
alias Mv.Membership.Import.ColumnResolver
alias Mv.Membership.Import.CsvParser
alias Mv.Membership.Import.HeaderMapper
alias MvWeb.Translations.FieldTypes
defmodule Error do
@moduledoc """
Error struct for CSV import errors.
@ -101,17 +109,6 @@ defmodule Mv.Membership.Import.MemberCSV do
groups_found: list(Mv.Membership.Group.t() | %{id: String.t(), name: String.t()})
}
alias Mv.Membership.Import.ColumnResolver
alias Mv.Membership.Import.CsvParser
alias Mv.Membership.Import.HeaderMapper
use Gettext, backend: MvWeb.Gettext
alias Mv.Helpers.SystemActor
# Import FieldTypes for human-readable type labels
alias MvWeb.Translations.FieldTypes
# Configuration constants
@default_max_errors 50
@default_chunk_size 200

View file

@ -17,13 +17,14 @@ defmodule Mv.Membership.MemberExport.Build do
No translations/Gettext in this module - labels come from the web layer via a function.
"""
require Ash.Query
import Ash.Expr
alias Mv.Membership.{CustomField, CustomFieldValueFormatter, Member, MemberExportSort}
alias MvWeb.MemberLive.Index
alias MvWeb.MemberLive.Index.MembershipFeeStatus
require Ash.Query
@custom_field_prefix Mv.Constants.custom_field_prefix()
@doc """

View file

@ -12,12 +12,12 @@ defmodule Mv.Membership.MembersPDF do
to avoid symlink issues and ensure isolation.
"""
require Logger
use Gettext, backend: MvWeb.Gettext
alias Mv.Config
require Logger
@template_filename "members_export.typ"
@doc """

View file

@ -1,11 +1,4 @@
defmodule Mv.MembershipFees.CycleGenerator do
@typedoc "Aggregate counts returned by a batch cycle-generation run."
@type results_summary :: %{
success: non_neg_integer(),
failed: non_neg_integer(),
total: non_neg_integer()
}
@moduledoc """
Module for generating membership fee cycles for members.
@ -66,6 +59,13 @@ defmodule Mv.MembershipFees.CycleGenerator do
require Ash.Query
require Logger
@typedoc "Aggregate counts returned by a batch cycle-generation run."
@type results_summary :: %{
success: non_neg_integer(),
failed: non_neg_integer(),
total: non_neg_integer()
}
@type generate_result ::
{:ok, [MembershipFeeCycle.t()], [Ash.Notifier.Notification.t()]} | {:error, term()}

View file

@ -12,8 +12,6 @@ defmodule Mv.Release do
or ADMIN_PASSWORD_FILE). Idempotent; can be run on every deployment or via shell
to update the admin password without redeploying.
"""
@app :mv
alias Mv.Accounts
alias Mv.Accounts.User
alias Mv.Authorization.Role
@ -21,6 +19,8 @@ defmodule Mv.Release do
require Ash.Query
require Logger
@app :mv
def migrate do
_ = load_app()

View file

@ -7,15 +7,15 @@ defmodule Mv.Statistics do
to Ash reads so that policies are enforced.
"""
require Ash.Query
import Ash.Expr
require Logger
alias Mv.Membership.Member
alias Mv.MembershipFees
alias Mv.MembershipFees.MembershipFeeCycle
require Ash.Query
require Logger
@doc """
Returns the earliest year in which any member has a join_date.

View file

@ -9,9 +9,10 @@ defmodule Mv.Vereinfacht.Changes.SyncLinkedMemberAfterUserChange do
"""
use Ash.Resource.Change
require Logger
alias Mv.EmailSync.Loader
require Logger
@impl true
def change(changeset, _opts, _context) do
if Mv.Config.vereinfacht_configured?() and relevant_change?(changeset) do

View file

@ -7,13 +7,15 @@ defmodule Mv.Vereinfacht do
the linked member's email via Ecto (e.g. user email change).
- `sync_members_without_contact/0` Bulk sync of members without a contact ID.
"""
require Ash.Query
import Ash.Expr
alias Mv.Helpers
alias Mv.Helpers.SystemActor
alias Mv.Membership.Member
alias Mv.Vereinfacht.Client
require Ash.Query
@doc """
Tests the connection to the Vereinfacht API using the current configuration.

View file

@ -3,9 +3,10 @@ defmodule MvWeb.TableComponents do
TableComponents that can be used in tables as components (like a button for sorting, a filter...)
"""
use Phoenix.Component
import MvWeb.CoreComponents
use Gettext, backend: MvWeb.Gettext
import MvWeb.CoreComponents
attr :field, :atom, required: true
attr :label, :string, required: true
attr :sort_field, :atom, default: nil

View file

@ -13,12 +13,12 @@ defmodule MvWeb.ImportTemplateController do
"""
use MvWeb, :controller
import MvWeb.ControllerHelpers, only: [current_actor: 1]
alias Mv.Membership.Member
alias Mv.Membership.MembersCSV
alias MvWeb.Authorization
import MvWeb.ControllerHelpers, only: [current_actor: 1]
# Standard member columns in template order, with their English and German headers
# and a placeholder example value. Groups and fee type are importable extras.
@columns [

View file

@ -6,9 +6,10 @@ defmodule MvWeb.MemberExportController do
Same permission and actor context as the member overview; 403 if unauthorized.
"""
use MvWeb, :controller
use Gettext, backend: MvWeb.Gettext
require Ash.Query
import Ash.Expr
import MvWeb.ControllerHelpers, only: [current_actor: 1]
alias Mv.Membership.CustomField
alias Mv.Membership.CustomFieldSort
@ -18,8 +19,7 @@ defmodule MvWeb.MemberExportController do
alias MvWeb.MemberLive.Index.MembershipFeeStatus
alias MvWeb.Translations.MemberFields
import MvWeb.ControllerHelpers, only: [current_actor: 1]
use Gettext, backend: MvWeb.Gettext
require Ash.Query
@member_fields_allowlist (Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)) ++
["membership_fee_type", "groups"]

View file

@ -7,15 +7,14 @@ defmodule MvWeb.MemberPdfExportController do
"""
use MvWeb, :controller
use Gettext, backend: MvWeb.Gettext
require Logger
import MvWeb.ControllerHelpers, only: [current_actor: 1]
alias Mv.Membership.{MemberExport, MemberExport.Build, MembersPDF}
alias MvWeb.Translations.MemberFields
import MvWeb.ControllerHelpers, only: [current_actor: 1]
use Gettext, backend: MvWeb.Gettext
require Logger
@payload_required_message "payload required"
@invalid_json_message "invalid JSON"

View file

@ -15,13 +15,14 @@ defmodule MvWeb.LinkOidcAccountLive do
6. User is redirected to complete OIDC login
"""
use MvWeb, :live_view
require Ash.Query
require Logger
alias AshAuthentication.Strategy.Password.Actions, as: PasswordActions
alias Mv.Accounts.User, as: UserResource
alias Mv.Helpers.SystemActor
require Ash.Query
require Logger
@impl true
def mount(_params, session, socket) do
# Use SystemActor for authorization during OIDC linking (user is not yet logged in)

View file

@ -34,7 +34,6 @@ defmodule MvWeb.GlobalSettingsLive do
"""
use MvWeb, :live_view
require Ash.Query
import Ash.Expr
alias Mv.Helpers
@ -44,6 +43,8 @@ defmodule MvWeb.GlobalSettingsLive do
alias MvWeb.Helpers.MemberHelpers
alias MvWeb.Translations.MemberFields
require Ash.Query
on_mount {MvWeb.LiveHelpers, :ensure_user_role_loaded}
@impl true

View file

@ -15,16 +15,16 @@ defmodule MvWeb.GroupLive.Show do
"""
use MvWeb, :live_view
require Logger
import Ash.Expr
import MvWeb.LiveHelpers, only: [current_actor: 1]
import MvWeb.Authorization
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.Membership
alias MvWeb.Helpers.MemberHelpers, as: MemberHelpers
alias MvWeb.Live.MemberDropdownNav
require Logger
@impl true
def mount(_params, _session, socket) do
{:ok,

View file

@ -7,13 +7,13 @@ defmodule MvWeb.ImportLive.Components do
use Phoenix.Component
use Gettext, backend: MvWeb.Gettext
import MvWeb.CoreComponents
use Phoenix.VerifiedRoutes,
endpoint: MvWeb.Endpoint,
router: MvWeb.Router,
statics: MvWeb.static_paths()
import MvWeb.CoreComponents
@doc """
Renders the info box explaining that data fields must exist before import
and linking to Manage Member Data (custom fields).

View file

@ -13,15 +13,15 @@ defmodule MvWeb.JoinRequestLive.Index do
"""
use MvWeb, :live_view
require Logger
import MvWeb.LiveHelpers, only: [current_actor: 1]
import MvWeb.Authorization
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.Membership
alias MvWeb.Helpers.DateFormatter
alias MvWeb.JoinRequestLive.Helpers, as: JoinRequestHelpers
require Logger
@impl true
def mount(_params, _session, socket) do
actor = current_actor(socket)

View file

@ -14,10 +14,8 @@ defmodule MvWeb.JoinRequestLive.Show do
"""
use MvWeb, :live_view
require Logger
import MvWeb.LiveHelpers, only: [current_actor: 1]
import MvWeb.Authorization
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.Constants
alias Mv.Membership
@ -26,6 +24,8 @@ defmodule MvWeb.JoinRequestLive.Show do
alias MvWeb.JoinRequestLive.Helpers, as: JoinRequestHelpers
alias MvWeb.Translations.MemberFields, as: MemberFieldsTranslations
require Logger
@impl true
def mount(_params, _session, socket) do
if Membership.join_form_enabled?() do

View file

@ -20,7 +20,6 @@ defmodule MvWeb.MemberLive.Form do
"""
use MvWeb, :live_view
require Logger
import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3]
alias Mv.Membership
@ -32,6 +31,8 @@ defmodule MvWeb.MemberLive.Form do
alias MvWeb.Helpers.MemberHelpers
alias MvWeb.Helpers.MembershipFeeHelpers
require Logger
@impl true
def render(assigns) do
# Sort custom fields by name for display only

View file

@ -26,8 +26,6 @@ defmodule MvWeb.MemberLive.Index do
"""
use MvWeb, :live_view
require Ash.Query
require Logger
import Ash.Expr
import MvWeb.LiveHelpers, only: [current_actor: 1]
@ -45,6 +43,9 @@ defmodule MvWeb.MemberLive.Index do
alias MvWeb.MemberLive.Index.Formatter
alias MvWeb.MemberLive.Index.MembershipFeeStatus
require Ash.Query
require Logger
@custom_field_prefix Mv.Constants.custom_field_prefix()
@boolean_filter_prefix Mv.Constants.boolean_filter_prefix()
@group_filter_prefix Mv.Constants.group_filter_prefix()

View file

@ -28,12 +28,13 @@ defmodule MvWeb.MemberLive.Index.DateFilter do
`exit_date IS NULL OR exit_date > today` a member who left today is hidden.
"""
require Ash.Query
import Ash.Expr
alias MvWeb.MemberLive.Index.CustomFieldValueLookup
alias MvWeb.MemberLive.Index.FilterParams
require Ash.Query
@join_date_from_param Mv.Constants.join_date_from_param()
@join_date_to_param Mv.Constants.join_date_to_param()
@exit_date_mode_param Mv.Constants.exit_date_mode_param()

View file

@ -12,10 +12,9 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
"""
use MvWeb, :live_component
require Ash.Query
import MvWeb.LiveHelpers, only: [current_actor: 1]
import MvWeb.Authorization, only: [can?: 3]
import MvWeb.Helpers.AshErrorHelpers, only: [format_error: 1]
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.Membership
alias Mv.MembershipFees
@ -25,6 +24,8 @@ defmodule MvWeb.MemberLive.Show.MembershipFeesComponent do
alias Mv.MembershipFees.MembershipFeeType
alias MvWeb.Helpers.MembershipFeeHelpers
require Ash.Query
@impl true
def render(assigns) do
~H"""

View file

@ -9,8 +9,6 @@ defmodule MvWeb.MembershipFeeSettingsLive do
"""
use MvWeb, :live_view
require Ash.Query
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.Membership
@ -18,6 +16,8 @@ defmodule MvWeb.MembershipFeeSettingsLive do
alias Mv.MembershipFees.MembershipFeeType
alias MvWeb.Helpers.MembershipFeeHelpers
require Ash.Query
@impl true
def mount(_params, _session, socket) do
actor = current_actor(socket)

View file

@ -15,13 +15,13 @@ defmodule MvWeb.MembershipFeeTypeLive.Form do
import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3]
require Ash.Query
alias Mv.Membership.Member
alias Mv.MembershipFees
alias Mv.MembershipFees.MembershipFeeType
alias MvWeb.Helpers.MembershipFeeHelpers
require Ash.Query
@impl true
def render(assigns) do
~H"""

View file

@ -16,14 +16,14 @@ defmodule MvWeb.MembershipFeeTypeLive.Index do
import MvWeb.LiveHelpers, only: [current_actor: 1]
require Ash.Query
alias Mv.Membership
alias Mv.Membership.Member
alias Mv.MembershipFees
alias Mv.MembershipFees.MembershipFeeType
alias MvWeb.Helpers.MembershipFeeHelpers
require Ash.Query
@impl true
def mount(_params, _session, socket) do
actor = current_actor(socket)

View file

@ -13,10 +13,10 @@ defmodule MvWeb.RoleLive.Form do
"""
use MvWeb, :live_view
alias Mv.Authorization.PermissionSets
import MvWeb.RoleLive.Helpers, only: [format_error: 1]
alias Mv.Authorization.PermissionSets
@impl true
def render(assigns) do
~H"""

View file

@ -13,13 +13,13 @@ defmodule MvWeb.RoleLive.Index do
"""
use MvWeb, :live_view
import MvWeb.RoleLive.Helpers, only: [permission_set_badge_variant: 1]
alias Mv.Accounts
alias Mv.Authorization
require Ash.Query
import MvWeb.RoleLive.Helpers, only: [permission_set_badge_variant: 1]
@impl true
def mount(_params, _session, socket) do
actor = socket.assigns[:current_user]

View file

@ -12,13 +12,13 @@ defmodule MvWeb.RoleLive.Show do
"""
use MvWeb, :live_view
import MvWeb.RoleLive.Helpers,
only: [format_error: 1, permission_set_badge_variant: 1, opts_with_actor: 3]
alias Mv.Accounts
require Ash.Query
import MvWeb.RoleLive.Helpers,
only: [format_error: 1, permission_set_badge_variant: 1, opts_with_actor: 3]
@impl true
def mount(%{"id" => id}, _session, socket) do
case Ash.get(

View file

@ -6,13 +6,14 @@ defmodule MvWeb.StatisticsLive do
"""
use MvWeb, :live_view
require Logger
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.MembershipFees.MembershipFeeType
alias Mv.Statistics
alias MvWeb.Helpers.MembershipFeeHelpers
require Logger
@impl true
def mount(_params, _session, socket) do
# Only static assigns and fee types here; load_statistics runs once in handle_params

View file

@ -33,7 +33,9 @@ defmodule MvWeb.UserLive.Form do
"""
use MvWeb, :live_view
require Jason
import MvWeb.Authorization, only: [can?: 3]
import MvWeb.ErrorHelpers, only: [format_ash_error: 1]
import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3]
alias Mv.Accounts
alias Mv.Accounts.User, as: UserResource
@ -45,9 +47,7 @@ defmodule MvWeb.UserLive.Form do
alias MvWeb.Helpers.MemberHelpers
alias MvWeb.Live.MemberDropdownNav
import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3]
import MvWeb.Authorization, only: [can?: 3]
import MvWeb.ErrorHelpers, only: [format_ash_error: 1]
require Jason
@impl true
def render(assigns) do

View file

@ -3,9 +3,10 @@ defmodule MvWeb.LiveUserAuth do
Helpers for authenticating users in LiveViews.
"""
import Phoenix.Component
use MvWeb, :verified_routes
import Phoenix.Component
alias AshAuthentication.Phoenix.LiveSession
alias Phoenix.LiveView

View file

@ -5,10 +5,11 @@ defmodule Mv.Membership.GroupDatabaseConstraintsTest do
"""
use Mv.DataCase, async: false
import Ash.Expr
alias Mv.Membership
require Ash.Query
import Ash.Expr
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -5,10 +5,11 @@ defmodule Mv.Membership.GroupTest do
"""
use Mv.DataCase, async: true
import Ash.Expr
alias Mv.Membership
require Ash.Query
import Ash.Expr
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -8,13 +8,14 @@ defmodule Mv.Membership.JoinRequestApprovalDomainTest do
use Mv.DataCase, async: true
import Ash.Expr
require Ash.Query
alias Mv.Fixtures
alias Mv.Helpers.SystemActor
alias Mv.Membership
alias Mv.Membership.Member
require Ash.Query
defp member_count do
actor = SystemActor.get_system_actor()
{:ok, members} = Membership.list_members(actor: actor)

View file

@ -12,13 +12,14 @@ defmodule Mv.Membership.JoinRequestTest do
"""
use Mv.DataCase, async: true
require Ash.Query
import Ash.Expr
alias Mv.Fixtures
alias Mv.Membership
alias Mv.Membership.JoinRequest
require Ash.Query
# Valid minimal attributes for submit (email required; confirmation_token optional for tests)
@valid_submit_attrs %{
email: "join#{System.unique_integer([:positive])}@example.com"

View file

@ -5,10 +5,11 @@ defmodule Mv.Membership.MemberGroupTest do
"""
use Mv.DataCase, async: true
import Ash.Expr
alias Mv.Membership
require Ash.Query
import Ash.Expr
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -4,10 +4,11 @@ defmodule Mv.Membership.MemberGroupsRelationshipTest do
"""
use Mv.DataCase, async: true
import Ash.Expr
alias Mv.Membership
require Ash.Query
import Ash.Expr
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -12,10 +12,10 @@ defmodule Mv.Authorization.Checks.HasPermissionFailClosedTest do
"""
use Mv.DataCase, async: true
alias Mv.Authorization.Checks.HasPermission
import Mv.Fixtures
alias Mv.Authorization.Checks.HasPermission
test "auto_filter deny-filter matches no records (regression for NOT IN [] allow-all bug)" do
# Arrange: create some members in DB
_m1 = member_fixture()

View file

@ -4,7 +4,6 @@ defmodule Mv.StatisticsTest do
"""
use Mv.DataCase, async: true
require Ash.Query
import Ash.Expr
alias Mv.Membership.Member
@ -13,6 +12,8 @@ defmodule Mv.StatisticsTest do
alias Mv.MembershipFees.MembershipFeeType
alias Mv.Statistics
require Ash.Query
setup do
actor = Mv.Helpers.SystemActor.get_system_actor()
%{actor: actor}

View file

@ -11,9 +11,10 @@ defmodule MvWeb.Components.MemberFilterComponentTest do
# async: false to prevent PostgreSQL deadlocks when running LiveView tests against DB
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Membership.CustomField
# Helper to create a boolean custom field (uses system_actor - only admin can create)

View file

@ -4,11 +4,11 @@ defmodule MvWeb.Helpers.MembershipFeeHelpersTest do
"""
use Mv.DataCase, async: true
require Ash.Query
alias Mv.MembershipFees.CalendarCycles
alias MvWeb.Helpers.MembershipFeeHelpers
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
%{actor: system_actor}

View file

@ -15,10 +15,11 @@ defmodule MvWeb.CustomFieldLive.DeletionTest do
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{CustomField, CustomFieldValue, Member}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
admin_role = Mv.Fixtures.role_fixture("admin")

View file

@ -8,10 +8,11 @@ defmodule MvWeb.CustomFieldLive.FormTest do
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.CustomField
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
admin_role = Mv.Fixtures.role_fixture("admin")

View file

@ -10,9 +10,10 @@ defmodule MvWeb.GroupLive.FormTest do
- Security
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
describe "create form" do

View file

@ -10,9 +10,10 @@ defmodule MvWeb.GroupLive.IndexTest do
- Edge cases
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -9,14 +9,16 @@ defmodule MvWeb.GroupLive.IntegrationTest do
- URL persistence
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
import Ash.Expr
use Gettext, backend: MvWeb.Gettext
import Ash.Expr
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership
require Ash.Query
describe "complete workflow" do
test "create → view via slug → edit → view via slug (slug unchanged)", %{
conn: conn,

View file

@ -5,9 +5,10 @@ defmodule MvWeb.GroupLive.ShowAccessibilityTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -5,10 +5,11 @@ defmodule MvWeb.GroupLive.ShowAddMemberTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
import MvWeb.GroupLiveHelpers
use Gettext, backend: MvWeb.Gettext
import MvWeb.GroupLiveHelpers
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -5,9 +5,10 @@ defmodule MvWeb.GroupLive.ShowAddRemoveMembersTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -5,9 +5,10 @@ defmodule MvWeb.GroupLive.ShowAuthorizationTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -5,9 +5,10 @@ defmodule MvWeb.GroupLive.ShowIntegrationTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -5,9 +5,10 @@ defmodule MvWeb.GroupLive.ShowMemberSearchTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -5,9 +5,10 @@ defmodule MvWeb.GroupLive.ShowRemoveMemberTest do
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership

View file

@ -11,13 +11,15 @@ defmodule MvWeb.GroupLive.ShowTest do
- Delete functionality
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
alias Mv.Membership
require Ash.Query
describe "mount and display" do
test "page renders successfully", %{conn: conn} do
group = Fixtures.group_fixture()

View file

@ -4,9 +4,10 @@ defmodule MvWeb.MemberLive.DeactivateTest do
driven through the parent LiveView (the DeactivateComponent is stateful).
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Fixtures
defp reload_member(member) do

View file

@ -11,13 +11,15 @@ defmodule MvWeb.RoleLive.ShowTest do
- Delete functionality
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Authorization
alias Mv.Authorization.Role
require Ash.Query
# Helper to create a role (authorize?: false for test data setup)
defp create_role(attrs \\ %{}) do
default_attrs = %{

View file

@ -10,10 +10,12 @@ defmodule MvWeb.UserLive.ShowTest do
- Error handling
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
require Ash.Query
setup do
# Create test user
user = create_test_user(%{email: "test@example.com", oidc_id: "test123"})

View file

@ -9,10 +9,11 @@ defmodule MvWeb.MemberLive.IndexCustomFieldsAccessibilityTest do
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{CustomField, CustomFieldValue}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -12,10 +12,11 @@ defmodule MvWeb.MemberLive.IndexCustomFieldsDisplayTest do
# async: false to prevent PostgreSQL deadlocks when creating members and custom fields
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{CustomField, CustomFieldValue}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -8,10 +8,11 @@ defmodule MvWeb.MemberLive.IndexCustomFieldsEdgeCasesTest do
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.CustomField
require Ash.Query
@tag :slow
test "displays custom field column even when no members have values", %{conn: conn} do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -11,10 +11,11 @@ defmodule MvWeb.MemberLive.IndexCustomFieldsSortingTest do
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{CustomField, CustomFieldValue}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -14,10 +14,11 @@ defmodule MvWeb.MemberLive.IndexFieldVisibilityTest do
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{CustomField, CustomFieldValue}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -11,10 +11,11 @@ defmodule MvWeb.MemberLive.IndexGroupsAccessibilityTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -11,10 +11,11 @@ defmodule MvWeb.MemberLive.IndexGroupsDisplayTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -9,10 +9,11 @@ defmodule MvWeb.MemberLive.IndexGroupsFilterTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -13,12 +13,13 @@ defmodule MvWeb.MemberLive.IndexGroupsIntegrationTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Helpers.SystemActor
alias Mv.Membership.{CustomField, CustomFieldValue, Group, MemberGroup}
alias Mv.MembershipFees.{MembershipFeeCycle, MembershipFeeType}
require Ash.Query
setup do
system_actor = SystemActor.get_system_actor()

View file

@ -11,10 +11,11 @@ defmodule MvWeb.MemberLive.IndexGroupsPerformanceTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -5,10 +5,11 @@ defmodule MvWeb.MemberLive.IndexGroupsSortingTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -12,10 +12,11 @@ defmodule MvWeb.MemberLive.IndexGroupsUrlParamsTest do
# async: false to prevent PostgreSQL deadlocks when creating members and groups
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -1,7 +1,6 @@
defmodule MvWeb.MemberLive.IndexTest do
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Helpers.SystemActor
alias Mv.Membership
@ -11,6 +10,8 @@ defmodule MvWeb.MemberLive.IndexTest do
alias Mv.MembershipFees.MembershipFeeType
alias MvWeb.MemberLive.Index, as: MemberIndex
require Ash.Query
# Helper to create a membership fee type (shared across all tests)
defp create_fee_type(attrs, actor) do
default_attrs = %{

View file

@ -14,12 +14,14 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
in the same test run (same as IndexGroupsDisplayTest).
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Membership.{Group, MemberGroup}
require Ash.Query
describe "groups section" do
setup do
actor = Mv.Helpers.SystemActor.get_system_actor()

View file

@ -14,12 +14,14 @@ defmodule MvWeb.MemberLive.ShowTest do
- Custom field cleanup in tests ensures no interference between tests
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
use Gettext, backend: MvWeb.Gettext
import Phoenix.LiveViewTest
alias Mv.Membership.{CustomField, CustomFieldValue}
require Ash.Query
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()