commit: 1dad72bf13f5e28781a2b2b6654f72624d205576
parent: 709c6685a90bb819696566cc9e42e587546d72dc
Author: Eugen Rochko <eugen@zeonfederated.com>
Date: Mon, 22 Feb 2016 18:10:30 +0100
Fixes and general progress
Diffstat:
15 files changed, 133 insertions(+), 34 deletions(-)
diff --git a/app/controllers/xrd_controller.rb b/app/controllers/xrd_controller.rb
@@ -7,7 +7,7 @@ class XrdController < ApplicationController
def webfinger
@account = Account.find_by!(username: username_from_resource, domain: nil)
- @canonical_account_uri = "acct:#{@account.username}#{LOCAL_DOMAIN}"
+ @canonical_account_uri = "acct:#{@account.username}@#{LOCAL_DOMAIN}"
@magic_key = pem_to_magic_key(@account.keypair.public_key)
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
@@ -1,12 +1,12 @@
module ApplicationHelper
- include GrapeRouteHelpers::NamedRouteMatcher
+ include RoutingHelper
def unique_tag(date, id, type)
"tag:#{LOCAL_DOMAIN},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
end
def subscription_url(account)
- add_base_url_prefix subscription_path(id: account.id, format: '')
+ add_base_url_prefix subscriptions_path(id: account.id, format: '')
end
def salmon_url(account)
@@ -14,6 +14,6 @@ module ApplicationHelper
end
def add_base_url_prefix(suffix)
- "#{root_url}api#{suffix}"
+ File.join(root_url, "api", suffix)
end
end
diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb
@@ -0,0 +1,11 @@
+module RoutingHelper
+ extend ActiveSupport::Concern
+ include Rails.application.routes.url_helpers
+ include GrapeRouteHelpers::NamedRouteMatcher
+
+ included do
+ def default_url_options
+ ActionMailer::Base.default_url_options
+ end
+ end
+end
diff --git a/app/models/account.rb b/app/models/account.rb
@@ -29,6 +29,18 @@ class Account < ActiveRecord::Base
self.domain.nil?
end
+ def acct
+ local? ? self.username : "#{self.username}@#{self.domain}"
+ end
+
+ def object_type
+ :person
+ end
+
+ def subscribed?
+ !(self.secret.blank? || self.verify_token.blank?)
+ end
+
def keypair
self.private_key.nil? ? OpenSSL::PKey::RSA.new(self.public_key) : OpenSSL::PKey::RSA.new(self.private_key)
end
diff --git a/app/models/follow.rb b/app/models/follow.rb
@@ -2,6 +2,28 @@ class Follow < ActiveRecord::Base
belongs_to :account
belongs_to :target_account, class_name: 'Account'
+ validates :account, :target_account, presence: true
+
+ def verb
+ :follow
+ end
+
+ def object_type
+ :person
+ end
+
+ def target
+ self.target_account
+ end
+
+ def content
+ "#{self.account.acct} started following #{self.target_account.acct}"
+ end
+
+ def title
+ content
+ end
+
after_create do
self.account.stream_entries.create!(activity: self)
end
diff --git a/app/models/status.rb b/app/models/status.rb
@@ -1,6 +1,24 @@
class Status < ActiveRecord::Base
belongs_to :account, inverse_of: :statuses
+ validates :account, presence: true
+
+ def verb
+ :post
+ end
+
+ def object_type
+ :note
+ end
+
+ def content
+ self.text
+ end
+
+ def title
+ content.truncate(80, omission: "...")
+ end
+
after_create do
self.account.stream_entries.create!(activity: self)
end
diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb
@@ -2,32 +2,29 @@ class StreamEntry < ActiveRecord::Base
belongs_to :account, inverse_of: :stream_entries
belongs_to :activity, polymorphic: true
+ validates :account, :activity, presence: true
+
def object_type
- case self.activity_type
- when 'Status'
- :note
- when 'Follow'
- :person
- end
+ self.activity.object_type
end
def verb
- case self.activity_type
- when 'Status'
- :post
- when 'Follow'
- :follow
- end
+ self.activity.verb
+ end
+
+ def targeted?
+ [:follow].include? self.verb
end
def target
- case self.activity_type
- when 'Follow'
- self.activity.target_account
- end
+ self.activity.target
+ end
+
+ def title
+ self.activity.title
end
def content
- self.activity.text if self.activity_type == 'Status'
+ self.activity.content
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
@@ -1,3 +1,5 @@
class User < ActiveRecord::Base
belongs_to :account, inverse_of: :user
+
+ validates :account, presence: true
end
diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb
@@ -5,10 +5,13 @@ class FollowRemoteAccountService
username, domain = uri.split('@')
account = Account.where(username: username, domain: domain).first
- return account unless account.nil?
+ if account.nil?
+ account = Account.new(username: username, domain: domain)
+ elsif account.subscribed?
+ return account
+ end
- account = Account.new(username: username, domain: domain)
- data = Goldfinger.finger("acct:#{uri}")
+ data = Goldfinger.finger("acct:#{uri}")
account.remote_url = data.link('http://schemas.google.com/g/2010#updates-from').href
account.salmon_url = data.link('salmon').href
@@ -21,16 +24,20 @@ class FollowRemoteAccountService
feed = get_feed(account.remote_url)
hubs = feed.xpath('//xmlns:link[@rel="hub"]')
- return false if hubs.empty? || hubs.first.attribute('href').nil? || feed.at_xpath('/xmlns:author/xmlns:uri').nil?
+ return nil if hubs.empty? || hubs.first.attribute('href').nil? || feed.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri').nil?
- account.uri = feed.at_xpath('/xmlns:author/xmlns:uri').content
+ account.uri = feed.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri').content
account.hub_url = hubs.first.attribute('href').value
+
+ get_profile(feed, account)
account.save!
subscription = account.subscription(subscription_url(account))
subscription.subscribe
+
+ return account
rescue Goldfinger::Error, HTTP::Error => e
- false
+ nil
end
private
@@ -40,6 +47,20 @@ class FollowRemoteAccountService
Nokogiri::XML(response)
end
+ def get_profile(xml, account)
+ author = xml.at_xpath('/xmlns:feed/xmlns:author')
+
+ if author.at_xpath('./poco:displayName').nil?
+ account.display_name = account.username
+ else
+ account.display_name = author.at_xpath('./poco:displayName').content
+ end
+
+ unless author.at_xpath('./poco:note').nil?
+ account.note = author.at_xpath('./poco:note').content
+ end
+ end
+
def magic_key_to_pem(magic_key)
_, modulus, exponent = magic_key.split('.')
modulus, exponent = [modulus, exponent].map { |n| Base64.urlsafe_decode64(n).bytes.inject(0) { |num, byte| (num << 8) | byte } }
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
@@ -1,7 +1,7 @@
class FollowService
def call(source_account, uri)
target_account = follow_remote_account_service.(uri)
- source_account.follow!(target_account)
+ source_account.follow!(target_account) unless target_account.nil?
end
private
diff --git a/app/views/atom/user_stream.xml.ruby b/app/views/atom/user_stream.xml.ruby
@@ -15,20 +15,29 @@ Nokogiri::XML::Builder.new do |xml|
end
xml.link(rel: 'alternate', type: 'text/html', href: profile_url(name: @account.username))
- xml.link(rel: 'hub', href: '')
+ xml.link(rel: 'hub', href: HUB_URL)
xml.link(rel: 'salmon', href: salmon_url(@account))
xml.link(rel: 'self', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id))
@account.stream_entries.each do |stream_entry|
xml.entry do
xml.id_ unique_tag(stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type)
+
xml.published stream_entry.activity.created_at.iso8601
xml.updated stream_entry.activity.updated_at.iso8601
- xml.content({ type: 'html' }, stream_entry.content)
- xml.title
+ xml.title stream_entry.title
+ xml.content({ type: 'html' }, stream_entry.content)
xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{stream_entry.verb}")
- xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.object_type}")
+
+ if stream_entry.targeted?
+ xml['activity'].send('object') do
+ xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.target.object_type}")
+ xml.id_ stream_entry.target.uri
+ end
+ else
+ xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{stream_entry.object_type}")
+ end
end
end
end
diff --git a/app/views/xrd/webfinger.xml.ruby b/app/views/xrd/webfinger.xml.ruby
@@ -1,6 +1,8 @@
Nokogiri::XML::Builder.new do |xml|
xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
xml.Subject @canonical_account_uri
+ xml.Alias profile_url(name: @account.username)
+ xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: profile_url(name: @account.username))
xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: atom_user_stream_url(id: @account.id))
xml.Link(rel: 'salmon', href: salmon_url(@account))
xml.Link(rel: 'magic-public-key', href: @magic_key)
diff --git a/config/application.rb b/config/application.rb
@@ -6,6 +6,8 @@ require 'rails/all'
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
+Dotenv::Railtie.load
+
module Mastodon
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
diff --git a/config/environments/development.rb b/config/environments/development.rb
@@ -38,6 +38,4 @@ Rails.application.configure do
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
-
- config.action_mailer.default_url_options = { host: ENV['NGROK_HOST'] }
end
diff --git a/config/initializers/ostatus.rb b/config/initializers/ostatus.rb
@@ -1 +1,6 @@
LOCAL_DOMAIN = ENV['LOCAL_DOMAIN'] || 'localhost'
+HUB_URL = ENV['HUB_URL'] || 'https://pubsubhubbub.superfeedr.com'
+
+Rails.application.configure do
+ config.action_mailer.default_url_options = { host: LOCAL_DOMAIN }
+end