diff --git a/lib/philomena/polls.ex b/lib/philomena/polls.ex index 0d80a454..fa77ae8c 100644 --- a/lib/philomena/polls.ex +++ b/lib/philomena/polls.ex @@ -51,7 +51,7 @@ defmodule Philomena.Polls do """ def create_poll(attrs \\ %{}) do %Poll{} - |> Poll.changeset(attrs) + |> Poll.update_changeset(attrs) |> Repo.insert() end @@ -69,7 +69,7 @@ defmodule Philomena.Polls do """ def update_poll(%Poll{} = poll, attrs) do poll - |> Poll.changeset(attrs) + |> Poll.update_changeset(attrs) |> Repo.update() end diff --git a/lib/philomena/polls/poll.ex b/lib/philomena/polls/poll.ex index eac14246..cb320431 100644 --- a/lib/philomena/polls/poll.ex +++ b/lib/philomena/polls/poll.ex @@ -5,6 +5,7 @@ defmodule Philomena.Polls.Poll do alias Philomena.Topics.Topic alias Philomena.Users.User alias Philomena.PollOptions.PollOption + alias Philomena.Schema.Time schema "polls" do belongs_to :topic, Topic @@ -27,13 +28,14 @@ defmodule Philomena.Polls.Poll do poll |> cast(attrs, []) |> validate_required([]) + |> Time.propagate_time(:active_until, :until) end @doc false - def creation_changeset(poll, attrs) do + def update_changeset(poll, attrs) do poll |> cast(attrs, [:title, :until, :vote_method]) - |> put_active_until() + |> Time.assign_time(:until, :active_until) |> validate_required([:title, :active_until, :vote_method]) |> validate_length(:title, max: 140, count: :bytes) |> validate_inclusion(:vote_method, ["single", "multiple"]) @@ -47,19 +49,4 @@ defmodule Philomena.Polls.Poll do defp ignore_if_blank(changeset), do: changeset - - defp put_active_until(changeset) do - changeset - |> get_field(:until) - |> RelativeDate.Parser.parse() - |> case do - {:ok, until} -> - changeset - |> change(active_until: until) - - _error -> - changeset - |> add_error(:active_until, "invalid date format") - end - end end diff --git a/lib/philomena/topics/topic.ex b/lib/philomena/topics/topic.ex index d6ce7634..81ac8a30 100644 --- a/lib/philomena/topics/topic.ex +++ b/lib/philomena/topics/topic.ex @@ -58,7 +58,7 @@ defmodule Philomena.Topics.Topic do |> put_slug() |> change(forum: forum, user: attribution[:user]) |> validate_required(:forum) - |> cast_assoc(:poll, with: &Poll.creation_changeset/2) + |> cast_assoc(:poll, with: &Poll.update_changeset/2) |> cast_assoc(:posts, with: {Post, :topic_creation_changeset, [attribution, anonymous?]}) |> validate_length(:posts, is: 1) |> unique_constraint(:slug, name: :index_topics_on_forum_id_and_slug) diff --git a/lib/philomena_web/controllers/topic/poll_controller.ex b/lib/philomena_web/controllers/topic/poll_controller.ex new file mode 100644 index 00000000..030d0b55 --- /dev/null +++ b/lib/philomena_web/controllers/topic/poll_controller.ex @@ -0,0 +1,49 @@ +defmodule PhilomenaWeb.Topic.PollController do + use PhilomenaWeb, :controller + + alias Philomena.Forums.Forum + alias Philomena.Polls + alias Philomena.Repo + + plug :load_and_authorize_resource, + model: Forum, + id_name: "forum_id", + id_field: "short_name", + persisted: true + + plug PhilomenaWeb.LoadTopicPlug + plug PhilomenaWeb.LoadPollPlug + + plug :verify_authorized + plug :preload_options + + def edit(conn, _params) do + changeset = Polls.change_poll(conn.assigns.poll) + render(conn, "edit.html", title: "Editing Poll", changeset: changeset) + end + + def update(conn, %{"poll" => poll_params}) do + case Polls.update_poll(conn.assigns.poll, poll_params) do + {:ok, _poll} -> + conn + |> put_flash(:info, "Poll successfully updated.") + |> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, conn.assigns.topic)) + + {:error, changeset} -> + render(conn, "edit.html", changeset: changeset) + end + end + + defp preload_options(conn, _opts) do + poll = Repo.preload(conn.assigns.poll, :options) + + assign(conn, :poll, poll) + end + + defp verify_authorized(conn, _opts) do + case Canada.Can.can?(conn.assigns.current_user, :hide, conn.assigns.topic) do + true -> conn + _false -> PhilomenaWeb.NotAuthorizedPlug.call(conn) + end + end +end diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index 5accded2..cf8c21bd 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -218,9 +218,9 @@ defmodule PhilomenaWeb.Router do resources "/delete", Topic.Post.DeleteController, only: [:create], singleton: true end - resources "/poll/votes", Topic.Poll.VoteController, - as: :poll_vote, - only: [:index, :create, :delete] + resources "/poll", Topic.PollController, only: [:edit, :update], singleton: true do + resources "/votes", Topic.Poll.VoteController, only: [:index, :create, :delete] + end end resources "/subscription", Forum.SubscriptionController, diff --git a/lib/philomena_web/templates/topic/new.html.slime b/lib/philomena_web/templates/topic/new.html.slime index 6b478460..0e8c6ef5 100644 --- a/lib/philomena_web/templates/topic/new.html.slime +++ b/lib/philomena_web/templates/topic/new.html.slime @@ -36,50 +36,7 @@ input.toggle-box id="add_poll" name="add_poll" type="checkbox" label for="add_poll" Add a poll .toggle-box-container - p - ' Polls may have a maximum of - span.js-max-option-count> 20 - ' options. Leave any options you don't want to use blank. - ' Only registered users will be able to vote. - - .field.field--block - = text_input fp, :title, class: "input input--wide", placeholder: "Poll title", maxlength: 140 - = error_tag fp, :title - - p.fieldlabel - ' End date - - .field.field--block - = text_input fp, :until, class: "input input--wide", placeholder: "2 weeks from now", maxlength: 255 - = error_tag fp, :until - = error_tag fp, :active_until - - p.fieldlabel - ' Specify when the poll should end. Once the poll ends, no more - ' votes can be cast and the final results will be displayed. Good - ' values to try are "1 week from now" and "24 hours from now". Polls - ' must last for at least 24 hours. - - p.fieldlabel - ' Voting method: - - .field.field--block - = select fp, :vote_method, ["-": "", "Single option": :single, "Multiple options": :multiple], class: "input" - = error_tag fp, :vote_method - - = inputs_for fp, :options, fn fo -> - .field.js-poll-option.field--inline.flex--no-wrap.flex--centered - = text_input fo, :label, class: "input flex__grow js-option-label", placeholder: "Option" - = error_tag fo, :label - - label.input--separate-left.flex__fixed.flex--centered - a.js-option-remove href="#" - i.fa.fa-trash> - ' Delete - - button.button.js-poll-add-option type="button" - i.fa.fa-plus> - ' Add option + = render PhilomenaWeb.Topic.PollView, "_form.html", Map.put(assigns, :f, fp) .block__tab.communication-edit__tab.hidden data-tab="preview" ' [Loading preview...] diff --git a/lib/philomena_web/templates/topic/poll/_display.html.slime b/lib/philomena_web/templates/topic/poll/_display.html.slime index 9d655847..08684008 100644 --- a/lib/philomena_web/templates/topic/poll/_display.html.slime +++ b/lib/philomena_web/templates/topic/poll/_display.html.slime @@ -3,6 +3,7 @@ = if can?(@conn, :hide, @topic) do = link "Voters", to: "#", data: [click_tab: "voters", load_tab: Routes.forum_topic_poll_vote_path(@conn, :index, @forum, @topic)] + = link "Administrate", to: "#", data: [click_tab: "administration"] .block__tab data-tab="voting" = cond do @@ -29,3 +30,7 @@ = if can?(@conn, :hide, @topic) do .block__tab.hidden data-tab="voters" p Loading… + .block__tab.hidden data-tab="administration" + a.button.button--state-warning.js-staff-action> href=Routes.forum_topic_poll_path(@conn, :edit, @forum, @topic) + i.fa.fa-edit> + | Edit diff --git a/lib/philomena_web/templates/topic/poll/_form.html.slime b/lib/philomena_web/templates/topic/poll/_form.html.slime new file mode 100644 index 00000000..c1ba66cf --- /dev/null +++ b/lib/philomena_web/templates/topic/poll/_form.html.slime @@ -0,0 +1,44 @@ +p + ' Polls may have a maximum of + span.js-max-option-count> 20 + ' options. Leave any options you don't want to use blank. + ' Only registered users will be able to vote. + +.field.field--block + = text_input @f, :title, class: "input input--wide", placeholder: "Poll title", maxlength: 140 + = error_tag @f, :title + +p.fieldlabel + ' End date + +.field.field--block + = text_input @f, :until, class: "input input--wide", placeholder: "2 weeks from now", maxlength: 255 + = error_tag @f, :until + = error_tag @f, :active_until + +p.fieldlabel + ' Specify when the poll should end. Once the poll ends, no more + ' votes can be cast and the final results will be displayed. Good + ' values to try are "1 week from now" and "24 hours from now". Polls + ' must last for at least 24 hours. + +p.fieldlabel + ' Voting method: + +.field.field--block + = select @f, :vote_method, ["-": "", "Single option": :single, "Multiple options": :multiple], class: "input" + = error_tag @f, :vote_method + += inputs_for @f, :options, fn fo -> + .field.js-poll-option.field--inline.flex--no-wrap.flex--centered + = text_input fo, :label, class: "input flex__grow js-option-label", placeholder: "Option" + = error_tag fo, :label + + label.input--separate-left.flex__fixed.flex--centered + a.js-option-remove href="#" + i.fa.fa-trash> + ' Delete + +button.button.js-poll-add-option type="button" + i.fa.fa-plus> + ' Add option diff --git a/lib/philomena_web/templates/topic/poll/edit.html.slime b/lib/philomena_web/templates/topic/poll/edit.html.slime new file mode 100644 index 00000000..1282a99e --- /dev/null +++ b/lib/philomena_web/templates/topic/poll/edit.html.slime @@ -0,0 +1,10 @@ +h1 Editing Poll + += form_for @changeset, Routes.forum_topic_poll_path(@conn, :update, @forum, @topic), fn f -> + = render PhilomenaWeb.Topic.PollView, "_form.html", f: f + + br + br + + .action + = submit "Save", class: "button", data: [disable_with: raw("Saving…")]