Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions priv/repo/migrations/20160815125009_create_preview.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule CodeCorps.Repo.Migrations.CreatePreview do
use Ecto.Migration

def change do
create table(:preview) do
add :markdown, :text, null: false
add :body, :text, null: false

add :user_id, references(:users, on_delete: :nothing)

timestamps()
end
end
end
72 changes: 72 additions & 0 deletions test/controllers/preview_controller_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
defmodule CodeCorps.PreviewControllerTest do
use CodeCorps.ConnCase

alias CodeCorps.Preview

setup do
conn =
%{build_conn | host: "api."}
|> put_req_header("accept", "application/vnd.api+json")
|> put_req_header("content-type", "application/vnd.api+json")

{:ok, conn: conn}
end

test "creates and renders resource, with body containing markdown rendered to html", %{conn: conn} do
conn = post conn, preview_path(conn, :create), %{
"meta" => %{},
"data" => %{"type" => "preview","attributes" => %{markdown: "A **strong** element"}}
}

json =
conn
|> json_response(201)

id =
json["data"]["id"]
|> String.to_integer

assert id

attributes = json["data"]["attributes"]

assert attributes["body"] == "<p>A <strong>strong</strong> element</p>\n"
assert attributes["markdown"] == "A **strong** element"

preview =
Preview
|> Repo.get!(id)

assert preview.body == "<p>A <strong>strong</strong> element</p>\n"
assert preview.markdown == "A **strong** element"
end

test "it assigns current user as owner of preview, if available", %{conn: conn} do
user = insert_user()

path = preview_path(conn, :create)
payload = %{
"meta" => %{},
"data" => %{"type" => "preview", "attributes" => %{markdown: "A **strong** element"}}
}

conn =
conn
|> Guardian.Plug.api_sign_in(user)
|> post(path, payload)

json =
conn
|> json_response(201)

id =
json["data"]["id"]
|> String.to_integer

preview =
Preview
|> Repo.get!(id)

assert preview.user_id == user.id
end
end
24 changes: 24 additions & 0 deletions test/models/preview_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule CodeCorps.PreviewTest do
use CodeCorps.ModelCase

alias CodeCorps.Preview

test "changeset renders body html from markdown" do
changeset = Preview.changeset(%Preview{}, %{markdown: "A **strong** element"}, nil)
assert changeset.valid?
assert changeset |> get_change(:body) == "<p>A <strong>strong</strong> element</p>\n"
end

test "changeset requires markdown change" do
changeset = Preview.changeset(%Preview{}, %{}, nil)
refute changeset.valid?
assert changeset.errors[:markdown] == {"can't be blank", []}
end

test "assings user_id if present" do
user = insert_user
changeset = Preview.changeset(%Preview{}, %{markdown: "A **strong** element"}, user)
assert changeset.valid?
assert Ecto.Changeset.get_change(changeset, :user).data == user
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use put_assoc, so get_change for :user is another Ecto.Changeset, with no changes and the data field populated with the user

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funny typo in the test string.

end
end
31 changes: 31 additions & 0 deletions web/controllers/preview_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
defmodule CodeCorps.PreviewController do
use CodeCorps.Web, :controller

alias CodeCorps.Preview
alias JaSerializer.Params

def create(conn, %{"data" => data = %{"type" => "preview", "attributes" => _project_params}}) do
user =
conn
|> Guardian.Plug.current_resource

changeset = Preview.changeset(%Preview{}, Params.to_attributes(data), user)



case Repo.insert(changeset) do
{:ok, preview} ->
preview =
preview
|> Repo.preload([:user])

conn
|> put_status(:created)
|> render("show.json-api", data: preview)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(CodeCorps.ChangesetView, "error.json-api", changeset: changeset)
end
end
end
43 changes: 43 additions & 0 deletions web/models/preview.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule CodeCorps.Preview do
@moduledoc """
Represents an category on Code Corps, e.g. "Society" and "Technology".
"""

use CodeCorps.Web, :model

schema "preview" do
field :body, :string
field :markdown, :string

belongs_to :user, CodeCorps.User

timestamps()
end

@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}, user) do
struct
|> cast(params, [:markdown])
|> validate_required([:markdown])
|> assign_user(user)
|> render_markdown_to_html
end

defp render_markdown_to_html(changeset = %Ecto.Changeset{changes: %{markdown: markdown}}) do
html =
markdown
|> Earmark.to_html

changeset
|> put_change(:body, html)
end
defp render_markdown_to_html(changeset), do: changeset

defp assign_user(changeset, nil), do: changeset
defp assign_user(changeset, user) do
changeset
|> put_assoc(:user, user)
end
end
2 changes: 2 additions & 0 deletions web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ defmodule CodeCorps.Router do

resources "/projects", ProjectController, except: [:delete]

resources "/previews", PreviewController, only: [:create]

get "/:slug", SluggedRouteController, :show
get "/:slug/projects", ProjectController, :index
get "/:slug/:project_slug", ProjectController, :show
Expand Down
8 changes: 8 additions & 0 deletions web/views/preview_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule CodeCorps.PreviewView do
use CodeCorps.Web, :view
use JaSerializer.PhoenixView

attributes [:markdown, :body, :inserted_at, :updated_at]

has_one :user, serializer: CodeCorps.UserView
end