<commit_before>defmodule BorsNG.WebhookController do
  @moduledoc """
  The webhook controller responds to HTTP requests
  that are initiated from other services (currently, just GitHub).

  For example, I can run `iex -S mix phoenix.server` and do this:

      iex> # Push state to "GitHub"
      iex> alias BorsNG.GitHub
      iex> alias BorsNG.GitHub.ServerMock
      iex> alias BorsNG.Database
      iex> ServerMock.put_state(%{
      ...>   {:installation, 91} => %{ repos: [
      ...>     %GitHub.Repo{
      ...>       id: 14,
      ...>       name: "test/repo",
      ...>       owner: %{
      ...>         id: 6,
      ...>         login: "bors-fanboi",
      ...>         avatar_url: "data:image/svg+xml,<svg></svg>",
      ...>         type: :user
      ...>       }}
      ...>   ] },
      ...>   {{:installation, 91}, 14} => %{
      ...>     branches: %{},
      ...>     comments: %{1 => []},
      ...>     pulls: %{
      ...>       1 => %GitHub.Pr{
      ...>         number: 1,
      ...>         title: "Test",
      ...>         body: "Mess",
      ...>         state: :open,
      ...>         base_ref: "master",
      ...>         head_sha: "00000001",
      ...>         user: %GitHub.User{
      ...>           id: 6,
      ...>           login: "bors-fanboi",
      ...>           avatar_url: "data:image/svg+xml,<svg></svg>"}}},
      ...>     statuses: %{},
      ...>     files: %{}}})
      iex> # The installation now exists; notify bors about it.
      iex> BorsNG.WebhookController.do_webhook(%{
      ...>   body_params: %{
      ...>     "installation" => %{ "id" => 91 },
      ...>     "sender" => %{
      ...>       "id" => 6,
      ...>       "login" => "bors-fanboi",
      ...>       "avatar_url" => "" },
      ...>     "action" => "created" }}, "github", "installation")
      iex> proj = Database.Repo.get_by!(Database.Project, repo_xref: 14)
      iex> proj.name
      "test/repo"
      iex> # This has also started a (background) sync of all attached patches.
      iex> # Watch it happen in the user interface.
      iex> BorsNG.Worker.Syncer.wait_hot_spin(proj.id)
      iex> patch = Database.Repo.get_by!(Database.Patch, pr_xref: 1)
      iex> patch.title
      "Test"
  """

  use BorsNG.Web, :controller

  require Logger

  @allow_private_repos Confex.fetch_env!(
    :bors_frontend, BorsNG)[:allow_private_repos]

  alias BorsNG.Worker.Attemptor
  alias BorsNG.Worker.Batcher
  alias BorsNG.Worker.BranchDeleter
  alias BorsNG.Command
  alias BorsNG.Database.Installation
  alias BorsNG.Database.Patch
  alias BorsNG.Database.Project
  alias BorsNG.Database.Repo
  alias BorsNG.Database.LinkUserProject
  alias BorsNG.GitHub
  alias BorsNG.Worker.Syncer

  @doc """
  This action is reached via `/webhook/:provider`
  """
  def webhook(conn, %{"provider" => "github"}) do
    event = hd(get_req_header(conn, "x-github-event"))
    do_webhook conn, "github", event
    conn
    |> send_resp(200, "")
  end

  def do_webhook(_conn, "github", "ping") do
    :ok
  end

  def do_webhook(conn, "github", "installation") do
    payload = conn.body_params
    installation_xref = payload["installation"]["id"]
    sender = payload["sender"]
    |> GitHub.User.from_json!()
    |> Syncer.sync_user()
    case payload["action"] do
      "deleted" -> Repo.delete_all(from(
        i in Installation,
        where: i.installation_xref == ^installation_xref
      ))
      "created" -> Repo.transaction(fn ->
        create_installation_by_xref(installation_xref, sender)
      end)
      _ -> nil
    end
    :ok
  end

  def do_webhook(conn, "github", "repositories") do
    payload = conn.body_params
    installation_xref = payload["installation"]["id"]
    installation = Repo.get_by!(<commit_msg>Revert "Update webhook names"<commit_after>defmodule BorsNG.WebhookController do
  @moduledoc """
  The webhook controller responds to HTTP requests
  that are initiated from other services (currently, just GitHub).

  For example, I can run `iex -S mix phoenix.server` and do this:

      iex> # Push state to "GitHub"
      iex> alias BorsNG.GitHub
      iex> alias BorsNG.GitHub.ServerMock
      iex> alias BorsNG.Database
      iex> ServerMock.put_state(%{
      ...>   {:installation, 91} => %{ repos: [
      ...>     %GitHub.Repo{
      ...>       id: 14,
      ...>       name: "test/repo",
      ...>       owner: %{
      ...>         id: 6,
      ...>         login: "bors-fanboi",
      ...>         avatar_url: "data:image/svg+xml,<svg></svg>",
      ...>         type: :user
      ...>       }}
      ...>   ] },
      ...>   {{:installation, 91}, 14} => %{
      ...>     branches: %{},
      ...>     comments: %{1 => []},
      ...>     pulls: %{
      ...>       1 => %GitHub.Pr{
      ...>         number: 1,
      ...>         title: "Test",
      ...>         body: "Mess",
      ...>         state: :open,
      ...>         base_ref: "master",
      ...>         head_sha: "00000001",
      ...>         user: %GitHub.User{
      ...>           id: 6,
      ...>           login: "bors-fanboi",
      ...>           avatar_url: "data:image/svg+xml,<svg></svg>"}}},
      ...>     statuses: %{},
      ...>     files: %{}}})
      iex> # The installation now exists; notify bors about it.
      iex> BorsNG.WebhookController.do_webhook(%{
      ...>   body_params: %{
      ...>     "installation" => %{ "id" => 91 },
      ...>     "sender" => %{
      ...>       "id" => 6,
      ...>       "login" => "bors-fanboi",
      ...>       "avatar_url" => "" },
      ...>     "action" => "created" }}, "github", "installation")
      iex> proj = Database.Repo.get_by!(Database.Project, repo_xref: 14)
      iex> proj.name
      "test/repo"
      iex> # This has also started a (background) sync of all attached patches.
      iex> # Watch it happen in the user interface.
      iex> BorsNG.Worker.Syncer.wait_hot_spin(proj.id)
      iex> patch = Database.Repo.get_by!(Database.Patch, pr_xref: 1)
      iex> patch.title
      "Test"
  """

  use BorsNG.Web, :controller

  require Logger

  @allow_private_repos Confex.fetch_env!(
    :bors_frontend, BorsNG)[:allow_private_repos]

  alias BorsNG.Worker.Attemptor
  alias BorsNG.Worker.Batcher
  alias BorsNG.Worker.BranchDeleter
  alias BorsNG.Command
  alias BorsNG.Database.Installation
  alias BorsNG.Database.Patch
  alias BorsNG.Database.Project
  alias BorsNG.Database.Repo
  alias BorsNG.Database.LinkUserProject
  alias BorsNG.GitHub
  alias BorsNG.Worker.Syncer

  @doc """
  This action is reached via `/webhook/:provider`
  """
  def webhook(conn, %{"provider" => "github"}) do
    event = hd(get_req_header(conn, "x-github-event"))
    do_webhook conn, "github", event
    conn
    |> send_resp(200, "")
  end

  def do_webhook(_conn, "github", "ping") do
    :ok
  end

  # 2 hooks for deprecated events, they will be deleted after November 22, 2017
  def do_webhook(_conn, "github", "integration_installation") do
    :ok
  end

  def do_webhook(_conn, "github", "integration_installation_repositories") do
    :ok
  end

  def do_webhook(conn, "github", "installation") do
    payload = conn.body_params
    installation_xref = payload["installation"]["id"]
    sender = payload["sender"]
    |> GitHub.User.from_json!()
    |> Syncer.sync_user()
    case payload["action"] do
      "deleted" -> Repo.delete_all(from(
        i in Installation,
        where: i.installation_xref == ^installation_xref
      ))
      "created" -> Repo.transaction(fn ->
        create_installation_by_xref(installation_xref, sender)
      end)
      _ -> nil
    end
    :ok
  end

  def do_webhook(conn, "github", "installation_repositories") do
    payload = conn.body_params
    installation_xref = payload["installation"]["id"]
    installation = Repo.get_by!(
{'fraction_non_alphanumeric': 0.16002570694087404, 'fraction_numerical': 0.008611825192802057, 'mean_word_length': 2.0633858267716536, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 147, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3518601', 'n_tokens_mistral': 2740, 'n_tokens_neox': 2620, 'n_words': 555}