Compare commits

...

8 Commits

Author SHA1 Message Date
Eashwar Ranganathan
36d23c7f18
Merge a17146b980 into 199376a080 2025-11-27 10:57:47 +01:00
Matt Jankowski
199376a080
Use existing time format string to generate backup archive filename (#36469)
Some checks are pending
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
Haml Linting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
2025-11-27 09:38:27 +00:00
diondiondion
e126cfc76d
Fix error page when logging out or boosting on mobile (#37028) 2025-11-27 09:36:58 +00:00
David Roetzel
322a4fee53
First steps towards a collection creation service (#37020)
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
2025-11-27 09:36:44 +00:00
renovate[bot]
be2caba527
chore(deps): update dependency i18n-tasks to v1.1.2 (#37027)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 09:29:14 +00:00
Eashwar Ranganathan
a17146b980
Negate the matcher 2025-08-03 01:53:03 -07:00
Eashwar Ranganathan
57d647ac2d
Restore parents scope 2025-08-03 01:53:00 -07:00
Eashwar Ranganathan
d9d7f7df82
Make tootctl aware of new 'require approval' for email domains 2025-08-03 01:52:57 -07:00
9 changed files with 199 additions and 11 deletions

View File

@ -538,7 +538,7 @@ and provided thanks to the work of the following contributors:
* [Drew Schuster](mailto:dtschust@gmail.com) * [Drew Schuster](mailto:dtschust@gmail.com)
* [Dryusdan](mailto:dryusdan@dryusdan.fr) * [Dryusdan](mailto:dryusdan@dryusdan.fr)
* [Eai](mailto:eai@mizle.net) * [Eai](mailto:eai@mizle.net)
* [Eashwar Ranganathan](mailto:eranganathan@lyft.com) * [Eashwar Ranganathan](mailto:eashwar@eashwar.com)
* [Ed Knutson](mailto:knutsoned@gmail.com) * [Ed Knutson](mailto:knutsoned@gmail.com)
* [Elizabeth Martín Campos](mailto:me@elizabeth.sh) * [Elizabeth Martín Campos](mailto:me@elizabeth.sh)
* [Elizabeth Myers](mailto:elizabeth@interlinked.me) * [Elizabeth Myers](mailto:elizabeth@interlinked.me)

View File

@ -324,7 +324,7 @@ GEM
rainbow (>= 2.0.0) rainbow (>= 2.0.0)
i18n (1.14.7) i18n (1.14.7)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n-tasks (1.1.1) i18n-tasks (1.1.2)
activesupport (>= 4.0.2) activesupport (>= 4.0.2)
ast (>= 2.1.0) ast (>= 2.1.0)
erubi erubi

View File

@ -136,7 +136,7 @@ export default class ModalRoot extends PureComponent {
<Base backgroundColor={backgroundColor} onClose={this.handleClose} ignoreFocus={ignoreFocus}> <Base backgroundColor={backgroundColor} onClose={this.handleClose} ignoreFocus={ignoreFocus}>
{visible && ( {visible && (
<> <>
<BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading} error={this.renderError} renderDelay={200}> <BundleContainer key={type} fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading} error={this.renderError} renderDelay={200}>
{(SpecificComponent) => { {(SpecificComponent) => {
return <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={this.setModalRef} />; return <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={this.setModalRef} />;
}} }}

View File

@ -63,7 +63,7 @@ class BackupService < BaseService
dump_actor!(zipfile) dump_actor!(zipfile)
end end
archive_filename = "#{['archive', Time.now.utc.strftime('%Y%m%d%H%M%S'), SecureRandom.hex(16)].join('-')}.zip" archive_filename = "#{['archive', Time.current.to_fs(:number), SecureRandom.hex(16)].join('-')}.zip"
@backup.dump = ActionDispatch::Http::UploadedFile.new(tempfile: tmp_file, filename: archive_filename) @backup.dump = ActionDispatch::Http::UploadedFile.new(tempfile: tmp_file, filename: archive_filename)
@backup.processed = true @backup.processed = true

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
class CreateCollectionService
def call(params, account)
tag = params.delete(:tag)
account_ids = params.delete(:account_ids)
@collection = Collection.new(params.merge({ account:, local: true, tag: find_or_create_tag(tag) }))
build_items(account_ids)
@collection.save!
@collection
end
private
def find_or_create_tag(name)
return nil if name.blank?
Tag.find_or_create_by_names(name).first
end
def build_items(account_ids)
return if account_ids.blank?
account_ids.each do |account_id|
account = Account.find(account_id)
# TODO: validate preferences
@collection.collection_items.build(account:)
end
end
end

View File

@ -5,9 +5,33 @@ require_relative 'base'
module Mastodon::CLI module Mastodon::CLI
class EmailDomainBlocks < Base class EmailDomainBlocks < Base
option :only_blocked, type: :boolean, defaut: false
option :only_with_approval, type: :boolean, default: false
desc 'list', 'List blocked e-mail domains' desc 'list', 'List blocked e-mail domains'
long_desc <<-LONG_DESC
By default this command lists all domains in the email domain block list
and their associated MX records (if included).
If the --only-blocked option is provided, this command will list only email
domains that are fully blocked from signup.
If the --only-with-approval option is provided, this command will list only
email domains that are allowed to be used but require manual approval.
The --only-blocked and --only-with-approval options are mutually exclusive.
LONG_DESC
def list def list
EmailDomainBlock.parents.find_each do |parent| fail_with_message 'Cannot specify both --only-blocked and --only-with-approval' if options[:only_blocked] && options[:only_with_approval]
base_query = EmailDomainBlock.parents
if options[:only_blocked]
base_query = base_query.where(allow_with_approval: false)
elsif options[:only_with_approval]
base_query = base_query.where(allow_with_approval: true)
end
base_query.find_each do |parent|
say(parent.domain.to_s, :white) say(parent.domain.to_s, :white)
shell.indent do shell.indent do
@ -19,6 +43,7 @@ module Mastodon::CLI
end end
option :with_dns_records, type: :boolean option :with_dns_records, type: :boolean
option :allow_with_approval, type: :boolean, defaut: false
desc 'add DOMAIN...', 'Block e-mail domain(s)' desc 'add DOMAIN...', 'Block e-mail domain(s)'
long_desc <<-LONG_DESC long_desc <<-LONG_DESC
Blocking an e-mail domain prevents users from signing up Blocking an e-mail domain prevents users from signing up
@ -30,6 +55,9 @@ module Mastodon::CLI
This can be helpful if you are blocking an e-mail server that has many This can be helpful if you are blocking an e-mail server that has many
different domains pointing to it as it allows you to essentially block different domains pointing to it as it allows you to essentially block
it at the root. it at the root.
When the --allow-with-approval option is set, the email domains provided will
have to be manually approved for signup.
LONG_DESC LONG_DESC
def add(*domains) def add(*domains)
fail_with_message 'No domain(s) given' if domains.empty? fail_with_message 'No domain(s) given' if domains.empty?
@ -47,19 +75,18 @@ module Mastodon::CLI
other_domains = [] other_domains = []
other_domains = DomainResource.new(domain).mx if options[:with_dns_records] other_domains = DomainResource.new(domain).mx if options[:with_dns_records]
email_domain_block = EmailDomainBlock.new(domain: domain, other_domains: other_domains) email_domain_block = EmailDomainBlock.new(domain: domain, other_domains: other_domains, allow_with_approval: options[:allow_with_approval])
email_domain_block.save! email_domain_block.save!
processed += 1 processed += 1
(email_domain_block.other_domains || []).uniq.each do |hostname| (email_domain_block.other_domains || []).uniq.each do |hostname|
another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block)
if EmailDomainBlock.exists?(domain: hostname) if EmailDomainBlock.exists?(domain: hostname)
say("#{hostname} is already blocked.", :yellow) say("#{hostname} is already blocked.", :yellow)
skipped += 1 skipped += 1
next next
end end
another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block, allow_with_approval: options[:allow_with_approval])
another_email_domain_block.save! another_email_domain_block.save!
processed += 1 processed += 1
end end

View File

@ -15,17 +15,62 @@ RSpec.describe Mastodon::CLI::EmailDomainBlocks do
describe '#list' do describe '#list' do
let(:action) { :list } let(:action) { :list }
context 'with both --only-blocked and --only-with-approval' do
let(:options) { { only_blocked: true, only_with_approval: true } }
it 'warns about usage and exits' do
expect { subject }
.to raise_error(Thor::Error, 'Cannot specify both --only-blocked and --only-with-approval')
end
end
context 'with email domain block records' do context 'with email domain block records' do
let!(:parent_block) { Fabricate(:email_domain_block) } let!(:parent_block) { Fabricate(:email_domain_block) }
let!(:child_block) { Fabricate(:email_domain_block, parent: parent_block) } let!(:child_block) { Fabricate(:email_domain_block, parent: parent_block) }
let!(:parent_allow_block) { Fabricate(:email_domain_block, allow_with_approval: true) }
let!(:child_allow_block) { Fabricate(:email_domain_block, parent: parent_allow_block, allow_with_approval: true) }
it 'lists the blocks' do it 'lists all the blocks by default' do
expect { subject } expect { subject }
.to output_results( .to output_results(
parent_block.domain, parent_block.domain,
child_block.domain child_block.domain,
parent_allow_block.domain,
child_allow_block.domain
) )
end end
context 'with the --only-blocked flag set' do
let(:options) { { only_blocked: true } }
it 'lists only blocked domains' do
expect { subject }
.to output_results(
parent_block.domain,
child_block.domain
)
.and not_output_results(
parent_allow_block.domain,
child_allow_block.domain
)
end
end
context 'with the --only-with-approval flag set' do
let(:options) { { only_with_approval: true } }
it 'lists only manually approvable domains' do
expect { subject }
.to output_results(
parent_allow_block.domain,
child_allow_block.domain
)
.and not_output_results(
parent_block.domain,
child_block.domain
)
end
end
end end
end end
@ -56,6 +101,7 @@ RSpec.describe Mastodon::CLI::EmailDomainBlocks do
context 'when no blocks exist' do context 'when no blocks exist' do
let(:domain) { 'host.example' } let(:domain) { 'host.example' }
let(:arguments) { [domain] } let(:arguments) { [domain] }
let(:options) { { allow_with_approval: false } }
it 'adds a new block' do it 'adds a new block' do
expect { subject } expect { subject }
@ -67,7 +113,7 @@ RSpec.describe Mastodon::CLI::EmailDomainBlocks do
context 'with --with-dns-records true' do context 'with --with-dns-records true' do
let(:domain) { 'host.example' } let(:domain) { 'host.example' }
let(:arguments) { [domain] } let(:arguments) { [domain] }
let(:options) { { with_dns_records: true } } let(:options) { { allow_with_approval: false, with_dns_records: true } }
before do before do
configure_mx(domain: domain, exchange: 'other.host') configure_mx(domain: domain, exchange: 'other.host')

View File

@ -0,0 +1,82 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe CreateCollectionService do
subject { described_class.new }
let(:author) { Fabricate.create(:account) }
describe '#call' do
let(:base_params) do
{
name: 'People to follow',
description: 'All my favourites',
sensitive: false,
discoverable: true,
}
end
context 'when given valid parameters' do
it 'creates a new local collection' do
collection = nil
expect do
collection = subject.call(base_params, author)
end.to change(Collection, :count).by(1)
expect(collection).to be_a(Collection)
expect(collection).to be_local
end
context 'when given account ids' do
let(:account_ids) do
Fabricate.times(2, :account).map { |a| a.id.to_s }
end
let(:params) do
base_params.merge(account_ids:)
end
it 'also creates collection items' do
expect do
subject.call(params, author)
end.to change(CollectionItem, :count).by(2)
end
end
context 'when given a tag' do
let(:params) { base_params.merge(tag: '#people') }
context 'when the tag exists' do
let!(:tag) { Fabricate.create(:tag, name: 'people') }
it 'correctly assigns the existing tag' do
collection = subject.call(params, author)
expect(collection.tag).to eq tag
end
end
context 'when the tag does not exist' do
it 'creates a new tag' do
collection = nil
expect do
collection = subject.call(params, author)
end.to change(Tag, :count).by(1)
expect(collection.tag.name).to eq 'people'
end
end
end
end
context 'when given invalid parameters' do
it 'raises an exception' do
expect do
subject.call({}, author)
end.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
end

View File

@ -7,3 +7,5 @@ module CommandLineHelpers
).to_stdout ).to_stdout
end end
end end
RSpec::Matchers.define_negated_matcher :not_output_results, :output_results