Merge branch 'bugfix/980-polls-double-vote' into 'develop'
authorlain <lain@soykaf.club>
Sat, 15 Jun 2019 15:13:48 +0000 (15:13 +0000)
committerlain <lain@soykaf.club>
Sat, 15 Jun 2019 15:13:48 +0000 (15:13 +0000)
MastodonAPI Controller: Band-Aid double vote problem.

See merge request pleroma/pleroma!1275

1  2 
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex

index eea4040ec754f4232033d5149f25abbd009d9c2a,ed1aa9db2d25cfb3aa8ecd97dec6bb2f0a874837..457709578f7fba823573d7f6f9d5495481910144
@@@ -136,14 -136,6 +136,14 @@@ defmodule Pleroma.Web.MastodonAPI.Masto
            _ -> :error
          end
        end)
 +      |> add_if_present(params, "pleroma_background_image", :background, fn value ->
 +        with %Plug.Upload{} <- value,
 +             {:ok, object} <- ActivityPub.upload(value, type: :background) do
 +          {:ok, object.data}
 +        else
 +          _ -> :error
 +        end
 +      end)
        |> Map.put(:emoji, user_info_emojis)
  
      info_cng = User.Info.profile_update(user.info, info_params)
    end
  
    def verify_credentials(%{assigns: %{user: user}} = conn, _) do
 +    chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
 +
      account =
 -      AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
 +      AccountView.render("account.json", %{
 +        user: user,
 +        for: user,
 +        with_pleroma_settings: true,
 +        with_chat_token: chat_token
 +      })
  
      json(conn, account)
    end
      end
    end
  
+   defp get_cached_vote_or_vote(user, object, choices) do
+     idempotency_key = "polls:#{user.id}:#{object.data["id"]}"
+     {_, res} =
+       Cachex.fetch(:idempotency_cache, idempotency_key, fn _ ->
+         case CommonAPI.vote(user, object, choices) do
+           {:error, _message} = res -> {:ignore, res}
+           res -> {:commit, res}
+         end
+       end)
+     res
+   end
    def poll_vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choices}) do
      with %Object{} = object <- Object.get_by_id(id),
           true <- object.data["type"] == "Question",
           %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
           true <- Visibility.visible_for_user?(activity, user),
-          {:ok, _activities, object} <- CommonAPI.vote(user, object, choices) do
+          {:ok, _activities, object} <- get_cached_vote_or_vote(user, object, choices) do
        conn
        |> put_view(StatusView)
        |> try_render("poll.json", %{object: object, for: user})
      end
    end
  
 -  def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
 -    accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
 -    statuses = Activity.search(user, query)
 -    tags_path = Web.base_url() <> "/tag/"
 -
 -    tags =
 -      query
 -      |> String.split()
 -      |> Enum.uniq()
 -      |> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
 -      |> Enum.map(fn tag -> String.slice(tag, 1..-1) end)
 -      |> Enum.map(fn tag -> %{name: tag, url: tags_path <> tag} end)
 -
 -    res = %{
 -      "accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
 -      "statuses" =>
 -        StatusView.render("index.json", activities: statuses, for: user, as: :activity),
 -      "hashtags" => tags
 -    }
 -
 -    json(conn, res)
 -  end
 -
 -  def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
 -    accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
 -    statuses = Activity.search(user, query)
 -
 -    tags =
 -      query
 -      |> String.split()
 -      |> Enum.uniq()
 -      |> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
 -      |> Enum.map(fn tag -> String.slice(tag, 1..-1) end)
 -
 -    res = %{
 -      "accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
 -      "statuses" =>
 -        StatusView.render("index.json", activities: statuses, for: user, as: :activity),
 -      "hashtags" => tags
 -    }
 -
 -    json(conn, res)
 -  end
 -
 -  def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
 -    accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
 -
 -    res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
 -
 -    json(conn, res)
 -  end
 -
    def favourites(%{assigns: %{user: user}} = conn, params) do
      params =
        params