diff --git a/Gemfile b/Gemfile
index ac1014ccb7..911e8c0e19 100644
--- a/Gemfile
+++ b/Gemfile
@@ -208,3 +208,5 @@ gem 'net-http', '~> 0.4.0'
gem 'rubyzip', '~> 2.3'
gem 'hcaptcha', '~> 7.1'
+
+gem 'mail', '~> 2.8'
diff --git a/Gemfile.lock b/Gemfile.lock
index d87be99e92..300b8073b5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -356,7 +356,7 @@ GEM
rdoc
reline (>= 0.4.2)
jmespath (1.6.2)
- json (2.7.1)
+ json (2.7.2)
json-canonicalization (1.0.0)
json-jwt (1.15.3.1)
activesupport (>= 4.2)
@@ -607,7 +607,7 @@ GEM
redlock (1.3.2)
redis (>= 3.0.0, < 6.0)
regexp_parser (2.9.0)
- reline (0.4.3)
+ reline (0.5.0)
io-console (~> 0.5)
request_store (1.5.1)
rack (>= 1.4)
@@ -673,7 +673,7 @@ GEM
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
- rubocop-rspec (2.28.0)
+ rubocop-rspec (2.29.1)
rubocop (~> 1.40)
rubocop-capybara (~> 2.17)
rubocop-factory_bot (~> 2.22)
@@ -694,7 +694,7 @@ GEM
sanitize (6.1.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
- scenic (1.7.0)
+ scenic (1.8.0)
activerecord (>= 4.0.0)
railties (>= 4.0.0)
selenium-webdriver (4.19.0)
@@ -882,6 +882,7 @@ DEPENDENCIES
letter_opener_web (~> 2.0)
link_header (~> 0.0)
lograge (~> 0.12)
+ mail (~> 2.8)
mario-redis-lock (~> 1.2)
md-paperclip-azure (~> 2.2)
memory_profiler
diff --git a/Vagrantfile b/Vagrantfile
index 12bd1ba67a..8a95e91f36 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -173,6 +173,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080
config.vm.network :forwarded_port, guest: 3000, host: 3000
+ config.vm.network :forwarded_port, guest: 3035, host: 3035
config.vm.network :forwarded_port, guest: 4000, host: 4000
config.vm.network :forwarded_port, guest: 8080, host: 8080
config.vm.network :forwarded_port, guest: 9200, host: 9200
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index d5d1daa815..1b4046bd31 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -166,18 +166,6 @@ module ApplicationHelper
output.compact_blank.join(' ')
end
- def theme_style_tags(theme)
- if theme == 'system'
- concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
- concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
- concat tag.meta name: 'theme-color', content: Themes::MASTODON_DARK_THEME_COLOR, media: '(prefers-color-scheme: dark)'
- concat tag.meta name: 'theme-color', content: Themes::MASTODON_LIGHT_THEME_COLOR, media: '(prefers-color-scheme: light)'
- else
- concat stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
- concat tag.meta name: 'theme-color', content: theme == 'mastodon-light' ? Themes::MASTODON_LIGHT_THEME_COLOR : Themes::MASTODON_DARK_THEME_COLOR
- end
- end
-
def cdn_host
Rails.configuration.action_controller.asset_host
end
diff --git a/app/helpers/theme_helper.rb b/app/helpers/theme_helper.rb
new file mode 100644
index 0000000000..83527ce611
--- /dev/null
+++ b/app/helpers/theme_helper.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module ThemeHelper
+ def theme_style_tags(theme)
+ if theme == 'system'
+ concat stylesheet_pack_tag('mastodon-light', media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
+ concat stylesheet_pack_tag('default', media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
+ else
+ stylesheet_pack_tag theme, media: 'all', crossorigin: 'anonymous'
+ end
+ end
+
+ def theme_color_tags(theme)
+ if theme == 'system'
+ concat tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:dark], media: '(prefers-color-scheme: dark)')
+ concat tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:light], media: '(prefers-color-scheme: light)')
+ else
+ tag.meta name: 'theme-color', content: theme_color_for(theme)
+ end
+ end
+
+ private
+
+ def theme_color_for(theme)
+ theme == 'mastodon-light' ? Themes::THEME_COLORS[:light] : Themes::THEME_COLORS[:dark]
+ end
+end
diff --git a/app/javascript/mastodon/utils/__tests__/html-test.s b/app/javascript/mastodon/utils/__tests__/html-test.ts
similarity index 67%
rename from app/javascript/mastodon/utils/__tests__/html-test.s
rename to app/javascript/mastodon/utils/__tests__/html-test.ts
index d948cf4c5d..99bfdcb801 100644
--- a/app/javascript/mastodon/utils/__tests__/html-test.s
+++ b/app/javascript/mastodon/utils/__tests__/html-test.ts
@@ -3,7 +3,9 @@ import * as html from '../html';
describe('html', () => {
describe('unescapeHTML', () => {
it('returns unescaped HTML', () => {
- const output = html.unescapeHTML('
lorem
ipsum
<br>');
+ const output = html.unescapeHTML(
+ 'lorem
ipsum
<br>',
+ );
expect(output).toEqual('lorem\n\nipsum\n
');
});
});
diff --git a/app/javascript/mastodon/utils/__tests__/numbers.ts b/app/javascript/mastodon/utils/__tests__/numbers.ts
new file mode 100644
index 0000000000..d1d1444e8a
--- /dev/null
+++ b/app/javascript/mastodon/utils/__tests__/numbers.ts
@@ -0,0 +1,24 @@
+import { DECIMAL_UNITS, toShortNumber } from '../numbers';
+
+interface TableRow {
+ input: number;
+ base: number;
+ unit: number;
+ digits: number;
+}
+
+describe.each`
+ input | base | unit | digits
+ ${10_000_000} | ${10} | ${DECIMAL_UNITS.MILLION} | ${0}
+ ${2_789_123} | ${2.789123} | ${DECIMAL_UNITS.MILLION} | ${1}
+ ${12_345_789} | ${12.345789} | ${DECIMAL_UNITS.MILLION} | ${0}
+ ${10_000_000_000} | ${10} | ${DECIMAL_UNITS.BILLION} | ${0}
+ ${12} | ${12} | ${DECIMAL_UNITS.ONE} | ${0}
+ ${123} | ${123} | ${DECIMAL_UNITS.ONE} | ${0}
+ ${1234} | ${1.234} | ${DECIMAL_UNITS.THOUSAND} | ${1}
+ ${6666} | ${6.666} | ${DECIMAL_UNITS.THOUSAND} | ${1}
+`('toShortNumber', ({ input, base, unit, digits }: TableRow) => {
+ test(`correctly formats ${input}`, () => {
+ expect(toShortNumber(input)).toEqual([base, unit, digits]);
+ });
+});
diff --git a/app/javascript/styles/mastodon/emoji_picker.scss b/app/javascript/styles/mastodon/emoji_picker.scss
index 22c421a77d..dd371feb15 100644
--- a/app/javascript/styles/mastodon/emoji_picker.scss
+++ b/app/javascript/styles/mastodon/emoji_picker.scss
@@ -112,9 +112,11 @@
border: 0;
}
- &:focus,
- &:active {
+ &:active,
+ &:focus {
outline: none !important;
+ border-width: 1px !important;
+ border-color: $ui-button-background-color;
}
&::-webkit-search-cancel-button {
diff --git a/app/lib/admin/metrics/measure/tag_servers_measure.rb b/app/lib/admin/metrics/measure/tag_servers_measure.rb
index e0f1bf3440..f273d739d0 100644
--- a/app/lib/admin/metrics/measure/tag_servers_measure.rb
+++ b/app/lib/admin/metrics/measure/tag_servers_measure.rb
@@ -46,11 +46,11 @@ class Admin::Metrics::Measure::TagServersMeasure < Admin::Metrics::Measure::Base
end
def earliest_status_id
- Mastodon::Snowflake.id_at(@start_at, with_random: false)
+ Mastodon::Snowflake.id_at(@start_at.beginning_of_day, with_random: false)
end
def latest_status_id
- Mastodon::Snowflake.id_at(@end_at, with_random: false)
+ Mastodon::Snowflake.id_at(@end_at.end_of_day, with_random: false)
end
def tag
diff --git a/app/lib/annual_report/top_statuses.rb b/app/lib/annual_report/top_statuses.rb
index 112e5591ce..1ab1709523 100644
--- a/app/lib/annual_report/top_statuses.rb
+++ b/app/lib/annual_report/top_statuses.rb
@@ -16,6 +16,6 @@ class AnnualReport::TopStatuses < AnnualReport::Source
end
def base_scope
- @account.statuses.with_public_visibility.joins(:status_stat).where(id: year_as_snowflake_range).reorder(nil)
+ @account.statuses.public_visibility.joins(:status_stat).where(id: year_as_snowflake_range).reorder(nil)
end
end
diff --git a/app/lib/themes.rb b/app/lib/themes.rb
index 3ad2304977..b6da980733 100644
--- a/app/lib/themes.rb
+++ b/app/lib/themes.rb
@@ -6,8 +6,10 @@ require 'yaml'
class Themes
include Singleton
- MASTODON_DARK_THEME_COLOR = '#191b22'
- MASTODON_LIGHT_THEME_COLOR = '#f3f5f7'
+ THEME_COLORS = {
+ dark: '#191b22',
+ light: '#f3f5f7',
+ }.freeze
def initialize
@conf = YAML.load_file(Rails.root.join('config', 'themes.yml'))
diff --git a/app/models/concerns/custom_filter_cache.rb b/app/models/concerns/custom_filter_cache.rb
new file mode 100644
index 0000000000..79b22f11f1
--- /dev/null
+++ b/app/models/concerns/custom_filter_cache.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module CustomFilterCache
+ extend ActiveSupport::Concern
+
+ included do
+ after_commit :invalidate_cache!
+ before_destroy :prepare_cache_invalidation!
+ before_save :prepare_cache_invalidation!
+
+ delegate(
+ :invalidate_cache!,
+ :prepare_cache_invalidation!,
+ to: :custom_filter
+ )
+ end
+end
diff --git a/app/models/custom_filter_keyword.rb b/app/models/custom_filter_keyword.rb
index 7cc9b6fef9..5280332fdd 100644
--- a/app/models/custom_filter_keyword.rb
+++ b/app/models/custom_filter_keyword.rb
@@ -13,16 +13,14 @@
#
class CustomFilterKeyword < ApplicationRecord
+ include CustomFilterCache
+
belongs_to :custom_filter
validates :keyword, presence: true
alias_attribute :phrase, :keyword
- before_save :prepare_cache_invalidation!
- before_destroy :prepare_cache_invalidation!
- after_commit :invalidate_cache!
-
def to_regex
if whole_word?
/(?mix:#{to_regex_sb}#{Regexp.escape(keyword)}#{to_regex_eb})/
@@ -40,12 +38,4 @@ class CustomFilterKeyword < ApplicationRecord
def to_regex_eb
/[[:word:]]\z/.match?(keyword) ? '\b' : ''
end
-
- def prepare_cache_invalidation!
- custom_filter.prepare_cache_invalidation!
- end
-
- def invalidate_cache!
- custom_filter.invalidate_cache!
- end
end
diff --git a/app/models/custom_filter_status.rb b/app/models/custom_filter_status.rb
index 0a5650204a..58b61cd79d 100644
--- a/app/models/custom_filter_status.rb
+++ b/app/models/custom_filter_status.rb
@@ -12,27 +12,17 @@
#
class CustomFilterStatus < ApplicationRecord
+ include CustomFilterCache
+
belongs_to :custom_filter
belongs_to :status
validates :status, uniqueness: { scope: :custom_filter }
validate :validate_status_access
- before_save :prepare_cache_invalidation!
- before_destroy :prepare_cache_invalidation!
- after_commit :invalidate_cache!
-
private
def validate_status_access
errors.add(:status_id, :invalid) unless StatusPolicy.new(custom_filter.account, status).show?
end
-
- def prepare_cache_invalidation!
- custom_filter.prepare_cache_invalidation!
- end
-
- def invalidate_cache!
- custom_filter.invalidate_cache!
- end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index abf4b12272..a0a04d6f66 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -98,6 +98,8 @@ class User < ApplicationRecord
accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text }
validates :invite_request, presence: true, on: :create, if: :invite_text_required?
+ validates :email, presence: true, email_address: true
+
validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? }
validates_with EmailMxValidator, if: :validate_email_dns?
validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
diff --git a/app/validators/email_address_validator.rb b/app/validators/email_address_validator.rb
new file mode 100644
index 0000000000..ed0bb11652
--- /dev/null
+++ b/app/validators/email_address_validator.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# NOTE: I initially wrote this as `EmailValidator` but it ended up clashing
+# with an indirect dependency of ours, `validate_email`, which, turns out,
+# has the same approach as we do, but with an extra check disallowing
+# single-label domains. Decided to not switch to `validate_email` because
+# we do want to allow at least `localhost`.
+
+class EmailAddressValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ value = value.strip
+
+ address = Mail::Address.new(value)
+ record.errors.add(attribute, :invalid) if address.address != value
+ rescue Mail::Field::FieldError
+ record.errors.add(attribute, :invalid)
+ end
+end
diff --git a/app/views/application/mailer/_feature.html.haml b/app/views/application/mailer/_feature.html.haml
index 5facdd0866..94dd4b9cff 100644
--- a/app/views/application/mailer/_feature.html.haml
+++ b/app/views/application/mailer/_feature.html.haml
@@ -4,7 +4,7 @@
%table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
%tr
%td.email-feature-td
- .email-desktop-flex{ class: ('email-dir-rtl' if defined?(text_first_on_desktop) && !text_first_on_desktop) }
+ .email-desktop-flex{ class: ('email-dir-rtl' if feature_iteration.index.odd?) }
/[if mso]
.email-desktop-column
@@ -24,7 +24,7 @@
%tr
%td.email-column-td
- if defined?(feature)
- %p{ class: ('email-desktop-text-right' if defined?(text_first_on_desktop) && text_first_on_desktop) }
+ %p{ class: ('email-desktop-text-right' if feature_iteration.index.even?) }
= image_tag frontend_asset_url("images/mailer-new/welcome/feature_#{feature}.png"), alt: '', width: 240, height: 230
/[if mso]
|
diff --git a/app/views/application/mailer/_hashtag.html.haml b/app/views/application/mailer/_hashtag.html.haml
index fcedfa80a5..74a00e67e1 100644
--- a/app/views/application/mailer/_hashtag.html.haml
+++ b/app/views/application/mailer/_hashtag.html.haml
@@ -1,4 +1,4 @@
-- accounts = hashtag.statuses.with_public_visibility.joins(:account).merge(Account.without_suspended.without_silenced).includes(:account).limit(3).map(&:account)
+- accounts = hashtag.statuses.public_visibility.joins(:account).merge(Account.without_suspended.without_silenced).includes(:account).limit(3).map(&:account)
%table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
%tr
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index c353b1d872..9d7669d685 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -21,6 +21,7 @@
%link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/
%link{ rel: 'manifest', href: manifest_path(format: :json) }/
+ = theme_color_tags current_theme
%meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/
%title= html_title
diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml
index 97fb0a2c97..0f9cbf36ff 100644
--- a/app/views/user_mailer/welcome.html.haml
+++ b/app/views/user_mailer/welcome.html.haml
@@ -68,7 +68,4 @@
%table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
%tr
%td.email-extra-td
- = render 'application/mailer/feature', feature: 'control', text_first_on_desktop: true
- = render 'application/mailer/feature', feature: 'audience', text_first_on_desktop: false
- = render 'application/mailer/feature', feature: 'moderation', text_first_on_desktop: true
- = render 'application/mailer/feature', feature: 'creativity', text_first_on_desktop: false
+ = render partial: 'application/mailer/feature', collection: %w(control audience moderation creativity)
diff --git a/spec/helpers/theme_helper_spec.rb b/spec/helpers/theme_helper_spec.rb
new file mode 100644
index 0000000000..c0b6380a1f
--- /dev/null
+++ b/spec/helpers/theme_helper_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe ThemeHelper do
+ describe 'theme_style_tags' do
+ let(:result) { helper.theme_style_tags(theme) }
+
+ context 'when using system theme' do
+ let(:theme) { 'system' }
+
+ it 'returns the mastodon-light and default stylesheets with correct color schemes' do
+ expect(html_links.first.attributes.symbolize_keys)
+ .to include(
+ href: have_attributes(value: match(/mastodon-light/)),
+ media: have_attributes(value: 'not all and (prefers-color-scheme: dark)')
+ )
+ expect(html_links.last.attributes.symbolize_keys)
+ .to include(
+ href: have_attributes(value: match(/default/)),
+ media: have_attributes(value: '(prefers-color-scheme: dark)')
+ )
+ end
+ end
+
+ context 'when using other theme' do
+ let(:theme) { 'contrast' }
+
+ it 'returns the theme stylesheet without color scheme information' do
+ expect(html_links.first.attributes.symbolize_keys)
+ .to include(
+ href: have_attributes(value: match(/contrast/)),
+ media: have_attributes(value: 'all')
+ )
+ end
+ end
+ end
+
+ describe 'theme_color_tags' do
+ let(:result) { helper.theme_color_tags(theme) }
+
+ context 'when using system theme' do
+ let(:theme) { 'system' }
+
+ it 'returns the mastodon-light and default stylesheets with correct color schemes' do
+ expect(html_theme_colors.first.attributes.symbolize_keys)
+ .to include(
+ content: have_attributes(value: Themes::THEME_COLORS[:dark]),
+ media: have_attributes(value: '(prefers-color-scheme: dark)')
+ )
+ expect(html_theme_colors.last.attributes.symbolize_keys)
+ .to include(
+ content: have_attributes(value: Themes::THEME_COLORS[:light]),
+ media: have_attributes(value: '(prefers-color-scheme: light)')
+ )
+ end
+ end
+
+ context 'when using mastodon-light theme' do
+ let(:theme) { 'mastodon-light' }
+
+ it 'returns the theme stylesheet without color scheme information' do
+ expect(html_theme_colors.first.attributes.symbolize_keys)
+ .to include(
+ content: have_attributes(value: Themes::THEME_COLORS[:light])
+ )
+ end
+ end
+
+ context 'when using other theme' do
+ let(:theme) { 'contrast' }
+
+ it 'returns the theme stylesheet without color scheme information' do
+ expect(html_theme_colors.first.attributes.symbolize_keys)
+ .to include(
+ content: have_attributes(value: Themes::THEME_COLORS[:dark])
+ )
+ end
+ end
+ end
+
+ private
+
+ def html_links
+ Nokogiri::HTML5.fragment(result).css('link')
+ end
+
+ def html_theme_colors
+ Nokogiri::HTML5.fragment(result).css('meta[name=theme-color]')
+ end
+end
diff --git a/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb b/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb
index 1722c4c616..9d80970693 100644
--- a/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb
+++ b/spec/lib/admin/metrics/dimension/languages_dimension_spec.rb
@@ -3,7 +3,7 @@
require 'rails_helper'
describe Admin::Metrics::Dimension::LanguagesDimension do
- subject(:dimension) { described_class.new(start_at, end_at, limit, params) }
+ subject { described_class.new(start_at, end_at, limit, params) }
let(:start_at) { 2.days.ago }
let(:end_at) { Time.now.utc }
@@ -11,8 +11,21 @@ describe Admin::Metrics::Dimension::LanguagesDimension do
let(:params) { ActionController::Parameters.new }
describe '#data' do
- it 'runs data query without error' do
- expect { dimension.data }.to_not raise_error
+ let(:alice) { Fabricate(:user, locale: 'en', current_sign_in_at: 1.day.ago) }
+ let(:bob) { Fabricate(:user, locale: 'en', current_sign_in_at: 30.days.ago) }
+
+ before do
+ alice.update(current_sign_in_at: 1.day.ago)
+ bob.update(current_sign_in_at: 30.days.ago)
+ end
+
+ it 'returns locales with sign in counts' do
+ expect(subject.data.size)
+ .to eq(1)
+ expect(subject.data.map(&:symbolize_keys))
+ .to contain_exactly(
+ include(key: 'en', value: '1')
+ )
end
end
end
diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 404b834702..5a8c293740 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -247,6 +247,12 @@ describe UserMailer do
describe '#welcome' do
let(:mail) { described_class.welcome(receiver) }
+ before do
+ # This is a bit hacky and low-level but this allows stubbing trending tags
+ tag_ids = Fabricate.times(5, :tag).pluck(:id)
+ allow(Trends.tags).to receive(:query).and_return(instance_double(Trends::Query, allowed: Tag.where(id: tag_ids)))
+ end
+
it 'renders welcome mail' do
expect(mail)
.to be_present
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 379429a4d9..27ddeb8f1e 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -38,6 +38,12 @@ RSpec.describe User do
user.save(validate: false)
expect(user.valid?).to be true
end
+
+ it 'is valid with a localhost e-mail address' do
+ user = Fabricate.build(:user, email: 'admin@localhost')
+ user.valid?
+ expect(user.valid?).to be true
+ end
end
describe 'Normalizations' do
diff --git a/spec/requests/api/web/embeds_spec.rb b/spec/requests/api/web/embeds_spec.rb
index 6314f43aaf..0e6195204b 100644
--- a/spec/requests/api/web/embeds_spec.rb
+++ b/spec/requests/api/web/embeds_spec.rb
@@ -137,6 +137,18 @@ RSpec.describe '/api/web/embed' do
end
end
+ context 'when sanitizing the fragment fails' do
+ let(:call_result) { { html: 'ok' } }
+
+ before { allow(Sanitize).to receive(:fragment).and_raise(ArgumentError) }
+
+ it 'returns http not found' do
+ subject
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
context 'when failing to fetch OEmbed' do
let(:call_result) { nil }
diff --git a/spec/features/oauth_spec.rb b/spec/system/oauth_spec.rb
similarity index 94%
rename from spec/features/oauth_spec.rb
rename to spec/system/oauth_spec.rb
index 720c262890..060978217f 100644
--- a/spec/features/oauth_spec.rb
+++ b/spec/system/oauth_spec.rb
@@ -3,13 +3,14 @@
require 'rails_helper'
describe 'Using OAuth from an external app' do
- let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
+ let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/health', scopes: 'read') }
context 'when the user is already logged in' do
let!(:user) { Fabricate(:user) }
before do
- sign_in user, scope: :user
+ visit new_user_session_path
+ fill_in_auth_details(user.email, user.password)
end
it 'when accepting the authorization request' do
@@ -164,20 +165,19 @@ describe 'Using OAuth from an external app' do
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be false
end
end
-
- private
-
- def fill_in_auth_details(email, password)
- fill_in 'user_email', with: email
- fill_in 'user_password', with: password
- click_on I18n.t('auth.login')
- end
-
- def fill_in_otp_details(value)
- fill_in 'user_otp_attempt', with: value
- click_on I18n.t('auth.login')
- end
-
# TODO: external auth
end
+
+ private
+
+ def fill_in_auth_details(email, password)
+ fill_in 'user_email', with: email
+ fill_in 'user_password', with: password
+ click_on I18n.t('auth.login')
+ end
+
+ def fill_in_otp_details(value)
+ fill_in 'user_otp_attempt', with: value
+ click_on I18n.t('auth.login')
+ end
end
diff --git a/yarn.lock b/yarn.lock
index f18d52364f..46bdb30910 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -52,24 +52,24 @@ __metadata:
languageName: node
linkType: hard
-"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.1":
- version: 7.24.1
- resolution: "@babel/compat-data@npm:7.24.1"
- checksum: 10c0/8a1935450345c326b14ea632174696566ef9b353bd0d6fb682456c0774342eeee7654877ced410f24a731d386fdcbf980b75083fc764964d6f816b65792af2f5
+"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/compat-data@npm:7.24.4"
+ checksum: 10c0/9cd8a9cd28a5ca6db5d0e27417d609f95a8762b655e8c9c97fd2de08997043ae99f0139007083c5e607601c6122e8432c85fe391731b19bf26ad458fa0c60dd3
languageName: node
linkType: hard
"@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1":
- version: 7.24.3
- resolution: "@babel/core@npm:7.24.3"
+ version: 7.24.4
+ resolution: "@babel/core@npm:7.24.4"
dependencies:
"@ampproject/remapping": "npm:^2.2.0"
"@babel/code-frame": "npm:^7.24.2"
- "@babel/generator": "npm:^7.24.1"
+ "@babel/generator": "npm:^7.24.4"
"@babel/helper-compilation-targets": "npm:^7.23.6"
"@babel/helper-module-transforms": "npm:^7.23.3"
- "@babel/helpers": "npm:^7.24.1"
- "@babel/parser": "npm:^7.24.1"
+ "@babel/helpers": "npm:^7.24.4"
+ "@babel/parser": "npm:^7.24.4"
"@babel/template": "npm:^7.24.0"
"@babel/traverse": "npm:^7.24.1"
"@babel/types": "npm:^7.24.0"
@@ -78,19 +78,19 @@ __metadata:
gensync: "npm:^1.0.0-beta.2"
json5: "npm:^2.2.3"
semver: "npm:^6.3.1"
- checksum: 10c0/e6e756b6de27d0312514a005688fa1915c521ad4269a388913eff2120a546538078f8488d6d16e86f851872f263cb45a6bbae08738297afb9382600d2ac342a9
+ checksum: 10c0/fc136966583e64d6f84f4a676368de6ab4583aa87f867186068655b30ef67f21f8e65a88c6d446a7efd219ad7ffb9185c82e8a90183ee033f6f47b5026641e16
languageName: node
linkType: hard
-"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.7.2":
- version: 7.24.1
- resolution: "@babel/generator@npm:7.24.1"
+"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.24.4, @babel/generator@npm:^7.7.2":
+ version: 7.24.4
+ resolution: "@babel/generator@npm:7.24.4"
dependencies:
"@babel/types": "npm:^7.24.0"
"@jridgewell/gen-mapping": "npm:^0.3.5"
"@jridgewell/trace-mapping": "npm:^0.3.25"
jsesc: "npm:^2.5.1"
- checksum: 10c0/f0eea7497657cdf68cfb4b7d181588e1498eefd1f303d73b0d8ca9b21a6db27136a6f5beb8f988b6bdcd4249870826080950450fd310951de42ecf36df274881
+ checksum: 10c0/67a1b2f7cc985aaaa11b01e8ddd4fffa4f285837bc7a209738eb8203aa34bdafeb8507ed75fd883ddbabd641a036ca0a8d984e760f28ad4a9d60bff29d0a60bb
languageName: node
linkType: hard
@@ -135,9 +135,9 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-create-class-features-plugin@npm:^7.24.1":
- version: 7.24.1
- resolution: "@babel/helper-create-class-features-plugin@npm:7.24.1"
+"@babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/helper-create-class-features-plugin@npm:7.24.4"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^7.22.5"
"@babel/helper-environment-visitor": "npm:^7.22.20"
@@ -150,7 +150,7 @@ __metadata:
semver: "npm:^6.3.1"
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 10c0/45372890634c37deefc81f44b7d958fe210f7da7d8a2239c9849c6041a56536f74bf3aa2d115bc06d5680d0dc49c1303f74a045d76ae0dd1592c7d5c0c268ebc
+ checksum: 10c0/6ebb38375dcd44c79f40008c2de4d023376cf436c135439f15c9c54603c2d6a8ada39b2e07be545da684d9e40b602a0cb0d1670f3877d056deb5f0d786c4bf86
languageName: node
linkType: hard
@@ -342,14 +342,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helpers@npm:^7.24.1":
- version: 7.24.1
- resolution: "@babel/helpers@npm:7.24.1"
+"@babel/helpers@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/helpers@npm:7.24.4"
dependencies:
"@babel/template": "npm:^7.24.0"
"@babel/traverse": "npm:^7.24.1"
"@babel/types": "npm:^7.24.0"
- checksum: 10c0/b3445860ae749fc664682b291f092285e949114e8336784ae29f88eb4c176279b01cc6740005a017a0389ae4b4e928d5bbbc01de7da7e400c972e3d6f792063a
+ checksum: 10c0/747ef62b7fe87de31a2f3c19ff337a86cbb79be2f6c18af63133b614ab5a8f6da5b06ae4b06fb0e71271cb6a27efec6f8b6c9f44c60b8a18777832dc7929e6c5
languageName: node
linkType: hard
@@ -365,12 +365,24 @@ __metadata:
languageName: node
linkType: hard
-"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1":
- version: 7.24.1
- resolution: "@babel/parser@npm:7.24.1"
+"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1, @babel/parser@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/parser@npm:7.24.4"
bin:
parser: ./bin/babel-parser.js
- checksum: 10c0/d2a8b99aa5f33182b69d5569367403a40e7c027ae3b03a1f81fd8ac9b06ceb85b31f6ee4267fb90726dc2ac99909c6bdaa9cf16c379efab73d8dfe85cee32c50
+ checksum: 10c0/8381e1efead5069cb7ed2abc3a583f4a86289b2f376c75cecc69f59a8eb36df18274b1886cecf2f97a6a0dff5334b27330f58535be9b3e4e26102cc50e12eac8
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4"
+ dependencies:
+ "@babel/helper-environment-visitor": "npm:^7.22.20"
+ "@babel/helper-plugin-utils": "npm:^7.24.0"
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 10c0/9aed453a1a21e4fd29add0b4a2d82a2c6f43a47c80d28411f8327f2a714064bc93a6f622c701d263970e0d72d7901d28f7f51e91ba91a31306efe8f17c411182
languageName: node
linkType: hard
@@ -700,14 +712,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-block-scoping@npm:^7.24.1":
- version: 7.24.1
- resolution: "@babel/plugin-transform-block-scoping@npm:7.24.1"
+"@babel/plugin-transform-block-scoping@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/plugin-transform-block-scoping@npm:7.24.4"
dependencies:
"@babel/helper-plugin-utils": "npm:^7.24.0"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10c0/1a230ad95d9672626831e22df9b4838901681fa11d44c3811d71ca64ea53f5e87de2abef865f70fe62657053278d9034cc4ea3bab0fd3300bdf9e73b3f85f97a
+ checksum: 10c0/62f55fd1b60a115506e9553c3bf925179b1ab8a42dc31471c4e3ada20573a488b5c5e3317145da352493ef07f1d9750ce1f8a49cb3f39489ac1ab42e5ddc883d
languageName: node
linkType: hard
@@ -723,16 +735,16 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-class-static-block@npm:^7.24.1":
- version: 7.24.1
- resolution: "@babel/plugin-transform-class-static-block@npm:7.24.1"
+"@babel/plugin-transform-class-static-block@npm:^7.24.4":
+ version: 7.24.4
+ resolution: "@babel/plugin-transform-class-static-block@npm:7.24.4"
dependencies:
- "@babel/helper-create-class-features-plugin": "npm:^7.24.1"
+ "@babel/helper-create-class-features-plugin": "npm:^7.24.4"
"@babel/helper-plugin-utils": "npm:^7.24.0"
"@babel/plugin-syntax-class-static-block": "npm:^7.14.5"
peerDependencies:
"@babel/core": ^7.12.0
- checksum: 10c0/3095d02b7932890b82346d42200a89a56b6ca7d25a69a94242ab5b1772f18138b8e639358dd70d23add2df8b0d1640e1e13729c2c275ecce550cbe89048ba85f
+ checksum: 10c0/19dfeaf4a2ac03695034f7211a8b5ad89103b224608ac3e91791055107c5fe4d7ebe5d9fbb31b4a91265694af78762260642eb270f4b239c175984ee4b253f80
languageName: node
linkType: hard
@@ -1333,13 +1345,14 @@ __metadata:
linkType: hard
"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4":
- version: 7.24.3
- resolution: "@babel/preset-env@npm:7.24.3"
+ version: 7.24.4
+ resolution: "@babel/preset-env@npm:7.24.4"
dependencies:
- "@babel/compat-data": "npm:^7.24.1"
+ "@babel/compat-data": "npm:^7.24.4"
"@babel/helper-compilation-targets": "npm:^7.23.6"
"@babel/helper-plugin-utils": "npm:^7.24.0"
"@babel/helper-validator-option": "npm:^7.23.5"
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.4"
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.1"
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.1"
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.1"
@@ -1366,9 +1379,9 @@ __metadata:
"@babel/plugin-transform-async-generator-functions": "npm:^7.24.3"
"@babel/plugin-transform-async-to-generator": "npm:^7.24.1"
"@babel/plugin-transform-block-scoped-functions": "npm:^7.24.1"
- "@babel/plugin-transform-block-scoping": "npm:^7.24.1"
+ "@babel/plugin-transform-block-scoping": "npm:^7.24.4"
"@babel/plugin-transform-class-properties": "npm:^7.24.1"
- "@babel/plugin-transform-class-static-block": "npm:^7.24.1"
+ "@babel/plugin-transform-class-static-block": "npm:^7.24.4"
"@babel/plugin-transform-classes": "npm:^7.24.1"
"@babel/plugin-transform-computed-properties": "npm:^7.24.1"
"@babel/plugin-transform-destructuring": "npm:^7.24.1"
@@ -1418,7 +1431,7 @@ __metadata:
semver: "npm:^6.3.1"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10c0/abd6f3b6c6a71d4ff766cda5b51467677a811240d022492e651065e26ce1a8eb2067eabe5653fce80dda9c5c204fb7b89b419578d7e86eaaf7970929ee7b4885
+ checksum: 10c0/72a79d0cd38cb26f143509dd0c58db34b5b1ae90116863f55a404f0eb06a64a3cdcb1abd0b6435fafe463bbf55b82ffcf56aedee91e8d37797bf53e4ae74c413
languageName: node
linkType: hard
@@ -1483,11 +1496,11 @@ __metadata:
linkType: hard
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.7, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
- version: 7.24.1
- resolution: "@babel/runtime@npm:7.24.1"
+ version: 7.24.4
+ resolution: "@babel/runtime@npm:7.24.4"
dependencies:
regenerator-runtime: "npm:^0.14.0"
- checksum: 10c0/500c6a99ddd84f37c7bc5dbc84777af47b1372b20e879941670451d55484faf18a673c5ebee9ca2b0f36208a729417873b35b1b92e76f811620f6adf7b8cb0f1
+ checksum: 10c0/785aff96a3aa8ff97f90958e1e8a7b1d47f793b204b47c6455eaadc3f694f48c97cd5c0a921fe3596d818e71f18106610a164fb0f1c71fd68c622a58269d537c
languageName: node
linkType: hard
@@ -15354,15 +15367,15 @@ __metadata:
linkType: hard
"sass@npm:^1.62.1":
- version: 1.72.0
- resolution: "sass@npm:1.72.0"
+ version: 1.74.1
+ resolution: "sass@npm:1.74.1"
dependencies:
chokidar: "npm:>=3.0.0 <4.0.0"
immutable: "npm:^4.0.0"
source-map-js: "npm:>=0.6.2 <2.0.0"
bin:
sass: sass.js
- checksum: 10c0/7df1bb470648edc4b528976b1b165c78d4c6731f680afac7cdc8324142f1ef4304598d317d98dac747a2ae8eee17271d760def90bba072021a8b19b459336ccd
+ checksum: 10c0/4610257ee27823276ce4998a534b4ee9f313e5a0b3d3899e70e0f87096feeae4cd8dd3c2f765b52f57dd87f5dab22370ef63f95a837a189fbb9401396d5ce717
languageName: node
linkType: hard