Add flag link to profile dropdown view (#12862)
* Add flag link to profile dropdown view * Add JS for flag button on profile * Only show flag button to trusted users * Quick fix for accidental unflagging This will be more properly addressed in a future refactoring. * Update reaction specs * Update spec * Make flagging togglable * Make CodeClimate happy * Revert accidentally changed file * CodeClimate * Update app/javascript/profileDropdown/flagButton.js Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com> * Add JSDoc * Remove second popup * Refactor and add system spec * CodeClimate * Change send to public_send * Address PR feedback by @aitchiss Co-authored-by: Vaidehi Joshi <vaidehi.sj@gmail.com>
This commit is contained in:
parent
a226379c45
commit
28e38cbb7d
6 changed files with 145 additions and 14 deletions
|
|
@ -236,6 +236,7 @@ class StoriesController < ApplicationController
|
|||
# 2nd with 1 badge (!) <-- and that would look off.
|
||||
@badges_limit = 6
|
||||
@profile = @user.profile.decorate
|
||||
@is_user_flagged = Reaction.where(user_id: session_current_user_id, reactable: @user).any?
|
||||
|
||||
set_surrogate_key_header "articles-user-#{@user.id}"
|
||||
set_user_json_ld
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import { initBlock } from '../profileDropdown/blockButton';
|
||||
import { initFlag } from '../profileDropdown/flagButton';
|
||||
|
||||
function initButtons() {
|
||||
initBlock();
|
||||
initFlag();
|
||||
}
|
||||
|
||||
window.InstantClick.on('change', () => {
|
||||
initBlock();
|
||||
initButtons();
|
||||
});
|
||||
|
||||
initBlock();
|
||||
initButtons();
|
||||
|
|
|
|||
67
app/javascript/profileDropdown/flagButton.js
Normal file
67
app/javascript/profileDropdown/flagButton.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* global userData */
|
||||
/* eslint-disable no-alert */
|
||||
/**
|
||||
* Adds a flag button visible only to trusted users on profile pages.
|
||||
* @function initFlag
|
||||
* @returns {(void|undefined)} This function has no useable return value.
|
||||
*/
|
||||
export function initFlag() {
|
||||
const flagButton = document.getElementById(
|
||||
'user-profile-dropdownmenu-flag-button',
|
||||
);
|
||||
|
||||
if (!flagButton) {
|
||||
// button not always present when this is called
|
||||
return;
|
||||
}
|
||||
|
||||
const user = userData();
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { profileUserId, profileUserName } = flagButton.dataset;
|
||||
let isUserFlagged = flagButton.dataset.isUserFlagged === 'true';
|
||||
const trustedOrAdmin = user.trusted || user.admin;
|
||||
|
||||
if (!trustedOrAdmin || user.id === parseInt(profileUserId, 10)) {
|
||||
flagButton.remove();
|
||||
}
|
||||
|
||||
function flag() {
|
||||
const confirmFlag = window.confirm(
|
||||
isUserFlagged
|
||||
? 'Are you sure you want to unflag this person? This will make all of their posts visible again.'
|
||||
: 'Are you sure you want to flag this person? This will make all of their posts less visible.',
|
||||
);
|
||||
|
||||
if (confirmFlag) {
|
||||
fetch('/reactions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-Token': window.csrfToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
reactable_type: 'User',
|
||||
category: 'vomit',
|
||||
reactable_id: profileUserId,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
if (response.result === 'create') {
|
||||
isUserFlagged = true;
|
||||
flagButton.innerHTML = `Unflag ${profileUserName}`;
|
||||
} else {
|
||||
isUserFlagged = false;
|
||||
flagButton.innerHTML = `Flag ${profileUserName}`;
|
||||
}
|
||||
})
|
||||
.catch((e) => window.alert(`Something went wrong: ${e}`));
|
||||
}
|
||||
}
|
||||
|
||||
flagButton.addEventListener('click', flag);
|
||||
}
|
||||
/* eslint-enable no-alert */
|
||||
|
|
@ -33,8 +33,17 @@
|
|||
</button>
|
||||
|
||||
<div id="user-profile-dropdownmenu" class="crayons-dropdown top-100 right-0 p-1">
|
||||
<a href="javascript:void(0);" id="user-profile-dropdownmenu-block-button" data-profile-user-id="<%= @user.id %>" class="border-none crayons-link crayons-link--block">Block @<%= @user.username %></a>
|
||||
<% if user_signed_in? %>
|
||||
<a href="javascript:void(0);" id="user-profile-dropdownmenu-block-button" data-profile-user-id="<%= @user.id %>" class="border-none crayons-link crayons-link--block">Block @<%= @user.username %></a>
|
||||
<a
|
||||
href="javascript:void(0);"
|
||||
id="user-profile-dropdownmenu-flag-button"
|
||||
data-profile-user-id="<%= @user.id %>"
|
||||
data-profile-user-name="@<%= @user.username %>"
|
||||
data-is-user-flagged="<%= @is_user_flagged %>"
|
||||
class="border-none crayons-link crayons-link--block">
|
||||
<%= @flag_status ? "Unflag" : "Flag" %> @<%= @user.username %>
|
||||
</a>
|
||||
<%= javascript_packs_with_chunks_tag "profileDropdown", defer: true %>
|
||||
<% end %>
|
||||
<span class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= user_url(@user) %>"></span>
|
||||
|
|
@ -75,9 +84,9 @@
|
|||
<% end %>
|
||||
<span class="profile-header__meta__item -ml-1">
|
||||
<% Profile.special_social_link_attributes.each do |attribute| %>
|
||||
<% if @user.send(attribute).present? %>
|
||||
<a href="<%= @user.send(attribute) %>" target="_blank" rel="noopener me" class="px-1 align-middle inline-block">
|
||||
<%= inline_svg_tag("#{attribute.gsub("_url","")}.svg", class: "crayons-icon", aria: true, title: "#{attribute.split("_").first.titleize} logo") %>
|
||||
<% if @user.public_send(attribute).present? %>
|
||||
<a href="<%= @user.public_send(attribute) %>" target="_blank" rel="noopener me" class="px-1 align-middle inline-block">
|
||||
<%= inline_svg_tag("#{attribute.gsub('_url', '')}.svg", class: "crayons-icon", aria: true, title: "#{attribute.split('_').first.titleize} logo") %>
|
||||
</a>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -190,17 +190,20 @@ RSpec.describe "Reactions", type: :request do
|
|||
context "when reacting to an article" do
|
||||
before do
|
||||
sign_in user
|
||||
post "/reactions", params: article_params
|
||||
end
|
||||
|
||||
it "creates reaction" do
|
||||
expect(Reaction.last.reactable_id).to eq(article.id)
|
||||
expect do
|
||||
post "/reactions", params: article_params
|
||||
end.to change(Reaction, :count).by(1)
|
||||
end
|
||||
|
||||
it "destroys existing reaction" do
|
||||
# same route to destroy, so sending POST request again
|
||||
post "/reactions", params: article_params
|
||||
expect(Reaction.all.size).to eq(0)
|
||||
expect do
|
||||
# same route to destroy, so sending POST request again
|
||||
post "/reactions", params: article_params
|
||||
end.to change(Reaction, :count).by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -270,17 +273,19 @@ RSpec.describe "Reactions", type: :request do
|
|||
context "when vomiting on a user" do
|
||||
before do
|
||||
sign_in trusted_user
|
||||
post "/reactions", params: user_params
|
||||
end
|
||||
|
||||
it "creates reaction" do
|
||||
expect(Reaction.last.reactable_id).to eq(user.id)
|
||||
expect do
|
||||
post "/reactions", params: user_params
|
||||
end.to change(Reaction, :count).by(1)
|
||||
end
|
||||
|
||||
it "destroys existing reaction" do
|
||||
# same route to destroy, so sending POST request again
|
||||
post "/reactions", params: user_params
|
||||
expect(Reaction.all.size).to eq(0)
|
||||
expect do
|
||||
post "/reactions", params: user_params
|
||||
end.to change(Reaction, :count).by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
43
spec/system/user/trusted_user_flags_user_spec.rb
Normal file
43
spec/system/user/trusted_user_flags_user_spec.rb
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "Flagging users from profile pages", type: :system, js: true do
|
||||
let(:user) { create :user }
|
||||
let(:flag_text) { "Flag @#{user.username}" }
|
||||
|
||||
context "when not logged in" do
|
||||
it "does not show the flag button" do
|
||||
visit user_profile_path(user.username)
|
||||
click_button(id: "user-profile-dropdown")
|
||||
expect(page).not_to have_link(flag_text)
|
||||
end
|
||||
end
|
||||
|
||||
context "when signed in as a non-trusted user" do
|
||||
it "does not show the flag button" do
|
||||
sign_in create(:user)
|
||||
|
||||
visit user_profile_path(user.username)
|
||||
click_button(id: "user-profile-dropdown")
|
||||
expect(page).not_to have_link(flag_text)
|
||||
end
|
||||
end
|
||||
|
||||
context "when signed in as the user" do
|
||||
it "does not show a button for flagging yourself" do
|
||||
sign_in user
|
||||
|
||||
visit user_profile_path(user.username)
|
||||
expect(page).not_to have_selector("user-profile-dropdown")
|
||||
end
|
||||
end
|
||||
|
||||
context "when signed in as a trusted user" do
|
||||
it "allows toggling the flagged status" do
|
||||
sign_in create(:user, :trusted)
|
||||
|
||||
visit user_profile_path(user.username)
|
||||
click_button(id: "user-profile-dropdown")
|
||||
expect(page).to have_link(flag_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue