Compare commits

..

No commits in common. "4e79a1fe19515a3ef1b565b9aa64607d89c4fc9c" and "09d2e4ae72564cca843293181bb3c9f5bfe0cafe" have entirely different histories.

19 changed files with 116 additions and 329 deletions

View File

@ -36,8 +36,6 @@ defmodule Frenzy.Feed do
field :title, :string field :title, :string
field :favicon, :string field :favicon, :string
field :favicon_url, :string field :favicon_url, :string
field :last_refreshed_at, :utc_datetime
field :refresh_frequency, :integer, default: 30
belongs_to :group, Frenzy.Group belongs_to :group, Frenzy.Group
belongs_to :pipeline, Frenzy.Pipeline belongs_to :pipeline, Frenzy.Pipeline
@ -56,8 +54,6 @@ defmodule Frenzy.Feed do
title: String.t() | nil, title: String.t() | nil,
favicon: String.t() | nil, favicon: String.t() | nil,
favicon_url: String.t() | nil, favicon_url: String.t() | nil,
last_refreshed_at: DateTime.t() | nil,
refresh_frequency: integer(),
group: Frenzy.Group.t() | Ecto.Association.NotLoaded.t(), group: Frenzy.Group.t() | Ecto.Association.NotLoaded.t(),
pipeline: Frenzy.Pipeline.t() | nil | Ecto.Association.NotLoaded.t(), pipeline: Frenzy.Pipeline.t() | nil | Ecto.Association.NotLoaded.t(),
items: [Frenzy.Item.t()] | Ecto.Association.NotLoaded.t(), items: [Frenzy.Item.t()] | Ecto.Association.NotLoaded.t(),
@ -75,11 +71,8 @@ defmodule Frenzy.Feed do
:last_updated, :last_updated,
:pipeline_id, :pipeline_id,
:favicon, :favicon,
:favicon_url, :favicon_url
:last_refreshed_at,
:refresh_frequency
]) ])
|> validate_required([:feed_url]) |> validate_required([:feed_url])
|> validate_inclusion(:refresh_frequency, [30 * 60, 60 * 60, 6 * 60 * 60, 24 * 60 * 60])
end end
end end

View File

@ -2,8 +2,8 @@ defmodule Frenzy.HTTP do
require Logger require Logger
@redirect_codes [301, 302] @redirect_codes [301, 302]
def get(url, opts \\ []) do def get(url) do
case HTTPoison.get(url, opts) do case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200} = response} -> {:ok, %HTTPoison.Response{status_code: 200} = response} ->
{:ok, response} {:ok, response}
@ -24,7 +24,7 @@ defmodule Frenzy.HTTP do
end end
Logger.debug("Got 301 redirect from #{url} to #{new_url}") Logger.debug("Got 301 redirect from #{url} to #{new_url}")
get(new_url, opts) get(new_url)
_ -> _ ->
{:error, "Missing Location header for redirect"} {:error, "Missing Location header for redirect"}
@ -43,4 +43,26 @@ defmodule Frenzy.HTTP do
{:error, reason} {:error, reason}
end end
end end
def resolve_uri(uri, site_uri) when is_binary(site_uri) do
resolve_uri(uri, URI.parse(site_uri))
end
def resolve_uri(%URI{host: nil, path: path}, %URI{} = site_uri) do
%URI{site_uri | path: path}
|> resolve_uri(site_uri)
end
def resolve_uri(%URI{scheme: nil} = uri, %URI{scheme: scheme} = site_uri) do
scheme =
case scheme do
nil -> "https"
_ -> scheme
end
%URI{uri | scheme: scheme}
|> resolve_uri(site_uri)
end
def resolve_uri(uri, _), do: uri
end end

View File

@ -1,28 +0,0 @@
defmodule Frenzy.Paginator do
import Ecto.Query
alias Frenzy.{Repo, Item}
@spec paginate(query :: Ecto.Queryable.t(), params :: map()) :: Ecto.Query.t()
def paginate(query, %{"before" => before_id}) do
before = Repo.get(Item, before_id)
query
# |> where([o], o.id < ^before_id)
|> where([i], i.date < ^before.date)
|> order_by(desc: :date)
end
def paginate(query, %{"after" => after_id}) do
after_item = Repo.get(Item, after_id)
query
|> where([i], i.date > ^after_item.date)
|> order_by(asc: :date)
end
def paginate(query, _) do
query
|> order_by(desc: :date)
end
end

View File

@ -18,10 +18,11 @@ defmodule Frenzy.Pipeline.ScrapeStage do
@impl Stage @impl Stage
def validate_opts(opts) when is_map(opts) do def validate_opts(opts) when is_map(opts) do
# todo: figure out why this errors when an empty map is provided
opts = opts =
case opts["extractor"] do case opts["extractor"] do
nil -> nil ->
{:ok, Map.put(opts, "extractor", "builtin")} {:ok, %{opts | extractor: "builtin"}}
extractor when not is_binary(extractor) -> extractor when not is_binary(extractor) ->
{:error, "extractor must be a string"} {:error, "extractor must be a string"}
@ -43,7 +44,7 @@ defmodule Frenzy.Pipeline.ScrapeStage do
{:ok, opts} -> {:ok, opts} ->
case opts["convert_to_data_uris"] do case opts["convert_to_data_uris"] do
nil -> nil ->
{:ok, Map.put(opts, "convert_to_data_uris", true)} {:ok, %{opts | convert_to_data_uris: true}}
value when is_boolean(value) -> value when is_boolean(value) ->
{:ok, opts} {:ok, opts}
@ -60,7 +61,7 @@ defmodule Frenzy.Pipeline.ScrapeStage do
@impl Stage @impl Stage
def validate_opts(_), do: {:error, "options must be a map"} def validate_opts(_), do: {:error, "options must be a map"}
@spec get_article_content(String.t(), map()) :: {:ok, String.t()} | {:error, String.t()} @spec get_article_content(String.t(), String.t()) :: {:ok, String.t()} | {:error, String.t()}
defp get_article_content(url, opts) when is_binary(url) and url != "" do defp get_article_content(url, opts) when is_binary(url) and url != "" do
Logger.debug("Getting article from #{url}") Logger.debug("Getting article from #{url}")
@ -75,9 +76,9 @@ defmodule Frenzy.Pipeline.ScrapeStage do
end end
end end
defp get_article_content(_url, _opts), do: {:error, "URL must be a non-empty string"} defp get_article_content(_url), do: {:error, "URL must be a non-empty string"}
@spec handle_response(String.t(), HTTPoison.Response.t(), map()) :: @spec handle_response(String.t(), HTTPoison.Response.t(), String.t()) ::
{:ok, String.t()} | {:error, String.t()} {:ok, String.t()} | {:error, String.t()}
defp handle_response(url, %HTTPoison.Response{body: body}, opts) do defp handle_response(url, %HTTPoison.Response{body: body}, opts) do
case opts["extractor"] do case opts["extractor"] do
@ -114,7 +115,7 @@ defmodule Frenzy.Pipeline.ScrapeStage do
# Generates a helper function for the article with the given URI that takes an HTML element and, # Generates a helper function for the article with the given URI that takes an HTML element and,
# if it's an <img> element whose src attribute does not have a hostname, adds the hostname and # if it's an <img> element whose src attribute does not have a hostname, adds the hostname and
# scheme to the element. # scheme to the element.
defp rewrite_image_urls(convert_to_data_uris, site_uri) do defp rewrite_image_urls(convert_to_data_uris, %URI{host: host, scheme: scheme} = site_uri) do
fn fn
{"img", attrs} -> {"img", attrs} ->
new_attrs = new_attrs =
@ -137,7 +138,10 @@ defmodule Frenzy.Pipeline.ScrapeStage do
# convert images to data URIs so that they're stored by clients as part of the body # convert images to data URIs so that they're stored by clients as part of the body
defp image_to_data_uri(src, site_uri, true) do defp image_to_data_uri(src, site_uri, true) do
absolute_url = URI.merge(site_uri, src) |> to_string() absolute_url =
src
|> URI.parse()
|> HTTP.resolve_uri(site_uri)
case HTTP.get(absolute_url) do case HTTP.get(absolute_url) do
{:ok, %HTTPoison.Response{body: body, headers: headers}} -> {:ok, %HTTPoison.Response{body: body, headers: headers}} ->

View File

@ -25,12 +25,8 @@ defmodule Frenzy.Task.FetchFavicon do
with %Feed{favicon_url: old_url} when old_url != favicon_url <- feed, with %Feed{favicon_url: old_url} when old_url != favicon_url <- feed,
{:ok, favicon_data} <- fetch_favicon_data(favicon_url) do {:ok, favicon_data} <- fetch_favicon_data(favicon_url) do
changeset = IO.inspect(favicon_url)
Feed.changeset(feed, %{ changeset = Feed.changeset(feed, %{favicon: favicon_data, favicon_url: favicon_url})
favicon: favicon_data,
favicon_url: to_string(favicon_url)
})
{:ok, _feed} = Repo.update(changeset) {:ok, _feed} = Repo.update(changeset)
else else
_ -> _ ->

View File

@ -10,7 +10,7 @@ defmodule Frenzy.UpdateFeeds do
end end
def refresh(pid, feed) do def refresh(pid, feed) do
GenServer.cast(pid, {:refresh, feed}) GenServer.call(pid, {:refresh, feed})
end end
def init(state) do def init(state) do
@ -19,9 +19,10 @@ defmodule Frenzy.UpdateFeeds do
{:ok, state} {:ok, state}
end end
def handle_cast({:refresh, feed}, state) do def handle_call({:refresh, feed}, _from, state) do
update_feed(feed) update_feed(feed)
{:noreply, state} new_feed = Feed |> Repo.get(feed.id) |> Repo.preload(:items)
{:reply, new_feed, state}
end end
def handle_info(:update_feeds, state) do def handle_info(:update_feeds, state) do
@ -40,17 +41,8 @@ defmodule Frenzy.UpdateFeeds do
defp update_feeds() do defp update_feeds() do
Logger.info("Updating all feeds") Logger.info("Updating all feeds")
{_count, feeds} = Repo.all(from(Feed))
Feed |> Enum.map(&update_feed/1)
|> where(
[f],
is_nil(f.last_refreshed_at) or
f.last_refreshed_at <= from_now(-1 * f.refresh_frequency, "second")
)
|> select([f], f)
|> Repo.update_all(set: [last_refreshed_at: DateTime.utc_now()])
Enum.map(feeds, &update_feed/1)
prune_old_items() prune_old_items()
end end
@ -75,7 +67,7 @@ defmodule Frenzy.UpdateFeeds do
defp update_feed(feed) do defp update_feed(feed) do
Logger.debug("Updating #{feed.feed_url}") Logger.debug("Updating #{feed.feed_url}")
case HTTP.get(feed.feed_url) do case HTTPoison.get(feed.feed_url) do
{:ok, {:ok,
%HTTPoison.Response{ %HTTPoison.Response{
status_code: 200, status_code: 200,

View File

@ -1,6 +1,6 @@
defmodule FrenzyWeb.FeedController do defmodule FrenzyWeb.FeedController do
use FrenzyWeb, :controller use FrenzyWeb, :controller
alias Frenzy.{Repo, Group, Feed, Item, Pipeline, Paginator} alias Frenzy.{Repo, Group, Feed, Item, Pipeline}
alias FrenzyWeb.Router.Helpers, as: Routes alias FrenzyWeb.Router.Helpers, as: Routes
alias FrenzyWeb.Endpoint alias FrenzyWeb.Endpoint
import Ecto.Query import Ecto.Query
@ -25,43 +25,13 @@ defmodule FrenzyWeb.FeedController do
defp user_owns_feed(conn, _opts), do: conn defp user_owns_feed(conn, _opts), do: conn
def show(conn, %{"id" => id} = params) do def show(conn, %{"id" => id}) do
feed = conn.assigns[:feed] feed = conn.assigns[:feed]
items = Repo.all(from Item, where: [feed_id: ^id, tombstone: false], order_by: [desc: :date])
items =
Item
|> where([i], i.feed_id == ^id)
|> Paginator.paginate(params)
|> limit(50)
|> Repo.all()
|> Enum.sort_by(fn item -> item.date end, fn a, b ->
DateTime.compare(a, b) == :gt
end)
first_item = List.first(items)
last_item = List.last(items)
prev_page_path =
if !is_nil(first_item) &&
Repo.exists?(from i in Item, where: i.date > ^first_item.date and i.feed_id == ^id) do
current_path(conn, %{after: first_item.id})
else
nil
end
next_page_path =
if !is_nil(last_item) &&
Repo.exists?(from i in Item, where: i.date < ^last_item.date and i.feed_id == ^id) do
current_path(conn, %{before: last_item.id})
else
nil
end
render(conn, "show.html", %{ render(conn, "show.html", %{
feed: feed, feed: feed,
items: items, items: items
next_page_path: next_page_path,
prev_page_path: prev_page_path
}) })
end end
@ -97,24 +67,17 @@ defmodule FrenzyWeb.FeedController do
end end
def edit(conn, _params) do def edit(conn, _params) do
user = conn.assigns[:user]
feed = conn.assigns[:feed] feed = conn.assigns[:feed]
edit_changeset = Feed.changeset(feed, %{}) edit_changeset = Feed.changeset(feed, %{})
pipelines = pipelines =
Repo.all(from p in Pipeline, where: p.user_id == ^user.id) Repo.all(Pipeline)
|> Enum.map(fn pipeline -> {pipeline.name, pipeline.id} end) |> Enum.map(fn pipeline -> {pipeline.name, pipeline.id} end)
render(conn, "edit.html", %{ render(conn, "edit.html", %{
feed: feed, feed: feed,
changeset: edit_changeset, changeset: edit_changeset,
pipelines: [{"No Pipeline", nil} | pipelines], pipelines: [{"No Pipeline", nil} | pipelines]
refresh_frequencies: [
{"Every 30 minutes", 30 * 60},
{"Every hour", 60 * 60},
{"Every 6 hours", 6 * 60 * 60},
{"Every 24 hours", 24 * 60 * 60}
]
}) })
end end
@ -147,7 +110,7 @@ defmodule FrenzyWeb.FeedController do
def refresh(conn, _params) do def refresh(conn, _params) do
feed = conn.assigns[:feed] feed = conn.assigns[:feed]
Frenzy.UpdateFeeds.refresh(Frenzy.UpdateFeeds, feed) feed = Frenzy.UpdateFeeds.refresh(Frenzy.UpdateFeeds, feed)
conn conn
|> put_flash(:info, "Refreshing feed. Wait a moment before reloading...") |> put_flash(:info, "Refreshing feed. Wait a moment before reloading...")

View File

@ -1,9 +1,8 @@
defmodule FrenzyWeb.GroupController do defmodule FrenzyWeb.GroupController do
use FrenzyWeb, :controller use FrenzyWeb, :controller
alias Frenzy.{Repo, Group, Feed, Item, Paginator} alias Frenzy.{Repo, Group, Feed}
alias FrenzyWeb.Router.Helpers, as: Routes alias FrenzyWeb.Router.Helpers, as: Routes
alias FrenzyWeb.Endpoint alias FrenzyWeb.Endpoint
import Ecto.Query
plug :user_owns_group plug :user_owns_group
@ -73,73 +72,10 @@ defmodule FrenzyWeb.GroupController do
end end
end end
def edit(conn, _params) do
group = conn.assigns[:group]
edit_changeset = Group.changeset(group, %{})
render(conn, "edit.html", %{
group: group,
changeset: edit_changeset
})
end
def update(conn, %{"group" => group_params}) do
group = conn.assigns[:group]
changeset = Group.changeset(group, group_params)
{:ok, group} = Repo.update(changeset)
redirect(conn, to: Routes.group_path(Endpoint, :show, group.id))
end
def delete(conn, _params) do def delete(conn, _params) do
group = conn.assigns[:group] group = conn.assigns[:group]
{:ok, _} = Repo.delete(group) {:ok, _} = Repo.delete(group)
redirect(conn, to: Routes.group_path(Endpoint, :index)) redirect(conn, to: Routes.group_path(Endpoint, :index))
end end
def read(conn, params) do
group = conn.assigns[:group] |> Repo.preload(:feeds)
feed_ids = Enum.map(group.feeds, fn feed -> feed.id end)
items =
Item
|> where([i], i.feed_id in ^feed_ids)
|> Paginator.paginate(params)
|> limit(50)
|> preload(:feed)
|> Repo.all()
|> Enum.sort_by(fn item -> item.date end, fn a, b ->
DateTime.compare(a, b) == :gt
end)
first_item = List.first(items)
last_item = List.last(items)
prev_page_path =
if !is_nil(first_item) &&
Repo.exists?(
from i in Item, where: i.date > ^first_item.date and i.feed_id in ^feed_ids
) do
current_path(conn, %{after: first_item.id})
else
nil
end
next_page_path =
if !is_nil(last_item) &&
Repo.exists?(
from i in Item, where: i.date < ^last_item.date and i.feed_id in ^feed_ids
) do
current_path(conn, %{before: last_item.id})
else
nil
end
render(conn, "read.html", %{
group: group,
items: items,
prev_page_path: prev_page_path,
next_page_path: next_page_path
})
end
end end

View File

@ -105,7 +105,7 @@ defmodule FrenzyWeb.PipelineController do
else else
{:error, reason} -> {:error, reason} ->
conn conn
|> put_flash(:error, "Unable to edit pipeline: #{reason}") |> put_flash(:error, "Unable to edit pipeline: #{inspect(reason)}")
|> render("edit.html", %{ |> render("edit.html", %{
pipeline: pipeline, pipeline: pipeline,
name: name, name: name,
@ -123,7 +123,7 @@ defmodule FrenzyWeb.PipelineController do
{:cont, {:ok, new_stages ++ [stage]}} {:cont, {:ok, new_stages ++ [stage]}}
{:error, reason} -> {:error, reason} ->
{:halt, {:error, "invalid stage at index #{index}: #{reason}"}} {:error, "invalid stage at #{index}: #{reason}"}
end end
end) end)
end end

View File

@ -47,8 +47,7 @@ defmodule FrenzyWeb.Router do
post "/account/export", AccountController, :export post "/account/export", AccountController, :export
get "/", GroupController, :index get "/", GroupController, :index
resources "/groups", GroupController resources "/groups", GroupController, except: [:edit, :update]
get "/groups/:id/read", GroupController, :read
resources "/feeds", FeedController, except: [:index, :new] resources "/feeds", FeedController, except: [:index, :new]
post "/feeds/:id/refresh", FeedController, :refresh post "/feeds/:id/refresh", FeedController, :refresh

View File

@ -1,18 +1,6 @@
<h1>Edit Feed</h1> <h1>Edit Feed</h1>
<%= form_for @changeset, Routes.feed_path(@conn, :update, @feed.id), fn f -> %> <%= form_for @changeset, Routes.feed_path(@conn, :update, @feed.id), fn f -> %>
<div class="form-group row">
<label class="col-sm-2 col-form-label" for="feed_url">Feed URL</label>
<div class="col-sm-10">
<%= text_input f, :feed_url, class: "form-control" %>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label" for="refresh_frequency">Refresh Frequency</label>
<div class="col-sm-10">
<%= select f, :refresh_frequency, @refresh_frequencies, class: "custom-select" %>
</div>
</div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" for="pipeline_id">Pipeline ID</label> <label class="col-sm-2 col-form-label" for="pipeline_id">Pipeline ID</label>
<div class="col-sm-10"> <div class="col-sm-10">
@ -20,11 +8,11 @@
</div> </div>
</div> </div>
<%= if @feed.pipeline_id do %> <%= if @feed.pipeline_id do %>
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-10"> <div class="col-sm-10">
<a href="<%= Routes.pipeline_path(@conn, :show, @feed.pipeline_id) %>" class="col-sm-2">View Pipeline</a> <a href="<%= Routes.pipeline_path(@conn, :show, @feed.pipeline_id) %>" class="col-sm-2">View Pipeline</a>
</div>
</div> </div>
</div>
<% end %> <% end %>
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-10"> <div class="col-sm-10">

View File

@ -17,12 +17,6 @@
<h3 class="mt-4">Items</h3> <h3 class="mt-4">Items</h3>
<%= unless is_nil(@prev_page_path) do %>
<p class="text-center">
<a href="<%= @prev_page_path %>" class="pagination-link">Newer</a>
</p>
<% end %>
<table class="table table-striped"> <table class="table table-striped">
<tbody> <tbody>
<%= for item <- @items do %> <%= for item <- @items do %>
@ -31,8 +25,8 @@
<a href="<%= Routes.item_path(@conn, :show, item.id) %>"><%= item.title || "(Untitled)" %></a> <a href="<%= Routes.item_path(@conn, :show, item.id) %>"><%= item.title || "(Untitled)" %></a>
</td> </td>
<td> <td>
<%= if item.date do %> <% if item.date do %>
<% {:ok, date} = Timex.format(item.date, "{YYYY}-{0M}-{0D} {0h12}:{m} {AM}") %> <% {:ok, date} = Timex.format(item.date, "{YYYY}-{M}-{D} {h12}:{m} {AM}") %>
<%= date %> <%= date %>
<% end %> <% end %>
</td> </td>
@ -40,9 +34,3 @@
<% end %> <% end %>
</tbody> </tbody>
</table> </table>
<%= unless is_nil(@next_page_path) do %>
<p class="text-center">
<a href="<%= @next_page_path %>" class="pagination-link">Older</a>
</p>
<% end %>

View File

@ -1,13 +0,0 @@
<h1>Edit Group</h1>
<%= form_for @changeset, Routes.group_path(@conn, :update, @group.id), fn f -> %>
<div class="form-group row">
<label class="col-sm-2 col-form-label" for="title">Title</label>
<div class="col-sm-10">
<%= text_input f, :title, class: "form-control" %>
</div>
</div>
<div class="form-group row">
<%= submit "Update Group", class: "btn btn-primary" %>
</div>
<% end %>

View File

@ -1,41 +0,0 @@
<h1><%= @group.title %></h1>
<%= unless is_nil(@prev_page_path) do %>
<p class="text-center">
<a href="<%= @prev_page_path %>" class="pagination-link">Newer</a>
</p>
<% end %>
<table class="table table-striped">
<tbody>
<%= for item <- @items do %>
<tr <%= if item.read do %>class="item-read"<% end %>>
<td>
<a href="<%= Routes.item_path(@conn, :show, item.id) %>">
<%= item.title || "(Untitled)" %>
</a>
</td>
<td>
<a href="<%= Routes.feed_path(@conn, :show, item.feed.id) %>">
<%= if item.feed.favicon do %>
<img src="<%= item.feed.favicon %>" alt="<%= item.feed.title %> favicon" class="favicon">
<% end %>
<%= item.feed.title || "(Untitled)" %>
</a>
</td>
<td>
<%= if item.date do %>
<% {:ok, date} = Timex.format(item.date, "{YYYY}-{0M}-{0D} {0h12}:{m} {AM}") %>
<%= date %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= unless is_nil(@next_page_path) do %>
<p class="text-center">
<a href="<%= @next_page_path %>" class="pagination-link">Older</a>
</p>
<% end %>

View File

@ -1,24 +1,23 @@
<h1><%= @group.title %></h1> <h1><%= @group.title %></h1>
<a href="<%= Routes.group_path(@conn, :edit, @group.id) %>" class="btn btn-primary">Edit Group</a> <%= form_for @create_feed_changeset, Routes.feed_path(@conn, :create), fn form -> %>
<%= form_tag Routes.group_path(@conn, :delete, @group.id), method: :delete, class: "d-inline" do %>
<%= submit "Delete Group", class: "btn btn-danger" %>
<% end %>
<%= form_for @create_feed_changeset, Routes.feed_path(@conn, :create), [class: "mt-2 mb-2"], fn form -> %>
<%= hidden_input form, :group_id %> <%= hidden_input form, :group_id %>
<div class="row"> <div class="form-group row">
<%= label form, :feed_url, "Feed URL", class: "col-sm-2 col-form-label" %> <%= label form, :feed_url, "Feed URL", class: "col-sm-2 col-form-label" %>
<div class="col-sm-8"> <div class="col-sm-10">
<%= text_input form, :feed_url, placeholder: "https://example.com/feed.xml", class: "form-control" %> <%= text_input form, :feed_url, placeholder: "https://example.com/feed.xml", class: "form-control" %>
</div> </div>
<div class="col-sm-2"> </div>
<div class="form-group row">
<div class="col-sm-10">
<%= submit "Add Feed", class: "btn btn-primary" %> <%= submit "Add Feed", class: "btn btn-primary" %>
</div> </div>
</div> </div>
<% end %> <% end %>
<a href="<%= Routes.group_path(@conn, :read, @group.id) %>" class="btn btn-secondary">Read Articles</a> <%= form_tag Routes.group_path(@conn, :delete, @group.id), method: :delete do %>
<%= submit "Delete Group", class: "btn btn-danger" %>
<% end %>
<h3 class="mt-4">Feeds</h3> <h3 class="mt-4">Feeds</h3>

View File

@ -44,7 +44,6 @@ defmodule Frenzy.MixProject do
{:jason, "~> 1.0"}, {:jason, "~> 1.0"},
{:plug_cowboy, "~> 2.0"}, {:plug_cowboy, "~> 2.0"},
{:httpoison, "~> 1.6.2"}, {:httpoison, "~> 1.6.2"},
{:hackney, "~> 1.16"},
{:feed_parser, {:feed_parser,
git: "https://git.shadowfacts.net/shadowfacts/feed_parser.git", branch: "master"}, git: "https://git.shadowfacts.net/shadowfacts/feed_parser.git", branch: "master"},
{:timex, "~> 3.6"}, {:timex, "~> 3.6"},

View File

@ -1,51 +1,51 @@
%{ %{
"basic_auth": {:hex, :basic_auth, "2.2.4", "d8c748237870dd1df3bc5c0f1ab4f1fad6270c75472d7e62b19302ec59e92a79", [:mix], [{:plug, "~> 0.14 or ~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "basic_auth": {:hex, :basic_auth, "2.2.4", "d8c748237870dd1df3bc5c0f1ab4f1fad6270c75472d7e62b19302ec59e92a79", [:mix], [{:plug, "~> 0.14 or ~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.0.1", "1061e2114aaac554c12e5c1e4608bf4aadaca839f30d1b85224272facd5e6427", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "64f174c76ea5edfcc471dfb7762280a20e29fe446baa02dc75c7d14251581e93"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.0.1", "1061e2114aaac554c12e5c1e4608bf4aadaca839f30d1b85224272facd5e6427", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"}, "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"comeonin": {:hex, :comeonin, "5.1.1", "0abd6bae41acc01c369bb3eafe46399f301bf4e1bacebafdb89252bbb8a1a32d", [:mix], [], "hexpm", "b77aef9eb7ec7a4c01cc3d0683332796052ab71067d858d5dacde967427de0a3"}, "comeonin": {:hex, :comeonin, "5.1.1", "0abd6bae41acc01c369bb3eafe46399f301bf4e1bacebafdb89252bbb8a1a32d", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.6.0", "dc1ff5354c89e36a3e3ef8d10433396dcff0dcbb1d4223b58c64c2d51a6d88d9", [:rebar3], [{:cowlib, "~> 2.7.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "ff7cf0fb7a2762f423d845468b32ed4edb5c7e0d78e6875b0628153239a7bb34"}, "cowboy": {:hex, :cowboy, "2.6.0", "dc1ff5354c89e36a3e3ef8d10433396dcff0dcbb1d4223b58c64c2d51a6d88d9", [:rebar3], [{:cowlib, "~> 2.7.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "2.7.0", "3ef16e77562f9855a2605900cedb15c1462d76fb1be6a32fc3ae91973ee543d2", [:rebar3], [], "hexpm", "59f952d504b9921a6f53226fdb8b4a671bb694277c7ccf1ddeaadcdc6d43d88e"}, "cowlib": {:hex, :cowlib, "2.7.0", "3ef16e77562f9855a2605900cedb15c1462d76fb1be6a32fc3ae91973ee543d2", [:rebar3], [], "hexpm"},
"db_connection": {:hex, :db_connection, "2.0.2", "440c05518b0bdca0469dafaf45403597430448c1281def14ef9ccaa41833ea1e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "da1cfb8ba1e2b77b594305ea62cce8d8c64776199f0d9a849718c4f0fceb9ad2"}, "db_connection": {:hex, :db_connection, "2.0.2", "440c05518b0bdca0469dafaf45403597430448c1281def14ef9ccaa41833ea1e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
"decimal": {:hex, :decimal, "1.6.0", "bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc", [:mix], [], "hexpm", "bbd124e240e3ff40f407d50fced3736049e72a73d547f69201484d3a624ab569"}, "decimal": {:hex, :decimal, "1.6.0", "bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "49496d63267bc1a4614ffd5f67c45d9fc3ea62701a6797975bc98bc156d2763f"}, "dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"},
"ecto": {:hex, :ecto, "3.0.3", "018a3df0956636f84eb3033d807485a7d3dea8474f47b90da5cb8073444c4384", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "30b0956495d12b53dbabe7965bfb40e4cd5c49c2f0b051b23fb94ac2854006ea"}, "ecto": {:hex, :ecto, "3.0.3", "018a3df0956636f84eb3033d807485a7d3dea8474f47b90da5cb8073444c4384", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_sql": {:hex, :ecto_sql, "3.0.2", "0e04cbc183b91ea0085c502226befcd237a4ac31c204fd4be8d4db6676b5f10d", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.2.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c047508d619a04ff193ea6e92f92701815fdee195be93bfd89bbee3025898b5e"}, "ecto_sql": {:hex, :ecto_sql, "3.0.2", "0e04cbc183b91ea0085c502226befcd237a4ac31c204fd4be8d4db6676b5f10d", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.2.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.5.2", "96a28c79f5b8d34879cd95ebc04d2a0d678cfbbd3e74c43cb63a76adf0ee8054", [:mix], [], "hexpm", "382eeea8e02dfe6c468f6729b6cf20fe5b14390671d38c7363e59621c7ab4efc"}, "elixir_make": {:hex, :elixir_make, "0.5.2", "96a28c79f5b8d34879cd95ebc04d2a0d678cfbbd3e74c43cb63a76adf0ee8054", [:mix], [], "hexpm"},
"erlex": {:hex, :erlex, "0.2.4", "23791959df45fe8f01f388c6f7eb733cc361668cbeedd801bf491c55a029917b", [:mix], [], "hexpm", "4a12ebc7cd8f24f2d0fce93d279fa34eb5068e0e885bb841d558c4d83c52c439"}, "erlex": {:hex, :erlex, "0.2.4", "23791959df45fe8f01f388c6f7eb733cc361668cbeedd801bf491c55a029917b", [:mix], [], "hexpm"},
"feed_parser": {:git, "https://git.shadowfacts.net/shadowfacts/feed_parser.git", "8c42d4587328698e8d29d2ad562e478abb146f75", [branch: "master"]}, "feed_parser": {:git, "https://git.shadowfacts.net/shadowfacts/feed_parser.git", "8c42d4587328698e8d29d2ad562e478abb146f75", [branch: "master"]},
"fiet": {:git, "https://github.com/shadowfacts/fiet.git", "bf117bc30a6355a189d05a562127cfaf9e0187ae", [branch: "master"]}, "fiet": {:git, "https://github.com/shadowfacts/fiet.git", "bf117bc30a6355a189d05a562127cfaf9e0187ae", [branch: "master"]},
"file_system": {:hex, :file_system, "0.2.6", "fd4dc3af89b9ab1dc8ccbcc214a0e60c41f34be251d9307920748a14bf41f1d3", [:mix], [], "hexpm", "0d50da6b04c58e101a3793b1600f9a03b86e3a8057b192ac1766013d35706fa6"}, "file_system": {:hex, :file_system, "0.2.6", "fd4dc3af89b9ab1dc8ccbcc214a0e60c41f34be251d9307920748a14bf41f1d3", [:mix], [], "hexpm"},
"floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "e680b5ef0b61ce02faa7137db8d1714903a5552be4c89fb57293b8770e7f49c2"}, "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm", "e0b8598e802676c81e66b061a2148c37c03886b24a3ca86a1f98ed40693b94b3"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"}, "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm", "3e3d7156a272950373ce5a4018b1490bea26676f8d6a7d409f6fac8568b8cb9a"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"},
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"}, "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm", "5e839994289d60326aa86020c4fbd9c6938af188ecddab2579f07b66cd665328"}, "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.4.0", "56fe9a809e0e735f3e3b9b31c1b749d4b436e466d8da627b8d82f90eaae714d2", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "22da8f659cf13d3ba73b767f66b8c389113ddf0ef7b94225cc84e94b85eac90e"}, "phoenix": {:hex, :phoenix, "1.4.0", "56fe9a809e0e735f3e3b9b31c1b749d4b436e466d8da627b8d82f90eaae714d2", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "fe15d9fee5b82f5e64800502011ffe530650d42e1710ae9b14bc4c9be38bf303"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.12.0", "1fb3c2e48b4b66d75564d8d63df6d53655469216d6b553e7e14ced2b46f97622", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "8bc079e2092f4447c8c75029b297cfc3256b8aa46dff02a16eaf1ade5eae96f6"}, "phoenix_html": {:hex, :phoenix_html, "2.12.0", "1fb3c2e48b4b66d75564d8d63df6d53655469216d6b553e7e14ced2b46f97622", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.0", "3bb31a9fbd40ffe8652e60c8660dffd72dd231efcdf49b744fb75b9ef7db5dd2", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b61c87a23fabcd85ff369fb9c041d9c01787d210322749026f56a69a914b7503"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.0", "3bb31a9fbd40ffe8652e60c8660dffd72dd231efcdf49b744fb75b9ef7db5dd2", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm", "a3d890aaa3156d51056179dcaaadaf32b844f71656bb27c58756f2b97875c36c"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"},
"plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm", "daa5fee4209c12c3c48b05a96cf88c320b627c9575f987554dcdc1fdcdf2c15e"}, "plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "fa9087d93f4962d099b9c4246dbea97c2f2e6aab1029e8b8206e733a1274cecc"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm", "73c1682f0e414cfb5d9b95c8e8cd6ffcfdae699e3b05e1db744e58b7be857759"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.14.0", "f3d6ffea1ca8a156e0633900a5338a3d17b00435227726baed8982718232b694", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ee6d8bc31ec7064f87030b98e431cf7ef0537052339de289b575b0a8872f501e"}, "postgrex": {:hex, :postgrex, "0.14.0", "f3d6ffea1ca8a156e0633900a5338a3d17b00435227726baed8982718232b694", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ranch": {:hex, :ranch, "1.7.0", "9583f47160ca62af7f8d5db11454068eaa32b56eeadf984d4f46e61a076df5f2", [:rebar3], [], "hexpm", "59f7501c3a56125b2fc5684c3048fac9d043c0bf4d173941b12ca927949af189"}, "ranch": {:hex, :ranch, "1.7.0", "9583f47160ca62af7f8d5db11454068eaa32b56eeadf984d4f46e61a076df5f2", [:rebar3], [], "hexpm"},
"readability": {:git, "https://github.com/shadowfacts/readability.git", "71fa17caaf8103ef213e2c7dde4b447a48669122", [branch: "master"]}, "readability": {:git, "https://github.com/shadowfacts/readability.git", "71fa17caaf8103ef213e2c7dde4b447a48669122", [branch: "master"]},
"saxy": {:hex, :saxy, "0.6.0", "cdb2f2fcd8133d1f3f8b0cf6a131ee1ca348dca613de266e9a239db850c4a093", [:mix], [], "hexpm"}, "saxy": {:hex, :saxy, "0.6.0", "cdb2f2fcd8133d1f3f8b0cf6a131ee1ca348dca613de266e9a239db850c4a093", [:mix], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.2.0", "5b40caa3efe4deb30fb12d7cd8ed4f556f6d6bd15c374c2366772161311ce377", [:mix], [], "hexpm", "4e9071b8d1795d0f1ae00584594c3faf430c88821b69e4bd09b02e7840231f32"}, "telemetry": {:hex, :telemetry, "0.2.0", "5b40caa3efe4deb30fb12d7cd8ed4f556f6d6bd15c374c2366772161311ce377", [:mix], [], "hexpm"},
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"}, "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "1.0.1", "f6027a331af7d837471248e62733c6ebee86a72e57c613aa071ebb1f750fc71a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cf1345dfbce6acdfd4e23cbb36e96e53d1981bc89181cd0b936f4f398f4c0b78"}, "tzdata": {:hex, :tzdata, "1.0.1", "f6027a331af7d837471248e62733c6ebee86a72e57c613aa071ebb1f750fc71a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
"xml_builder": {:hex, :xml_builder, "2.1.1", "2d6d665f09cf1319e3e1c46035755271b414d99ad8615d0bd6f337623e0c885b", [:mix], [], "hexpm", "214c16caa77e66bf0c6b74099a7059ee00de8fd07728d2a3dc32afe344a7452b"}, "xml_builder": {:hex, :xml_builder, "2.1.1", "2d6d665f09cf1319e3e1c46035755271b414d99ad8615d0bd6f337623e0c885b", [:mix], [], "hexpm"},
} }

View File

@ -1,10 +0,0 @@
defmodule Frenzy.Repo.Migrations.FeedsAddRefreshFrequency do
use Ecto.Migration
def change do
alter table(:feeds) do
add :last_refreshed_at, :naive_datetime, default: nil
add :refresh_frequency, :integer, default: 30 * 60
end
end
end