소스 검색

Some cleanup

theenglishway (time) 4 년 전
부모
커밋
c85b0eb87b
4개의 변경된 파일68개의 추가작업 그리고 52개의 파일을 삭제
  1. 57 32
      lib/vaccins/queries.ex
  2. 6 15
      lib/vaccins/search.ex
  3. 4 4
      lib/vaccins_web/live/index.ex
  4. 1 1
      lib/vaccins_web/live/index_live.html.leex

+ 57 - 32
lib/vaccins/queries.ex

@@ -1,10 +1,15 @@
 defmodule Vaccins.Queries do
-  defmodule Query do
+  defmodule Provider do
+    @callback new(list) :: any
+
     @callback to_url(any) :: String.t()
+
+    @doc "Find slots in the result from the query, if any"
+    @callback analyze_result(any) :: any
   end
 
   defmodule Doctolib do
-    @behaviour Query
+    @behaviour Provider
     alias __MODULE__, as: Doctolib
 
     defstruct [
@@ -23,9 +28,6 @@ defmodule Vaccins.Queries do
         struct(Doctolib, kw_list)
         |> Map.replace(:start_date, Date.utc_today() |> Date.to_string())
 
-    def motives(), do: %{premiere_injection_pfizer: 2_743_305}
-    def practices(), do: %{fontenay: 180_541}
-
     def to_url(q = %__MODULE__{}) do
       query_string = q |> Map.from_struct() |> URI.encode_query()
 
@@ -53,45 +55,68 @@ defmodule Vaccins.Queries do
     end
   end
 
-  def valid_queries(),
-    do: [
-      %{
-        id: "Centre de Vaccination - Salle Olympe de Gouges",
-        availability_query:
-          Doctolib.new(
+  defmodule Location do
+    alias __MODULE__, as: Location
+    defstruct [:id, :availability_query, :booking_page, :provider, availability_query_params: []]
+
+    def build_query(l = %Location{availability_query_params: params, provider: provider})
+        when params != [],
+        do: %{l | availability_query: params |> provider.new}
+
+    def query_availability(
+          l = %Location{id: id, availability_query: q, booking_page: bp, provider: provider}
+        ) do
+      with url <- q |> provider.to_url() |> URI.to_string(),
+           {:ok, result} <- url |> Vaccins.Scraper.get_json() do
+        case result |> provider.analyze_result() do
+          {:ok, slots} -> {id, slots, bp}
+          {:error, reason} when reason in [:no_availability] -> {id, reason}
+        end
+      end
+    end
+  end
+
+  def get_locations(),
+    do:
+      [
+        %Location{
+          id: "Centre de Vaccination - Salle Olympe de Gouges",
+          provider: Doctolib,
+          availability_query_params: [
             visit_motive_ids: 2_549_915,
             agenda_ids:
               "434477-434486-434466-434472-440075-440077-440078-415625-434490-462178-462452-433984-462177-433604-433601-415628-440074-433997-434489-440076",
             practice_ids: 164_922,
             limit: 7
-          ),
-        booking_page:
-          "https://partners.doctolib.fr/centre-de-sante/fontenay-sous-bois/centre-de-vaccination-covid-19-fontenay-sous-bois?pid=practice-180541"
-      },
-      %{
-        id: "Centre de Vaccination - Paris 20e",
-        availability_query:
-          Doctolib.new(
+          ],
+          booking_page:
+            "https://partners.doctolib.fr/centre-de-sante/fontenay-sous-bois/centre-de-vaccination-covid-19-fontenay-sous-bois?pid=practice-180541"
+        },
+        %Location{
+          id: "Centre de Vaccination - Paris 20e",
+          provider: Doctolib,
+          availability_query_params: [
             visit_motive_ids: 2_549_915,
             agenda_ids:
               "463167-415613-463168-415615-429620-434343-463166-463170-463171-447048-440655-434052-440654-462614-462613-433994-434337-434338",
             practice_ids: 166_459,
             limit: 3
-          ),
-        booking_page:
-          "https://www.doctolib.fr/centre-de-sante/paris/centre-de-vaccination-covid-19-ville-de-paris?pid=practice-166459"
-      },
-      %{
-        id: "Hotel de ville de Fontenay-sous-Bois",
-        availability_query:
-          Doctolib.new(
+          ],
+          booking_page:
+            "https://www.doctolib.fr/centre-de-sante/paris/centre-de-vaccination-covid-19-ville-de-paris?pid=practice-166459"
+        },
+        %Location{
+          id: "Hotel de ville de Fontenay-sous-Bois",
+          provider: Doctolib,
+          availability_query_params: [
             visit_motive_ids: 2_743_304,
             agenda_ids: "449169-449170-466472",
             practice_ids: 180_541,
             limit: 15
-          ),
-        booking_page:
-          "https://partners.doctolib.fr/centre-de-sante/fontenay-sous-bois/centre-de-vaccination-covid-19-fontenay-sous-bois?pid=practice-180541&enable_cookies_consent=1"
-      }
-    ]
+          ],
+          booking_page:
+            "https://partners.doctolib.fr/centre-de-sante/fontenay-sous-bois/centre-de-vaccination-covid-19-fontenay-sous-bois?pid=practice-180541&enable_cookies_consent=1"
+        }
+      ]
+      |> Enum.map(&Location.build_query/1)
 end

+ 6 - 15
lib/vaccins/search.ex

@@ -1,26 +1,17 @@
 defmodule Vaccins.Search do
   alias Vaccins.Scraper
-  alias Vaccins.Queries.Query
-
-  def do_query(%{id: id, availability_query: q, booking_page: bp}) do
-    with url <- q |> q._converter.to_url() |> URI.to_string(),
-         {:ok, result} <- url |> Vaccins.Scraper.get_json() do
-      case result |> q._converter.analyze_result() do
-        {:ok, slots} -> {id, slots, bp}
-        {:error, reason} when reason in [:no_availability] -> {id, reason}
-      end
-    end
-  end
-
-  def do_all_queries(list) when is_list(list), do: list |> Enum.map(&do_query/1)
+  alias Vaccins.Queries.Location
 
   def async_trigger_query(q, target \\ nil)
   def async_trigger_query(q, nil), do: async_trigger_query(q, self())
 
-  def async_trigger_query(q, target) when not is_nil(target) do
+  def async_trigger_query(l, target) when not is_nil(target) do
     ref = make_ref()
 
-    with {:ok, _} <- Task.start(fn -> send(target, {:query_result, ref, q |> do_query}) end),
+    with {:ok, _} <-
+           Task.start(fn ->
+             send(target, {:query_result, ref, l |> Location.query_availability()})
+           end),
          do: ref
   end
 end

+ 4 - 4
lib/vaccins_web/live/index.ex

@@ -4,12 +4,12 @@ defmodule VaccinsWeb.IndexLive do
 
   @impl true
   def mount(_params, _session, socket) do
-    queries = Queries.valid_queries()
+    queries = Queries.get_locations()
 
     {:ok,
      socket
      |> assign(
-       valid_queries: queries,
+       locations: queries,
        pending: %{},
        availabilities: queries |> Map.new(&{&1.id, []})
      )}
@@ -19,7 +19,7 @@ defmodule VaccinsWeb.IndexLive do
   def handle_event(
         "trigger_query",
         %{"id" => query_id},
-        socket = %{assigns: %{valid_queries: valid, pending: pending}}
+        socket = %{assigns: %{locations: valid, pending: pending}}
       ) do
     query = valid |> Enum.find(&(&1.id == query_id))
     ref = Search.async_trigger_query(query)
@@ -29,7 +29,7 @@ defmodule VaccinsWeb.IndexLive do
   @impl true
   def handle_info(
         {:query_result, ref, res},
-        socket = %{assigns: %{valid_queries: valid, pending: pending}}
+        socket = %{assigns: %{locations: valid, pending: pending}}
       ) do
     query = pending |> Map.get(ref) |> IO.inspect()
     res |> IO.inspect()

+ 1 - 1
lib/vaccins_web/live/index_live.html.leex

@@ -1,5 +1,5 @@
 <ul>
-  <%= for q <- @valid_queries do %>
+  <%= for q <- @locations do %>
     <li><%= q |> render_query %></li>
   <% end %>
 </ul>