Merge commit '163db814c2b3cf544b78e427e7f7bbd99b94a025' into glitch-soc/merge-upstream
commit
0700eb58bc
|
@ -80,14 +80,12 @@ Rails/WhereExists:
|
||||||
- 'app/lib/activitypub/activity/create.rb'
|
- 'app/lib/activitypub/activity/create.rb'
|
||||||
- 'app/lib/delivery_failure_tracker.rb'
|
- 'app/lib/delivery_failure_tracker.rb'
|
||||||
- 'app/lib/feed_manager.rb'
|
- 'app/lib/feed_manager.rb'
|
||||||
- 'app/lib/status_cache_hydrator.rb'
|
|
||||||
- 'app/lib/suspicious_sign_in_detector.rb'
|
- 'app/lib/suspicious_sign_in_detector.rb'
|
||||||
- 'app/models/poll.rb'
|
- 'app/models/poll.rb'
|
||||||
- 'app/models/session_activation.rb'
|
- 'app/models/session_activation.rb'
|
||||||
- 'app/models/status.rb'
|
- 'app/models/status.rb'
|
||||||
- 'app/policies/status_policy.rb'
|
- 'app/policies/status_policy.rb'
|
||||||
- 'app/serializers/rest/announcement_serializer.rb'
|
- 'app/serializers/rest/announcement_serializer.rb'
|
||||||
- 'app/serializers/rest/tag_serializer.rb'
|
|
||||||
- 'app/services/activitypub/fetch_remote_status_service.rb'
|
- 'app/services/activitypub/fetch_remote_status_service.rb'
|
||||||
- 'app/services/vote_service.rb'
|
- 'app/services/vote_service.rb'
|
||||||
- 'app/validators/reaction_validator.rb'
|
- 'app/validators/reaction_validator.rb'
|
||||||
|
|
10
Gemfile.lock
10
Gemfile.lock
|
@ -150,7 +150,7 @@ GEM
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
parser (>= 2.4)
|
parser (>= 2.4)
|
||||||
smart_properties
|
smart_properties
|
||||||
bigdecimal (3.1.5)
|
bigdecimal (3.1.6)
|
||||||
bindata (2.4.15)
|
bindata (2.4.15)
|
||||||
binding_of_caller (1.0.0)
|
binding_of_caller (1.0.0)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
|
@ -398,12 +398,12 @@ GEM
|
||||||
activerecord
|
activerecord
|
||||||
kaminari-core (= 1.2.2)
|
kaminari-core (= 1.2.2)
|
||||||
kaminari-core (1.2.2)
|
kaminari-core (1.2.2)
|
||||||
kt-paperclip (7.2.1)
|
kt-paperclip (7.2.2)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 4.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
marcel (~> 1.0.1)
|
marcel (~> 1.0.1)
|
||||||
mime-types
|
mime-types
|
||||||
terrapin (~> 0.6.0)
|
terrapin (>= 0.6.0, < 2.0)
|
||||||
language_server-protocol (3.17.0.3)
|
language_server-protocol (3.17.0.3)
|
||||||
launchy (2.5.2)
|
launchy (2.5.2)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
|
@ -600,8 +600,8 @@ GEM
|
||||||
rdf (3.3.1)
|
rdf (3.3.1)
|
||||||
bcp47_spec (~> 0.2)
|
bcp47_spec (~> 0.2)
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
rdf-normalize (0.6.1)
|
rdf-normalize (0.7.0)
|
||||||
rdf (~> 3.2)
|
rdf (~> 3.3)
|
||||||
rdoc (6.6.2)
|
rdoc (6.6.2)
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
redcarpet (3.6.0)
|
redcarpet (3.6.0)
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :audit_log, :index?
|
authorize :audit_log, :index?
|
||||||
@auditable_accounts = Account.where(id: Admin::ActionLog.select('distinct account_id')).select(:id, :username)
|
@auditable_accounts = Account.auditable.select(:id, :username)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
||||||
return [] if hide_results?
|
return [] if hide_results?
|
||||||
|
|
||||||
scope = default_accounts
|
scope = default_accounts
|
||||||
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id
|
scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id
|
||||||
scope.merge(paginated_follows).to_a
|
scope.merge(paginated_follows).to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
||||||
return [] if hide_results?
|
return [] if hide_results?
|
||||||
|
|
||||||
scope = default_accounts
|
scope = default_accounts
|
||||||
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id
|
scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id
|
||||||
scope.merge(paginated_follows).to_a
|
scope.merge(paginated_follows).to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ module JsonLdHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_resource(uri, id, on_behalf_of = nil)
|
def fetch_resource(uri, id, on_behalf_of = nil, request_options: {})
|
||||||
unless id
|
unless id
|
||||||
json = fetch_resource_without_id_validation(uri, on_behalf_of)
|
json = fetch_resource_without_id_validation(uri, on_behalf_of)
|
||||||
|
|
||||||
|
@ -164,14 +164,14 @@ module JsonLdHelper
|
||||||
uri = json['id']
|
uri = json['id']
|
||||||
end
|
end
|
||||||
|
|
||||||
json = fetch_resource_without_id_validation(uri, on_behalf_of)
|
json = fetch_resource_without_id_validation(uri, on_behalf_of, request_options: request_options)
|
||||||
json.present? && json['id'] == uri ? json : nil
|
json.present? && json['id'] == uri ? json : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false)
|
def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false, request_options: {})
|
||||||
on_behalf_of ||= Account.representative
|
on_behalf_of ||= Account.representative
|
||||||
|
|
||||||
build_request(uri, on_behalf_of).perform do |response|
|
build_request(uri, on_behalf_of, options: request_options).perform do |response|
|
||||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error
|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error
|
||||||
|
|
||||||
body_to_json(response.body_with_limit) if response.code == 200
|
body_to_json(response.body_with_limit) if response.code == 200
|
||||||
|
@ -204,8 +204,8 @@ module JsonLdHelper
|
||||||
response.code == 501 || ((400...500).cover?(response.code) && ![401, 408, 429].include?(response.code))
|
response.code == 501 || ((400...500).cover?(response.code) && ![401, 408, 429].include?(response.code))
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_request(uri, on_behalf_of = nil)
|
def build_request(uri, on_behalf_of = nil, options: {})
|
||||||
Request.new(:get, uri).tap do |request|
|
Request.new(:get, uri, **options).tap do |request|
|
||||||
request.on_behalf_of(on_behalf_of) if on_behalf_of
|
request.on_behalf_of(on_behalf_of) if on_behalf_of
|
||||||
request.add_headers('Accept' => 'application/activity+json, application/ld+json')
|
request.add_headers('Accept' => 'application/activity+json, application/ld+json')
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||||
import type { TypedUseSelectorHook } from 'react-redux';
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import type { AppDispatch, RootState } from './store';
|
import type { AppDispatch, RootState } from './store';
|
||||||
|
|
||||||
export const useAppDispatch: () => AppDispatch = useDispatch;
|
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
|
||||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
export const useAppSelector = useSelector.withTypes<RootState>();
|
||||||
|
|
||||||
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
||||||
state: RootState;
|
state: RootState;
|
||||||
|
|
|
@ -100,9 +100,8 @@ table + p {
|
||||||
border-top-right-radius: 12px;
|
border-top-right-radius: 12px;
|
||||||
height: 140px;
|
height: 140px;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
background-color: #f3f2f5;
|
background-position: center !important;
|
||||||
background-position: center;
|
background-size: cover !important;
|
||||||
background-size: cover;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-account-banner-inner-td {
|
.email-account-banner-inner-td {
|
||||||
|
|
|
@ -26,11 +26,11 @@ class StatusCacheHydrator
|
||||||
|
|
||||||
def hydrate_non_reblog_payload(empty_payload, account_id)
|
def hydrate_non_reblog_payload(empty_payload, account_id)
|
||||||
empty_payload.tap do |payload|
|
empty_payload.tap do |payload|
|
||||||
payload[:favourited] = Favourite.where(account_id: account_id, status_id: @status.id).exists?
|
payload[:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.id)
|
||||||
payload[:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.id).exists?
|
payload[:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.id)
|
||||||
payload[:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.conversation_id).exists?
|
payload[:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.conversation_id)
|
||||||
payload[:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.id).exists?
|
payload[:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.id)
|
||||||
payload[:pinned] = StatusPin.where(account_id: account_id, status_id: @status.id).exists? if @status.account_id == account_id
|
payload[:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.id) if @status.account_id == account_id
|
||||||
payload[:filtered] = mapped_applied_custom_filter(account_id, @status)
|
payload[:filtered] = mapped_applied_custom_filter(account_id, @status)
|
||||||
|
|
||||||
if payload[:poll]
|
if payload[:poll]
|
||||||
|
@ -51,11 +51,11 @@ class StatusCacheHydrator
|
||||||
# used to create the status, we need to hydrate it here too
|
# used to create the status, we need to hydrate it here too
|
||||||
payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account_id
|
payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account_id
|
||||||
|
|
||||||
payload[:reblog][:favourited] = Favourite.where(account_id: account_id, status_id: @status.reblog_of_id).exists?
|
payload[:reblog][:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.reblog_of_id)
|
||||||
payload[:reblog][:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.reblog_of_id).exists?
|
payload[:reblog][:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.reblog_of_id)
|
||||||
payload[:reblog][:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.reblog.conversation_id).exists?
|
payload[:reblog][:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.reblog.conversation_id)
|
||||||
payload[:reblog][:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.reblog_of_id).exists?
|
payload[:reblog][:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.reblog_of_id)
|
||||||
payload[:reblog][:pinned] = StatusPin.where(account_id: account_id, status_id: @status.reblog_of_id).exists? if @status.reblog.account_id == account_id
|
payload[:reblog][:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.reblog_of_id) if @status.reblog.account_id == account_id
|
||||||
payload[:reblog][:filtered] = payload[:filtered]
|
payload[:reblog][:filtered] = payload[:filtered]
|
||||||
|
|
||||||
if payload[:reblog][:poll]
|
if payload[:reblog][:poll]
|
||||||
|
|
|
@ -130,6 +130,7 @@ class Account < ApplicationRecord
|
||||||
scope :matches_username, ->(value) { where('lower((username)::text) LIKE lower(?)', "#{value}%") }
|
scope :matches_username, ->(value) { where('lower((username)::text) LIKE lower(?)', "#{value}%") }
|
||||||
scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) }
|
scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) }
|
||||||
scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) }
|
scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) }
|
||||||
|
scope :auditable, -> { where(id: Admin::ActionLog.select(:account_id).distinct) }
|
||||||
scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
|
scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
|
||||||
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
|
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
|
||||||
scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
|
scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
|
||||||
|
|
|
@ -72,7 +72,7 @@ class Admin::ActionLogFilter
|
||||||
end
|
end
|
||||||
|
|
||||||
def results
|
def results
|
||||||
scope = latest_action_logs.includes(:target)
|
scope = latest_action_logs.includes(:target, :account)
|
||||||
|
|
||||||
params.each do |key, value|
|
params.each do |key, value|
|
||||||
next if key.to_s == 'page'
|
next if key.to_s == 'page'
|
||||||
|
|
|
@ -19,7 +19,7 @@ class REST::TagSerializer < ActiveModel::Serializer
|
||||||
if instance_options && instance_options[:relationships]
|
if instance_options && instance_options[:relationships]
|
||||||
instance_options[:relationships].following_map[object.id] || false
|
instance_options[:relationships].following_map[object.id] || false
|
||||||
else
|
else
|
||||||
TagFollow.where(tag_id: object.id, account_id: current_user.account_id).exists?
|
TagFollow.exists?(tag_id: object.id, account_id: current_user.account_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,20 @@ class ActivityPub::FetchRepliesService < BaseService
|
||||||
return unless @allow_synchronous_requests
|
return unless @allow_synchronous_requests
|
||||||
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
|
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
|
||||||
|
|
||||||
|
# NOTE: For backward compatibility reasons, Mastodon signs outgoing
|
||||||
|
# queries incorrectly by default.
|
||||||
|
#
|
||||||
|
# While this is relevant for all URLs with query strings, this is
|
||||||
|
# the only code path where this happens in practice.
|
||||||
|
#
|
||||||
|
# Therefore, retry with correct signatures if this fails.
|
||||||
|
begin
|
||||||
fetch_resource_without_id_validation(collection_or_uri, nil, true)
|
fetch_resource_without_id_validation(collection_or_uri, nil, true)
|
||||||
|
rescue Mastodon::UnexpectedResponseError => e
|
||||||
|
raise unless e.response && e.response.code == 401 && Addressable::URI.parse(collection_or_uri).query.present?
|
||||||
|
|
||||||
|
fetch_resource_without_id_validation(collection_or_uri, nil, true, request_options: { with_query_string: true })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def filtered_replies
|
def filtered_replies
|
||||||
|
|
|
@ -835,6 +835,25 @@ RSpec.describe Account do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'scopes' do
|
describe 'scopes' do
|
||||||
|
describe 'auditable' do
|
||||||
|
let!(:alice) { Fabricate :account }
|
||||||
|
let!(:bob) { Fabricate :account }
|
||||||
|
|
||||||
|
before do
|
||||||
|
2.times { Fabricate :action_log, account: alice }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns distinct accounts with action log records' do
|
||||||
|
results = described_class.auditable
|
||||||
|
|
||||||
|
expect(results.size)
|
||||||
|
.to eq(1)
|
||||||
|
expect(results)
|
||||||
|
.to include(alice)
|
||||||
|
.and not_include(bob)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'alphabetic' do
|
describe 'alphabetic' do
|
||||||
it 'sorts by alphabetic order of domain and username' do
|
it 'sorts by alphabetic order of domain and username' do
|
||||||
matches = [
|
matches = [
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Api::V1::Accounts::FollowerAccountsController do
|
describe 'API V1 Accounts FollowerAccounts' do
|
||||||
render_views
|
|
||||||
|
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||||
|
let(:scopes) { 'read:accounts' }
|
||||||
|
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||||
let(:account) { Fabricate(:account) }
|
let(:account) { Fabricate(:account) }
|
||||||
let(:alice) { Fabricate(:account) }
|
let(:alice) { Fabricate(:account) }
|
||||||
let(:bob) { Fabricate(:account) }
|
let(:bob) { Fabricate(:account) }
|
||||||
|
@ -14,12 +14,11 @@ describe Api::V1::Accounts::FollowerAccountsController do
|
||||||
before do
|
before do
|
||||||
alice.follow!(account)
|
alice.follow!(account)
|
||||||
bob.follow!(account)
|
bob.follow!(account)
|
||||||
allow(controller).to receive(:doorkeeper_token) { token }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET /api/v1/accounts/:acount_id/followers' do
|
||||||
it 'returns accounts following the given account', :aggregate_failures do
|
it 'returns accounts following the given account', :aggregate_failures do
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(body_as_json.size).to eq 2
|
expect(body_as_json.size).to eq 2
|
||||||
|
@ -28,7 +27,7 @@ describe Api::V1::Accounts::FollowerAccountsController do
|
||||||
|
|
||||||
it 'does not return blocked users', :aggregate_failures do
|
it 'does not return blocked users', :aggregate_failures do
|
||||||
user.account.block!(bob)
|
user.account.block!(bob)
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(body_as_json.size).to eq 1
|
expect(body_as_json.size).to eq 1
|
||||||
|
@ -41,7 +40,7 @@ describe Api::V1::Accounts::FollowerAccountsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'hides results' do
|
it 'hides results' do
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers
|
||||||
expect(body_as_json.size).to eq 0
|
expect(body_as_json.size).to eq 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -51,7 +50,7 @@ describe Api::V1::Accounts::FollowerAccountsController do
|
||||||
|
|
||||||
it 'returns all accounts, including muted accounts' do
|
it 'returns all accounts, including muted accounts' do
|
||||||
account.mute!(bob)
|
account.mute!(bob)
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/followers", params: { limit: 2 }, headers: headers
|
||||||
|
|
||||||
expect(body_as_json.size).to eq 2
|
expect(body_as_json.size).to eq 2
|
||||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Api::V1::Accounts::FollowingAccountsController do
|
describe 'API V1 Accounts FollowingAccounts' do
|
||||||
render_views
|
|
||||||
|
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||||
|
let(:scopes) { 'read:accounts' }
|
||||||
|
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||||
let(:account) { Fabricate(:account) }
|
let(:account) { Fabricate(:account) }
|
||||||
let(:alice) { Fabricate(:account) }
|
let(:alice) { Fabricate(:account) }
|
||||||
let(:bob) { Fabricate(:account) }
|
let(:bob) { Fabricate(:account) }
|
||||||
|
@ -14,12 +14,11 @@ describe Api::V1::Accounts::FollowingAccountsController do
|
||||||
before do
|
before do
|
||||||
account.follow!(alice)
|
account.follow!(alice)
|
||||||
account.follow!(bob)
|
account.follow!(bob)
|
||||||
allow(controller).to receive(:doorkeeper_token) { token }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET /api/v1/accounts/:account_id/following' do
|
||||||
it 'returns accounts followed by the given account', :aggregate_failures do
|
it 'returns accounts followed by the given account', :aggregate_failures do
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(body_as_json.size).to eq 2
|
expect(body_as_json.size).to eq 2
|
||||||
|
@ -28,7 +27,7 @@ describe Api::V1::Accounts::FollowingAccountsController do
|
||||||
|
|
||||||
it 'does not return blocked users', :aggregate_failures do
|
it 'does not return blocked users', :aggregate_failures do
|
||||||
user.account.block!(bob)
|
user.account.block!(bob)
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(body_as_json.size).to eq 1
|
expect(body_as_json.size).to eq 1
|
||||||
|
@ -41,7 +40,7 @@ describe Api::V1::Accounts::FollowingAccountsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'hides results' do
|
it 'hides results' do
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers
|
||||||
expect(body_as_json.size).to eq 0
|
expect(body_as_json.size).to eq 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -51,7 +50,7 @@ describe Api::V1::Accounts::FollowingAccountsController do
|
||||||
|
|
||||||
it 'returns all accounts, including muted accounts' do
|
it 'returns all accounts, including muted accounts' do
|
||||||
account.mute!(bob)
|
account.mute!(bob)
|
||||||
get :index, params: { account_id: account.id, limit: 2 }
|
get "/api/v1/accounts/#{account.id}/following", params: { limit: 2 }, headers: headers
|
||||||
|
|
||||||
expect(body_as_json.size).to eq 2
|
expect(body_as_json.size).to eq 2
|
||||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
90
yarn.lock
90
yarn.lock
|
@ -3786,16 +3786,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@npm:6.9.1":
|
|
||||||
version: 6.9.1
|
|
||||||
resolution: "@typescript-eslint/scope-manager@npm:6.9.1"
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types": "npm:6.9.1"
|
|
||||||
"@typescript-eslint/visitor-keys": "npm:6.9.1"
|
|
||||||
checksum: 53fa7c3813d22b119e464f9b6d7d23407dfe103ee8ad2dcacf9ad6d656fda20e2bb3346df39e62b0e6b6ce71572ce5838071c5d2cca6daa4e0ce117ff22eafe5
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@npm:6.19.0":
|
"@typescript-eslint/type-utils@npm:6.19.0":
|
||||||
version: 6.19.0
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/type-utils@npm:6.19.0"
|
resolution: "@typescript-eslint/type-utils@npm:6.19.0"
|
||||||
|
@ -3820,13 +3810,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/types@npm:6.9.1":
|
|
||||||
version: 6.9.1
|
|
||||||
resolution: "@typescript-eslint/types@npm:6.9.1"
|
|
||||||
checksum: 4ba21ba18e256da210a4caedfbc5d4927cf8cb4f2c4d74f8ccc865576f3659b974e79119d3c94db2b68a4cec9cd687e43971d355450b7082d6d1736a5dd6db85
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@npm:6.19.0":
|
"@typescript-eslint/typescript-estree@npm:6.19.0":
|
||||||
version: 6.19.0
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/typescript-estree@npm:6.19.0"
|
resolution: "@typescript-eslint/typescript-estree@npm:6.19.0"
|
||||||
|
@ -3846,25 +3829,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@npm:6.9.1":
|
"@typescript-eslint/utils@npm:6.19.0, @typescript-eslint/utils@npm:^6.5.0":
|
||||||
version: 6.9.1
|
|
||||||
resolution: "@typescript-eslint/typescript-estree@npm:6.9.1"
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types": "npm:6.9.1"
|
|
||||||
"@typescript-eslint/visitor-keys": "npm:6.9.1"
|
|
||||||
debug: "npm:^4.3.4"
|
|
||||||
globby: "npm:^11.1.0"
|
|
||||||
is-glob: "npm:^4.0.3"
|
|
||||||
semver: "npm:^7.5.4"
|
|
||||||
ts-api-utils: "npm:^1.0.1"
|
|
||||||
peerDependenciesMeta:
|
|
||||||
typescript:
|
|
||||||
optional: true
|
|
||||||
checksum: 850b1865a90107879186c3f2969968a2c08fc6fcc56d146483c297cf5be376e33d505ac81533ba8e8103ca4d2edfea7d21b178de9e52217f7ee2922f51a445fa
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/utils@npm:6.19.0":
|
|
||||||
version: 6.19.0
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/utils@npm:6.19.0"
|
resolution: "@typescript-eslint/utils@npm:6.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -3881,23 +3846,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/utils@npm:^6.5.0":
|
|
||||||
version: 6.9.1
|
|
||||||
resolution: "@typescript-eslint/utils@npm:6.9.1"
|
|
||||||
dependencies:
|
|
||||||
"@eslint-community/eslint-utils": "npm:^4.4.0"
|
|
||||||
"@types/json-schema": "npm:^7.0.12"
|
|
||||||
"@types/semver": "npm:^7.5.0"
|
|
||||||
"@typescript-eslint/scope-manager": "npm:6.9.1"
|
|
||||||
"@typescript-eslint/types": "npm:6.9.1"
|
|
||||||
"@typescript-eslint/typescript-estree": "npm:6.9.1"
|
|
||||||
semver: "npm:^7.5.4"
|
|
||||||
peerDependencies:
|
|
||||||
eslint: ^7.0.0 || ^8.0.0
|
|
||||||
checksum: 3d329d54c3d155ed29e2b456a602aef76bda1b88dfcf847145849362e4ddefabe5c95de236de750d08d5da9bedcfb2131bdfd784ce4eb87cf82728f0b6662033
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@npm:6.19.0":
|
"@typescript-eslint/visitor-keys@npm:6.19.0":
|
||||||
version: 6.19.0
|
version: 6.19.0
|
||||||
resolution: "@typescript-eslint/visitor-keys@npm:6.19.0"
|
resolution: "@typescript-eslint/visitor-keys@npm:6.19.0"
|
||||||
|
@ -3908,16 +3856,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@npm:6.9.1":
|
|
||||||
version: 6.9.1
|
|
||||||
resolution: "@typescript-eslint/visitor-keys@npm:6.9.1"
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types": "npm:6.9.1"
|
|
||||||
eslint-visitor-keys: "npm:^3.4.1"
|
|
||||||
checksum: ac5f375a177add30489e5b63cafa8d82a196b33624bb36418422ebe0d7973b3ba550dc7e0dda36ea75a94cf9b200b4fb5f5fb4d77c027fd801201c1a269d343b
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@ungap/structured-clone@npm:^1.2.0":
|
"@ungap/structured-clone@npm:^1.2.0":
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
resolution: "@ungap/structured-clone@npm:1.2.0"
|
resolution: "@ungap/structured-clone@npm:1.2.0"
|
||||||
|
@ -9377,7 +9315,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"intl-messageformat@npm:10.5.10":
|
"intl-messageformat@npm:10.5.10, intl-messageformat@npm:^10.3.5":
|
||||||
version: 10.5.10
|
version: 10.5.10
|
||||||
resolution: "intl-messageformat@npm:10.5.10"
|
resolution: "intl-messageformat@npm:10.5.10"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -9389,18 +9327,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"intl-messageformat@npm:^10.3.5":
|
|
||||||
version: 10.5.8
|
|
||||||
resolution: "intl-messageformat@npm:10.5.8"
|
|
||||||
dependencies:
|
|
||||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
|
||||||
"@formatjs/fast-memoize": "npm:2.2.0"
|
|
||||||
"@formatjs/icu-messageformat-parser": "npm:2.7.3"
|
|
||||||
tslib: "npm:^2.4.0"
|
|
||||||
checksum: 1d2854aae8471ec48165ca265760d6c5b1814eca831c88db698eb29b5ed20bee21ca8533090c9d28d9c6f1d844dda210b0bc58a2e036446158fae0845e5eed4f
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"invariant@npm:^2.2.2, invariant@npm:^2.2.4":
|
"invariant@npm:^2.2.2, invariant@npm:^2.2.4":
|
||||||
version: 2.2.4
|
version: 2.2.4
|
||||||
resolution: "invariant@npm:2.2.4"
|
resolution: "invariant@npm:2.2.4"
|
||||||
|
@ -13897,8 +13823,8 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"react-redux@npm:^9.0.4":
|
"react-redux@npm:^9.0.4":
|
||||||
version: 9.0.4
|
version: 9.1.0
|
||||||
resolution: "react-redux@npm:9.0.4"
|
resolution: "react-redux@npm:9.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/use-sync-external-store": "npm:^0.0.3"
|
"@types/use-sync-external-store": "npm:^0.0.3"
|
||||||
use-sync-external-store: "npm:^1.0.0"
|
use-sync-external-store: "npm:^1.0.0"
|
||||||
|
@ -13914,7 +13840,7 @@ __metadata:
|
||||||
optional: true
|
optional: true
|
||||||
redux:
|
redux:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 23af10014b129aeb051de729bde01de21175170b860deefb7ad83483feab5816253f770a4cea93333fc22a53ac9ac699b27f5c3705c388dab53dbcb2906a571a
|
checksum: 53161b5dc4d109020fbc42d26906ace92fed9ba1d7ab6274af60e9c0684583d20d1c8ec6d58601ac7b833c6468a652bbf3d4a102149d1793cb8a28b05b042f73
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -14775,15 +14701,15 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"sass@npm:^1.62.1":
|
"sass@npm:^1.62.1":
|
||||||
version: 1.69.7
|
version: 1.70.0
|
||||||
resolution: "sass@npm:1.69.7"
|
resolution: "sass@npm:1.70.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar: "npm:>=3.0.0 <4.0.0"
|
chokidar: "npm:>=3.0.0 <4.0.0"
|
||||||
immutable: "npm:^4.0.0"
|
immutable: "npm:^4.0.0"
|
||||||
source-map-js: "npm:>=0.6.2 <2.0.0"
|
source-map-js: "npm:>=0.6.2 <2.0.0"
|
||||||
bin:
|
bin:
|
||||||
sass: sass.js
|
sass: sass.js
|
||||||
checksum: 773d0938e7d4ff3972d3fda3132f34fe98a2f712e028a58e28fecd615434795eff3266eddc38d5e13f03b90c0d6360d0e737b30bff2949a47280c64a18e0fb18
|
checksum: 7c309ee1c096d591746d122da9f1ebd65b4c4b3a60c2cc0ec720fd98fe1205fa8b44c9f563d113b9fdfeb25af1e32ec9b3e048bd4b8e05d267f020953bd7baf0
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue