mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-02-20 04:14:23 +01:00
fixes #45: add poll administration options
This commit is contained in:
parent
7b49f8d978
commit
d1783cdeb8
9 changed files with 119 additions and 67 deletions
|
@ -51,7 +51,7 @@ defmodule Philomena.Polls do
|
||||||
"""
|
"""
|
||||||
def create_poll(attrs \\ %{}) do
|
def create_poll(attrs \\ %{}) do
|
||||||
%Poll{}
|
%Poll{}
|
||||||
|> Poll.changeset(attrs)
|
|> Poll.update_changeset(attrs)
|
||||||
|> Repo.insert()
|
|> Repo.insert()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ defmodule Philomena.Polls do
|
||||||
"""
|
"""
|
||||||
def update_poll(%Poll{} = poll, attrs) do
|
def update_poll(%Poll{} = poll, attrs) do
|
||||||
poll
|
poll
|
||||||
|> Poll.changeset(attrs)
|
|> Poll.update_changeset(attrs)
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ defmodule Philomena.Polls.Poll do
|
||||||
alias Philomena.Topics.Topic
|
alias Philomena.Topics.Topic
|
||||||
alias Philomena.Users.User
|
alias Philomena.Users.User
|
||||||
alias Philomena.PollOptions.PollOption
|
alias Philomena.PollOptions.PollOption
|
||||||
|
alias Philomena.Schema.Time
|
||||||
|
|
||||||
schema "polls" do
|
schema "polls" do
|
||||||
belongs_to :topic, Topic
|
belongs_to :topic, Topic
|
||||||
|
@ -27,13 +28,14 @@ defmodule Philomena.Polls.Poll do
|
||||||
poll
|
poll
|
||||||
|> cast(attrs, [])
|
|> cast(attrs, [])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
|
|> Time.propagate_time(:active_until, :until)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def creation_changeset(poll, attrs) do
|
def update_changeset(poll, attrs) do
|
||||||
poll
|
poll
|
||||||
|> cast(attrs, [:title, :until, :vote_method])
|
|> cast(attrs, [:title, :until, :vote_method])
|
||||||
|> put_active_until()
|
|> Time.assign_time(:until, :active_until)
|
||||||
|> validate_required([:title, :active_until, :vote_method])
|
|> validate_required([:title, :active_until, :vote_method])
|
||||||
|> validate_length(:title, max: 140, count: :bytes)
|
|> validate_length(:title, max: 140, count: :bytes)
|
||||||
|> validate_inclusion(:vote_method, ["single", "multiple"])
|
|> validate_inclusion(:vote_method, ["single", "multiple"])
|
||||||
|
@ -47,19 +49,4 @@ defmodule Philomena.Polls.Poll do
|
||||||
|
|
||||||
defp ignore_if_blank(changeset),
|
defp ignore_if_blank(changeset),
|
||||||
do: 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
|
end
|
||||||
|
|
|
@ -58,7 +58,7 @@ defmodule Philomena.Topics.Topic do
|
||||||
|> put_slug()
|
|> put_slug()
|
||||||
|> change(forum: forum, user: attribution[:user])
|
|> change(forum: forum, user: attribution[:user])
|
||||||
|> validate_required(:forum)
|
|> 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?]})
|
|> cast_assoc(:posts, with: {Post, :topic_creation_changeset, [attribution, anonymous?]})
|
||||||
|> validate_length(:posts, is: 1)
|
|> validate_length(:posts, is: 1)
|
||||||
|> unique_constraint(:slug, name: :index_topics_on_forum_id_and_slug)
|
|> unique_constraint(:slug, name: :index_topics_on_forum_id_and_slug)
|
||||||
|
|
49
lib/philomena_web/controllers/topic/poll_controller.ex
Normal file
49
lib/philomena_web/controllers/topic/poll_controller.ex
Normal 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
|
|
@ -218,9 +218,9 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/delete", Topic.Post.DeleteController, only: [:create], singleton: true
|
resources "/delete", Topic.Post.DeleteController, only: [:create], singleton: true
|
||||||
end
|
end
|
||||||
|
|
||||||
resources "/poll/votes", Topic.Poll.VoteController,
|
resources "/poll", Topic.PollController, only: [:edit, :update], singleton: true do
|
||||||
as: :poll_vote,
|
resources "/votes", Topic.Poll.VoteController, only: [:index, :create, :delete]
|
||||||
only: [:index, :create, :delete]
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources "/subscription", Forum.SubscriptionController,
|
resources "/subscription", Forum.SubscriptionController,
|
||||||
|
|
|
@ -36,50 +36,7 @@
|
||||||
input.toggle-box id="add_poll" name="add_poll" type="checkbox"
|
input.toggle-box id="add_poll" name="add_poll" type="checkbox"
|
||||||
label for="add_poll" Add a poll
|
label for="add_poll" Add a poll
|
||||||
.toggle-box-container
|
.toggle-box-container
|
||||||
p
|
= render PhilomenaWeb.Topic.PollView, "_form.html", Map.put(assigns, :f, fp)
|
||||||
' 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
|
|
||||||
|
|
||||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||||
' [Loading preview...]
|
' [Loading preview...]
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
= if can?(@conn, :hide, @topic) do
|
= 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 "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"
|
.block__tab data-tab="voting"
|
||||||
= cond do
|
= cond do
|
||||||
|
@ -29,3 +30,7 @@
|
||||||
= if can?(@conn, :hide, @topic) do
|
= if can?(@conn, :hide, @topic) do
|
||||||
.block__tab.hidden data-tab="voters"
|
.block__tab.hidden data-tab="voters"
|
||||||
p Loading…
|
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
|
||||||
|
|
44
lib/philomena_web/templates/topic/poll/_form.html.slime
Normal file
44
lib/philomena_web/templates/topic/poll/_form.html.slime
Normal 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
|
10
lib/philomena_web/templates/topic/poll/edit.html.slime
Normal file
10
lib/philomena_web/templates/topic/poll/edit.html.slime
Normal 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…")]
|
Loading…
Reference in a new issue