Add ActivityPub actor representing the entire server (#11321)
* Add support for an instance actor * Skip username validation for local Application accounts * Add migration script to create instance actor * Make Codeclimate happy * Switch to id -99 for instance actor * Remove unused `icon` and `image` attributes from instance actor * Use if/elsif/else instead of return + ternary operator * Add instance actor to fresh installs * Use instance actor as instance representative Use instance actor for forwarding reports, relay operations, and spam auto-reporting. * Seed database in test environment * Fix single-user mode * Fix tests * Fix specs to accomodate for an extra `Account` * Auto-reject follows on instance actor Following an instance actor might make sense, but we are not handling that right now, so auto-reject. * Fix webfinger lookup and serialization for instance actor * Rename instance actor * Make it clear in the HTML view that the instance actor should not be blocked * Raise cache time for instance actor as there's no dynamic content * Re-use /about/more with a flash message for instance actor profile
This commit is contained in:
parent
15c7478c55
commit
730c4053d6
23 changed files with 141 additions and 52 deletions
|
@ -11,7 +11,9 @@ class AboutController < ApplicationController
|
||||||
|
|
||||||
def show; end
|
def show; end
|
||||||
|
|
||||||
def more; end
|
def more
|
||||||
|
flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor]
|
||||||
|
end
|
||||||
|
|
||||||
def terms; end
|
def terms; end
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def single_user_mode?
|
def single_user_mode?
|
||||||
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.exists?
|
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def use_seamless_external_login?
|
def use_seamless_external_login?
|
||||||
|
|
|
@ -58,7 +58,7 @@ class HomeController < ApplicationController
|
||||||
if request.path.start_with?('/web')
|
if request.path.start_with?('/web')
|
||||||
new_user_session_path
|
new_user_session_path
|
||||||
elsif single_user_mode?
|
elsif single_user_mode?
|
||||||
short_account_path(Account.local.without_suspended.first)
|
short_account_path(Account.local.without_suspended.where('id > 0').first)
|
||||||
else
|
else
|
||||||
about_path
|
about_path
|
||||||
end
|
end
|
||||||
|
|
20
app/controllers/instance_actors_controller.rb
Normal file
20
app/controllers/instance_actors_controller.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class InstanceActorsController < ApplicationController
|
||||||
|
include AccountControllerConcern
|
||||||
|
|
||||||
|
def show
|
||||||
|
expires_in 10.minutes, public: true
|
||||||
|
render json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, fields: restrict_fields_to
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = Account.find(-99)
|
||||||
|
end
|
||||||
|
|
||||||
|
def restrict_fields_to
|
||||||
|
%i(id type preferred_username inbox public_key endpoints url manually_approves_followers)
|
||||||
|
end
|
||||||
|
end
|
|
@ -145,6 +145,10 @@
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flash-message {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 738px) {
|
@media screen and (max-width: 738px) {
|
||||||
grid-template-columns: minmax(0, 50%) minmax(0, 50%);
|
grid-template-columns: minmax(0, 50%) minmax(0, 50%);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
|
||||||
|
|
||||||
return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account)
|
return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account)
|
||||||
|
|
||||||
if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved?
|
if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? || target_account.instance_actor?
|
||||||
reject_follow_request!(target_account)
|
reject_follow_request!(target_account)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ class ActivityPub::TagManager
|
||||||
|
|
||||||
case target.object_type
|
case target.object_type
|
||||||
when :person
|
when :person
|
||||||
short_account_url(target)
|
target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target)
|
||||||
when :note, :comment, :activity
|
when :note, :comment, :activity
|
||||||
return activity_account_status_url(target.account, target) if target.reblog?
|
return activity_account_status_url(target.account, target) if target.reblog?
|
||||||
short_account_status_url(target.account, target)
|
short_account_status_url(target.account, target)
|
||||||
|
@ -29,7 +29,7 @@ class ActivityPub::TagManager
|
||||||
|
|
||||||
case target.object_type
|
case target.object_type
|
||||||
when :person
|
when :person
|
||||||
account_url(target)
|
target.instance_actor? ? instance_actor_url : account_url(target)
|
||||||
when :note, :comment, :activity
|
when :note, :comment, :activity
|
||||||
return activity_account_status_url(target.account, target) if target.reblog?
|
return activity_account_status_url(target.account, target) if target.reblog?
|
||||||
account_status_url(target.account, target)
|
account_status_url(target.account, target)
|
||||||
|
@ -119,6 +119,7 @@ class ActivityPub::TagManager
|
||||||
|
|
||||||
def uri_to_local_id(uri, param = :id)
|
def uri_to_local_id(uri, param = :id)
|
||||||
path_params = Rails.application.routes.recognize_path(uri)
|
path_params = Rails.application.routes.recognize_path(uri)
|
||||||
|
path_params[:username] = Rails.configuration.x.local_domain if path_params[:controller] == 'instance_actors'
|
||||||
path_params[param]
|
path_params[param]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,17 @@ class WebfingerResource
|
||||||
def username_from_url
|
def username_from_url
|
||||||
if account_show_page?
|
if account_show_page?
|
||||||
path_params[:username]
|
path_params[:username]
|
||||||
|
elsif instance_actor_page?
|
||||||
|
Rails.configuration.x.local_domain
|
||||||
else
|
else
|
||||||
raise ActiveRecord::RecordNotFound
|
raise ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def instance_actor_page?
|
||||||
|
path_params[:controller] == 'instance_actors'
|
||||||
|
end
|
||||||
|
|
||||||
def account_show_page?
|
def account_show_page?
|
||||||
path_params[:controller] == 'accounts' && path_params[:action] == 'show'
|
path_params[:controller] == 'accounts' && path_params[:action] == 'show'
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,7 +77,7 @@ class Account < ApplicationRecord
|
||||||
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? }
|
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? }
|
||||||
|
|
||||||
# Local user validations
|
# Local user validations
|
||||||
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? }
|
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
|
||||||
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
||||||
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
|
||||||
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
|
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
|
||||||
|
@ -139,6 +139,10 @@ class Account < ApplicationRecord
|
||||||
%w(Application Service).include? actor_type
|
%w(Application Service).include? actor_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def instance_actor?
|
||||||
|
id == -99
|
||||||
|
end
|
||||||
|
|
||||||
alias bot bot?
|
alias bot bot?
|
||||||
|
|
||||||
def bot=(val)
|
def bot=(val)
|
||||||
|
@ -498,7 +502,7 @@ class Account < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_keys
|
def generate_keys
|
||||||
return unless local? && !Rails.env.test?
|
return unless local? && private_key.blank? && public_key.blank?
|
||||||
|
|
||||||
keypair = OpenSSL::PKey::RSA.new(2048)
|
keypair = OpenSSL::PKey::RSA.new(2048)
|
||||||
self.private_key = keypair.to_pem
|
self.private_key = keypair.to_pem
|
||||||
|
|
|
@ -13,7 +13,7 @@ module AccountFinderConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def representative
|
def representative
|
||||||
find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.without_suspended.first
|
Account.find(-99)
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_local(username)
|
def find_local(username)
|
||||||
|
|
|
@ -39,11 +39,17 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
delegate :moved?, to: :object
|
delegate :moved?, to: :object
|
||||||
|
|
||||||
def id
|
def id
|
||||||
account_url(object)
|
object.instance_actor? ? instance_actor_url : account_url(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
object.bot? ? 'Service' : 'Person'
|
if object.instance_actor?
|
||||||
|
'Application'
|
||||||
|
elsif object.bot?
|
||||||
|
'Service'
|
||||||
|
else
|
||||||
|
'Person'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def following
|
def following
|
||||||
|
@ -55,7 +61,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox
|
def inbox
|
||||||
account_inbox_url(object)
|
object.instance_actor? ? instance_actor_inbox_url : account_inbox_url(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def outbox
|
def outbox
|
||||||
|
@ -95,7 +101,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def url
|
def url
|
||||||
short_account_url(object)
|
object.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def avatar_exists?
|
def avatar_exists?
|
||||||
|
|
|
@ -10,10 +10,20 @@ class WebfingerSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def aliases
|
def aliases
|
||||||
|
if object.instance_actor?
|
||||||
|
[instance_actor_url]
|
||||||
|
else
|
||||||
[short_account_url(object), account_url(object)]
|
[short_account_url(object), account_url(object)]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def links
|
def links
|
||||||
|
if object.instance_actor?
|
||||||
|
[
|
||||||
|
{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: about_more_url(instance_actor: true) },
|
||||||
|
{ rel: 'self', type: 'application/activity+json', href: instance_actor_url },
|
||||||
|
]
|
||||||
|
else
|
||||||
[
|
[
|
||||||
{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) },
|
{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) },
|
||||||
{ rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') },
|
{ rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') },
|
||||||
|
@ -21,4 +31,5 @@ class WebfingerSerializer < ActiveModel::Serializer
|
||||||
{ rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" },
|
{ rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" },
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,5 +43,7 @@
|
||||||
= mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email
|
= mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email
|
||||||
|
|
||||||
.column-3
|
.column-3
|
||||||
|
= render 'application/flashes'
|
||||||
|
|
||||||
.box-widget
|
.box-widget
|
||||||
.rich-formatting= @instance_presenter.site_extended_description.html_safe.presence || t('about.extended_description_html')
|
.rich-formatting= @instance_presenter.site_extended_description.html_safe.presence || t('about.extended_description_html')
|
||||||
|
|
|
@ -4,6 +4,22 @@ doc << Ox::Element.new('XRD').tap do |xrd|
|
||||||
xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
|
xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
|
||||||
|
|
||||||
xrd << (Ox::Element.new('Subject') << @account.to_webfinger_s)
|
xrd << (Ox::Element.new('Subject') << @account.to_webfinger_s)
|
||||||
|
|
||||||
|
if @account.instance_actor?
|
||||||
|
xrd << (Ox::Element.new('Alias') << instance_actor_url)
|
||||||
|
|
||||||
|
xrd << Ox::Element.new('Link').tap do |link|
|
||||||
|
link['rel'] = 'http://webfinger.net/rel/profile-page'
|
||||||
|
link['type'] = 'text/html'
|
||||||
|
link['href'] = about_more_url(instance_actor: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
xrd << Ox::Element.new('Link').tap do |link|
|
||||||
|
link['rel'] = 'self'
|
||||||
|
link['type'] = 'application/activity+json'
|
||||||
|
link['href'] = instance_actor_url
|
||||||
|
end
|
||||||
|
else
|
||||||
xrd << (Ox::Element.new('Alias') << short_account_url(@account))
|
xrd << (Ox::Element.new('Alias') << short_account_url(@account))
|
||||||
xrd << (Ox::Element.new('Alias') << account_url(@account))
|
xrd << (Ox::Element.new('Alias') << account_url(@account))
|
||||||
|
|
||||||
|
@ -29,6 +45,7 @@ doc << Ox::Element.new('XRD').tap do |xrd|
|
||||||
link['rel'] = 'http://ostatus.org/schema/1.0/subscribe'
|
link['rel'] = 'http://ostatus.org/schema/1.0/subscribe'
|
||||||
link['template'] = "#{authorize_interaction_url}?acct={uri}"
|
link['template'] = "#{authorize_interaction_url}?acct={uri}"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
('<?xml version="1.0" encoding="UTF-8"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')
|
('<?xml version="1.0" encoding="UTF-8"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')
|
||||||
|
|
|
@ -24,6 +24,9 @@ en:
|
||||||
generic_description: "%{domain} is one server in the network"
|
generic_description: "%{domain} is one server in the network"
|
||||||
get_apps: Try a mobile app
|
get_apps: Try a mobile app
|
||||||
hosted_on: Mastodon hosted on %{domain}
|
hosted_on: Mastodon hosted on %{domain}
|
||||||
|
instance_actor_flash: |
|
||||||
|
This account is a virtual actor used to represent the server itself and not any individual user.
|
||||||
|
It is used for federation purposes and should not be blocked unless you want to block the whole instance, in which case you should use a domain block.
|
||||||
learn_more: Learn more
|
learn_more: Learn more
|
||||||
privacy_policy: Privacy policy
|
privacy_policy: Privacy policy
|
||||||
see_whats_happening: See what's happening
|
see_whats_happening: See what's happening
|
||||||
|
|
|
@ -28,6 +28,10 @@ Rails.application.routes.draw do
|
||||||
get 'intent', to: 'intents#show'
|
get 'intent', to: 'intents#show'
|
||||||
get 'custom.css', to: 'custom_css#show', as: :custom_css
|
get 'custom.css', to: 'custom_css#show', as: :custom_css
|
||||||
|
|
||||||
|
resource :instance_actor, path: 'actor', only: [:show] do
|
||||||
|
resource :inbox, only: [:create], module: :activitypub
|
||||||
|
end
|
||||||
|
|
||||||
devise_scope :user do
|
devise_scope :user do
|
||||||
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
|
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
|
||||||
match '/auth/finish_signup' => 'auth/confirmations#finish_signup', via: [:get, :patch], as: :finish_signup
|
match '/auth/finish_signup' => 'auth/confirmations#finish_signup', via: [:get, :patch], as: :finish_signup
|
||||||
|
|
9
db/migrate/20190715164535_add_instance_actor.rb
Normal file
9
db/migrate/20190715164535_add_instance_actor.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class AddInstanceActor < ActiveRecord::Migration[5.2]
|
||||||
|
def up
|
||||||
|
Account.create!(id: -99, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
Account.find_by(id: -99, actor_type: 'Application').destroy!
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2019_07_06_233204) do
|
ActiveRecord::Schema.define(version: 2019_07_15_164535) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
Doorkeeper::Application.create!(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow')
|
Doorkeeper::Application.create!(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow')
|
||||||
|
|
||||||
|
domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain
|
||||||
|
Account.create!(id: -99, actor_type: 'Application', locked: true, username: domain)
|
||||||
|
|
||||||
if Rails.env.development?
|
if Rails.env.development?
|
||||||
domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain
|
|
||||||
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
|
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
|
||||||
admin.save(validate: false)
|
admin.save(validate: false)
|
||||||
User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, admin: true, account: admin, agreement: true, approved: true).save!
|
User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, admin: true, account: admin, agreement: true, approved: true).save!
|
||||||
|
|
|
@ -450,7 +450,7 @@ RSpec.describe Account, type: :model do
|
||||||
describe '.domains' do
|
describe '.domains' do
|
||||||
it 'returns domains' do
|
it 'returns domains' do
|
||||||
Fabricate(:account, domain: 'domain')
|
Fabricate(:account, domain: 'domain')
|
||||||
expect(Account.domains).to match_array(['domain'])
|
expect(Account.remote.domains).to match_array(['domain'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -665,7 +665,7 @@ RSpec.describe Account, type: :model do
|
||||||
{ username: 'b', domain: 'b' },
|
{ username: 'b', domain: 'b' },
|
||||||
].map(&method(:Fabricate).curry(2).call(:account))
|
].map(&method(:Fabricate).curry(2).call(:account))
|
||||||
|
|
||||||
expect(Account.alphabetic).to eq matches
|
expect(Account.where('id > 0').alphabetic).to eq matches
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -732,7 +732,7 @@ RSpec.describe Account, type: :model do
|
||||||
2.times { Fabricate(:account, domain: 'example.com') }
|
2.times { Fabricate(:account, domain: 'example.com') }
|
||||||
Fabricate(:account, domain: 'example2.com')
|
Fabricate(:account, domain: 'example2.com')
|
||||||
|
|
||||||
results = Account.by_domain_accounts
|
results = Account.where('id > 0').by_domain_accounts
|
||||||
expect(results.length).to eq 2
|
expect(results.length).to eq 2
|
||||||
expect(results.first.domain).to eq 'example.com'
|
expect(results.first.domain).to eq 'example.com'
|
||||||
expect(results.first.accounts_count).to eq 2
|
expect(results.first.accounts_count).to eq 2
|
||||||
|
@ -745,7 +745,7 @@ RSpec.describe Account, type: :model do
|
||||||
it 'returns an array of accounts who do not have a domain' do
|
it 'returns an array of accounts who do not have a domain' do
|
||||||
account_1 = Fabricate(:account, domain: nil)
|
account_1 = Fabricate(:account, domain: nil)
|
||||||
account_2 = Fabricate(:account, domain: 'example.com')
|
account_2 = Fabricate(:account, domain: 'example.com')
|
||||||
expect(Account.local).to match_array([account_1])
|
expect(Account.where('id > 0').local).to match_array([account_1])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -756,14 +756,14 @@ RSpec.describe Account, type: :model do
|
||||||
matches[index] = Fabricate(:account, domain: matches[index])
|
matches[index] = Fabricate(:account, domain: matches[index])
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Account.partitioned).to match_array(matches)
|
expect(Account.where('id > 0').partitioned).to match_array(matches)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'recent' do
|
describe 'recent' do
|
||||||
it 'returns a relation of accounts sorted by recent creation' do
|
it 'returns a relation of accounts sorted by recent creation' do
|
||||||
matches = 2.times.map { Fabricate(:account) }
|
matches = 2.times.map { Fabricate(:account) }
|
||||||
expect(Account.recent).to match_array(matches)
|
expect(Account.where('id > 0').recent).to match_array(matches)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ RSpec.describe FetchRemoteAccountService, type: :service do
|
||||||
let(:url) { 'https://example.com/alice' }
|
let(:url) { 'https://example.com/alice' }
|
||||||
let(:prefetched_body) { nil }
|
let(:prefetched_body) { nil }
|
||||||
let(:protocol) { :ostatus }
|
let(:protocol) { :ostatus }
|
||||||
let!(:representative) { Fabricate(:account) }
|
|
||||||
|
|
||||||
subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) }
|
subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) }
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe FetchResourceService, type: :service do
|
RSpec.describe FetchResourceService, type: :service do
|
||||||
let!(:representative) { Fabricate(:account) }
|
|
||||||
|
|
||||||
describe '#call' do
|
describe '#call' do
|
||||||
let(:url) { 'http://example.com' }
|
let(:url) { 'http://example.com' }
|
||||||
|
|
||||||
|
@ -60,7 +58,7 @@ RSpec.describe FetchResourceService, type: :service do
|
||||||
|
|
||||||
it 'signs request' do
|
it 'signs request' do
|
||||||
subject
|
subject
|
||||||
expect(a_request(:get, url).with(headers: { 'Signature' => /keyId="#{Regexp.escape(ActivityPub::TagManager.instance.uri_for(representative) + '#main-key')}"/ })).to have_been_made
|
expect(a_request(:get, url).with(headers: { 'Signature' => /keyId="#{Regexp.escape(ActivityPub::TagManager.instance.uri_for(Account.representative) + '#main-key')}"/ })).to have_been_made
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when content type is application/atom+xml' do
|
context 'when content type is application/atom+xml' do
|
||||||
|
|
|
@ -27,6 +27,7 @@ RSpec.configure do |config|
|
||||||
end
|
end
|
||||||
|
|
||||||
config.before :suite do
|
config.before :suite do
|
||||||
|
Rails.application.load_seed
|
||||||
Chewy.strategy(:bypass)
|
Chewy.strategy(:bypass)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue