diff --git a/lib/frenzy/update_feeds.ex b/lib/frenzy/update_feeds.ex index 1fc40e5..38a3ee8 100644 --- a/lib/frenzy/update_feeds.ex +++ b/lib/frenzy/update_feeds.ex @@ -32,9 +32,9 @@ defmodule Frenzy.UpdateFeeds do defp schedule_update() do # 15 minutes - # Process.send_after(self(), :update_feeds, 15 * 60 * 1000) + Process.send_after(self(), :update_feeds, 15 * 60 * 1000) # 1 minutes - Process.send_after(self(), :update_feeds, 60 * 1000) + # Process.send_after(self(), :update_feeds, 60 * 1000) end defp update_feeds() do diff --git a/lib/frenzy_web/controllers/feed_controller.ex b/lib/frenzy_web/controllers/feed_controller.ex index 9e9cdfa..248fb8e 100644 --- a/lib/frenzy_web/controllers/feed_controller.ex +++ b/lib/frenzy_web/controllers/feed_controller.ex @@ -5,8 +5,28 @@ defmodule FrenzyWeb.FeedController do alias FrenzyWeb.Endpoint import Ecto.Query + plug :user_owns_feed + + defp user_owns_feed(%Plug.Conn{path_params: %{"id" => id}} = conn, _opts) do + user = conn.assigns[:user] + + feed = Repo.get(Feed, id) + + if Enum.any?(user.groups, fn g -> g.id == feed.group_id end) do + conn + |> assign(:feed, feed) + else + conn + |> put_flash(:error, "You do not have permission to access that resource.") + |> redirect(to: Routes.group_path(Endpoint, :index)) + |> halt() + end + end + + defp user_owns_feed(conn, _opts), do: conn + def show(conn, %{"id" => id}) do - feed = Repo.get(Feed, id) |> Repo.preload(:filter) + feed = conn.assigns[:feed] items = Repo.all(from Item, where: [feed_id: ^id, tombstone: false], order_by: [desc: :date]) render(conn, "show.html", %{ @@ -32,28 +52,28 @@ defmodule FrenzyWeb.FeedController do redirect(conn, to: Routes.group_path(Endpoint, :show, group_id)) end - def delete(conn, %{"id" => id}) do - feed = Repo.get(Feed, id) + def delete(conn, _params) do + feed = conn.assigns[:feed] {:ok, _} = Repo.delete(feed) redirect(conn, to: Routes.group_path(Endpoint, :show, feed.group_id)) end - def enable_filter(conn, %{"id" => id}) do - feed = Repo.get(Feed, id) |> Repo.preload(:filter) + def enable_filter(conn, _params) do + feed = conn.assigns[:feed] |> Repo.preload(:filter) changeset = Feed.changeset(feed, %{filter_enabled: true}) Repo.update(changeset) - redirect(conn, to: Routes.feed_path(Endpoint, :show, id)) + redirect(conn, to: Routes.feed_path(Endpoint, :show, feed.id)) end - def disable_filter(conn, %{"id" => id}) do - feed = Repo.get(Feed, id) |> Repo.preload(:filter) + def disable_filter(conn, _params) do + feed = conn.assigns[:feed] |> Repo.preload(:filter) changeset = Feed.changeset(feed, %{filter_enabled: false}) Repo.update(changeset) - redirect(conn, to: Routes.feed_path(Endpoint, :show, id)) + redirect(conn, to: Routes.feed_path(Endpoint, :show, feed.id)) end - def refresh(conn, %{"id" => id}) do - feed = Repo.get(Feed, id) |> Repo.preload(:filter) + def refresh(conn, _params) do + feed = conn.assgins[:feed] |> Repo.preload(:filter) feed = Frenzy.UpdateFeeds.refresh(Frenzy.UpdateFeeds, feed) redirect(conn, to: Routes.feed_path(Endpoint, :show, feed.id)) end diff --git a/lib/frenzy_web/controllers/group_controller.ex b/lib/frenzy_web/controllers/group_controller.ex index 2d3603d..2a71237 100644 --- a/lib/frenzy_web/controllers/group_controller.ex +++ b/lib/frenzy_web/controllers/group_controller.ex @@ -3,20 +3,39 @@ defmodule FrenzyWeb.GroupController do alias Frenzy.{Repo, Group, Feed} alias FrenzyWeb.Router.Helpers, as: Routes alias FrenzyWeb.Endpoint - import Ecto.Query + + plug :user_owns_group + + defp user_owns_group(%Plug.Conn{path_params: %{"id" => id}} = conn, _opts) do + user = conn.assigns[:user] + + group = Repo.get(Group, id) + + if Enum.any?(user.groups, fn g -> g.id == group.id end) do + conn + |> assign(:group, group) + else + conn + |> put_flash(:error, "You do not have permission to acess that resource.") + |> redirect(to: Routes.group_path(Endpoint, :index)) + |> halt() + end + end + + defp user_owns_group(conn, _opts), do: conn def index(conn, _params) do - groups = Repo.all(from group in Group, preload: [:feeds]) + groups = conn.assigns[:user].groups render(conn, "index.html", groups: groups) end - def show(conn, %{"id" => id}) do - group = Repo.get(Group, id) |> Repo.preload(:feeds) + def show(conn, _params) do + group = conn.assigns[:group] |> Repo.preload(:feeds) create_feed_changeset = Feed.changeset( %Feed{ - group_id: id + group_id: group.id }, %{} ) @@ -34,15 +53,21 @@ defmodule FrenzyWeb.GroupController do end def create(conn, %{"group" => %{"title" => title}}) do - changeset = Group.changeset(%Group{title: title}, %{}) + user = conn.assigns[:user] + + changeset = + Ecto.build_assoc(user, :groups, %{ + title: title + }) {:ok, group} = Repo.insert(changeset) - redirect(conn, to: Routes.group_path(Endpoint, :index)) + redirect(conn, to: Routes.group_path(Endpoint, :show, group.id)) end - def delete(conn, %{"id" => id}) do - group = Repo.get(Group, id) + def delete(conn, _params) do + group = conn.assigns[:group] + {:ok, _} = Repo.delete(group) redirect(conn, to: Routes.group_path(Endpoint, :index)) end diff --git a/lib/frenzy_web/controllers/item_controller.ex b/lib/frenzy_web/controllers/item_controller.ex index 281fd6c..7b95479 100644 --- a/lib/frenzy_web/controllers/item_controller.ex +++ b/lib/frenzy_web/controllers/item_controller.ex @@ -4,33 +4,60 @@ defmodule FrenzyWeb.ItemController do alias FrenzyWeb.Router.Helpers, as: Routes alias FrenzyWeb.Endpoint - def show(conn, %{"id" => id}) do + plug :user_owns_item + + defp user_owns_item(%Plug.Conn{path_params: %{"id" => id}} = conn, _opts) do + user = conn.assigns[:user] + item = Repo.get(Item, id) - feed = Repo.get(Feed, item.feed_id) + + feeds = Enum.flat_map(user.groups, fn g -> g.feeds end) + + if Enum.any?(feeds, fn f -> f.id == item.feed_id end) do + conn + |> assign(:item, item) + else + conn + |> put_flash(:error, "You do not have permission to access that resource.") + |> redirect(to: Routes.group_path(Endpoint, :index)) + |> halt() + end + end + + defp user_owns_item(conn, _opts), do: conn + + def show(conn, _params) do + item = conn.assigns[:item] |> Repo.preload(:feed) + render(conn, "show.html", %{ item: item, - feed: feed - }) + feed: item.feed + }) end - def read(conn, %{"id" => id}) do - item = Repo.get(Item, id) |> Repo.preload(:feed) - changeset = Item.changeset(item, %{ - read: true, - read_date: Timex.now + def read(conn, _params) do + item = conn.assigns[:item] |> Repo.preload(:feed) + + changeset = + Item.changeset(item, %{ + read: true, + read_date: Timex.now() }) + Repo.update(changeset) - redirect(conn, to: Routes.item_path(Endpoint, :show, id)) + redirect(conn, to: Routes.item_path(Endpoint, :show, item.id)) end - def unread(conn, %{"id" => id}) do - item = Repo.get(Item, id) |> Repo.preload(:feed) - changeset = Item.changeset(item, %{ - read: false, - read_date: nil + def unread(conn, _params) do + item = conn.assigns[:item] |> Repo.preload(:feed) + + changeset = + Item.changeset(item, %{ + read: false, + read_date: nil }) - Repo.update(changeset) - redirect(conn, to: Routes.item_path(Endpoint, :show, id)) - end -end \ No newline at end of file + Repo.update(changeset) + redirect(conn, to: Routes.item_path(Endpoint, :show, item.id)) + end +end diff --git a/lib/frenzy_web/controllers/login_controller.ex b/lib/frenzy_web/controllers/login_controller.ex new file mode 100644 index 0000000..a201f96 --- /dev/null +++ b/lib/frenzy_web/controllers/login_controller.ex @@ -0,0 +1,31 @@ +defmodule FrenzyWeb.LoginController do + use FrenzyWeb, :controller + alias Frenzy.{Repo, User} + alias FrenzyWeb.Router.Helpers, as: Routes + alias FrenzyWeb.Endpoint + import Ecto.Query + + def login(conn, _params) do + render(conn, "login.html") + end + + @error_message "Invalid username or password" + + def login_post(conn, %{"username" => username, "password" => password}) do + user = Repo.get_by(User, username: username) + + case Bcrypt.check_pass(user, password) do + {:ok, user} -> + user_token = Phoenix.Token.sign(Endpoint, "user token", user.id) + + conn + |> put_session(:user_token, user_token) + |> redirect(to: Routes.group_path(Endpoint, :index)) + + {:error, _reason} -> + conn + |> put_flash(:error, @error_message) + |> redirect(to: Routes.login_path(Endpoint, :login)) + end + end +end diff --git a/lib/frenzy_web/plug/authenticate.ex b/lib/frenzy_web/plug/authenticate.ex new file mode 100644 index 0000000..db1f90b --- /dev/null +++ b/lib/frenzy_web/plug/authenticate.ex @@ -0,0 +1,31 @@ +defmodule FrenzyWeb.Plug.Authenticate do + import Plug.Conn + alias Frenzy.{Repo, User} + alias FrenzyWeb.Router.Helpers, as: Routes + alias FrenzyWeb.Endpoint + + def init(opts), do: opts + + def call(conn, _opts) do + user_token = get_session(conn, :user_token) + + case Phoenix.Token.verify(Endpoint, "user token", user_token, max_age: 24 * 60 * 60) do + {:error, _reason} -> + conn + |> Phoenix.Controller.redirect(to: Routes.login_path(Endpoint, :login)) + |> halt() + + {:ok, user_id} -> + case Repo.get(User, user_id) do + nil -> + conn + |> Phoenix.Controller.redirect(to: Routes.login_path(Endpoint, :login)) + |> halt() + + user -> + user = Repo.preload(user, groups: [:feeds]) + assign(conn, :user, user) + end + end + end +end diff --git a/lib/frenzy_web/router.ex b/lib/frenzy_web/router.ex index 6b91517..d9d7d14 100644 --- a/lib/frenzy_web/router.ex +++ b/lib/frenzy_web/router.ex @@ -7,7 +7,15 @@ defmodule FrenzyWeb.Router do plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers - plug BasicAuth, use_config: {:frenzy, :auth} + end + + pipeline :authenticate do + # plug :accepts, ["html"] + # plug :fetch_session + # plug :fetch_flash + # plug :protect_from_forgery + # plug :put_secure_browser_headers + plug FrenzyWeb.Plug.Authenticate end pipeline :api do @@ -17,6 +25,14 @@ defmodule FrenzyWeb.Router do scope "/", FrenzyWeb do pipe_through :browser + get "/login", LoginController, :login + post "/login", LoginController, :login_post + end + + scope "/", FrenzyWeb do + pipe_through :browser + pipe_through :authenticate + get "/", GroupController, :index resources "/groups", GroupController, except: [:edit, :update] diff --git a/lib/frenzy_web/templates/login/login.html.eex b/lib/frenzy_web/templates/login/login.html.eex new file mode 100644 index 0000000..3c61165 --- /dev/null +++ b/lib/frenzy_web/templates/login/login.html.eex @@ -0,0 +1,15 @@ +<% IO.inspect(get_flash(@conn, :error)) %> + +<%= form_tag Routes.login_path(@conn, :login_post), method: :post do %> +
+ + +
+
+ + +
+
+ <%= submit "Log In" %> +
+<% end %> \ No newline at end of file diff --git a/lib/frenzy_web/views/login_view.ex b/lib/frenzy_web/views/login_view.ex new file mode 100644 index 0000000..0cd4d3f --- /dev/null +++ b/lib/frenzy_web/views/login_view.ex @@ -0,0 +1,3 @@ +defmodule FrenzyWeb.LoginView do + use FrenzyWeb, :view +end diff --git a/mix.exs b/mix.exs index 8f70354..71b970d 100644 --- a/mix.exs +++ b/mix.exs @@ -47,7 +47,6 @@ defmodule Frenzy.MixProject do {:fiet, git: "https://github.com/shadowfacts/fiet.git", branch: "master"}, {:timex, "~> 3.0"}, {:readability, git: "https://github.com/shadowfacts/readability.git", branch: "master"}, - {:basic_auth, "~> 2.2.2"}, {:bcrypt_elixir, "~> 2.0"} ] end