diff --git a/lib/philomena/filters.ex b/lib/philomena/filters.ex index 81ff15ca..70affae8 100644 --- a/lib/philomena/filters.ex +++ b/lib/philomena/filters.ex @@ -116,4 +116,30 @@ defmodule Philomena.Filters do def change_filter(%Filter{} = filter) do Filter.changeset(filter, %{}) end + + def recent_and_user_filters(user) do + user_filters = + Filter + |> select([f], %{id: f.id, name: f.name, recent: ^"f"}) + |> where(user_id: ^user.id) + |> limit(10) + + recent_filters = + Filter + |> select([f], %{id: f.id, name: f.name, recent: ^"t"}) + |> where([f], f.id in ^user.recent_filter_ids) + |> limit(10) + + union(recent_filters, ^user_filters) + |> Repo.all() + |> Enum.group_by( + fn + %{recent: "t"} -> "Recent Filters" + _user -> "Your Filters" + end, + fn %{id: id, name: name} -> + [key: name, value: id] + end + ) + end end diff --git a/lib/philomena/users.ex b/lib/philomena/users.ex index c2dca60e..6288171a 100644 --- a/lib/philomena/users.ex +++ b/lib/philomena/users.ex @@ -77,6 +77,12 @@ defmodule Philomena.Users do |> Repo.update() end + def update_spoiler_type(%User{} = user, attrs) do + user + |> User.spoiler_type_changeset(attrs) + |> Repo.update() + end + @doc """ Returns an `%Ecto.Changeset{}` for tracking user changes. diff --git a/lib/philomena/users/user.ex b/lib/philomena/users/user.ex index df2e77f4..c0672aed 100644 --- a/lib/philomena/users/user.ex +++ b/lib/philomena/users/user.ex @@ -143,8 +143,19 @@ defmodule Philomena.Users.User do end def filter_changeset(user, filter) do - change(user) + changeset = change(user) + user = changeset.data + + changeset |> put_change(:current_filter_id, filter.id) + |> put_change(:recent_filter_ids, Enum.take([filter.id | user.recent_filter_ids], 10)) + end + + def spoiler_type_changeset(user, attrs) do + user + |> cast(attrs, [:spoiler_type]) + |> validate_required([:spoiler_type]) + |> validate_inclusion(:spoiler_type, ~W(static click hover off)) end def create_totp_secret_changeset(user) do diff --git a/lib/philomena_web/controllers/filter/current_controller.ex b/lib/philomena_web/controllers/filter/current_controller.ex index 45acee2e..646e9161 100644 --- a/lib/philomena_web/controllers/filter/current_controller.ex +++ b/lib/philomena_web/controllers/filter/current_controller.ex @@ -20,7 +20,7 @@ defmodule PhilomenaWeb.Filter.CurrentController do conn |> update_filter(user, filter) |> put_flash(:info, "Switched to filter #{filter.name}") - |> redirect(to: Routes.filter_path(conn, :index)) + |> redirect(external: conn.assigns.referrer) end defp update_filter(conn, nil, filter) do diff --git a/lib/philomena_web/controllers/filter/spoiler_type_controller.ex b/lib/philomena_web/controllers/filter/spoiler_type_controller.ex new file mode 100644 index 00000000..b3d0f9e5 --- /dev/null +++ b/lib/philomena_web/controllers/filter/spoiler_type_controller.ex @@ -0,0 +1,21 @@ +defmodule PhilomenaWeb.Filter.SpoilerTypeController do + use PhilomenaWeb, :controller + + alias Philomena.Users + + plug PhilomenaWeb.RequireUserPlug + + def update(conn, %{"user" => user_params}) do + case Users.update_spoiler_type(conn.assigns.current_user, user_params) do + {:ok, user} -> + conn + |> put_flash(:info, "Changed spoiler type to #{user.spoiler_type}") + |> redirect(external: conn.assigns.referrer) + + {:error, _changeset} -> + conn + |> put_flash(:error, "Failed to set spoiler type") + |> redirect(external: conn.assigns.referrer) + end + end +end \ No newline at end of file diff --git a/lib/philomena_web/plugs/filter_select_plug.ex b/lib/philomena_web/plugs/filter_select_plug.ex new file mode 100644 index 00000000..64471837 --- /dev/null +++ b/lib/philomena_web/plugs/filter_select_plug.ex @@ -0,0 +1,47 @@ +defmodule PhilomenaWeb.FilterSelectPlug do + @moduledoc """ + This plug sets up the filter menu for the layout if there is a + user currently signed in. + + ## Example + + plug PhilomenaWeb.FilterSelectPlug + """ + + alias Philomena.Filters + alias Philomena.Users + alias Plug.Conn + + @spoiler_types %{ + "Spoilers" => [ + static: "static", + click: "click", + hover: "hover", + off: "off" + ] + } + + @doc false + @spec init(any()) :: any() + def init(opts), do: opts + + @doc false + @spec call(Conn.t(), any()) :: Conn.t() + def call(conn, _opts) do + user = Pow.Plug.current_user(conn) + + conn + |> maybe_assign_filters(user) + end + + defp maybe_assign_filters(conn, nil), do: conn + defp maybe_assign_filters(conn, user) do + filters = Filters.recent_and_user_filters(user) + user = Users.change_user(user) + + conn + |> Conn.assign(:user_changeset, user) + |> Conn.assign(:available_filters, filters) + |> Conn.assign(:spoiler_types, @spoiler_types) + end +end \ No newline at end of file diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index e1c181a9..0faaf97b 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -15,6 +15,7 @@ defmodule PhilomenaWeb.Router do plug PhilomenaWeb.EnsureUserEnabledPlug plug PhilomenaWeb.CurrentBanPlug plug PhilomenaWeb.NotificationCountPlug + plug PhilomenaWeb.FilterSelectPlug end pipeline :api do @@ -67,6 +68,10 @@ defmodule PhilomenaWeb.Router do resources "/subscription", Topic.SubscriptionController, only: [:create, :delete], singleton: true end end + + scope "/filters", Filter, as: :filter do + resources "/spoiler_type", SpoilerTypeController, only: [:update], singleton: true + end end scope "/", PhilomenaWeb do diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index 2f2197f4..16540fe1 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -43,6 +43,13 @@ header.header a.header__link.hide-mobile href="/filters" title="Filters" i.fa.fa-filter span.hide-limited-desktop< Filters + + = form_for @conn.assigns.user_changeset, Routes.filter_current_path(@conn, :update), [class: "header__filter-form", id: "filter-quick-form"], fn f -> + = select f, :current_filter_id, @conn.assigns.available_filters, name: "id", id: "filter-quick-menu", class: "input header__input", data: [change_submit: "#filter-quick-form"], autocomplete: "off" + + = form_for @conn.assigns.user_changeset, Routes.filter_spoiler_type_path(@conn, :update), [class: "header__filter-form hide-mobile hide-limited-desktop", id: "spoiler-quick-form"], fn f -> + = select f, :spoiler_type, @conn.assigns.spoiler_types, id: "spoiler-quick-menu", class: "input header__input", data: [change_submit: "#spoiler-quick-form"], autocomplete: "off" + .dropdown.header__dropdown a.header__link.header__link-user href="/" = render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: %{user: @current_user}, class: "avatar--28px"