diff --git a/lib/philomena/topics.ex b/lib/philomena/topics.ex index 524af5fa..649ab174 100644 --- a/lib/philomena/topics.ex +++ b/lib/philomena/topics.ex @@ -252,6 +252,12 @@ defmodule Philomena.Topics do |> Repo.update() end + def update_topic_title(topic, attrs) do + topic + |> Topic.title_changeset(attrs) + |> Repo.update() + end + def clear_notification(_topic, nil), do: nil def clear_notification(topic, user) do diff --git a/lib/philomena/topics/topic.ex b/lib/philomena/topics/topic.ex index 81ac8a30..1dd1b1c4 100644 --- a/lib/philomena/topics/topic.ex +++ b/lib/philomena/topics/topic.ex @@ -111,6 +111,15 @@ defmodule Philomena.Topics.Topic do |> put_change(:deletion_reason, "") end + def title_changeset(topic, attrs) do + topic + |> cast(attrs, [:title]) + |> validate_required([:title]) + |> validate_length(:title, min: 4, max: 96, count: :bytes) + |> put_slug() + |> unique_constraint(:slug, name: :index_topics_on_forum_id_and_slug) + end + def put_slug(changeset) do slug = changeset diff --git a/lib/philomena/users/ability.ex b/lib/philomena/users/ability.ex index ab70daa2..9f3937a7 100644 --- a/lib/philomena/users/ability.ex +++ b/lib/philomena/users/ability.ex @@ -100,6 +100,7 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do # Hide topics def can?(%User{role: "moderator"}, :show, %Topic{}), do: true def can?(%User{role: "moderator"}, :hide, %Topic{}), do: true + def can?(%User{role: "moderator"}, :edit, %Topic{}), do: true def can?(%User{role: "moderator"}, :create_post, %Topic{}), do: true # Edit tags diff --git a/lib/philomena_web/controllers/topic_controller.ex b/lib/philomena_web/controllers/topic_controller.ex index bc092c10..1f86c474 100644 --- a/lib/philomena_web/controllers/topic_controller.ex +++ b/lib/philomena_web/controllers/topic_controller.ex @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.TopicController do plug PhilomenaWeb.UserAttributionPlug when action in [:new, :create] plug PhilomenaWeb.AdvertPlug when action in [:show] - plug PhilomenaWeb.CanaryMapPlug, new: :show, create: :show + plug PhilomenaWeb.CanaryMapPlug, new: :show, create: :show, update: :show plug :load_and_authorize_resource, model: Forum, @@ -21,7 +21,8 @@ defmodule PhilomenaWeb.TopicController do id_field: "short_name", persisted: true - plug PhilomenaWeb.LoadTopicPlug, [param: "id"] when action in [:show] + plug PhilomenaWeb.LoadTopicPlug, [param: "id"] when action in [:show, :update] + plug :verify_authorized when action in [:update] def show(conn, params) do forum = conn.assigns.forum @@ -75,12 +76,15 @@ defmodule PhilomenaWeb.TopicController do %Post{} |> Posts.change_post() + topic_changeset = Topics.change_topic(conn.assigns.topic) + title = "#{topic.title} - #{forum.name} - Forums" render(conn, "show.html", title: title, posts: posts, changeset: changeset, + topic_changeset: topic_changeset, watching: watching, voted: voted ) @@ -118,4 +122,25 @@ defmodule PhilomenaWeb.TopicController do |> redirect(to: Routes.forum_topic_path(conn, :new, forum)) end end + + def update(conn, %{"topic" => topic_params}) do + case Topics.update_topic_title(conn.assigns.topic, topic_params) do + {:ok, topic} -> + conn + |> put_flash(:info, "Successfully updated topic.") + |> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, topic)) + + {:error, _changeset} -> + conn + |> put_flash(:error, "There was an error with your submission. Please try again.") + |> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, conn.assigns.topic)) + end + end + + defp verify_authorized(conn, _opts) do + case Canada.Can.can?(conn.assigns.current_user, :edit, 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 86013338..221c8692 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -212,7 +212,7 @@ defmodule PhilomenaWeb.Router do end resources "/forums", ForumController, only: [] do - resources "/topics", TopicController, only: [:new, :create] do + resources "/topics", TopicController, only: [:new, :create, :update] do resources "/subscription", Topic.SubscriptionController, only: [:create, :delete], singleton: true diff --git a/lib/philomena_web/templates/topic/show.html.slime b/lib/philomena_web/templates/topic/show.html.slime index 859b1b36..fe4101e3 100644 --- a/lib/philomena_web/templates/topic/show.html.slime +++ b/lib/philomena_web/templates/topic/show.html.slime @@ -108,18 +108,6 @@ h1 = @topic.title .toggle-box-container__content p = if not @topic.hidden_from_users do - = if @topic.locked_at do - = link(to: Routes.forum_topic_lock_path(@conn, :delete, @forum, @topic), method: :delete, class: "button") do - i.fas.fa-unlock> - ' Unlock - - - else - = form_for :topic, Routes.forum_topic_lock_path(@conn, :create, @forum, @topic), [method: :post, class: "hform"], fn f -> - = text_input f, :lock_reason, class: "input hform__text", placeholder: "Lock reason", required: true - = submit class: "hform__button button" do - i.fas.fa-lock> - ' Lock - = if @topic.sticky do = link(to: Routes.forum_topic_stick_path(@conn, :delete, @forum, @topic), method: :delete, class: "button") do i.fas.fa-thumbtack> @@ -130,6 +118,26 @@ h1 = @topic.title i.fas.fa-thumbtack> ' Stick + = if @topic.locked_at do + = link(to: Routes.forum_topic_lock_path(@conn, :delete, @forum, @topic), method: :delete, class: "button") do + i.fas.fa-unlock> + ' Unlock + + - else + = form_for :topic, Routes.forum_topic_lock_path(@conn, :create, @forum, @topic), [method: :post, class: "hform"], fn f -> + .field + = text_input f, :lock_reason, class: "input hform__text", placeholder: "Lock reason", required: true + = submit class: "hform__button button" do + i.fas.fa-lock> + ' Lock + + = form_for @topic_changeset, Routes.forum_topic_path(@conn, :update, @forum, @topic), [method: :put, class: "hform"], fn f -> + .field + = text_input f, :title, class: "input hform__text", placeholder: "New Title" + = submit class: "hform__button button" do + i.fas.fa-pen> + ' Set Title + = form_for :topic, Routes.forum_topic_move_path(@conn, :create, @forum, @topic), [method: :post, class: "hform"], fn f -> .field = select f, :target_forum_id, Enum.map(@conn.assigns.forums, &{&1.name, &1.id}), class: "input hform__text"