<.form
:let={f}
for={@changeset}
@@ -8,27 +6,44 @@
phx-target={@myself}
phx-change="validate"
phx-submit="save"
+ phx-debounce="300"
+ class="flex flex-col justify-start items-stretch space-y-4"
>
- <%= label(f, :title) %>
- <%= text_input(f, :title) %>
+ <%= text_input(f, :title,
+ class: "input input-primary",
+ placeholder: gettext("title")
+ ) %>
<%= error_tag(f, :title) %>
- <%= label(f, :content) %>
- <%= textarea(f, :content) %>
+ <%= textarea(f, :content,
+ id: "context-form-content",
+ class: "input input-primary h-64 min-h-64",
+ phx_hook: "MaintainAttrs",
+ phx_update: "ignore",
+ placeholder: gettext("content")
+ ) %>
<%= error_tag(f, :content) %>
- <%= label(f, :tag) %>
- <%= multiple_select(f, :tag, "Option 1": "option1", "Option 2": "option2") %>
- <%= error_tag(f, :tag) %>
-
- <%= label(f, :visibility) %>
- <%= select(f, :visibility, Ecto.Enum.values(Memex.Contexts.Context, :visibility),
- prompt: "Choose a value"
+ <%= text_input(f, :tags_string,
+ id: "tags-input",
+ class: "input input-primary",
+ placeholder: gettext("tag1,tag2"),
+ phx_update: "ignore",
+ value: Contexts.get_tags_string(@changeset)
) %>
- <%= error_tag(f, :visibility) %>
+ <%= error_tag(f, :tags_string) %>
-
- <%= submit("Save", phx_disable_with: "Saving...") %>
+
+ <%= select(f, :visibility, Ecto.Enum.values(Memex.Contexts.Context, :visibility),
+ class: "grow input input-primary",
+ prompt: gettext("select privacy")
+ ) %>
+
+ <%= submit(dgettext("actions", "save"),
+ phx_disable_with: gettext("saving..."),
+ class: "mx-auto btn btn-primary"
+ ) %>
+ <%= error_tag(f, :visibility) %>
diff --git a/lib/memex_web/live/context_live/index.ex b/lib/memex_web/live/context_live/index.ex
index de1fa0d..d4c0666 100644
--- a/lib/memex_web/live/context_live/index.ex
+++ b/lib/memex_web/live/context_live/index.ex
@@ -1,46 +1,80 @@
defmodule MemexWeb.ContextLive.Index do
use MemexWeb, :live_view
-
- alias Memex.Contexts
- alias Memex.Contexts.Context
+ alias Memex.{Contexts, Contexts.Context}
@impl true
+ def mount(%{"search" => search}, _session, socket) do
+ {:ok, socket |> assign(search: search) |> display_contexts()}
+ end
+
def mount(_params, _session, socket) do
- {:ok, assign(socket, :contexts, list_contexts())}
+ {:ok, socket |> assign(search: nil) |> display_contexts()}
end
@impl true
- def handle_params(params, _url, socket) do
- {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+ def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do
+ {:noreply, apply_action(socket, live_action, params)}
end
- defp apply_action(socket, :edit, %{"id" => id}) do
+ defp apply_action(%{assigns: %{current_user: current_user}} = socket, :edit, %{"id" => id}) do
+ %{title: title} = context = Contexts.get_context!(id, current_user)
+
socket
- |> assign(:page_title, "edit context")
- |> assign(:context, Contexts.get_context!(id))
+ |> assign(page_title: gettext("edit %{title}", title: title))
+ |> assign(context: context)
end
- defp apply_action(socket, :new, _params) do
+ defp apply_action(%{assigns: %{current_user: %{id: current_user_id}}} = socket, :new, _params) do
socket
- |> assign(:page_title, "new context")
- |> assign(:context, %Context{})
+ |> assign(page_title: gettext("new context"))
+ |> assign(context: %Context{user_id: current_user_id})
end
defp apply_action(socket, :index, _params) do
socket
- |> assign(:page_title, "listing contexts")
- |> assign(:context, nil)
+ |> assign(page_title: gettext("contexts"))
+ |> assign(search: nil)
+ |> assign(context: nil)
+ |> display_contexts()
+ end
+
+ defp apply_action(socket, :search, %{"search" => search}) do
+ socket
+ |> assign(page_title: gettext("contexts"))
+ |> assign(search: search)
+ |> assign(context: nil)
+ |> display_contexts()
end
@impl true
- def handle_event("delete", %{"id" => id}, socket) do
- context = Contexts.get_context!(id)
- {:ok, _} = Contexts.delete_context(context)
+ def handle_event("delete", %{"id" => id}, %{assigns: %{current_user: current_user}} = socket) do
+ context = Contexts.get_context!(id, current_user)
+ {:ok, %{title: title}} = Contexts.delete_context(context, current_user)
- {:noreply, assign(socket, :contexts, list_contexts())}
+ socket =
+ socket
+ |> assign(contexts: Contexts.list_contexts(current_user))
+ |> put_flash(:info, gettext("%{title} deleted", title: title))
+
+ {:noreply, socket}
end
- defp list_contexts do
- Contexts.list_contexts()
+ @impl true
+ def handle_event("search", %{"search" => %{"search_term" => ""}}, socket) do
+ {:noreply, socket |> push_patch(to: Routes.context_index_path(Endpoint, :index))}
+ end
+
+ def handle_event("search", %{"search" => %{"search_term" => search_term}}, socket) do
+ {:noreply,
+ socket |> push_patch(to: Routes.context_index_path(Endpoint, :search, search_term))}
+ end
+
+ defp display_contexts(%{assigns: %{current_user: current_user, search: search}} = socket)
+ when not (current_user |> is_nil()) do
+ socket |> assign(contexts: Contexts.list_contexts(search, current_user))
+ end
+
+ defp display_contexts(%{assigns: %{search: search}} = socket) do
+ socket |> assign(contexts: Contexts.list_public_contexts(search))
end
end
diff --git a/lib/memex_web/live/context_live/index.html.heex b/lib/memex_web/live/context_live/index.html.heex
index 3e8a1cf..ab8ae63 100644
--- a/lib/memex_web/live/context_live/index.html.heex
+++ b/lib/memex_web/live/context_live/index.html.heex
@@ -1,10 +1,69 @@
-
listing contexts
+
+
+ <%= gettext("contexts") %>
+
+
+ <.form
+ :let={f}
+ for={:search}
+ phx-change="search"
+ phx-submit="search"
+ class="self-stretch flex flex-col items-stretch"
+ >
+ <%= text_input(f, :search_term,
+ class: "input input-primary",
+ value: @search,
+ phx_debounce: 300,
+ placeholder: gettext("search")
+ ) %>
+
+
+ <%= if @contexts |> Enum.empty?() do %>
+
+ <%= gettext("no contexts found") %>
+
+ <% else %>
+ <.live_component
+ module={MemexWeb.Components.ContextsTableComponent}
+ id="contexts-index-table"
+ current_user={@current_user}
+ contexts={@contexts}
+ >
+ <:actions :let={context}>
+ <%= if @current_user do %>
+ <.link
+ patch={Routes.context_index_path(@socket, :edit, context)}
+ data-qa={"context-edit-#{context.id}"}
+ >
+ <%= dgettext("actions", "edit") %>
+
+ <.link
+ href="#"
+ phx-click="delete"
+ phx-value-id={context.id}
+ data-confirm={dgettext("prompts", "are you sure?")}
+ data-qa={"delete-context-#{context.id}"}
+ >
+ <%= dgettext("actions", "delete") %>
+
+ <% end %>
+
+
+ <% end %>
+
+ <%= if @current_user do %>
+ <.link patch={Routes.context_index_path(@socket, :new)} class="self-end btn btn-primary">
+ <%= dgettext("actions", "new context") %>
+
+ <% end %>
+
<%= if @live_action in [:new, :edit] do %>
<.modal return_to={Routes.context_index_path(@socket, :index)}>
<.live_component
module={MemexWeb.ContextLive.FormComponent}
id={@context.id || :new}
+ current_user={@current_user}
title={@page_title}
action={@live_action}
context={@context}
@@ -12,55 +71,3 @@
/>
<% end %>
-
-
-
-
- Title |
- Content |
- Tag |
- Visibility |
-
- |
-
-
-
- <%= for context <- @contexts do %>
-
- <%= context.title %> |
- <%= context.content %> |
- <%= context.tag %> |
- <%= context.visibility %> |
-
-
-
- <.link navigate={Routes.context_show_path(@socket, :show, context)}>
- <%= dgettext("actions", "show") %>
-
-
-
- <.link patch={Routes.context_index_path(@socket, :edit, context)}>
- <%= dgettext("actions", "edit") %>
-
-
-
- <.link
- href="#"
- phx-click="delete"
- phx-value-id={context.id}
- data-confirm={dgettext("prompts", "are you sure?")}
- >
- <%= dgettext("actions", "delete") %>
-
-
- |
-
- <% end %>
-
-
-
-
- <.link patch={Routes.context_index_path(@socket, :new)}>
- <%= dgettext("actions", "new context") %>
-
-
diff --git a/lib/memex_web/live/context_live/show.ex b/lib/memex_web/live/context_live/show.ex
index 6f77a96..3e3239a 100644
--- a/lib/memex_web/live/context_live/show.ex
+++ b/lib/memex_web/live/context_live/show.ex
@@ -9,13 +9,33 @@ defmodule MemexWeb.ContextLive.Show do
end
@impl true
- def handle_params(%{"id" => id}, _, socket) do
+ def handle_params(
+ %{"id" => id},
+ _,
+ %{assigns: %{live_action: live_action, current_user: current_user}} = socket
+ ) do
{:noreply,
socket
- |> assign(:page_title, page_title(socket.assigns.live_action))
- |> assign(:context, Contexts.get_context!(id))}
+ |> assign(:page_title, page_title(live_action))
+ |> assign(:context, Contexts.get_context!(id, current_user))}
end
- defp page_title(:show), do: "show context"
- defp page_title(:edit), do: "edit context"
+ @impl true
+ def handle_event(
+ "delete",
+ _params,
+ %{assigns: %{context: context, current_user: current_user}} = socket
+ ) do
+ {:ok, %{title: title}} = Contexts.delete_context(context, current_user)
+
+ socket =
+ socket
+ |> put_flash(:info, gettext("%{title} deleted", title: title))
+ |> push_navigate(to: Routes.context_index_path(Endpoint, :index))
+
+ {:noreply, socket}
+ end
+
+ defp page_title(:show), do: gettext("show context")
+ defp page_title(:edit), do: gettext("edit context")
end
diff --git a/lib/memex_web/live/context_live/show.html.heex b/lib/memex_web/live/context_live/show.html.heex
index 510618b..c1fe16e 100644
--- a/lib/memex_web/live/context_live/show.html.heex
+++ b/lib/memex_web/live/context_live/show.html.heex
@@ -1,10 +1,51 @@
-
show context
+
+
+ <%= @context.title %>
+
+
+
<%= if @context.tags, do: @context.tags |> Enum.join(", ") %>
+
+
+
+
+ <%= gettext("Visibility: %{visibility}", visibility: @context.visibility) %>
+
+
+
+ <.link class="btn btn-primary" patch={Routes.context_index_path(@socket, :index)}>
+ <%= dgettext("actions", "back") %>
+
+ <%= if @current_user do %>
+ <.link class="btn btn-primary" patch={Routes.context_show_path(@socket, :edit, @context)}>
+ <%= dgettext("actions", "edit") %>
+
+
+
+ <% end %>
+
+
<%= if @live_action in [:edit] do %>
<.modal return_to={Routes.context_show_path(@socket, :show, @context)}>
<.live_component
module={MemexWeb.ContextLive.FormComponent}
id={@context.id}
+ current_user={@current_user}
title={@page_title}
action={@live_action}
context={@context}
@@ -12,37 +53,3 @@
/>
<% end %>
-
-
- -
- Title:
- <%= @context.title %>
-
-
- -
- Content:
- <%= @context.content %>
-
-
- -
- Tag:
- <%= @context.tag %>
-
-
- -
- Visibility:
- <%= @context.visibility %>
-
-
-
-
- <.link patch={Routes.context_show_path(@socket, :edit, @context)} class="button">
- <%= dgettext("actions", "edit") %>
-
-
-|
-
- <.link navigate={Routes.context_index_path(@socket, :index)}>
- <%= dgettext("actions", "Back") %>
-
-
diff --git a/lib/memex_web/router.ex b/lib/memex_web/router.ex
index 0b15cc6..5ce90ce 100644
--- a/lib/memex_web/router.ex
+++ b/lib/memex_web/router.ex
@@ -63,7 +63,7 @@ defmodule MemexWeb.Router do
live "/contexts/new", ContextLive.Index, :new
live "/contexts/:id/edit", ContextLive.Index, :edit
- live "/contexts/:id/show/edit", ContextLive.Show, :edit
+ live "/context/:id/edit", ContextLive.Show, :edit
live "/pipelines/new", PipelineLive.Index, :new
live "/pipelines/:id/edit", PipelineLive.Index, :edit
@@ -83,7 +83,8 @@ defmodule MemexWeb.Router do
live "/note/:id", NoteLive.Show, :show
live "/contexts", ContextLive.Index, :index
- live "/contexts/:id", ContextLive.Show, :show
+ live "/contexts/:search", ContextLive.Index, :search
+ live "/context/:id", ContextLive.Show, :show
live "/pipelines", PipelineLive.Index, :index
live "/pipelines/:id", PipelineLive.Show, :show
diff --git a/priv/gettext/actions.pot b/priv/gettext/actions.pot
index e1bff9b..bc02bce 100644
--- a/priv/gettext/actions.pot
+++ b/priv/gettext/actions.pot
@@ -10,7 +10,6 @@
msgid ""
msgstr ""
-#: lib/memex_web/live/context_live/show.html.heex:46
#: lib/memex_web/live/pipeline_live/show.html.heex:41
#, elixir-autogen, elixir-format
msgid "Back"
@@ -73,7 +72,8 @@ msgstr ""
msgid "create invite"
msgstr ""
-#: lib/memex_web/live/context_live/index.html.heex:53
+#: lib/memex_web/live/context_live/index.html.heex:47
+#: lib/memex_web/live/context_live/show.html.heex:37
#: lib/memex_web/live/note_live/index.html.heex:47
#: lib/memex_web/live/note_live/show.html.heex:37
#: lib/memex_web/live/pipeline_live/index.html.heex:51
@@ -86,8 +86,8 @@ msgstr ""
msgid "delete user"
msgstr ""
-#: lib/memex_web/live/context_live/index.html.heex:43
-#: lib/memex_web/live/context_live/show.html.heex:40
+#: lib/memex_web/live/context_live/index.html.heex:38
+#: lib/memex_web/live/context_live/show.html.heex:27
#: lib/memex_web/live/note_live/index.html.heex:38
#: lib/memex_web/live/note_live/show.html.heex:27
#: lib/memex_web/live/pipeline_live/index.html.heex:41
@@ -112,7 +112,7 @@ msgstr ""
msgid "log in"
msgstr ""
-#: lib/memex_web/live/context_live/index.html.heex:64
+#: lib/memex_web/live/context_live/index.html.heex:56
#, elixir-autogen, elixir-format
msgid "new context"
msgstr ""
@@ -138,17 +138,18 @@ msgstr ""
msgid "register"
msgstr ""
+#: lib/memex_web/live/context_live/form_component.html.heex:42
#: lib/memex_web/live/note_live/form_component.html.heex:42
#, elixir-autogen, elixir-format
msgid "save"
msgstr ""
-#: lib/memex_web/live/context_live/index.html.heex:38
#: lib/memex_web/live/pipeline_live/index.html.heex:36
#, elixir-autogen, elixir-format
msgid "show"
msgstr ""
+#: lib/memex_web/live/context_live/show.html.heex:23
#: lib/memex_web/live/note_live/show.html.heex:23
#, elixir-autogen, elixir-format
msgid "back"
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot
index 7be0417..7c719a4 100644
--- a/priv/gettext/default.pot
+++ b/priv/gettext/default.pot
@@ -10,17 +10,21 @@
msgid ""
msgstr ""
+#: lib/memex_web/live/context_live/form_component.ex:61
#: lib/memex_web/live/note_live/form_component.ex:60
#, elixir-autogen, elixir-format
msgid "%{title} created"
msgstr ""
+#: lib/memex_web/live/context_live/index.ex:57
+#: lib/memex_web/live/context_live/show.ex:33
#: lib/memex_web/live/note_live/index.ex:57
#: lib/memex_web/live/note_live/show.ex:33
#, elixir-autogen, elixir-format
msgid "%{title} deleted"
msgstr ""
+#: lib/memex_web/live/context_live/form_component.ex:44
#: lib/memex_web/live/note_live/form_component.ex:43
#, elixir-autogen, elixir-format
msgid "%{title} saved"
@@ -101,6 +105,7 @@ msgstr ""
msgid "Uses left"
msgstr ""
+#: lib/memex_web/live/context_live/show.html.heex:18
#: lib/memex_web/live/note_live/show.html.heex:18
#, elixir-autogen, elixir-format
msgid "Visibility: %{visibility}"
@@ -126,13 +131,18 @@ msgstr ""
msgid "confirm new password"
msgstr ""
+#: lib/memex_web/components/contexts_table_component.ex:48
#: lib/memex_web/components/notes_table_component.ex:48
+#: lib/memex_web/live/context_live/form_component.html.heex:23
#: lib/memex_web/live/note_live/form_component.html.heex:23
#, elixir-autogen, elixir-format
msgid "content"
msgstr ""
#: lib/memex_web/components/topbar.ex:52
+#: lib/memex_web/live/context_live/index.ex:35
+#: lib/memex_web/live/context_live/index.ex:43
+#: lib/memex_web/live/context_live/index.html.heex:3
#, elixir-autogen, elixir-format
msgid "contexts"
msgstr ""
@@ -168,6 +178,7 @@ msgstr ""
msgid "document your processes, attaching contexts to each step"
msgstr ""
+#: lib/memex_web/live/context_live/index.ex:23
#: lib/memex_web/live/note_live/index.ex:23
#, elixir-autogen, elixir-format
msgid "edit %{title}"
@@ -331,11 +342,13 @@ msgstr ""
msgid "report bugs or request features"
msgstr ""
+#: lib/memex_web/live/context_live/form_component.html.heex:43
#: lib/memex_web/live/note_live/form_component.html.heex:43
#, elixir-autogen, elixir-format
msgid "saving..."
msgstr ""
+#: lib/memex_web/live/context_live/form_component.html.heex:39
#: lib/memex_web/live/note_live/form_component.html.heex:39
#, elixir-autogen, elixir-format
msgid "select privacy"
@@ -351,17 +364,21 @@ msgstr ""
msgid "settings"
msgstr ""
+#: lib/memex_web/live/context_live/form_component.html.heex:30
#: lib/memex_web/live/note_live/form_component.html.heex:30
#, elixir-autogen, elixir-format
msgid "tag1,tag2"
msgstr ""
+#: lib/memex_web/components/contexts_table_component.ex:49
#: lib/memex_web/components/notes_table_component.ex:49
#, elixir-autogen, elixir-format
msgid "tags"
msgstr ""
+#: lib/memex_web/components/contexts_table_component.ex:47
#: lib/memex_web/components/notes_table_component.ex:47
+#: lib/memex_web/live/context_live/form_component.html.heex:14
#: lib/memex_web/live/note_live/form_component.html.heex:14
#, elixir-autogen, elixir-format
msgid "title"
@@ -392,6 +409,7 @@ msgstr ""
msgid "view the source code"
msgstr ""
+#: lib/memex_web/components/contexts_table_component.ex:50
#: lib/memex_web/components/notes_table_component.ex:50
#, elixir-autogen, elixir-format
msgid "visibility"
@@ -412,6 +430,7 @@ msgstr ""
msgid "new note"
msgstr ""
+#: lib/memex_web/live/context_live/index.html.heex:17
#: lib/memex_web/live/note_live/index.html.heex:17
#, elixir-autogen, elixir-format
msgid "search"
@@ -421,3 +440,23 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "show note"
msgstr ""
+
+#: lib/memex_web/live/context_live/show.ex:40
+#, elixir-autogen, elixir-format
+msgid "edit context"
+msgstr ""
+
+#: lib/memex_web/live/context_live/index.ex:29
+#, elixir-autogen, elixir-format
+msgid "new context"
+msgstr ""
+
+#: lib/memex_web/live/context_live/index.html.heex:23
+#, elixir-autogen, elixir-format
+msgid "no contexts found"
+msgstr ""
+
+#: lib/memex_web/live/context_live/show.ex:39
+#, elixir-autogen, elixir-format
+msgid "show context"
+msgstr ""
diff --git a/priv/gettext/prompts.pot b/priv/gettext/prompts.pot
index 4247e90..a6ec60f 100644
--- a/priv/gettext/prompts.pot
+++ b/priv/gettext/prompts.pot
@@ -141,7 +141,8 @@ msgstr ""
msgid "are you sure you want to make %{invite_name} unlimited?"
msgstr ""
-#: lib/memex_web/live/context_live/index.html.heex:51
+#: lib/memex_web/live/context_live/index.html.heex:44
+#: lib/memex_web/live/context_live/show.html.heex:34
#: lib/memex_web/live/note_live/index.html.heex:44
#: lib/memex_web/live/note_live/show.html.heex:34
#: lib/memex_web/live/pipeline_live/index.html.heex:49
diff --git a/priv/repo/migrations/20220726001039_create_contexts.exs b/priv/repo/migrations/20220726001039_create_contexts.exs
index 177b2bc..82d050c 100644
--- a/priv/repo/migrations/20220726001039_create_contexts.exs
+++ b/priv/repo/migrations/20220726001039_create_contexts.exs
@@ -6,10 +6,30 @@ defmodule Memex.Repo.Migrations.CreateContexts do
add :id, :binary_id, primary_key: true
add :title, :string
add :content, :text
- add :tag, {:array, :string}
+ add :tags, {:array, :string}
add :visibility, :string
+ add :user_id, references(:users, on_delete: :delete_all, type: :binary_id)
+
timestamps()
end
+
+ flush()
+
+ execute """
+ ALTER TABLE contexts
+ ADD COLUMN search tsvector
+ GENERATED ALWAYS AS (
+ setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
+ setweight(to_tsvector('english', coalesce(immutable_array_to_string(tags, ' '), '')), 'B') ||
+ setweight(to_tsvector('english', coalesce(content, '')), 'C')
+ ) STORED
+ """
+
+ execute("CREATE INDEX contexts_trgm_idx ON contexts USING GIN (search)")
+ end
+
+ def down do
+ drop table(:contexts)
end
end
diff --git a/test/memex/contexts_test.exs b/test/memex/contexts_test.exs
index f2062ee..69438dd 100644
--- a/test/memex/contexts_test.exs
+++ b/test/memex/contexts_test.exs
@@ -1,71 +1,113 @@
defmodule Memex.ContextsTest do
use Memex.DataCase
-
- alias Memex.Contexts
+ import Memex.ContextsFixtures
+ alias Memex.{Contexts, Contexts.Context}
+ @moduletag :contexts_test
+ @invalid_attrs %{content: nil, tag: nil, title: nil, visibility: nil}
describe "contexts" do
- alias Memex.Contexts.Context
-
- import Memex.ContextsFixtures
-
- @invalid_attrs %{content: nil, tag: nil, title: nil, visibility: nil}
-
- test "list_contexts/0 returns all contexts" do
- context = context_fixture()
- assert Contexts.list_contexts() == [context]
+ setup do
+ [user: user_fixture()]
end
- test "get_context!/1 returns the context with given id" do
- context = context_fixture()
- assert Contexts.get_context!(context.id) == context
+ test "list_contexts/1 returns all contexts for a user", %{user: user} do
+ context_a = context_fixture(%{title: "a", visibility: :public}, user)
+ context_b = context_fixture(%{title: "b", visibility: :unlisted}, user)
+ context_c = context_fixture(%{title: "c", visibility: :private}, user)
+ assert Contexts.list_contexts(user) == [context_a, context_b, context_c]
end
- test "create_context/1 with valid data creates a context" do
- valid_attrs = %{content: "some content", tag: [], title: "some title", visibility: :public}
+ test "list_public_contexts/0 returns public contexts", %{user: user} do
+ public_context = context_fixture(%{visibility: :public}, user)
+ context_fixture(%{visibility: :unlisted}, user)
+ context_fixture(%{visibility: :private}, user)
+ assert Contexts.list_public_contexts() == [public_context]
+ end
- assert {:ok, %Context{} = context} = Contexts.create_context(valid_attrs)
+ test "get_context!/1 returns the context with given id", %{user: user} do
+ context = context_fixture(%{visibility: :public}, user)
+ assert Contexts.get_context!(context.id, user) == context
+
+ context = context_fixture(%{visibility: :unlisted}, user)
+ assert Contexts.get_context!(context.id, user) == context
+
+ context = context_fixture(%{visibility: :private}, user)
+ assert Contexts.get_context!(context.id, user) == context
+ end
+
+ test "get_context!/1 only returns unlisted or public contexts for other users", %{user: user} do
+ another_user = user_fixture()
+ context = context_fixture(%{visibility: :public}, another_user)
+ assert Contexts.get_context!(context.id, user) == context
+
+ context = context_fixture(%{visibility: :unlisted}, another_user)
+ assert Contexts.get_context!(context.id, user) == context
+
+ context = context_fixture(%{visibility: :private}, another_user)
+
+ assert_raise Ecto.NoResultsError, fn ->
+ Contexts.get_context!(context.id, user)
+ end
+ end
+
+ test "create_context/1 with valid data creates a context", %{user: user} do
+ valid_attrs = %{
+ "content" => "some content",
+ "tags_string" => "tag1,tag2",
+ "title" => "some title",
+ "visibility" => :public
+ }
+
+ assert {:ok, %Context{} = context} = Contexts.create_context(valid_attrs, user)
assert context.content == "some content"
- assert context.tag == []
+ assert context.tags == ["tag1", "tag2"]
assert context.title == "some title"
assert context.visibility == :public
end
- test "create_context/1 with invalid data returns error changeset" do
- assert {:error, %Ecto.Changeset{}} = Contexts.create_context(@invalid_attrs)
+ test "create_context/1 with invalid data returns error changeset", %{user: user} do
+ assert {:error, %Ecto.Changeset{}} = Contexts.create_context(@invalid_attrs, user)
end
- test "update_context/2 with valid data updates the context" do
- context = context_fixture()
+ test "update_context/2 with valid data updates the context", %{user: user} do
+ context = context_fixture(user)
update_attrs = %{
- content: "some updated content",
- tag: [],
- title: "some updated title",
- visibility: :private
+ "content" => "some updated content",
+ "tags_string" => "tag1,tag2",
+ "title" => "some updated title",
+ "visibility" => :private
}
- assert {:ok, %Context{} = context} = Contexts.update_context(context, update_attrs)
+ assert {:ok, %Context{} = context} = Contexts.update_context(context, update_attrs, user)
assert context.content == "some updated content"
- assert context.tag == []
+ assert context.tags == ["tag1", "tag2"]
assert context.title == "some updated title"
assert context.visibility == :private
end
- test "update_context/2 with invalid data returns error changeset" do
- context = context_fixture()
- assert {:error, %Ecto.Changeset{}} = Contexts.update_context(context, @invalid_attrs)
- assert context == Contexts.get_context!(context.id)
+ test "update_context/2 with invalid data returns error changeset", %{user: user} do
+ context = context_fixture(user)
+ assert {:error, %Ecto.Changeset{}} = Contexts.update_context(context, @invalid_attrs, user)
+ assert context == Contexts.get_context!(context.id, user)
end
- test "delete_context/1 deletes the context" do
- context = context_fixture()
- assert {:ok, %Context{}} = Contexts.delete_context(context)
- assert_raise Ecto.NoResultsError, fn -> Contexts.get_context!(context.id) end
+ test "delete_context/1 deletes the context", %{user: user} do
+ context = context_fixture(user)
+ assert {:ok, %Context{}} = Contexts.delete_context(context, user)
+ assert_raise Ecto.NoResultsError, fn -> Contexts.get_context!(context.id, user) end
end
- test "change_context/1 returns a context changeset" do
- context = context_fixture()
- assert %Ecto.Changeset{} = Contexts.change_context(context)
+ test "delete_context/1 deletes the context for an admin user", %{user: user} do
+ admin_user = admin_fixture()
+ context = context_fixture(user)
+ assert {:ok, %Context{}} = Contexts.delete_context(context, admin_user)
+ assert_raise Ecto.NoResultsError, fn -> Contexts.get_context!(context.id, user) end
+ end
+
+ test "change_context/1 returns a context changeset", %{user: user} do
+ context = context_fixture(user)
+ assert %Ecto.Changeset{} = Contexts.change_context(context, user)
end
end
end
diff --git a/test/memex_web/live/context_live_test.exs b/test/memex_web/live/context_live_test.exs
index 2522147..6e17aa5 100644
--- a/test/memex_web/live/context_live_test.exs
+++ b/test/memex_web/live/context_live_test.exs
@@ -23,18 +23,17 @@ defmodule MemexWeb.ContextLiveTest do
"visibility" => nil
}
- defp create_context(_) do
- context = context_fixture()
- %{context: context}
+ defp create_context(%{user: user}) do
+ [context: context_fixture(user)]
end
describe "Index" do
- setup [:create_context]
+ setup [:register_and_log_in_user, :create_context]
test "lists all contexts", %{conn: conn, context: context} do
{:ok, _index_live, html} = live(conn, Routes.context_index_path(conn, :index))
- assert html =~ "listing contexts"
+ assert html =~ "contexts"
assert html =~ context.content
end
@@ -56,15 +55,15 @@ defmodule MemexWeb.ContextLiveTest do
|> render_submit()
|> follow_redirect(conn, Routes.context_index_path(conn, :index))
- assert html =~ "context created successfully"
+ assert html =~ "#{@create_attrs |> Map.get("title")} created"
assert html =~ "some content"
end
test "updates context in listing", %{conn: conn, context: context} do
{:ok, index_live, _html} = live(conn, Routes.context_index_path(conn, :index))
- assert index_live |> element("#context-#{context.id} a", "edit") |> render_click() =~
- "edit context"
+ assert index_live |> element("[data-qa=\"context-edit-#{context.id}\"]") |> render_click() =~
+ "edit"
assert_patch(index_live, Routes.context_index_path(conn, :edit, context))
@@ -78,20 +77,20 @@ defmodule MemexWeb.ContextLiveTest do
|> render_submit()
|> follow_redirect(conn, Routes.context_index_path(conn, :index))
- assert html =~ "context updated successfully"
+ assert html =~ "#{@update_attrs |> Map.get("title")} saved"
assert html =~ "some updated content"
end
test "deletes context in listing", %{conn: conn, context: context} do
{:ok, index_live, _html} = live(conn, Routes.context_index_path(conn, :index))
- assert index_live |> element("#context-#{context.id} a", "delete") |> render_click()
+ assert index_live |> element("[data-qa=\"delete-context-#{context.id}\"]") |> render_click()
refute has_element?(index_live, "#context-#{context.id}")
end
end
describe "show" do
- setup [:create_context]
+ setup [:register_and_log_in_user, :create_context]
test "displays context", %{conn: conn, context: context} do
{:ok, _show_live, html} = live(conn, Routes.context_show_path(conn, :show, context))
@@ -103,8 +102,7 @@ defmodule MemexWeb.ContextLiveTest do
test "updates context within modal", %{conn: conn, context: context} do
{:ok, show_live, _html} = live(conn, Routes.context_show_path(conn, :show, context))
- assert show_live |> element("a", "edit") |> render_click() =~
- "edit context"
+ assert show_live |> element("a", "edit") |> render_click() =~ "edit"
assert_patch(show_live, Routes.context_show_path(conn, :edit, context))
@@ -118,8 +116,20 @@ defmodule MemexWeb.ContextLiveTest do
|> render_submit()
|> follow_redirect(conn, Routes.context_show_path(conn, :show, context))
- assert html =~ "context updated successfully"
+ assert html =~ "#{@update_attrs |> Map.get("title")} saved"
assert html =~ "some updated content"
end
+
+ test "deletes context", %{conn: conn, context: context} do
+ {:ok, show_live, _html} = live(conn, Routes.context_show_path(conn, :show, context))
+
+ {:ok, index_live, _html} =
+ show_live
+ |> element("[data-qa=\"delete-context-#{context.id}\"]")
+ |> render_click()
+ |> follow_redirect(conn, Routes.context_index_path(conn, :index))
+
+ refute has_element?(index_live, "#context-#{context.id}")
+ end
end
end
diff --git a/test/support/fixtures/contexts_fixtures.ex b/test/support/fixtures/contexts_fixtures.ex
index 0965668..b930f21 100644
--- a/test/support/fixtures/contexts_fixtures.ex
+++ b/test/support/fixtures/contexts_fixtures.ex
@@ -3,20 +3,23 @@ defmodule Memex.ContextsFixtures do
This module defines test helpers for creating
entities via the `Memex.Contexts` context.
"""
+ alias Memex.{Accounts.User, Contexts, Contexts.Context}
@doc """
Generate a context.
"""
- def context_fixture(attrs \\ %{}) do
+ @spec context_fixture(User.t()) :: Context.t()
+ @spec context_fixture(attrs :: map(), User.t()) :: Context.t()
+ def context_fixture(attrs \\ %{}, user) do
{:ok, context} =
attrs
|> Enum.into(%{
content: "some content",
tag: [],
title: "some title",
- visibility: :public
+ visibility: :private
})
- |> Memex.Contexts.create_context()
+ |> Contexts.create_context(user)
context
end