diff --git a/lib/philomena/artist_links.ex b/lib/philomena/artist_links.ex index eeddac65..44097f73 100644 --- a/lib/philomena/artist_links.ex +++ b/lib/philomena/artist_links.ex @@ -165,16 +165,6 @@ defmodule Philomena.ArtistLinks do ArtistLink.changeset(artist_link, %{}) end - def count_artist_links(user) do - if Canada.Can.can?(user, :index, %ArtistLink{}) do - ArtistLink - |> where([ul], ul.aasm_state in ^["unverified", "link_verified", "contacted"]) - |> Repo.aggregate(:count, :id) - else - nil - end - end - defp fetch_tag(name) do Tag |> preload(:aliased_tag) diff --git a/lib/philomena/dnp_entries.ex b/lib/philomena/dnp_entries.ex index 03946710..e0ed8f1e 100644 --- a/lib/philomena/dnp_entries.ex +++ b/lib/philomena/dnp_entries.ex @@ -111,14 +111,4 @@ defmodule Philomena.DnpEntries do def change_dnp_entry(%DnpEntry{} = dnp_entry) do DnpEntry.changeset(dnp_entry, %{}) end - - def count_dnp_entries(user) do - if Canada.Can.can?(user, :index, DnpEntry) do - DnpEntry - |> where([dnp], dnp.aasm_state in ["requested", "claimed", "acknowledged"]) - |> Repo.aggregate(:count, :id) - else - nil - end - end end diff --git a/lib/philomena/duplicate_reports.ex b/lib/philomena/duplicate_reports.ex index 1ba90050..108bb696 100644 --- a/lib/philomena/duplicate_reports.ex +++ b/lib/philomena/duplicate_reports.ex @@ -173,14 +173,4 @@ defmodule Philomena.DuplicateReports do def change_duplicate_report(%DuplicateReport{} = duplicate_report) do DuplicateReport.changeset(duplicate_report, %{}) end - - def count_duplicate_reports(user) do - if Canada.Can.can?(user, :index, DuplicateReport) do - DuplicateReport - |> where(state: "open") - |> Repo.aggregate(:count, :id) - else - nil - end - end end diff --git a/lib/philomena/layouts.ex b/lib/philomena/layouts.ex new file mode 100644 index 00000000..ccf02ced --- /dev/null +++ b/lib/philomena/layouts.ex @@ -0,0 +1,24 @@ +defmodule Philomena.Layouts do + @moduledoc """ + The Layouts context. + """ + + import Ecto.Query, warn: false + alias Philomena.Repo + + alias Philomena.Layouts.Layout + + @doc """ + Gets a single layout. + + ## Examples + + iex> get_layout!() + %Layout{} + + """ + @spec get_layout!() :: Layout.t() + def get_layout! do + Repo.one!(Layout) + end +end diff --git a/lib/philomena/layouts/layout.ex b/lib/philomena/layouts/layout.ex new file mode 100644 index 00000000..450e6d7c --- /dev/null +++ b/lib/philomena/layouts/layout.ex @@ -0,0 +1,18 @@ +defmodule Philomena.Layouts.Layout do + use Ecto.Schema + + alias Philomena.SiteNotices.SiteNotice + alias Philomena.Forums.Forum + + @primary_key false + schema "layouts" do + field :artist_link_count, :integer + field :channel_count, :integer + field :dnp_entry_count, :integer + field :duplicate_report_count, :integer + field :report_count, :integer + + embeds_many :site_notices, SiteNotice + embeds_many :forums, Forum + end +end diff --git a/lib/philomena/reports.ex b/lib/philomena/reports.ex index 904222ca..5fb79789 100644 --- a/lib/philomena/reports.ex +++ b/lib/philomena/reports.ex @@ -165,14 +165,4 @@ defmodule Philomena.Reports do |> Polymorphic.load_polymorphic(reportable: [reportable_id: :reportable_type]) |> Enum.map(&Elasticsearch.index_document(&1, Report)) end - - def count_reports(user) do - if Canada.Can.can?(user, :index, Report) do - Report - |> where(open: true) - |> Repo.aggregate(:count, :id) - else - nil - end - end end diff --git a/lib/philomena_web/plugs/admin_counters_plug.ex b/lib/philomena_web/plugs/admin_counters_plug.ex deleted file mode 100644 index ac9cb938..00000000 --- a/lib/philomena_web/plugs/admin_counters_plug.ex +++ /dev/null @@ -1,48 +0,0 @@ -defmodule PhilomenaWeb.AdminCountersPlug do - @moduledoc """ - This plug stores the counts used by the admin bar. - ## Example - plug PhilomenaWeb.AdminCountersPlug - """ - - alias Philomena.DuplicateReports - alias Philomena.Reports - alias Philomena.ArtistLinks - alias Philomena.DnpEntries - - import Plug.Conn, only: [assign: 3] - - @doc false - @spec init(any()) :: any() - def init(opts), do: opts - - @doc false - @spec call(Plug.Conn.t()) :: Plug.Conn.t() - def call(conn), do: call(conn, nil) - - @doc false - @spec call(Plug.Conn.t(), any()) :: Plug.Conn.t() - def call(conn, _opts) do - user = conn.assigns.current_user - - maybe_assign_admin_metrics(conn, user, staff?(user)) - end - - defp maybe_assign_admin_metrics(conn, _user, false), do: conn - - defp maybe_assign_admin_metrics(conn, user, true) do - duplicate_reports = DuplicateReports.count_duplicate_reports(user) - reports = Reports.count_reports(user) - artist_links = ArtistLinks.count_artist_links(user) - dnps = DnpEntries.count_dnp_entries(user) - - conn - |> assign(:duplicate_report_count, duplicate_reports) - |> assign(:report_count, reports) - |> assign(:artist_link_count, artist_links) - |> assign(:dnp_entry_count, dnps) - end - - defp staff?(%{role: role}) when role in ["assistant", "moderator", "admin"], do: true - defp staff?(_user), do: false -end diff --git a/lib/philomena_web/plugs/channel_plug.ex b/lib/philomena_web/plugs/channel_plug.ex deleted file mode 100644 index d736b241..00000000 --- a/lib/philomena_web/plugs/channel_plug.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule PhilomenaWeb.ChannelPlug do - alias Plug.Conn - alias Philomena.Channels.Channel - alias Philomena.Repo - import Ecto.Query - - def init([]), do: [] - - def call(conn, _opts) do - live_channels = - Channel - |> where(is_live: true) - |> Repo.aggregate(:count, :id) - - conn - |> Conn.assign(:live_channels, live_channels) - end -end diff --git a/lib/philomena_web/plugs/forum_list_plug.ex b/lib/philomena_web/plugs/forum_list_plug.ex deleted file mode 100644 index b74bb762..00000000 --- a/lib/philomena_web/plugs/forum_list_plug.ex +++ /dev/null @@ -1,25 +0,0 @@ -defmodule PhilomenaWeb.ForumListPlug do - alias Plug.Conn - - alias Philomena.Forums.Forum - alias Philomena.Repo - alias Canada.Can - import Ecto.Query - - def init(opts), do: opts - - def call(conn, _opts) do - forums = lookup_visible_forums(conn.assigns.current_user) - - conn - |> Conn.assign(:forums, forums) - end - - # fixme: add caching! - defp lookup_visible_forums(user) do - Forum - |> order_by(asc: :name) - |> Repo.all() - |> Enum.filter(&Can.can?(user, :show, &1)) - end -end diff --git a/lib/philomena_web/plugs/layout_plug.ex b/lib/philomena_web/plugs/layout_plug.ex new file mode 100644 index 00000000..b70c0cd9 --- /dev/null +++ b/lib/philomena_web/plugs/layout_plug.ex @@ -0,0 +1,43 @@ +defmodule PhilomenaWeb.LayoutPlug do + @moduledoc """ + This plug stores the current site-wide layout attributes. + + ## Example + + plug PhilomenaWeb.LayoutPlug + """ + + alias Canada.Can + alias Philomena.Layouts + import Plug.Conn + + @doc false + @spec init(any()) :: any() + def init(opts), do: opts + + @doc false + @spec call(Plug.Conn.t(), any()) :: Plug.Conn.t() + def call(conn, _opts) do + user = conn.assigns.current_user + layout = Layouts.get_layout!() + + conn + |> assign(:artist_link_count, layout.duplicate_report_count) + |> assign(:dnp_entry_count, layout.dnp_entry_count) + |> assign(:duplicate_report_count, layout.duplicate_report_count) + |> assign(:live_channels, layout.channel_count) + |> assign(:report_count, layout.report_count) + |> assign(:forums, visible_forums(user, layout.forums)) + |> assign(:site_notices, site_notices(layout.site_notices)) + end + + defp visible_forums(user, forum_list) do + forum_list + |> Enum.filter(&Can.can?(user, :show, &1)) + |> Enum.sort_by(& &1.name) + end + + defp site_notices(notice_list) do + Enum.sort_by(notice_list, & &1.start_date, Date) + end +end diff --git a/lib/philomena_web/plugs/site_notice_plug.ex b/lib/philomena_web/plugs/site_notice_plug.ex deleted file mode 100644 index 30aaa586..00000000 --- a/lib/philomena_web/plugs/site_notice_plug.ex +++ /dev/null @@ -1,25 +0,0 @@ -defmodule PhilomenaWeb.SiteNoticePlug do - @moduledoc """ - This plug stores the current site-wide notices. - - ## Example - - plug PhilomenaWeb.SiteNoticePlug - """ - - alias Plug.Conn - alias Philomena.SiteNotices - - @doc false - @spec init(any()) :: any() - def init(opts), do: opts - - @doc false - @spec call(Plug.Conn.t(), any()) :: Plug.Conn.t() - def call(conn, _opts) do - notices = SiteNotices.active_site_notices() - - conn - |> Conn.assign(:site_notices, notices) - end -end diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index e0606dc8..82675a8c 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -17,11 +17,8 @@ defmodule PhilomenaWeb.Router do plug PhilomenaWeb.EnsureUserEnabledPlug plug PhilomenaWeb.CurrentBanPlug plug PhilomenaWeb.NotificationCountPlug - plug PhilomenaWeb.SiteNoticePlug - plug PhilomenaWeb.ForumListPlug + plug PhilomenaWeb.LayoutPlug plug PhilomenaWeb.FilterSelectPlug - plug PhilomenaWeb.ChannelPlug - plug PhilomenaWeb.AdminCountersPlug end pipeline :api do diff --git a/priv/repo/migrations/20211108003620_add_layouts.exs b/priv/repo/migrations/20211108003620_add_layouts.exs new file mode 100644 index 00000000..4ec92ad2 --- /dev/null +++ b/priv/repo/migrations/20211108003620_add_layouts.exs @@ -0,0 +1,36 @@ +defmodule Philomena.Repo.Migrations.AddLayouts do + use Ecto.Migration + + def change do + execute( + """ + CREATE VIEW layouts AS + WITH + artist_link_count AS (SELECT COUNT(*) FROM artist_links WHERE aasm_state IN ('unverified', 'link_verified', 'contacted')), + channel_count AS (SELECT COUNT(*) FROM channels WHERE is_live='t'), + duplicate_report_count AS (SELECT COUNT(*) FROM duplicate_reports WHERE state='open'), + dnp_entry_count AS (SELECT COUNT(*) FROM dnp_entries WHERE aasm_state IN ('requested', 'claimed', 'acknowledged')), + report_count AS (SELECT COUNT(*) FROM reports WHERE open='t'), + forums AS (SELECT array_agg(row_to_json(f)) AS array FROM forums f), + site_notices AS (SELECT array_agg(row_to_json(sn)) AS array FROM site_notices sn WHERE start_date <= now() AND finish_date > now()) + SELECT + artist_link_count.count AS artist_link_count, + channel_count.count AS channel_count, + dnp_entry_count.count AS dnp_entry_count, + duplicate_report_count.count AS duplicate_report_count, + report_count.count AS report_count, + forums.array AS forums, + site_notices.array AS site_notices + FROM + artist_link_count, + channel_count, + duplicate_report_count, + dnp_entry_count, + report_count, + forums, + site_notices + """, + "DROP VIEW layouts" + ) + end +end diff --git a/priv/repo/structure.sql b/priv/repo/structure.sql index d80f8bca..6c0efb90 100644 --- a/priv/repo/structure.sql +++ b/priv/repo/structure.sql @@ -984,6 +984,97 @@ CREATE SEQUENCE public.images_id_seq ALTER SEQUENCE public.images_id_seq OWNED BY public.images.id; +-- +-- Name: reports; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.reports ( + id integer NOT NULL, + ip inet NOT NULL, + fingerprint character varying, + user_agent character varying DEFAULT ''::character varying, + referrer character varying DEFAULT ''::character varying, + reason_textile character varying DEFAULT ''::character varying NOT NULL, + state character varying DEFAULT 'open'::character varying NOT NULL, + open boolean DEFAULT true NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + user_id integer, + admin_id integer, + reportable_id integer NOT NULL, + reportable_type character varying NOT NULL, + reason character varying NOT NULL +); + + +-- +-- Name: site_notices; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.site_notices ( + id integer NOT NULL, + title character varying NOT NULL, + text character varying NOT NULL, + link character varying NOT NULL, + link_text character varying NOT NULL, + live boolean DEFAULT false NOT NULL, + start_date timestamp without time zone NOT NULL, + finish_date timestamp without time zone NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + user_id integer NOT NULL +); + + +-- +-- Name: layouts; Type: VIEW; Schema: public; Owner: - +-- + +CREATE VIEW public.layouts AS + WITH artist_link_count AS ( + SELECT count(*) AS count + FROM public.artist_links + WHERE ((artist_links.aasm_state)::text = ANY ((ARRAY['unverified'::character varying, 'link_verified'::character varying, 'contacted'::character varying])::text[])) + ), channel_count AS ( + SELECT count(*) AS count + FROM public.channels + WHERE (channels.is_live = true) + ), duplicate_report_count AS ( + SELECT count(*) AS count + FROM public.duplicate_reports + WHERE ((duplicate_reports.state)::text = 'open'::text) + ), dnp_entry_count AS ( + SELECT count(*) AS count + FROM public.dnp_entries + WHERE ((dnp_entries.aasm_state)::text = ANY ((ARRAY['requested'::character varying, 'claimed'::character varying, 'acknowledged'::character varying])::text[])) + ), report_count AS ( + SELECT count(*) AS count + FROM public.reports + WHERE (reports.open = true) + ), forums AS ( + SELECT array_agg(row_to_json(f.*)) AS "array" + FROM public.forums f + ), site_notices AS ( + SELECT array_agg(row_to_json(sn.*)) AS "array" + FROM public.site_notices sn + WHERE ((sn.start_date <= now()) AND (sn.finish_date > now())) + ) + SELECT artist_link_count.count AS artist_link_count, + channel_count.count AS channel_count, + dnp_entry_count.count AS dnp_entry_count, + duplicate_report_count.count AS duplicate_report_count, + report_count.count AS report_count, + forums."array" AS forums, + site_notices."array" AS site_notices + FROM artist_link_count, + channel_count, + duplicate_report_count, + dnp_entry_count, + report_count, + forums, + site_notices; + + -- -- Name: messages; Type: TABLE; Schema: public; Owner: - -- @@ -1238,29 +1329,6 @@ CREATE SEQUENCE public.posts_id_seq ALTER SEQUENCE public.posts_id_seq OWNED BY public.posts.id; --- --- Name: reports; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.reports ( - id integer NOT NULL, - ip inet NOT NULL, - fingerprint character varying, - user_agent character varying DEFAULT ''::character varying, - referrer character varying DEFAULT ''::character varying, - reason_textile character varying DEFAULT ''::character varying NOT NULL, - state character varying DEFAULT 'open'::character varying NOT NULL, - open boolean DEFAULT true NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, - user_id integer, - admin_id integer, - reportable_id integer NOT NULL, - reportable_type character varying NOT NULL, - reason character varying NOT NULL -); - - -- -- Name: reports_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- @@ -1323,25 +1391,6 @@ CREATE TABLE public.schema_migrations ( ); --- --- Name: site_notices; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.site_notices ( - id integer NOT NULL, - title character varying NOT NULL, - text character varying NOT NULL, - link character varying NOT NULL, - link_text character varying NOT NULL, - live boolean DEFAULT false NOT NULL, - start_date timestamp without time zone NOT NULL, - finish_date timestamp without time zone NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, - user_id integer NOT NULL -); - - -- -- Name: site_notices_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- @@ -4867,3 +4916,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20210912171343); INSERT INTO public."schema_migrations" (version) VALUES (20210917190346); INSERT INTO public."schema_migrations" (version) VALUES (20210921025336); INSERT INTO public."schema_migrations" (version) VALUES (20210929181319); +INSERT INTO public."schema_migrations" (version) VALUES (20211108003620);