Skip to content

Commit

Permalink
feat: add a description to hold Markdown-flavored content for a `Ba…
Browse files Browse the repository at this point in the history
…llot` (#78)
  • Loading branch information
zorn authored Sep 3, 2024
1 parent d55451a commit 371383a
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 6 deletions.
4 changes: 3 additions & 1 deletion lib/flick/ranked_voting/ballot.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule Flick.RankedVoting.Ballot do
@type t :: %__MODULE__{
id: Ecto.UUID.t(),
question_title: String.t(),
description: String.t() | nil,
url_slug: String.t(),
secret: Ecto.UUID.t(),
possible_answers: String.t(),
Expand All @@ -37,6 +38,7 @@ defmodule Flick.RankedVoting.Ballot do
@foreign_key_type :binary_id
schema "ballots" do
field :question_title, :string
field :description, :string, default: nil
field :url_slug, :string
field :secret, :binary_id, read_after_writes: true
field :possible_answers, :string
Expand All @@ -45,7 +47,7 @@ defmodule Flick.RankedVoting.Ballot do
end

@required_fields [:question_title, :possible_answers, :url_slug]
@optional_fields [:published_at]
@optional_fields [:published_at, :description]

@spec changeset(t() | struct_t(), map()) :: Ecto.Changeset.t(t()) | Ecto.Changeset.t(struct_t())
def changeset(ballot, attrs) do
Expand Down
8 changes: 8 additions & 0 deletions lib/flick_web/live/ballots/editor_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ defmodule FlickWeb.Ballots.EditorLive do
<.simple_form for={@form} phx-change="validate" phx-submit="save">
<.input field={@form[:question_title]} label="Question Title" placeholder="What is for dinner?" />
<.input
field={@form[:description]}
type="textarea"
label="Description (Markdown)"
placeholder="Some context to help people know about the possible answers. "
/>
<.input
field={@form[:possible_answers]}
label="Possible Answers (comma separated)"
Expand Down
6 changes: 5 additions & 1 deletion lib/flick_web/live/ballots/viewer_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,18 @@ defmodule FlickWeb.Ballots.ViewerLive do
<dl>
<dt class="font-bold">Question Title</dt>
<dd id="ballot-question-title" class="pb-4"><%= @ballot.question_title %></dd>
<dt class="font-bold">Description</dt>
<%!-- FIXME: Showing this inline feels wrong.
Revisit how we render this "preview" of the ballot. --%>
<dd id="ballot-description" class="pb-4"><%= @ballot.description %></dd>
<dt class="font-bold">Possible Answers</dt>
<dd id="ballot-possible-answers" class="pb-4"><%= @ballot.possible_answers %></dd>
<dt class="font-bold">URL Slug</dt>
<dd id="ballot-url-slug" class="pb-4"><%= @ballot.url_slug %></dd>
</dl>
<.button :if={RankedVoting.can_update_ballot?(@ballot)} id="edit-ballot-button">
<.link
navigate={~p"/ballot/#{@ballot.url_slug}/#{@ballot.id}/edit"}
navigate={~p"/ballot/#{@ballot.url_slug}/#{@ballot.secret}/edit"}
class="text-white no-underline"
>
Edit Ballot
Expand Down
13 changes: 13 additions & 0 deletions lib/flick_web/live/vote/vote_capture_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ defmodule FlickWeb.Vote.VoteCaptureLive do
<div id="question-title" class="prose">
<h2><%= @ballot.question_title %></h2>
<div>
<%!-- FIXME: Consider the security implications of `raw`. --%>
<%!-- https://github.com/zorn/flick/issues/77 --%>
<%= raw(rendered_description(@ballot.description)) %>
</div>
</div>
<.inputs_for :let={ranked_answer_form} field={@form[:ranked_answers]}>
Expand All @@ -92,6 +98,13 @@ defmodule FlickWeb.Vote.VoteCaptureLive do
"""
end

defp rendered_description(description) when is_binary(description) do
{:ok, html_doc, _deprecation_messages} = Earmark.as_html(description)
html_doc
end

defp rendered_description(_description), do: nil

defp answer_label("vote_ranked_answers_" <> number = _form_id) do
case number do
"0" -> "First Preference"
Expand Down
5 changes: 4 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ defmodule Flick.MixProject do
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},

# For Observability
# For Observability.
{:appsignal_phoenix, "~> 2.3.9"},

# To Render Markdown.
{:earmark, "~> 1.4"},

# Unorganized
{:bandit, "~> 1.2"},
{:dns_cluster, "~> 0.1.1"},
Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"decorator": {:hex, :decorator, "1.4.0", "a57ac32c823ea7e4e67f5af56412d12b33274661bb7640ec7fc882f8d23ac419", [:mix], [], "hexpm", "0a07cedd9083da875c7418dea95b78361197cf2bf3211d743f6f7ce39656597f"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
"earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"},
"ecto": {:hex, :ecto, "3.12.1", "626765f7066589de6fa09e0876a253ff60c3d00870dd3a1cd696e2ba67bfceea", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df0045ab9d87be947228e05a8d153f3e06e0d05ab10c3b3cc557d2f7243d1940"},
"ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule Flick.Repo.Migrations.AddDescriptionToBallots do
use Ecto.Migration

def change do
alter table(:ballots) do
add :description, :text, null: true
end
end
end
23 changes: 20 additions & 3 deletions test/flick/ranked_voting_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Flick.RankedVotingTest do
alias Flick.RankedVoting.Ballot
alias Flick.RankedVoting.RankedAnswer
alias Flick.RankedVoting.Vote
alias Support.Fixtures.BallotFixture

@empty_values ["", nil, " "]

Expand Down Expand Up @@ -45,9 +46,14 @@ defmodule Flick.RankedVotingTest do
end

test "success: `question_title` can be more than 255 characters" do
long_value = String.duplicate("a", 1_000)
assert {:error, changeset} = RankedVoting.create_ballot(%{question_title: long_value})
refute Map.has_key?(errors_on(changeset), :question_title)
long_question_title = String.duplicate("a", 1_000)

valid_ballot_attrs =
BallotFixture.valid_ballot_attributes()
|> Map.put(:question_title, long_question_title)

assert {:ok, ballot} = RankedVoting.create_ballot(valid_ballot_attrs)
assert long_question_title == ballot.question_title
end

test "failure: `question_title` is required" do
Expand Down Expand Up @@ -136,6 +142,17 @@ defmodule Flick.RankedVotingTest do
%Ballot{secret: secret} = ballot_fixture()
assert uuid_string?(secret)
end

test "success: `description` can be more than 255 characters" do
long_description = String.duplicate("a", 1_000)

valid_ballot_attrs =
BallotFixture.valid_ballot_attributes()
|> Map.put(:description, long_description)

assert {:ok, ballot} = RankedVoting.create_ballot(valid_ballot_attrs)
assert long_description == ballot.description
end
end

describe "update_ballot/1" do
Expand Down

0 comments on commit 371383a

Please sign in to comment.