diff --git a/lib/philomena/users/ability.ex b/lib/philomena/users/ability.ex index 810984e0..ad234af3 100644 --- a/lib/philomena/users/ability.ex +++ b/lib/philomena/users/ability.ex @@ -3,6 +3,7 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do alias Philomena.Images.Image alias Philomena.Forums.Forum alias Philomena.Topics.Topic + alias Philomena.Filters.Filter # Admins can do anything def can?(%User{role: "admin"}, _action, _model), do: true @@ -11,6 +12,9 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do # Moderators can... # + # View filters + def can?(%User{role: "moderator"}, :show, %Filter{}), do: true + # View images def can?(%User{role: "moderator"}, :show, %Image{}), do: true @@ -35,6 +39,10 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do # Users and anonymous users can... # + # View filters they own and system filters + def can?(_user, :show, %Filter{system: true}), do: true + def can?(%User{id: id}, :show, %Filter{user_id: id}), do: true + # View non-deleted images def can?(_user, action, Image) when action in [:new, :create, :index], diff --git a/lib/philomena_web/controllers/filter/current_controller.ex b/lib/philomena_web/controllers/filter/current_controller.ex new file mode 100644 index 00000000..82f6b1e6 --- /dev/null +++ b/lib/philomena_web/controllers/filter/current_controller.ex @@ -0,0 +1,31 @@ +defmodule PhilomenaWeb.Filter.CurrentController do + use PhilomenaWeb, :controller + + alias Philomena.{Filters, Filters.Filter} + + plug :load_resource, model: Filter + + def update(conn, _params) do + filter = conn.assigns.filter + user = conn.assigns.current_user + + filter = + if Canada.Can.can?(user, :show, filter) do + filter + else + Filters.default_filter() + end + + conn = + if user do + nil + else + conn + |> put_session(:filter_id, filter.id) + end + + conn + |> put_flash(:info, "Switched to filter #{filter.name}") + |> redirect(to: "/") + end +end diff --git a/lib/philomena_web/controllers/filter_controller.ex b/lib/philomena_web/controllers/filter_controller.ex new file mode 100644 index 00000000..9f1f15a8 --- /dev/null +++ b/lib/philomena_web/controllers/filter_controller.ex @@ -0,0 +1,29 @@ +defmodule PhilomenaWeb.FilterController do + use PhilomenaWeb, :controller + + alias Philomena.Filters.Filter + alias Philomena.Repo + import Ecto.Query + + def index(conn, _params) do + user = conn.assigns.current_user + + my_filters = + if user do + Filter + |> where(user_id: ^user.id) + |> preload(:user) + |> Repo.all() + else + [] + end + + system_filters = + Filter + |> where(system: true) + |> preload(:user) + |> Repo.all() + + render(conn, "index.html", my_filters: my_filters, system_filters: system_filters) + end +end diff --git a/lib/philomena_web/plugs/current_filter.ex b/lib/philomena_web/plugs/current_filter.ex index 645db57d..f26fb1c0 100644 --- a/lib/philomena_web/plugs/current_filter.ex +++ b/lib/philomena_web/plugs/current_filter.ex @@ -2,7 +2,8 @@ defmodule PhilomenaWeb.Plugs.CurrentFilter do import Plug.Conn import Ecto.Query - alias Philomena.Filters + alias Philomena.{Filters, Filters.Filter} + alias Philomena.Repo alias Pow.Plug # No options @@ -10,6 +11,7 @@ defmodule PhilomenaWeb.Plugs.CurrentFilter do # Assign current filter def call(conn, _opts) do + conn = conn |> fetch_session() user = conn |> Plug.current_user() filter = @@ -17,7 +19,11 @@ defmodule PhilomenaWeb.Plugs.CurrentFilter do user = user |> preload(:current_filter) user.current_filter else - Filters.default_filter() + filter_id = conn |> get_session(:filter_id) + + filter = if filter_id, do: Repo.get(Filter, filter_id) + + filter = filter || Filters.default_filter() end conn diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index ff4cb4bd..2cbeba00 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -35,6 +35,11 @@ defmodule PhilomenaWeb.Router do resources "/topics", TopicController, only: [:show] end + scope "/filters", Filter, as: :filter do + resources "/current", CurrentController, only: [:update], singular: true + end + resources "/filters", FilterController, only: [:index, :show] + get "/:id", ImageController, :show end diff --git a/lib/philomena_web/templates/filter/_filter.html.slime b/lib/philomena_web/templates/filter/_filter.html.slime new file mode 100644 index 00000000..b4a9583b --- /dev/null +++ b/lib/philomena_web/templates/filter/_filter.html.slime @@ -0,0 +1,38 @@ +.filter + h3 + = @filter.name + + = if @filter.user do + p + ' Maintained by + = render PhilomenaWeb.UserAttributionView, "_user.html", object: @filter + ' . + + .filter-options + ul + li + ' Spoilers + = length(@filter.spoilered_tag_ids) + ' , hides + = length(@filter.hidden_tag_ids) + + li + = link("View this filter", to: Routes.filter_path(@conn, :show, @filter), class: "button") + + = if @filter.id == @conn.assigns.current_filter.id do + li + strong Your current filter + - else + li + = form_for nil, Routes.filter_current_path(@conn, :update, @filter), [method: "put", class: "button_to"], fn f -> + = submit "Use this filter", class: "button" + + /- if can?(:edit, filter) && current_user && filter.user_id == current_user.id + / li = link_to 'Edit this filter', edit_filter_path(filter), class: 'button' + / - if can?(:delete, filter) && current_user && filter.user_id == current_user.id + / li = button_to 'Delete this filter', filter_path(filter), data: { confirm: 'Are you sure you want to delete this filter?' }, method: :delete, class: 'button' + /- elsif can? :create, Filter + / li = link_to 'Copy and Customize this filter', new_filter_path(based_on_filter_id: filter.id), class: 'button' + p + em + = @filter.description diff --git a/lib/philomena_web/templates/filter/index.html.slime b/lib/philomena_web/templates/filter/index.html.slime new file mode 100644 index 00000000..f6b1171c --- /dev/null +++ b/lib/philomena_web/templates/filter/index.html.slime @@ -0,0 +1,40 @@ +.walloftext + .block.block--fixed.block--warning + h2 Content Safety + p + ' By default, content that is safe and suitable for all ages is all you'll see on the site, and how most of our users browse. The default filters focus on art, so filter out things like memes and what some users would consider "spam". + p + ' Filters let you customize what content you see on the site. This means that with the appropriate filter selected, you can access content which is not suitable for everyone, such as sexually explicit, grimdark or gory material. + p + strong + ' By changing away from the default filters, you accept you are legally permitted to view this content in your jurisdiction. If in doubt, stick with the recommended default filters. + h1 Browsing Filters + p + ' Images posted on the site are tagged, allowing you to easily search for content. You can also filter out content you'd rather not see using filters. Filters are sets of tags - spoilered tags and hidden tags. Spoilers are images that show up as thumbnails instead of the image, letting you click through and find out more about an image before deciding to view it or not. Hidden tags will simply hide images. + p + ' There are set of global filters to pick from which cover some common use-cases. + ' If you're logged in you can also customize these filters and make your own, as well as quickly switch (via the menu on every page) between them. + + h2 So how do these work? + p + ' You can select any filter you can see. This will become your + strong + ' active filter + ' and will affect how you see the site. You can edit filters if you own them - you can create a filter from scratch with the link under "My Filters" (if you're logged in, of course) or by clicking "Customize", which will copy an existing filter for you to edit. + p + ' By default all the filters you create are private and only visible by you. You can have as many as you like and switch between them instantly with no limits. You can also create a public filter, which can be seen and used by any user on the site, allowing you to share useful filters with others. + + h2 My Filters + = if @current_user do + /- if can? :create, Filter + / p + / => link_to 'Click here to make a new filter from scratch', new_filter_path + / | or click "Copy and Customize" on a global or shared filter to use as a starting point. + /= render partial: 'filter_list', locals: { filters: @user_filters } + - else + p + ' If you're logged in, you can create and maintain custom filters here. + + h2 Global Filters + = for filter <- @system_filters do + = render PhilomenaWeb.FilterView, "_filter.html", conn: @conn, filter: filter \ No newline at end of file diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index 5f2aedf8..cdd81bea 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -74,7 +74,9 @@ header.header | Logout - else a.header__link.hide-mobile href="/filters" - | Filters + | Filters ( + = @current_filter.name + | ) span.js-burger-links.hide-mobile a.header__link href='/settings/edit' i.fa.fa-fw.fa-cogs.hide-desktop> diff --git a/lib/philomena_web/views/filter_view.ex b/lib/philomena_web/views/filter_view.ex new file mode 100644 index 00000000..eb176d6d --- /dev/null +++ b/lib/philomena_web/views/filter_view.ex @@ -0,0 +1,3 @@ +defmodule PhilomenaWeb.FilterView do + use PhilomenaWeb, :view +end