diff --git a/lib/ketbin/pastes.ex b/lib/ketbin/pastes.ex new file mode 100644 index 0000000..27f738b --- /dev/null +++ b/lib/ketbin/pastes.ex @@ -0,0 +1,104 @@ +defmodule Ketbin.Pastes do + @moduledoc """ + The Pastes context. + """ + + import Ecto.Query, warn: false + alias Ketbin.Repo + + alias Ketbin.Pastes.Paste + + @doc """ + Returns the list of pastes. + + ## Examples + + iex> list_pastes() + [%Paste{}, ...] + + """ + def list_pastes do + Repo.all(Paste) + end + + @doc """ + Gets a single paste. + + Raises `Ecto.NoResultsError` if the Paste does not exist. + + ## Examples + + iex> get_paste!(123) + %Paste{} + + iex> get_paste!(456) + ** (Ecto.NoResultsError) + + """ + def get_paste!(id), do: Repo.get!(Paste, id) + + @doc """ + Creates a paste. + + ## Examples + + iex> create_paste(%{field: value}) + {:ok, %Paste{}} + + iex> create_paste(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_paste(attrs \\ %{}) do + %Paste{} + |> Paste.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a paste. + + ## Examples + + iex> update_paste(paste, %{field: new_value}) + {:ok, %Paste{}} + + iex> update_paste(paste, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_paste(%Paste{} = paste, attrs) do + paste + |> Paste.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a paste. + + ## Examples + + iex> delete_paste(paste) + {:ok, %Paste{}} + + iex> delete_paste(paste) + {:error, %Ecto.Changeset{}} + + """ + def delete_paste(%Paste{} = paste) do + Repo.delete(paste) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking paste changes. + + ## Examples + + iex> change_paste(paste) + %Ecto.Changeset{data: %Paste{}} + + """ + def change_paste(%Paste{} = paste, attrs \\ %{}) do + Paste.changeset(paste, attrs) + end +end diff --git a/lib/ketbin/pastes/paste.ex b/lib/ketbin/pastes/paste.ex new file mode 100644 index 0000000..8c6cd5f --- /dev/null +++ b/lib/ketbin/pastes/paste.ex @@ -0,0 +1,17 @@ +defmodule Ketbin.Pastes.Paste do + use Ecto.Schema + import Ecto.Changeset + + schema "pastes" do + field :content, :string + field :is_url, :boolean, default: false + field :belongs_to, :id + end + + @doc false + def changeset(paste, attrs) do + paste + |> cast(attrs, [:is_url, :content]) + |> validate_required([:is_url, :content]) + end +end diff --git a/lib/ketbin_web/controllers/paste_controller.ex b/lib/ketbin_web/controllers/paste_controller.ex new file mode 100644 index 0000000..4e6ec80 --- /dev/null +++ b/lib/ketbin_web/controllers/paste_controller.ex @@ -0,0 +1,62 @@ +defmodule KetbinWeb.PasteController do + use KetbinWeb, :controller + + alias Ketbin.Pastes + alias Ketbin.Pastes.Paste + + def index(conn, _params) do + pastes = Pastes.list_pastes() + render(conn, "index.html", pastes: pastes) + end + + def new(conn, _params) do + changeset = Pastes.change_paste(%Paste{}) + render(conn, "new.html", changeset: changeset) + end + + def create(conn, %{"paste" => paste_params}) do + case Pastes.create_paste(paste_params) do + {:ok, paste} -> + conn + |> put_flash(:info, "Paste created successfully.") + |> redirect(to: Routes.paste_path(conn, :show, paste)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "new.html", changeset: changeset) + end + end + + def show(conn, %{"id" => id}) do + paste = Pastes.get_paste!(id) + render(conn, "show.html", paste: paste) + end + + def edit(conn, %{"id" => id}) do + paste = Pastes.get_paste!(id) + changeset = Pastes.change_paste(paste) + render(conn, "edit.html", paste: paste, changeset: changeset) + end + + def update(conn, %{"id" => id, "paste" => paste_params}) do + paste = Pastes.get_paste!(id) + + case Pastes.update_paste(paste, paste_params) do + {:ok, paste} -> + conn + |> put_flash(:info, "Paste updated successfully.") + |> redirect(to: Routes.paste_path(conn, :show, paste)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "edit.html", paste: paste, changeset: changeset) + end + end + + def delete(conn, %{"id" => id}) do + paste = Pastes.get_paste!(id) + {:ok, _paste} = Pastes.delete_paste(paste) + + conn + |> put_flash(:info, "Paste deleted successfully.") + |> redirect(to: Routes.paste_path(conn, :index)) + end +end diff --git a/lib/ketbin_web/router.ex b/lib/ketbin_web/router.ex index 0e49138..fc3d630 100644 --- a/lib/ketbin_web/router.ex +++ b/lib/ketbin_web/router.ex @@ -73,5 +73,7 @@ defmodule KetbinWeb.Router do get "/users/confirm", UserConfirmationController, :new post "/users/confirm", UserConfirmationController, :create get "/users/confirm/:token", UserConfirmationController, :confirm + + resources "/pastes", PasteController end end diff --git a/lib/ketbin_web/templates/paste/edit.html.eex b/lib/ketbin_web/templates/paste/edit.html.eex new file mode 100644 index 0000000..0bb1c93 --- /dev/null +++ b/lib/ketbin_web/templates/paste/edit.html.eex @@ -0,0 +1,5 @@ +

Edit Paste

+ +<%= render "form.html", Map.put(assigns, :action, Routes.paste_path(@conn, :update, @paste)) %> + +<%= link "Back", to: Routes.paste_path(@conn, :index) %> diff --git a/lib/ketbin_web/templates/paste/form.html.eex b/lib/ketbin_web/templates/paste/form.html.eex new file mode 100644 index 0000000..ecc0d25 --- /dev/null +++ b/lib/ketbin_web/templates/paste/form.html.eex @@ -0,0 +1,19 @@ +<%= form_for @changeset, @action, fn f -> %> + <%= if @changeset.action do %> +
+

Oops, something went wrong! Please check the errors below.

+
+ <% end %> + + <%= label f, :is_url %> + <%= checkbox f, :is_url %> + <%= error_tag f, :is_url %> + + <%= label f, :content %> + <%= textarea f, :content %> + <%= error_tag f, :content %> + +
+ <%= submit "Save" %> +
+<% end %> diff --git a/lib/ketbin_web/templates/paste/index.html.eex b/lib/ketbin_web/templates/paste/index.html.eex new file mode 100644 index 0000000..3eb7ecd --- /dev/null +++ b/lib/ketbin_web/templates/paste/index.html.eex @@ -0,0 +1,28 @@ +

Listing Pastes

+ + + + + + + + + + + +<%= for paste <- @pastes do %> + + + + + + +<% end %> + +
Is urlContent
<%= paste.is_url %><%= paste.content %> + <%= link "Show", to: Routes.paste_path(@conn, :show, paste) %> + <%= link "Edit", to: Routes.paste_path(@conn, :edit, paste) %> + <%= link "Delete", to: Routes.paste_path(@conn, :delete, paste), method: :delete, data: [confirm: "Are you sure?"] %> +
+ +<%= link "New Paste", to: Routes.paste_path(@conn, :new) %> diff --git a/lib/ketbin_web/templates/paste/new.html.eex b/lib/ketbin_web/templates/paste/new.html.eex new file mode 100644 index 0000000..9e8ab11 --- /dev/null +++ b/lib/ketbin_web/templates/paste/new.html.eex @@ -0,0 +1,5 @@ +

New Paste

+ +<%= render "form.html", Map.put(assigns, :action, Routes.paste_path(@conn, :create)) %> + +<%= link "Back", to: Routes.paste_path(@conn, :index) %> diff --git a/lib/ketbin_web/templates/paste/show.html.eex b/lib/ketbin_web/templates/paste/show.html.eex new file mode 100644 index 0000000..b1cb68d --- /dev/null +++ b/lib/ketbin_web/templates/paste/show.html.eex @@ -0,0 +1,18 @@ +

Show Paste

+ + + +<%= link "Edit", to: Routes.paste_path(@conn, :edit, @paste) %> +<%= link "Back", to: Routes.paste_path(@conn, :index) %> diff --git a/lib/ketbin_web/views/paste_view.ex b/lib/ketbin_web/views/paste_view.ex new file mode 100644 index 0000000..5cfb6d9 --- /dev/null +++ b/lib/ketbin_web/views/paste_view.ex @@ -0,0 +1,3 @@ +defmodule KetbinWeb.PasteView do + use KetbinWeb, :view +end diff --git a/priv/repo/migrations/20210811213141_create_pastes.exs b/priv/repo/migrations/20210811213141_create_pastes.exs new file mode 100644 index 0000000..cd9e076 --- /dev/null +++ b/priv/repo/migrations/20210811213141_create_pastes.exs @@ -0,0 +1,14 @@ +defmodule Ketbin.Repo.Migrations.CreatePastes do + use Ecto.Migration + + def change do + create table(:pastes, primary_key: false) do + add :id, :string, primary_key: true + add :is_url, :boolean, default: false, null: false + add :content, :text, null: false + add :belongs_to, references(:users, on_delete: :delete_all) + end + + create index(:pastes, [:belongs_to]) + end +end diff --git a/test/ketbin/pastes_test.exs b/test/ketbin/pastes_test.exs new file mode 100644 index 0000000..a51b738 --- /dev/null +++ b/test/ketbin/pastes_test.exs @@ -0,0 +1,66 @@ +defmodule Ketbin.PastesTest do + use Ketbin.DataCase + + alias Ketbin.Pastes + + describe "pastes" do + alias Ketbin.Pastes.Paste + + @valid_attrs %{content: "some content", is_url: true} + @update_attrs %{content: "some updated content", is_url: false} + @invalid_attrs %{content: nil, is_url: nil} + + def paste_fixture(attrs \\ %{}) do + {:ok, paste} = + attrs + |> Enum.into(@valid_attrs) + |> Pastes.create_paste() + + paste + end + + test "list_pastes/0 returns all pastes" do + paste = paste_fixture() + assert Pastes.list_pastes() == [paste] + end + + test "get_paste!/1 returns the paste with given id" do + paste = paste_fixture() + assert Pastes.get_paste!(paste.id) == paste + end + + test "create_paste/1 with valid data creates a paste" do + assert {:ok, %Paste{} = paste} = Pastes.create_paste(@valid_attrs) + assert paste.content == "some content" + assert paste.is_url == true + end + + test "create_paste/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Pastes.create_paste(@invalid_attrs) + end + + test "update_paste/2 with valid data updates the paste" do + paste = paste_fixture() + assert {:ok, %Paste{} = paste} = Pastes.update_paste(paste, @update_attrs) + assert paste.content == "some updated content" + assert paste.is_url == false + end + + test "update_paste/2 with invalid data returns error changeset" do + paste = paste_fixture() + assert {:error, %Ecto.Changeset{}} = Pastes.update_paste(paste, @invalid_attrs) + assert paste == Pastes.get_paste!(paste.id) + end + + test "delete_paste/1 deletes the paste" do + paste = paste_fixture() + assert {:ok, %Paste{}} = Pastes.delete_paste(paste) + assert_raise Ecto.NoResultsError, fn -> Pastes.get_paste!(paste.id) end + end + + test "change_paste/1 returns a paste changeset" do + paste = paste_fixture() + assert %Ecto.Changeset{} = Pastes.change_paste(paste) + end + end +end diff --git a/test/ketbin_web/controllers/paste_controller_test.exs b/test/ketbin_web/controllers/paste_controller_test.exs new file mode 100644 index 0000000..06aaf5c --- /dev/null +++ b/test/ketbin_web/controllers/paste_controller_test.exs @@ -0,0 +1,88 @@ +defmodule KetbinWeb.PasteControllerTest do + use KetbinWeb.ConnCase + + alias Ketbin.Pastes + + @create_attrs %{content: "some content", is_url: true} + @update_attrs %{content: "some updated content", is_url: false} + @invalid_attrs %{content: nil, is_url: nil} + + def fixture(:paste) do + {:ok, paste} = Pastes.create_paste(@create_attrs) + paste + end + + describe "index" do + test "lists all pastes", %{conn: conn} do + conn = get(conn, Routes.paste_path(conn, :index)) + assert html_response(conn, 200) =~ "Listing Pastes" + end + end + + describe "new paste" do + test "renders form", %{conn: conn} do + conn = get(conn, Routes.paste_path(conn, :new)) + assert html_response(conn, 200) =~ "New Paste" + end + end + + describe "create paste" do + test "redirects to show when data is valid", %{conn: conn} do + conn = post(conn, Routes.paste_path(conn, :create), paste: @create_attrs) + + assert %{id: id} = redirected_params(conn) + assert redirected_to(conn) == Routes.paste_path(conn, :show, id) + + conn = get(conn, Routes.paste_path(conn, :show, id)) + assert html_response(conn, 200) =~ "Show Paste" + end + + test "renders errors when data is invalid", %{conn: conn} do + conn = post(conn, Routes.paste_path(conn, :create), paste: @invalid_attrs) + assert html_response(conn, 200) =~ "New Paste" + end + end + + describe "edit paste" do + setup [:create_paste] + + test "renders form for editing chosen paste", %{conn: conn, paste: paste} do + conn = get(conn, Routes.paste_path(conn, :edit, paste)) + assert html_response(conn, 200) =~ "Edit Paste" + end + end + + describe "update paste" do + setup [:create_paste] + + test "redirects when data is valid", %{conn: conn, paste: paste} do + conn = put(conn, Routes.paste_path(conn, :update, paste), paste: @update_attrs) + assert redirected_to(conn) == Routes.paste_path(conn, :show, paste) + + conn = get(conn, Routes.paste_path(conn, :show, paste)) + assert html_response(conn, 200) =~ "some updated content" + end + + test "renders errors when data is invalid", %{conn: conn, paste: paste} do + conn = put(conn, Routes.paste_path(conn, :update, paste), paste: @invalid_attrs) + assert html_response(conn, 200) =~ "Edit Paste" + end + end + + describe "delete paste" do + setup [:create_paste] + + test "deletes chosen paste", %{conn: conn, paste: paste} do + conn = delete(conn, Routes.paste_path(conn, :delete, paste)) + assert redirected_to(conn) == Routes.paste_path(conn, :index) + assert_error_sent 404, fn -> + get(conn, Routes.paste_path(conn, :show, paste)) + end + end + end + + defp create_paste(_) do + paste = fixture(:paste) + %{paste: paste} + end +end