Merge pull request #6207 from jaywink/social-relay
Implement social relay requirements
This commit is contained in:
commit
e8297f8d6b
9 changed files with 272 additions and 6 deletions
7
app/controllers/social_relay_controller.rb
Normal file
7
app/controllers/social_relay_controller.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
class SocialRelayController < ApplicationController
|
||||||
|
respond_to :json
|
||||||
|
|
||||||
|
def well_known
|
||||||
|
render json: SocialRelayPresenter.new
|
||||||
|
end
|
||||||
|
end
|
||||||
24
app/presenters/social_relay_presenter.rb
Normal file
24
app/presenters/social_relay_presenter.rb
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
class SocialRelayPresenter
|
||||||
|
def as_json(*)
|
||||||
|
{
|
||||||
|
"subscribe" => AppConfig.relay.inbound.subscribe,
|
||||||
|
"scope" => AppConfig.relay.inbound.scope,
|
||||||
|
"tags" => tags
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def tags
|
||||||
|
return [] unless AppConfig.relay.inbound.scope == "tags"
|
||||||
|
tags = AppConfig.relay.inbound.pod_tags.present? ? AppConfig.relay.inbound.pod_tags.split(",") : []
|
||||||
|
add_user_tags(tags)
|
||||||
|
tags.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_user_tags(tags)
|
||||||
|
if AppConfig.relay.inbound.include_user_tags?
|
||||||
|
user_ids = User.halfyear_actives.pluck(:id)
|
||||||
|
tag_ids = TagFollowing.where(user: user_ids).select(:tag_id).distinct.pluck(:tag_id)
|
||||||
|
tags.concat ActsAsTaggableOn::Tag.where(id: tag_ids).pluck(:name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -10,14 +10,38 @@ module Workers
|
||||||
user = User.find(user_id)
|
user = User.find(user_id)
|
||||||
object = object_class_name.constantize.find(object_id)
|
object = object_class_name.constantize.find(object_id)
|
||||||
opts = HashWithIndifferentAccess.new(opts)
|
opts = HashWithIndifferentAccess.new(opts)
|
||||||
opts[:services] = user.services.where(:type => opts.delete(:service_types))
|
opts[:services] = user.services.where(type: opts.delete(:service_types))
|
||||||
|
|
||||||
if opts[:additional_subscribers].present?
|
|
||||||
opts[:additional_subscribers] = Person.where(:id => opts[:additional_subscribers])
|
|
||||||
end
|
|
||||||
|
|
||||||
|
add_additional_subscribers(object, object_class_name, opts)
|
||||||
Postzord::Dispatcher.build(user, object, opts).post
|
Postzord::Dispatcher.build(user, object, opts).post
|
||||||
rescue ActiveRecord::RecordNotFound # The target got deleted before the job was run
|
rescue ActiveRecord::RecordNotFound # The target got deleted before the job was run
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_additional_subscribers(object, object_class_name, opts)
|
||||||
|
if AppConfig.relay.outbound.send? &&
|
||||||
|
object_class_name == "StatusMessage" &&
|
||||||
|
object.respond_to?(:public?) && object.public?
|
||||||
|
handle_relay(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts[:additional_subscribers].present?
|
||||||
|
opts[:additional_subscribers] = Person.where(id: opts[:additional_subscribers])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_relay(opts)
|
||||||
|
relay_person = Person.find_by diaspora_handle: AppConfig.relay.outbound.handle.to_s
|
||||||
|
if relay_person
|
||||||
|
add_person_to_subscribers(opts, relay_person)
|
||||||
|
else
|
||||||
|
# Skip this message for relay and just queue a webfinger fetch for the relay handle
|
||||||
|
Workers::FetchWebfinger.perform_async(AppConfig.relay.outbound.handle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_person_to_subscribers(opts, person)
|
||||||
|
opts[:additional_subscribers] ||= []
|
||||||
|
opts[:additional_subscribers] << person.id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,15 @@ defaults:
|
||||||
admins:
|
admins:
|
||||||
account:
|
account:
|
||||||
podmin_email:
|
podmin_email:
|
||||||
|
relay:
|
||||||
|
outbound:
|
||||||
|
send: false
|
||||||
|
handle: 'relay@relay.iliketoast.net'
|
||||||
|
inbound:
|
||||||
|
subscribe: false
|
||||||
|
scope: tags
|
||||||
|
include_user_tags: false
|
||||||
|
pod_tags:
|
||||||
# List valid environment variables
|
# List valid environment variables
|
||||||
redistogo_url:
|
redistogo_url:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -679,6 +679,38 @@ configuration: ## Section
|
||||||
## E-mail address to contact the administrator.
|
## E-mail address to contact the administrator.
|
||||||
#podmin_email: 'podmin@example.org'
|
#podmin_email: 'podmin@example.org'
|
||||||
|
|
||||||
|
## Settings related to relays
|
||||||
|
relay: ## Section
|
||||||
|
|
||||||
|
## Relays are applications that exist to push public posts around to
|
||||||
|
## pods which want to subscribe to them but would not otherwise
|
||||||
|
## receive them due to not having direct contact with the remote pods.
|
||||||
|
##
|
||||||
|
## See more regarding relays: https://wiki.diasporafoundation.org/Relay_servers_for_public_posts
|
||||||
|
|
||||||
|
outbound: ## Section
|
||||||
|
## Enable this setting to send out public posts from this pod to a relay
|
||||||
|
#send: false
|
||||||
|
## Change default remote relay handle used for sending out here
|
||||||
|
#handle: 'relay@relay.iliketoast.net'
|
||||||
|
|
||||||
|
inbound: ## Section
|
||||||
|
## Enable this to receive public posts from relays
|
||||||
|
#subscribe: false
|
||||||
|
|
||||||
|
## Scope is either 'all' or 'tags' (default).
|
||||||
|
## - 'all', means this pod wants to receive all public posts from a relay
|
||||||
|
## - 'tags', means this pod wants only posts tagged with certain tags
|
||||||
|
#scope: tags
|
||||||
|
|
||||||
|
## If scope is 'tags', should we include tags that users on this pod follow?
|
||||||
|
## These are added in addition to 'pod_tags', if set.
|
||||||
|
#include_user_tags: false
|
||||||
|
|
||||||
|
## If scope is 'tags', a comma separated list of tags here can be set.
|
||||||
|
## For example "linux,diaspora", to receive posts related to these tags
|
||||||
|
#pod_tags:
|
||||||
|
|
||||||
## Here you can override settings defined above if you need
|
## Here you can override settings defined above if you need
|
||||||
## to have them different in different environments.
|
## to have them different in different environments.
|
||||||
production: ## Section
|
production: ## Section
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,9 @@ Diaspora::Application.routes.draw do
|
||||||
get 'terms' => 'terms#index'
|
get 'terms' => 'terms#index'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Relay
|
||||||
|
get ".well-known/x-social-relay" => "social_relay#well_known"
|
||||||
|
|
||||||
# Startpage
|
# Startpage
|
||||||
root :to => 'home#show'
|
root :to => 'home#show'
|
||||||
end
|
end
|
||||||
|
|
|
||||||
16
spec/controllers/social_relay_controller_spec.rb
Normal file
16
spec/controllers/social_relay_controller_spec.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe SocialRelayController, type: :controller do
|
||||||
|
describe "#well_known" do
|
||||||
|
it "responds to format json" do
|
||||||
|
get :well_known, format: "json"
|
||||||
|
expect(response.code).to eq("200")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "contains json" do
|
||||||
|
get :well_known, format: "json"
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json["scope"]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
122
spec/presenters/social_relay_presenter_spec.rb
Normal file
122
spec/presenters/social_relay_presenter_spec.rb
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe SocialRelayPresenter do
|
||||||
|
before do
|
||||||
|
@presenter = SocialRelayPresenter.new
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#as_json" do
|
||||||
|
it "works" do
|
||||||
|
expect(@presenter.as_json).to be_present
|
||||||
|
expect(@presenter.as_json).to be_a Hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#social relay well-known contents" do
|
||||||
|
describe "defaults" do
|
||||||
|
it "provides valid detault data" do
|
||||||
|
expect(@presenter.as_json).to eq(
|
||||||
|
"subscribe" => false,
|
||||||
|
"scope" => "tags",
|
||||||
|
"tags" => []
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "pod tags" do
|
||||||
|
before do
|
||||||
|
AppConfig.relay.inbound.pod_tags = "foo,bar"
|
||||||
|
AppConfig.relay.inbound.include_user_tags = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides pod tags" do
|
||||||
|
expect(@presenter.as_json).to eq(
|
||||||
|
"subscribe" => false,
|
||||||
|
"scope" => "tags",
|
||||||
|
"tags" => ["foo", "bar"]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "user tags" do
|
||||||
|
before do
|
||||||
|
AppConfig.relay.inbound.pod_tags = ""
|
||||||
|
AppConfig.relay.inbound.include_user_tags = true
|
||||||
|
ceetag = FactoryGirl.create(:tag, name: "cee")
|
||||||
|
lootag = FactoryGirl.create(:tag, name: "loo")
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: ceetag)
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: lootag)
|
||||||
|
alice.last_seen = Time.now - 2.month
|
||||||
|
alice.save
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides user tags" do
|
||||||
|
expect(@presenter.as_json).to eq(
|
||||||
|
"subscribe" => false,
|
||||||
|
"scope" => "tags",
|
||||||
|
"tags" => ["cee", "loo"]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "pod tags combined with user tags" do
|
||||||
|
before do
|
||||||
|
AppConfig.relay.inbound.pod_tags = "foo,bar"
|
||||||
|
AppConfig.relay.inbound.include_user_tags = true
|
||||||
|
ceetag = FactoryGirl.create(:tag, name: "cee")
|
||||||
|
lootag = FactoryGirl.create(:tag, name: "loo")
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: ceetag)
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: lootag)
|
||||||
|
alice.last_seen = Time.now - 2.month
|
||||||
|
alice.save
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides combined pod and user tags" do
|
||||||
|
expect(@presenter.as_json).to eq(
|
||||||
|
"subscribe" => false,
|
||||||
|
"scope" => "tags",
|
||||||
|
"tags" => ["foo", "bar", "cee", "loo"]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "user tags for inactive user" do
|
||||||
|
before do
|
||||||
|
AppConfig.relay.inbound.pod_tags = ""
|
||||||
|
AppConfig.relay.inbound.include_user_tags = true
|
||||||
|
ceetag = FactoryGirl.create(:tag, name: "cee")
|
||||||
|
lootag = FactoryGirl.create(:tag, name: "loo")
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: ceetag)
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: lootag)
|
||||||
|
alice.last_seen = Time.now - 8.month
|
||||||
|
alice.save
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores user tags" do
|
||||||
|
expect(@presenter.as_json).to eq(
|
||||||
|
"subscribe" => false,
|
||||||
|
"scope" => "tags",
|
||||||
|
"tags" => []
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when scope is all" do
|
||||||
|
before do
|
||||||
|
AppConfig.relay.inbound.scope = "all"
|
||||||
|
AppConfig.relay.inbound.pod_tags = "foo,bar"
|
||||||
|
AppConfig.relay.inbound.include_user_tags = true
|
||||||
|
ceetag = FactoryGirl.create(:tag, name: "cee")
|
||||||
|
FactoryGirl.create(:tag_following, user: alice, tag: ceetag)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides empty tags list" do
|
||||||
|
expect(@presenter.as_json).to eq(
|
||||||
|
"subscribe" => false,
|
||||||
|
"scope" => "all",
|
||||||
|
"tags" => []
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -3,7 +3,36 @@ require 'spec_helper'
|
||||||
describe Workers::DeferredDispatch do
|
describe Workers::DeferredDispatch do
|
||||||
it "handles non existing records gracefully" do
|
it "handles non existing records gracefully" do
|
||||||
expect {
|
expect {
|
||||||
described_class.new.perform(alice.id, 'Comment', 0, {})
|
described_class.new.perform(alice.id, "Comment", 0, {})
|
||||||
}.to_not raise_error
|
}.to_not raise_error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#social relay functionality" do
|
||||||
|
let(:message) { FactoryGirl.create(:status_message, author: alice.person, public: true) }
|
||||||
|
before do
|
||||||
|
AppConfig.relay.outbound.send = true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "triggers fetch of relay handle" do
|
||||||
|
allow(Person).to receive(:find_by).and_return(nil)
|
||||||
|
|
||||||
|
expect(Workers::FetchWebfinger).to receive(:perform_async)
|
||||||
|
|
||||||
|
described_class.new.perform(alice.id, "StatusMessage", message.id, {})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "triggers post to relay" do
|
||||||
|
relay_person = FactoryGirl.create(:person, diaspora_handle: AppConfig.relay.outbound.handle)
|
||||||
|
opts = {"additional_subscribers" => [relay_person], "services" => []}
|
||||||
|
allow(Person).to receive(:find_by).and_return(relay_person)
|
||||||
|
postzord = double
|
||||||
|
allow(Postzord::Dispatcher).to receive(:build).with(any_args).and_return(postzord)
|
||||||
|
allow(postzord).to receive(:post)
|
||||||
|
allow(Person).to receive(:where).and_return([relay_person])
|
||||||
|
|
||||||
|
expect(Postzord::Dispatcher).to receive(:build).with(alice, message, opts)
|
||||||
|
|
||||||
|
described_class.new.perform(alice.id, "StatusMessage", message.id, {})
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue