defmodule ToweropsWeb.Org.IntegrationsLive do @moduledoc false use ToweropsWeb, :live_view alias Towerops.Integrations alias Towerops.Integrations.Integration alias Towerops.Preseem.Client, as: PreseemClient @providers [ %{ id: "preseem", name: "Preseem", description: "QoE monitoring and subscriber experience analytics for wireless ISPs.", icon: "hero-signal" } ] @impl true def mount(_params, _session, socket) do organization = socket.assigns.current_scope.organization integrations = load_integrations(organization.id) {:ok, socket |> assign(:organization, organization) |> assign(:providers, @providers) |> assign(:integrations, integrations) |> assign(:configuring, nil) |> assign(:form, nil) |> assign(:test_result, nil)} end @impl true def handle_event("configure", %{"provider" => provider}, socket) do integration = Map.get(socket.assigns.integrations, provider) form = case integration do nil -> %Integration{} |> Integrations.change_integration(%{provider: provider}) |> to_form() existing -> existing |> Integrations.change_integration(%{}) |> to_form() end {:noreply, socket |> assign(:configuring, provider) |> assign(:form, form) |> assign(:test_result, nil)} end @impl true def handle_event("close_config", _params, socket) do {:noreply, socket |> assign(:configuring, nil) |> assign(:form, nil) |> assign(:test_result, nil)} end @impl true def handle_event("validate", %{"integration" => params}, socket) do integration = get_current_integration(socket) changeset = integration |> Integrations.change_integration(normalize_params(params)) |> Map.put(:action, :validate) {:noreply, assign(socket, :form, to_form(changeset))} end @impl true def handle_event("save", %{"integration" => params}, socket) do organization = socket.assigns.organization provider = socket.assigns.configuring existing = Map.get(socket.assigns.integrations, provider) attrs = normalize_params(params) result = case existing do nil -> Integrations.create_integration(organization.id, Map.put(attrs, :provider, provider)) integration -> Integrations.update_integration(integration, attrs) end case result do {:ok, _integration} -> integrations = load_integrations(organization.id) {:noreply, socket |> assign(:integrations, integrations) |> assign(:configuring, nil) |> assign(:form, nil) |> assign(:test_result, nil) |> put_flash(:info, "Integration saved successfully")} {:error, changeset} -> {:noreply, assign(socket, :form, to_form(changeset))} end end @impl true def handle_event("test_connection", _params, socket) do api_key = extract_api_key(socket) if api_key == "" or is_nil(api_key) do {:noreply, assign(socket, :test_result, {:error, "Please enter an API key first"})} else case PreseemClient.test_connection(api_key) do {:ok, _body} -> {:noreply, assign(socket, :test_result, {:ok, "Connection successful"})} {:error, :unauthorized} -> {:noreply, assign(socket, :test_result, {:error, "Invalid API key"})} {:error, :forbidden} -> {:noreply, assign(socket, :test_result, {:error, "Access forbidden"})} {:error, reason} -> {:noreply, assign(socket, :test_result, {:error, "Connection failed: #{inspect(reason)}"})} end end end @impl true def handle_event("toggle_enabled", %{"provider" => provider}, socket) do case Map.get(socket.assigns.integrations, provider) do nil -> {:noreply, socket} integration -> case Integrations.update_integration(integration, %{enabled: !integration.enabled}) do {:ok, _updated} -> integrations = load_integrations(socket.assigns.organization.id) {:noreply, socket |> assign(:integrations, integrations) |> put_flash(:info, "Integration updated")} {:error, _changeset} -> {:noreply, put_flash(socket, :error, "Failed to update integration")} end end end defp load_integrations(organization_id) do organization_id |> Integrations.list_integrations() |> Map.new(fn integration -> {integration.provider, integration} end) end defp get_current_integration(socket) do provider = socket.assigns.configuring case Map.get(socket.assigns.integrations, provider) do nil -> %Integration{} integration -> integration end end defp normalize_params(params) do api_key = Map.get(params, "api_key", "") base_url = Map.get(params, "base_url", "") credentials = then(%{"api_key" => api_key}, fn creds -> if base_url == "", do: creds, else: Map.put(creds, "base_url", base_url) end) %{credentials: credentials} end defp get_credential(nil, _key), do: "" defp get_credential(%Integration{credentials: credentials}, key) when is_map(credentials) do Map.get(credentials, key, "") end defp get_credential(_integration, _key), do: "" defp extract_api_key(socket) do changeset = socket.assigns.form.source data = Ecto.Changeset.apply_changes(changeset) case data.credentials do %{"api_key" => key} -> key _ -> nil end end end