+
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index adfcaa1593..cd68725a02 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -10804,21 +10804,17 @@ noscript {
color: $darker-text-color;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
- max-height: 4 * 22px;
+ max-height: none;
overflow: hidden;
- p {
- display: none;
-
- &:first-child {
- display: initial;
- }
- }
-
p,
a {
color: inherit;
}
+
+ p {
+ margin-bottom: 8px;
+ }
}
.reply-indicator__attachments {
diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss
index e4e299ff82..0a05ce7c62 100644
--- a/app/javascript/styles/mastodon/rtl.scss
+++ b/app/javascript/styles/mastodon/rtl.scss
@@ -35,6 +35,10 @@ body.rtl {
direction: rtl;
}
+ .column-back-button__icon {
+ transform: scale(-1, 1);
+ }
+
.simple_form select {
background: $ui-base-color
url("data:image/svg+xml;utf8,")
diff --git a/app/lib/content_security_policy.rb b/app/lib/content_security_policy.rb
index a6901a6757..2e6c43be8f 100644
--- a/app/lib/content_security_policy.rb
+++ b/app/lib/content_security_policy.rb
@@ -40,7 +40,7 @@ class ContentSecurityPolicy
end
def cdn_host_value
- s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host
+ s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host || swift_object_url
end
def paperclip_root_url
@@ -76,6 +76,14 @@ class ContentSecurityPolicy
host_to_url ENV.fetch('S3_HOSTNAME', nil)
end
+ def swift_object_url
+ url = ENV.fetch('SWIFT_OBJECT_URL', nil)
+ return if url.blank? || !url.start_with?('https://')
+
+ url += '/' unless url.end_with?('/')
+ url
+ end
+
def uri_from_configuration_and_string(host_string)
Addressable::URI.parse("#{host_protocol}://#{host_string}").tap do |uri|
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
diff --git a/app/models/follow_recommendation.rb b/app/models/follow_recommendation.rb
index 7ac9e6dfb9..0435437a81 100644
--- a/app/models/follow_recommendation.rb
+++ b/app/models/follow_recommendation.rb
@@ -18,5 +18,6 @@ class FollowRecommendation < ApplicationRecord
belongs_to :account_summary, foreign_key: :account_id, inverse_of: false
belongs_to :account
- scope :localized, ->(locale) { joins(:account_summary).merge(AccountSummary.localized(locale)) }
+ scope :unsupressed, -> { where.not(FollowRecommendationSuppression.where(FollowRecommendationSuppression.arel_table[:account_id].eq(arel_table[:account_id])).select(1).arel.exists) }
+ scope :localized, ->(locale) { unsupressed.joins(:account_summary).merge(AccountSummary.localized(locale)) }
end
diff --git a/app/services/translate_status_service.rb b/app/services/translate_status_service.rb
index e2e076e21b..bcd4703beb 100644
--- a/app/services/translate_status_service.rb
+++ b/app/services/translate_status_service.rb
@@ -9,6 +9,8 @@ class TranslateStatusService < BaseService
def call(status, target_language)
@status = status
@source_texts = source_texts
+
+ target_language = target_language.split(/[_-]/).first unless target_languages.include?(target_language)
@target_language = target_language
raise Mastodon::NotPermittedError unless permitted?
@@ -32,11 +34,15 @@ class TranslateStatusService < BaseService
def permitted?
return false unless @status.distributable? && TranslationService.configured?
- languages[@status.language]&.include?(@target_language)
+ target_languages.include?(@target_language)
end
def languages
- Rails.cache.fetch('translation_service/languages', expires_in: 7.days, race_condition_ttl: 1.hour) { TranslationService.configured.languages }
+ Rails.cache.fetch('translation_service/languages', expires_in: 7.days, race_condition_ttl: 1.hour) { translation_backend.languages }
+ end
+
+ def target_languages
+ languages[@status.language] || []
end
def content_hash
diff --git a/app/views/admin/invites/_invite.html.haml b/app/views/admin/invites/_invite.html.haml
index 53eac1d0cd..e3e5d32542 100644
--- a/app/views/admin/invites/_invite.html.haml
+++ b/app/views/admin/invites/_invite.html.haml
@@ -1,4 +1,4 @@
-%tr
+%tr{ id: dom_id(invite) }
%td
.input-copy
.input-copy__wrapper
diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb
index b7a874e404..c53f16d4d1 100644
--- a/config/initializers/active_record_encryption.rb
+++ b/config/initializers/active_record_encryption.rb
@@ -20,6 +20,7 @@
- ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
Run `bin/rails db:encryption:init` to generate new secrets and then assign the environment variables.
+ Do not change the secrets once they are set, as doing so may cause data loss and other issues that will be difficult or impossible to recover from.
MESSAGE
end
diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake
index 79599bd917..73de0c120f 100644
--- a/lib/tasks/db.rake
+++ b/lib/tasks/db.rake
@@ -7,6 +7,17 @@ namespace :db do
namespace :encryption do
desc 'Generate a set of keys for configuring Active Record encryption in a given environment'
task :init do # rubocop:disable Rails/RakeEnvironment
+ if %w(
+ ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
+ ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
+ ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
+ ).any? { |key| ENV.key?(key) }
+ pastel = Pastel.new
+ puts pastel.red(<<~MSG)
+ WARNING: It looks like encryption secrets have already been set. Please ensure you are not changing secrets for a Mastodon installation that already uses them, as this will cause data loss and other issues that are difficult to recover from.
+ MSG
+ end
+
puts <<~MSG
Add the following secret environment variables to your Mastodon environment (e.g. .env.production), ensure they are shared across all your nodes and do not change them after they are set:#{' '}
diff --git a/spec/controllers/admin/invites_controller_spec.rb b/spec/controllers/admin/invites_controller_spec.rb
deleted file mode 100644
index b6471e80b2..0000000000
--- a/spec/controllers/admin/invites_controller_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Admin::InvitesController 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
- subject { get :index, params: { available: true } }
-
- let!(:invite) { Fabricate(:invite) }
-
- it 'renders index page' do
- expect(subject).to render_template :index
- expect(response.body)
- .to include(invite.code)
- end
- end
-
- describe 'POST #create' do
- subject { post :create, params: { invite: { max_uses: '10', expires_in: 1800 } } }
-
- it 'succeeds to create a invite' do
- expect { subject }.to change(Invite, :count).by(1)
- expect(subject).to redirect_to admin_invites_path
- expect(Invite.last).to have_attributes(user_id: user.id, max_uses: 10)
- end
- end
-
- describe 'DELETE #destroy' do
- subject { delete :destroy, params: { id: invite.id } }
-
- let!(:invite) { Fabricate(:invite, expires_at: nil) }
-
- it 'expires invite' do
- expect(subject).to redirect_to admin_invites_path
- expect(invite.reload).to be_expired
- end
- end
-
- describe 'POST #deactivate_all' do
- before { Fabricate(:invite, expires_at: nil) }
-
- it 'expires all invites, then redirects to admin_invites_path' do
- expect { post :deactivate_all }
- .to change { Invite.exists?(expires_at: nil) }
- .from(true)
- .to(false)
-
- expect(response).to redirect_to admin_invites_path
- end
- end
-end
diff --git a/spec/controllers/admin/tags_controller_spec.rb b/spec/controllers/admin/tags_controller_spec.rb
deleted file mode 100644
index 1df2bc4003..0000000000
--- a/spec/controllers/admin/tags_controller_spec.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Admin::TagsController do
- render_views
-
- before do
- sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
- end
-
- describe 'GET #index' do
- before do
- Fabricate(:tag)
-
- tag_filter = instance_double(Admin::TagFilter, results: Tag.all)
- allow(Admin::TagFilter).to receive(:new).and_return(tag_filter)
- end
-
- let(:params) { { order: 'newest' } }
-
- it 'returns http success' do
- get :index
-
- expect(response).to have_http_status(200)
- expect(response).to render_template(:index)
-
- expect(Admin::TagFilter)
- .to have_received(:new)
- .with(hash_including(params))
- end
-
- describe 'with filters' do
- let(:params) { { order: 'newest', name: 'test' } }
-
- it 'returns http success' do
- get :index, params: { name: 'test' }
-
- expect(response).to have_http_status(200)
- expect(response).to render_template(:index)
-
- expect(Admin::TagFilter)
- .to have_received(:new)
- .with(hash_including(params))
- end
- end
- end
-
- describe 'GET #show' do
- let!(:tag) { Fabricate(:tag) }
-
- before do
- get :show, params: { id: tag.id }
- end
-
- it 'returns status 200' do
- expect(response).to have_http_status(200)
- end
- end
-
- describe 'PUT #update' do
- let!(:tag) { Fabricate(:tag, listable: false) }
-
- context 'with valid params' do
- it 'updates the tag' do
- put :update, params: { id: tag.id, tag: { listable: '1' } }
-
- expect(response).to redirect_to(admin_tag_path(tag.id))
- expect(tag.reload).to be_listable
- end
- end
-
- context 'with invalid params' do
- it 'does not update the tag' do
- put :update, params: { id: tag.id, tag: { name: 'cant-change-name' } }
-
- expect(response).to have_http_status(200)
- expect(response).to render_template(:show)
- end
- end
- end
-end
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
index d9702251f4..121e4aa6c6 100644
--- a/spec/controllers/statuses_controller_spec.rb
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -736,76 +736,4 @@ RSpec.describe StatusesController do
end
end
end
-
- describe 'GET #embed' do
- let(:account) { Fabricate(:account) }
- let(:status) { Fabricate(:status, account: account) }
-
- context 'when account is suspended' do
- let(:account) { Fabricate(:account, suspended: true) }
-
- before do
- get :embed, params: { account_username: account.username, id: status.id }
- end
-
- it 'returns http gone' do
- expect(response).to have_http_status(410)
- end
- end
-
- context 'when status is a reblog' do
- let(:original_account) { Fabricate(:account, domain: 'example.com') }
- let(:original_status) { Fabricate(:status, account: original_account, url: 'https://example.com/123') }
- let(:status) { Fabricate(:status, account: account, reblog: original_status) }
-
- before do
- get :embed, params: { account_username: status.account.username, id: status.id }
- end
-
- it 'returns http not found' do
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when status is public' do
- before do
- get :embed, params: { account_username: status.account.username, id: status.id }
- end
-
- it 'renders status successfully', :aggregate_failures do
- expect(response)
- .to have_http_status(200)
- .and render_template(:embed)
- expect(response.headers).to include(
- 'Vary' => 'Accept, Accept-Language, Cookie',
- 'Cache-Control' => include('public'),
- 'Link' => include('activity+json')
- )
- end
- end
-
- context 'when status is private' do
- let(:status) { Fabricate(:status, account: account, visibility: :private) }
-
- before do
- get :embed, params: { account_username: status.account.username, id: status.id }
- end
-
- it 'returns http not found' do
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when status is direct' do
- let(:status) { Fabricate(:status, account: account, visibility: :direct) }
-
- before do
- get :embed, params: { account_username: status.account.username, id: status.id }
- end
-
- it 'returns http not found' do
- expect(response).to have_http_status(404)
- end
- end
- end
end
diff --git a/spec/fabricators/ip_block_fabricator.rb b/spec/fabricators/ip_block_fabricator.rb
new file mode 100644
index 0000000000..30c48b90c6
--- /dev/null
+++ b/spec/fabricators/ip_block_fabricator.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+Fabricator(:ip_block) do
+ severity { :sign_up_requires_approval }
+ ip { sequence(:ip) { |n| "10.0.0.#{n}" } }
+end
diff --git a/spec/lib/account_reach_finder_spec.rb b/spec/lib/account_reach_finder_spec.rb
index e5d85656a2..0c1d92b2da 100644
--- a/spec/lib/account_reach_finder_spec.rb
+++ b/spec/lib/account_reach_finder_spec.rb
@@ -38,16 +38,23 @@ RSpec.describe AccountReachFinder do
end
describe '#inboxes' do
- it 'includes the preferred inbox URL of followers' do
- expect(described_class.new(account).inboxes).to include(*[ap_follower_example_com, ap_follower_example_org, ap_follower_with_shared].map(&:preferred_inbox_url))
+ subject { described_class.new(account).inboxes }
+
+ it 'includes the preferred inbox URL of followers and recently mentioned accounts but not unrelated users' do
+ expect(subject)
+ .to include(*follower_inbox_urls)
+ .and include(*mentioned_account_inbox_urls)
+ .and not_include(unrelated_account.preferred_inbox_url)
end
- it 'includes the preferred inbox URL of recently-mentioned accounts' do
- expect(described_class.new(account).inboxes).to include(*[ap_mentioned_with_shared, ap_mentioned_example_com, ap_mentioned_example_org].map(&:preferred_inbox_url))
+ def follower_inbox_urls
+ [ap_follower_example_com, ap_follower_example_org, ap_follower_with_shared]
+ .map(&:preferred_inbox_url)
end
- it 'does not include the inbox of unrelated users' do
- expect(described_class.new(account).inboxes).to_not include(unrelated_account.preferred_inbox_url)
+ def mentioned_account_inbox_urls
+ [ap_mentioned_with_shared, ap_mentioned_example_com, ap_mentioned_example_org]
+ .map(&:preferred_inbox_url)
end
end
end
diff --git a/spec/lib/activitypub/activity/block_spec.rb b/spec/lib/activitypub/activity/block_spec.rb
index 6f68984018..385628852b 100644
--- a/spec/lib/activitypub/activity/block_spec.rb
+++ b/spec/lib/activitypub/activity/block_spec.rb
@@ -3,6 +3,8 @@
require 'rails_helper'
RSpec.describe ActivityPub::Activity::Block do
+ subject { described_class.new(json, sender) }
+
let(:sender) { Fabricate(:account) }
let(:recipient) { Fabricate(:account) }
@@ -16,93 +18,65 @@ RSpec.describe ActivityPub::Activity::Block do
}.with_indifferent_access
end
- context 'when the recipient does not follow the sender' do
- describe '#perform' do
- subject { described_class.new(json, sender) }
-
- before do
- subject.perform
- end
-
+ describe '#perform' do
+ context 'when the recipient does not follow the sender' do
it 'creates a block from sender to recipient' do
- expect(sender.blocking?(recipient)).to be true
+ subject.perform
+
+ expect(sender)
+ .to be_blocking(recipient)
end
end
- end
- context 'when the recipient is already blocked' do
- before do
- sender.block!(recipient, uri: 'old')
+ context 'when the recipient is already blocked' do
+ before { sender.block!(recipient, uri: 'old') }
+
+ it 'creates a block from sender to recipient and sets uri to last received block activity' do
+ subject.perform
+
+ expect(sender)
+ .to be_blocking(recipient)
+ expect(sender.block_relationships.find_by(target_account: recipient).uri)
+ .to eq 'foo'
+ end
end
- describe '#perform' do
- subject { described_class.new(json, sender) }
+ context 'when the recipient follows the sender' do
+ before { recipient.follow!(sender) }
+
+ it 'creates a block from sender to recipient and ensures recipient not following sender' do
+ subject.perform
+
+ expect(sender)
+ .to be_blocking(recipient)
+ expect(recipient)
+ .to_not be_following(sender)
+ end
+ end
+
+ context 'when a matching undo has been received first' do
+ let(:undo_json) do
+ {
+ '@context': 'https://www.w3.org/ns/activitystreams',
+ id: 'bar',
+ type: 'Undo',
+ actor: ActivityPub::TagManager.instance.uri_for(sender),
+ object: json,
+ }.with_indifferent_access
+ end
before do
+ recipient.follow!(sender)
+ ActivityPub::Activity::Undo.new(undo_json, sender).perform
+ end
+
+ it 'does not create a block from sender to recipient and ensures recipient not following sender' do
subject.perform
- end
- it 'creates a block from sender to recipient' do
- expect(sender.blocking?(recipient)).to be true
- end
-
- it 'sets the uri to that of last received block activity' do
- expect(sender.block_relationships.find_by(target_account: recipient).uri).to eq 'foo'
- end
- end
- end
-
- context 'when the recipient follows the sender' do
- before do
- recipient.follow!(sender)
- end
-
- describe '#perform' do
- subject { described_class.new(json, sender) }
-
- before do
- subject.perform
- end
-
- it 'creates a block from sender to recipient' do
- expect(sender.blocking?(recipient)).to be true
- end
-
- it 'ensures recipient is not following sender' do
- expect(recipient.following?(sender)).to be false
- end
- end
- end
-
- context 'when a matching undo has been received first' do
- let(:undo_json) do
- {
- '@context': 'https://www.w3.org/ns/activitystreams',
- id: 'bar',
- type: 'Undo',
- actor: ActivityPub::TagManager.instance.uri_for(sender),
- object: json,
- }.with_indifferent_access
- end
-
- before do
- recipient.follow!(sender)
- ActivityPub::Activity::Undo.new(undo_json, sender).perform
- end
-
- describe '#perform' do
- subject { described_class.new(json, sender) }
-
- before do
- subject.perform
- end
-
- it 'does not create a block from sender to recipient' do
- expect(sender.blocking?(recipient)).to be false
- end
-
- it 'ensures recipient is not following sender' do
- expect(recipient.following?(sender)).to be false
+ expect(sender)
+ .to_not be_blocking(recipient)
+ expect(recipient)
+ .to_not be_following(sender)
end
end
end
diff --git a/spec/lib/vacuum/access_tokens_vacuum_spec.rb b/spec/lib/vacuum/access_tokens_vacuum_spec.rb
index 54760c41bd..8768f6b2dc 100644
--- a/spec/lib/vacuum/access_tokens_vacuum_spec.rb
+++ b/spec/lib/vacuum/access_tokens_vacuum_spec.rb
@@ -14,32 +14,24 @@ RSpec.describe Vacuum::AccessTokensVacuum do
let!(:expired_access_grant) { Fabricate(:access_grant, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) }
let!(:active_access_grant) { Fabricate(:access_grant) }
- before do
+ it 'deletes revoked/expired access tokens and revoked/expired grants, but preserves active tokens/grants' do
subject.perform
- end
- it 'deletes revoked access tokens' do
- expect { revoked_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
- end
+ expect { revoked_access_token.reload }
+ .to raise_error ActiveRecord::RecordNotFound
+ expect { expired_access_token.reload }
+ .to raise_error ActiveRecord::RecordNotFound
- it 'deletes expired access tokens' do
- expect { expired_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
- end
+ expect { revoked_access_grant.reload }
+ .to raise_error ActiveRecord::RecordNotFound
+ expect { expired_access_grant.reload }
+ .to raise_error ActiveRecord::RecordNotFound
- it 'deletes revoked access grants' do
- expect { revoked_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
- end
+ expect { active_access_token.reload }
+ .to_not raise_error
- it 'deletes expired access grants' do
- expect { expired_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
- end
-
- it 'does not delete active access tokens' do
- expect { active_access_token.reload }.to_not raise_error
- end
-
- it 'does not delete active access grants' do
- expect { active_access_grant.reload }.to_not raise_error
+ expect { active_access_grant.reload }
+ .to_not raise_error
end
end
end
diff --git a/spec/lib/vacuum/backups_vacuum_spec.rb b/spec/lib/vacuum/backups_vacuum_spec.rb
index 867dbe4020..4a025352cb 100644
--- a/spec/lib/vacuum/backups_vacuum_spec.rb
+++ b/spec/lib/vacuum/backups_vacuum_spec.rb
@@ -11,16 +11,13 @@ RSpec.describe Vacuum::BackupsVacuum do
let!(:expired_backup) { Fabricate(:backup, created_at: (retention_period + 1.day).ago) }
let!(:current_backup) { Fabricate(:backup) }
- before do
+ it 'deletes backups past the retention period but preserves those within the period' do
subject.perform
- end
- it 'deletes backups past the retention period' do
- expect { expired_backup.reload }.to raise_error ActiveRecord::RecordNotFound
- end
-
- it 'does not delete backups within the retention period' do
- expect { current_backup.reload }.to_not raise_error
+ expect { expired_backup.reload }
+ .to raise_error ActiveRecord::RecordNotFound
+ expect { current_backup.reload }
+ .to_not raise_error
end
end
end
diff --git a/spec/lib/vacuum/feeds_vacuum_spec.rb b/spec/lib/vacuum/feeds_vacuum_spec.rb
index ede1e3c360..38459a558f 100644
--- a/spec/lib/vacuum/feeds_vacuum_spec.rb
+++ b/spec/lib/vacuum/feeds_vacuum_spec.rb
@@ -14,11 +14,11 @@ RSpec.describe Vacuum::FeedsVacuum do
redis.zadd(feed_key_for(active_user), 1, 1)
redis.zadd(feed_key_for(inactive_user, 'reblogs'), 2, 2)
redis.sadd(feed_key_for(inactive_user, 'reblogs:2'), 3)
-
- subject.perform
end
it 'clears feeds of inactive users and lists' do
+ subject.perform
+
expect(redis.zcard(feed_key_for(inactive_user))).to eq 0
expect(redis.zcard(feed_key_for(active_user))).to eq 1
expect(redis.exists?(feed_key_for(inactive_user, 'reblogs'))).to be false
diff --git a/spec/lib/vacuum/media_attachments_vacuum_spec.rb b/spec/lib/vacuum/media_attachments_vacuum_spec.rb
index 1039c36cea..f7749038cb 100644
--- a/spec/lib/vacuum/media_attachments_vacuum_spec.rb
+++ b/spec/lib/vacuum/media_attachments_vacuum_spec.rb
@@ -17,9 +17,9 @@ RSpec.describe Vacuum::MediaAttachmentsVacuum do
let!(:old_unattached_media) { Fabricate(:media_attachment, account_id: nil, created_at: 10.days.ago) }
let!(:new_unattached_media) { Fabricate(:media_attachment, account_id: nil, created_at: 1.hour.ago) }
- before { subject.perform }
-
it 'handles attachments based on metadata details' do
+ subject.perform
+
expect(old_remote_media.reload.file) # Remote and past retention period
.to be_blank
expect(old_local_media.reload.file) # Local and past retention
diff --git a/spec/lib/vacuum/preview_cards_vacuum_spec.rb b/spec/lib/vacuum/preview_cards_vacuum_spec.rb
index 9dbdf0bc2f..caeedd3269 100644
--- a/spec/lib/vacuum/preview_cards_vacuum_spec.rb
+++ b/spec/lib/vacuum/preview_cards_vacuum_spec.rb
@@ -15,24 +15,22 @@ RSpec.describe Vacuum::PreviewCardsVacuum do
before do
old_preview_card.statuses << Fabricate(:status)
new_preview_card.statuses << Fabricate(:status)
+ end
+ it 'handles preview card cleanup' do
subject.perform
- end
- it 'deletes cache of preview cards last updated before the retention period' do
- expect(old_preview_card.reload.image).to be_blank
- end
+ expect(old_preview_card.reload.image) # last updated before retention period
+ .to be_blank
- it 'does not delete cache of preview cards last updated within the retention period' do
- expect(new_preview_card.reload.image).to_not be_blank
- end
+ expect(new_preview_card.reload.image) # last updated within the retention period
+ .to_not be_blank
- it 'does not delete attached preview cards' do
- expect(new_preview_card.reload).to be_persisted
- end
+ expect(new_preview_card.reload) # Keep attached preview cards
+ .to be_persisted
- it 'does not delete orphaned preview cards in the retention period' do
- expect(orphaned_preview_card.reload).to be_persisted
+ expect(orphaned_preview_card.reload) # keep orphaned cards in the retention period
+ .to be_persisted
end
end
end
diff --git a/spec/lib/vacuum/statuses_vacuum_spec.rb b/spec/lib/vacuum/statuses_vacuum_spec.rb
index d5c0139506..1fff864879 100644
--- a/spec/lib/vacuum/statuses_vacuum_spec.rb
+++ b/spec/lib/vacuum/statuses_vacuum_spec.rb
@@ -15,24 +15,20 @@ RSpec.describe Vacuum::StatusesVacuum do
let!(:local_status_old) { Fabricate(:status, created_at: (retention_period + 2.days).ago) }
let!(:local_status_recent) { Fabricate(:status, created_at: (retention_period - 2.days).ago) }
- before do
+ it 'deletes remote statuses past the retention period and keeps others' do
subject.perform
- end
- it 'deletes remote statuses past the retention period' do
- expect { remote_status_old.reload }.to raise_error ActiveRecord::RecordNotFound
- end
+ expect { remote_status_old.reload }
+ .to raise_error ActiveRecord::RecordNotFound
- it 'does not delete local statuses past the retention period' do
- expect { local_status_old.reload }.to_not raise_error
- end
+ expect { local_status_old.reload }
+ .to_not raise_error
- it 'does not delete remote statuses within the retention period' do
- expect { remote_status_recent.reload }.to_not raise_error
- end
+ expect { remote_status_recent.reload }
+ .to_not raise_error
- it 'does not delete local statuses within the retention period' do
- expect { local_status_recent.reload }.to_not raise_error
+ expect { local_status_recent.reload }
+ .to_not raise_error
end
end
end
diff --git a/spec/models/account_statuses_cleanup_policy_spec.rb b/spec/models/account_statuses_cleanup_policy_spec.rb
index a08fd723a4..c142a0359a 100644
--- a/spec/models/account_statuses_cleanup_policy_spec.rb
+++ b/spec/models/account_statuses_cleanup_policy_spec.rb
@@ -16,6 +16,8 @@ RSpec.describe AccountStatusesCleanupPolicy do
describe 'save hooks' do
context 'when widening a policy' do
+ subject { account_statuses_cleanup_policy.last_inspected }
+
let!(:account_statuses_cleanup_policy) do
Fabricate(:account_statuses_cleanup_policy,
account: account,
@@ -33,64 +35,64 @@ RSpec.describe AccountStatusesCleanupPolicy do
account_statuses_cleanup_policy.record_last_inspected(42)
end
- it 'invalidates last_inspected when widened because of keep_direct' do
- account_statuses_cleanup_policy.keep_direct = false
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of keep_direct' do
+ before { account_statuses_cleanup_policy.update(keep_direct: false) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of keep_pinned' do
- account_statuses_cleanup_policy.keep_pinned = false
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of keep_pinned' do
+ before { account_statuses_cleanup_policy.update(keep_pinned: false) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of keep_polls' do
- account_statuses_cleanup_policy.keep_polls = false
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of keep_polls' do
+ before { account_statuses_cleanup_policy.update(keep_polls: false) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of keep_media' do
- account_statuses_cleanup_policy.keep_media = false
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of keep_media' do
+ before { account_statuses_cleanup_policy.update(keep_media: false) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of keep_self_fav' do
- account_statuses_cleanup_policy.keep_self_fav = false
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of keep_self_fav' do
+ before { account_statuses_cleanup_policy.update(keep_self_fav: false) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of keep_self_bookmark' do
- account_statuses_cleanup_policy.keep_self_bookmark = false
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of keep_self_bookmark' do
+ before { account_statuses_cleanup_policy.update(keep_self_bookmark: false) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of higher min_favs' do
- account_statuses_cleanup_policy.min_favs = 5
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of higher min_favs' do
+ before { account_statuses_cleanup_policy.update(min_favs: 5) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of disabled min_favs' do
- account_statuses_cleanup_policy.min_favs = nil
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of disabled min_favs' do
+ before { account_statuses_cleanup_policy.update(min_favs: nil) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of higher min_reblogs' do
- account_statuses_cleanup_policy.min_reblogs = 5
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of higher min_reblogs' do
+ before { account_statuses_cleanup_policy.update(min_reblogs: 5) }
+
+ it { is_expected.to be_nil }
end
- it 'invalidates last_inspected when widened because of disable min_reblogs' do
- account_statuses_cleanup_policy.min_reblogs = nil
- account_statuses_cleanup_policy.save
- expect(account_statuses_cleanup_policy.last_inspected).to be_nil
+ context 'when widened because of disable min_reblogs' do
+ before { account_statuses_cleanup_policy.update(min_reblogs: nil) }
+
+ it { is_expected.to be_nil }
end
end
diff --git a/spec/models/block_spec.rb b/spec/models/block_spec.rb
index 84f0f318f4..62d7e40e28 100644
--- a/spec/models/block_spec.rb
+++ b/spec/models/block_spec.rb
@@ -3,11 +3,37 @@
require 'rails_helper'
RSpec.describe Block do
- describe 'validations' do
+ describe 'Associations' do
it { is_expected.to belong_to(:account).required }
it { is_expected.to belong_to(:target_account).required }
end
+ describe '#local?' do
+ it { is_expected.to_not be_local }
+ end
+
+ describe 'Callbacks' do
+ describe 'Setting a URI' do
+ context 'when URI exists' do
+ subject { Fabricate.build :block, uri: 'https://uri/value' }
+
+ it 'does not change' do
+ expect { subject.save }
+ .to not_change(subject, :uri)
+ end
+ end
+
+ context 'when URI is blank' do
+ subject { Fabricate.build :follow, uri: nil }
+
+ it 'populates the value' do
+ expect { subject.save }
+ .to change(subject, :uri).to(be_present)
+ end
+ end
+ end
+ end
+
it 'removes blocking cache after creation' do
account = Fabricate(:account)
target_account = Fabricate(:account)
diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb
index 736f3615d0..66f521ab3f 100644
--- a/spec/models/poll_spec.rb
+++ b/spec/models/poll_spec.rb
@@ -3,7 +3,7 @@
require 'rails_helper'
RSpec.describe Poll do
- describe 'scopes' do
+ describe 'Scopes' do
let(:status) { Fabricate(:status) }
let(:attached_poll) { Fabricate(:poll, status: status) }
let(:not_attached_poll) do
@@ -13,7 +13,7 @@ RSpec.describe Poll do
end
end
- describe 'attached' do
+ describe '.attached' do
it 'finds the correct records' do
results = described_class.attached
@@ -21,7 +21,7 @@ RSpec.describe Poll do
end
end
- describe 'unattached' do
+ describe '.unattached' do
it 'finds the correct records' do
results = described_class.unattached
@@ -30,11 +30,23 @@ RSpec.describe Poll do
end
end
- describe 'validations' do
- context 'when not valid' do
- subject { Fabricate.build(:poll) }
+ describe '#reset_votes!' do
+ let(:poll) { Fabricate :poll, cached_tallies: [2, 3], votes_count: 5, voters_count: 5 }
+ let!(:vote) { Fabricate :poll_vote, poll: }
- it { is_expected.to validate_presence_of(:expires_at) }
+ it 'resets vote data and deletes votes' do
+ expect { poll.reset_votes! }
+ .to change(poll, :cached_tallies).to([0, 0])
+ .and change(poll, :votes_count).to(0)
+ .and(change(poll, :voters_count).to(0))
+ expect { vote.reload }
+ .to raise_error(ActiveRecord::RecordNotFound)
end
end
+
+ describe 'Validations' do
+ subject { Fabricate.build(:poll) }
+
+ it { is_expected.to validate_presence_of(:expires_at) }
+ end
end
diff --git a/spec/models/public_feed_spec.rb b/spec/models/public_feed_spec.rb
index 8a1a01e892..5f2444dc6b 100644
--- a/spec/models/public_feed_spec.rb
+++ b/spec/models/public_feed_spec.rb
@@ -55,12 +55,10 @@ RSpec.describe PublicFeed do
context 'without a viewer' do
let(:viewer) { nil }
- it 'includes remote instances statuses' do
- expect(subject).to include(remote_status.id)
- end
-
- it 'includes local statuses' do
- expect(subject).to include(local_status.id)
+ it 'includes remote instances statuses and local statuses' do
+ expect(subject)
+ .to include(remote_status.id)
+ .and include(local_status.id)
end
it 'does not include local-only statuses' do
@@ -71,12 +69,10 @@ RSpec.describe PublicFeed do
context 'with a viewer' do
let(:viewer) { Fabricate(:account, username: 'viewer') }
- it 'includes remote instances statuses' do
- expect(subject).to include(remote_status.id)
- end
-
- it 'includes local statuses' do
- expect(subject).to include(local_status.id)
+ it 'includes remote instances statuses and local statuses' do
+ expect(subject)
+ .to include(remote_status.id)
+ .and include(local_status.id)
end
it 'does not include local-only statuses' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index d28e6658f1..4393be5a4e 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -387,23 +387,43 @@ RSpec.describe User do
end
end
- describe 'token_for_app' do
+ describe '#token_for_app' do
let(:user) { Fabricate(:user) }
- let(:app) { Fabricate(:application, owner: user) }
- it 'returns a token' do
- expect(user.token_for_app(app)).to be_a(Doorkeeper::AccessToken)
+ context 'when user owns app but does not have tokens' do
+ let(:app) { Fabricate(:application, owner: user) }
+
+ it 'creates and returns a persisted token' do
+ expect { user.token_for_app(app) }
+ .to change(Doorkeeper::AccessToken.where(resource_owner_id: user.id, application: app), :count).by(1)
+ end
end
- it 'persists a token' do
- t = user.token_for_app(app)
- expect(user.token_for_app(app)).to eql(t)
+ context 'when user owns app and already has tokens' do
+ let(:app) { Fabricate(:application, owner: user) }
+ let!(:token) { Fabricate :access_token, application: app, resource_owner_id: user.id }
+
+ it 'returns a persisted token' do
+ expect(user.token_for_app(app))
+ .to be_a(Doorkeeper::AccessToken)
+ .and eq(token)
+ end
end
- it 'is nil if user does not own app' do
- app.update!(owner: nil)
+ context 'when user does not own app' do
+ let(:app) { Fabricate(:application) }
- expect(user.token_for_app(app)).to be_nil
+ it 'returns nil' do
+ expect(user.token_for_app(app))
+ .to be_nil
+ end
+ end
+
+ context 'when app is nil' do
+ it 'returns nil' do
+ expect(user.token_for_app(nil))
+ .to be_nil
+ end
end
end
diff --git a/spec/policies/account_moderation_note_policy_spec.rb b/spec/policies/account_moderation_note_policy_spec.rb
index 8c37acc39f..8b33a71012 100644
--- a/spec/policies/account_moderation_note_policy_spec.rb
+++ b/spec/policies/account_moderation_note_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe AccountModerationNotePolicy do
subject { described_class }
@@ -12,13 +11,13 @@ RSpec.describe AccountModerationNotePolicy do
permissions :create? do
context 'when staff' do
it 'grants to create' do
- expect(subject).to permit(admin, described_class)
+ expect(subject).to permit(admin, AccountModerationNote)
end
end
context 'when not staff' do
it 'denies to create' do
- expect(subject).to_not permit(john, described_class)
+ expect(subject).to_not permit(john, AccountModerationNote)
end
end
end
diff --git a/spec/policies/account_policy_spec.rb b/spec/policies/account_policy_spec.rb
index d7a21d8e39..75724e831b 100644
--- a/spec/policies/account_policy_spec.rb
+++ b/spec/policies/account_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe AccountPolicy do
subject { described_class }
@@ -24,7 +23,7 @@ RSpec.describe AccountPolicy do
end
end
- permissions :show?, :unsilence?, :unsensitive?, :remove_avatar?, :remove_header? do
+ permissions :show?, :unsilence?, :unsensitive?, :remove_avatar?, :remove_header?, :sensitive?, :warn? do
context 'when staff' do
it 'permits' do
expect(subject).to permit(admin, alice)
diff --git a/spec/policies/account_warning_policy_spec.rb b/spec/policies/account_warning_policy_spec.rb
new file mode 100644
index 0000000000..9abc9d35d6
--- /dev/null
+++ b/spec/policies/account_warning_policy_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe AccountWarningPolicy do
+ subject { described_class }
+
+ let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
+ let(:account) { Fabricate(:account) }
+
+ permissions :show? do
+ context 'with an admin' do
+ it { is_expected.to permit(admin, AccountWarning.new) }
+ end
+
+ context 'with a non-admin' do
+ context 'when account is not target' do
+ it { is_expected.to_not permit(account, AccountWarning.new) }
+ end
+
+ context 'when account is target' do
+ it { is_expected.to permit(account, AccountWarning.new(target_account_id: account.id)) }
+ end
+ end
+ end
+
+ permissions :appeal? do
+ context 'when account is not target' do
+ it { is_expected.to_not permit(account, AccountWarning.new) }
+ end
+
+ context 'when account is target' do
+ context 'when record is appealable' do
+ it { is_expected.to permit(account, AccountWarning.new(target_account_id: account.id, created_at: Appeal::MAX_STRIKE_AGE.ago + 1.hour)) }
+ end
+
+ context 'when record is not appealable' do
+ it { is_expected.to_not permit(account, AccountWarning.new(target_account_id: account.id, created_at: Appeal::MAX_STRIKE_AGE.ago - 1.hour)) }
+ end
+ end
+ end
+end
diff --git a/spec/policies/account_warning_preset_policy_spec.rb b/spec/policies/account_warning_preset_policy_spec.rb
index 53e224f19f..33f2fb1187 100644
--- a/spec/policies/account_warning_preset_policy_spec.rb
+++ b/spec/policies/account_warning_preset_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe AccountWarningPresetPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe AccountWarningPresetPolicy do
permissions :index?, :create?, :update?, :destroy? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, AccountWarningPreset)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, AccountWarningPreset)
end
end
end
diff --git a/spec/policies/admin/status_policy_spec.rb b/spec/policies/admin/status_policy_spec.rb
index 07af425516..4df29393e3 100644
--- a/spec/policies/admin/status_policy_spec.rb
+++ b/spec/policies/admin/status_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe Admin::StatusPolicy do
let(:policy) { described_class }
@@ -13,13 +12,13 @@ RSpec.describe Admin::StatusPolicy do
permissions :index?, :update?, :review?, :destroy? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, Status)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, Status)
end
end
end
diff --git a/spec/policies/announcement_policy_spec.rb b/spec/policies/announcement_policy_spec.rb
index 503ffca6dc..ab0c1dbaf5 100644
--- a/spec/policies/announcement_policy_spec.rb
+++ b/spec/policies/announcement_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe AnnouncementPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe AnnouncementPolicy do
permissions :index?, :create?, :update?, :destroy? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, Announcement)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, Announcement)
end
end
end
diff --git a/spec/policies/appeal_policy_spec.rb b/spec/policies/appeal_policy_spec.rb
index 1bf8ce0a0d..cdb93bf56c 100644
--- a/spec/policies/appeal_policy_spec.rb
+++ b/spec/policies/appeal_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe AppealPolicy do
let(:policy) { described_class }
@@ -12,18 +11,18 @@ RSpec.describe AppealPolicy do
permissions :index? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, Appeal)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, Appeal)
end
end
end
- permissions :reject? do
+ permissions :reject?, :approve? do
context 'with an admin' do
context 'with a pending appeal' do
before { allow(appeal).to receive(:pending?).and_return(true) }
diff --git a/spec/policies/audit_log_policy_spec.rb b/spec/policies/audit_log_policy_spec.rb
new file mode 100644
index 0000000000..d9d9359433
--- /dev/null
+++ b/spec/policies/audit_log_policy_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe AuditLogPolicy do
+ subject { described_class }
+
+ let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
+ let(:account) { Fabricate(:account) }
+
+ permissions :index? do
+ context 'with an admin' do
+ it { is_expected.to permit(admin, nil) }
+ end
+
+ context 'with a non-admin' do
+ it { is_expected.to_not permit(account, nil) }
+ end
+ end
+end
diff --git a/spec/policies/backup_policy_spec.rb b/spec/policies/backup_policy_spec.rb
index 28cb65d789..031021d91d 100644
--- a/spec/policies/backup_policy_spec.rb
+++ b/spec/policies/backup_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe BackupPolicy do
subject { described_class }
diff --git a/spec/policies/canonical_email_block_policy_spec.rb b/spec/policies/canonical_email_block_policy_spec.rb
index f5029d9e6b..b253b439a6 100644
--- a/spec/policies/canonical_email_block_policy_spec.rb
+++ b/spec/policies/canonical_email_block_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe CanonicalEmailBlockPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe CanonicalEmailBlockPolicy do
permissions :index?, :show?, :test?, :create?, :destroy? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, CanonicalEmailBlock)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, CanonicalEmailBlock)
end
end
end
diff --git a/spec/policies/custom_emoji_policy_spec.rb b/spec/policies/custom_emoji_policy_spec.rb
index cb869c7d9a..189885938c 100644
--- a/spec/policies/custom_emoji_policy_spec.rb
+++ b/spec/policies/custom_emoji_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe CustomEmojiPolicy do
subject { described_class }
diff --git a/spec/policies/dashboard_policy_spec.rb b/spec/policies/dashboard_policy_spec.rb
new file mode 100644
index 0000000000..90c71db381
--- /dev/null
+++ b/spec/policies/dashboard_policy_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe DashboardPolicy do
+ subject { described_class }
+
+ let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
+ let(:account) { Fabricate(:account) }
+
+ permissions :index? do
+ context 'with an admin' do
+ it { is_expected.to permit(admin, nil) }
+ end
+
+ context 'with a non-admin' do
+ it { is_expected.to_not permit(account, nil) }
+ end
+ end
+end
diff --git a/spec/policies/delivery_policy_spec.rb b/spec/policies/delivery_policy_spec.rb
index bb82389eec..8bc200159a 100644
--- a/spec/policies/delivery_policy_spec.rb
+++ b/spec/policies/delivery_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe DeliveryPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe DeliveryPolicy do
permissions :clear_delivery_errors?, :restart_delivery?, :stop_delivery? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, nil)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, nil)
end
end
end
diff --git a/spec/policies/domain_allow_policy_spec.rb b/spec/policies/domain_allow_policy_spec.rb
new file mode 100644
index 0000000000..1d285065b8
--- /dev/null
+++ b/spec/policies/domain_allow_policy_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe DomainAllowPolicy do
+ subject { described_class }
+
+ let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
+ let(:john) { Fabricate(:account) }
+
+ permissions :index?, :show?, :create?, :destroy? do
+ context 'when admin' do
+ it 'permits' do
+ expect(subject).to permit(admin, DomainAllow)
+ end
+ end
+
+ context 'when not admin' do
+ it 'denies' do
+ expect(subject).to_not permit(john, DomainAllow)
+ end
+ end
+ end
+end
diff --git a/spec/policies/domain_block_policy_spec.rb b/spec/policies/domain_block_policy_spec.rb
index 4c89f3f374..7c77d1870d 100644
--- a/spec/policies/domain_block_policy_spec.rb
+++ b/spec/policies/domain_block_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe DomainBlockPolicy do
subject { described_class }
@@ -9,7 +8,7 @@ RSpec.describe DomainBlockPolicy do
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
let(:john) { Fabricate(:account) }
- permissions :index?, :show?, :create?, :destroy? do
+ permissions :index?, :show?, :create?, :destroy?, :update? do
context 'when admin' do
it 'permits' do
expect(subject).to permit(admin, DomainBlock)
diff --git a/spec/policies/email_domain_block_policy_spec.rb b/spec/policies/email_domain_block_policy_spec.rb
index 7ecff4be49..e98d65a3c7 100644
--- a/spec/policies/email_domain_block_policy_spec.rb
+++ b/spec/policies/email_domain_block_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe EmailDomainBlockPolicy do
subject { described_class }
diff --git a/spec/policies/follow_recommendation_policy_spec.rb b/spec/policies/follow_recommendation_policy_spec.rb
index ae74d5c3a8..665ed9b059 100644
--- a/spec/policies/follow_recommendation_policy_spec.rb
+++ b/spec/policies/follow_recommendation_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe FollowRecommendationPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe FollowRecommendationPolicy do
permissions :show?, :suppress?, :unsuppress? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, FollowRecommendation)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, FollowRecommendation)
end
end
end
diff --git a/spec/policies/instance_policy_spec.rb b/spec/policies/instance_policy_spec.rb
index a0d9a008b7..6cdc738022 100644
--- a/spec/policies/instance_policy_spec.rb
+++ b/spec/policies/instance_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe InstancePolicy do
subject { described_class }
diff --git a/spec/policies/invite_policy_spec.rb b/spec/policies/invite_policy_spec.rb
index cbe3735d80..3717a44999 100644
--- a/spec/policies/invite_policy_spec.rb
+++ b/spec/policies/invite_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe InvitePolicy do
subject { described_class }
diff --git a/spec/policies/ip_block_policy_spec.rb b/spec/policies/ip_block_policy_spec.rb
index 97bc239e9a..33ea342c10 100644
--- a/spec/policies/ip_block_policy_spec.rb
+++ b/spec/policies/ip_block_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe IpBlockPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe IpBlockPolicy do
permissions :index?, :show?, :create?, :update?, :destroy? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, IpBlock)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, IpBlock)
end
end
end
diff --git a/spec/policies/poll_policy_spec.rb b/spec/policies/poll_policy_spec.rb
new file mode 100644
index 0000000000..aa1701cb06
--- /dev/null
+++ b/spec/policies/poll_policy_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe PollPolicy do
+ subject { described_class }
+
+ let(:account) { Fabricate(:account) }
+ let(:poll) { Fabricate :poll }
+
+ permissions :vote? do
+ context 'when account cannot view status' do
+ before { poll.status.update(visibility: :private) }
+
+ it { is_expected.to_not permit(account, poll) }
+ end
+
+ context 'when account can view status' do
+ context 'when accounts do not block each other' do
+ it { is_expected.to permit(account, poll) }
+ end
+
+ context 'when view blocks poll creator' do
+ before { Fabricate :block, account: account, target_account: poll.account }
+
+ it { is_expected.to_not permit(account, poll) }
+ end
+
+ context 'when poll creator blocks viewer' do
+ before { Fabricate :block, account: poll.account, target_account: account }
+
+ it { is_expected.to_not permit(account, poll) }
+ end
+ end
+ end
+end
diff --git a/spec/policies/preview_card_policy_spec.rb b/spec/policies/preview_card_policy_spec.rb
index a1944303e1..d02a6016cd 100644
--- a/spec/policies/preview_card_policy_spec.rb
+++ b/spec/policies/preview_card_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe PreviewCardPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe PreviewCardPolicy do
permissions :index?, :review? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, PreviewCard)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, PreviewCard)
end
end
end
diff --git a/spec/policies/preview_card_provider_policy_spec.rb b/spec/policies/preview_card_provider_policy_spec.rb
index 676039a1b7..5e25b364a4 100644
--- a/spec/policies/preview_card_provider_policy_spec.rb
+++ b/spec/policies/preview_card_provider_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe PreviewCardProviderPolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe PreviewCardProviderPolicy do
permissions :index?, :review? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, PreviewCardProvider)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, PreviewCardProvider)
end
end
end
diff --git a/spec/policies/relay_policy_spec.rb b/spec/policies/relay_policy_spec.rb
index 29ba02c26a..5983b2d2ff 100644
--- a/spec/policies/relay_policy_spec.rb
+++ b/spec/policies/relay_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe RelayPolicy do
subject { described_class }
diff --git a/spec/policies/report_note_policy_spec.rb b/spec/policies/report_note_policy_spec.rb
index b40a878887..02317f763a 100644
--- a/spec/policies/report_note_policy_spec.rb
+++ b/spec/policies/report_note_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe ReportNotePolicy do
subject { described_class }
diff --git a/spec/policies/report_policy_spec.rb b/spec/policies/report_policy_spec.rb
index 4fc4178075..67f40b5188 100644
--- a/spec/policies/report_policy_spec.rb
+++ b/spec/policies/report_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe ReportPolicy do
subject { described_class }
diff --git a/spec/policies/rule_policy_spec.rb b/spec/policies/rule_policy_spec.rb
index 5d435e38c1..3086f30446 100644
--- a/spec/policies/rule_policy_spec.rb
+++ b/spec/policies/rule_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe RulePolicy do
let(:policy) { described_class }
@@ -11,13 +10,13 @@ RSpec.describe RulePolicy do
permissions :index?, :create?, :update?, :destroy? do
context 'with an admin' do
it 'permits' do
- expect(policy).to permit(admin, Tag)
+ expect(policy).to permit(admin, Rule)
end
end
context 'with a non-admin' do
it 'denies' do
- expect(policy).to_not permit(john, Tag)
+ expect(policy).to_not permit(john, Rule)
end
end
end
diff --git a/spec/policies/settings_policy_spec.rb b/spec/policies/settings_policy_spec.rb
index 4a99314905..48821c706a 100644
--- a/spec/policies/settings_policy_spec.rb
+++ b/spec/policies/settings_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe SettingsPolicy do
subject { described_class }
diff --git a/spec/policies/software_update_policy_spec.rb b/spec/policies/software_update_policy_spec.rb
index e19ba61612..2bda84cce9 100644
--- a/spec/policies/software_update_policy_spec.rb
+++ b/spec/policies/software_update_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe SoftwareUpdatePolicy do
subject { described_class }
diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb
index 725bd0bbb3..eb2af75d92 100644
--- a/spec/policies/status_policy_spec.rb
+++ b/spec/policies/status_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe StatusPolicy, type: :model do
subject { described_class }
diff --git a/spec/policies/tag_policy_spec.rb b/spec/policies/tag_policy_spec.rb
index 35da3cc62a..23166e4669 100644
--- a/spec/policies/tag_policy_spec.rb
+++ b/spec/policies/tag_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe TagPolicy do
subject { described_class }
diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb
index 7854547d26..11a166a24e 100644
--- a/spec/policies/user_policy_spec.rb
+++ b/spec/policies/user_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe UserPolicy do
subject { described_class }
@@ -112,4 +111,42 @@ RSpec.describe UserPolicy do
end
end
end
+
+ permissions :approve?, :reject? do
+ context 'when admin' do
+ context 'when user is approved' do
+ it { is_expected.to_not permit(admin, User.new(approved: true)) }
+ end
+
+ context 'when user is not approved' do
+ it { is_expected.to permit(admin, User.new(approved: false)) }
+ end
+ end
+
+ context 'when not admin' do
+ it { is_expected.to_not permit(john, User.new) }
+ end
+ end
+
+ permissions :change_role? do
+ context 'when not admin' do
+ it { is_expected.to_not permit(john, User.new) }
+ end
+
+ context 'when admin' do
+ let(:user) { User.new(role: role) }
+
+ context 'when role of admin overrides user role' do
+ let(:role) { UserRole.new(position: admin.user.role.position - 10, id: 123) }
+
+ it { is_expected.to permit(admin, user) }
+ end
+
+ context 'when role of admin does not override user role' do
+ let(:role) { UserRole.new(position: admin.user.role.position + 10, id: 123) }
+
+ it { is_expected.to_not permit(admin, user) }
+ end
+ end
+ end
end
diff --git a/spec/policies/user_role_policy_spec.rb b/spec/policies/user_role_policy_spec.rb
new file mode 100644
index 0000000000..c48b345d68
--- /dev/null
+++ b/spec/policies/user_role_policy_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe UserRolePolicy do
+ subject { described_class }
+
+ let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
+ let(:account) { Fabricate(:account) }
+
+ permissions :index?, :create? do
+ context 'when admin' do
+ it { is_expected.to permit(admin, UserRole.new) }
+ end
+
+ context 'when not admin' do
+ it { is_expected.to_not permit(account, UserRole.new) }
+ end
+ end
+
+ permissions :update? do
+ context 'when admin' do
+ context 'when role of admin overrides relevant role' do
+ it { is_expected.to permit(admin, UserRole.new(position: admin.user.role.position - 10, id: 123)) }
+ end
+
+ context 'when role of admin does not override relevant role' do
+ it { is_expected.to_not permit(admin, UserRole.new(position: admin.user.role.position + 10, id: 123)) }
+ end
+ end
+
+ context 'when not admin' do
+ it { is_expected.to_not permit(account, UserRole.new) }
+ end
+ end
+
+ permissions :destroy? do
+ context 'when admin' do
+ context 'when role of admin overrides relevant role' do
+ it { is_expected.to permit(admin, UserRole.new(position: admin.user.role.position - 10)) }
+ end
+
+ context 'when role of admin does not override relevant role' do
+ it { is_expected.to_not permit(admin, UserRole.new(position: admin.user.role.position + 10)) }
+ end
+
+ context 'when everyone role' do
+ it { is_expected.to_not permit(admin, UserRole.everyone) }
+ end
+ end
+
+ context 'when not admin' do
+ it { is_expected.to_not permit(account, UserRole.new) }
+ end
+ end
+end
diff --git a/spec/policies/webhook_policy_spec.rb b/spec/policies/webhook_policy_spec.rb
index 96aaae2c30..9899235d83 100644
--- a/spec/policies/webhook_policy_spec.rb
+++ b/spec/policies/webhook_policy_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rails_helper'
-require 'pundit/rspec'
RSpec.describe WebhookPolicy do
let(:policy) { described_class }
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 84cee0974f..91a2e21bbb 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -43,6 +43,7 @@ require 'paperclip/matchers'
require 'capybara/rspec'
require 'chewy/rspec'
require 'email_spec/rspec'
+require 'pundit/rspec'
require 'test_prof/recipes/rspec/before_all'
Rails.root.glob('spec/support/**/*.rb').each { |f| require f }
diff --git a/spec/requests/statuses/embed_spec.rb b/spec/requests/statuses/embed_spec.rb
new file mode 100644
index 0000000000..33c7ea192c
--- /dev/null
+++ b/spec/requests/statuses/embed_spec.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Status embed' do
+ describe 'GET /users/:account_username/statuses/:id/embed' do
+ subject { get "/users/#{account.username}/statuses/#{status.id}/embed" }
+
+ let(:account) { Fabricate(:account) }
+ let(:status) { Fabricate(:status, account: account) }
+
+ context 'when account is suspended' do
+ let(:account) { Fabricate(:account, suspended: true) }
+
+ it 'returns http gone' do
+ subject
+
+ expect(response)
+ .to have_http_status(410)
+ end
+ end
+
+ context 'when status is a reblog' do
+ let(:original_account) { Fabricate(:account, domain: 'example.com') }
+ let(:original_status) { Fabricate(:status, account: original_account, url: 'https://example.com/123') }
+ let(:status) { Fabricate(:status, account: account, reblog: original_status) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response)
+ .to have_http_status(404)
+ end
+ end
+
+ context 'when status is public' do
+ it 'renders status successfully', :aggregate_failures do
+ subject
+
+ expect(response)
+ .to have_http_status(200)
+ expect(response.parsed_body.at('body.embed'))
+ .to be_present
+ expect(response.headers).to include(
+ 'Vary' => 'Accept, Accept-Language, Cookie',
+ 'Cache-Control' => include('public'),
+ 'Link' => include('activity+json')
+ )
+ end
+ end
+
+ context 'when status is private' do
+ let(:status) { Fabricate(:status, account: account, visibility: :private) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response)
+ .to have_http_status(404)
+ end
+ end
+
+ context 'when status is direct' do
+ let(:status) { Fabricate(:status, account: account, visibility: :direct) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response)
+ .to have_http_status(404)
+ end
+ end
+ end
+end
diff --git a/spec/serializers/activitypub/note_serializer_spec.rb b/spec/serializers/activitypub/note_serializer_spec.rb
index 285b241ee2..a6976193b2 100644
--- a/spec/serializers/activitypub/note_serializer_spec.rb
+++ b/spec/serializers/activitypub/note_serializer_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe ActivityPub::NoteSerializer do
let!(:reply_by_account_third) { Fabricate(:status, account: account, thread: parent, visibility: :public) }
let!(:reply_by_account_visibility_direct) { Fabricate(:status, account: account, thread: parent, visibility: :direct) }
- it 'has the expected shape' do
+ it 'has the expected shape and replies collection' do
expect(subject).to include({
'@context' => include('https://www.w3.org/ns/activitystreams'),
'type' => 'Note',
@@ -22,26 +22,23 @@ RSpec.describe ActivityPub::NoteSerializer do
'contentMap' => include({
'zh-TW' => a_kind_of(String),
}),
+ 'replies' => replies_collection_values,
})
end
- it 'has a replies collection' do
- expect(subject['replies']['type']).to eql('Collection')
+ def replies_collection_values
+ include(
+ 'type' => eql('Collection'),
+ 'first' => include(
+ 'type' => eql('CollectionPage'),
+ 'items' => reply_items
+ )
+ )
end
- it 'has a replies collection with a first Page' do
- expect(subject['replies']['first']['type']).to eql('CollectionPage')
- end
-
- it 'includes public self-replies in its replies collection' do
- expect(subject['replies']['first']['items']).to include(reply_by_account_first.uri, reply_by_account_next.uri, reply_by_account_third.uri)
- end
-
- it 'does not include replies from others in its replies collection' do
- expect(subject['replies']['first']['items']).to_not include(reply_by_other_first.uri)
- end
-
- it 'does not include replies with direct visibility in its replies collection' do
- expect(subject['replies']['first']['items']).to_not include(reply_by_account_visibility_direct.uri)
+ def reply_items
+ include(reply_by_account_first.uri, reply_by_account_next.uri, reply_by_account_third.uri) # Public self replies
+ .and(not_include(reply_by_other_first.uri)) # Replies from others
+ .and(not_include(reply_by_account_visibility_direct.uri)) # Replies with direct visibility
end
end
diff --git a/spec/services/translate_status_service_spec.rb b/spec/services/translate_status_service_spec.rb
index cd92fb8d10..ac7a43ff2a 100644
--- a/spec/services/translate_status_service_spec.rb
+++ b/spec/services/translate_status_service_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe TranslateStatusService do
describe '#call' do
before do
translation_service = TranslationService.new
- allow(translation_service).to receive(:languages).and_return({ 'en' => ['es'] })
+ allow(translation_service).to receive(:languages).and_return({ 'en' => ['es', 'es-MX'] })
allow(translation_service).to receive(:translate) do |texts|
texts.map do |text|
TranslationService::Translation.new(
@@ -37,6 +37,7 @@ RSpec.describe TranslateStatusService do
.to have_attributes(
content: '
Hola
',
detected_source_language: 'en',
+ language: 'es',
provider: 'Dummy',
status: status
)
@@ -101,6 +102,16 @@ RSpec.describe TranslateStatusService do
expect(media_attachment.description).to eq 'Hola & :highfive:'
end
end
+
+ describe 'target language is regional' do
+ it 'uses regional variant' do
+ expect(service.call(status, 'es-MX').language).to eq 'es-MX'
+ end
+
+ it 'uses parent locale for unsupported regional variant' do
+ expect(service.call(status, 'es-XX').language).to eq 'es'
+ end
+ end
end
describe '#source_texts' do
diff --git a/spec/system/admin/invites_spec.rb b/spec/system/admin/invites_spec.rb
new file mode 100644
index 0000000000..f2cee626c6
--- /dev/null
+++ b/spec/system/admin/invites_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Admin Invites' do
+ describe 'Invite interaction' do
+ let!(:invite) { Fabricate(:invite, expires_at: nil) }
+
+ let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ before { sign_in user }
+
+ it 'allows invite listing and creation' do
+ visit admin_invites_path
+
+ expect(page)
+ .to have_title(I18n.t('admin.invites.title'))
+ for_invite(invite) do
+ expect(find('input').value)
+ .to include(invite.code)
+ end
+
+ select I18n.t('invites.max_uses', count: 10), from: max_use_field
+
+ expect { generate_invite }
+ .to change(Invite, :count).by(1)
+ expect(user.invites.last)
+ .to have_attributes(max_uses: 10)
+ end
+
+ it 'allows invite expiration' do
+ visit admin_invites_path
+
+ for_invite(invite) do
+ expect { expire_invite }
+ .to change { invite.reload.expired? }.from(false).to(true)
+ end
+ end
+
+ it 'allows invite deactivation' do
+ visit admin_invites_path
+
+ expect { click_on I18n.t('admin.invites.deactivate_all') }
+ .to change { Invite.exists?(expires_at: nil) }.from(true).to(false)
+ end
+
+ def for_invite(invite, &block)
+ within("#invite_#{invite.id}", &block)
+ end
+
+ def expire_invite
+ click_on I18n.t('invites.delete')
+ end
+
+ def generate_invite
+ click_on I18n.t('invites.generate')
+ end
+
+ def max_use_field
+ I18n.t('simple_form.labels.defaults.max_uses')
+ end
+ end
+end
diff --git a/spec/system/admin/tags_spec.rb b/spec/system/admin/tags_spec.rb
new file mode 100644
index 0000000000..a3eca80d13
--- /dev/null
+++ b/spec/system/admin/tags_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe 'Admin Tags' do
+ describe 'Tag interaction' do
+ let!(:tag) { Fabricate(:tag, name: 'test') }
+
+ before { sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
+
+ it 'allows tags listing and editing' do
+ visit admin_tags_path
+
+ expect(page)
+ .to have_title(I18n.t('admin.tags.title'))
+
+ click_on '#test'
+
+ fill_in display_name_field, with: 'NewTagName'
+ expect { click_on submit_button }
+ .to_not(change { tag.reload.display_name })
+ expect(page)
+ .to have_content(match_error_text)
+
+ fill_in display_name_field, with: 'TEST'
+ expect { click_on submit_button }
+ .to(change { tag.reload.display_name }.to('TEST'))
+ end
+
+ def display_name_field
+ I18n.t('simple_form.labels.defaults.display_name')
+ end
+
+ def match_error_text
+ I18n.t('tags.does_not_match_previous_name')
+ end
+ end
+end
diff --git a/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb b/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb
index 7071fa6e98..98150aa5ef 100644
--- a/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb
+++ b/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb
@@ -5,9 +5,50 @@ require 'rails_helper'
RSpec.describe Scheduler::IpCleanupScheduler do
let(:worker) { described_class.new }
- describe 'perform' do
- it 'runs without error' do
- expect { worker.perform }.to_not raise_error
+ describe '#perform' do
+ context 'with IP-related data past retention times' do
+ let!(:future_ip_block) { Fabricate :ip_block, expires_at: 1.week.from_now }
+ let!(:old_ip_block) { Fabricate :ip_block, expires_at: 1.week.ago }
+ let!(:session_past_retention) { Fabricate :session_activation, ip: '10.0.0.0', updated_at: 18.months.ago }
+ let!(:inactive_user) { Fabricate :user, current_sign_in_at: 18.months.ago, sign_up_ip: '10.0.0.0' }
+ let!(:old_login_activity) { Fabricate :login_activity, created_at: 18.months.ago }
+ let!(:old_token) { Fabricate :access_token, last_used_at: 18.months.ago, last_used_ip: '10.0.0.0' }
+
+ before { stub_const 'Scheduler::IpCleanupScheduler::SESSION_RETENTION_PERIOD', 10.years.to_i.seconds }
+
+ it 'deletes the expired block' do
+ expect { worker.perform }
+ .to_not raise_error
+ expect { old_ip_block.reload }
+ .to raise_error(ActiveRecord::RecordNotFound)
+ expect { old_login_activity.reload }
+ .to raise_error(ActiveRecord::RecordNotFound)
+ expect(session_past_retention.reload.ip)
+ .to be_nil
+ expect(inactive_user.reload.sign_up_ip)
+ .to be_nil
+ expect(old_token.reload.last_used_ip)
+ .to be_nil
+ expect(future_ip_block.reload)
+ .to be_present
+ end
+ end
+
+ context 'with old session data' do
+ let!(:new_activation) { Fabricate :session_activation, updated_at: 1.week.ago }
+ let!(:old_activation) { Fabricate :session_activation, updated_at: 1.month.ago }
+
+ before { stub_const 'Scheduler::IpCleanupScheduler::SESSION_RETENTION_PERIOD', 10.days.to_i.seconds }
+
+ it 'clears old sessions' do
+ expect { worker.perform }
+ .to_not raise_error
+
+ expect { old_activation.reload }
+ .to raise_error(ActiveRecord::RecordNotFound)
+ expect(new_activation.reload)
+ .to be_present
+ end
end
end
end
diff --git a/streaming/redis.js b/streaming/redis.js
index 2a36b89dc5..0b582ef2f5 100644
--- a/streaming/redis.js
+++ b/streaming/redis.js
@@ -50,9 +50,9 @@ function getSentinelConfiguration(env, commonOptions) {
return {
db: redisDatabase,
name: env.REDIS_SENTINEL_MASTER,
- username: env.REDIS_USERNAME,
+ username: env.REDIS_USER,
password: env.REDIS_PASSWORD,
- sentinelUsername: env.REDIS_SENTINEL_USERNAME ?? env.REDIS_USERNAME,
+ sentinelUsername: env.REDIS_SENTINEL_USERNAME ?? env.REDIS_USER,
sentinelPassword: env.REDIS_SENTINEL_PASSWORD ?? env.REDIS_PASSWORD,
sentinels,
...commonOptions,
@@ -104,7 +104,7 @@ export function configFromEnv(env) {
host: env.REDIS_HOST ?? '127.0.0.1',
port: redisPort,
db: redisDatabase,
- username: env.REDIS_USERNAME,
+ username: env.REDIS_USER,
password: env.REDIS_PASSWORD,
...commonOptions,
};