From 686bb489ba95ff3ae6a9531fc5d95cd0a7a07d19 Mon Sep 17 00:00:00 2001
From: Adam Piontek <adam@73k.us>
Date: Wed, 24 Mar 2021 19:35:49 -0400
Subject: [PATCH] initial work on allowing import from ics/iCal

---
 assets/js/app.js                              |  1 +
 .../live/shift_import_live/index.ex           | 63 +++++++++++++++++++
 .../live/shift_import_live/index.html.leex    | 35 +++++++++++
 lib/shift73k_web/router.ex                    |  2 +
 .../layout/navbar/_shifts_menu.html.eex       |  6 ++
 mix.exs                                       |  3 +-
 mix.lock                                      |  1 +
 7 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 lib/shift73k_web/live/shift_import_live/index.ex
 create mode 100644 lib/shift73k_web/live/shift_import_live/index.html.leex

diff --git a/assets/js/app.js b/assets/js/app.js
index 5f83b83e..b9f19848 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -56,6 +56,7 @@ import "../node_modules/bootstrap-icons/icons/save.svg";
 import "../node_modules/bootstrap-icons/icons/asterisk.svg";
 import "../node_modules/bootstrap-icons/icons/card-list.svg";
 import "../node_modules/bootstrap-icons/icons/file-earmark-spreadsheet.svg";
+import "../node_modules/bootstrap-icons/icons/box-arrow-in-left.svg";
 
 // webpack automatically bundles all modules in your
 // entry points. Those entry points can be configured
diff --git a/lib/shift73k_web/live/shift_import_live/index.ex b/lib/shift73k_web/live/shift_import_live/index.ex
new file mode 100644
index 00000000..9da8abb9
--- /dev/null
+++ b/lib/shift73k_web/live/shift_import_live/index.ex
@@ -0,0 +1,63 @@
+defmodule Shift73kWeb.ShiftImportLive.Index do
+  use Shift73kWeb, :live_view
+
+  @impl true
+  def mount(_params, session, socket) do
+    HTTPoison.start()
+
+    socket
+    |> assign_defaults(session)
+    |> live_okreply()
+  end
+
+  @impl true
+  def handle_event("save", %{"ics_import" => %{"ics_url" => ics_url}}, socket) do
+    ics_url
+    |> IO.inspect(label: "given ical url :")
+    |> HTTPoison.get!()
+    |> handle_http_ics_response(socket)
+  end
+
+  defp handle_http_ics_response(%HTTPoison.Response{status_code: 200} = resp, socket) do
+    case content_type_calendar?(resp.headers) do
+      false ->
+        handle_http_ics_response(false, socket)
+
+      true ->
+        resp.body
+        |> ICalendar.from_ics()
+        |> handle_parsed_ics_data(socket)
+    end
+  end
+
+  defp handle_http_ics_response(_, socket) do
+    socket
+    |> put_flash(:error, "Bad data, bad URL, or some other error")
+    |> live_noreply()
+  end
+
+  defp handle_parsed_ics_data([], socket), do: handle_http_ics_response(false, socket)
+
+  defp handle_parsed_ics_data(events, socket) do
+    IO.inspect(events, label: "We got some ical events! :")
+
+    socket
+    |> put_flash(:success, "We got some ical events")
+    |> live_noreply()
+  end
+
+  def ical_request(ics_url) do
+    # ics_url = "https://calendar.google.com/calendar/ical/l44mcggj2rsoqq7prlakvitqfo%40group.calendar.google.com/private-66f4cf8b340bdd6e9de8c60b2ae36528/basic.ics"
+  end
+
+  defp content_type_calendar?(headers) do
+    headers
+    |> List.keyfind("Content-Type", 0)
+    |> elem(1)
+    |> String.contains?("text/calendar")
+  end
+
+  def shift_from_event(%ICalendar.Event{} = event) do
+    %{}
+  end
+end
diff --git a/lib/shift73k_web/live/shift_import_live/index.html.leex b/lib/shift73k_web/live/shift_import_live/index.html.leex
new file mode 100644
index 00000000..3edf3548
--- /dev/null
+++ b/lib/shift73k_web/live/shift_import_live/index.html.leex
@@ -0,0 +1,35 @@
+<div class="row justify-content-center">
+  <div class="col-12 col-md-10 col-xl-8">
+
+    <h2>
+      <%= icon_div @socket, "bi-box-arrow-in-left", [class: "icon baseline"] %>
+      Import Shifts
+    </h2>
+
+    <p class="lead">If you have an iCal/ics formatted calendar hosted elsewhere, provide its URL here to import its events.</p>
+
+    <div class="row justify-content-center">
+      <div class="col-12 col-sm-11 col-md-10 col-lg-9 col-xxl-8">
+
+        <%= form_for :ics_import, "#", [phx_submit: "save"], fn iimf -> %>
+
+          <div class="row">
+            <div class="col mb-3">
+              <%= label iimf, :ics_url, "iCal/ics URL", class: "form-label" %>
+              <%= url_input iimf, :ics_url, class: "form-control" %>
+            </div>
+          </div>
+
+          <div class="row">
+            <div class="col mb-3 text-end">
+              <%= submit "Submit", class: "btn btn-primary" %>
+            </div>
+          </div>
+
+        <% end %>
+
+      </div>
+    </div>
+
+  </div>
+</div>
diff --git a/lib/shift73k_web/router.ex b/lib/shift73k_web/router.ex
index a22c1a95..1cdf67b0 100644
--- a/lib/shift73k_web/router.ex
+++ b/lib/shift73k_web/router.ex
@@ -106,6 +106,8 @@ defmodule Shift73kWeb.Router do
 
     get "/csv", UserShiftsCsvController, :new
     post "/csv", UserShiftsCsvController, :export
+
+    live "/import", ShiftImportLive.Index, :index
   end
 
   # scope "/", Shift73kWeb do
diff --git a/lib/shift73k_web/templates/layout/navbar/_shifts_menu.html.eex b/lib/shift73k_web/templates/layout/navbar/_shifts_menu.html.eex
index 137f8140..ae472ab1 100644
--- a/lib/shift73k_web/templates/layout/navbar/_shifts_menu.html.eex
+++ b/lib/shift73k_web/templates/layout/navbar/_shifts_menu.html.eex
@@ -34,6 +34,12 @@
         CSV Export
       <% end %>
     </li>
+    <li>
+      <%= link nav_link_opts(@conn, to: Routes.shift_import_index_path(@conn, :index), class: "dropdown-item") do %>
+        <%= icon_div @conn, "bi-box-arrow-in-left", [class: "icon baseline me-1"] %>
+        iCal Import
+      <% end %>
+    </li>
 
   </ul>
 
diff --git a/mix.exs b/mix.exs
index 9d064ea5..520ec53b 100644
--- a/mix.exs
+++ b/mix.exs
@@ -53,7 +53,8 @@ defmodule Shift73k.MixProject do
       {:scrivener_ecto, "~> 2.0"},
       {:tzdata, "~> 1.1"},
       {:nimble_csv, "~> 1.0"},
-      {:icalendar, "~> 1.1"}
+      {:icalendar, "~> 1.1"},
+      {:httpoison, "~> 1.7"}
     ]
   end
 
diff --git a/mix.lock b/mix.lock
index 578aa5fe..7149b0ff 100644
--- a/mix.lock
+++ b/mix.lock
@@ -21,6 +21,7 @@
   "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
   "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
   "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
+  "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
   "hut": {:hex, :hut, "1.3.0", "71f2f054e657c03f959cf1acc43f436ea87580696528ca2a55c8afb1b06c85e7", [:"erlang.mk", :rebar, :rebar3], [], "hexpm", "7e15d28555d8a1f2b5a3a931ec120af0753e4853a4c66053db354f35bf9ab563"},
   "icalendar": {:hex, :icalendar, "1.1.0", "898a8640abb32d161d990e419999004718a7a4b48be31f48db248f90ca33fa6e", [:mix], [{:timex, "~> 3.4", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "a131f45fbabd2ee5a22e6bc49ea91e81131158394e7169274cee866263640dca"},
   "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},