feat: generate modules for openid apps

This commit is contained in:
Ivan R. 2024-09-05 02:27:33 +05:00
parent 3ebcf2db4d
commit d09bcf646e
Signed by: lumin
GPG key ID: E0937DC7CD6D3817
18 changed files with 541 additions and 2 deletions

View file

@ -27,6 +27,7 @@
border-radius: 0 0 8px 8px;
}
.admin-panel h1,
.admin-panel h3 {
margin-top: 0;
}

View file

@ -137,6 +137,12 @@ defmodule Comfycamp.Accounts.User do
|> validate_required([:is_approved])
end
def admin_status_changeset(user, attrs) do
user
|> cast(attrs, [:is_admin])
|> validate_required([:is_admin])
end
@doc """
Verifies the password.

104
lib/comfycamp/sso.ex Normal file
View file

@ -0,0 +1,104 @@
defmodule Comfycamp.SSO do
@moduledoc """
The SSO context.
"""
import Ecto.Query, warn: false
alias Comfycamp.Repo
alias Comfycamp.SSO.OIDCApp
@doc """
Returns the list of oidc_apps.
## Examples
iex> list_oidc_apps()
[%OIDCApp{}, ...]
"""
def list_oidc_apps do
Repo.all(OIDCApp)
end
@doc """
Gets a single oidc_app.
Raises `Ecto.NoResultsError` if the Oidc app does not exist.
## Examples
iex> get_oidc_app!(123)
%OIDCApp{}
iex> get_oidc_app!(456)
** (Ecto.NoResultsError)
"""
def get_oidc_app!(id), do: Repo.get!(OIDCApp, id)
@doc """
Creates a oidc_app.
## Examples
iex> create_oidc_app(%{field: value})
{:ok, %OIDCApp{}}
iex> create_oidc_app(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_oidc_app(attrs \\ %{}) do
%OIDCApp{}
|> OIDCApp.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a oidc_app.
## Examples
iex> update_oidc_app(oidc_app, %{field: new_value})
{:ok, %OIDCApp{}}
iex> update_oidc_app(oidc_app, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_oidc_app(%OIDCApp{} = oidc_app, attrs) do
oidc_app
|> OIDCApp.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a oidc_app.
## Examples
iex> delete_oidc_app(oidc_app)
{:ok, %OIDCApp{}}
iex> delete_oidc_app(oidc_app)
{:error, %Ecto.Changeset{}}
"""
def delete_oidc_app(%OIDCApp{} = oidc_app) do
Repo.delete(oidc_app)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking oidc_app changes.
## Examples
iex> change_oidc_app(oidc_app)
%Ecto.Changeset{data: %OIDCApp{}}
"""
def change_oidc_app(%OIDCApp{} = oidc_app, attrs \\ %{}) do
OIDCApp.changeset(oidc_app, attrs)
end
end

View file

@ -0,0 +1,23 @@
defmodule Comfycamp.SSO.OIDCApp do
use Ecto.Schema
import Ecto.Changeset
schema "oidc_apps" do
field :enabled, :boolean, default: false
field :name, :string
field :client_id, :string
field :client_secret, :string
timestamps(type: :utc_datetime)
end
@doc false
def changeset(oidc_app, attrs) do
oidc_app
|> cast(attrs, [:name, :client_id, :client_secret, :enabled])
|> validate_required([:name, :client_id, :client_secret, :enabled])
|> validate_length(:name, min: 2)
|> validate_length(:client_id, min: 8)
|> validate_length(:client_secret, min: 12)
end
end

View file

@ -22,8 +22,8 @@
</.link>
</li>
<li>
<.link href={~p"/admin/services"}>
Сервисы
<.link href={~p"/admin/oidc_apps"}>
OpenID
</.link>
</li>
</ul>

View file

@ -0,0 +1,76 @@
defmodule ComfycampWeb.OIDCAppController do
use ComfycampWeb, :controller
alias Comfycamp.SSO
alias Comfycamp.SSO.OIDCApp
def index(conn, _params) do
oidc_apps = SSO.list_oidc_apps()
conn
|> put_layout(html: :admin)
|> render(:index, oidc_apps: oidc_apps)
end
def new(conn, _params) do
changeset = SSO.change_oidc_app(%OIDCApp{})
conn
|> put_layout(html: :admin)
|> render(:new, changeset: changeset)
end
def create(conn, %{"oidc_app" => oidc_app_params}) do
case SSO.create_oidc_app(oidc_app_params) do
{:ok, oidc_app} ->
conn
|> put_flash(:info, "Oidc app created successfully.")
|> redirect(to: ~p"/admin/oidc_apps/#{oidc_app}")
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_layout(html: :admin)
|> render(:new, changeset: changeset)
end
end
def show(conn, %{"id" => id}) do
oidc_app = SSO.get_oidc_app!(id)
conn
|> put_layout(html: :admin)
|> render(:show, oidc_app: oidc_app)
end
def edit(conn, %{"id" => id}) do
oidc_app = SSO.get_oidc_app!(id)
changeset = SSO.change_oidc_app(oidc_app)
conn
|> put_layout(html: :admin)
|> render(:edit, oidc_app: oidc_app, changeset: changeset)
end
def update(conn, %{"id" => id, "oidc_app" => oidc_app_params}) do
oidc_app = SSO.get_oidc_app!(id)
case SSO.update_oidc_app(oidc_app, oidc_app_params) do
{:ok, oidc_app} ->
conn
|> put_flash(:info, "Oidc app updated successfully.")
|> redirect(to: ~p"/admin/oidc_apps/#{oidc_app}")
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, :edit, oidc_app: oidc_app, changeset: changeset)
end
end
def delete(conn, %{"id" => id}) do
oidc_app = SSO.get_oidc_app!(id)
{:ok, _oidc_app} = SSO.delete_oidc_app(oidc_app)
conn
|> put_flash(:info, "Oidc app deleted successfully.")
|> redirect(to: ~p"/admin/oidc_apps")
end
end

View file

@ -0,0 +1,13 @@
defmodule ComfycampWeb.OIDCAppHTML do
use ComfycampWeb, :html
embed_templates "oidc_app_html/*"
@doc """
Renders a oidc_app form.
"""
attr :changeset, Ecto.Changeset, required: true
attr :action, :string, required: true
def oidc_app_form(assigns)
end

View file

@ -0,0 +1,10 @@
<div>
<.header>
Edit Oidc app <%= @oidc_app.id %>
<:subtitle>Use this form to manage oidc_app records in your database.</:subtitle>
</.header>
<.oidc_app_form changeset={@changeset} action={~p"/admin/oidc_apps/#{@oidc_app}"} />
<.back navigate={~p"/admin/oidc_apps"}>Back to oidc_apps</.back>
</div>

View file

@ -0,0 +1,28 @@
<div>
<.header>
Listing Oidc apps
<:actions>
<.link href={~p"/admin/oidc_apps/new"}>
<.button>New Oidc app</.button>
</.link>
</:actions>
</.header>
<.table id="oidc_apps" rows={@oidc_apps} row_click={&JS.navigate(~p"/admin/oidc_apps/#{&1}")}>
<:col :let={oidc_app} label="Name"><%= oidc_app.name %></:col>
<:col :let={oidc_app} label="Client"><%= oidc_app.client_id %></:col>
<:col :let={oidc_app} label="Client secret"><%= oidc_app.client_secret %></:col>
<:col :let={oidc_app} label="Enabled"><%= oidc_app.enabled %></:col>
<:action :let={oidc_app}>
<div class="sr-only">
<.link navigate={~p"/admin/oidc_apps/#{oidc_app}"}>Show</.link>
</div>
<.link navigate={~p"/admin/oidc_apps/#{oidc_app}/edit"}>Edit</.link>
</:action>
<:action :let={oidc_app}>
<.link href={~p"/admin/oidc_apps/#{oidc_app}"} method="delete" data-confirm="Are you sure?">
Delete
</.link>
</:action>
</.table>
</div>

View file

@ -0,0 +1,10 @@
<div>
<.header>
New Oidc app
<:subtitle>Use this form to manage oidc_app records in your database.</:subtitle>
</.header>
<.oidc_app_form changeset={@changeset} action={~p"/admin/oidc_apps"} />
<.back navigate={~p"/admin/oidc_apps"}>Back to oidc_apps</.back>
</div>

View file

@ -0,0 +1,14 @@
<div>
<.simple_form :let={f} for={@changeset} action={@action}>
<.error :if={@changeset.action}>
Oops, something went wrong! Please check the errors below.
</.error>
<.input field={f[:name]} type="text" label="Name" />
<.input field={f[:client_id]} type="text" label="Client" />
<.input field={f[:client_secret]} type="text" label="Client secret" />
<.input field={f[:enabled]} type="checkbox" label="Enabled" />
<:actions>
<.button>Save Oidc app</.button>
</:actions>
</.simple_form>
</div>

View file

@ -0,0 +1,20 @@
<div>
<.header>
Oidc app <%= @oidc_app.id %>
<:subtitle>This is a oidc_app record from your database.</:subtitle>
<:actions>
<.link href={~p"/admin/oidc_apps/#{@oidc_app}/edit"}>
<.button>Edit oidc_app</.button>
</.link>
</:actions>
</.header>
<.list>
<:item title="Name"><%= @oidc_app.name %></:item>
<:item title="Client"><%= @oidc_app.client_id %></:item>
<:item title="Client secret"><%= @oidc_app.client_secret %></:item>
<:item title="Enabled"><%= @oidc_app.enabled %></:item>
</.list>
<.back navigate={~p"/admin/oidc_apps"}>Back to oidc_apps</.back>
</div>

View file

@ -95,6 +95,7 @@ defmodule ComfycampWeb.Router do
get "/services", AdminPageController, :services
resources "/notes", NotesEditorController
resources "/users", UserEditorController, only: [:index, :show]
resources "/oidc_apps", OIDCAppController
put "/users/:id/approve", UserEditorController, :approve
put "/users/:id/disapprove", UserEditorController, :disapprove
end

View file

@ -0,0 +1,14 @@
defmodule Comfycamp.Repo.Migrations.CreateOidcApps do
use Ecto.Migration
def change do
create table(:oidc_apps) do
add :name, :string
add :client_id, :string
add :client_secret, :string
add :enabled, :boolean, default: false, null: false
timestamps(type: :utc_datetime)
end
end
end

View file

@ -0,0 +1,76 @@
defmodule Comfycamp.SSOTest do
use Comfycamp.DataCase
alias Comfycamp.SSO
describe "oidc_apps" do
alias Comfycamp.SSO.OIDCApp
import Comfycamp.SSOFixtures
@invalid_attrs %{enabled: nil, name: nil, client_id: nil, client_secret: nil}
test "list_oidc_apps/0 returns all oidc_apps" do
oidc_app = oidc_app_fixture()
assert SSO.list_oidc_apps() == [oidc_app]
end
test "get_oidc_app!/1 returns the oidc_app with given id" do
oidc_app = oidc_app_fixture()
assert SSO.get_oidc_app!(oidc_app.id) == oidc_app
end
test "create_oidc_app/1 with valid data creates a oidc_app" do
valid_attrs = %{
enabled: true,
name: "some name",
client_id: "some client_id",
client_secret: "some client_secret"
}
assert {:ok, %OIDCApp{} = oidc_app} = SSO.create_oidc_app(valid_attrs)
assert oidc_app.enabled == true
assert oidc_app.name == "some name"
assert oidc_app.client_id == "some client_id"
assert oidc_app.client_secret == "some client_secret"
end
test "create_oidc_app/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = SSO.create_oidc_app(@invalid_attrs)
end
test "update_oidc_app/2 with valid data updates the oidc_app" do
oidc_app = oidc_app_fixture()
update_attrs = %{
enabled: false,
name: "some updated name",
client_id: "some updated client_id",
client_secret: "some updated client_secret"
}
assert {:ok, %OIDCApp{} = oidc_app} = SSO.update_oidc_app(oidc_app, update_attrs)
assert oidc_app.enabled == false
assert oidc_app.name == "some updated name"
assert oidc_app.client_id == "some updated client_id"
assert oidc_app.client_secret == "some updated client_secret"
end
test "update_oidc_app/2 with invalid data returns error changeset" do
oidc_app = oidc_app_fixture()
assert {:error, %Ecto.Changeset{}} = SSO.update_oidc_app(oidc_app, @invalid_attrs)
assert oidc_app == SSO.get_oidc_app!(oidc_app.id)
end
test "delete_oidc_app/1 deletes the oidc_app" do
oidc_app = oidc_app_fixture()
assert {:ok, %OIDCApp{}} = SSO.delete_oidc_app(oidc_app)
assert_raise Ecto.NoResultsError, fn -> SSO.get_oidc_app!(oidc_app.id) end
end
test "change_oidc_app/1 returns a oidc_app changeset" do
oidc_app = oidc_app_fixture()
assert %Ecto.Changeset{} = SSO.change_oidc_app(oidc_app)
end
end
end

View file

@ -0,0 +1,100 @@
defmodule ComfycampWeb.OIDCAppControllerTest do
use ComfycampWeb.ConnCase
import Comfycamp.SSOFixtures
@create_attrs %{
enabled: true,
name: "some name",
client_id: "some client_id",
client_secret: "some client_secret"
}
@update_attrs %{
enabled: false,
name: "some updated name",
client_id: "some updated client_id",
client_secret: "some updated client_secret"
}
@invalid_attrs %{enabled: nil, name: nil, client_id: nil, client_secret: nil}
describe "index" do
setup [:register_and_log_in_admin_user]
test "lists all oidc_apps", %{conn: conn} do
conn = get(conn, ~p"/admin/oidc_apps")
assert html_response(conn, 200) =~ "Listing Oidc apps"
end
end
describe "new oidc_app" do
setup [:register_and_log_in_admin_user]
test "renders form", %{conn: conn} do
conn = get(conn, ~p"/admin/oidc_apps/new")
assert html_response(conn, 200) =~ "New Oidc app"
end
end
describe "create oidc_app" do
setup [:register_and_log_in_admin_user]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, ~p"/admin/oidc_apps", oidc_app: @create_attrs)
assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == ~p"/admin/oidc_apps/#{id}"
conn = get(conn, ~p"/admin/oidc_apps/#{id}")
assert html_response(conn, 200) =~ "Oidc app #{id}"
end
test "renders errors when data is invalid", %{conn: conn} do
conn = post(conn, ~p"/admin/oidc_apps", oidc_app: @invalid_attrs)
assert html_response(conn, 200) =~ "New Oidc app"
end
end
describe "edit oidc_app" do
setup [:create_oidc_app, :register_and_log_in_admin_user]
test "renders form for editing chosen oidc_app", %{conn: conn, oidc_app: oidc_app} do
conn = get(conn, ~p"/admin/oidc_apps/#{oidc_app}/edit")
assert html_response(conn, 200) =~ "Edit Oidc app"
end
end
describe "update oidc_app" do
setup [:create_oidc_app, :register_and_log_in_admin_user]
test "redirects when data is valid", %{conn: conn, oidc_app: oidc_app} do
conn = put(conn, ~p"/admin/oidc_apps/#{oidc_app}", oidc_app: @update_attrs)
assert redirected_to(conn) == ~p"/admin/oidc_apps/#{oidc_app}"
conn = get(conn, ~p"/admin/oidc_apps/#{oidc_app}")
assert html_response(conn, 200) =~ "some updated name"
end
test "renders errors when data is invalid", %{conn: conn, oidc_app: oidc_app} do
conn = put(conn, ~p"/admin/oidc_apps/#{oidc_app}", oidc_app: @invalid_attrs)
assert html_response(conn, 200) =~ "Edit Oidc app"
end
end
describe "delete oidc_app" do
setup [:create_oidc_app, :register_and_log_in_admin_user]
test "deletes chosen oidc_app", %{conn: conn, oidc_app: oidc_app} do
conn = delete(conn, ~p"/admin/oidc_apps/#{oidc_app}")
assert redirected_to(conn) == ~p"/admin/oidc_apps"
assert_error_sent 404, fn ->
get(conn, ~p"/admin/oidc_apps/#{oidc_app}")
end
end
end
defp create_oidc_app(_) do
oidc_app = oidc_app_fixture()
%{oidc_app: oidc_app}
end
end

View file

@ -15,6 +15,7 @@ defmodule ComfycampWeb.ConnCase do
this option is not recommended for other databases.
"""
alias Comfycamp.Repo
use ExUnit.CaseTemplate
using do
@ -49,6 +50,25 @@ defmodule ComfycampWeb.ConnCase do
%{conn: log_in_user(conn, user), user: user}
end
@doc """
Setup helper that registers and logs in admin users.
setup :register_and_log_in_admin_user
It stores an updated connection and a registered user in the
test context.
"""
def register_and_log_in_admin_user(%{conn: conn}) do
user = Comfycamp.AccountsFixtures.user_fixture(%{is_admin: true})
{:ok, user} =
user
|> Comfycamp.Accounts.User.admin_status_changeset(%{is_admin: true})
|> Repo.update()
%{conn: log_in_user(conn, user), user: user}
end
@doc """
Logs the given `user` into the `conn`.

View file

@ -0,0 +1,23 @@
defmodule Comfycamp.SSOFixtures do
@moduledoc """
This module defines test helpers for creating
entities via the `Comfycamp.SSO` context.
"""
@doc """
Generate a oidc_app.
"""
def oidc_app_fixture(attrs \\ %{}) do
{:ok, oidc_app} =
attrs
|> Enum.into(%{
client_id: "some client_id",
client_secret: "some client_secret",
enabled: true,
name: "some name"
})
|> Comfycamp.SSO.create_oidc_app()
oidc_app
end
end