diff options
22 files changed, 443 insertions, 59 deletions
diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml index a9d8ea2ea..9a7463060 100644 --- a/.github/workflows/check-i18n.yml +++ b/.github/workflows/check-i18n.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.0' + ruby-version: .ruby-version bundler-cache: true - name: Check locale file normalization run: bundle exec i18n-tasks check-normalized diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 874afc459..319152e93 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -53,7 +53,7 @@ jobs: - name: Set-up Node.js uses: actions/setup-node@v3 with: - node-version: 16.x + node-version-file: .nvmrc cache: yarn - name: Install dependencies run: yarn install --frozen-lockfile diff --git a/Vagrantfile b/Vagrantfile index 0d44b4d23..043bab3e9 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -3,16 +3,14 @@ ENV["PORT"] ||= "3000" -$provision = <<SCRIPT - -cd /vagrant # This is where the host folder/repo is mounted +$provisionA = <<SCRIPT # Add the yarn repo + yarn repo keys curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main' # Add repo for NodeJS -curl -sL https://deb.nodesource.com/setup_14.x | sudo bash - +curl -sL https://deb.nodesource.com/setup_16.x | sudo bash - # Add firewall rule to redirect 80 to PORT and save sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]} @@ -33,32 +31,56 @@ sudo apt-get install \ redis-tools \ postgresql \ postgresql-contrib \ - yarn \ libicu-dev \ libidn11-dev \ - libreadline-dev \ - libpam0g-dev \ + libreadline6-dev \ + autoconf \ + bison \ + build-essential \ + ffmpeg \ + file \ + gcc \ + libffi-dev \ + libgdbm-dev \ + libjemalloc-dev \ + libncurses5-dev \ + libprotobuf-dev \ + libssl-dev \ + libyaml-dev \ + pkg-config \ + protobuf-compiler \ + zlib1g-dev \ -y # Install rvm -read RUBY_VERSION < .ruby-version +sudo apt-add-repository -y ppa:rael-gc/rvm +sudo apt-get install rvm -y -curl -sSL https://rvm.io/mpapis.asc | gpg --import -curl -sSL https://rvm.io/pkuczynski.asc | gpg --import +sudo usermod -a -G rvm $USER + +SCRIPT -curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION -source /home/vagrant/.rvm/scripts/rvm +$provisionB = <<SCRIPT + +source "/etc/profile.d/rvm.sh" # Install Ruby -rvm reinstall ruby-$RUBY_VERSION --disable-binary +read RUBY_VERSION < /vagrant/.ruby-version +rvm install ruby-$RUBY_VERSION --disable-binary # Configure database sudo -u postgres createuser -U postgres vagrant -s sudo -u postgres createdb -U postgres mastodon_development -# Install gems and node modules +cd /vagrant # This is where the host folder/repo is mounted + +# Install gems gem install bundler foreman bundle install + +# Install node modules +sudo corepack enable +yarn set version classic yarn install # Build Mastodon @@ -72,18 +94,11 @@ echo 'export $(cat "/vagrant/.env.vagrant" | xargs)' >> ~/.bash_profile SCRIPT -$start = <<SCRIPT - -echo 'To start server' -echo ' $ vagrant ssh -c "cd /vagrant && foreman start"' - -SCRIPT - VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - config.vm.box = "ubuntu/bionic64" + config.vm.box = "ubuntu/focal64" config.vm.provider :virtualbox do |vb| vb.name = "mastodon" @@ -100,7 +115,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Use "virtio" network interfaces for better performance. vb.customize ["modifyvm", :id, "--nictype1", "virtio"] vb.customize ["modifyvm", :id, "--nictype2", "virtio"] - end # This uses the vagrant-hostsupdater plugin, and lets you @@ -118,7 +132,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end if config.vm.networks.any? { |type, options| type == :private_network } - config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'actimeo=1'] + config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'actimeo=1'] else config.vm.synced_folder ".", "/vagrant" end @@ -129,9 +143,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.network :forwarded_port, guest: 8080, host: 8080 # Full provisioning script, only runs on first 'vagrant up' or with 'vagrant provision' - config.vm.provision :shell, inline: $provision, privileged: false + config.vm.provision :shell, inline: $provisionA, privileged: false, reset: true + config.vm.provision :shell, inline: $provisionB, privileged: false - # Start up script, runs on every 'vagrant up' - config.vm.provision :shell, inline: $start, run: 'always', privileged: false + config.vm.post_up_message = <<MESSAGE +To start server + $ vagrant ssh -c "cd /vagrant && foreman start" +MESSAGE end diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 40bf685c5..9beb8fde6 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -55,12 +55,14 @@ module Admin def approve authorize @account.user, :approve? @account.user.approve! + log_action :approve, @account.user redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.approved_msg', username: @account.acct) end def reject authorize @account.user, :reject? DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false) + log_action :reject, @account.user redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct) end diff --git a/app/controllers/api/v1/admin/accounts_controller.rb b/app/controllers/api/v1/admin/accounts_controller.rb index ae7f7d076..f48300072 100644 --- a/app/controllers/api/v1/admin/accounts_controller.rb +++ b/app/controllers/api/v1/admin/accounts_controller.rb @@ -54,12 +54,14 @@ class Api::V1::Admin::AccountsController < Api::BaseController def approve authorize @account.user, :approve? @account.user.approve! + log_action :approve, @account.user render json: @account, serializer: REST::Admin::AccountSerializer end def reject authorize @account.user, :reject? DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false) + log_action :reject, @account.user render_empty end diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb index 149139b40..772791b25 100644 --- a/app/controllers/api/v1/filters_controller.rb +++ b/app/controllers/api/v1/filters_controller.rb @@ -13,7 +13,7 @@ class Api::V1::FiltersController < Api::BaseController def create ApplicationRecord.transaction do - filter_category = current_account.custom_filters.create!(resource_params) + filter_category = current_account.custom_filters.create!(filter_params) @filter = filter_category.keywords.create!(keyword_params) end @@ -52,11 +52,11 @@ class Api::V1::FiltersController < Api::BaseController end def resource_params - params.permit(:phrase, :expires_in, :irreversible, context: []) + params.permit(:phrase, :expires_in, :irreversible, :whole_word, context: []) end def filter_params - resource_params.slice(:expires_in, :irreversible, :context) + resource_params.slice(:phrase, :expires_in, :irreversible, :context) end def keyword_params diff --git a/app/javascript/mastodon/features/ui/components/header.js b/app/javascript/mastodon/features/ui/components/header.js index bbb0ca1c6..1384bebda 100644 --- a/app/javascript/mastodon/features/ui/components/header.js +++ b/app/javascript/mastodon/features/ui/components/header.js @@ -6,6 +6,7 @@ import { registrationsOpen, me } from 'mastodon/initial_state'; import Avatar from 'mastodon/components/avatar'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; +import { openModal } from 'mastodon/actions/modal'; const Account = connect(state => ({ account: state.getIn(['accounts', me]), @@ -15,7 +16,14 @@ const Account = connect(state => ({ </Link> )); -export default @withRouter +const mapDispatchToProps = (dispatch) => ({ + openClosedRegistrationsModal() { + dispatch(openModal('CLOSED_REGISTRATIONS')); + }, +}); + +export default @connect(null, mapDispatchToProps) +@withRouter class Header extends React.PureComponent { static contextTypes = { @@ -23,12 +31,13 @@ class Header extends React.PureComponent { }; static propTypes = { + openClosedRegistrationsModal: PropTypes.func, location: PropTypes.object, }; render () { const { signedIn } = this.context.identity; - const { location } = this.props; + const { location, openClosedRegistrationsModal } = this.props; let content; @@ -40,10 +49,26 @@ class Header extends React.PureComponent { </> ); } else { + let signupButton; + + if (registrationsOpen) { + signupButton = ( + <a href='/auth/sign_up' className='button button-tertiary'> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </a> + ); + } else { + signupButton = ( + <button className='button button-tertiary' onClick={openClosedRegistrationsModal}> + <FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /> + </button> + ); + } + content = ( <> <a href='/auth/sign_in' className='button'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a> - <a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a> + {signupButton} </> ); } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 8a2f64526..3650e3ec8 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2217,6 +2217,7 @@ $ui-header-height: 55px; z-index: 2; justify-content: space-between; align-items: center; + overflow: hidden; &__logo { display: inline-flex; @@ -2233,10 +2234,15 @@ $ui-header-height: 55px; align-items: center; gap: 10px; padding: 0 10px; + overflow: hidden; .button { flex: 0 0 auto; } + + .button-tertiary { + flex-shrink: 1; + } } } @@ -7138,10 +7144,12 @@ noscript { .verified { border: 1px solid rgba($valid-value-color, 0.5); + margin-top: -1px; &:first-child { border-top-left-radius: 4px; border-top-right-radius: 4px; + margin-top: 0; } &:last-child { @@ -7973,7 +7981,8 @@ noscript { width: 600px; background: $ui-base-color; border-radius: 8px; - overflow: hidden; + overflow-x: hidden; + overflow-y: auto; position: relative; display: block; padding: 20px; diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb index 16276158d..fa8cb6013 100644 --- a/app/models/account_migration.rb +++ b/app/models/account_migration.rb @@ -59,7 +59,7 @@ class AccountMigration < ApplicationRecord def set_target_account self.target_account = ResolveAccountService.new.call(acct, skip_cache: true) - rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error + rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError # Validation will take care of it end diff --git a/app/models/concerns/domain_materializable.rb b/app/models/concerns/domain_materializable.rb index 798672213..0eac6878e 100644 --- a/app/models/concerns/domain_materializable.rb +++ b/app/models/concerns/domain_materializable.rb @@ -14,7 +14,6 @@ module DomainMaterializable Instance.refresh count_unique_subdomains! - end def count_unique_subdomains! diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb index da2a91493..5a4a974be 100644 --- a/app/models/custom_filter.rb +++ b/app/models/custom_filter.rb @@ -54,7 +54,7 @@ class CustomFilter < ApplicationRecord end def irreversible=(value) - self.action = value ? :hide : :warn + self.action = ActiveModel::Type::Boolean.new.cast(value) ? :hide : :warn end def irreversible? diff --git a/app/models/form/redirect.rb b/app/models/form/redirect.rb index 795fdd057..3cd5731e6 100644 --- a/app/models/form/redirect.rb +++ b/app/models/form/redirect.rb @@ -32,7 +32,7 @@ class Form::Redirect def set_target_account @target_account = ResolveAccountService.new.call(acct, skip_cache: true) - rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error + rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError # Validation will take care of it end diff --git a/config/application.rb b/config/application.rb index 6fa3654d8..83124cfda 100644 --- a/config/application.rb +++ b/config/application.rb @@ -71,6 +71,7 @@ module Mastodon :af, :ar, :ast, + :be, :bg, :bn, :br, diff --git a/config/database.yml b/config/database.yml index 127a78abf..bfb53f21b 100644 --- a/config/database.yml +++ b/config/database.yml @@ -2,6 +2,7 @@ default: &default adapter: postgresql pool: <%= ENV["DB_POOL"] || ENV['MAX_THREADS'] || 5 %> timeout: 5000 + connect_timeout: 15 encoding: unicode sslmode: <%= ENV['DB_SSLMODE'] || "prefer" %> diff --git a/db/post_migrate/20221101190723_backfill_admin_action_logs.rb b/db/post_migrate/20221101190723_backfill_admin_action_logs.rb index 9a64d1715..48ef1e6e3 100644 --- a/db/post_migrate/20221101190723_backfill_admin_action_logs.rb +++ b/db/post_migrate/20221101190723_backfill_admin_action_logs.rb @@ -79,69 +79,72 @@ class BackfillAdminActionLogs < ActiveRecord::Migration[6.1] safety_assured do AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log| next if log.account.nil? - log.update(human_identifier: log.account.acct) + log.update_attribute('human_identifier', log.account.acct) end AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log| next if log.user.nil? - log.update(human_identifier: log.user.account.acct, route_param: log.user.account_id) + log.update_attribute('human_identifier', log.user.account.acct) + log.update_attribute('route_param', log.user.account_id) end Admin::ActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text') AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log| next if log.domain_block.nil? - log.update(human_identifier: log.domain_block.domain) + log.update_attribute('human_identifier', log.domain_block.domain) end AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log| next if log.domain_allow.nil? - log.update(human_identifier: log.domain_allow.domain) + log.update_attribute('human_identifier', log.domain_allow.domain) end AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log| next if log.email_domain_block.nil? - log.update(human_identifier: log.email_domain_block.domain) + log.update_attribute('human_identifier', log.email_domain_block.domain) end AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log| next if log.unavailable_domain.nil? - log.update(human_identifier: log.unavailable_domain.domain) + log.update_attribute('human_identifier', log.unavailable_domain.domain) end AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log| next if log.status.nil? - log.update(human_identifier: log.status.account.acct, permalink: log.status.uri) + log.update_attribute('human_identifier', log.status.account.acct) + log.update_attribute('permalink', log.status.uri) end AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log| next if log.account_warning.nil? - log.update(human_identifier: log.account_warning.account.acct) + log.update_attribute('human_identifier', log.account_warning.account.acct) end AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log| next if log.announcement.nil? - log.update(human_identifier: log.announcement.text) + log.update_attribute('human_identifier', log.announcement.text) end AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log| next if log.ip_block.nil? - log.update(human_identifier: "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") + log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") end AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log| next if log.custom_emoji.nil? - log.update(human_identifier: log.custom_emoji.shortcode) + log.update_attribute('human_identifier', log.custom_emoji.shortcode) end AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log| next if log.canonical_email_block.nil? - log.update(human_identifier: log.canonical_email_block.canonical_email_hash) + log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash) end AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log| next if log.appeal.nil? - log.update(human_identifier: log.appeal.account.acct, route_param: log.appeal.account_warning_id) + log.update_attribute('human_identifier', log.appeal.account.acct) + log.update_attribute('route_param', log.appeal.account_warning_id) end end end diff --git a/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb b/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb new file mode 100644 index 000000000..279053ab9 --- /dev/null +++ b/db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +class BackfillAdminActionLogsAgain < ActiveRecord::Migration[6.1] + disable_ddl_transaction! + + class Account < ApplicationRecord + # Dummy class, to make migration possible across version changes + has_one :user, inverse_of: :account + + def local? + domain.nil? + end + + def acct + local? ? username : "#{username}@#{domain}" + end + end + + class User < ApplicationRecord + # Dummy class, to make migration possible across version changes + belongs_to :account + end + + class Status < ApplicationRecord + include RoutingHelper + + # Dummy class, to make migration possible across version changes + belongs_to :account + + def local? + attributes['local'] || attributes['uri'].nil? + end + + def uri + local? ? activity_account_status_url(account, self) : attributes['uri'] + end + end + + class DomainBlock < ApplicationRecord; end + class DomainAllow < ApplicationRecord; end + class EmailDomainBlock < ApplicationRecord; end + class UnavailableDomain < ApplicationRecord; end + + class AccountWarning < ApplicationRecord + # Dummy class, to make migration possible across version changes + belongs_to :account + end + + class Announcement < ApplicationRecord; end + class IpBlock < ApplicationRecord; end + class CustomEmoji < ApplicationRecord; end + class CanonicalEmailBlock < ApplicationRecord; end + + class Appeal < ApplicationRecord + # Dummy class, to make migration possible across version changes + belongs_to :account + end + + class AdminActionLog < ApplicationRecord + # Dummy class, to make migration possible across version changes + + # Cannot use usual polymorphic support because of namespacing issues + belongs_to :status, foreign_key: :target_id + belongs_to :account, foreign_key: :target_id + belongs_to :user, foreign_key: :user_id + belongs_to :domain_block, foreign_key: :target_id + belongs_to :domain_allow, foreign_key: :target_id + belongs_to :email_domain_block, foreign_key: :target_id + belongs_to :unavailable_domain, foreign_key: :target_id + belongs_to :account_warning, foreign_key: :target_id + belongs_to :announcement, foreign_key: :target_id + belongs_to :ip_block, foreign_key: :target_id + belongs_to :custom_emoji, foreign_key: :target_id + belongs_to :canonical_email_block, foreign_key: :target_id + belongs_to :appeal, foreign_key: :target_id + end + + def up + safety_assured do + AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log| + next if log.account.nil? + log.update_attribute('human_identifier', log.account.acct) + end + + AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log| + next if log.user.nil? + log.update_attribute('human_identifier', log.user.account.acct) + log.update_attribute('route_param', log.user.account_id) + end + + Admin::ActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text') + + AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log| + next if log.domain_block.nil? + log.update_attribute('human_identifier', log.domain_block.domain) + end + + AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log| + next if log.domain_allow.nil? + log.update_attribute('human_identifier', log.domain_allow.domain) + end + + AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log| + next if log.email_domain_block.nil? + log.update_attribute('human_identifier', log.email_domain_block.domain) + end + + AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log| + next if log.unavailable_domain.nil? + log.update_attribute('human_identifier', log.unavailable_domain.domain) + end + + AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log| + next if log.status.nil? + log.update_attribute('human_identifier', log.status.account.acct) + log.update_attribute('permalink', log.status.uri) + end + + AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log| + next if log.account_warning.nil? + log.update_attribute('human_identifier', log.account_warning.account.acct) + end + + AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log| + next if log.announcement.nil? + log.update_attribute('human_identifier', log.announcement.text) + end + + AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log| + next if log.ip_block.nil? + log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}") + end + + AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log| + next if log.custom_emoji.nil? + log.update_attribute('human_identifier', log.custom_emoji.shortcode) + end + + AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log| + next if log.canonical_email_block.nil? + log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash) + end + + AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log| + next if log.appeal.nil? + log.update_attribute('human_identifier', log.appeal.account.acct) + log.update_attribute('route_param', log.appeal.account_warning_id) + end + end + end + + def down; end +end diff --git a/db/schema.rb b/db/schema.rb index 01a95c0f2..7462bf2c7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_11_04_133904) do +ActiveRecord::Schema.define(version: 2022_12_06_114142) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 96d2f7112..1dd25abb9 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -43,6 +43,16 @@ namespace :tests do puts 'CustomFilterKeyword records not created as expected' exit(1) end + + unless Admin::ActionLog.find_by(target_type: 'DomainBlock', target_id: 1).human_identifier == 'example.org' + puts 'Admin::ActionLog domain block records not updated as expected' + exit(1) + end + + unless Admin::ActionLog.find_by(target_type: 'EmailDomainBlock', target_id: 1).human_identifier == 'example.org' + puts 'Admin::ActionLog email domain block records not updated as expected' + exit(1) + end end desc 'Populate the database with test data for 2.4.3' @@ -84,8 +94,8 @@ namespace :tests do VALUES (1, 'destroy', 'Account', 1, now(), now()), (1, 'destroy', 'User', 1, now(), now()), - (1, 'destroy', 'DomainBlock', 1312, now(), now()), - (1, 'destroy', 'EmailDomainBlock', 1312, now(), now()), + (1, 'destroy', 'DomainBlock', 1, now(), now()), + (1, 'destroy', 'EmailDomainBlock', 1, now(), now()), (1, 'destroy', 'Status', 1, now(), now()), (1, 'destroy', 'CustomEmoji', 3, now(), now()); SQL diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index 1bd51a0c8..81d592ddd 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -147,6 +147,87 @@ RSpec.describe Admin::AccountsController, type: :controller do end end + describe 'POST #approve' do + subject { post :approve, params: { id: account.id } } + + let(:current_user) { Fabricate(:user, role: role) } + let(:account) { user.account } + let(:user) { Fabricate(:user) } + + before do + account.user.update(approved: false) + end + + context 'when user is admin' do + let(:role) { UserRole.find_by(name: 'Admin') } + + it 'succeeds in approving account' do + is_expected.to redirect_to admin_accounts_path(status: 'pending') + expect(user.reload).to be_approved + end + + it 'logs action' do + is_expected.to have_http_status :found + + log_item = Admin::ActionLog.last + + expect(log_item).to_not be_nil + expect(log_item.action).to eq :approve + expect(log_item.account_id).to eq current_user.account_id + expect(log_item.target_id).to eq account.user.id + end + end + + context 'when user is not admin' do + let(:role) { UserRole.everyone } + + it 'fails to approve account' do + is_expected.to have_http_status :forbidden + expect(user.reload).not_to be_approved + end + end + end + + describe 'POST #reject' do + subject { post :reject, params: { id: account.id } } + + let(:current_user) { Fabricate(:user, role: role) } + let(:account) { user.account } + let(:user) { Fabricate(:user) } + + before do + account.user.update(approved: false) + end + + context 'when user is admin' do + let(:role) { UserRole.find_by(name: 'Admin') } + + it 'succeeds in rejecting account' do + is_expected.to redirect_to admin_accounts_path(status: 'pending') + end + + it 'logs action' do + is_expected.to have_http_status :found + + log_item = Admin::ActionLog.last + + expect(log_item).to_not be_nil + expect(log_item.action).to eq :reject + expect(log_item.account_id).to eq current_user.account_id + expect(log_item.target_id).to eq account.user.id + end + end + + context 'when user is not admin' do + let(:role) { UserRole.everyone } + + it 'fails to reject account' do + is_expected.to have_http_status :forbidden + expect(user.reload).not_to be_approved + end + end + end + describe 'POST #redownload' do subject { post :redownload, params: { id: account.id } } diff --git a/spec/controllers/api/v1/admin/accounts_controller_spec.rb b/spec/controllers/api/v1/admin/accounts_controller_spec.rb index cd38030e0..8d35b86cb 100644 --- a/spec/controllers/api/v1/admin/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/admin/accounts_controller_spec.rb @@ -100,6 +100,15 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do it 'approves user' do expect(account.reload.user_approved?).to be true end + + it 'logs action' do + log_item = Admin::ActionLog.last + + expect(log_item).to_not be_nil + expect(log_item.action).to eq :approve + expect(log_item.account_id).to eq user.account_id + expect(log_item.target_id).to eq account.user.id + end end describe 'POST #reject' do @@ -118,6 +127,15 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do it 'removes user' do expect(User.where(id: account.user.id).count).to eq 0 end + + it 'logs action' do + log_item = Admin::ActionLog.last + + expect(log_item).to_not be_nil + expect(log_item.action).to eq :reject + expect(log_item.account_id).to eq user.account_id + expect(log_item.target_id).to eq account.user.id + end end describe 'POST #enable' do diff --git a/spec/controllers/api/v1/filters_controller_spec.rb b/spec/controllers/api/v1/filters_controller_spec.rb index af1951f0b..8acb46a00 100644 --- a/spec/controllers/api/v1/filters_controller_spec.rb +++ b/spec/controllers/api/v1/filters_controller_spec.rb @@ -22,9 +22,11 @@ RSpec.describe Api::V1::FiltersController, type: :controller do describe 'POST #create' do let(:scopes) { 'write:filters' } + let(:irreversible) { true } + let(:whole_word) { false } before do - post :create, params: { phrase: 'magic', context: %w(home), irreversible: true } + post :create, params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word } end it 'returns http success' do @@ -34,11 +36,29 @@ RSpec.describe Api::V1::FiltersController, type: :controller do it 'creates a filter' do filter = user.account.custom_filters.first expect(filter).to_not be_nil - expect(filter.keywords.pluck(:keyword)).to eq ['magic'] + expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]] expect(filter.context).to eq %w(home) - expect(filter.irreversible?).to be true + expect(filter.irreversible?).to be irreversible expect(filter.expires_at).to be_nil end + + context 'with different parameters' do + let(:irreversible) { false } + let(:whole_word) { true } + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it 'creates a filter' do + filter = user.account.custom_filters.first + expect(filter).to_not be_nil + expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]] + expect(filter.context).to eq %w(home) + expect(filter.irreversible?).to be irreversible + expect(filter.expires_at).to be_nil + end + end end describe 'GET #show' do diff --git a/spec/models/account_migration_spec.rb b/spec/models/account_migration_spec.rb index 8461b4b28..5f66fe8da 100644 --- a/spec/models/account_migration_spec.rb +++ b/spec/models/account_migration_spec.rb @@ -1,5 +1,48 @@ require 'rails_helper' RSpec.describe AccountMigration, type: :model do + describe 'validations' do + let(:source_account) { Fabricate(:account) } + let(:target_acct) { target_account.acct } + let(:subject) { AccountMigration.new(account: source_account, acct: target_acct) } + + context 'with valid properties' do + let(:target_account) { Fabricate(:account, username: 'target', domain: 'remote.org') } + + before do + target_account.aliases.create!(acct: source_account.acct) + + service_double = double + allow(ResolveAccountService).to receive(:new).and_return(service_double) + allow(service_double).to receive(:call).with(target_acct, anything).and_return(target_account) + end + + it 'passes validations' do + expect(subject).to be_valid + end + end + + context 'with unresolveable account' do + let(:target_acct) { 'target@remote' } + + before do + service_double = double + allow(ResolveAccountService).to receive(:new).and_return(service_double) + allow(service_double).to receive(:call).with(target_acct, anything).and_return(nil) + end + + it 'has errors on acct field' do + expect(subject).to model_have_error_on_field(:acct) + end + end + + context 'with a space in the domain part' do + let(:target_acct) { 'target@remote. org' } + + it 'has errors on acct field' do + expect(subject).to model_have_error_on_field(:acct) + end + end + end end |