towerops/lib/towerops_web/controllers/user_settings_controller.ex
Graham McIntire c52f313e2d
1. User Authentication
- Full auth system with email/password (using phx.gen.auth)
  - Login, registration, password reset
  - Session management with remember-me functionality
  - Magic link login support

  2. Organization Management
  - Multi-tenant organization system
  - Organizations schema with unique slugs
  - Automatic organization creation when users register
  - Organization switcher UI at /orgs

  3. Membership System
  - Users can belong to multiple organizations
  - 4 permission levels: Owner, Admin, Member, Viewer
  - Complete permission matrix implemented
  - Join/leave organizations

  4. Invitation System
  - Email-based invitations with secure tokens
  - 7-day expiration on invites
  - Track who invited and who accepted

  5. Authorization
  - Full policy system (Organizations.Policy)
  - can?(membership, :action, :resource) helper
  - Enforced via plugs in router

  6. LiveView Pages
  - /orgs - List all your organizations
  - /orgs/new - Create new organization
  - /orgs/:slug - Organization dashboard (placeholder)

  7. Database Schema
  - users table
  - organizations table
  - organization_memberships table
  - organization_invitations table
  - All migrations run successfully
2025-12-21 13:31:59 -06:00

77 lines
2.2 KiB
Elixir

defmodule ToweropsWeb.UserSettingsController do
use ToweropsWeb, :controller
import ToweropsWeb.UserAuth, only: [require_sudo_mode: 2]
alias Towerops.Accounts
alias ToweropsWeb.UserAuth
plug :require_sudo_mode
plug :assign_email_and_password_changesets
def edit(conn, _params) do
render(conn, :edit)
end
def update(conn, %{"action" => "update_email"} = params) do
%{"user" => user_params} = params
user = conn.assigns.current_scope.user
case Accounts.change_user_email(user, user_params) do
%{valid?: true} = changeset ->
Accounts.deliver_user_update_email_instructions(
Ecto.Changeset.apply_action!(changeset, :insert),
user.email,
&url(~p"/users/settings/confirm-email/#{&1}")
)
conn
|> put_flash(
:info,
"A link to confirm your email change has been sent to the new address."
)
|> redirect(to: ~p"/users/settings")
changeset ->
render(conn, :edit, email_changeset: %{changeset | action: :insert})
end
end
def update(conn, %{"action" => "update_password"} = params) do
%{"user" => user_params} = params
user = conn.assigns.current_scope.user
case Accounts.update_user_password(user, user_params) do
{:ok, {user, _}} ->
conn
|> put_flash(:info, "Password updated successfully.")
|> put_session(:user_return_to, ~p"/users/settings")
|> UserAuth.log_in_user(user)
{:error, changeset} ->
render(conn, :edit, password_changeset: changeset)
end
end
def confirm_email(conn, %{"token" => token}) do
case Accounts.update_user_email(conn.assigns.current_scope.user, token) do
{:ok, _user} ->
conn
|> put_flash(:info, "Email changed successfully.")
|> redirect(to: ~p"/users/settings")
{:error, _} ->
conn
|> put_flash(:error, "Email change link is invalid or it has expired.")
|> redirect(to: ~p"/users/settings")
end
end
defp assign_email_and_password_changesets(conn, _opts) do
user = conn.assigns.current_scope.user
conn
|> assign(:email_changeset, Accounts.change_user_email(user))
|> assign(:password_changeset, Accounts.change_user_password(user))
end
end