fixes #45: add poll administration options

This commit is contained in:
byte[] 2020-04-30 17:24:24 -04:00
parent 7b49f8d978
commit d1783cdeb8
9 changed files with 119 additions and 67 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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,

View file

@ -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...]

View file

@ -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

View file

@ -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

View file

@ -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…")]