Permalink
Browse files

Merge remote-tracking branch 'origin/issue_698'

Conflicts:
	test/lib/converts_subscriber_to_feed_data_test.rb
	test/lib/finds_or_creates_feeds_test.rb
	test/lib/finger_test.rb
  • Loading branch information...
2 parents 2120fb6 + c4eba18 commit 066143ef56f335acf05d2eb70518430c9fe6d8ac @carols10cents carols10cents committed Dec 27, 2012
@@ -60,43 +60,39 @@ def post_update
def create
require_login! :return => request.referrer and return
- # Find or create the Feed
- begin
- subscribe_to_feed = Feed.find_or_create(params[:subscribe_to])
- rescue RstatUs::InvalidSubscribeTo => e
- # This means the user's entry was neither a webfinger identifier
- # nor a feed URL, and calling `open` on it did not return anything.
- flash[:error] = "There was a problem following #{params[:subscribe_to]}. Please specify the whole ID for the person you would like to follow, including both their username and the domain of the site they're on. It should look like an email address-- for example, username@status.net"
- redirect_to request.referrer
- return
- end
+ target = FeedService.new(params[:subscribe_to], root_url).find_or_create!
- # Stop and return a nice message if already following this feed
- if current_user.following_feed? subscribe_to_feed
- flash[:notice] = "You're already following #{subscribe_to_feed.author.username}."
+ if current_user.following_feed? target
+ # Stop and return a nice message if already following this feed
+ flash[:notice] = "You're already following #{target.author.username}."
redirect_to request.referrer
return
- end
+ else
+ # Actually follow!
+ target_feed = current_user.follow! target
- # Actually follow!
- f = current_user.follow! subscribe_to_feed
+ if target_feed
+ # Attempt to inform the hub for remote feeds
+ if target_feed.remote? && target_feed.hubs.any?
+ hub_url = target_feed.hubs.first
- unless f
- flash[:error] = "There was a problem following #{params[:subscribe_to]}."
- redirect_to request.referrer
- return
- end
-
- # Attempt to inform the hub for remote feeds
- unless f.local? || f.hubs.empty?
- hub_url = f.hubs.first
+ sub = OSub::Subscription.new(subscription_url(target_feed.id, :format => "atom"), target_feed.url, target_feed.secret)
+ sub.subscribe(hub_url, true, target_feed.verify_token)
+ end
- sub = OSub::Subscription.new(subscription_url(f.id, :format => "atom"), f.url, f.secret)
- sub.subscribe(hub_url, true, f.verify_token)
+ flash[:notice] = "Now following #{target_feed.author.username}."
+ redirect_to request.referrer
+ else
+ raise RstatUs::InvalidSubscribeTo
+ end
end
- flash[:notice] = "Now following #{f.author.username}."
+ rescue RstatUs::InvalidSubscribeTo => e
+ # This means the user's entry was neither a webfinger identifier
+ # nor a feed URL, and calling `open` on it did not return anything.
+ flash[:error] = "There was a problem following #{params[:subscribe_to]}. Please specify the whole ID for the person you would like to follow, including both their username and the domain of the site they're on. It should look like an email address-- for example, username@status.net"
redirect_to request.referrer
+ return
end
private
View
@@ -1,5 +1,3 @@
-require_relative '../../lib/finds_or_creates_feeds'
-
# Feeds are pretty central to everything. They're a representation of a PuSH
# enabled Atom feed. Every user has a feed of their updates, we keep feeds
# for remote users that our users are subscribed to, and maybe even other
@@ -31,17 +29,13 @@ class Feed
after_create :default_hubs
- def self.find_or_create(subscribe_to)
- FindsOrCreatesFeeds.find_or_create(subscribe_to)
- end
-
- def self.create_from_feed_data(feed_data)
- feed = Feed.create(:remote_url => feed_data.url)
+ def self.create_and_populate!(feed_data)
+ feed = create(:remote_url => feed_data.url)
feed.populate(feed_data.finger_data)
feed
end
- # This is because sometimes the mongomapper association returns nil
+ # This is because sometimes the mongomapper association returns nil
# even though there is an author_id and the Author exists; see Issue #421
def author
Author.find(author_id)
@@ -127,6 +121,10 @@ def local?
remote_url.nil?
end
+ def remote?
+ !local?
+ end
+
def url(params = {})
atom_format = params.fetch(:format, false) == :atom
View
@@ -0,0 +1 @@
+class FeedData < Struct.new(:url, :finger_data); end
View
@@ -0,0 +1,29 @@
+class FingerData
+ def initialize(xrd)
+ @xrd = xrd
+ end
+
+ def url
+ find('http://schemas.google.com/g/2010#updates-from')
+ end
+
+ def public_key
+ public_key = find('magic-public-key')
+ public_key.split(",")[1] || ""
+ end
+
+ def salmon_url
+ find('salmon')
+ end
+
+ private
+
+ def find(rel)
+ element_hash = links.find { |link| link['rel'].downcase == rel } || {}
+ element_hash.fetch("href") { "" }
+ end
+
+ def links
+ @xrd.links || []
+ end
+end
View
@@ -150,24 +150,22 @@ def unfollowed_by!(f)
end
# Follow a particular feed
- def follow!(f)
- # can't follow yourself
- if f == self.feed
- return
- end
+ def follow!(target_feed)
+ return false if target_feed == self.feed # can't follow yourself
- following << f
- save
+ self.following << target_feed
+ self.save
- if f.local?
+ if target_feed.local?
# Add the inverse relationship
- followee = User.first(:author_id => f.author.id)
+ followee = User.first(:author_id => target_feed.author.id)
followee.followed_by! self.feed
else
# Queue a notification job
- self.delay.send_follow_notification(f.id)
+ self.delay.send_follow_notification(target_feed.id)
end
- f
+
+ target_feed
end
# Send Salmon notification so that the remote user
@@ -368,7 +366,8 @@ def edit_user_profile(params)
# A better name would be very welcome.
def self.find_by_case_insensitive_username(username)
- User.first(:username => /^#{Regexp.escape(username)}$/i)
+ username = Regexp.escape(username)
+ User.first(:username => /^#{username}$/i)
end
def token_expired?
@@ -0,0 +1,44 @@
+require 'uri'
+
+class FeedService
+ def initialize(target_feed, current_node_domain = nil)
+ @target_feed = target_feed
+ @current_node_domain = current_node_domain
+ end
+
+ def find_or_create!
+ find_feed_by_id ||
+ find_feed_by_username ||
+ find_feed_by_remote_url ||
+ create_feed_from_feed_data
+ end
+
+ private
+
+ def find_feed_by_id
+ Feed.first(:id => @target_feed)
+ end
+
+ def find_feed_by_username
+ username, domain = @target_feed.split /@/
+
+ if @current_node_domain && domain == URI(@current_node_domain).host
+ u = User.find_by_case_insensitive_username(username)
+ u && u.author.feed
+ end
+ end
+
+ def find_feed_by_remote_url
+ feed_data = get_feed_data_for_target
+ Feed.first(:remote_url => feed_data.url)
+ end
+
+ def create_feed_from_feed_data
+ feed_data = get_feed_data_for_target
+ Feed.create_and_populate!(feed_data)
+ end
+
+ def get_feed_data_for_target
+ SubscriberToFeedDataConverter.new(@target_feed).get_feed_data!
+ end
+end
@@ -0,0 +1,23 @@
+class FingerService
+
+ attr_reader :feed_data
+
+ def initialize(target)
+ @target = target
+ @feed_data = FeedData.new
+ end
+
+ def finger!
+ # TODO: ensure caching of finger lookup.
+ data = FingerData.new(Redfinger.finger(@target))
+ @feed_data.url = data.url
+ @feed_data.finger_data = data
+ @feed_data
+ # TODO: other exceptions to rescue; check what Redfinger raises
+ rescue RestClient::ResourceNotFound
+ raise RstatUs::InvalidSubscribeTo
+ rescue SocketError
+ raise RstatUs::InvalidSubscribeTo
+ end
+
+end
@@ -0,0 +1,49 @@
+class SubscriberToFeedDataConverter
+
+ def initialize(subscriber_url)
+ @subscriber_url = subscriber_url
+ @feed_data = FeedData.new
+ end
+
+ def get_feed_data!
+ case @subscriber_url
+ when /^feed:\/\//
+ convert_safari_scheme
+ when /@/
+ query_web_finger
+ when /^https?:\/\//
+ http_https_subscriber
+ else
+ raise RstatUs::InvalidSubscribeTo
+ end
+
+ @feed_data
+
+ rescue StandardError
+ # TODO Bubble up a better description of what went wrong.
+ #
+ # We could see any one of the following here:
+ #
+ # Redfinger::ResourceNotFound
+ # Nokogiri::SyntaxError (Bad XML parsed by Redfinger)
+ # SocketError (DNS resolution or connect failure)
+ # ??? more ???
+ raise RstatUs::InvalidSubscribeTo
+ end
+
+ private
+
+ # replace Safari feed:// scheme with http://
+ def convert_safari_scheme
+ @feed_data.url = "http" + @subscriber_url[4..-1]
+ end
+
+ def query_web_finger
+ @feed_data = FingerService.new(@subscriber_url).finger!
+ end
+
+ def http_https_subscriber
+ @feed_data.url = @subscriber_url
+ end
+
+end
@@ -0,0 +1,3 @@
+= form_tag "/subscriptions" do
+ %input{:type => "hidden", :name => "subscribe_to", :value => feed_id}
+ %input.button.follow{:type => "submit", :value => "Follow", :id => "follow-#{feed_id}"}
@@ -24,6 +24,4 @@
%input{:type => "hidden", :name => "_method", :value => "delete"}
= submit_tag "Unfollow", :class => "button unfollow", :id => "unfollow-#{author.feed.id}", :confirm => t(:unfollow, :scope => :confirms)
- else
- = form_tag "/subscriptions" do
- %input{:type => "hidden", :name => "subscribe_to", :value => author.feed.id}
- %input.button.follow{:type => "submit", :value => "Follow", :id => "follow-#{author.feed.id}"}
+ = render :partial => "follow_user", :locals => { :feed_id => author.feed.id }
@@ -24,9 +24,7 @@
%input{:type => "hidden", :name => "_method", :value => "delete"}
%input.button.unfollow{:type => "submit", :value => "Unfollow", :id => "unfollow-#{@author.feed.id}"}
- elsif current_user
- = form_tag "/subscriptions" do
- %input{:type => "hidden", :name => "subscribe_to", :value => @author.feed.id}
- %input.button.follow{:type => "submit", :value => "Follow", :id => "follow-#{@author.feed.id}"}
+ = render :partial => "follow_user", :locals => { :feed_id => @author.feed.id }
- if @author.user == current_user
.edit
@@ -1,39 +0,0 @@
-require_relative "queries_web_finger"
-
-FeedData = Struct.new(:url, :finger_data)
-
-class ConvertsSubscriberToFeedData
- def self.get_feed_data(subscriber_url)
- feed_data = FeedData.new
-
- case subscriber_url
- when /^feed:\/\//
- # SAFARI!!!!1 /me shakes his first at the sky
- feed_data.url = "http" + subscriber_url[4..-1]
- when /@/
- begin
- finger_data = QueriesWebFinger.query(subscriber_url)
- rescue StandardError
- #
- # TODO Bubble up a better description of what went wrong.
- #
- # We could see any one of the following here:
- #
- # Redfinger::ResourceNotFound
- # Nokogiri::SyntaxError (Bad XML parsed by Redfinger)
- # SocketError (DNS resolution or connect failure)
- # ??? more ???
- #
- raise RstatUs::InvalidSubscribeTo
- end
- feed_data.url = finger_data.url
- feed_data.finger_data = finger_data
- when /^https?:\/\//
- feed_data.url = subscriber_url
- else
- raise RstatUs::InvalidSubscribeTo
- end
-
- feed_data
- end
-end
@@ -1,15 +0,0 @@
-require_relative 'converts_subscriber_to_feed_data'
-
-class FindsOrCreatesFeeds
- def self.find_or_create(subscribe_to)
- feed = Feed.first(:id => subscribe_to)
-
- unless feed
- feed_data = ConvertsSubscriberToFeedData.get_feed_data(subscribe_to)
- feed = Feed.first(:remote_url => feed_data.url) || Feed.create_from_feed_data(feed_data)
- end
-
- feed
- end
-end
-
Oops, something went wrong.

0 comments on commit 066143e

Please sign in to comment.