From c90f2d48e27f8591c9f2af00cc9ab9b12d752693 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 10 Mar 2019 19:47:01 -0400 Subject: [PATCH] Add filter web UI --- lib/frenzy/feed.ex | 5 ++- lib/frenzy/filter.ex | 22 +++++++++ lib/frenzy/rule.ex | 22 +++++++++ lib/frenzy/update_feeds.ex | 3 +- lib/frenzy_web/controllers/feed_controller.ex | 45 +++++++++++++++---- .../controllers/filter_controller.ex | 36 +++++++++++++++ lib/frenzy_web/router.ex | 6 ++- lib/frenzy_web/templates/feed/show.html.eex | 16 +++++++ lib/frenzy_web/templates/filter/edit.html.eex | 43 ++++++++++++++++++ lib/frenzy_web/views/filter_view.ex | 3 ++ .../20181121001107_create_feeds.exs | 1 - .../20190309150407_create_filters.exs | 16 +++++++ .../20190309151322_feeds_add_filter.exs | 9 ++++ .../20190309185450_create_rules.exs | 15 +++++++ 14 files changed, 229 insertions(+), 13 deletions(-) create mode 100644 lib/frenzy/filter.ex create mode 100644 lib/frenzy/rule.ex create mode 100644 lib/frenzy_web/controllers/filter_controller.ex create mode 100644 lib/frenzy_web/templates/filter/edit.html.eex create mode 100644 lib/frenzy_web/views/filter_view.ex create mode 100644 priv/repo/migrations/20190309150407_create_filters.exs create mode 100644 priv/repo/migrations/20190309151322_feeds_add_filter.exs create mode 100644 priv/repo/migrations/20190309185450_create_rules.exs diff --git a/lib/frenzy/feed.ex b/lib/frenzy/feed.ex index 3d538cc..facd90c 100644 --- a/lib/frenzy/feed.ex +++ b/lib/frenzy/feed.ex @@ -19,8 +19,10 @@ defmodule Frenzy.Feed do field :last_updated, :utc_datetime field :site_url, :string field :title, :string + field :filter_enabled, :boolean has_many :items, Frenzy.Item, on_delete: :delete_all + has_one :filter, Frenzy.Filter, on_delete: :delete_all timestamps() end @@ -28,7 +30,8 @@ defmodule Frenzy.Feed do @doc false def changeset(feed, attrs) do feed - |> cast(attrs, [:title, :feed_url, :site_url, :last_updated]) + |> cast(attrs, [:title, :feed_url, :site_url, :last_updated, :filter_enabled]) + |> cast_assoc(:filter, required: true) |> validate_required([:feed_url]) end end diff --git a/lib/frenzy/filter.ex b/lib/frenzy/filter.ex new file mode 100644 index 0000000..27c53d7 --- /dev/null +++ b/lib/frenzy/filter.ex @@ -0,0 +1,22 @@ +defmodule Frenzy.Filter do + use Ecto.Schema + import Ecto.Changeset + + schema "filters" do + field :mode, :string + field :score, :integer + + belongs_to :feed, Frenzy.Feed + has_many :rules, Frenzy.Rule, on_delete: :delete_all + + timestamps() + end + + @doc false + def changeset(filter, attrs) do + filter + |> cast(attrs, [:mode, :score]) + |> cast_assoc(:rules) + |> validate_required([:mode, :score]) + end +end diff --git a/lib/frenzy/rule.ex b/lib/frenzy/rule.ex new file mode 100644 index 0000000..b303507 --- /dev/null +++ b/lib/frenzy/rule.ex @@ -0,0 +1,22 @@ +defmodule Frenzy.Rule do + use Ecto.Schema + import Ecto.Changeset + + schema "rules" do + field :mode, :string + field :property, :string + field :param, :string + field :weight, :integer + + belongs_to :filter, Frenzy.Filter + + timestamps() + end + + @doc false + def changeset(rule, attrs) do + rule + |> cast(attrs, [:mode, :property, :param, :weight]) + |> validate_required([:mode, :property, :param, :weight]) + end +end diff --git a/lib/frenzy/update_feeds.ex b/lib/frenzy/update_feeds.ex index 8ae9e15..a26bde6 100644 --- a/lib/frenzy/update_feeds.ex +++ b/lib/frenzy/update_feeds.ex @@ -81,6 +81,7 @@ defmodule Frenzy.UpdateFeeds do feed = Repo.preload(feed, :items) Enum.map(rss.items, fn entry -> + # todo: use Repo.exists for this if !Enum.any?(feed.items, fn item -> item.guid == entry.id end) do create_item(feed, entry) end @@ -100,7 +101,7 @@ defmodule Frenzy.UpdateFeeds do {:err, reason} -> Logger.warn("Unable to fetch article for #{url}: #{reason}") - entry.content || entry.summary + entry.description end changeset = diff --git a/lib/frenzy_web/controllers/feed_controller.ex b/lib/frenzy_web/controllers/feed_controller.ex index bbb1ec1..6772ee5 100644 --- a/lib/frenzy_web/controllers/feed_controller.ex +++ b/lib/frenzy_web/controllers/feed_controller.ex @@ -1,34 +1,61 @@ defmodule FrenzyWeb.FeedController do - use FrenzyWeb, :controller - alias Frenzy.{Repo, Feed, Item} + use FrenzyWeb, :controller + alias Frenzy.{Repo, Feed, Filter, Item} alias FrenzyWeb.Router.Helpers, as: Routes alias FrenzyWeb.Endpoint import Ecto.Query - def index(conn, _params) do - render(conn, "index.html", feeds: Repo.all(Feed)) - end + def index(conn, _params) do + render(conn, "index.html", feeds: Repo.all(Feed)) + end def show(conn, %{"id" => id}) do - feed = Repo.get(Feed, id) + feed = Repo.get(Feed, id) |> Repo.preload(:filter) items = Repo.all(from Item, where: [feed_id: ^id], order_by: [desc: :date]) + render(conn, "show.html", %{ feed: feed, items: items - }) + }) end def new(conn, _params) do changeset = Feed.changeset(%Feed{}, %{}) + render(conn, "new.html", changeset: changeset) end def create(conn, %{"feed" => feed}) do - changeset = Feed.changeset(%Feed{}, feed) + changeset = + Feed.changeset( + %Feed{ + filter: %Filter{ + mode: "accept", + score: 0, + rules: [] + } + }, + feed + ) + {:ok, feed} = Repo.insert(changeset) redirect(conn, to: Routes.feed_path(Endpoint, :index)) end + def enable_filter(conn, %{"id" => id}) do + feed = Repo.get(Feed, id) |> Repo.preload(:filter) + changeset = Feed.changeset(feed, %{filter_enabled: true}) + Repo.update(changeset) + redirect(conn, to: Routes.feed_path(Endpoint, :show, id)) + end + + def disable_filter(conn, %{"id" => id}) do + feed = Repo.get(Feed, id) + changeset = Feed.changeset(feed, %{filter_enabled: false}) + Repo.update(changeset) + redirect(conn, to: Routes.feed_path(Endpoint, :show, id)) + end + def delete(conn, %{"id" => id}) do feed = Repo.get(Feed, id) {:ok, _} = Repo.delete(feed) @@ -40,4 +67,4 @@ defmodule FrenzyWeb.FeedController do feed = Frenzy.UpdateFeeds.refresh(Frenzy.UpdateFeeds, feed) redirect(conn, to: Routes.feed_path(Endpoint, :show, feed.id)) end -end \ No newline at end of file +end diff --git a/lib/frenzy_web/controllers/filter_controller.ex b/lib/frenzy_web/controllers/filter_controller.ex new file mode 100644 index 0000000..5ea28e1 --- /dev/null +++ b/lib/frenzy_web/controllers/filter_controller.ex @@ -0,0 +1,36 @@ +defmodule FrenzyWeb.FilterController do + use FrenzyWeb, :controller + alias Frenzy.{Repo, Feed, Filter, Rule} + alias FrenzyWeb.Router.Helpers, as: Routes + alias FrenzyWeb.Endpoint + import Ecto.Query + + def edit(conn, %{"id" => id}) do + filter = Repo.get(Filter, id) |> Repo.preload(:rules) + changeset = Filter.changeset(filter, %{}) + render(conn, "edit.html", changeset: changeset) + end + + def update(conn, %{"id" => id, "filter" => filter_params}) do + filter = Repo.get(Filter, id) |> Repo.preload(:rules) + changeset = Filter.changeset(filter, filter_params) + Repo.update(changeset) + redirect(conn, to: Routes.filter_path(Endpoint, :edit, id)) + end + + def add_rule(conn, %{"id" => id}) do + filter = Repo.get(Filter, id) + + changeset = + Ecto.build_assoc(filter, :rules, %{ + property: "title", + mode: "contains_string", + param: "", + weight: 5 + }) + + Repo.insert(changeset) + + redirect(conn, to: Routes.filter_path(Endpoint, :edit, id)) + end +end diff --git a/lib/frenzy_web/router.ex b/lib/frenzy_web/router.ex index c6bf4a1..9456985 100644 --- a/lib/frenzy_web/router.ex +++ b/lib/frenzy_web/router.ex @@ -12,7 +12,6 @@ defmodule FrenzyWeb.Router do pipeline :api do plug :accepts, ["json"] - end scope "/", FrenzyWeb do @@ -23,6 +22,11 @@ defmodule FrenzyWeb.Router do get "/", FeedController, :index resources "/feeds", FeedController, except: [:edit, :update] post "/feeds/:id/refresh", FeedController, :refresh + post "/feeds/:id/enable_filter", FeedController, :enable_filter + post "/feeds/:id/disable_filter", FeedController, :disable_filter + + resources "/filters", FilterController, only: [:edit, :update] + post "/filters/:id/add_rule", FilterController, :add_rule resources "/items", ItemController, only: [:show] post "/items/:id/read", ItemController, :read diff --git a/lib/frenzy_web/templates/feed/show.html.eex b/lib/frenzy_web/templates/feed/show.html.eex index ca36dc9..cd5635f 100644 --- a/lib/frenzy_web/templates/feed/show.html.eex +++ b/lib/frenzy_web/templates/feed/show.html.eex @@ -2,10 +2,26 @@ <%= submit "Refresh Feed" %> <% end %> + +<%= if @feed.filter_enabled do %> + <%= form_tag Routes.feed_path(@conn, :disable_filter, @feed.id), method: :post do %> + <%= submit "Disable Filter" %> + <% end %> + + <%= form_tag Routes.filter_path(@conn, :edit, @feed.filter.id), method: :get do %> + <%= submit "Edit Filter" %> + <% end %> +<% else %> + <%= form_tag Routes.feed_path(@conn, :enable_filter, @feed.id), method: :post do %> + <%= submit "Enable Filter" %> + <% end %> +<% end %> + <%= form_tag Routes.feed_path(@conn, :delete, @feed.id), method: :delete do %> <%= submit "Delete Feed" %> <% end %> + <%= for item <- @items do %> class="item-read"<% end %>> diff --git a/lib/frenzy_web/templates/filter/edit.html.eex b/lib/frenzy_web/templates/filter/edit.html.eex new file mode 100644 index 0000000..c2ae383 --- /dev/null +++ b/lib/frenzy_web/templates/filter/edit.html.eex @@ -0,0 +1,43 @@ +

Filter

+<%= form_for @changeset, Routes.filter_path(@conn, :update, @changeset.data.id), fn form -> %> +
+ + <%= select form, :mode, [{"Accept", :accept}, {"Reject", :reject}] %> +
+
+ + <%= number_input form, :score %> +
+ +
+ + + + + + + <%= inputs_for form, :rules, fn p -> %> + + + + + + + <% end %> +
PropertyModeParamWeight
+ <%= select p, :property, [{"URL", :url}, {"Title", :title}, {"Author", :author}, {"Content", :content}] %> + + <%= select p, :mode, [{"contains", :contains_string}, {"matches regex", :matches_regex}] %> + + <%= text_input p, :param %> + + <%= number_input p, :weight %> +
+ +
+ <%= submit "Update Filter" %> +
+<% end %> +<%= form_tag Routes.filter_path(@conn, :add_rule, @changeset.data.id), method: :post do %> + <%= submit "Add Rule" %> +<% end %> \ No newline at end of file diff --git a/lib/frenzy_web/views/filter_view.ex b/lib/frenzy_web/views/filter_view.ex new file mode 100644 index 0000000..36a3a84 --- /dev/null +++ b/lib/frenzy_web/views/filter_view.ex @@ -0,0 +1,3 @@ +defmodule FrenzyWeb.FilterView do + use FrenzyWeb, :view +end diff --git a/priv/repo/migrations/20181121001107_create_feeds.exs b/priv/repo/migrations/20181121001107_create_feeds.exs index 63c46d4..609b7b3 100644 --- a/priv/repo/migrations/20181121001107_create_feeds.exs +++ b/priv/repo/migrations/20181121001107_create_feeds.exs @@ -10,6 +10,5 @@ defmodule Frenzy.Repo.Migrations.CreateFeeds do timestamps() end - end end diff --git a/priv/repo/migrations/20190309150407_create_filters.exs b/priv/repo/migrations/20190309150407_create_filters.exs new file mode 100644 index 0000000..513b535 --- /dev/null +++ b/priv/repo/migrations/20190309150407_create_filters.exs @@ -0,0 +1,16 @@ +defmodule Frenzy.Repo.Migrations.CreateRules do + use Ecto.Migration + + def change do + create table(:filters) do + add :mode, :string + add :score, :integer + add :rules, :map + add :feed_id, references(:feeds) + + timestamps() + end + + # create index(:rules, [:filter]) + end +end diff --git a/priv/repo/migrations/20190309151322_feeds_add_filter.exs b/priv/repo/migrations/20190309151322_feeds_add_filter.exs new file mode 100644 index 0000000..dd1516b --- /dev/null +++ b/priv/repo/migrations/20190309151322_feeds_add_filter.exs @@ -0,0 +1,9 @@ +defmodule Frenzy.Repo.Migrations.FeedsAddFilter do + use Ecto.Migration + + def change do + alter table(:feeds) do + add :filter_enabled, :boolean + end + end +end diff --git a/priv/repo/migrations/20190309185450_create_rules.exs b/priv/repo/migrations/20190309185450_create_rules.exs new file mode 100644 index 0000000..d74821e --- /dev/null +++ b/priv/repo/migrations/20190309185450_create_rules.exs @@ -0,0 +1,15 @@ +defmodule Frenzy.Repo.Migrations.CreateRules do + use Ecto.Migration + + def change do + create table(:rules) do + add :mode, :string + add :property, :string + add :param, :string + add :weight, :integer + add :filter_id, references(:filters) + + timestamps() + end + end +end