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; border-radius: 0 0 8px 8px;
} }
.admin-panel h1,
.admin-panel h3 { .admin-panel h3 {
margin-top: 0; margin-top: 0;
} }

View file

@ -137,6 +137,12 @@ defmodule Comfycamp.Accounts.User do
|> validate_required([:is_approved]) |> validate_required([:is_approved])
end end
def admin_status_changeset(user, attrs) do
user
|> cast(attrs, [:is_admin])
|> validate_required([:is_admin])
end
@doc """ @doc """
Verifies the password. 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> </.link>
</li> </li>
<li> <li>
<.link href={~p"/admin/services"}> <.link href={~p"/admin/oidc_apps"}>
Сервисы OpenID
</.link> </.link>
</li> </li>
</ul> </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 get "/services", AdminPageController, :services
resources "/notes", NotesEditorController resources "/notes", NotesEditorController
resources "/users", UserEditorController, only: [:index, :show] resources "/users", UserEditorController, only: [:index, :show]
resources "/oidc_apps", OIDCAppController
put "/users/:id/approve", UserEditorController, :approve put "/users/:id/approve", UserEditorController, :approve
put "/users/:id/disapprove", UserEditorController, :disapprove put "/users/:id/disapprove", UserEditorController, :disapprove
end 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. this option is not recommended for other databases.
""" """
alias Comfycamp.Repo
use ExUnit.CaseTemplate use ExUnit.CaseTemplate
using do using do
@ -49,6 +50,25 @@ defmodule ComfycampWeb.ConnCase do
%{conn: log_in_user(conn, user), user: user} %{conn: log_in_user(conn, user), user: user}
end 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 """ @doc """
Logs the given `user` into the `conn`. 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