[deploy] Bulk Fetch Follow Button Data for Users (#7676)

This commit is contained in:
Molly Struve 2020-05-08 13:58:58 -05:00 committed by GitHub
parent 4eb2f05387
commit ea1d38d3b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 156 additions and 7 deletions

View file

@ -16,6 +16,7 @@ function callInitalizers(){
initializeAllTagEditButtons();
}
initializeAllFollowButts();
initializeUserFollowButts();
initializeReadingListIcons();
initializeSponsorshipVisibility();
if ( document.getElementById("sidebar-additional") ) {

View file

@ -1,4 +1,4 @@
'use strict';
/* global initializeUserFollowButts */
function initializeAdditionalContentBoxes() {
var el = document.getElementById('additional-content-area');
@ -32,6 +32,7 @@ function initializeAdditionalContentBoxes() {
el.innerHTML = html;
initializeReadingListIcons();
initializeAllFollowButts();
initializeUserFollowButts();
initializeSponsorshipVisibility();
});
} else {

View file

@ -1,10 +1,59 @@
function initializeAllFollowButts() {
var followButts = document.getElementsByClassName('follow-action-button');
for (var i = 0; i < followButts.length; i++) {
initializeFollowButt(followButts[i]);
if (!followButts[i].className.includes("follow-user")) {
initializeFollowButt(followButts[i]);
};
}
}
function fetchUserFollowStatuses(idButtonHash) {
const url = new URL("/follows/bulk_show", document.location);
const searchParams = new URLSearchParams();
Object.keys(idButtonHash).forEach((id) => {
searchParams.append("ids[]", id);
});
searchParams.append("followable_type", "User");
url.search = searchParams;
fetch(url, {
method: 'GET',
headers: {
Accept: 'application/json',
'X-CSRF-Token': window.csrfToken,
'Content-Type': 'application/json',
},
credentials: 'same-origin',
}).then((response) => response.json())
.then((idStatuses) => {
Object.keys(idStatuses).forEach(function(id) {
addButtClickHandle(idStatuses[id], idButtonHash[id]);
})
});
}
function initializeUserFollowButtons(buttons) {
if (buttons.length > 0) {
var userIds = {};
for (var i = 0; i < buttons.length; i++) {
var userStatus = document.body.getAttribute('data-user-status');
if (userStatus === 'logged-out') {
addModalEventListener(buttons[i]);
} else {
var userId = JSON.parse(buttons[i].dataset.info).id
userIds[userId] = buttons[i];
}
}
if (Object.keys(userIds).length > 0) { fetchUserFollowStatuses(userIds); }
}
}
function initializeUserFollowButts() {
var buttons = document.getElementsByClassName('follow-action-button follow-user');
initializeUserFollowButtons(buttons);
}
//private
function initializeFollowButt(butt) {

View file

@ -1,4 +1,4 @@
'use strict';
/* global initializeUserFollowButts */
function initializeLocalStorageRender() {
try {
@ -8,6 +8,7 @@ function initializeLocalStorageRender() {
initializeBaseUserData();
initializeReadingListIcons();
initializeAllFollowButts();
initializeUserFollowButts();
initializeSponsorshipVisibility();
}
} catch (err) {

View file

@ -84,7 +84,7 @@ function buildArticleHTML(article) {
<span class="bm-success">SAVED</span>\
</button>'
} else if (article.class_name === "User") {
saveButton = '<button type="button" style="width: 122px" class="article-engagement-count engage-button follow-action-button"\
saveButton = '<button type="button" style="width: 122px" class="article-engagement-count engage-button follow-action-button follow-user"\
data-info=\'{"id":'+article.id+',"className":"User"}\' data-follow-action-button>\
&nbsp;\
</button>'

View file

@ -25,6 +25,29 @@ class FollowsController < ApplicationController
end
end
def bulk_show
skip_authorization
render(plain: "not-logged-in") && return unless current_user
response = params.require(:ids).map(&:to_i).each_with_object({}) do |id, hsh|
hsh[id] = if current_user.id == id
"self"
else
following_them_check = FollowChecker.new(current_user, params[:followable_type], id).cached_follow_check
following_you_check = FollowChecker.new(User.find_by(id: id), params[:followable_type], current_user.id).cached_follow_check
if following_them_check && following_you_check
"mutual"
elsif following_you_check
"follow-back"
else
following_them_check.to_s
end
end
end
render json: response
end
def create
authorize Follow

View file

@ -25,7 +25,8 @@ module Search
"comments_count" => source["comments_count"],
"badge_achievements_count" => source["badge_achievements_count"],
"last_comment_at" => source["last_comment_at"],
"roles" => source["roles"]
"roles" => source["roles"],
"user_id" => source["id"]
}
end

View file

@ -116,6 +116,7 @@
document.getElementById("substories").innerHTML = resultDivs.join("");
initializeReadingListIcons();
initializeAllFollowButts();
initializeUserFollowButts();
document.getElementById("substories").classList.add("search-results-loaded");
if (content.result.length == 0) {
document.getElementById("substories").innerHTML = '<div class="query-results-nothing">No results match that query</div>'

View file

@ -1,7 +1,7 @@
import querystring;
sub vcl_recv {
# return this URL with only the parameters that match this regular expression
if (req.url !~ "/internal/" && req.url !~ "/search/") {
if (req.url !~ "/internal/" && req.url !~ "/search/" && req.url !~ "/bulk_show") {
set req.url = querystring.regfilter_except(req.url, "^(a_id|args|article_id|article_ids|articles|asc|callback_url|category|chat_channel_id|client_id|code|collection_id|commentable_id|commentable_type|confirmation_token|created_at|end|filter|followable_id|followable_type|fork_id|i|key|message_offset|name|oauth_token|oauth_verifier|offset|org_id|organization_id|p|page|per_page|prefill|preview|purchaser|reactable_ids|redirect_uri|reported_url|reporter_username|response_type|scope|search|signature|sort|start|state|status|tag|tag_list|top|type_of|url|username|ut|verb)$");
}
}

View file

@ -176,7 +176,11 @@ Rails.application.routes.draw do
resources :feedback_messages, only: %i[index create]
resources :organizations, only: %i[update create]
resources :followed_articles, only: [:index]
resources :follows, only: %i[show create update]
resources :follows, only: %i[show create update] do
collection do
get "/bulk_show", to: "follows#bulk_show"
end
end
resources :image_uploads, only: [:create]
resources :blocks
resources :notifications, only: [:index]

View file

@ -0,0 +1,42 @@
require "rails_helper"
RSpec.describe "Follows #bulk_show", type: :request do
let(:current_user) { create(:user) }
let(:followed_user) { create(:user) }
let(:not_followed_user) { create(:user) }
let(:follow_back_user) { create(:user) }
let(:mutal_follow_user) { create(:user) }
context "when ids are present" do
before do
sign_in current_user
current_user.follow(followed_user)
current_user.follow(mutal_follow_user)
follow_back_user.follow(current_user)
mutal_follow_user.follow(current_user)
end
it "returns correct following values" do
ids = [followed_user.id, not_followed_user.id, current_user.id, follow_back_user.id, mutal_follow_user.id]
get bulk_show_follows_path, params: { ids: ids }
expect(response.parsed_body[current_user.id.to_s]).to eq("self")
expect(response.parsed_body[followed_user.id.to_s]).to eq("true")
expect(response.parsed_body[not_followed_user.id.to_s]).to eq("false")
expect(response.parsed_body[follow_back_user.id.to_s]).to eq("follow-back")
expect(response.parsed_body[mutal_follow_user.id.to_s]).to eq("mutual")
end
end
it "without ids raises a missing param error" do
sign_in current_user
expect { get bulk_show_follows_path, params: {} }.to raise_error(ActionController::ParameterMissing)
end
it "rejects unless logged-in" do
sign_out(current_user)
get bulk_show_follows_path
expect(response.body).to eq("not-logged-in")
end
end

View file

@ -0,0 +1,26 @@
require "rails_helper"
RSpec.describe "User searches users", type: :system do
let(:current_user) { create(:user) }
let(:followed_user) { create(:user) }
let(:not_followed_user) { create(:user) }
let(:follow_back_user) { create(:user) }
before do
sign_in current_user
current_user.follow(followed_user)
follow_back_user.follow(current_user)
[current_user, followed_user, not_followed_user, follow_back_user].each(&:index_to_elasticsearch_inline)
Search::User.refresh_index
end
it "shows the correct follow buttons", js: true, elasticsearch: "User" do
stub_request(:post, "http://www.google-analytics.com/collect")
visit "/search?q=&filters=class_name:User"
expect(JSON.parse(find_button("EDIT PROFILE")["data-info"])["id"]).to eq(current_user.id)
expect(JSON.parse(find_button("FOLLOWING")["data-info"])["id"]).to eq(followed_user.id)
expect(JSON.parse(find_button("+ FOLLOW")["data-info"])["id"]).to eq(not_followed_user.id)
expect(JSON.parse(find_button("+ FOLLOW BACK")["data-info"])["id"]).to eq(follow_back_user.id)
end
end