captain-fact icon indicating copy to clipboard operation
captain-fact copied to clipboard

Reputation log: better record inversed votes

Open Betree opened this issue 4 years ago • 1 comments

Currently, voting down after voting up (or the opposite) just removes the old vote and replaces it with the new one, recording only one UserAction for the new vote. To make sure we register things properly with the reputation, we should record a revert_vote action before recording the new one.

Betree avatar Sep 01 '21 20:09 Betree

Only the first part of the issue was solved in https://github.com/CaptainFact/captain-fact-api/pull/367, we still need a migration to fix the reputation for past entries.

defmodule :"Elixir.DB.Repo.Migrations.Add-missing-revert-vote-actions" do
  use Ecto.Migration

  def up do
    Ecto.Adapters.SQL.query!(DB.Repo, """
      WITH vote_actions AS (
        SELECT user_id, entity, entity_id
        FROM users_actions
        WHERE entity IN (4,5) -- comments + sourced comments
        AND "type" IN (9,10,12,13) -- Votes up/down AND their revert actions
        AND entity_id IS NOT NULL -- TODO: See what TO DO WITH deleted comments
        GROUP BY user_id, entity, entity_id
        HAVING COUNT(*) > 1
      ) SELECT ua.*
      FROM users_actions ua
      INNER JOIN vote_actions va
        ON va.user_id = ua.user_id
        AND va.entity = ua.entity
        AND va.entity_id = ua.entity_id
      ORDER BY user_id ASC, entity ASC, entity_id ASC, inserted_at ASC, id ASC
    """)
    |> Map.get(:rows)
    |> Enum.group_by(fn action -> "#{action.user_id}-#{action.entity}-#{action.entity_id}" end)
    |> Enum.each(fn {_key, actions} -> analyze_actions(actions) end)

    # TODO: Need to test with real data (local dev doesn't have occurences)

    raise "abort"
  end

  def down do
    # No rollack
  end

  defp analyze_actions([action | next_actions], prev_action = nil) do
    check_action(action, prev_action)
    analyze_actions(next_actions, action)
  end

  defp analyze_actions([], _prev_action = nil) do
    nil
  end

  # Triggered when a vote up is found right after a vote down
  defp check_action(action, prev_action)
       when not is_nil(prev_action) and prev_action.type == 10 and action.type == 9 do
    action.user_id
    |> CF.Actions.ActionCreator.action_revert_vote(action.video_id, :revert_vote_down, comment)
    |> Ecto.Changeset.change(inserted_at: DateTime.add(prev_action.inserted_at, 1, :microsecond))
    |> DB.Repo.insert()
  end

  defp check_action(_action, _prev_action) do
    nil
  end
end

Betree avatar Sep 07 '21 17:09 Betree