Merge branch 'main' into bark-prod
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dalite 2024-02-06 14:53:05 +01:00
commit 757da79182
30 changed files with 298 additions and 251 deletions

View file

@ -70,7 +70,7 @@ services:
hard: -1
libretranslate:
image: libretranslate/libretranslate:v1.5.4
image: libretranslate/libretranslate:v1.5.5
restart: unless-stopped
volumes:
- lt-data:/home/libretranslate/.local

View file

@ -139,7 +139,7 @@ jobs:
- name: Upload coverage reports to Codecov
if: matrix.ruby-version == '.ruby-version'
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
files: coverage/lcov/mastodon.lcov

View file

@ -39,7 +39,7 @@ RSpec/ExampleLength:
Max: 22
RSpec/MultipleExpectations:
Max: 8
Max: 7
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:

View file

@ -26,7 +26,7 @@ gem 'blurhash', '~> 0.1'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
gem 'bootsnap', '~> 1.17.0', require: false
gem 'bootsnap', '~> 1.18.0', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.3'
@ -63,7 +63,7 @@ gem 'kaminari', '~> 1.2'
gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.15'
gem 'nsa', github: 'jhawthorn/nsa', ref: 'e020fcc3a54d993ab45b7194d89ab720296c111b'
gem 'nsa'
gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14'
gem 'parslet'

View file

@ -7,17 +7,6 @@ GIT
hkdf (~> 0.2)
jwt (~> 2.0)
GIT
remote: https://github.com/jhawthorn/nsa.git
revision: e020fcc3a54d993ab45b7194d89ab720296c111b
ref: e020fcc3a54d993ab45b7194d89ab720296c111b
specs:
nsa (0.2.8)
activesupport (>= 4.2, < 7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
GEM
remote: https://rubygems.org/
specs:
@ -155,7 +144,7 @@ GEM
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
blurhash (0.1.7)
bootsnap (1.17.1)
bootsnap (1.18.3)
msgpack (~> 1.2)
brakeman (6.1.1)
racc
@ -319,7 +308,7 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.55.0)
haml_lint (0.56.0)
haml (>= 5.0)
parallel (~> 1.10)
rainbow
@ -465,9 +454,14 @@ GEM
net-smtp (0.4.0.1)
net-protocol
nio4r (2.5.9)
nokogiri (1.16.0)
nokogiri (1.16.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nsa (0.3.0)
activesupport (>= 4.2, < 7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
oj (3.16.3)
bigdecimal (>= 3.0)
omniauth (2.1.1)
@ -771,7 +765,7 @@ GEM
unf (~> 0.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2023.4)
tzinfo-data (1.2024.1)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@ -829,7 +823,7 @@ DEPENDENCIES
better_errors (~> 2.9)
binding_of_caller (~> 1.0)
blurhash (~> 0.1)
bootsnap (~> 1.17.0)
bootsnap (~> 1.18.0)
brakeman (~> 6.0)
browser
bundler-audit (~> 0.9)
@ -886,7 +880,7 @@ DEPENDENCIES
net-http (~> 0.4.0)
net-ldap (~> 0.18)
nokogiri (~> 1.15)
nsa!
nsa
oj (~> 3.14)
omniauth (~> 2.0)
omniauth-cas (~> 3.0.0.beta.1)

View file

@ -35,6 +35,7 @@ class Api::V1::Admin::ReportsController < Api::BaseController
def update
authorize @report, :update?
@report.update!(report_params)
log_action :update, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end

View file

@ -1,27 +1,26 @@
# frozen_string_literal: true
class IntentsController < ApplicationController
before_action :check_uri
EXPECTED_SCHEME = 'web+mastodon'
before_action :handle_invalid_uri, unless: :valid_uri?
rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri
def show
if uri.scheme == 'web+mastodon'
case uri.host
when 'follow'
return redirect_to authorize_interaction_path(uri: uri.query_values['uri'].delete_prefix('acct:'))
when 'share'
return redirect_to share_path(text: uri.query_values['text'])
end
case uri.host
when 'follow'
redirect_to authorize_interaction_path(uri: uri.query_values['uri'].delete_prefix('acct:'))
when 'share'
redirect_to share_path(text: uri.query_values['text'])
else
handle_invalid_uri
end
not_found
end
private
def check_uri
not_found if uri.blank?
def valid_uri?
uri.present? && uri.scheme == EXPECTED_SCHEME
end
def handle_invalid_uri

View file

@ -15,9 +15,20 @@ module ReactComponentHelper
div_tag_with_data(data)
end
def serialized_media_attachments(media_attachments)
media_attachments.map { |attachment| serialized_attachment(attachment) }
end
private
def div_tag_with_data(data)
content_tag(:div, nil, data: data)
end
def serialized_attachment(attachment)
ActiveModelSerializers::SerializableResource.new(
attachment,
serializer: REST::MediaAttachmentSerializer
).as_json
end
end

View file

@ -124,7 +124,7 @@ class ReportReasonSelector extends PureComponent {
api().put(`/api/v1/admin/reports/${id}`, {
category,
rule_ids,
rule_ids: category === 'violation' ? rule_ids : [],
}).catch(err => {
console.error(err);
});

View file

@ -438,7 +438,7 @@ class UI extends PureComponent {
handleHotkeyNew = e => {
e.preventDefault();
const element = this.node.querySelector('.compose-form__autosuggest-wrapper textarea');
const element = this.node.querySelector('.autosuggest-textarea__textarea');
if (element) {
element.focus();

View file

@ -10,21 +10,13 @@
#
class AccountSummary < ApplicationRecord
include DatabaseViewRecord
self.primary_key = :account_id
has_many :follow_recommendation_suppressions, primary_key: :account_id, foreign_key: :account_id, inverse_of: false
has_many :follow_recommendation_suppressions, primary_key: :account_id, foreign_key: :account_id, inverse_of: false, dependent: nil
scope :safe, -> { where(sensitive: false) }
scope :localized, ->(locale) { order(Arel::Nodes::Case.new.when(arel_table[:language].eq(locale)).then(1).else(0).desc) }
scope :filtered, -> { where.missing(:follow_recommendation_suppressions) }
def self.refresh
Scenic.database.refresh_materialized_view(table_name, concurrently: true, cascade: false)
rescue ActiveRecord::StatementInvalid
Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false)
end
def readonly?
true
end
end

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
module DatabaseViewRecord
extend ActiveSupport::Concern
class_methods do
def refresh
Scenic.database.refresh_materialized_view(
table_name,
concurrently: true,
cascade: false
)
rescue ActiveRecord::StatementInvalid
Scenic.database.refresh_materialized_view(
table_name,
concurrently: false,
cascade: false
)
end
end
def readonly?
true
end
end

View file

@ -10,6 +10,8 @@
#
class FollowRecommendation < ApplicationRecord
include DatabaseViewRecord
self.primary_key = :account_id
self.table_name = :global_follow_recommendations
@ -17,14 +19,4 @@ class FollowRecommendation < ApplicationRecord
belongs_to :account
scope :localized, ->(locale) { joins(:account_summary).merge(AccountSummary.localized(locale)) }
def self.refresh
Scenic.database.refresh_materialized_view(table_name, concurrently: true, cascade: false)
rescue ActiveRecord::StatementInvalid
Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false)
end
def readonly?
true
end
end

View file

@ -9,6 +9,8 @@
#
class Instance < ApplicationRecord
include DatabaseViewRecord
self.primary_key = :domain
attr_accessor :failure_days
@ -27,10 +29,6 @@ class Instance < ApplicationRecord
scope :by_domain_and_subdomains, ->(domain) { where("reverse('.' || domain) LIKE reverse(?)", "%.#{domain}") }
scope :with_domain_follows, ->(domains) { where(domain: domains).where(domain_account_follows) }
def self.refresh
Scenic.database.refresh_materialized_view(table_name, concurrently: true, cascade: false)
end
def self.domain_account_follows
Arel.sql(
<<~SQL.squish
@ -44,10 +42,6 @@ class Instance < ApplicationRecord
)
end
def readonly?
true
end
def delivery_failure_tracker
@delivery_failure_tracker ||= DeliveryFailureTracker.new(domain)
end

View file

@ -47,9 +47,9 @@ class Report < ApplicationRecord
delegate :local?, to: :account
validates :comment, length: { maximum: 1_000 }, if: :local?
validates :rule_ids, absence: true, unless: :violation?
validates :rule_ids, absence: true, if: -> { (category_changed? || rule_ids_changed?) && !violation? }
validate :validate_rule_ids
validate :validate_rule_ids, if: -> { (category_changed? || rule_ids_changed?) && violation? }
# entries here need to be kept in sync with the front-end:
# - app/javascript/mastodon/features/notifications/components/report.jsx
@ -162,8 +162,6 @@ class Report < ApplicationRecord
end
def validate_rule_ids
return unless violation?
errors.add(:rule_ids, I18n.t('reports.errors.invalid_rules')) unless rules.size == rule_ids&.size
end

View file

@ -10,11 +10,9 @@
#
class UserIp < ApplicationRecord
include DatabaseViewRecord
self.primary_key = :user_id
belongs_to :user
def readonly?
true
end
end

View file

@ -1,11 +1,15 @@
# frozen_string_literal: true
class REST::Admin::DomainBlockSerializer < ActiveModel::Serializer
attributes :id, :domain, :created_at, :severity,
attributes :id, :domain, :digest, :created_at, :severity,
:reject_media, :reject_reports,
:private_comment, :public_comment, :obfuscate
def id
object.id.to_s
end
def digest
object.domain_digest
end
end

View file

@ -12,6 +12,6 @@
= react_component :media_gallery,
height: 343,
lang: status.language,
media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json },
media: serialized_media_attachments(status.ordered_media_attachments),
sensitive: status.sensitive?,
visible: false

View file

@ -8,9 +8,7 @@
%td.email-inner-card-td.email-prose
%p= t @resource.approved? ? 'devise.mailer.confirmation_instructions.explanation' : 'devise.mailer.confirmation_instructions.explanation_when_pending', host: site_hostname
- if @resource.created_by_application
= render 'application/mailer/button', text: t('settings.account_settings'), url: edit_user_registration_url
= link_to confirmation_url(@resource, confirmation_token: @token, redirect_to_app: 'true') do
%span= t 'devise.mailer.confirmation_instructions.action_with_app', app: @resource.created_by_application.name
= render 'application/mailer/button', text: t('devise.mailer.confirmation_instructions.action_with_app', app: @resource.created_by_application.name), url: confirmation_url(@resource, confirmation_token: @token, redirect_to_app: 'true')
- else
= render 'application/mailer/button', text: t('devise.mailer.confirmation_instructions.action'), url: confirmation_url(@resource, confirmation_token: @token)
%p= t 'devise.mailer.confirmation_instructions.extra_html', terms_path: about_more_url, policy_path: privacy_policy_url

View file

@ -1,12 +1,6 @@
# frozen_string_literal: true
MIGRATION_BASE_CLASS = if ActiveRecord::VERSION::MAJOR >= 5
ActiveRecord::Migration[5.0]
else
ActiveRecord::Migration[4.2]
end
class RailsSettingsMigration < MIGRATION_BASE_CLASS
class RailsSettingsMigration < ActiveRecord::Migration[5.0]
def self.up
create_table :settings do |t|
t.string :var, null: false

View file

@ -7,80 +7,73 @@ class IdsToBigints < ActiveRecord::Migration[5.1]
include Mastodon::MigrationHelpers
include Mastodon::MigrationWarning
TABLE_COLUMN_MAPPING = [
[:account_domain_blocks, :account_id],
[:account_domain_blocks, :id],
[:accounts, :id],
[:blocks, :account_id],
[:blocks, :id],
[:blocks, :target_account_id],
[:conversation_mutes, :account_id],
[:conversation_mutes, :id],
[:domain_blocks, :id],
[:favourites, :account_id],
[:favourites, :id],
[:favourites, :status_id],
[:follow_requests, :account_id],
[:follow_requests, :id],
[:follow_requests, :target_account_id],
[:follows, :account_id],
[:follows, :id],
[:follows, :target_account_id],
[:imports, :account_id],
[:imports, :id],
[:media_attachments, :account_id],
[:media_attachments, :id],
[:mentions, :account_id],
[:mentions, :id],
[:mutes, :account_id],
[:mutes, :id],
[:mutes, :target_account_id],
[:notifications, :account_id],
[:notifications, :from_account_id],
[:notifications, :id],
[:oauth_access_grants, :application_id],
[:oauth_access_grants, :id],
[:oauth_access_grants, :resource_owner_id],
[:oauth_access_tokens, :application_id],
[:oauth_access_tokens, :id],
[:oauth_access_tokens, :resource_owner_id],
[:oauth_applications, :id],
[:oauth_applications, :owner_id],
[:reports, :account_id],
[:reports, :action_taken_by_account_id],
[:reports, :id],
[:reports, :target_account_id],
[:session_activations, :access_token_id],
[:session_activations, :user_id],
[:session_activations, :web_push_subscription_id],
[:settings, :id],
[:settings, :thing_id],
[:statuses, :account_id],
[:statuses, :application_id],
[:statuses, :in_reply_to_account_id],
[:stream_entries, :account_id],
[:stream_entries, :id],
[:subscriptions, :account_id],
[:subscriptions, :id],
[:tags, :id],
[:users, :account_id],
[:users, :id],
[:web_settings, :id],
[:web_settings, :user_id],
].freeze
disable_ddl_transaction!
def migrate_columns(to_type)
included_columns = [
[:account_domain_blocks, :account_id],
[:account_domain_blocks, :id],
[:accounts, :id],
[:blocks, :account_id],
[:blocks, :id],
[:blocks, :target_account_id],
[:conversation_mutes, :account_id],
[:conversation_mutes, :id],
[:domain_blocks, :id],
[:favourites, :account_id],
[:favourites, :id],
[:favourites, :status_id],
[:follow_requests, :account_id],
[:follow_requests, :id],
[:follow_requests, :target_account_id],
[:follows, :account_id],
[:follows, :id],
[:follows, :target_account_id],
[:imports, :account_id],
[:imports, :id],
[:media_attachments, :account_id],
[:media_attachments, :id],
[:mentions, :account_id],
[:mentions, :id],
[:mutes, :account_id],
[:mutes, :id],
[:mutes, :target_account_id],
[:notifications, :account_id],
[:notifications, :from_account_id],
[:notifications, :id],
[:oauth_access_grants, :application_id],
[:oauth_access_grants, :id],
[:oauth_access_grants, :resource_owner_id],
[:oauth_access_tokens, :application_id],
[:oauth_access_tokens, :id],
[:oauth_access_tokens, :resource_owner_id],
[:oauth_applications, :id],
[:oauth_applications, :owner_id],
[:reports, :account_id],
[:reports, :action_taken_by_account_id],
[:reports, :id],
[:reports, :target_account_id],
[:session_activations, :access_token_id],
[:session_activations, :user_id],
[:session_activations, :web_push_subscription_id],
[:settings, :id],
[:settings, :thing_id],
[:statuses, :account_id],
[:statuses, :application_id],
[:statuses, :in_reply_to_account_id],
[:stream_entries, :account_id],
[:stream_entries, :id],
[:subscriptions, :account_id],
[:subscriptions, :id],
[:tags, :id],
[:users, :account_id],
[:users, :id],
[:web_settings, :id],
[:web_settings, :user_id],
]
included_columns << [:deprecated_preview_cards, :id] if table_exists?(:deprecated_preview_cards)
display_warning
migration_duration_warning(<<~EXPLANATION)
This migration has some sections that can be safely interrupted
and restarted later, and will tell you when those are occurring.
For more information, see https://github.com/mastodon/mastodon/pull/5088
EXPLANATION
tables = included_columns.map(&:first).uniq
table_sizes = {}
# Sort tables by their size
@ -103,6 +96,25 @@ class IdsToBigints < ActiveRecord::Migration[5.1]
end
end
def display_warning
migration_duration_warning(<<~EXPLANATION)
This migration has some sections that can be safely interrupted
and restarted later, and will tell you when those are occurring.
For more information, see https://github.com/mastodon/mastodon/pull/5088
EXPLANATION
end
def tables
included_columns.map(&:first).uniq
end
def included_columns
TABLE_COLUMN_MAPPING.dup.tap do |included_columns|
included_columns << [:deprecated_preview_cards, :id] if table_exists?(:deprecated_preview_cards)
end
end
def up
migrate_columns(:bigint)
end

View file

@ -17,34 +17,27 @@ RSpec.describe ActivityPub::CollectionsController do
end
describe 'GET #show' do
context 'when id is "featured"' do
context 'without signature' do
subject(:response) { get :show, params: { id: 'featured', account_username: account.username } }
subject(:response) { get :show, params: { id: id, account_username: account.username } }
let(:body) { body_as_json }
context 'when id is "featured"' do
let(:id) { 'featured' }
context 'without signature' do
let(:remote_account) { nil }
it 'returns http success' do
it 'returns http success and correct media type' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
it_behaves_like 'cacheable response'
it 'returns orderedItems with pinned statuses' do
expect(body[:orderedItems]).to be_an Array
expect(body[:orderedItems].size).to eq 3
end
it 'includes URI of private pinned status' do
expect(body[:orderedItems]).to include(ActivityPub::TagManager.instance.uri_for(private_pinned))
end
it 'does not include contents of private pinned status' do
expect(response.body).to_not include(private_pinned.text)
it 'returns orderedItems with correct items' do
expect(body_as_json[:orderedItems])
.to be_an(Array)
.and have_attributes(size: 3)
.and include(ActivityPub::TagManager.instance.uri_for(private_pinned))
.and not_include(private_pinned.text)
end
context 'when account is permanently suspended' do
@ -73,33 +66,19 @@ RSpec.describe ActivityPub::CollectionsController do
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
context 'when getting a featured resource' do
before do
get :show, params: { id: 'featured', account_username: account.username }
end
it 'returns http success' do
it 'returns http success and correct media type' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
it_behaves_like 'cacheable response'
it 'returns orderedItems with pinned statuses' do
json = body_as_json
expect(json[:orderedItems]).to be_an Array
expect(json[:orderedItems].size).to eq 3
end
it 'includes URI of private pinned status' do
json = body_as_json
expect(json[:orderedItems]).to include(ActivityPub::TagManager.instance.uri_for(private_pinned))
end
it 'does not include contents of private pinned status' do
expect(response.body).to_not include(private_pinned.text)
it 'returns orderedItems with expected items' do
expect(body_as_json[:orderedItems])
.to be_an(Array)
.and have_attributes(size: 3)
.and include(ActivityPub::TagManager.instance.uri_for(private_pinned))
.and not_include(private_pinned.text)
end
end
@ -111,50 +90,36 @@ RSpec.describe ActivityPub::CollectionsController do
context 'when signed request account is blocked' do
before do
account.block!(remote_account)
get :show, params: { id: 'featured', account_username: account.username }
end
it 'returns http success' do
it 'returns http success and correct media type and cache headers' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
it 'returns private Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'private'
end
it 'returns empty orderedItems' do
json = body_as_json
expect(json[:orderedItems]).to be_an Array
expect(json[:orderedItems].size).to eq 0
expect(body_as_json[:orderedItems])
.to be_an(Array)
.and have_attributes(size: 0)
end
end
context 'when signed request account is domain blocked' do
before do
account.block_domain!(remote_account.domain)
get :show, params: { id: 'featured', account_username: account.username }
end
it 'returns http success' do
it 'returns http success and correct media type and cache headers' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
it 'returns private Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'private'
end
it 'returns empty orderedItems' do
json = body_as_json
expect(json[:orderedItems]).to be_an Array
expect(json[:orderedItems].size).to eq 0
expect(body_as_json[:orderedItems])
.to be_an(Array)
.and have_attributes(size: 0)
end
end
end
@ -162,8 +127,9 @@ RSpec.describe ActivityPub::CollectionsController do
end
context 'when id is not "featured"' do
let(:id) { 'hoge' }
it 'returns http not found' do
get :show, params: { id: 'hoge', account_username: account.username }
expect(response).to have_http_status(404)
end
end

View file

@ -58,6 +58,7 @@ describe Admin::ReportsController do
report.reload
expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken?).to be true
expect(last_action_log.target).to eq(report)
end
end
@ -70,6 +71,7 @@ describe Admin::ReportsController do
report.reload
expect(report.action_taken_by_account).to be_nil
expect(report.action_taken?).to be false
expect(last_action_log.target).to eq(report)
end
end
@ -81,6 +83,7 @@ describe Admin::ReportsController do
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq user.account
expect(last_action_log.target).to eq(report)
end
end
@ -92,6 +95,13 @@ describe Admin::ReportsController do
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to be_nil
expect(last_action_log.target).to eq(report)
end
end
private
def last_action_log
Admin::ActionLog.last
end
end

View file

@ -133,5 +133,18 @@ describe Report do
report = Fabricate.build(:report, account: remote_account, comment: Faker::Lorem.characters(number: 1001))
expect(report.valid?).to be true
end
it 'is invalid if it references invalid rules' do
report = Fabricate.build(:report, category: :violation, rule_ids: [-1])
expect(report.valid?).to be false
expect(report).to model_have_error_on_field(:rule_ids)
end
it 'is invalid if it references rules but category is not "violation"' do
rule = Fabricate(:rule)
report = Fabricate.build(:report, category: :spam, rule_ids: rule.id)
expect(report.valid?).to be false
expect(report).to model_have_error_on_field(:rule_ids)
end
end
end

View file

@ -95,8 +95,13 @@ RSpec.configure do |config|
self.use_transactional_tests = true
end
config.around(:each, :sidekiq_inline) do |example|
Sidekiq::Testing.inline!(&example)
config.around do |example|
if example.metadata[:sidekiq_inline] == true
Sidekiq::Testing.inline!
else
Sidekiq::Testing.fake!
end
example.run
end
config.before :each, type: :cli do

View file

@ -49,6 +49,7 @@ RSpec.describe 'Domain Blocks' do
{
id: domain_block.id.to_s,
domain: domain_block.domain,
digest: domain_block.domain_digest,
created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
severity: domain_block.severity.to_s,
reject_media: domain_block.reject_media,
@ -97,6 +98,7 @@ RSpec.describe 'Domain Blocks' do
{
id: domain_block.id.to_s,
domain: domain_block.domain,
digest: domain_block.domain_digest,
created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
severity: domain_block.severity.to_s,
reject_media: domain_block.reject_media,
@ -188,6 +190,7 @@ RSpec.describe 'Domain Blocks' do
{
id: domain_block.id.to_s,
domain: domain_block.domain,
digest: domain_block.domain_digest,
severity: 'suspend',
}
)

View file

@ -151,7 +151,9 @@ RSpec.describe 'Reports' do
let(:params) { { category: 'spam' } }
it 'updates the report category', :aggregate_failures do
expect { subject }.to change { report.reload.category }.from('other').to('spam')
expect { subject }
.to change { report.reload.category }.from('other').to('spam')
.and create_an_action_log
expect(response).to have_http_status(200)
@ -184,7 +186,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong role', ''
it 'marks report as resolved', :aggregate_failures do
expect { subject }.to change { report.reload.unresolved? }.from(true).to(false)
expect { subject }
.to change { report.reload.unresolved? }.from(true).to(false)
.and create_an_action_log
expect(response).to have_http_status(200)
end
end
@ -200,7 +204,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong role', ''
it 'marks report as unresolved', :aggregate_failures do
expect { subject }.to change { report.reload.unresolved? }.from(false).to(true)
expect { subject }
.to change { report.reload.unresolved? }.from(false).to(true)
.and create_an_action_log
expect(response).to have_http_status(200)
end
end
@ -216,7 +222,9 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong role', ''
it 'assigns report to the requesting user', :aggregate_failures do
expect { subject }.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id)
expect { subject }
.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id)
.and create_an_action_log
expect(response).to have_http_status(200)
end
end
@ -232,8 +240,16 @@ RSpec.describe 'Reports' do
it_behaves_like 'forbidden for wrong role', ''
it 'unassigns report from assignee', :aggregate_failures do
expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil)
expect { subject }
.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil)
.and create_an_action_log
expect(response).to have_http_status(200)
end
end
private
def create_an_action_log
change(Admin::ActionLog, :count).by(1)
end
end

View file

@ -52,5 +52,19 @@ RSpec.describe 'API Markers' do
expect(user.markers.first.last_read_id).to eq 70_120
end
end
context 'when database object becomes stale' do
before do
allow(Marker).to receive(:transaction).and_raise(ActiveRecord::StaleObjectError)
post '/api/v1/markers', headers: headers, params: { home: { last_read_id: '69420' } }
end
it 'returns error json' do
expect(response)
.to have_http_status(409)
expect(body_as_json)
.to include(error: /Conflict during update/)
end
end
end
end

View file

@ -21,14 +21,22 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
it 'parses out of attachment' do
account = subject.call('alice', 'example.com', payload)
expect(account.fields).to be_a Array
expect(account.fields.size).to eq 2
expect(account.fields[0]).to be_a Account::Field
expect(account.fields[0].name).to eq 'Pronouns'
expect(account.fields[0].value).to eq 'They/them'
expect(account.fields[1]).to be_a Account::Field
expect(account.fields[1].name).to eq 'Occupation'
expect(account.fields[1].value).to eq 'Unit test'
expect(account.fields)
.to be_an(Array)
.and have_attributes(size: 2)
expect(account.fields.first)
.to be_an(Account::Field)
.and have_attributes(
name: eq('Pronouns'),
value: eq('They/them')
)
expect(account.fields.last)
.to be_an(Account::Field)
.and have_attributes(
name: eq('Occupation'),
value: eq('Unit test')
)
end
end

View file

@ -3179,12 +3179,12 @@ __metadata:
linkType: hard
"@types/jest@npm:^29.5.2":
version: 29.5.11
resolution: "@types/jest@npm:29.5.11"
version: 29.5.12
resolution: "@types/jest@npm:29.5.12"
dependencies:
expect: "npm:^29.0.0"
pretty-format: "npm:^29.0.0"
checksum: 524a3394845214581278bf4d75055927261fbeac7e1a89cd621bd0636da37d265fe0a85eac58b5778758faad1cbd7c7c361dfc190c78ebde03a91cce33463261
checksum: 25fc8e4c611fa6c4421e631432e9f0a6865a8cb07c9815ec9ac90d630271cad773b2ee5fe08066f7b95bebd18bb967f8ce05d018ee9ab0430f9dfd1d84665b6f
languageName: node
linkType: hard
@ -3286,13 +3286,13 @@ __metadata:
linkType: hard
"@types/pg@npm:^8.6.6":
version: 8.10.9
resolution: "@types/pg@npm:8.10.9"
version: 8.11.0
resolution: "@types/pg@npm:8.11.0"
dependencies:
"@types/node": "npm:*"
pg-protocol: "npm:*"
pg-types: "npm:^4.0.1"
checksum: 6b3bec7230d09da6459636a66dfd6fb538378e466ffff0a0bcd07d67aa4ddce49c73afc7442f53adec92a49dbf9e71d8d847e0075750d7545331735dfd92d22c
checksum: df2c2ac11fa5e8863a98aadce9a9168af5cfc38a226a228d8b1be513ef48d33ceb9bfaa64ef685a87e0611a4f8d94f2e0736bb2812fa00ed264f76679b86945d
languageName: node
linkType: hard
@ -3476,13 +3476,13 @@ __metadata:
linkType: hard
"@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7":
version: 18.2.48
resolution: "@types/react@npm:18.2.48"
version: 18.2.54
resolution: "@types/react@npm:18.2.54"
dependencies:
"@types/prop-types": "npm:*"
"@types/scheduler": "npm:*"
csstype: "npm:^3.0.2"
checksum: 7e89f18ea2928b1638f564b156d692894dcb9352a7e0a807873c97e858abe1f23dbd165a25dd088a991344e973fdeef88ba5724bfb64504b74072cbc9c220c3a
checksum: ad38193c30a063a481aeec2460de6396c80d8de2f1c7a8cbb80a4e8bc594f74c308ce93e165d743b38507c3ac0a491c24ce0efbd84c9ab21fd5fd38d2963d329
languageName: node
linkType: hard
@ -3599,9 +3599,9 @@ __metadata:
linkType: hard
"@types/uuid@npm:^9.0.0":
version: 9.0.7
resolution: "@types/uuid@npm:9.0.7"
checksum: b329ebd4f9d1d8e08d4f2cc211be4922d70d1149f73d5772630e4a3acfb5170c6d37b3d7a39a0412f1a56e86e8a844c7f297c798b082f90380608bf766688787
version: 9.0.8
resolution: "@types/uuid@npm:9.0.8"
checksum: b411b93054cb1d4361919579ef3508a1f12bf15b5fdd97337d3d351bece6c921b52b6daeef89b62340fd73fd60da407878432a1af777f40648cbe53a01723489
languageName: node
linkType: hard
@ -12667,8 +12667,8 @@ __metadata:
linkType: hard
"pino@npm:^8.17.1, pino@npm:^8.17.2":
version: 8.17.2
resolution: "pino@npm:8.17.2"
version: 8.18.0
resolution: "pino@npm:8.18.0"
dependencies:
atomic-sleep: "npm:^1.0.0"
fast-redact: "npm:^3.1.1"
@ -12683,7 +12683,7 @@ __metadata:
thread-stream: "npm:^2.0.0"
bin:
pino: bin.js
checksum: 9e55af6cd9d1833a4dbe64924fc73163295acd3c988a9c7db88926669f2574ab7ec607e8487b6dd71dbdad2d7c1c1aac439f37e59233f37220b1a9d88fa2ce01
checksum: ca73bb31e4656954413b89f48c486b1680fec0c6bb12d4d796c5ccf8eca40f3ee12c9532a0fa61284ed9a800c14eaa0f496f520057ef70cdee0447114813e8eb
languageName: node
linkType: hard
@ -13144,13 +13144,13 @@ __metadata:
linkType: hard
"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.33":
version: 8.4.33
resolution: "postcss@npm:8.4.33"
version: 8.4.34
resolution: "postcss@npm:8.4.34"
dependencies:
nanoid: "npm:^3.3.7"
picocolors: "npm:^1.0.0"
source-map-js: "npm:^1.0.2"
checksum: 16eda83458fcd8a91bece287b5920c7f57164c3ea293e6c80d0ea71ce7843007bcd8592260a5160b9a7f02693e6ac93e2495b02d8c7596d3f3f72c1447e3ba79
checksum: 4d6f072cdfdc1ced16b4336263d830f8b4397fc47b9b382e02f6448fda9386d881aa9d27fbe0dd124f59c76f3a5da4f360919d25dfc818eca50b48f042af35a8
languageName: node
linkType: hard