Add API route to (un)block a user
This commit is contained in:
parent
6278925ce2
commit
2d28ddc1ef
8 changed files with 198 additions and 59 deletions
|
|
@ -17,6 +17,10 @@ module Api
|
||||||
require_access_token %w[contacts:read]
|
require_access_token %w[contacts:read]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
before_action only: %i[block] do
|
||||||
|
require_access_token %w[contacts:modify]
|
||||||
|
end
|
||||||
|
|
||||||
before_action only: %i[show] do
|
before_action only: %i[show] do
|
||||||
require_access_token %w[profile]
|
require_access_token %w[profile]
|
||||||
end
|
end
|
||||||
|
|
@ -81,6 +85,28 @@ module Api
|
||||||
render_paged_api_response posts_page
|
render_paged_api_response posts_page
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def block
|
||||||
|
person = Person.find_by!(guid: params[:user_id])
|
||||||
|
service = BlockService.new(current_user)
|
||||||
|
if request.request_method_symbol == :post
|
||||||
|
begin
|
||||||
|
service.block(person)
|
||||||
|
head :created
|
||||||
|
rescue ActiveRecord::RecordNotUnique
|
||||||
|
render_error 409, "User is already blocked"
|
||||||
|
end
|
||||||
|
elsif request.request_method_symbol == :delete
|
||||||
|
begin
|
||||||
|
service.unblock(person)
|
||||||
|
head :no_content
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_error 410, "User is not blocked"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise AbstractController::ActionNotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def aspects_service
|
def aspects_service
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ class BlocksController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
|
|
||||||
def create
|
def create
|
||||||
block = current_user.blocks.new(block_params)
|
begin
|
||||||
|
block_service.block(Person.find_by!(id: block_params[:person_id]))
|
||||||
send_message(block) if block.save
|
rescue ActiveRecord::RecordNotUnique
|
||||||
|
end
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
|
|
@ -15,12 +16,12 @@ class BlocksController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
block = current_user.blocks.find_by(id: params[:id])
|
notice = nil
|
||||||
notice = if block&.delete
|
begin
|
||||||
ContactRetraction.for(block).defer_dispatch(current_user)
|
block_service.remove_block(current_user.blocks.find_by!(id: params[:id]))
|
||||||
{notice: t("blocks.destroy.success")}
|
notice = {notice: t("blocks.destroy.success")}
|
||||||
else
|
rescue ActiveRecord::RecordNotFound
|
||||||
{error: t("blocks.destroy.failure")}
|
notice = {error: t("blocks.destroy.failure")}
|
||||||
end
|
end
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|
@ -31,17 +32,11 @@ class BlocksController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def send_message(block)
|
|
||||||
contact = current_user.contact_for(block.person)
|
|
||||||
|
|
||||||
if contact
|
|
||||||
current_user.disconnect(contact)
|
|
||||||
elsif block.person.remote?
|
|
||||||
Diaspora::Federation::Dispatcher.defer_dispatch(current_user, block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def block_params
|
def block_params
|
||||||
params.require(:block).permit(:person_id)
|
params.require(:block).permit(:person_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def block_service
|
||||||
|
BlockService.new(current_user)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
29
app/services/block_service.rb
Normal file
29
app/services/block_service.rb
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class BlockService
|
||||||
|
def initialize(user)
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def block(person)
|
||||||
|
raise ActiveRecord::RecordNotUnique if @user.blocks.exists?(person: person)
|
||||||
|
|
||||||
|
block = @user.blocks.create!(person: person)
|
||||||
|
contact = @user.contact_for(person)
|
||||||
|
|
||||||
|
if contact
|
||||||
|
@user.disconnect(contact)
|
||||||
|
elsif block.person.remote?
|
||||||
|
Diaspora::Federation::Dispatcher.defer_dispatch(@user, block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unblock(person)
|
||||||
|
remove_block(@user.blocks.find_by!(person: person))
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_block(block)
|
||||||
|
block.destroy
|
||||||
|
ContactRetraction.for(block).defer_dispatch(@user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -255,6 +255,8 @@ Rails.application.routes.draw do
|
||||||
get :contacts
|
get :contacts
|
||||||
get :photos
|
get :photos
|
||||||
get :posts
|
get :posts
|
||||||
|
post :block
|
||||||
|
delete :block
|
||||||
end
|
end
|
||||||
resources :tag_followings, only: %i[index create destroy]
|
resources :tag_followings, only: %i[index create destroy]
|
||||||
get "search/users" => "search#user_index", :as => "user_index"
|
get "search/users" => "search#user_index", :as => "user_index"
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,6 @@ describe BlocksController, :type => :controller do
|
||||||
post :create, params: {block: {person_id: eve.person.id}}, format: :json
|
post :create, params: {block: {person_id: eve.person.id}}, format: :json
|
||||||
expect(response.status).to eq(204)
|
expect(response.status).to eq(204)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "calls #send_message" do
|
|
||||||
expect(@controller).to receive(:send_message).with(an_instance_of(Block))
|
|
||||||
post :create, params: {block: {person_id: bob.person.id}}, format: :json
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#destroy" do
|
describe "#destroy" do
|
||||||
|
|
@ -66,33 +61,4 @@ describe BlocksController, :type => :controller do
|
||||||
expect(flash[:error]).to eq(I18n.t("blocks.destroy.failure"))
|
expect(flash[:error]).to eq(I18n.t("blocks.destroy.failure"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#send_message" do
|
|
||||||
before do
|
|
||||||
allow(@controller).to receive(:current_user).and_return(alice)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls disconnect if there is a contact for a given user" do
|
|
||||||
block = alice.blocks.create(person: bob.person)
|
|
||||||
contact = alice.contact_for(bob.person)
|
|
||||||
expect(alice).to receive(:contact_for).and_return(contact)
|
|
||||||
expect(alice).to receive(:disconnect).with(contact)
|
|
||||||
expect(Diaspora::Federation::Dispatcher).not_to receive(:defer_dispatch)
|
|
||||||
@controller.send(:send_message, block)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "queues a message with the block if the person is remote and there is no contact for a given user" do
|
|
||||||
block = alice.blocks.create(person: remote_raphael)
|
|
||||||
expect(alice).not_to receive(:disconnect)
|
|
||||||
expect(Diaspora::Federation::Dispatcher).to receive(:defer_dispatch).with(alice, block)
|
|
||||||
@controller.send(:send_message, block)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does nothing if the person is local and there is no contact for a given user" do
|
|
||||||
block = alice.blocks.create(person: eve.person)
|
|
||||||
expect(alice).not_to receive(:disconnect)
|
|
||||||
expect(Diaspora::Federation::Dispatcher).not_to receive(:defer_dispatch)
|
|
||||||
@controller.send(:send_message, block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -199,15 +199,15 @@ describe Api::V1::NotificationsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "fails" do
|
context "fails" do
|
||||||
it "with proper invalid GUID" do
|
it "with invalid GUID" do
|
||||||
patch(
|
patch(
|
||||||
api_v1_notification_path("999_999_999"),
|
api_v1_notification_path("999_999_999"),
|
||||||
params: {access_token: access_token}
|
params: {read: true, access_token: access_token}
|
||||||
)
|
)
|
||||||
confirm_api_error(response, 422, "Could not process the notifications request")
|
confirm_api_error(response, 404, "Notification with provided guid could not be found")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "with proper missing read field" do
|
it "with missing read field" do
|
||||||
patch(
|
patch(
|
||||||
api_v1_notification_path(@notification.guid),
|
api_v1_notification_path(@notification.guid),
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ describe Api::V1::UsersController do
|
||||||
include PeopleHelper
|
include PeopleHelper
|
||||||
|
|
||||||
let(:full_scopes) {
|
let(:full_scopes) {
|
||||||
%w[openid public:read public:modify private:read private:modify contacts:read profile profile:modify]
|
%w[openid public:read public:modify private:read private:modify
|
||||||
|
contacts:read contacts:modify profile profile:modify]
|
||||||
}
|
}
|
||||||
|
|
||||||
let(:auth) {
|
let(:auth) {
|
||||||
|
|
@ -509,6 +510,99 @@ describe Api::V1::UsersController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#block" do
|
||||||
|
let(:person) { FactoryGirl.create(:user).person }
|
||||||
|
|
||||||
|
context "success" do
|
||||||
|
it "with proper credentials and flags" do
|
||||||
|
auth.user.share_with(person, auth.user.aspects.create(name: "Test"))
|
||||||
|
person.owner.share_with(auth.user.person, person.owner.aspects.create(name: "Victims"))
|
||||||
|
|
||||||
|
post(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(201)
|
||||||
|
expect(auth.user.blocks.exists?(person_id: person.id)).to be(true)
|
||||||
|
contact = auth.user.contact_for(person)
|
||||||
|
expect(contact.receiving).to be(false)
|
||||||
|
|
||||||
|
delete(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(204)
|
||||||
|
expect(auth.user.blocks.exists?(person: person)).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "fails" do
|
||||||
|
it "with invalid GUID" do
|
||||||
|
post(
|
||||||
|
api_v1_user_block_path("999_999_999"),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "User not found")
|
||||||
|
|
||||||
|
delete(
|
||||||
|
api_v1_user_block_path("999_999_999"),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 404, "User not found")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "to block already blocked user" do
|
||||||
|
post(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(201)
|
||||||
|
|
||||||
|
post(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 409, "User is already blocked")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "to unblock not blocked user" do
|
||||||
|
delete(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token}
|
||||||
|
)
|
||||||
|
confirm_api_error(response, 410, "User is not blocked")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "with insufficient credentials" do
|
||||||
|
post(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token_minimum_scopes}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
|
||||||
|
delete(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: access_token_minimum_scopes}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "with improper credentials" do
|
||||||
|
post(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: "999_999_999"}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(401)
|
||||||
|
|
||||||
|
delete(
|
||||||
|
api_v1_user_block_path(person.guid),
|
||||||
|
params: {access_token: "999_999_999"}
|
||||||
|
)
|
||||||
|
expect(response.status).to eq(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def confirm_self_data_format(json)
|
def confirm_self_data_format(json)
|
||||||
confirm_common_profile_elements(json)
|
confirm_common_profile_elements(json)
|
||||||
confirm_profile_details(json)
|
confirm_profile_details(json)
|
||||||
|
|
|
||||||
27
spec/services/block_serivce_spec.rb
Normal file
27
spec/services/block_serivce_spec.rb
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe BlockService do
|
||||||
|
describe "#block" do
|
||||||
|
let(:service) { BlockService.new(alice) }
|
||||||
|
|
||||||
|
it "calls disconnect if there is a contact for a given user" do
|
||||||
|
contact = alice.contact_for(bob.person)
|
||||||
|
expect(alice).to receive(:contact_for).and_return(contact)
|
||||||
|
expect(alice).to receive(:disconnect).with(contact)
|
||||||
|
expect(Diaspora::Federation::Dispatcher).not_to receive(:defer_dispatch)
|
||||||
|
service.block(bob.person)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "queues a message with the block if the person is remote and there is no contact for a given user" do
|
||||||
|
expect(alice).not_to receive(:disconnect)
|
||||||
|
expect(Diaspora::Federation::Dispatcher).to receive(:defer_dispatch)
|
||||||
|
service.block(remote_raphael)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does nothing if the person is local and there is no contact for a given user" do
|
||||||
|
expect(alice).not_to receive(:disconnect)
|
||||||
|
expect(Diaspora::Federation::Dispatcher).not_to receive(:defer_dispatch)
|
||||||
|
service.block(eve.person)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue