Merge remote-tracking branch 'parent/main' into upstream-20241216
This commit is contained in:
commit
3784ad273c
555 changed files with 7564 additions and 3363 deletions
|
@ -32,15 +32,16 @@ RSpec.describe Admin::ExportDomainAllowsController do
|
|||
it 'allows imported domains' do
|
||||
post :import, params: { admin_import: { data: fixture_file_upload('domain_allows.csv') } }
|
||||
|
||||
expect(response).to redirect_to(admin_instances_path)
|
||||
expect(response)
|
||||
.to redirect_to(admin_instances_path)
|
||||
|
||||
# Header should not be imported
|
||||
expect(DomainAllow.where(domain: '#domain').present?).to be(false)
|
||||
|
||||
# Domains should now be added
|
||||
get :export, params: { format: :csv }
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.body).to eq(domain_allows_csv_file)
|
||||
# Header row should not be imported, but domains should
|
||||
expect(DomainAllow)
|
||||
.to_not exist(domain: '#domain')
|
||||
expect(DomainAllow)
|
||||
.to exist(domain: 'good.domain')
|
||||
expect(DomainAllow)
|
||||
.to exist(domain: 'better.domain')
|
||||
end
|
||||
|
||||
it 'displays error on no file selected' do
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfService::DistributionsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:terms_of_service) { Fabricate(:terms_of_service, notification_sent_at: nil) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
it 'returns http success' do
|
||||
post :create, params: { terms_of_service_id: terms_of_service.id }
|
||||
|
||||
expect(response).to redirect_to(admin_terms_of_service_index_path)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfService::DraftsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http success' do
|
||||
get :show
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
subject { put :update, params: params }
|
||||
|
||||
let!(:terms) { Fabricate :terms_of_service, published_at: nil }
|
||||
|
||||
context 'with publishing params' do
|
||||
let(:params) { { terms_of_service: { text: 'new' }, action_type: 'publish' } }
|
||||
|
||||
it 'publishes the record' do
|
||||
expect { subject }
|
||||
.to change(Admin::ActionLog, :count).by(1)
|
||||
|
||||
expect(response)
|
||||
.to redirect_to(admin_terms_of_service_index_path)
|
||||
expect(terms.reload.published_at)
|
||||
.to_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non publishing params' do
|
||||
let(:params) { { terms_of_service: { text: 'new' }, action_type: 'save_draft' } }
|
||||
|
||||
it 'updates but does not publish the record' do
|
||||
expect { subject }
|
||||
.to_not change(Admin::ActionLog, :count)
|
||||
|
||||
expect(response)
|
||||
.to redirect_to(admin_terms_of_service_draft_path)
|
||||
expect(terms.reload.published_at)
|
||||
.to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
let(:params) { { terms_of_service: { text: '' }, action_type: 'save_draft' } }
|
||||
|
||||
it 'does not update the record' do
|
||||
subject
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfService::GeneratesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http success' do
|
||||
get :show
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
subject { post :create, params: params }
|
||||
|
||||
context 'with valid params' do
|
||||
let(:params) do
|
||||
{
|
||||
terms_of_service_generator: {
|
||||
admin_email: 'test@host.example',
|
||||
arbitration_address: '123 Main Street',
|
||||
arbitration_website: 'https://host.example',
|
||||
dmca_address: '123 DMCA Ave',
|
||||
dmca_email: 'dmca@host.example',
|
||||
domain: 'host.example',
|
||||
jurisdiction: 'Europe',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it 'saves new record' do
|
||||
expect { subject }
|
||||
.to change(TermsOfService, :count).by(1)
|
||||
expect(response)
|
||||
.to redirect_to(admin_terms_of_service_draft_path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
let(:params) do
|
||||
{
|
||||
terms_of_service_generator: {
|
||||
admin_email: 'what the',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it 'does not save new record' do
|
||||
expect { subject }
|
||||
.to_not change(TermsOfService, :count)
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfService::HistoriesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http success' do
|
||||
get :show
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfService::PreviewsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:terms_of_service) { Fabricate(:terms_of_service, notification_sent_at: nil) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http success' do
|
||||
get :show, params: { terms_of_service_id: terms_of_service.id }
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfService::TestsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:terms_of_service) { Fabricate(:terms_of_service, notification_sent_at: nil) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
it 'returns http success' do
|
||||
post :create, params: { terms_of_service_id: terms_of_service.id }
|
||||
|
||||
expect(response).to redirect_to(admin_terms_of_service_preview_path(terms_of_service))
|
||||
end
|
||||
end
|
||||
end
|
21
spec/controllers/admin/terms_of_service_controller_spec.rb
Normal file
21
spec/controllers/admin/terms_of_service_controller_spec.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TermsOfServiceController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Settings::VerificationsController do
|
||||
render_views
|
||||
|
||||
let!(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
before do
|
||||
get :show
|
||||
end
|
||||
|
||||
it 'returns http success with private cache control headers', :aggregate_failures do
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
.and have_attributes(
|
||||
headers: include(
|
||||
'Cache-Control' => 'private, no-store'
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
5
spec/fabricators/status_edit_fabricator.rb
Normal file
5
spec/fabricators/status_edit_fabricator.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:status_edit) do
|
||||
status { Fabricate.build(:status) }
|
||||
end
|
8
spec/fabricators/terms_of_service_fabricator.rb
Normal file
8
spec/fabricators/terms_of_service_fabricator.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Fabricator(:terms_of_service) do
|
||||
text { Faker::Lorem.paragraph }
|
||||
changelog { Faker::Lorem.paragraph }
|
||||
published_at { Time.zone.now }
|
||||
notification_sent_at { Time.zone.now }
|
||||
end
|
BIN
spec/fixtures/files/600x400-animated.gif
vendored
Normal file
BIN
spec/fixtures/files/600x400-animated.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
spec/fixtures/files/600x400-animated.png
vendored
Normal file
BIN
spec/fixtures/files/600x400-animated.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
BIN
spec/fixtures/files/600x400.gif
vendored
Normal file
BIN
spec/fixtures/files/600x400.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
spec/fixtures/files/attachment.gif
vendored
BIN
spec/fixtures/files/attachment.gif
vendored
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
|
@ -39,15 +39,15 @@ RSpec.describe Sanitize::Config do
|
|||
end
|
||||
|
||||
it 'keeps a with href' do
|
||||
expect(Sanitize.fragment('<a href="http://example.com">Test</a>', subject)).to eq '<a href="http://example.com" rel="nofollow noopener noreferrer" target="_blank">Test</a>'
|
||||
expect(Sanitize.fragment('<a href="http://example.com">Test</a>', subject)).to eq '<a href="http://example.com" rel="nofollow noopener" target="_blank">Test</a>'
|
||||
end
|
||||
|
||||
it 'keeps a with translate="no"' do
|
||||
expect(Sanitize.fragment('<a href="http://example.com" translate="no">Test</a>', subject)).to eq '<a href="http://example.com" translate="no" rel="nofollow noopener noreferrer" target="_blank">Test</a>'
|
||||
expect(Sanitize.fragment('<a href="http://example.com" translate="no">Test</a>', subject)).to eq '<a href="http://example.com" translate="no" rel="nofollow noopener" target="_blank">Test</a>'
|
||||
end
|
||||
|
||||
it 'removes "translate" attribute with invalid value' do
|
||||
expect(Sanitize.fragment('<a href="http://example.com" translate="foo">Test</a>', subject)).to eq '<a href="http://example.com" rel="nofollow noopener noreferrer" target="_blank">Test</a>'
|
||||
expect(Sanitize.fragment('<a href="http://example.com" translate="foo">Test</a>', subject)).to eq '<a href="http://example.com" rel="nofollow noopener" target="_blank">Test</a>'
|
||||
end
|
||||
|
||||
it 'removes a with unparsable href' do
|
||||
|
@ -55,7 +55,7 @@ RSpec.describe Sanitize::Config do
|
|||
end
|
||||
|
||||
it 'keeps a with supported scheme and no host' do
|
||||
expect(Sanitize.fragment('<a href="dweb:/a/foo">Test</a>', subject)).to eq '<a href="dweb:/a/foo" rel="nofollow noopener noreferrer" target="_blank">Test</a>'
|
||||
expect(Sanitize.fragment('<a href="dweb:/a/foo">Test</a>', subject)).to eq '<a href="dweb:/a/foo" rel="nofollow noopener" target="_blank">Test</a>'
|
||||
end
|
||||
|
||||
it 'sanitizes math to LaTeX' do
|
||||
|
|
|
@ -50,7 +50,7 @@ RSpec.describe TextFormatter do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when given a stand-alone google URL' do
|
||||
context 'when given a stand-alone Google URL' do
|
||||
let(:text) { 'http://google.com' }
|
||||
|
||||
it 'matches the full URL' do
|
||||
|
@ -280,6 +280,26 @@ RSpec.describe TextFormatter do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when given a lengthy URL' do
|
||||
let(:text) { 'lorem https://prepitaph.org/wip/web-dovespair/ ipsum' }
|
||||
|
||||
it 'truncates the URL' do
|
||||
expect(subject).to include '<span class="invisible">https://</span>'
|
||||
expect(subject).to include '<span class="ellipsis">prepitaph.org/wip/web-dovespai</span>'
|
||||
expect(subject).to include '<span class="invisible">r/</span>'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given a sufficiently short URL' do
|
||||
let(:text) { 'lorem https://prepitaph.org/wip/web-devspair/ ipsum' }
|
||||
|
||||
it 'does not truncate the URL' do
|
||||
expect(subject).to include '<span class="invisible">https://</span>'
|
||||
expect(subject).to include '<span class="">prepitaph.org/wip/web-devspair/</span>'
|
||||
expect(subject).to include '<span class="invisible"></span>'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when given text containing a hashtag' do
|
||||
let(:text) { '#hashtag' }
|
||||
|
||||
|
|
|
@ -98,4 +98,9 @@ class UserMailerPreview < ActionMailer::Preview
|
|||
def failed_2fa
|
||||
UserMailer.failed_2fa(User.first, '127.0.0.1', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0', Time.now.utc)
|
||||
end
|
||||
|
||||
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/terms_of_service_changed
|
||||
def terms_of_service_changed
|
||||
UserMailer.terms_of_service_changed(User.first, TermsOfService.live.first)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -272,4 +272,16 @@ RSpec.describe UserMailer do
|
|||
.and(have_body_text(I18n.t('user_mailer.backup_ready.explanation')))
|
||||
end
|
||||
end
|
||||
|
||||
describe '#terms_of_service_changed' do
|
||||
let(:terms) { Fabricate :terms_of_service }
|
||||
let(:mail) { described_class.terms_of_service_changed(receiver, terms) }
|
||||
|
||||
it 'renders terms_of_service_changed mail' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(have_subject(I18n.t('user_mailer.terms_of_service_changed.subject')))
|
||||
.and(have_body_text(I18n.t('user_mailer.terms_of_service_changed.changelog')))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
33
spec/models/account_pin_spec.rb
Normal file
33
spec/models/account_pin_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountPin do
|
||||
describe 'Associations' do
|
||||
it { is_expected.to belong_to(:account).required }
|
||||
it { is_expected.to belong_to(:target_account).required }
|
||||
end
|
||||
|
||||
describe 'Validations' do
|
||||
describe 'the follow relationship' do
|
||||
subject { Fabricate.build :account_pin, account: account }
|
||||
|
||||
let(:account) { Fabricate :account }
|
||||
let(:target_account) { Fabricate :account }
|
||||
|
||||
context 'when account is following target account' do
|
||||
before { account.follow!(target_account) }
|
||||
|
||||
it { is_expected.to allow_value(target_account).for(:target_account).against(:base) }
|
||||
end
|
||||
|
||||
context 'when account is not following target account' do
|
||||
it { is_expected.to_not allow_value(target_account).for(:target_account).against(:base).with_message(not_following_message) }
|
||||
|
||||
def not_following_message
|
||||
I18n.t('accounts.pin_errors.following')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,19 +7,8 @@ RSpec.describe CustomFilter do
|
|||
it { is_expected.to validate_presence_of(:title) }
|
||||
it { is_expected.to validate_presence_of(:context) }
|
||||
|
||||
it 'requires non-empty of context' do
|
||||
record = described_class.new(context: [])
|
||||
record.valid?
|
||||
|
||||
expect(record).to model_have_error_on_field(:context)
|
||||
end
|
||||
|
||||
it 'requires valid context value' do
|
||||
record = described_class.new(context: ['invalid'])
|
||||
record.valid?
|
||||
|
||||
expect(record).to model_have_error_on_field(:context)
|
||||
end
|
||||
it { is_expected.to_not allow_values([], %w(invalid)).for(:context) }
|
||||
it { is_expected.to allow_values(%w(home)).for(:context) }
|
||||
end
|
||||
|
||||
describe 'Normalizations' do
|
||||
|
|
|
@ -61,10 +61,7 @@ RSpec.describe Form::Import do
|
|||
let(:import_type) { 'following' }
|
||||
let(:import_file) { 'boop.ogg' }
|
||||
|
||||
it 'has errors' do
|
||||
# NOTE: not testing more specific error because we don't know the string to match
|
||||
expect(subject).to model_have_error_on_field(:data)
|
||||
end
|
||||
it { is_expected.to_not allow_value(data).for(:data) }
|
||||
end
|
||||
|
||||
context 'when importing more follows than allowed' do
|
||||
|
|
|
@ -90,7 +90,7 @@ RSpec.describe MediaAttachment, :attachment_processing do
|
|||
media.destroy
|
||||
end
|
||||
|
||||
it 'saves media attachment with correct file and size metadata' do
|
||||
it 'saves metadata and generates styles' do
|
||||
expect(media)
|
||||
.to be_persisted
|
||||
.and be_processing_complete
|
||||
|
@ -98,18 +98,28 @@ RSpec.describe MediaAttachment, :attachment_processing do
|
|||
file: be_present,
|
||||
type: eq('image'),
|
||||
file_content_type: eq(content_type),
|
||||
file_file_name: end_with(extension)
|
||||
file_file_name: end_with(extension),
|
||||
blurhash: have_attributes(size: eq(36))
|
||||
)
|
||||
|
||||
# Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension
|
||||
expect(Rack::Mime.mime_type(extension, nil)).to eq content_type
|
||||
|
||||
# Strip original file name
|
||||
expect(media.file_file_name)
|
||||
.to_not start_with '600x400'
|
||||
|
||||
# Generate styles
|
||||
expect(FastImage.size(media.file.path(:original)))
|
||||
.to eq [600, 400]
|
||||
expect(FastImage.size(media.file.path(:small)))
|
||||
.to eq [588, 392]
|
||||
|
||||
# Use extension recognized by Rack::Mime (used by PublicFileServerMiddleware)
|
||||
expect(media.file.path(:original))
|
||||
.to end_with(extension)
|
||||
expect(media.file.path(:small))
|
||||
.to end_with(extension)
|
||||
|
||||
# Set meta for original and thumbnail
|
||||
expect(media.file.meta.deep_symbolize_keys)
|
||||
expect(media_metadata)
|
||||
.to include(
|
||||
original: include(
|
||||
width: eq(600),
|
||||
|
@ -122,6 +132,60 @@ RSpec.describe MediaAttachment, :attachment_processing do
|
|||
aspect: eq(1.5)
|
||||
)
|
||||
)
|
||||
|
||||
# Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension
|
||||
expect(Rack::Mime.mime_type(extension, nil)).to eq content_type
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'animated 600x400 image' do
|
||||
after do
|
||||
media.destroy
|
||||
end
|
||||
|
||||
it 'saves metadata and generates styles' do
|
||||
expect(media)
|
||||
.to be_persisted
|
||||
.and be_processing_complete
|
||||
.and have_attributes(
|
||||
file: be_present,
|
||||
type: eq('gifv'),
|
||||
file_content_type: eq('video/mp4'),
|
||||
file_file_name: end_with('.mp4'),
|
||||
blurhash: have_attributes(size: eq(36))
|
||||
)
|
||||
|
||||
# Strip original file name
|
||||
expect(media.file_file_name)
|
||||
.to_not start_with '600x400'
|
||||
|
||||
# Transcode to MP4
|
||||
expect(media.file.path(:original))
|
||||
.to end_with('.mp4')
|
||||
|
||||
# Generate static thumbnail
|
||||
expect(FastImage.size(media.file.path(:small)))
|
||||
.to eq [600, 400]
|
||||
expect(FastImage.animated?(media.file.path(:small)))
|
||||
.to be false
|
||||
expect(media.file.path(:small))
|
||||
.to end_with('.png')
|
||||
|
||||
# Set meta for styles
|
||||
expect(media_metadata)
|
||||
.to include(
|
||||
original: include(
|
||||
width: eq(600),
|
||||
height: eq(400),
|
||||
duration: eq(3),
|
||||
frame_rate: '1/1'
|
||||
),
|
||||
small: include(
|
||||
width: eq(600),
|
||||
height: eq(400),
|
||||
aspect: eq(1.5)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -137,10 +201,10 @@ RSpec.describe MediaAttachment, :attachment_processing do
|
|||
it_behaves_like 'static 600x400 image', 'image/png', '.png'
|
||||
end
|
||||
|
||||
describe 'monochrome jpg' do
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture('monochrome.png')) }
|
||||
describe 'gif' do
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.gif')) }
|
||||
|
||||
it_behaves_like 'static 600x400 image', 'image/png', '.png'
|
||||
it_behaves_like 'static 600x400 image', 'image/gif', '.gif'
|
||||
end
|
||||
|
||||
describe 'webp' do
|
||||
|
@ -161,6 +225,12 @@ RSpec.describe MediaAttachment, :attachment_processing do
|
|||
it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
|
||||
end
|
||||
|
||||
describe 'monochrome jpg' do
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture('monochrome.png')) }
|
||||
|
||||
it_behaves_like 'static 600x400 image', 'image/png', '.png'
|
||||
end
|
||||
|
||||
describe 'base64-encoded image' do
|
||||
let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('600x400.jpeg').read)}" }
|
||||
let(:media) { Fabricate(:media_attachment, file: base64_attachment) }
|
||||
|
@ -169,51 +239,15 @@ RSpec.describe MediaAttachment, :attachment_processing do
|
|||
end
|
||||
|
||||
describe 'animated gif' do
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture('avatar.gif')) }
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400-animated.gif')) }
|
||||
|
||||
it 'sets correct file metadata' do
|
||||
expect(media)
|
||||
.to have_attributes(
|
||||
type: eq('gifv'),
|
||||
file_content_type: eq('video/mp4')
|
||||
)
|
||||
expect(media_metadata)
|
||||
.to include(
|
||||
original: include(
|
||||
width: eq(128),
|
||||
height: eq(128)
|
||||
)
|
||||
)
|
||||
end
|
||||
it_behaves_like 'animated 600x400 image'
|
||||
end
|
||||
|
||||
describe 'static gif' do
|
||||
fixtures = [
|
||||
{ filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 },
|
||||
{ filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 },
|
||||
]
|
||||
describe 'animated png' do
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400-animated.png')) }
|
||||
|
||||
fixtures.each do |fixture|
|
||||
context fixture[:filename] do
|
||||
let(:media) { Fabricate(:media_attachment, file: attachment_fixture(fixture[:filename])) }
|
||||
|
||||
it 'sets correct file metadata' do
|
||||
expect(media)
|
||||
.to have_attributes(
|
||||
type: eq('image'),
|
||||
file_content_type: eq('image/gif')
|
||||
)
|
||||
expect(media_metadata)
|
||||
.to include(
|
||||
original: include(
|
||||
width: eq(fixture[:width]),
|
||||
height: eq(fixture[:height]),
|
||||
aspect: eq(fixture[:aspect])
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
it_behaves_like 'animated 600x400 image'
|
||||
end
|
||||
|
||||
describe 'ogg with cover art' do
|
||||
|
|
|
@ -3,8 +3,14 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Mention do
|
||||
describe 'validations' do
|
||||
describe 'Associations' do
|
||||
it { is_expected.to belong_to(:account).required }
|
||||
it { is_expected.to belong_to(:status).required }
|
||||
end
|
||||
|
||||
describe 'Validations' do
|
||||
subject { Fabricate.build :mention }
|
||||
|
||||
it { is_expected.to validate_uniqueness_of(:account_id).scoped_to(:status_id) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -105,25 +105,32 @@ RSpec.describe Report do
|
|||
describe 'history' do
|
||||
subject(:action_logs) { report.history }
|
||||
|
||||
let(:report) { Fabricate(:report, target_account_id: target_account.id, status_ids: [status.id], created_at: 3.days.ago, updated_at: 1.day.ago) }
|
||||
let(:report) { Fabricate(:report, target_account_id: target_account.id, status_ids: [status.id]) }
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:account_warning) { Fabricate(:account_warning, report_id: report.id) }
|
||||
|
||||
before do
|
||||
Fabricate(:action_log, target_type: 'Report', account_id: target_account.id, target_id: report.id, created_at: 2.days.ago)
|
||||
Fabricate(:action_log, target_type: 'Account', account_id: target_account.id, target_id: report.target_account_id, created_at: 2.days.ago)
|
||||
Fabricate(:action_log, target_type: 'Status', account_id: target_account.id, target_id: status.id, created_at: 2.days.ago)
|
||||
Fabricate(:action_log, target_type: 'AccountWarning', account_id: target_account.id, target_id: account_warning.id, created_at: 2.days.ago)
|
||||
end
|
||||
let!(:matched_type_account_warning) { Fabricate(:action_log, target_type: 'AccountWarning', target_id: account_warning.id) }
|
||||
let!(:matched_type_account) { Fabricate(:action_log, target_type: 'Account', target_id: report.target_account_id) }
|
||||
let!(:matched_type_report) { Fabricate(:action_log, target_type: 'Report', target_id: report.id) }
|
||||
let!(:matched_type_status) { Fabricate(:action_log, target_type: 'Status', target_id: status.id) }
|
||||
|
||||
let!(:unmatched_type_account_warning) { Fabricate(:action_log, target_type: 'AccountWarning') }
|
||||
let!(:unmatched_type_account) { Fabricate(:action_log, target_type: 'Account') }
|
||||
let!(:unmatched_type_report) { Fabricate(:action_log, target_type: 'Report') }
|
||||
let!(:unmatched_type_status) { Fabricate(:action_log, target_type: 'Status') }
|
||||
|
||||
it 'returns expected logs' do
|
||||
expect(action_logs)
|
||||
.to have_attributes(count: 4)
|
||||
.and include(have_attributes(target_type: 'Account'))
|
||||
.and include(have_attributes(target_type: 'AccountWarning'))
|
||||
.and include(have_attributes(target_type: 'Report'))
|
||||
.and include(have_attributes(target_type: 'Status'))
|
||||
.and include(matched_type_account_warning)
|
||||
.and include(matched_type_account)
|
||||
.and include(matched_type_report)
|
||||
.and include(matched_type_status)
|
||||
.and not_include(unmatched_type_account_warning)
|
||||
.and not_include(unmatched_type_account)
|
||||
.and not_include(unmatched_type_report)
|
||||
.and not_include(unmatched_type_status)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -149,13 +156,13 @@ RSpec.describe Report do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
describe 'Validations' do
|
||||
let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') }
|
||||
|
||||
it 'is invalid if comment is longer than character limit and reporter is local' do
|
||||
report = Fabricate.build(:report, comment: comment_over_limit)
|
||||
expect(report.valid?).to be false
|
||||
expect(report).to model_have_error_on_field(:comment)
|
||||
report = Fabricate.build(:report)
|
||||
|
||||
expect(report).to_not allow_value(comment_over_limit).for(:comment)
|
||||
end
|
||||
|
||||
it 'is valid if comment is longer than character limit and reporter is not local' do
|
||||
|
@ -164,16 +171,16 @@ RSpec.describe Report do
|
|||
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)
|
||||
report = Fabricate.build(:report, category: :violation)
|
||||
|
||||
expect(report).to_not allow_value([-1]).for(: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)
|
||||
report = Fabricate.build(:report, category: :spam)
|
||||
|
||||
expect(report).to_not allow_value(rule.id).for(:rule_ids)
|
||||
end
|
||||
|
||||
def comment_over_limit
|
||||
|
|
|
@ -5,7 +5,39 @@ require 'rails_helper'
|
|||
RSpec.describe Tag do
|
||||
include_examples 'Reviewable'
|
||||
|
||||
describe 'validations' do
|
||||
describe 'Validations' do
|
||||
describe 'name' do
|
||||
context 'with a new record' do
|
||||
subject { Fabricate.build :tag, name: 'original' }
|
||||
|
||||
it { is_expected.to allow_value('changed').for(:name) }
|
||||
end
|
||||
|
||||
context 'with an existing record' do
|
||||
subject { Fabricate :tag, name: 'original' }
|
||||
|
||||
it { is_expected.to_not allow_value('changed').for(:name).with_message(previous_name_error_message) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'display_name' do
|
||||
context 'with a new record' do
|
||||
subject { Fabricate.build :tag, name: 'original', display_name: 'OriginalDisplayName' }
|
||||
|
||||
it { is_expected.to allow_value('ChangedDisplayName').for(:display_name) }
|
||||
end
|
||||
|
||||
context 'with an existing record' do
|
||||
subject { Fabricate :tag, name: 'original', display_name: 'OriginalDisplayName' }
|
||||
|
||||
it { is_expected.to_not allow_value('ChangedDisplayName').for(:display_name).with_message(previous_name_error_message) }
|
||||
end
|
||||
end
|
||||
|
||||
def previous_name_error_message
|
||||
I18n.t('tags.does_not_match_previous_name')
|
||||
end
|
||||
|
||||
it 'invalid with #' do
|
||||
expect(described_class.new(name: '#hello_world')).to_not be_valid
|
||||
end
|
||||
|
|
27
spec/models/terms_of_service_spec.rb
Normal file
27
spec/models/terms_of_service_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TermsOfService do
|
||||
describe '#scope_for_notification' do
|
||||
subject { terms_of_service.scope_for_notification }
|
||||
|
||||
let(:published_at) { Time.now.utc }
|
||||
let(:terms_of_service) { Fabricate(:terms_of_service, published_at: published_at) }
|
||||
let(:user_before) { Fabricate(:user, created_at: published_at - 2.days) }
|
||||
let(:user_before_unconfirmed) { Fabricate(:user, created_at: published_at - 2.days, confirmed_at: nil) }
|
||||
let(:user_before_suspended) { Fabricate(:user, created_at: published_at - 2.days) }
|
||||
let(:user_after) { Fabricate(:user, created_at: published_at + 1.hour) }
|
||||
|
||||
before do
|
||||
user_before_suspended.account.suspend!
|
||||
user_before_unconfirmed
|
||||
user_before
|
||||
user_after
|
||||
end
|
||||
|
||||
it 'includes only users created before the terms of service were published' do
|
||||
expect(subject.pluck(:id)).to match_array(user_before.id)
|
||||
end
|
||||
end
|
||||
end
|
73
spec/policies/terms_of_service_policy_spec.rb
Normal file
73
spec/policies/terms_of_service_policy_spec.rb
Normal file
|
@ -0,0 +1,73 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TermsOfServicePolicy do
|
||||
subject { described_class }
|
||||
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :index?, :create? do
|
||||
it { is_expected.to permit(admin, TermsOfService) }
|
||||
it { is_expected.to_not permit(john, TermsOfService) }
|
||||
end
|
||||
|
||||
permissions :update?, :destroy? do
|
||||
let(:terms) { Fabricate(:terms_of_service, published_at: published) }
|
||||
|
||||
context 'with an unpublished terms' do
|
||||
let(:published) { nil }
|
||||
|
||||
it { is_expected.to permit(admin, terms) }
|
||||
it { is_expected.to_not permit(john, terms) }
|
||||
end
|
||||
|
||||
context 'with a published terms' do
|
||||
let(:published) { 5.days.ago }
|
||||
|
||||
it { is_expected.to_not permit(admin, terms) }
|
||||
it { is_expected.to_not permit(john, terms) }
|
||||
end
|
||||
end
|
||||
|
||||
permissions :distribute? do
|
||||
let(:terms) { Fabricate(:terms_of_service, published_at: published, notification_sent_at: notification) }
|
||||
|
||||
context 'with notification already sent' do
|
||||
let(:notification) { 3.days.ago }
|
||||
|
||||
context 'with published true' do
|
||||
let(:published) { 5.days.ago }
|
||||
|
||||
it { is_expected.to_not permit(admin, terms) }
|
||||
it { is_expected.to_not permit(john, terms) }
|
||||
end
|
||||
|
||||
context 'with published false' do
|
||||
let(:published) { nil }
|
||||
|
||||
it { is_expected.to_not permit(admin, terms) }
|
||||
it { is_expected.to_not permit(john, terms) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with notification not yet sent' do
|
||||
let(:notification) { nil }
|
||||
|
||||
context 'with published true' do
|
||||
let(:published) { 5.days.ago }
|
||||
|
||||
it { is_expected.to permit(admin, terms) }
|
||||
it { is_expected.to_not permit(john, terms) }
|
||||
end
|
||||
|
||||
context 'with published false' do
|
||||
let(:published) { nil }
|
||||
|
||||
it { is_expected.to_not permit(admin, terms) }
|
||||
it { is_expected.to_not permit(john, terms) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
spec/requests/api/v1/instances/terms_of_services_spec.rb
Normal file
24
spec/requests/api/v1/instances/terms_of_services_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Terms of Service' do
|
||||
describe 'GET /api/v1/instance/terms_of_service' do
|
||||
before do
|
||||
Fabricate(:terms_of_service)
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get api_v1_instance_terms_of_service_path
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(200)
|
||||
expect(response.content_type)
|
||||
.to start_with('application/json')
|
||||
|
||||
expect(response.parsed_body)
|
||||
.to be_present
|
||||
.and include(:content)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -137,7 +137,7 @@ RSpec.describe 'Media' do
|
|||
end
|
||||
|
||||
context 'with image/gif', :attachment_processing do
|
||||
let(:params) { { file: fixture_file_upload('attachment.gif', 'image/gif') } }
|
||||
let(:params) { { file: fixture_file_upload('600x400.gif', 'image/gif') } }
|
||||
|
||||
it_behaves_like 'a successful media upload', 'image'
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'rails_helper'
|
|||
RSpec.describe REST::AccountRelationshipSeveranceEventSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:record) { Fabricate.build :account_relationship_severance_event, id: 123 }
|
||||
let(:record) { Fabricate.build :account_relationship_severance_event, id: 123, created_at: DateTime.new(2024, 11, 28, 16, 20, 0) }
|
||||
|
||||
describe 'serialization' do
|
||||
it 'returns expected values' do
|
||||
|
@ -15,4 +15,10 @@ RSpec.describe REST::AccountRelationshipSeveranceEventSerializer do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::AccountSerializer::FieldSerializer do
|
||||
subject { serialized_record_json(field, described_class) }
|
||||
|
||||
let(:default_datetime) { DateTime.new(2024, 11, 28, 16, 20, 0) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:account) { user.account }
|
||||
|
||||
context 'when verified_at is populated' do
|
||||
let(:field) { Account::Field.new(account, 'name' => 'Foo', 'value' => 'Bar', 'verified_at' => default_datetime) }
|
||||
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['verified_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,6 +5,7 @@ require 'rails_helper'
|
|||
RSpec.describe REST::AccountSerializer do
|
||||
subject { serialized_record_json(account, described_class) }
|
||||
|
||||
let(:default_datetime) { DateTime.new(2024, 11, 28, 16, 20, 0) }
|
||||
let(:role) { Fabricate(:user_role, name: 'Role', highlighted: true) }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:account) { user.account }
|
||||
|
@ -44,4 +45,24 @@ RSpec.describe REST::AccountSerializer do
|
|||
expect(subject['memorial']).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when created_at is populated' do
|
||||
before do
|
||||
account.account_stat.update!(created_at: default_datetime)
|
||||
end
|
||||
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when last_status_at is populated' do
|
||||
before do
|
||||
account.account_stat.update!(last_status_at: default_datetime)
|
||||
end
|
||||
|
||||
it 'is serialized as yyyy-mm-dd' do
|
||||
expect(subject['last_status_at']).to eq('2024-11-28')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,7 @@ RSpec.describe REST::AccountWarningSerializer do
|
|||
'id' => be_a(String).and(eq('123')),
|
||||
'status_ids' => be_a(Array).and(eq(['456', '789']))
|
||||
)
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,14 @@ require 'rails_helper'
|
|||
RSpec.describe REST::Admin::AccountSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
let(:record) { Fabricate :account, user: Fabricate(:user) }
|
||||
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe 'created_by_application_id' do
|
||||
context 'when account is application-created' do
|
||||
let(:record) { Fabricate :account, user: Fabricate(:user, created_by_application: application) }
|
||||
|
|
|
@ -14,6 +14,8 @@ RSpec.describe REST::Admin::CohortSerializer do
|
|||
'data' => be_a(Array),
|
||||
'period' => /2024-01-01/
|
||||
)
|
||||
expect { DateTime.rfc3339(subject['period']) }.to_not raise_error
|
||||
subject['data'].each { |datum| expect { DateTime.rfc3339(datum['date']) }.to_not raise_error }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
15
spec/serializers/rest/admin/domain_allow_serializer_spec.rb
Normal file
15
spec/serializers/rest/admin/domain_allow_serializer_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::DomainAllowSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:record) { Fabricate(:domain_allow) }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
15
spec/serializers/rest/admin/domain_block_serializer_spec.rb
Normal file
15
spec/serializers/rest/admin/domain_block_serializer_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::DomainBlockSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:record) { Fabricate(:domain_block) }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::EmailDomainBlockSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:record) { Fabricate(:email_domain_block) }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
23
spec/serializers/rest/admin/ip_block_serializer_spec.rb
Normal file
23
spec/serializers/rest/admin/ip_block_serializer_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::IpBlockSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:record) { Fabricate(:ip_block) }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when expires_at is populated' do
|
||||
let(:record) { Fabricate(:ip_block, expires_at: DateTime.new(2024, 11, 28, 16, 20, 0)) }
|
||||
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['expires_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
15
spec/serializers/rest/admin/ip_serializer_spec.rb
Normal file
15
spec/serializers/rest/admin/ip_serializer_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::IpSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:record) { UserIp.new(used_at: 3.days.ago) }
|
||||
|
||||
context 'when used_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['used_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
18
spec/serializers/rest/admin/measure_serializer_spec.rb
Normal file
18
spec/serializers/rest/admin/measure_serializer_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::MeasureSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:start_at) { 2.days.ago }
|
||||
let(:end_at) { Time.now.utc }
|
||||
let(:params) { ActionController::Parameters.new({ instance_accounts: [123] }) }
|
||||
let(:record) { Admin::Metrics::Measure::ActiveUsersMeasure.new(start_at, end_at, params) }
|
||||
|
||||
context 'when start_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
subject['data'].each { |datum| expect { DateTime.rfc3339(datum['date']) }.to_not raise_error }
|
||||
end
|
||||
end
|
||||
end
|
27
spec/serializers/rest/admin/report_serializer_spec.rb
Normal file
27
spec/serializers/rest/admin/report_serializer_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::Admin::ReportSerializer do
|
||||
subject { serialized_record_json(report, described_class) }
|
||||
|
||||
let(:report) { Fabricate(:report) }
|
||||
|
||||
context 'with created_at' do
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'with action_taken_at' do
|
||||
let(:acting_account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
report.resolve!(acting_account)
|
||||
end
|
||||
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['action_taken_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
28
spec/serializers/rest/announcement_serializer_spec.rb
Normal file
28
spec/serializers/rest/announcement_serializer_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::AnnouncementSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
announcement,
|
||||
described_class,
|
||||
options: {
|
||||
scope: current_user,
|
||||
scope_name: :current_user,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let(:current_user) { Fabricate(:user) }
|
||||
let(:announcement) { Fabricate(:announcement, starts_at: 10.days.ago, published_at: 10.days.ago, ends_at: 5.days.from_now) }
|
||||
|
||||
context 'when date fields are populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['starts_at']) }.to_not raise_error
|
||||
expect { DateTime.rfc3339(subject['ends_at']) }.to_not raise_error
|
||||
expect { DateTime.rfc3339(subject['published_at']) }.to_not raise_error
|
||||
expect { DateTime.rfc3339(subject['updated_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,9 +5,11 @@ require 'rails_helper'
|
|||
RSpec.describe REST::ExtendedDescriptionSerializer do
|
||||
subject { serialized_record_json(record, described_class) }
|
||||
|
||||
let(:default_datetime) { DateTime.new(2024, 11, 28, 16, 20, 0) }
|
||||
|
||||
describe 'serialization' do
|
||||
context 'with text present' do
|
||||
let(:record) { ExtendedDescription.new text: 'Hello world', updated_at: Date.new(2024, 1, 1) }
|
||||
let(:record) { ExtendedDescription.new text: 'Hello world', updated_at: default_datetime }
|
||||
|
||||
it 'returns expected values' do
|
||||
expect(subject)
|
||||
|
@ -15,19 +17,19 @@ RSpec.describe REST::ExtendedDescriptionSerializer do
|
|||
'content' => eq(<<~HTML),
|
||||
<p>Hello world</p>
|
||||
HTML
|
||||
'updated_at' => eq('2024-01-01')
|
||||
'updated_at' => eq('2024-11-28T16:20:00+00:00')
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with text missing' do
|
||||
let(:record) { ExtendedDescription.new text: nil, updated_at: Date.new(2024, 1, 1) }
|
||||
let(:record) { ExtendedDescription.new text: nil, updated_at: default_datetime }
|
||||
|
||||
it 'returns expected values' do
|
||||
expect(subject)
|
||||
.to include(
|
||||
'content' => eq(''),
|
||||
'updated_at' => eq('2024-01-01')
|
||||
'updated_at' => eq('2024-11-28T16:20:00+00:00')
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
24
spec/serializers/rest/featured_tag_serializer_spec.rb
Normal file
24
spec/serializers/rest/featured_tag_serializer_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::FeaturedTagSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
featured_tag,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:featured_tag) { Fabricate :featured_tag }
|
||||
|
||||
context 'when last_status_at is populated' do
|
||||
before do
|
||||
featured_tag.increment(DateTime.new(2024, 11, 28, 16, 20, 0))
|
||||
end
|
||||
|
||||
it 'is serialized as yyyy-mm-dd' do
|
||||
expect(subject['last_status_at']).to eq('2024-11-28')
|
||||
end
|
||||
end
|
||||
end
|
20
spec/serializers/rest/filter_serializer_spec.rb
Normal file
20
spec/serializers/rest/filter_serializer_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::FilterSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
filter,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:filter) { Fabricate :custom_filter, expires_at: DateTime.new(2024, 11, 28, 16, 20, 0) }
|
||||
|
||||
context 'when expires_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['expires_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
20
spec/serializers/rest/marker_serializer_spec.rb
Normal file
20
spec/serializers/rest/marker_serializer_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::MarkerSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
marker,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:marker) { Fabricate :marker }
|
||||
|
||||
context 'when updated_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['updated_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
42
spec/serializers/rest/muted_account_serializer_spec.rb
Normal file
42
spec/serializers/rest/muted_account_serializer_spec.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::MutedAccountSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
mutee,
|
||||
described_class,
|
||||
options: {
|
||||
scope: current_user,
|
||||
scope_name: :current_user,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let(:current_user) { Fabricate(:user) }
|
||||
let(:account) { current_user.account }
|
||||
let(:mutee) { Fabricate(:account, username: 'mutee') }
|
||||
|
||||
context 'when mute_expires_at is populated and non-nil' do
|
||||
before do
|
||||
account.follow!(mutee)
|
||||
account.mute!(mutee, duration: 1.day)
|
||||
end
|
||||
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['mute_expires_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when mute has no duration' do
|
||||
before do
|
||||
account.follow!(mutee)
|
||||
account.mute!(mutee)
|
||||
end
|
||||
|
||||
it 'has a nil mute_expires_at' do
|
||||
expect(subject['mute_expires_at']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
20
spec/serializers/rest/notification_group_serializer_spec.rb
Normal file
20
spec/serializers/rest/notification_group_serializer_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::NotificationGroupSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
notification_group,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:notification_group) { NotificationGroup.new pagination_data: { latest_notification_at: 3.days.ago }, notification: Fabricate(:notification), sample_accounts: [] }
|
||||
|
||||
context 'when latest_page_notification_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['latest_page_notification_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::NotificationRequestSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
notification_request,
|
||||
described_class,
|
||||
options: {
|
||||
scope: current_user,
|
||||
scope_name: :current_user,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let(:current_user) { Fabricate(:user) }
|
||||
let(:notification_request) { Fabricate :notification_request }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when updated_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['updated_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
20
spec/serializers/rest/notification_serializer_spec.rb
Normal file
20
spec/serializers/rest/notification_serializer_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::NotificationSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
notification,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:notification) { Fabricate :notification }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
25
spec/serializers/rest/poll_serializer_spec.rb
Normal file
25
spec/serializers/rest/poll_serializer_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::PollSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
poll,
|
||||
described_class,
|
||||
options: {
|
||||
scope: current_user,
|
||||
scope_name: :current_user,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let(:current_user) { Fabricate(:user) }
|
||||
let(:poll) { Fabricate :poll }
|
||||
|
||||
context 'when expires_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['expires_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
33
spec/serializers/rest/report_serializer_spec.rb
Normal file
33
spec/serializers/rest/report_serializer_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::ReportSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
report,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:report) { Fabricate(:report, status_ids: [status.id]) }
|
||||
|
||||
context 'with created_at' do
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'with action_taken_at' do
|
||||
let(:acting_account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
report.resolve!(acting_account)
|
||||
end
|
||||
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['action_taken_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
21
spec/serializers/rest/scheduled_status_serializer_spec.rb
Normal file
21
spec/serializers/rest/scheduled_status_serializer_spec.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::ScheduledStatusSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
scheduled_status,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:scheduled_status) { Fabricate.build(:scheduled_status, scheduled_at: 4.minutes.from_now, account: account) }
|
||||
|
||||
context 'with scheduled_at' do
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['scheduled_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
20
spec/serializers/rest/status_edit_serializer_spec.rb
Normal file
20
spec/serializers/rest/status_edit_serializer_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe REST::StatusEditSerializer do
|
||||
subject do
|
||||
serialized_record_json(
|
||||
status_edit,
|
||||
described_class
|
||||
)
|
||||
end
|
||||
|
||||
let(:status_edit) { Fabricate(:status_edit) }
|
||||
|
||||
context 'when created_at is populated' do
|
||||
it 'parses as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -51,5 +51,19 @@ RSpec.describe REST::StatusSerializer do
|
|||
expect(subject['favourites_count']).to eq(40)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with created_at' do
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['created_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when edited_at is populated' do
|
||||
let(:status) { Fabricate.build :status, edited_at: 3.days.ago }
|
||||
|
||||
it 'is serialized as RFC 3339 datetime' do
|
||||
expect { DateTime.rfc3339(subject['edited_at']) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,7 +38,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
let(:media_attachments) { [] }
|
||||
|
||||
before do
|
||||
mentions.each { |a| Fabricate(:mention, status: status, account: a) }
|
||||
mentions.each { |(account, silent)| Fabricate(:mention, status: status, account: account, silent: silent) }
|
||||
tags.each { |t| status.tags << t }
|
||||
media_attachments.each { |m| status.media_attachments << m }
|
||||
stub_request(:get, bogus_mention).to_raise(HTTP::ConnectionError)
|
||||
|
@ -324,7 +324,19 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
|
|||
end
|
||||
|
||||
context 'when originally with mentions' do
|
||||
let(:mentions) { [alice, bob] }
|
||||
let(:mentions) { [[alice, false], [bob, false]] }
|
||||
|
||||
before do
|
||||
subject.call(status, json, json)
|
||||
end
|
||||
|
||||
it 'updates mentions' do
|
||||
expect(status.active_mentions.reload.map(&:account_id)).to eq [alice.id]
|
||||
end
|
||||
end
|
||||
|
||||
context 'when originally with silent mentions' do
|
||||
let(:mentions) { [[alice, true], [bob, true]] }
|
||||
|
||||
before do
|
||||
subject.call(status, json, json)
|
||||
|
|
|
@ -109,7 +109,7 @@ RSpec.describe ReblogService do
|
|||
Status
|
||||
.where(id: reblog_of_id)
|
||||
.where(text: 'discard-status-text')
|
||||
.update_all(deleted_at: Time.now.utc)
|
||||
.touch_all(:deleted_at)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -199,6 +199,14 @@ RSpec.describe UpdateStatusService do
|
|||
.to eq [bob.id]
|
||||
expect(status.mentions.pluck(:account_id))
|
||||
.to contain_exactly(alice.id, bob.id)
|
||||
|
||||
# Going back when a mention was switched to silence should still be possible
|
||||
subject.call(status, status.account_id, text: 'Hello @alice')
|
||||
|
||||
expect(status.active_mentions.pluck(:account_id))
|
||||
.to eq [alice.id]
|
||||
expect(status.mentions.pluck(:account_id))
|
||||
.to contain_exactly(alice.id, bob.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec::Matchers.define :model_have_error_on_field do |expected|
|
||||
match do |record|
|
||||
record.valid? if record.errors.empty?
|
||||
|
||||
record.errors.key?(expected)
|
||||
end
|
||||
|
||||
failure_message do |record|
|
||||
keys = record.errors.attribute_names
|
||||
|
||||
"expect record.errors(#{keys}) to include #{expected}"
|
||||
end
|
||||
end
|
21
spec/system/admin/terms_of_service_spec.rb
Normal file
21
spec/system/admin/terms_of_service_spec.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Terms of services' do
|
||||
describe 'Viewing terms of services index page' do
|
||||
let!(:terms) { Fabricate :terms_of_service, text: 'Test terms' }
|
||||
|
||||
before { sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
it 'allows tags listing and editing' do
|
||||
visit admin_terms_of_service_index_path
|
||||
|
||||
expect(page)
|
||||
.to have_title(I18n.t('admin.terms_of_service.title'))
|
||||
|
||||
expect(page)
|
||||
.to have_content(terms.text)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,7 +34,7 @@ RSpec.describe 'Log in' do
|
|||
it 'A unconfirmed user is able to log in' do
|
||||
fill_in_auth_details(email, password)
|
||||
|
||||
expect(subject).to have_css('div.admin-wrapper')
|
||||
expect(subject).to have_css('.title', text: I18n.t('auth.setup.title'))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
34
spec/system/settings/verifications_spec.rb
Normal file
34
spec/system/settings/verifications_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Settings verification page' do
|
||||
let(:user) { Fabricate :user }
|
||||
|
||||
before { sign_in user }
|
||||
|
||||
describe 'Viewing the verification page' do
|
||||
it 'shows the page and updates attribution' do
|
||||
visit settings_verification_path
|
||||
|
||||
expect(page)
|
||||
.to have_content(verification_summary)
|
||||
.and have_private_cache_control
|
||||
|
||||
fill_in attribution_field, with: 'host.example'
|
||||
|
||||
expect { click_on submit_button }
|
||||
.to(change { user.account.reload.attribution_domains_as_text })
|
||||
expect(page)
|
||||
.to have_content(success_message)
|
||||
end
|
||||
end
|
||||
|
||||
def verification_summary
|
||||
I18n.t('verification.website_verification')
|
||||
end
|
||||
|
||||
def attribution_field
|
||||
I18n.t('simple_form.labels.account.attribution_domains_as_text')
|
||||
end
|
||||
end
|
13
spec/system/terms_of_service_spec.rb
Normal file
13
spec/system/terms_of_service_spec.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Terms of Service page' do
|
||||
it 'visits the about page and renders the web app' do
|
||||
visit terms_of_service_path
|
||||
|
||||
expect(page)
|
||||
.to have_css('noscript', text: /Mastodon/)
|
||||
.and have_css('body', class: 'app-body')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::DistributeTermsOfServiceNotificationWorker do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
context 'with missing record' do
|
||||
it 'runs without error' do
|
||||
expect { worker.perform(nil) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid terms' do
|
||||
let(:terms) { Fabricate(:terms_of_service) }
|
||||
let!(:user) { Fabricate :user, confirmed_at: 3.days.ago }
|
||||
|
||||
it 'sends the terms update via email', :inline_jobs do
|
||||
emails = capture_emails { worker.perform(terms.id) }
|
||||
|
||||
expect(emails.size)
|
||||
.to eq(1)
|
||||
expect(emails.first)
|
||||
.to have_attributes(
|
||||
to: [user.email],
|
||||
subject: I18n.t('user_mailer.terms_of_service_changed.subject')
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue