Merge branch 'main' into glitch-soc/merge-upstream

Conflicts:
- `.github/workflows/build-image.yml`:
  Upstream switched to pushing to both DockerHub and GitHub Container
  Repository, while glitch-soc was already pushing to the latter only.
  Updated our configuration to be slightly more consistent with upstream's
  naming and styling, but kept our behavior.
- `Gemfile.lock`:
  Updated dependencies textually too close to glitch-soc only hcaptcha
  dependency.
  Updated dependencies as upstream did.
- `README.md`:
  Upstream updated its README, but we have a completely different one.
  Kept our README, though it probably should be reworked at some point.
- `app/views/auth/sessions/two_factor.html.haml`:
  Minor style fix upstream that's on a line glitch-soc removed because
  of its different theming system.
  Kept our file as is.
- `spec/controllers/health_controller_spec.rb`:
  This file apparently did not exist upstream, upstream created it with
  different contents but it is functionally the same.
  Switched to upstream's version of the file.
- `spec/presenters/instance_presenter_spec.rb`:
  Upstream changed the specs around `GITHUB_REPOSITORY`, while glitch-soc
  had its own code because it's a fork and does not have the same default
  source URL.
  Took upstream's change, but with glitch-soc's repo as the default case.
- `yarn.lock`:
  Upstream dependencies textually too close to a glitch-soc only one.
  Updated dependencies as upstream did.
This commit is contained in:
Claire
2023-03-15 09:08:12 +01:00
171 changed files with 2089 additions and 1778 deletions

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'rails_helper'
describe AccountsIndex do
describe 'Searching the index' do
before do
mock_elasticsearch_response(described_class, raw_response)
end
it 'returns results from a query' do
results = described_class.query(match: { name: 'account' })
expect(results).to eq []
end
end
def raw_response
{
took: 3,
hits: {
hits: [
{
_id: '0',
_score: 1.6375021,
},
],
},
}
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'rails_helper'
describe StatusesIndex do
describe 'Searching the index' do
before do
mock_elasticsearch_response(described_class, raw_response)
end
it 'returns results from a query' do
results = described_class.query(match: { name: 'status' })
expect(results).to eq []
end
end
def raw_response
{
took: 3,
hits: {
hits: [
{
_id: '0',
_score: 1.6375021,
},
],
},
}
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'rails_helper'
describe TagsIndex do
describe 'Searching the index' do
before do
mock_elasticsearch_response(described_class, raw_response)
end
it 'returns results from a query' do
results = described_class.query(match: { name: 'tag' })
expect(results).to eq []
end
end
def raw_response
{
took: 3,
hits: {
hits: [
{
_id: '0',
_score: 1.6375021,
},
],
},
}
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::ClaimsController do
let(:account) { Fabricate(:account) }
describe 'POST #create' do
context 'without signature' do
before do
post :create, params: { account_username: account.username }, body: '{}'
end
it 'returns http not authorized' do
expect(response).to have_http_status(401)
end
end
end
end

View File

@@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V2::InstancesController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
it 'returns http success' do
get :show
expect(response).to have_http_status(200)
end
end
end

View File

@@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V2::SuggestionsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index
expect(response).to have_http_status(200)
end
end
end

View File

@@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'rails_helper'
describe Auth::SetupController do
render_views
describe 'GET #show' do
context 'with a signed out request' do
it 'returns http redirect' do
get :show
expect(response).to be_redirect
end
end
context 'with an unconfirmed signed in user' do
before { sign_in Fabricate(:user, confirmed_at: nil) }
it 'returns http success' do
get :show
expect(response).to have_http_status(200)
end
end
end
end

View File

@@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
describe CustomCssController do
render_views
describe 'GET #show' do
it 'returns http success' do
get :show
expect(response).to have_http_status(200)
end
end
end

View File

@@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'rails_helper'
describe Filters::StatusesController do
render_views
describe 'GET #index' do
let(:filter) { Fabricate(:custom_filter) }
context 'with signed out user' do
it 'redirects' do
get :index, params: { filter_id: filter }
expect(response).to be_redirect
end
end
context 'with a signed in user' do
context 'with the filter user signed in' do
before { sign_in(filter.account.user) }
it 'returns http success' do
get :index, params: { filter_id: filter }
expect(response).to have_http_status(200)
end
end
context 'with another user signed in' do
before { sign_in(Fabricate(:user)) }
it 'returns http not found' do
get :index, params: { filter_id: filter }
expect(response).to have_http_status(404)
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
require 'rails_helper'
describe FiltersController do
render_views
describe 'GET #index' do
context 'with signed out user' do
it 'redirects' do
get :index
expect(response).to be_redirect
end
end
context 'with a signed in user' do
before { sign_in(Fabricate(:user)) }
it 'returns http success' do
get :index
expect(response).to have_http_status(200)
end
end
end
end

View File

@@ -1,13 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
describe HealthController do
render_views
describe 'GET #show' do
subject(:response) { get :show, params: { format: :json } }
it 'returns the right response' do
expect(response).to have_http_status 200
it 'returns http success' do
get :show
expect(response).to have_http_status(200)
end
end
end

View File

@@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
describe PrivacyController do
render_views
describe 'GET #show' do
it 'returns http success' do
get :show
expect(response).to have_http_status(200)
end
end
end

View File

@@ -248,7 +248,7 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do
post :create, params: { credential: new_webauthn_credential, nickname: 'USB Key' }
expect(response).to have_http_status(500)
expect(response).to have_http_status(422)
expect(flash[:error]).to be_present
end
end
@@ -268,7 +268,7 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do
post :create, params: { credential: new_webauthn_credential, nickname: nickname }
expect(response).to have_http_status(500)
expect(response).to have_http_status(422)
expect(flash[:error]).to be_present
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
Fabricator(:encrypted_message) do
device
from_account { Fabricate(:account) }
from_device_id { Faker::Number.number(digits: 5) }
end

View File

@@ -2,7 +2,33 @@
require 'rails_helper'
RSpec.describe StatusesHelper, type: :helper do
describe StatusesHelper do
describe 'status_text_summary' do
context 'with blank text' do
let(:status) { Status.new(spoiler_text: '') }
it 'returns immediately with nil' do
result = helper.status_text_summary(status)
expect(result).to be_nil
end
end
context 'with present text' do
let(:status) { Status.new(spoiler_text: 'SPOILERS!!!') }
it 'returns the content warning' do
result = helper.status_text_summary(status)
expect(result).to eq(I18n.t('statuses.content_warning', warning: 'SPOILERS!!!'))
end
end
end
def status_text_summary(status)
return if status.spoiler_text.blank?
I18n.t('statuses.content_warning', warning: status.spoiler_text)
end
describe 'link_to_newer' do
it 'returns a link to newer content' do
url = 'https://example.com'

View File

@@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
describe Importer::BaseImporter do
describe 'import!' do
let(:pool) { Concurrent::FixedThreadPool.new(5) }
let(:importer) { described_class.new(batch_size: 123, executor: pool) }
it 'raises an error' do
expect { importer.import! }.to raise_error(NotImplementedError)
end
end
end

View File

@@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'rails_helper'
require 'cli'
describe Mastodon::CLI do
describe 'version' do
it 'returns the Mastodon version' do
expect { described_class.new.invoke(:version) }.to output(
a_string_including(Mastodon::Version.to_s)
).to_stdout
end
end
end

View File

@@ -6,7 +6,7 @@ RSpec.describe PlainTextFormatter do
describe '#to_s' do
subject { described_class.new(status.text, status.local?).to_s }
context 'given a post with local status' do
context 'when status is local' do
let(:status) { Fabricate(:status, text: '<p>a text by a nerd who uses an HTML tag in text</p>', uri: nil) }
it 'returns the raw text' do
@@ -14,12 +14,63 @@ RSpec.describe PlainTextFormatter do
end
end
context 'given a post with remote status' do
context 'when status is remote' do
let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') }
let(:status) { Fabricate(:status, account: remote_account, text: '<p>Hello</p><script>alert("Hello")</script>') }
it 'returns tag-stripped text' do
expect(subject).to eq 'Hello'
context 'when text contains inline HTML tags' do
let(:status) { Fabricate(:status, account: remote_account, text: '<b>Lorem</b> <em>ipsum</em>') }
it 'strips the tags' do
expect(subject).to eq 'Lorem ipsum'
end
end
context 'when text contains <p> tags' do
let(:status) { Fabricate(:status, account: remote_account, text: '<p>Lorem</p><p>ipsum</p>') }
it 'inserts a newline' do
expect(subject).to eq "Lorem\nipsum"
end
end
context 'when text contains a single <br> tag' do
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem<br>ipsum') }
it 'inserts a newline' do
expect(subject).to eq "Lorem\nipsum"
end
end
context 'when text contains consecutive <br> tag' do
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem<br><br><br>ipsum') }
it 'inserts a single newline' do
expect(subject).to eq "Lorem\nipsum"
end
end
context 'when text contains HTML entity' do
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem &amp; ipsum &#x2764;') }
it 'unescapes the entity' do
expect(subject).to eq 'Lorem & ipsum ❤'
end
end
context 'when text contains <script> tag' do
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem <script> alert("Booh!") </script>ipsum') }
it 'strips the tag and its contents' do
expect(subject).to eq 'Lorem ipsum'
end
end
context 'when text contains an HTML comment tags' do
let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem <!-- Booh! -->ipsum') }
it 'strips the comment' do
expect(subject).to eq 'Lorem ipsum'
end
end
end
end

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'rails_helper'
describe SearchQueryTransformer do
describe 'initialization' do
let(:parser) { SearchQueryParser.new.parse('query') }
it 'sets attributes' do
transformer = described_class.new.apply(parser)
expect(transformer.should_clauses.first).to be_a(SearchQueryTransformer::TermClause)
expect(transformer.must_clauses.first).to be_nil
expect(transformer.must_not_clauses.first).to be_nil
expect(transformer.filter_clauses.first).to be_nil
end
end
end

View File

@@ -0,0 +1,16 @@
# frozen_string_literal: true
require 'rails_helper'
describe Admin::AppealFilter do
describe '#results' do
let(:approved_appeal) { Fabricate(:appeal, approved_at: 10.days.ago) }
let(:not_approved_appeal) { Fabricate(:appeal, approved_at: nil) }
it 'returns filtered appeals' do
filter = described_class.new(status: 'approved')
expect(filter.results).to eq([approved_appeal])
end
end
end

View File

@@ -0,0 +1,36 @@
# frozen_string_literal: true
require 'rails_helper'
describe Form::AdminSettings do
describe 'validations' do
describe 'site_contact_username' do
context 'with no accounts' do
it 'is not valid' do
setting = described_class.new(site_contact_username: 'Test')
setting.valid?
expect(setting).to model_have_error_on_field(:site_contact_username)
end
end
context 'with an account' do
before { Fabricate(:account, username: 'Glorp') }
it 'is not valid when account doesnt match' do
setting = described_class.new(site_contact_username: 'Test')
setting.valid?
expect(setting).to model_have_error_on_field(:site_contact_username)
end
it 'is valid when account matches' do
setting = described_class.new(site_contact_username: 'Glorp')
setting.valid?
expect(setting).to_not model_have_error_on_field(:site_contact_username)
end
end
end
end
end

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'rails_helper'
describe Form::StatusFilterBatchAction do
describe '#save!' do
it 'does nothing if status_filter_ids is empty' do
batch_action = described_class.new(status_filter_ids: [])
expect(batch_action.save!).to be_nil
end
end
end

View File

@@ -89,8 +89,28 @@ describe InstancePresenter do
end
describe '#source_url' do
it 'returns "https://github.com/glitch-soc/mastodon"' do
expect(instance_presenter.source_url).to eq('https://github.com/glitch-soc/mastodon')
context 'with the GITHUB_REPOSITORY env variable set' do
around do |example|
ClimateControl.modify GITHUB_REPOSITORY: 'other/repo' do
example.run
end
end
it 'uses the env variable to build a repo URL' do
expect(instance_presenter.source_url).to eq('https://github.com/other/repo')
end
end
context 'without the GITHUB_REPOSITORY env variable set' do
around do |example|
ClimateControl.modify GITHUB_REPOSITORY: nil do
example.run
end
end
it 'defaults to the core glitch-soc repo URL' do
expect(instance_presenter.source_url).to eq('https://github.com/glitch-soc/mastodon')
end
end
end

View File

@@ -10,6 +10,7 @@ require 'rspec/rails'
require 'webmock/rspec'
require 'paperclip/matchers'
require 'capybara/rspec'
require 'chewy/rspec'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
@@ -45,6 +46,7 @@ RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :view
config.include Paperclip::Shoulda::Matchers
config.include ActiveSupport::Testing::TimeHelpers
config.include Chewy::Rspec::Helpers
config.include Redisable
config.before :each, type: :feature do

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::DeviceSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Fabricate(:device) }
describe 'type' do
it 'returns correct serialized type' do
expect(serialization['type']).to eq('Device')
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::OneTimeKeySerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Fabricate(:one_time_key) }
describe 'type' do
it 'returns correct serialized type' do
expect(serialization['type']).to eq('Curve25519Key')
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::UndoLikeSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Fabricate(:favourite) }
describe 'type' do
it 'returns correct serialized type' do
expect(serialization['type']).to eq('Undo')
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe ActivityPub::VoteSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Fabricate(:poll_vote) }
describe 'type' do
it 'returns correct serialized type' do
expect(serialization['type']).to eq('Create')
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe REST::EncryptedMessageSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Fabricate(:encrypted_message) }
describe 'account' do
it 'returns the associated account' do
expect(serialization['account_id']).to eq(record.from_account.id.to_s)
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe REST::InstanceSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { InstancePresenter.new }
describe 'usage' do
it 'returns recent usage data' do
expect(serialization['usage']).to eq({ 'users' => { 'active_month' => 0 } })
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe REST::Keys::ClaimResultSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Keys::ClaimService::Result.new(Account.new(id: 123), 456) }
describe 'account' do
it 'returns the associated account' do
expect(serialization['account_id']).to eq('123')
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe REST::Keys::DeviceSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Device.new(name: 'Device name') }
describe 'name' do
it 'returns the name' do
expect(serialization['name']).to eq('Device name')
end
end
end

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'rails_helper'
describe REST::Keys::QueryResultSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) { Keys::QueryService::Result.new(Account.new(id: 123), []) }
describe 'account' do
it 'returns the associated account id' do
expect(serialization['account_id']).to eq('123')
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'rails_helper'
describe REST::SuggestionSerializer do
let(:serialization) do
JSON.parse(
ActiveModelSerializers::SerializableResource.new(
record, serializer: described_class
).to_json
)
end
let(:record) do
AccountSuggestions::Suggestion.new(
account: account,
source: 'SuggestionSource'
)
end
let(:account) { Fabricate(:account) }
describe 'account' do
it 'returns the associated account' do
expect(serialization['account']['id']).to eq(account.id.to_s)
end
end
end

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'rails_helper'
describe VerifyAccountLinksWorker do
let(:worker) { described_class.new }
describe 'perform' do
it 'runs without error for missing record' do
expect { worker.perform(nil) }.to_not raise_error
end
end
end