4 Commits

  1. 11
      CHANGELOG.md
  2. 96
      lib/mirage/accounts.ex
  3. 3
      lib/mirage/accounts/user.ex
  4. 19
      lib/mirage/accounts/user_identity.ex
  5. 25
      lib/mirage/links.ex
  6. 2
      lib/mirage_web/live/note_live/show.html.leex
  7. 55
      lib/mirage_web/live/user_identity_live/form_component.ex
  8. 22
      lib/mirage_web/live/user_identity_live/form_component.html.leex
  9. 46
      lib/mirage_web/live/user_identity_live/index.ex
  10. 39
      lib/mirage_web/live/user_identity_live/index.html.leex
  11. 21
      lib/mirage_web/live/user_identity_live/show.ex
  12. 32
      lib/mirage_web/live/user_identity_live/show.html.leex
  13. 13
      lib/mirage_web/router.ex
  14. 9
      lib/mirage_web/templates/layout/root.html.leex
  15. 1
      lib/mirage_web/templates/setting/index.html.eex
  16. 2
      mix.exs
  17. 14
      priv/repo/migrations/20210330060742_create_user_identities.exs
  18. 63
      test/mirage/accounts_test.exs
  19. 116
      test/mirage_web/live/user_identity_live_test.exs

11
CHANGELOG.md

@ -5,6 +5,17 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
<!-- changelog -->
## [v0.100.0](https://git.inhji.de/inhji/mirage/compare/v0.99.0...v0.100.0) (2021-03-30)
### Features:
* add user identities
* link to web manifest
## [v0.99.0](https://git.inhji.de/inhji/mirage/compare/v0.98.0...v0.99.0) (2021-03-29)

96
lib/mirage/accounts.ex

@ -370,4 +370,100 @@ defmodule Mirage.Accounts do
{:error, :user, changeset, _} -> {:error, changeset}
end
end
alias Mirage.Accounts.UserIdentity
@doc """
Returns the list of user_identities.
## Examples
iex> list_user_identities()
[%UserIdentity{}, ...]
"""
def list_user_identities do
Repo.all(UserIdentity)
end
@doc """
Gets a single user_identity.
Raises `Ecto.NoResultsError` if the User identity does not exist.
## Examples
iex> get_user_identity!(123)
%UserIdentity{}
iex> get_user_identity!(456)
** (Ecto.NoResultsError)
"""
def get_user_identity!(id), do: Repo.get!(UserIdentity, id)
@doc """
Creates a user_identity.
## Examples
iex> create_user_identity(%{field: value})
{:ok, %UserIdentity{}}
iex> create_user_identity(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_user_identity(attrs \\ %{}) do
%UserIdentity{}
|> UserIdentity.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a user_identity.
## Examples
iex> update_user_identity(user_identity, %{field: new_value})
{:ok, %UserIdentity{}}
iex> update_user_identity(user_identity, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_user_identity(%UserIdentity{} = user_identity, attrs) do
user_identity
|> UserIdentity.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a user_identity.
## Examples
iex> delete_user_identity(user_identity)
{:ok, %UserIdentity{}}
iex> delete_user_identity(user_identity)
{:error, %Ecto.Changeset{}}
"""
def delete_user_identity(%UserIdentity{} = user_identity) do
Repo.delete(user_identity)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking user_identity changes.
## Examples
iex> change_user_identity(user_identity)
%Ecto.Changeset{data: %UserIdentity{}}
"""
def change_user_identity(%UserIdentity{} = user_identity, attrs \\ %{}) do
UserIdentity.changeset(user_identity, attrs)
end
end

3
lib/mirage/accounts/user.ex

@ -72,6 +72,9 @@ defmodule Mirage.Accounts.User do
end
end
@doc """
A user changeset for updating the profile
"""
def profile_changeset(changeset, attrs) do
changeset
|> cast(attrs, [:name, :real_name, :notes])

19
lib/mirage/accounts/user_identity.ex

@ -0,0 +1,19 @@
defmodule Mirage.Accounts.UserIdentity do
use Ecto.Schema
import Ecto.Changeset
schema "user_identities" do
field :name, :string
field :rel, :string
field :value, :string
timestamps()
end
@doc false
def changeset(user_identity, attrs) do
user_identity
|> cast(attrs, [:name, :value, :rel])
|> validate_required([:name, :value, :rel])
end
end

25
lib/mirage/links.ex

@ -38,12 +38,37 @@ defmodule Mirage.Links do
"""
def get_link!(id), do: Repo.get!(Link, id)
@doc """
Gets a single link.
Returns `nil` if the Note link does not exist.
## Examples
iex> get_link(123)
%Link{}
"""
def get_link(id), do: Repo.get(Link, id)
@doc """
Gets a single link by its url.
Raises if the Note link does not exist.
## Examples
iex> get_link!("http://inhji.de")
%Link{}
"""
def get_link_by_url!(url) do
Repo.get_by!(Link, url: url)
end
@doc """
Preloads a single link.
"""
def preload_link(link), do: Repo.preload(link, @link_preloads)
@doc """

2
lib/mirage_web/live/note_live/show.html.leex

@ -85,8 +85,6 @@
</form>
</section>
<% end %>
</article>
<%= if @current_user do %>

55
lib/mirage_web/live/user_identity_live/form_component.ex

@ -0,0 +1,55 @@
defmodule MirageWeb.UserIdentityLive.FormComponent do
use MirageWeb, :live_component
alias Mirage.Accounts
@impl true
def update(%{user_identity: user_identity} = assigns, socket) do
changeset = Accounts.change_user_identity(user_identity)
{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)}
end
@impl true
def handle_event("validate", %{"user_identity" => user_identity_params}, socket) do
changeset =
socket.assigns.user_identity
|> Accounts.change_user_identity(user_identity_params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :changeset, changeset)}
end
def handle_event("save", %{"user_identity" => user_identity_params}, socket) do
save_user_identity(socket, socket.assigns.action, user_identity_params)
end
defp save_user_identity(socket, :edit, user_identity_params) do
case Accounts.update_user_identity(socket.assigns.user_identity, user_identity_params) do
{:ok, _user_identity} ->
{:noreply,
socket
|> put_flash(:info, "User identity updated successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
defp save_user_identity(socket, :new, user_identity_params) do
case Accounts.create_user_identity(user_identity_params) do
{:ok, _user_identity} ->
{:noreply,
socket
|> put_flash(:info, "User identity created successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
end

22
lib/mirage_web/live/user_identity_live/form_component.html.leex

@ -0,0 +1,22 @@
<h2><%= @title %></h2>
<%= f = form_for @changeset, "#",
id: "user_identity-form",
phx_target: @myself,
phx_change: "validate",
phx_submit: "save" %>
<%= label f, :name %>
<%= text_input f, :name %>
<%= error_tag f, :name %>
<%= label f, :value %>
<%= text_input f, :value %>
<%= error_tag f, :value %>
<%= label f, :rel %>
<%= text_input f, :rel %>
<%= error_tag f, :rel %>
<%= submit "Save", phx_disable_with: "Saving..." %>
</form>

46
lib/mirage_web/live/user_identity_live/index.ex

@ -0,0 +1,46 @@
defmodule MirageWeb.UserIdentityLive.Index do
use MirageWeb, :live_view
alias Mirage.Accounts
alias Mirage.Accounts.UserIdentity
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :user_identities, list_user_identities())}
end
@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit User identity")
|> assign(:user_identity, Accounts.get_user_identity!(id))
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New User identity")
|> assign(:user_identity, %UserIdentity{})
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing User identities")
|> assign(:user_identity, nil)
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
user_identity = Accounts.get_user_identity!(id)
{:ok, _} = Accounts.delete_user_identity(user_identity)
{:noreply, assign(socket, :user_identities, list_user_identities())}
end
defp list_user_identities do
Accounts.list_user_identities()
end
end

39
lib/mirage_web/live/user_identity_live/index.html.leex

@ -0,0 +1,39 @@
<h1>Listing User identities</h1>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal @socket, MirageWeb.UserIdentityLive.FormComponent,
id: @user_identity.id || :new,
title: @page_title,
action: @live_action,
user_identity: @user_identity,
return_to: Routes.user_identity_index_path(@socket, :index) %>
<% end %>
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Rel</th>
<th></th>
</tr>
</thead>
<tbody id="user_identities">
<%= for user_identity <- @user_identities do %>
<tr id="user_identity-<%= user_identity.id %>">
<td><%= user_identity.name %></td>
<td><%= user_identity.value %></td>
<td><%= user_identity.rel %></td>
<td>
<span><%= live_redirect "Show", to: Routes.user_identity_show_path(@socket, :show, user_identity) %></span>
<span><%= live_patch "Edit", to: Routes.user_identity_index_path(@socket, :edit, user_identity) %></span>
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: user_identity.id, data: [confirm: "Are you sure?"] %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
<span><%= live_patch "New User identity", to: Routes.user_identity_index_path(@socket, :new) %></span>

21
lib/mirage_web/live/user_identity_live/show.ex

@ -0,0 +1,21 @@
defmodule MirageWeb.UserIdentityLive.Show do
use MirageWeb, :live_view
alias Mirage.Accounts
@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end
@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:user_identity, Accounts.get_user_identity!(id))}
end
defp page_title(:show), do: "Show User identity"
defp page_title(:edit), do: "Edit User identity"
end

32
lib/mirage_web/live/user_identity_live/show.html.leex

@ -0,0 +1,32 @@
<h1>Show User identity</h1>
<%= if @live_action in [:edit] do %>
<%= live_modal @socket, MirageWeb.UserIdentityLive.FormComponent,
id: @user_identity.id,
title: @page_title,
action: @live_action,
user_identity: @user_identity,
return_to: Routes.user_identity_show_path(@socket, :show, @user_identity) %>
<% end %>
<ul>
<li>
<strong>Name:</strong>
<%= @user_identity.name %>
</li>
<li>
<strong>Value:</strong>
<%= @user_identity.value %>
</li>
<li>
<strong>Rel:</strong>
<%= @user_identity.rel %>
</li>
</ul>
<span><%= live_patch "Edit", to: Routes.user_identity_show_path(@socket, :edit, @user_identity), class: "button" %></span>
<span><%= live_redirect "Back", to: Routes.user_identity_index_path(@socket, :index) %></span>

13
lib/mirage_web/router.ex

@ -8,10 +8,16 @@ defmodule MirageWeb.Router do
assign(conn, :_s, settings)
end
def fetch_identities(conn, _opts) do
identities = Mirage.Accounts.list_user_identities()
assign(conn, :_i, identities)
end
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_settings
plug :fetch_identities
plug :fetch_live_flash
plug :put_root_layout, {MirageWeb.LayoutView, :root}
plug :protect_from_forgery
@ -94,6 +100,13 @@ defmodule MirageWeb.Router do
get "/user/edit", UserSettingsController, :edit
put "/user/edit", UserSettingsController, :update
get "/user/edit/confirm_email/:token", UserSettingsController, :confirm_email
live "/user/identities", UserIdentityLive.Index, :index
live "/user/identities/new", UserIdentityLive.Index, :new
live "/user/identities/:id/edit", UserIdentityLive.Index, :edit
live "/user/identities/:id", UserIdentityLive.Show, :show
live "/user/identities/:id/show/edit", UserIdentityLive.Show, :edit
end
scope "/", MirageWeb do

9
lib/mirage_web/templates/layout/root.html.leex

@ -6,7 +6,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<%= csrf_meta_tag() %>
<%= live_title_tag assigns[:page_title] || "Inhji.de", suffix: " · Inhji.de" %>
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.ico" />
<link rel="manifest" href="/manifest.json" />
<%= for identity <- @_i do %>
<link rel="<%= identity.rel %>" href="<%= identity.value %>" />
<% end %>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>

1
lib/mirage_web/templates/setting/index.html.eex

@ -16,4 +16,5 @@
<h2>User Settings</h2>
<%= link "Edit User", to: Routes.user_settings_path(@conn, :edit), class: "button" %>
<%= link "Edit Identities", to: Routes.user_identity_index_path(@conn, :index), class: "button" %>
</section>

2
mix.exs

@ -1,7 +1,7 @@
defmodule Mirage.MixProject do
use Mix.Project
@version "0.99.0"
@version "0.100.0"
def project do
[

14
priv/repo/migrations/20210330060742_create_user_identities.exs

@ -0,0 +1,14 @@
defmodule Mirage.Repo.Migrations.CreateUserIdentities do
use Ecto.Migration
def change do
create table(:user_identities) do
add :name, :string
add :value, :string
add :rel, :string, default: "me"
timestamps()
end
end
end

63
test/mirage/accounts_test.exs

@ -501,4 +501,67 @@ defmodule Mirage.AccountsTest do
refute inspect(%User{password: "123456"}) =~ "password: \"123456\""
end
end
describe "user_identities" do
alias Mirage.Accounts.UserIdentity
@valid_attrs %{name: "some name", rel: "some rel", value: "some value"}
@update_attrs %{name: "some updated name", rel: "some updated rel", value: "some updated value"}
@invalid_attrs %{name: nil, rel: nil, value: nil}
def user_identity_fixture(attrs \\ %{}) do
{:ok, user_identity} =
attrs
|> Enum.into(@valid_attrs)
|> Accounts.create_user_identity()
user_identity
end
test "list_user_identities/0 returns all user_identities" do
user_identity = user_identity_fixture()
assert Accounts.list_user_identities() == [user_identity]
end
test "get_user_identity!/1 returns the user_identity with given id" do
user_identity = user_identity_fixture()
assert Accounts.get_user_identity!(user_identity.id) == user_identity
end
test "create_user_identity/1 with valid data creates a user_identity" do
assert {:ok, %UserIdentity{} = user_identity} = Accounts.create_user_identity(@valid_attrs)
assert user_identity.name == "some name"
assert user_identity.rel == "some rel"
assert user_identity.value == "some value"
end
test "create_user_identity/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Accounts.create_user_identity(@invalid_attrs)
end
test "update_user_identity/2 with valid data updates the user_identity" do
user_identity = user_identity_fixture()
assert {:ok, %UserIdentity{} = user_identity} = Accounts.update_user_identity(user_identity, @update_attrs)
assert user_identity.name == "some updated name"
assert user_identity.rel == "some updated rel"
assert user_identity.value == "some updated value"
end
test "update_user_identity/2 with invalid data returns error changeset" do
user_identity = user_identity_fixture()
assert {:error, %Ecto.Changeset{}} = Accounts.update_user_identity(user_identity, @invalid_attrs)
assert user_identity == Accounts.get_user_identity!(user_identity.id)
end
test "delete_user_identity/1 deletes the user_identity" do
user_identity = user_identity_fixture()
assert {:ok, %UserIdentity{}} = Accounts.delete_user_identity(user_identity)
assert_raise Ecto.NoResultsError, fn -> Accounts.get_user_identity!(user_identity.id) end
end
test "change_user_identity/1 returns a user_identity changeset" do
user_identity = user_identity_fixture()
assert %Ecto.Changeset{} = Accounts.change_user_identity(user_identity)
end
end
end

116
test/mirage_web/live/user_identity_live_test.exs

@ -0,0 +1,116 @@
defmodule MirageWeb.UserIdentityLiveTest do
use MirageWeb.ConnCase
import Phoenix.LiveViewTest
alias Mirage.Accounts
@create_attrs %{name: "some name", rel: "some rel", value: "some value"}
@update_attrs %{name: "some updated name", rel: "some updated rel", value: "some updated value"}
@invalid_attrs %{name: nil, rel: nil, value: nil}
defp fixture(:user_identity) do
{:ok, user_identity} = Accounts.create_user_identity(@create_attrs)
user_identity
end
defp create_user_identity(_) do
user_identity = fixture(:user_identity)
%{user_identity: user_identity}
end
describe "Index" do
setup [:create_user_identity]
test "lists all user_identities", %{conn: conn, user_identity: user_identity} do
{:ok, _index_live, html} = live(conn, Routes.user_identity_index_path(conn, :index))
assert html =~ "Listing User identities"
assert html =~ user_identity.name
end
test "saves new user_identity", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.user_identity_index_path(conn, :index))
assert index_live |> element("a", "New User identity") |> render_click() =~
"New User identity"
assert_patch(index_live, Routes.user_identity_index_path(conn, :new))
assert index_live
|> form("#user_identity-form", user_identity: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
index_live
|> form("#user_identity-form", user_identity: @create_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.user_identity_index_path(conn, :index))
assert html =~ "User identity created successfully"
assert html =~ "some name"
end
test "updates user_identity in listing", %{conn: conn, user_identity: user_identity} do
{:ok, index_live, _html} = live(conn, Routes.user_identity_index_path(conn, :index))
assert index_live |> element("#user_identity-#{user_identity.id} a", "Edit") |> render_click() =~
"Edit User identity"
assert_patch(index_live, Routes.user_identity_index_path(conn, :edit, user_identity))
assert index_live
|> form("#user_identity-form", user_identity: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
index_live
|> form("#user_identity-form", user_identity: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.user_identity_index_path(conn, :index))
assert html =~ "User identity updated successfully"
assert html =~ "some updated name"
end
test "deletes user_identity in listing", %{conn: conn, user_identity: user_identity} do
{:ok, index_live, _html} = live(conn, Routes.user_identity_index_path(conn, :index))
assert index_live |> element("#user_identity-#{user_identity.id} a", "Delete") |> render_click()
refute has_element?(index_live, "#user_identity-#{user_identity.id}")
end
end
describe "Show" do
setup [:create_user_identity]
test "displays user_identity", %{conn: conn, user_identity: user_identity} do
{:ok, _show_live, html} = live(conn, Routes.user_identity_show_path(conn, :show, user_identity))
assert html =~ "Show User identity"
assert html =~ user_identity.name
end
test "updates user_identity within modal", %{conn: conn, user_identity: user_identity} do
{:ok, show_live, _html} = live(conn, Routes.user_identity_show_path(conn, :show, user_identity))
assert show_live |> element("a", "Edit") |> render_click() =~
"Edit User identity"
assert_patch(show_live, Routes.user_identity_show_path(conn, :edit, user_identity))
assert show_live
|> form("#user_identity-form", user_identity: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
show_live
|> form("#user_identity-form", user_identity: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.user_identity_show_path(conn, :show, user_identity))
assert html =~ "User identity updated successfully"
assert html =~ "some updated name"
end
end
end
Loading…
Cancel
Save