little refactor and tests
for voted & own_votes fields in polls
This commit is contained in:
		
							parent
							
								
									6bfd497f4a
								
							
						
					
					
						commit
						3f3d64acbf
					
				
					 3 changed files with 101 additions and 24 deletions
				
			
		| 
						 | 
				
			
			@ -10,9 +10,8 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
 | 
			
		|||
  def render("show.json", %{object: object, multiple: multiple, options: options} = params) do
 | 
			
		||||
    {end_time, expired} = end_time_and_expired(object)
 | 
			
		||||
    {options, votes_count} = options_and_votes_count(options)
 | 
			
		||||
    {voted, own_votes} = voted_and_own_votes(params, options)
 | 
			
		||||
 | 
			
		||||
    %{
 | 
			
		||||
    poll = %{
 | 
			
		||||
      # Mastodon uses separate ids for polls, but an object can't have
 | 
			
		||||
      # more than one poll embedded so object id is fine
 | 
			
		||||
      id: to_string(object.id),
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +21,16 @@ def render("show.json", %{object: object, multiple: multiple, options: options}
 | 
			
		|||
      votes_count: votes_count,
 | 
			
		||||
      voters_count: voters_count(object),
 | 
			
		||||
      options: options,
 | 
			
		||||
      voted: voted,
 | 
			
		||||
      own_votes: own_votes,
 | 
			
		||||
      emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if params[:for] do
 | 
			
		||||
      # if a user is not authenticated Mastodon doesn't include `voted` & `own_votes` keys in response
 | 
			
		||||
      {voted, own_votes} = voted_and_own_votes(params, options)
 | 
			
		||||
      Map.merge(poll, %{voted: voted, own_votes: own_votes})
 | 
			
		||||
    else
 | 
			
		||||
      poll
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def render("show.json", %{object: object} = params) do
 | 
			
		||||
| 
						 | 
				
			
			@ -70,21 +75,25 @@ defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do
 | 
			
		|||
  defp voters_count(_), do: 0
 | 
			
		||||
 | 
			
		||||
  defp voted_and_own_votes(%{object: object} = params, options) do
 | 
			
		||||
    options = options |> Enum.map(fn x -> Map.get(x, :title) end)
 | 
			
		||||
 | 
			
		||||
    if params[:for] do
 | 
			
		||||
      existing_votes =
 | 
			
		||||
        Pleroma.Web.ActivityPub.Utils.get_existing_votes(params[:for].ap_id, object)
 | 
			
		||||
 | 
			
		||||
      own_votes =
 | 
			
		||||
        for vote <- existing_votes do
 | 
			
		||||
          data = Map.get(vote, :object) |> Map.get(:data)
 | 
			
		||||
 | 
			
		||||
          Enum.find_index(options, fn x -> x == data["name"] end)
 | 
			
		||||
        end || []
 | 
			
		||||
 | 
			
		||||
      voted = existing_votes != [] or params[:for].ap_id == object.data["actor"]
 | 
			
		||||
 | 
			
		||||
      own_votes =
 | 
			
		||||
        if voted do
 | 
			
		||||
          titles = Enum.map(options, & &1[:title])
 | 
			
		||||
 | 
			
		||||
          Enum.reduce(existing_votes, [], fn vote, acc ->
 | 
			
		||||
            data = vote |> Map.get(:object) |> Map.get(:data)
 | 
			
		||||
            index = Enum.find_index(titles, &(&1 == data["name"]))
 | 
			
		||||
            [index | acc]
 | 
			
		||||
          end)
 | 
			
		||||
        else
 | 
			
		||||
          []
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      {voted, own_votes}
 | 
			
		||||
    else
 | 
			
		||||
      {false, []}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,78 @@ test "does not expose polls for private statuses", %{conn: conn} do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "own_votes" do
 | 
			
		||||
    %{conn: conn} = oauth_access(["write:statuses", "read:statuses"])
 | 
			
		||||
 | 
			
		||||
    other_user = insert(:user)
 | 
			
		||||
 | 
			
		||||
    {:ok, activity} =
 | 
			
		||||
      CommonAPI.post(other_user, %{
 | 
			
		||||
        status: "A very delicious sandwich",
 | 
			
		||||
        poll: %{
 | 
			
		||||
          options: ["Lettuce", "Grilled Bacon", "Tomato"],
 | 
			
		||||
          expires_in: 20,
 | 
			
		||||
          multiple: true
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
    object = Object.normalize(activity, fetch: false)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_req_header("content-type", "application/json")
 | 
			
		||||
    |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 2]})
 | 
			
		||||
    |> json_response_and_validate_schema(200)
 | 
			
		||||
 | 
			
		||||
    object = Object.get_by_id(object.id)
 | 
			
		||||
 | 
			
		||||
    assert [
 | 
			
		||||
             %{
 | 
			
		||||
               "name" => "Lettuce",
 | 
			
		||||
               "replies" => %{"totalItems" => 1, "type" => "Collection"},
 | 
			
		||||
               "type" => "Note"
 | 
			
		||||
             },
 | 
			
		||||
             %{
 | 
			
		||||
               "name" => "Grilled Bacon",
 | 
			
		||||
               "replies" => %{"totalItems" => 0, "type" => "Collection"},
 | 
			
		||||
               "type" => "Note"
 | 
			
		||||
             },
 | 
			
		||||
             %{
 | 
			
		||||
               "name" => "Tomato",
 | 
			
		||||
               "replies" => %{"totalItems" => 1, "type" => "Collection"},
 | 
			
		||||
               "type" => "Note"
 | 
			
		||||
             }
 | 
			
		||||
           ] == object.data["anyOf"]
 | 
			
		||||
 | 
			
		||||
    assert %{"replies" => %{"totalItems" => 0}} =
 | 
			
		||||
             Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == "Grilled Bacon" end)
 | 
			
		||||
 | 
			
		||||
    Enum.each(["Lettuce", "Tomato"], fn title ->
 | 
			
		||||
      %{"replies" => %{"totalItems" => total_items}} =
 | 
			
		||||
        Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == title end)
 | 
			
		||||
 | 
			
		||||
      assert total_items == 1
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    assert %{
 | 
			
		||||
             "own_votes" => own_votes,
 | 
			
		||||
             "voted" => true
 | 
			
		||||
           } =
 | 
			
		||||
             conn
 | 
			
		||||
             |> get("/api/v1/polls/#{object.id}")
 | 
			
		||||
             |> json_response_and_validate_schema(200)
 | 
			
		||||
 | 
			
		||||
    assert 0 in own_votes
 | 
			
		||||
    assert 2 in own_votes
 | 
			
		||||
    # for non authenticated user
 | 
			
		||||
    response =
 | 
			
		||||
      build_conn()
 | 
			
		||||
      |> get("/api/v1/polls/#{object.id}")
 | 
			
		||||
      |> json_response_and_validate_schema(200)
 | 
			
		||||
 | 
			
		||||
    refute Map.has_key?(response, "own_votes")
 | 
			
		||||
    refute Map.has_key?(response, "voted")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "POST /api/v1/polls/:id/votes" do
 | 
			
		||||
    setup do: oauth_access(["write:statuses"])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,12 +137,11 @@ test "votes are added to the poll", %{conn: conn} do
 | 
			
		|||
 | 
			
		||||
      object = Object.normalize(activity, fetch: false)
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("content-type", "application/json")
 | 
			
		||||
        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
 | 
			
		||||
      conn
 | 
			
		||||
      |> put_req_header("content-type", "application/json")
 | 
			
		||||
      |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
 | 
			
		||||
      |> json_response_and_validate_schema(200)
 | 
			
		||||
 | 
			
		||||
      assert json_response_and_validate_schema(conn, 200)
 | 
			
		||||
      object = Object.get_by_id(object.id)
 | 
			
		||||
 | 
			
		||||
      assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,10 +42,8 @@ test "renders a poll" do
 | 
			
		|||
        %{title: "yes", votes_count: 0},
 | 
			
		||||
        %{title: "why are you even asking?", votes_count: 0}
 | 
			
		||||
      ],
 | 
			
		||||
      voted: false,
 | 
			
		||||
      votes_count: 0,
 | 
			
		||||
      voters_count: 0,
 | 
			
		||||
      own_votes: []
 | 
			
		||||
      voters_count: 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = PollView.render("show.json", %{object: object})
 | 
			
		||||
| 
						 | 
				
			
			@ -124,10 +122,9 @@ test "detects vote status" do
 | 
			
		|||
 | 
			
		||||
    result = PollView.render("show.json", %{object: object, for: other_user})
 | 
			
		||||
 | 
			
		||||
    _own_votes = result[:own_votes]
 | 
			
		||||
 | 
			
		||||
    assert result[:voted] == true
 | 
			
		||||
    assert own_votes = [1, 2]
 | 
			
		||||
    assert 1 in result[:own_votes]
 | 
			
		||||
    assert 2 in result[:own_votes]
 | 
			
		||||
    assert Enum.at(result[:options], 1)[:votes_count] == 1
 | 
			
		||||
    assert Enum.at(result[:options], 2)[:votes_count] == 1
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue