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

Conflicts:
- `README.md`:
  Upstream added a link to the roadmap, but we have a completely different README.
  Kept ours.
- `app/models/media_attachment.rb`:
  Upstream upped media attachment limits.
  Updated the default according to upstream's.
- `db/migrate/20180831171112_create_bookmarks.rb`:
  Upstream changed the migration compatibility level.
  Did so too.
- `config/initializers/content_security_policy.rb`:
  Upstream refactored this file but we have a different version.
  Kept our version.
- `app/controllers/settings/preferences_controller.rb`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  The file does not directly references individual settings anymore.
  Applied upstream changes.
- `app/lib/user_settings_decorator.rb`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  The file got removed entirely.
  Removed it as well.
- `app/models/user.rb`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  References to individual settings have been removed from the file.
  Removed them as well.
- `app/views/settings/preferences/appearance/show.html.haml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  Applied upstream's changes and ported ours back.
- `app/views/settings/preferences/notifications/show.html.haml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  Applied upstream's changes and ported ours back.
- `app/views/settings/preferences/other/show.html.haml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  Applied upstream's changes and ported ours back.
- `config/settings.yml`:
  Upstream completely refactored user settings storage, and glitch-soc has a
  different set of settings.
  In particular, upstream removed user-specific and unused settings.
  Did the same in glitch-soc.
- `spec/controllers/application_controller_spec.rb`:
  Conflicts due to glitch-soc's theming system.
  Mostly kept our version, as upstream messed up the tests.
pull/59/head
Claire 2023-03-31 21:30:27 +02:00
commit 01d6f7529f
341 changed files with 4055 additions and 2756 deletions

View File

@ -1,39 +0,0 @@
version: '2'
checks:
argument-count:
enabled: false
complex-logic:
enabled: false
file-lines:
enabled: false
method-complexity:
enabled: false
method-count:
enabled: false
method-lines:
enabled: false
nested-control-flow:
enabled: false
return-statements:
enabled: false
similar-code:
enabled: false
identical-code:
enabled: false
plugins:
brakeman:
enabled: true
bundler-audit:
enabled: false
eslint:
enabled: false
rubocop:
enabled: false
sass-lint:
enabled: false
exclude_patterns:
- spec/
- vendor/asset/
- app/javascript/mastodon/locales/**/*.json
- config/locales/**/*.yml

View File

@ -15,6 +15,7 @@
"forwardPorts": [3000, 4000],
// Use 'postCreateCommand' to run commands after the container is created.
"onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
"postCreateCommand": ".devcontainer/post-create.sh",
"waitFor": "postCreateCommand",

View File

@ -10,7 +10,7 @@ services:
environment:
RAILS_ENV: development
NODE_ENV: development
BIND: 0.0.0.0
REDIS_HOST: redis
REDIS_PORT: '6379'
DB_HOST: db
@ -23,6 +23,10 @@ services:
LIBRE_TRANSLATE_ENDPOINT: http://libretranslate:5000
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
ports:
- '127.0.0.1:3000:3000'
- '127.0.0.1:4000:4000'
- '127.0.0.1:80:3000'
networks:
- external_network
- internal_network
@ -66,15 +70,19 @@ services:
hard: -1
libretranslate:
image: libretranslate/libretranslate:v1.2.9
image: libretranslate/libretranslate:v1.3.10
restart: unless-stopped
volumes:
- lt-data:/home/libretranslate/.local
networks:
- external_network
- internal_network
volumes:
postgres-data:
redis-data:
es-data:
lt-data:
networks:
external_network:

View File

@ -14,6 +14,9 @@ git checkout -- Gemfile.lock
# [re]create, migrate, and seed the test database
RAILS_ENV=test ./bin/rails db:setup
# [re]create, migrate, and seed the development database
RAILS_ENV=development ./bin/rails db:setup
# Precompile assets for development
RAILS_ENV=development ./bin/rails assets:precompile

View File

@ -30,7 +30,9 @@ jobs:
uses: actions/checkout@v3
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1

View File

@ -16,7 +16,7 @@ jobs:
- id: skip_check
uses: fkirc/skip-duplicate-actions@v5
with:
paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-one-step.yml"]'
paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-one-step.yml", "lib/tasks/tests.rake"]'
test:
runs-on: ubuntu-latest
@ -64,7 +64,9 @@ jobs:
- uses: actions/checkout@v3
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1

View File

@ -16,7 +16,7 @@ jobs:
- id: skip_check
uses: fkirc/skip-duplicate-actions@v5
with:
paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-two-step.yml"]'
paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-two-step.yml", "lib/tasks/tests.rake"]'
test:
runs-on: ubuntu-latest
@ -63,7 +63,9 @@ jobs:
- uses: actions/checkout@v3
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1

View File

@ -32,7 +32,9 @@ jobs:
node-version-file: '.nvmrc'
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
@ -119,6 +121,9 @@ jobs:
path: './public'
name: ${{ github.sha }}
- name: Update package index
run: sudo apt-get update
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged

View File

@ -1,5 +1,7 @@
# Can be removed once all rules are addressed or moved to this file as documented overrides
inherit_from: .rubocop_todo.yml
# Used for merging with exclude lists with .rubocop_todo.yml
inherit_mode:
merge:
- Exclude
@ -11,13 +13,13 @@ require:
- rubocop-capybara
AllCops:
TargetRubyVersion: 2.7
TargetRubyVersion: 2.7 # Set to minimum supported version of CI
DisplayCopNames: true
DisplayStyleGuide: true
ExtraDetails: true
UseCache: true
CacheRootDirectory: tmp
NewCops: enable
NewCops: enable # Opt-in to newly added rules
Exclude:
- db/schema.rb
- 'bin/*'
@ -25,12 +27,16 @@ AllCops:
- 'node_modules/**/*'
- 'Vagrantfile'
- 'vendor/**/*'
- 'lib/json_ld/*'
- 'lib/json_ld/*' # Generated files
- 'lib/templates/**/*'
# Reason: Prefer Hashes without extreme indentation
# https://docs.rubocop.org/rubocop/cops_layout.html#layoutfirsthashelementindentation
Layout/FirstHashElementIndentation:
EnforcedStyle: consistent
# Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength
Layout/LineLength:
AllowedPatterns:
# Allow comments to be long lines
@ -41,20 +47,50 @@ Layout/LineLength:
- db/*migrate/**/*
- db/seeds/**/*
# Reason:
# https://docs.rubocop.org/rubocop/cops_lint.html#lintuselessaccessmodifier
Lint/UselessAccessModifier:
ContextCreatingMethods:
- class_methods
# Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsabcsize
Metrics/AbcSize:
Exclude:
- 'lib/**/*cli*.rb'
- db/*migrate/**/*
# Reason: Some functions cannot be broken up, but others may be refactor candidates
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsblocklength
Metrics/BlockLength:
CountAsOne: [array, heredoc]
CountAsOne: ['array', 'hash', 'heredoc', 'method_call']
Exclude:
- 'lib/mastodon/*_cli.rb'
- 'lib/tasks/*.rake'
- 'app/models/concerns/account_associations.rb'
- 'app/models/concerns/account_interactions.rb'
- 'app/models/concerns/ldap_authenticable.rb'
- 'app/models/concerns/omniauthable.rb'
- 'app/models/concerns/pam_authenticable.rb'
- 'app/models/concerns/remotable.rb'
- 'app/services/suspend_account_service.rb'
- 'app/services/unsuspend_account_service.rb'
- 'app/views/accounts/show.rss.ruby'
- 'app/views/tags/show.rss.ruby'
- 'config/environments/development.rb'
- 'config/environments/production.rb'
- 'config/initializers/devise.rb'
- 'config/initializers/doorkeeper.rb'
- 'config/initializers/omniauth.rb'
- 'config/initializers/simple_form.rb'
- 'config/navigation.rb'
- 'config/routes.rb'
- 'db/post_migrate/20221101190723_backfill_admin_action_logs.rb'
- 'db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb'
- 'lib/paperclip/gif_transcoder.rb'
# Reason:
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsblocknesting
Metrics/BlockNesting:
Exclude:
- 'lib/mastodon/*_cli.rb'
@ -103,22 +139,32 @@ Metrics/ClassLength:
- 'app/services/update_status_service.rb'
- 'lib/paperclip/color_extractor.rb'
# Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity
Metrics/CyclomaticComplexity:
Exclude:
- lib/mastodon/*cli*.rb
- db/*migrate/**/*
# Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmethodlength
Metrics/MethodLength:
CountAsOne: [array, heredoc]
Exclude:
- 'lib/mastodon/*_cli.rb'
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror
Metrics/ModuleLength:
CountAsOne: [array, heredoc]
# Reason: Prevailing style uses numeric status codes, matches RSpec/Rails/HttpStatus
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railshttpstatus
Rails/HttpStatus:
EnforcedStyle: numeric
# Reason: Allowed only in the `tootctl` CLI application code
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit
Rails/Exit:
Exclude:
- 'lib/mastodon/*_cli.rb'
@ -146,9 +192,18 @@ RSpec/FilePath:
- 'spec/controllers/concerns/signature_verification_spec.rb'
- 'spec/controllers/concerns/user_tracking_concern_spec.rb'
# Reason:
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnamedsubject
RSpec/NamedSubject:
EnforcedStyle: named_only
# Reason: Prevailing style choice
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnottonot
RSpec/NotToNot:
EnforcedStyle: to_not
# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
RSpec/Rails/HttpStatus:
EnforcedStyle: numeric
@ -162,26 +217,45 @@ Style/ClassAndModuleChildren:
Style/Documentation:
Enabled: false
# Reason: Enforce modern Ruby style
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals
Style/NumericLiterals:
AllowedPatterns:
- \d{4}_\d{2}_\d{2}_\d{6} # For DB migration date version number readability
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#stylepercentliteraldelimiters
Style/PercentLiteralDelimiters:
PreferredDelimiters:
'%i': '()'
'%w': '()'
# Reason: Prefer less indentation in conditional assignments
# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantbegin
Style/RedundantBegin:
Enabled: false
# Reason: Overridden to reduce implicit StandardError rescues
# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror
Style/RescueStandardError:
EnforcedStyle: implicit
# Reason: Originally disabled for CodeClimate, and no config consensus has been found
# https://docs.rubocop.org/rubocop/cops_style.html#stylesymbolarray
Style/SymbolArray:
Enabled: false
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#styletrailingcommainarrayliteral
Style/TrailingCommaInArrayLiteral:
EnforcedStyleForMultiline: 'comma'
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#styletrailingcommainhashliteral
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: 'comma'
Style/SymbolArray:
Enabled: false

View File

@ -117,7 +117,6 @@ Lint/ConstantDefinitionInBlock:
- 'spec/lib/activitypub/adapter_spec.rb'
- 'spec/lib/connection_pool/shared_connection_pool_spec.rb'
- 'spec/lib/connection_pool/shared_timed_stack_spec.rb'
- 'spec/lib/settings/extend_spec.rb'
- 'spec/models/concerns/remotable_spec.rb'
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches.
@ -233,11 +232,6 @@ Lint/Void:
Metrics/AbcSize:
Max: 150
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
# AllowedMethods: refine
Metrics/BlockLength:
Max: 544
# Configuration parameters: CountBlocks, Max.
Metrics/BlockNesting:
Exclude:
@ -259,6 +253,7 @@ Metrics/ModuleLength:
- 'app/helpers/jsonld_helper.rb'
- 'app/helpers/statuses_helper.rb'
- 'app/models/concerns/account_interactions.rb'
- 'app/models/concerns/has_user_settings.rb'
# Configuration parameters: Max, CountKeywordArgs, MaxOptionalParameters.
Metrics/ParameterLists:
@ -730,7 +725,6 @@ RSpec/LeakyConstantDeclaration:
- 'spec/lib/activitypub/adapter_spec.rb'
- 'spec/lib/connection_pool/shared_connection_pool_spec.rb'
- 'spec/lib/connection_pool/shared_timed_stack_spec.rb'
- 'spec/lib/settings/extend_spec.rb'
- 'spec/models/concerns/remotable_spec.rb'
RSpec/LetSetup:
@ -880,204 +874,6 @@ RSpec/MultipleSubjects:
- 'spec/controllers/follower_accounts_controller_spec.rb'
- 'spec/controllers/following_accounts_controller_spec.rb'
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
# SupportedStyles: always, named_only
RSpec/NamedSubject:
Exclude:
- 'spec/controllers/admin/account_moderation_notes_controller_spec.rb'
- 'spec/controllers/admin/accounts_controller_spec.rb'
- 'spec/controllers/admin/confirmations_controller_spec.rb'
- 'spec/controllers/admin/custom_emojis_controller_spec.rb'
- 'spec/controllers/admin/domain_blocks_controller_spec.rb'
- 'spec/controllers/admin/instances_controller_spec.rb'
- 'spec/controllers/admin/invites_controller_spec.rb'
- 'spec/controllers/admin/report_notes_controller_spec.rb'
- 'spec/controllers/api/v1/accounts/notes_controller_spec.rb'
- 'spec/controllers/api/v1/accounts/pins_controller_spec.rb'
- 'spec/controllers/api/v1/admin/domain_blocks_controller_spec.rb'
- 'spec/controllers/auth/passwords_controller_spec.rb'
- 'spec/controllers/auth/registrations_controller_spec.rb'
- 'spec/controllers/home_controller_spec.rb'
- 'spec/controllers/invites_controller_spec.rb'
- 'spec/controllers/oauth/authorizations_controller_spec.rb'
- 'spec/controllers/oauth/authorized_applications_controller_spec.rb'
- 'spec/controllers/relationships_controller_spec.rb'
- 'spec/controllers/settings/featured_tags_controller_spec.rb'
- 'spec/controllers/settings/migrations_controller_spec.rb'
- 'spec/controllers/settings/sessions_controller_spec.rb'
- 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb'
- 'spec/controllers/well_known/webfinger_controller_spec.rb'
- 'spec/features/log_in_spec.rb'
- 'spec/features/profile_spec.rb'
- 'spec/lib/activitypub/activity/accept_spec.rb'
- 'spec/lib/activitypub/activity/add_spec.rb'
- 'spec/lib/activitypub/activity/announce_spec.rb'
- 'spec/lib/activitypub/activity/block_spec.rb'
- 'spec/lib/activitypub/activity/create_spec.rb'
- 'spec/lib/activitypub/activity/delete_spec.rb'
- 'spec/lib/activitypub/activity/flag_spec.rb'
- 'spec/lib/activitypub/activity/follow_spec.rb'
- 'spec/lib/activitypub/activity/like_spec.rb'
- 'spec/lib/activitypub/activity/move_spec.rb'
- 'spec/lib/activitypub/activity/reject_spec.rb'
- 'spec/lib/activitypub/activity/remove_spec.rb'
- 'spec/lib/activitypub/activity/undo_spec.rb'
- 'spec/lib/activitypub/activity/update_spec.rb'
- 'spec/lib/activitypub/adapter_spec.rb'
- 'spec/lib/activitypub/dereferencer_spec.rb'
- 'spec/lib/activitypub/linked_data_signature_spec.rb'
- 'spec/lib/activitypub/tag_manager_spec.rb'
- 'spec/lib/connection_pool/shared_connection_pool_spec.rb'
- 'spec/lib/connection_pool/shared_timed_stack_spec.rb'
- 'spec/lib/delivery_failure_tracker_spec.rb'
- 'spec/lib/emoji_formatter_spec.rb'
- 'spec/lib/entity_cache_spec.rb'
- 'spec/lib/fast_ip_map_spec.rb'
- 'spec/lib/feed_manager_spec.rb'
- 'spec/lib/hashtag_normalizer_spec.rb'
- 'spec/lib/html_aware_formatter_spec.rb'
- 'spec/lib/link_details_extractor_spec.rb'
- 'spec/lib/ostatus/tag_manager_spec.rb'
- 'spec/lib/plain_text_formatter_spec.rb'
- 'spec/lib/request_pool_spec.rb'
- 'spec/lib/request_spec.rb'
- 'spec/lib/sanitize_config_spec.rb'
- 'spec/lib/status_finder_spec.rb'
- 'spec/lib/status_reach_finder_spec.rb'
- 'spec/lib/suspicious_sign_in_detector_spec.rb'
- 'spec/lib/text_formatter_spec.rb'
- 'spec/lib/vacuum/access_tokens_vacuum_spec.rb'
- 'spec/lib/vacuum/backups_vacuum_spec.rb'
- 'spec/lib/vacuum/feeds_vacuum_spec.rb'
- 'spec/lib/vacuum/media_attachments_vacuum_spec.rb'
- 'spec/lib/vacuum/preview_cards_vacuum_spec.rb'
- 'spec/lib/vacuum/statuses_vacuum_spec.rb'
- 'spec/lib/vacuum/system_keys_vacuum_spec.rb'
- 'spec/models/account/field_spec.rb'
- 'spec/models/account_migration_spec.rb'
- 'spec/models/account_spec.rb'
- 'spec/models/account_statuses_cleanup_policy_spec.rb'
- 'spec/models/account_statuses_filter_spec.rb'
- 'spec/models/admin/account_action_spec.rb'
- 'spec/models/canonical_email_block_spec.rb'
- 'spec/models/concerns/account_interactions_spec.rb'
- 'spec/models/custom_emoji_filter_spec.rb'
- 'spec/models/custom_emoji_spec.rb'
- 'spec/models/follow_spec.rb'
- 'spec/models/home_feed_spec.rb'
- 'spec/models/media_attachment_spec.rb'
- 'spec/models/notification_spec.rb'
- 'spec/models/public_feed_spec.rb'
- 'spec/models/relationship_filter_spec.rb'
- 'spec/models/remote_follow_spec.rb'
- 'spec/models/report_spec.rb'
- 'spec/models/session_activation_spec.rb'
- 'spec/models/setting_spec.rb'
- 'spec/models/status_spec.rb'
- 'spec/models/tag_spec.rb'
- 'spec/models/trends/statuses_spec.rb'
- 'spec/models/trends/tags_spec.rb'
- 'spec/models/user_role_spec.rb'
- 'spec/models/user_spec.rb'
- 'spec/models/web/push_subscription_spec.rb'
- 'spec/policies/account_moderation_note_policy_spec.rb'
- 'spec/policies/account_policy_spec.rb'
- 'spec/policies/backup_policy_spec.rb'
- 'spec/policies/custom_emoji_policy_spec.rb'
- 'spec/policies/domain_block_policy_spec.rb'
- 'spec/policies/email_domain_block_policy_spec.rb'
- 'spec/policies/instance_policy_spec.rb'
- 'spec/policies/invite_policy_spec.rb'
- 'spec/policies/relay_policy_spec.rb'
- 'spec/policies/report_note_policy_spec.rb'
- 'spec/policies/report_policy_spec.rb'
- 'spec/policies/settings_policy_spec.rb'
- 'spec/policies/status_policy_spec.rb'
- 'spec/policies/tag_policy_spec.rb'
- 'spec/policies/user_policy_spec.rb'
- 'spec/presenters/familiar_followers_presenter_spec.rb'
- 'spec/serializers/activitypub/note_serializer_spec.rb'
- 'spec/serializers/activitypub/update_poll_serializer_spec.rb'
- 'spec/serializers/rest/account_serializer_spec.rb'
- 'spec/services/account_search_service_spec.rb'
- 'spec/services/account_statuses_cleanup_service_spec.rb'
- 'spec/services/activitypub/fetch_remote_account_service_spec.rb'
- 'spec/services/activitypub/fetch_remote_actor_service_spec.rb'
- 'spec/services/activitypub/fetch_remote_status_service_spec.rb'
- 'spec/services/activitypub/fetch_replies_service_spec.rb'
- 'spec/services/activitypub/process_account_service_spec.rb'
- 'spec/services/activitypub/process_collection_service_spec.rb'
- 'spec/services/activitypub/process_status_update_service_spec.rb'
- 'spec/services/after_block_domain_from_account_service_spec.rb'
- 'spec/services/after_block_service_spec.rb'
- 'spec/services/app_sign_up_service_spec.rb'
- 'spec/services/authorize_follow_service_spec.rb'
- 'spec/services/batched_remove_status_service_spec.rb'
- 'spec/services/block_domain_service_spec.rb'
- 'spec/services/block_service_spec.rb'
- 'spec/services/bootstrap_timeline_service_spec.rb'
- 'spec/services/clear_domain_media_service_spec.rb'
- 'spec/services/delete_account_service_spec.rb'
- 'spec/services/fan_out_on_write_service_spec.rb'
- 'spec/services/favourite_service_spec.rb'
- 'spec/services/fetch_link_card_service_spec.rb'
- 'spec/services/fetch_oembed_service_spec.rb'
- 'spec/services/fetch_remote_status_service_spec.rb'
- 'spec/services/fetch_resource_service_spec.rb'
- 'spec/services/follow_service_spec.rb'
- 'spec/services/import_service_spec.rb'
- 'spec/services/mute_service_spec.rb'
- 'spec/services/notify_service_spec.rb'
- 'spec/services/post_status_service_spec.rb'
- 'spec/services/precompute_feed_service_spec.rb'
- 'spec/services/process_mentions_service_spec.rb'
- 'spec/services/purge_domain_service_spec.rb'
- 'spec/services/reblog_service_spec.rb'
- 'spec/services/reject_follow_service_spec.rb'
- 'spec/services/remove_from_followers_service_spec.rb'
- 'spec/services/remove_status_service_spec.rb'
- 'spec/services/report_service_spec.rb'
- 'spec/services/resolve_account_service_spec.rb'
- 'spec/services/resolve_url_service_spec.rb'
- 'spec/services/search_service_spec.rb'
- 'spec/services/suspend_account_service_spec.rb'
- 'spec/services/unallow_domain_service_spec.rb'
- 'spec/services/unblock_domain_service_spec.rb'
- 'spec/services/unblock_service_spec.rb'
- 'spec/services/unfollow_service_spec.rb'
- 'spec/services/unsuspend_account_service_spec.rb'
- 'spec/services/update_account_service_spec.rb'
- 'spec/services/update_status_service_spec.rb'
- 'spec/services/verify_link_service_spec.rb'
- 'spec/validators/blacklisted_email_validator_spec.rb'
- 'spec/validators/email_mx_validator_spec.rb'
- 'spec/validators/note_length_validator_spec.rb'
- 'spec/validators/reaction_validator_spec.rb'
- 'spec/validators/status_length_validator_spec.rb'
- 'spec/validators/status_pin_validator_spec.rb'
- 'spec/validators/unique_username_validator_spec.rb'
- 'spec/workers/activitypub/delivery_worker_spec.rb'
- 'spec/workers/activitypub/distribute_poll_update_worker_spec.rb'
- 'spec/workers/activitypub/distribution_worker_spec.rb'
- 'spec/workers/activitypub/fetch_replies_worker_spec.rb'
- 'spec/workers/activitypub/move_distribution_worker_spec.rb'
- 'spec/workers/activitypub/processing_worker_spec.rb'
- 'spec/workers/activitypub/status_update_distribution_worker_spec.rb'
- 'spec/workers/activitypub/update_distribution_worker_spec.rb'
- 'spec/workers/admin/domain_purge_worker_spec.rb'
- 'spec/workers/domain_block_worker_spec.rb'
- 'spec/workers/domain_clear_media_worker_spec.rb'
- 'spec/workers/feed_insert_worker_spec.rb'
- 'spec/workers/move_worker_spec.rb'
- 'spec/workers/publish_scheduled_announcement_worker_spec.rb'
- 'spec/workers/publish_scheduled_status_worker_spec.rb'
- 'spec/workers/refollow_worker_spec.rb'
- 'spec/workers/regeneration_worker_spec.rb'
- 'spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb'
- 'spec/workers/scheduler/user_cleanup_scheduler_spec.rb'
- 'spec/workers/unfollow_follow_worker_spec.rb'
- 'spec/workers/web/push_notification_worker_spec.rb'
# Configuration parameters: AllowedGroups.
RSpec/NestedGroups:
Max: 6
@ -1476,7 +1272,6 @@ Rails/CompactBlank:
- 'app/helpers/statuses_helper.rb'
- 'app/models/concerns/attachmentable.rb'
- 'app/models/poll.rb'
- 'app/models/user.rb'
- 'app/services/import_service.rb'
- 'config/initializers/paperclip.rb'
@ -1527,7 +1322,6 @@ Rails/FilePath:
- 'app/validators/reaction_validator.rb'
- 'config/environments/test.rb'
- 'db/migrate/20170716191202_add_hide_notifications_to_mute.rb'
- 'db/migrate/20170918125918_ids_to_bigints.rb'
- 'db/migrate/20171005171936_add_disabled_to_custom_emojis.rb'
- 'db/migrate/20171028221157_add_reblogs_to_follows.rb'
- 'db/migrate/20171107143332_add_memorial_to_accounts.rb'
@ -1637,18 +1431,6 @@ Rails/I18nLocaleTexts:
- 'lib/tasks/mastodon.rake'
- 'spec/helpers/flashes_helper_spec.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/IgnoredColumnsAssignment:
Exclude:
- 'app/models/account.rb'
- 'app/models/account_stat.rb'
- 'app/models/admin/action_log.rb'
- 'app/models/custom_filter.rb'
- 'app/models/email_domain_block.rb'
- 'app/models/report.rb'
- 'app/models/status_edit.rb'
- 'app/models/user.rb'
# Configuration parameters: IgnoreScopes, Include.
# Include: app/models/**/*.rb
Rails/InverseOf:
@ -2425,11 +2207,6 @@ Style/HashTransformValues:
- 'app/serializers/rest/web_push_subscription_serializer.rb'
- 'app/services/import_service.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/IdenticalConditionalBranches:
Exclude:
- 'config/initializers/content_security_policy.rb'
# This cop supports safe autocorrection (--autocorrect).
Style/IfUnlessModifier:
Exclude:
@ -2529,11 +2306,6 @@ Style/PreferredHashMethods:
Exclude:
- 'config/initializers/paperclip.rb'
# This cop supports safe autocorrection (--autocorrect).
Style/RedundantBegin:
Exclude:
- 'config/initializers/simple_form.rb'
# This cop supports safe autocorrection (--autocorrect).
Style/RedundantConstantBase:
Exclude:

View File

@ -1 +1 @@
3.2.1
3.2.2

View File

@ -44,3 +44,6 @@ Gruntfile.js
# for specific ignore
!.svgo.yml
!sass-lint/**/*.yml
# breaks lint-staged or generally anything using https://github.com/eemeli/yaml/issues/384
!**/yaml/dist/**/doc

View File

@ -2,7 +2,7 @@
# This needs to be bullseye-slim because the Ruby image is built on bullseye-slim
ARG NODE_VERSION="16.19-bullseye-slim"
FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.1-slim as ruby
FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.2-slim as ruby
FROM node:${NODE_VERSION} as build
COPY --link --from=ruby /opt/ruby /opt/ruby

View File

@ -87,10 +87,10 @@ gem 'simple-navigation', '~> 4.4'
gem 'simple_form', '~> 5.2'
gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie'
gem 'stoplight', '~> 3.0.1'
gem 'strong_migrations', '~> 0.7'
gem 'strong_migrations', '~> 0.8'
gem 'tty-prompt', '~> 0.23', require: false
gem 'twitter-text', '~> 3.1.0'
gem 'tzinfo-data', '~> 1.2022'
gem 'tzinfo-data', '~> 1.2023'
gem 'webpacker', '~> 5.4'
gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9'
gem 'webauthn', '~> 3.0'

View File

@ -109,16 +109,16 @@ GEM
attr_required (1.0.1)
awrence (1.2.1)
aws-eventstream (1.2.0)
aws-partitions (1.711.0)
aws-sdk-core (3.170.0)
aws-partitions (1.735.0)
aws-sdk-core (3.171.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.62.0)
aws-sdk-kms (1.63.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.119.1)
aws-sdk-s3 (1.119.2)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@ -685,8 +685,8 @@ GEM
statsd-ruby (1.5.0)
stoplight (3.0.1)
redlock (~> 1.0)
strong_migrations (0.7.9)
activerecord (>= 5)
strong_migrations (0.8.0)
activerecord (>= 5.2)
swd (1.3.0)
activesupport (>= 3)
attr_required (>= 0.0.5)
@ -719,7 +719,7 @@ GEM
unf (~> 0.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2022.7)
tzinfo-data (1.2023.2)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@ -885,11 +885,11 @@ DEPENDENCIES
sprockets-rails (~> 3.4)
stackprof
stoplight (~> 3.0.1)
strong_migrations (~> 0.7)
strong_migrations (~> 0.8)
thor (~> 1.2)
tty-prompt (~> 0.23)
twitter-text (~> 3.1.0)
tzinfo-data (~> 1.2022)
tzinfo-data (~> 1.2023)
webauthn (~> 3.0)
webmock (~> 3.18)
webpacker (~> 5.4)

View File

@ -13,7 +13,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
def update
@account = current_account
UpdateAccountService.new.call(@account, account_params, raise_error: true)
UserSettingsDecorator.new(current_user).update(user_settings_params) if user_settings_params
current_user.update(user_params) if user_params
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
render json: @account, serializer: REST::CredentialAccountSerializer
end
@ -34,15 +34,17 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
)
end
def user_settings_params
def user_params
return nil if params[:source].blank?
source_params = params.require(:source)
{
'setting_default_privacy' => source_params.fetch(:privacy, @account.user.setting_default_privacy),
'setting_default_sensitive' => source_params.fetch(:sensitive, @account.user.setting_default_sensitive),
'setting_default_language' => source_params.fetch(:language, @account.user.setting_default_language),
settings_attributes: {
default_privacy: source_params.fetch(:privacy, @account.user.setting_default_privacy),
default_sensitive: source_params.fetch(:sensitive, @account.user.setting_default_sensitive),
default_language: source_params.fetch(:language, @account.user.setting_default_language),
},
}
end
end

View File

@ -5,7 +5,7 @@ class Api::V1::StreamingController < Api::BaseController
if Rails.configuration.x.streaming_api_base_url == request.host
not_found
else
redirect_to streaming_api_url, status: 301
redirect_to streaming_api_url, status: 301, allow_other_host: true
end
end

View File

@ -13,7 +13,11 @@ class BackupsController < ApplicationController
when :s3
redirect_to @backup.dump.expiring_url(10)
when :fog
redirect_to @backup.dump.expiring_url(Time.now.utc + 10)
if Paperclip::Attachment.default_options.dig(:storage, :fog_credentials, :openstack_temp_url_key).present?
redirect_to @backup.dump.expiring_url(Time.now.utc + 10)
else
redirect_to full_asset_url(@backup.dump.url)
end
when :filesystem
redirect_to full_asset_url(@backup.dump.url)
end

View File

@ -10,7 +10,8 @@ module AccountControllerConcern
included do
before_action :set_instance_presenter
before_action :set_link_headers, if: -> { request.format.nil? || request.format == :html }
after_action :set_link_headers, if: -> { request.format.nil? || request.format == :html }
end
private

View File

@ -23,7 +23,7 @@ class MediaProxyController < ApplicationController
redownload! if @media_attachment.needs_redownload? && !reject_media?
end
redirect_to full_asset_url(@media_attachment.file.url(version))
redirect_to full_asset_url(@media_attachment.file.url(version)), allow_other_host: true
end
private

View File

@ -4,8 +4,6 @@ class Settings::PreferencesController < Settings::BaseController
def show; end
def update
user_settings.update(user_settings_params.to_h)
if current_user.update(user_params)
I18n.locale = current_user.locale
redirect_to after_update_redirect_path, notice: I18n.t('generic.changes_saved_msg')
@ -20,46 +18,7 @@ class Settings::PreferencesController < Settings::BaseController
settings_preferences_path
end
def user_settings
UserSettingsDecorator.new(current_user)
end
def user_params
params.require(:user).permit(
:locale,
chosen_languages: []
)
end
def user_settings_params
params.require(:user).permit(
:setting_default_privacy,
:setting_default_sensitive,
:setting_default_language,
:setting_unfollow_modal,
:setting_boost_modal,
:setting_favourite_modal,
:setting_delete_modal,
:setting_auto_play_gif,
:setting_display_media,
:setting_expand_spoilers,
:setting_reduce_motion,
:setting_disable_swiping,
:setting_system_font_ui,
:setting_system_emoji_font,
:setting_noindex,
:setting_hide_followers_count,
:setting_aggregate_reblogs,
:setting_show_application,
:setting_advanced_layout,
:setting_default_content_type,
:setting_use_blurhash,
:setting_use_pending_items,
:setting_trends,
:setting_crop_images,
:setting_always_send_emails,
notification_emails: %i(follow follow_request reblog favourite mention report pending_account trending_tag trending_link trending_status appeal),
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
params.require(:user).permit(:locale, chosen_languages: [], settings_attributes: UserSettings.keys)
end
end

View File

@ -9,11 +9,12 @@ class StatusesController < ApplicationController
before_action :require_account_signature!, only: [:show, :activity], if: -> { request.format == :json && authorized_fetch_mode? }
before_action :set_status
before_action :set_instance_presenter
before_action :set_link_headers
before_action :redirect_to_original, only: :show
before_action :set_cache_headers
before_action :set_body_classes, only: :embed
after_action :set_link_headers
skip_around_action :set_locale, if: -> { request.format == :json }
skip_before_action :require_functional!, only: [:show, :embed], unless: :whitelist_mode?
@ -71,6 +72,6 @@ class StatusesController < ApplicationController
end
def redirect_to_original
redirect_to ActivityPub::TagManager.instance.url_for(@status.reblog) if @status.reblog?
redirect_to(ActivityPub::TagManager.instance.url_for(@status.reblog), allow_other_host: true) if @status.reblog?
end
end

View File

@ -4,7 +4,6 @@ import { defineMessages } from 'react-intl';
import api from 'mastodon/api';
import { search as emojiSearch } from 'mastodon/features/emoji/emoji_mart_search_light';
import { tagHistory } from 'mastodon/settings';
import resizeImage from 'mastodon/utils/resize_image';
import { showAlert, showAlertForError } from './alerts';
import { useEmoji } from './emojis';
import { importFetchedAccounts, importFetchedStatus } from './importer';
@ -276,46 +275,42 @@ export function uploadCompose(files) {
dispatch(uploadComposeRequest());
for (const [i, f] of Array.from(files).entries()) {
for (const [i, file] of Array.from(files).entries()) {
if (media.size + i > 3) break;
resizeImage(f).then(file => {
const data = new FormData();
data.append('file', file);
// Account for disparity in size of original image and resized data
total += file.size - f.size;
const data = new FormData();
data.append('file', file);
return api(getState).post('/api/v2/media', data, {
onUploadProgress: function({ loaded }){
progress[i] = loaded;
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
},
}).then(({ status, data }) => {
// If server-side processing of the media attachment has not completed yet,
// poll the server until it is, before showing the media attachment as uploaded
api(getState).post('/api/v2/media', data, {
onUploadProgress: function({ loaded }){
progress[i] = loaded;
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
},
}).then(({ status, data }) => {
// If server-side processing of the media attachment has not completed yet,
// poll the server until it is, before showing the media attachment as uploaded
if (status === 200) {
dispatch(uploadComposeSuccess(data, f));
} else if (status === 202) {
dispatch(uploadComposeProcessing());
if (status === 200) {
dispatch(uploadComposeSuccess(data, file));
} else if (status === 202) {
dispatch(uploadComposeProcessing());
let tryCount = 1;
let tryCount = 1;
const poll = () => {
api(getState).get(`/api/v1/media/${data.id}`).then(response => {
if (response.status === 200) {
dispatch(uploadComposeSuccess(response.data, f));
} else if (response.status === 206) {
const retryAfter = (Math.log2(tryCount) || 1) * 1000;
tryCount += 1;
setTimeout(() => poll(), retryAfter);
}
}).catch(error => dispatch(uploadComposeFail(error)));
};
const poll = () => {
api(getState).get(`/api/v1/media/${data.id}`).then(response => {
if (response.status === 200) {
dispatch(uploadComposeSuccess(response.data, file));
} else if (response.status === 206) {
const retryAfter = (Math.log2(tryCount) || 1) * 1000;
tryCount += 1;
setTimeout(() => poll(), retryAfter);
}
}).catch(error => dispatch(uploadComposeFail(error)));
};
poll();
}
});
poll();
}
}).catch(error => dispatch(uploadComposeFail(error)));
}
};

View File

@ -10,6 +10,9 @@ import { me } from '../initial_state';
import RelativeTimestamp from './relative_timestamp';
import Skeleton from 'mastodon/components/skeleton';
import { Link } from 'react-router-dom';
import { counterRenderer } from 'mastodon/components/common_counter';
import ShortNumber from 'mastodon/components/short_number';
import Icon from 'mastodon/components/icon';
const messages = defineMessages({
follow: { id: 'account.follow', defaultMessage: 'Follow' },
@ -23,6 +26,26 @@ const messages = defineMessages({
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
});
class VerifiedBadge extends React.PureComponent {
static propTypes = {
link: PropTypes.string.isRequired,
verifiedAt: PropTypes.string.isRequired,
};
render () {
const { link } = this.props;
return (
<span className='verified-badge'>
<Icon id='check' className='verified-badge__mark' />
<span dangerouslySetInnerHTML={{ __html: link }} />
</span>
);
}
}
class Account extends ImmutablePureComponent {
static propTypes = {
@ -77,7 +100,11 @@ class Account extends ImmutablePureComponent {
<div className='account__wrapper'>
<div className='account__display-name'>
<div className='account__avatar-wrapper'><Skeleton width={36} height={36} /></div>
<DisplayName />
<div>
<DisplayName />
<Skeleton width='7ch' />
</div>
</div>
</div>
</div>
@ -131,18 +158,32 @@ class Account extends ImmutablePureComponent {
}
}
let mute_expires_at;
let muteTimeRemaining;
if (account.get('mute_expires_at')) {
mute_expires_at = <div><RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></div>;
muteTimeRemaining = <>· <RelativeTimestamp timestamp={account.get('mute_expires_at')} futureDate /></>;
}
let verification;
const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
if (firstVerifiedField) {
verification = <>· <VerifiedBadge link={firstVerifiedField.get('value')} verifiedAt={firstVerifiedField.get('verified_at')} /></>;
}
return (
<div className='account'>
<div className='account__wrapper'>
<Link key={account.get('id')} className='account__display-name' title={account.get('acct')} to={`/@${account.get('acct')}`}>
<div className='account__avatar-wrapper'><Avatar account={account} size={size} /></div>
{mute_expires_at}
<DisplayName account={account} />
<div className='account__avatar-wrapper'>
<Avatar account={account} size={size} />
</div>
<div>
<DisplayName account={account} />
<ShortNumber value={account.get('followers_count')} renderer={counterRenderer('followers')} /> {verification} {muteTimeRemaining}
</div>
</Link>
<div className='account__relationship'>

View File

@ -386,6 +386,13 @@ class Status extends ImmutablePureComponent {
account = status.get('account');
status = status.get('reblog');
} else if (status.get('visibility') === 'direct') {
prepend = (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
</div>
);
} else if (showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id'])) {
const display_name_html = { __html: status.getIn(['account', 'display_name_html']) };

View File

@ -14,7 +14,7 @@ const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
edit: { id: 'status.edit', defaultMessage: 'Edit' },
direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' },
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
block: { id: 'account.block', defaultMessage: 'Block @{name}' },

View File

@ -28,7 +28,7 @@ const messages = defineMessages({
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },
direct: { id: 'account.direct', defaultMessage: 'Privately mention @{name}' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },

View File

@ -11,7 +11,7 @@ import ColumnHeader from 'mastodon/components/column_header';
import ConversationsListContainer from './containers/conversations_list_container';
const messages = defineMessages({
title: { id: 'column.direct', defaultMessage: 'Direct messages' },
title: { id: 'column.direct', defaultMessage: 'Private mentions' },
});
class DirectTimeline extends React.PureComponent {
@ -91,7 +91,7 @@ class DirectTimeline extends React.PureComponent {
timelineId='direct'
onLoadMore={this.handleLoadMore}
prepend={<div className='follow_requests-unlocked_explanation'><span><FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> <a href='/terms' target='_blank'><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a></span></div>}
emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any direct messages yet. When you send or receive one, it will show up here." />}
emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any private mentions yet. When you send or receive one, it will show up here." />}
/>
<Helmet>

View File

@ -88,7 +88,9 @@ class Explore extends React.PureComponent {
<Route path='/explore/tags' component={Tags} />
<Route path='/explore/links' component={Links} />
<Route path='/explore/suggestions' component={Suggestions} />
<Route exact path={['/explore', '/explore/posts', '/search']} component={Statuses} componentParams={{ multiColumn }} />
<Route exact path={['/explore', '/explore/posts', '/search']}>
<Statuses multiColumn={multiColumn} />
</Route>
</Switch>
<Helmet>

View File

@ -23,7 +23,7 @@ const messages = defineMessages({
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
explore: { id: 'navigation_bar.explore', defaultMessage: 'Explore' },
direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },
direct: { id: 'navigation_bar.direct', defaultMessage: 'Private mentions' },
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },

View File

@ -13,7 +13,7 @@ const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
edit: { id: 'status.edit', defaultMessage: 'Edit' },
direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' },
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
reply: { id: 'status.reply', defaultMessage: 'Reply' },
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },

View File

@ -6,7 +6,7 @@ import DisplayName from '../../../components/display_name';
import StatusContent from '../../../components/status_content';
import MediaGallery from '../../../components/media_gallery';
import { Link } from 'react-router-dom';
import { injectIntl, defineMessages, FormattedDate } from 'react-intl';
import { injectIntl, defineMessages, FormattedDate, FormattedMessage } from 'react-intl';
import Card from './card';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Video from '../../video';
@ -262,7 +262,13 @@ class DetailedStatus extends ImmutablePureComponent {
return (
<div style={outerStyle}>
<div ref={this.setRef} className={classNames('detailed-status', `detailed-status-${status.get('visibility')}`, { compact })}>
<div ref={this.setRef} className={classNames('detailed-status', { compact })}>
{status.get('visibility') === 'direct' && (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
</div>
)}
<a href={`/@${status.getIn(['account', 'acct'])}`} onClick={this.handleAccountClick} className='detailed-status__display-name'>
<div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={46} /></div>
<DisplayName account={status.get('account')} localDomain={this.props.domain} />

View File

@ -630,7 +630,7 @@ class Status extends ImmutablePureComponent {