refactoring delete from services

This commit is contained in:
Benjamin Neff 2016-06-13 02:20:57 +02:00
parent dee8bc6f0e
commit 2476b74dbe
14 changed files with 151 additions and 86 deletions

View file

@ -12,8 +12,8 @@ class Service < ActiveRecord::Base
nil
end
def delete_post(post)
#don't do anything (should be overriden by service extensions)
def post_opts(post)
# don't do anything (should be overridden by service extensions)
end
class << self

View file

@ -37,11 +37,13 @@ class Services::Facebook < Service
"https://graph.facebook.com/#{self.uid}/picture?type=large&access_token=#{URI.escape(self.access_token)}"
end
def delete_post(post)
if post.present? && post.facebook_id.present?
logger.debug "event=delete_from_service type=facebook sender_id=#{user_id} post=#{post.guid}"
delete_from_facebook("https://graph.facebook.com/#{post.facebook_id}/", {:access_token => self.access_token})
end
def post_opts(post)
{facebook_id: post.facebook_id} if post.facebook_id.present?
end
def delete_from_service(opts)
logger.debug "event=delete_from_service type=facebook sender_id=#{user_id} facebook_id=#{opts[:facebook_id]}"
delete_from_facebook("https://graph.facebook.com/#{opts[:facebook_id]}/", access_token: access_token)
end
def delete_from_facebook(url, body)

View file

@ -43,13 +43,15 @@ class Services::Tumblr < Service
html << "\n\n[original post](#{url})"
end
def delete_post(post)
if post.present? && post.tumblr_ids.present?
logger.debug "event=delete_from_service type=tumblr sender_id=#{user_id} post=#{post.guid}"
tumblr_posts = JSON.parse(post.tumblr_ids)
tumblr_posts.each do |blog_name,post_id|
delete_from_tumblr(blog_name, post_id)
end
def post_opts(post)
{tumblr_ids: post.tumblr_ids} if post.tumblr_ids.present?
end
def delete_from_service(opts)
logger.debug "event=delete_from_service type=tumblr sender_id=#{user_id} tumblr_ids=#{opts[:tumblr_ids]}"
tumblr_posts = JSON.parse(opts[:tumblr_ids])
tumblr_posts.each do |blog_name, post_id|
delete_from_tumblr(blog_name, post_id)
end
end

View file

@ -20,11 +20,13 @@ class Services::Twitter < Service
client.user(nickname).profile_image_url_https "original"
end
def delete_post post
if post.present? && post.tweet_id.present?
logger.debug "event=delete_from_service type=twitter sender_id=#{user_id} post=#{post.guid}"
delete_from_twitter post.tweet_id
end
def post_opts(post)
{tweet_id: post.tweet_id} if post.tweet_id.present?
end
def delete_from_service(opts)
logger.debug "event=delete_from_service type=twitter sender_id=#{user_id} tweet_id=#{opts[:tweet_id]}"
delete_from_twitter(opts[:tweet_id])
end
private

View file

@ -6,12 +6,13 @@ module Workers
class DeferredRetraction < Base
sidekiq_options queue: :dispatch
def perform(user_id, retraction_data, recipient_ids)
def perform(user_id, retraction_data, recipient_ids, opts)
user = User.find(user_id)
subscribers = Person.where(id: recipient_ids)
object = Retraction.new(retraction_data.deep_symbolize_keys, subscribers)
opts = HashWithIndifferentAccess.new(opts)
Diaspora::Federation::Dispatcher.build(user, object).dispatch
Diaspora::Federation::Dispatcher.build(user, object, opts).dispatch
end
end
end

View file

@ -6,10 +6,10 @@ module Workers
class DeletePostFromService < Base
sidekiq_options queue: :http_service
def perform(service_id, post_id)
def perform(service_id, opts)
service = Service.find_by_id(service_id)
post = Post.find_by_id(post_id)
service.delete_post(post)
opts = HashWithIndifferentAccess.new(opts)
service.delete_from_service(opts)
end
end
end

View file

@ -28,7 +28,7 @@ class Retraction
end
def defer_dispatch(user)
Workers::DeferredRetraction.perform_async(user.id, data, subscribers.map(&:id)) unless subscribers.empty?
Workers::DeferredRetraction.perform_async(user.id, data, subscribers.map(&:id), service_opts(user))
end
def perform
@ -41,11 +41,19 @@ class Retraction
data[:target][:public]
end
def target_type
data[:target_type]
end
private
attr_reader :target
def service_opts(user)
return {} unless target.is_a?(StatusMessage)
user.services.each_with_object(service_types: []) do |service, opts|
service_opts = service.post_opts(target)
if service_opts
opts.merge!(service_opts)
opts[:service_types] << service.class.to_s
end
end
end
end

View file

@ -31,7 +31,7 @@ module Diaspora
attr_reader :sender, :object, :opts
def deliver_to_services
deliver_to_user_services
deliver_to_user_services if opts[:service_types]
end
def deliver_to_subscribers
@ -52,21 +52,16 @@ module Diaspora
end
def deliver_to_user_services
if object.is_a?(StatusMessage) && opts[:service_types]
post_to_services
elsif object.is_a?(Retraction) && object.target_type == "Post"
delete_from_services
case object
when StatusMessage
each_service {|service| Workers::PostToService.perform_async(service.id, object.id, opts[:url]) }
when Retraction
each_service {|service| Workers::DeletePostFromService.perform_async(service.id, opts) }
end
end
def post_to_services
sender.services.where(type: opts[:service_types]).each do |service|
Workers::PostToService.perform_async(service.id, object.id, opts[:url])
end
end
def delete_from_services
sender.services.each {|service| Workers::DeletePostFromService.perform_async(service.id, object.target.id) }
def each_service
sender.services.where(type: opts[:service_types]).each {|service| yield(service) }
end
end
end

View file

@ -53,21 +53,51 @@ describe Retraction do
describe ".defer_dispatch" do
it "queues a job to send the retraction later" do
post = local_luke.post(:status_message, text: "destroy!", public: true)
federation_retraction = Diaspora::Federation::Entities.signed_retraction(post, local_luke)
expect(Workers::DeferredRetraction).to receive(:perform_async).with(
local_luke.id, federation_retraction.to_h, [remote_raphael.id], service_types: []
)
Retraction.for(post, local_luke).defer_dispatch(local_luke)
end
it "adds service metadata to queued job for deletion" do
post.tweet_id = "123"
twitter = Services::Twitter.new(access_token: "twitter")
facebook = Services::Facebook.new(access_token: "facebook")
alice.services << twitter << facebook
federation_retraction = Diaspora::Federation::Entities.signed_retraction(post, alice)
expect(Workers::DeferredRetraction)
.to receive(:perform_async).with(alice.id, federation_retraction.to_h, [remote_raphael.id])
expect(Workers::DeferredRetraction).to receive(:perform_async).with(
alice.id, federation_retraction.to_h, [], service_types: ["Services::Twitter"], tweet_id: "123"
)
Retraction.for(post, alice).defer_dispatch(alice)
end
it "does not queue a job if subscribers is empty" do
it "queues also a job if subscribers is empty" do
federation_retraction = Diaspora::Federation::Entities.signed_retraction(post, alice)
expect(Workers::DeferredRetraction).not_to receive(:perform_async).with(alice.id, federation_retraction.to_h, [])
expect(Workers::DeferredRetraction).to receive(:perform_async).with(
alice.id, federation_retraction.to_h, [], service_types: []
)
Retraction.for(post, alice).defer_dispatch(alice)
end
it "queues a job with empty opts for non-StatusMessage" do
post = local_luke.post(:status_message, text: "hello", public: true)
comment = local_luke.comment!(post, "destroy!")
federation_retraction = Diaspora::Federation::Entities.relayable_retraction(comment, local_luke)
expect(Workers::DeferredRetraction).to receive(:perform_async).with(
local_luke.id, federation_retraction.to_h, [remote_raphael.id], {}
)
Retraction.for(comment, local_luke).defer_dispatch(local_luke)
end
end
describe "#perform" do
@ -87,15 +117,4 @@ describe Retraction do
expect(Retraction.for(private_post, alice).public?).to be_falsey
end
end
describe "#target_type" do
it "returns the type of the target as String" do
expect(Retraction.for(post, alice).target_type).to eq("Post")
end
it "is Person for a Contact-retraction" do
contact = FactoryGirl.create(:contact)
expect(Retraction.for(contact, contact.user).target_type).to eq("Person")
end
end
end

View file

@ -78,14 +78,25 @@ describe Services::Facebook, :type => :model do
end
end
describe '#delete_post' do
it 'removes a post from facebook' do
describe "#post_opts" do
it "returns the facebook_id of the post" do
@post.facebook_id = "2345"
url="https://graph.facebook.com/#{@post.facebook_id}/"
stub_request(:delete, "#{url}?access_token=#{@service.access_token}").to_return(:status => 200)
expect(@service).to receive(:delete_from_facebook).with(url, {access_token: @service.access_token})
expect(@service.post_opts(@post)).to eq(facebook_id: "2345")
end
@service.delete_post(@post)
it "returns nil when the post has no facebook_id" do
expect(@service.post_opts(@post)).to be_nil
end
end
describe "#delete_from_service" do
it "removes a post from facebook" do
facebook_id = "2345"
url = "https://graph.facebook.com/#{facebook_id}/"
stub_request(:delete, "#{url}?access_token=#{@service.access_token}").to_return(status: 200)
expect(@service).to receive(:delete_from_facebook).with(url, access_token: @service.access_token)
@service.delete_from_service(facebook_id: facebook_id)
end
end
end

View file

@ -25,7 +25,7 @@ describe Services::Tumblr, type: :model do
it "posts a status message to the primary blog and stores the id" do
stub = stub_request(:post, "http://api.tumblr.com/v2/blog/bar.tumblr.com/post")
.with(post_request).to_return(post_response)
.with(post_request).to_return(post_response)
expect(post).to receive(:tumblr_ids=).with({"bar.tumblr.com" => post_id}.to_json)
@ -40,7 +40,7 @@ describe Services::Tumblr, type: :model do
it "posts a status message to the returned blog" do
stub = stub_request(:post, "http://api.tumblr.com/v2/blog/foo.tumblr.com/post")
.with(post_request).to_return(post_response)
.with(post_request).to_return(post_response)
service.post(post)
@ -49,13 +49,24 @@ describe Services::Tumblr, type: :model do
end
end
describe "#delete_post" do
it "removes posts from tumblr" do
describe "#post_opts" do
it "returns the tumblr_ids of the post" do
post.tumblr_ids = {"foodbar.tumblr.com" => post_id}.to_json
stub = stub_request(:post, "http://api.tumblr.com/v2/blog/foodbar.tumblr.com/post/delete")
.with(body: {"id" => post_id}).to_return(status: 200)
expect(service.post_opts(post)).to eq(tumblr_ids: post.tumblr_ids)
end
service.delete_post(post)
it "returns nil when the post has no tumblr_ids" do
expect(service.post_opts(post)).to be_nil
end
end
describe "#delete_from_service" do
it "removes posts from tumblr" do
tumblr_ids = {"foodbar.tumblr.com" => post_id}.to_json
stub = stub_request(:post, "http://api.tumblr.com/v2/blog/foodbar.tumblr.com/post/delete")
.with(body: {"id" => post_id}).to_return(status: 200)
service.delete_from_service(tumblr_ids: tumblr_ids)
expect(stub).to have_been_requested
end

View file

@ -147,4 +147,15 @@ describe Services::Twitter, :type => :model do
expect(@service.profile_photo_url).to eq("http://a2.twimg.com/profile_images/uid/avatar.png")
end
end
describe "#post_opts" do
it "returns the tweet_id of the post" do
@post.tweet_id = "2345"
expect(@service.post_opts(@post)).to eq(tweet_id: "2345")
end
it "returns nil when the post has no tweet_id" do
expect(@service.post_opts(@post)).to be_nil
end
end
end

View file

@ -2,10 +2,9 @@ shared_examples "a dispatcher" do
describe "#dispatch" do
context "deliver to user services" do
let(:twitter) { Services::Twitter.new(access_token: "twitter") }
let(:facebook) { Services::Facebook.new(access_token: "facebook") }
before do
alice.services << twitter << facebook
alice.services << twitter
end
it "delivers a StatusMessage to specified services" do
@ -14,11 +13,18 @@ shared_examples "a dispatcher" do
Diaspora::Federation::Dispatcher.build(alice, post, opts).dispatch
end
it "delivers a Retraction of a Post to all user services" do
skip # TODO
it "delivers a Retraction of a Post to specified services" do
opts = {service_types: "Services::Twitter", tweet_id: "123"}
expect(Workers::DeletePostFromService).to receive(:perform_async).with(twitter.id, opts)
retraction = Retraction.for(post, alice)
Diaspora::Federation::Dispatcher.build(alice, retraction).dispatch
Diaspora::Federation::Dispatcher.build(alice, retraction, opts).dispatch
end
it "does not queue service jobs when no services specified" do
opts = {url: "https://example.org/p/123"}
expect(Workers::PostToService).not_to receive(:perform_async)
Diaspora::Federation::Dispatcher.build(alice, post, opts).dispatch
end
it "does not deliver a Comment to services" do

View file

@ -1,16 +1,13 @@
require 'spec_helper'
require "spec_helper"
describe Workers::DeletePostFromService do
before do
@user = alice
@post = @user.post(:status_message, :text => "hello", :to =>@user.aspects.first.id, :public =>true, :facebook_id => "23456" )
end
it "calls service#delete_from_service with given opts" do
service = double
opts = {facebook_id: "23456"}
it 'calls service#delete_post with given service' do
m = double()
url = "foobar"
expect(m).to receive(:delete_post)
allow(Service).to receive(:find_by_id).and_return(m)
Workers::DeletePostFromService.new.perform("123", @post.id.to_s)
expect(service).to receive(:delete_from_service).with(opts)
allow(Service).to receive(:find_by_id).with("123").and_return(service)
Workers::DeletePostFromService.new.perform("123", opts)
end
end