diff --git a/lib/google_crawler/accounts/user.ex b/lib/google_crawler/accounts/user.ex
index 9538db0..f50ab45 100644
--- a/lib/google_crawler/accounts/user.ex
+++ b/lib/google_crawler/accounts/user.ex
@@ -10,6 +10,8 @@ defmodule GoogleCrawler.Accounts.User do
field :password, :string, virtual: true
field :password_confirmation, :string, virtual: true
+ has_many :keywords, GoogleCrawler.Search.Keyword
+
timestamps()
end
diff --git a/lib/google_crawler/search.ex b/lib/google_crawler/search.ex
index 913aaf4..9c261e0 100644
--- a/lib/google_crawler/search.ex
+++ b/lib/google_crawler/search.ex
@@ -10,16 +10,18 @@ defmodule GoogleCrawler.Search do
alias GoogleCrawler.Search.KeywordFile
@doc """
- Returns the list of keywords.
+ Returns the list of keywords belongs to the given user.
## Examples
- iex> list_keywords()
+ iex> list_user_keywords(user)
[%Keyword{}, ...]
"""
- def list_keywords do
- Repo.all(Keyword)
+ def list_user_keywords(user) do
+ Keyword
+ |> where(user_id: ^user.id)
+ |> Repo.all()
end
@doc """
@@ -43,15 +45,15 @@ defmodule GoogleCrawler.Search do
## Examples
- iex> create_keyword(%{field: value})
+ iex> create_keyword(%{field: value}, %User{})
{:ok, %Keyword{}}
- iex> create_keyword(%{field: bad_value})
+ iex> create_keyword(%{field: bad_value}, %User{})
{:error, %Ecto.Changeset{}}
"""
- def create_keyword(attrs \\ %{}) do
- %Keyword{}
+ def create_keyword(attrs \\ %{}, user) do
+ Ecto.build_assoc(user, :keywords)
|> Keyword.changeset(attrs)
|> Repo.insert()
end
diff --git a/lib/google_crawler/search/keyword.ex b/lib/google_crawler/search/keyword.ex
index 50656c7..d87ca11 100644
--- a/lib/google_crawler/search/keyword.ex
+++ b/lib/google_crawler/search/keyword.ex
@@ -5,12 +5,14 @@ defmodule GoogleCrawler.Search.Keyword do
schema "keywords" do
field :keyword, :string
+ belongs_to :user, GoogleCrawler.Accounts.User
+
timestamps()
end
def changeset(keyword, attrs \\ %{}) do
keyword
- |> cast(attrs, [:keyword])
- |> validate_required([:keyword])
+ |> cast(attrs, [:keyword, :user_id])
+ |> validate_required([:keyword, :user_id])
end
end
diff --git a/lib/google_crawler_web/controllers/dashboard_controller.ex b/lib/google_crawler_web/controllers/dashboard_controller.ex
index e341dbb..c3e146d 100644
--- a/lib/google_crawler_web/controllers/dashboard_controller.ex
+++ b/lib/google_crawler_web/controllers/dashboard_controller.ex
@@ -1,11 +1,13 @@
defmodule GoogleCrawlerWeb.DashboardController do
use GoogleCrawlerWeb, :controller
+ alias GoogleCrawler.Search
alias GoogleCrawler.Search.KeywordFile
def index(conn, _params) do
+ keywords = Search.list_user_keywords(conn.assigns.current_user)
changeset = KeywordFile.changeset(%KeywordFile{})
- render(conn, "index.html", changeset: changeset)
+ render(conn, "index.html", keywords: keywords, changeset: changeset)
end
end
diff --git a/lib/google_crawler_web/controllers/upload_controller.ex b/lib/google_crawler_web/controllers/upload_controller.ex
index 02172d8..e7ddf8b 100644
--- a/lib/google_crawler_web/controllers/upload_controller.ex
+++ b/lib/google_crawler_web/controllers/upload_controller.ex
@@ -10,14 +10,49 @@ defmodule GoogleCrawlerWeb.UploadController do
if changeset.valid? do
file = get_change(changeset, :file, nil)
- result = Search.parse_keywords_from_file!(file.path, file.content_type)
- # TODO: Save these keywords and triggers the task to google search for each keyword
- text(conn, result |> Enum.map(fn keyword -> List.first(keyword) end) |> Enum.join(", "))
+ Search.parse_keywords_from_file!(file.path, file.content_type)
+ |> create_and_trigger_google_search(conn)
+ |> put_error_flash_for_failed_keywords(conn)
+ |> redirect(to: Routes.dashboard_path(conn, :index))
else
conn
|> put_flash(:error, gettext("Invalid file, please select again."))
|> redirect(to: Routes.dashboard_path(conn, :index))
end
end
+
+ # TODO: Trigger the scrapper background worker
+ defp create_and_trigger_google_search(csv_result, conn) do
+ csv_result
+ |> Stream.map(fn keyword_row -> List.first(keyword_row) end)
+ |> Stream.map(fn keyword -> %{keyword: keyword} end)
+ |> Enum.map(&Search.create_keyword(&1, conn.assigns.current_user))
+ end
+
+ defp put_error_flash_for_failed_keywords(create_result, conn) do
+ failed_keywords = failed_keywords(create_result)
+
+ if length(failed_keywords) > 0 do
+ conn
+ |> put_flash(
+ :error,
+ gettext("Some keywords could not be created: %{failed_keywords}",
+ failed_keywords: Enum.join(failed_keywords, ", ")
+ )
+ )
+ else
+ conn
+ end
+ end
+
+ defp failed_keywords(create_result) do
+ create_result
+ |> Enum.filter(&match?({:error, _}, &1))
+ |> Enum.map(fn error_tuple ->
+ error_tuple
+ |> elem(1)
+ |> get_change(:keyword, nil)
+ end)
+ end
end
diff --git a/lib/google_crawler_web/templates/dashboard/index.html.eex b/lib/google_crawler_web/templates/dashboard/index.html.eex
index a3bf664..16d85d2 100644
--- a/lib/google_crawler_web/templates/dashboard/index.html.eex
+++ b/lib/google_crawler_web/templates/dashboard/index.html.eex
@@ -1,6 +1,16 @@
-<%= render GoogleCrawlerWeb.KeywordView, "_form.html", assigns %>
+
<%= gettext("You don't have any keywords.") %>
+ <%= if length(@keywords) == 0 do %> +<%= gettext("You don't have any keywords.") %>
+ <% else %> +<%= gettext("📝 Please put one keyword per line") %>
- <%= form_for @changeset, Routes.upload_path(@conn, :create), [multipart: true], fn f -> %> - <%= label f, :file %> - <%= file_input f, :file, required: true %> - <%= error_tag f, :file %> +<%= gettext("📝 Please put one keyword per line") %>
+<%= form_for @changeset, Routes.upload_path(@conn, :create), [multipart: true], fn f -> %> + <%= label f, :file %> + <%= file_input f, :file, required: true, accept: "text/csv" %> + <%= error_tag f, :file %> - <%= submit gettext("Upload") %> - <% end %> -