Skip to content

Commit

Permalink
Merge pull request #43 from OpenFn/22-credential-model-form
Browse files Browse the repository at this point in the history
22 credential model form
  • Loading branch information
stuartc committed Mar 28, 2022
2 parents 25d5945 + 355dce5 commit ff27f05
Show file tree
Hide file tree
Showing 20 changed files with 667 additions and 58 deletions.
108 changes: 108 additions & 0 deletions lib/lightning/credentials.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
defmodule Lightning.Credentials do
@moduledoc """
The Credentials context.
"""

import Ecto.Query, warn: false
import Lightning.Helpers, only: [coerce_json_field: 2]
alias Lightning.Repo

alias Lightning.Credentials.Credential

@doc """
Returns the list of credentials.
## Examples
iex> list_credentials()
[%Credential{}, ...]
"""
def list_credentials do
Repo.all(Credential)
end

@doc """
Gets a single credential.
Raises `Ecto.NoResultsError` if the Credential does not exist.
## Examples
iex> get_credential!(123)
%Credential{}
iex> get_credential!(456)
** (Ecto.NoResultsError)
"""
def get_credential!(id), do: Repo.get!(Credential, id)

@doc """
Creates a credential.
## Examples
iex> create_credential(%{field: value})
{:ok, %Credential{}}
iex> create_credential(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_credential(attrs \\ %{}) do
%Credential{}
|> Credential.changeset(attrs |> coerce_json_field("body"))
|> Repo.insert()
end

@doc """
Updates a credential.
## Examples
iex> update_credential(credential, %{field: new_value})
{:ok, %Credential{}}
iex> update_credential(credential, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_credential(%Credential{} = credential, attrs) do
credential
|> Credential.changeset(attrs |> coerce_json_field("body"))
|> Repo.update()
end

@doc """
Deletes a credential.
## Examples
iex> delete_credential(credential)
{:ok, %Credential{}}
iex> delete_credential(credential)
{:error, %Ecto.Changeset{}}
"""
def delete_credential(%Credential{} = credential) do
Repo.delete(credential)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking credential changes.
## Examples
iex> change_credential(credential)
%Ecto.Changeset{data: %Credential{}}
"""
def change_credential(%Credential{} = credential, attrs \\ %{}) do
Credential.changeset(
credential,
attrs |> coerce_json_field("body")
)
end
end
24 changes: 24 additions & 0 deletions lib/lightning/credentials/credential.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Lightning.Credentials.Credential do
@moduledoc """
The Credential model.
"""

use Ecto.Schema
import Ecto.Changeset

@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "credentials" do
field :body, :map
field :name, :string

timestamps()
end

@doc false
def changeset(credential, attrs) do
credential
|> cast(attrs, [:name, :body])
|> validate_required([:name, :body])
end
end
35 changes: 35 additions & 0 deletions lib/lightning/helpers.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Lightning.Helpers do
@moduledoc """
Common functions for the context
"""

@doc """
Changes a given maps field from a json string to a map.
If it cannot be converted, it leaves the original value
"""
@spec coerce_json_field(map(), Map.key()) :: map()
def coerce_json_field(attrs, field) do
{_, attrs} =
Map.get_and_update(attrs, field, fn body ->
case body do
nil ->
:pop

body when is_binary(body) ->
{body, decode_and_replace(body)}

any ->
{body, any}
end
end)

attrs
end

defp decode_and_replace(body) do
case Jason.decode(body) do
{:error, _} -> body
{:ok, body_map} -> body_map
end
end
end
32 changes: 4 additions & 28 deletions lib/lightning/invocation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Lightning.Invocation do
"""

import Ecto.Query, warn: false
import Lightning.Helpers, only: [coerce_json_field: 2]
alias Lightning.Repo

alias Lightning.Invocation.{Dataclip, Event, Run}
Expand Down Expand Up @@ -73,7 +74,7 @@ defmodule Lightning.Invocation do
"""
def create_dataclip(attrs \\ %{}) do
%Dataclip{}
|> Dataclip.changeset(attrs |> coerce_json_body())
|> Dataclip.changeset(attrs |> coerce_json_field("body"))
|> Repo.insert()
end

Expand All @@ -91,7 +92,7 @@ defmodule Lightning.Invocation do
"""
def update_dataclip(%Dataclip{} = dataclip, attrs) do
dataclip
|> Dataclip.changeset(attrs |> coerce_json_body())
|> Dataclip.changeset(attrs |> coerce_json_field("body"))
|> Repo.update()
end

Expand Down Expand Up @@ -121,32 +122,7 @@ defmodule Lightning.Invocation do
"""
def change_dataclip(%Dataclip{} = dataclip, attrs \\ %{}) do
Dataclip.changeset(dataclip, attrs |> coerce_json_body())
end

defp coerce_json_body(attrs) do
{_, attrs} =
Map.get_and_update(attrs, "body", fn body ->
case body do
nil ->
:pop

body when is_binary(body) ->
{body, decode_and_replace(body)}

any ->
{body, any}
end
end)

attrs
end

def decode_and_replace(body) do
case Jason.decode(body) do
{:error, _} -> body
{:ok, body_map} -> body_map
end
Dataclip.changeset(dataclip, attrs |> coerce_json_field("body"))
end

@doc """
Expand Down
26 changes: 26 additions & 0 deletions lib/lightning_web/live/credential_live/edit.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule LightningWeb.CredentialLive.Edit do
@moduledoc """
LiveView for editing a single job, which inturn uses `LightningWeb.JobLive.FormComponent`
for common functionality.
"""
use LightningWeb, :live_view

alias Lightning.Credentials

@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(:active_menu_item, :credentials)
|> assign(:credentials, Credentials.get_credential!(id))}
end

defp page_title(:show), do: "Show Job"
defp page_title(:edit), do: "Edit Job"
end
14 changes: 14 additions & 0 deletions lib/lightning_web/live/credential_live/edit.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<MainSection.header title={"#{@credential.name}"} />

<MainSection.main>

<.live_component
module={LightningWeb.CredentialLive.FormComponent}
id={@credential.id || :new}
title={@page_title}
action={@live_action}
credential={@credential}
return_to={Routes.credential_index_path(@socket, :index)}
/>

</MainSection.main>
58 changes: 58 additions & 0 deletions lib/lightning_web/live/credential_live/form_component.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
defmodule LightningWeb.CredentialLive.FormComponent do
@moduledoc """
Form Component for working with a single Credential
"""
use LightningWeb, :live_component

alias Lightning.{Credentials}

@impl true
def update(%{credential: credential} = assigns, socket) do
changeset = Credentials.change_credential(credential)

{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)}
end

@impl true
def handle_event("validate", %{"credential" => credential_params}, socket) do
changeset =
socket.assigns.credential
|> Credentials.change_credential(credential_params)
|> Map.put(:action, :validate)

{:noreply, assign(socket, :changeset, changeset)}
end

def handle_event("save", %{"credential" => credential_params}, socket) do
save_credential(socket, socket.assigns.action, credential_params)
end

defp save_credential(socket, :edit, credential_params) do
case Credentials.update_credential(socket.assigns.credential, credential_params) do
{:ok, _credential} ->
{:noreply,
socket
|> put_flash(:info, "Credential updated successfully")
|> push_redirect(to: socket.assigns.return_to)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end

defp save_credential(socket, :new, credential_params) do
case Credentials.create_credential(credential_params) do
{:ok, _credential} ->
{:noreply,
socket
|> put_flash(:info, "Credential created successfully")
|> push_redirect(to: socket.assigns.return_to)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
end
34 changes: 34 additions & 0 deletions lib/lightning_web/live/credential_live/form_component.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<div id={"credential-#{@id}"}>
<.form
let={f}
for={@changeset}
id="credential-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save">

<div class="grid grid-cols-6 gap-6">
<div class="col-span-3">

<%= label f, :name, class: "block text-sm font-medium text-gray-700" %>
<%= error_tag f, :name, class: "block w-full rounded-md" %>
<%= text_input f, :name, class: "mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md" %>

</div>

</div>

<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>

<%= error_tag f, :body %>
<%= textarea f, :body, class: "rounded-md w-full font-mono bg-slate-800 text-slate-50 h-96 min-h-full" %>

<div>
<%= submit "Save", phx_disable_with: "Saving...", class: "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %>
</div>
</.form>
</div>
Loading

0 comments on commit ff27f05

Please sign in to comment.