diff --git a/.rubocop.yml b/.rubocop.yml index f1095e022..8bd4c867f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,6 @@ +require: + - rubocop-rails + AllCops: TargetRubyVersion: 2.3 Exclude: @@ -82,6 +85,9 @@ Rails/Exit: - 'lib/mastodon/*' - 'lib/cli.rb' +Rails/HelperInstanceVariable: + Enabled: false + Style/ClassAndModuleChildren: Enabled: false diff --git a/.sass-lint.yml b/.sass-lint.yml index d2c1d059e..a84adff3f 100644 --- a/.sass-lint.yml +++ b/.sass-lint.yml @@ -4,261 +4,34 @@ files: include: app/javascript/styles/**/*.scss ignore: - - app/javascript/styles/reset.scss - -linters: - # Reports when you use improper spacing around ! (the "bang") in !default, - # !global, !important, and !optional flags. - BangFormat: - enabled: false - - # Whether or not to prefer `border: 0` over `border: none`. - BorderZero: - enabled: false - - # Reports when you define a rule set using a selector with chained classes - # (a.k.a. adjoining classes). - ChainedClasses: - enabled: false - - # Prefer hexadecimal color codes over color keywords. - # (e.g. `color: green` is a color keyword) - ColorKeyword: - enabled: false - - # Prefer color literals (keywords or hexadecimal codes) to be used only in - # variable declarations. They should be referred to via variables everywhere - # else. - ColorVariable: - enabled: true - - # Which form of comments to prefer in CSS. - Comment: - enabled: false - - # Reports @debug statements (which you probably left behind accidentally). - DebugStatement: - enabled: false - - # Rule sets should be ordered as follows: - # - @extend declarations - # - @include declarations without inner @content - # - properties, @include declarations with inner @content - # - nested rule sets. - DeclarationOrder: - enabled: false - - # `scss-lint:disable` control comments should be preceded by a comment - # explaining why these linters are being disabled for this file. - # See https://github.com/brigade/scss-lint#disabling-linters-via-source for - # more information. - DisableLinterReason: - enabled: true - - # Reports when you define the same property twice in a single rule set. - DuplicateProperty: - enabled: false - - # Separate rule, function, and mixin declarations with empty lines. - EmptyLineBetweenBlocks: - enabled: true - - # Reports when you have an empty rule set. - EmptyRule: - enabled: true - - # Reports when you have an @extend directive. - ExtendDirective: - enabled: false - - # Files should always have a final newline. This results in better diffs - # when adding lines to the file, since SCM systems such as git won't - # think that you touched the last line. - FinalNewline: - enabled: false - - # HEX colors should use three-character values where possible. - HexLength: - enabled: false - - # HEX color values should use lower-case colors to differentiate between - # letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`. - HexNotation: - enabled: true - - # Avoid using ID selectors. - IdSelector: - enabled: false - - # The basenames of @imported SCSS partials should not begin with an - # underscore and should not include the filename extension. - ImportPath: - enabled: false - - # Avoid using !important in properties. It is usually indicative of a - # misunderstanding of CSS specificity and can lead to brittle code. - ImportantRule: - enabled: false - - # Indentation should always be done in increments of 2 spaces. - Indentation: - enabled: true - width: 2 - - # Don't write leading zeros for numeric values with a decimal point. - LeadingZero: - enabled: false - - # Reports when you define the same selector twice in a single sheet. - MergeableSelector: - enabled: false - - # Functions, mixins, variables, and placeholders should be declared - # with all lowercase letters and hyphens instead of underscores. - NameFormat: - enabled: false - - # Avoid nesting selectors too deeply. - NestingDepth: - enabled: false - - # Always use placeholder selectors in @extend. - PlaceholderInExtend: - enabled: false - - # Sort properties in a strict order. - PropertySortOrder: - enabled: false - - # Reports when you use an unknown or disabled CSS property - # (ignoring vendor-prefixed properties). - PropertySpelling: - enabled: false - - # Configure which units are allowed for property values. - PropertyUnits: - enabled: false - - # Pseudo-elements, like ::before, and ::first-letter, should be declared - # with two colons. Pseudo-classes, like :hover and :first-child, should - # be declared with one colon. - PseudoElement: - enabled: true - - # Avoid qualifying elements in selectors (also known as "tag-qualifying"). - QualifyingElement: - enabled: false - - # Don't write selectors with a depth of applicability greater than 3. - SelectorDepth: - enabled: false - - # Selectors should always use hyphenated-lowercase, rather than camelCase or - # snake_case. - SelectorFormat: - enabled: false - convention: hyphenated_lowercase - - # Prefer the shortest shorthand form possible for properties that support it. - Shorthand: - enabled: true - - # Each property should have its own line, except in the special case of - # single line rulesets. - SingleLinePerProperty: - enabled: true - allow_single_line_rule_sets: true - - # Split selectors onto separate lines after each comma, and have each - # individual selector occupy a single line. - SingleLinePerSelector: - enabled: true - - # Commas in lists should be followed by a space. - SpaceAfterComma: - enabled: false - - # Properties should be formatted with a single space separating the colon - # from the property's value. - SpaceAfterPropertyColon: - enabled: true - - # Properties should be formatted with no space between the name and the - # colon. - SpaceAfterPropertyName: - enabled: true - - # Variables should be formatted with a single space separating the colon - # from the variable's value. - SpaceAfterVariableColon: - enabled: true - - # Variables should be formatted with no space between the name and the - # colon. - SpaceAfterVariableName: - enabled: false - - # Operators should be formatted with a single space on both sides of an - # infix operator. - SpaceAroundOperator: - enabled: true - - # Opening braces should be preceded by a single space. - SpaceBeforeBrace: - enabled: true - - # Parentheses should not be padded with spaces. - SpaceBetweenParens: - enabled: false - - # Enforces that string literals should be written with a consistent form - # of quotes (single or double). - StringQuotes: - enabled: false - - # Property values, @extend, @include, and @import directives, and variable - # declarations should always end with a semicolon. - TrailingSemicolon: - enabled: true - - # Reports lines containing trailing whitespace. - TrailingWhitespace: - enabled: true - - # Don't write trailing zeros for numeric values with a decimal point. - TrailingZero: - enabled: false - - # Don't use the `all` keyword to specify transition properties. - TransitionAll: - enabled: false - - # Numeric values should not contain unnecessary fractional portions. - UnnecessaryMantissa: - enabled: false - - # Do not use parent selector references (&) when they would otherwise - # be unnecessary. - UnnecessaryParentReference: - enabled: false - - # URLs should be valid and not contain protocols or domain names. - UrlFormat: - enabled: true - - # URLs should always be enclosed within quotes. - UrlQuotes: - enabled: true - - # Properties, like color and font, are easier to read and maintain - # when defined using variables rather than literals. - VariableForProperty: - enabled: false - - # Avoid vendor prefixes. Or rather: don't write them yourself. - VendorPrefix: - enabled: false - - # Omit length units on zero values, e.g. `0px` vs. `0`. - ZeroUnit: - enabled: true + - app/javascript/styles/mastodon/reset.scss + +rules: + # Disallows + no-color-literals: 0 + no-css-comments: 0 + no-duplicate-properties: 0 + no-ids: 0 + no-important: 0 + no-mergeable-selectors: 0 + no-misspelled-properties: 0 + no-qualifying-elements: 0 + no-transition-all: 0 + no-vendor-prefixes: 0 + + # Nesting + force-element-nesting: 0 + force-attribute-nesting: 0 + force-pseudo-nesting: 0 + + # Name Formats + class-name-format: 0 + leading-zero: 0 + + # Style Guide + attribute-quotes: 0 + hex-length: 0 + indentation: 0 + nesting-depth: 0 + property-sort-order: 0 + quotes: 0 diff --git a/Gemfile b/Gemfile index 68fd5e98f..65f6fa3cb 100644 --- a/Gemfile +++ b/Gemfile @@ -132,6 +132,7 @@ group :development do gem 'letter_opener_web', '~> 1.3' gem 'memory_profiler' gem 'rubocop', '~> 0.71', require: false + gem 'rubocop-rails', '~> 2.0', require: false gem 'brakeman', '~> 4.5', require: false gem 'bundler-audit', '~> 0.6', require: false diff --git a/Gemfile.lock b/Gemfile.lock index be8ce27cd..73f0d63f5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -534,6 +534,9 @@ GEM rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 1.7) + rubocop-rails (2.0.0) + rack (>= 2.0) + rubocop (>= 0.70.0) ruby-progressbar (1.10.1) ruby-saml (1.9.0) nokogiri (>= 1.5.10) @@ -740,6 +743,7 @@ DEPENDENCIES rspec-rails (~> 3.8) rspec-sidekiq (~> 3.0) rubocop (~> 0.71) + rubocop-rails (~> 2.0) sanitize (~> 5.0) sidekiq (~> 5.2) sidekiq-bulk (~> 0.2.0) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index fcdebb47f..051b6ecbd 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -47,8 +47,6 @@ class AccountsController < ApplicationController end format.json do - mark_cacheable! - render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter) end diff --git a/app/controllers/activitypub/collections_controller.rb b/app/controllers/activitypub/collections_controller.rb index 853f4f907..012c3c538 100644 --- a/app/controllers/activitypub/collections_controller.rb +++ b/app/controllers/activitypub/collections_controller.rb @@ -9,8 +9,6 @@ class ActivityPub::CollectionsController < Api::BaseController before_action :set_cache_headers def show - skip_session! - render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do ActiveModelSerializers::SerializableResource.new( collection_presenter, diff --git a/app/controllers/activitypub/outboxes_controller.rb b/app/controllers/activitypub/outboxes_controller.rb index 438fa226e..5147afbf7 100644 --- a/app/controllers/activitypub/outboxes_controller.rb +++ b/app/controllers/activitypub/outboxes_controller.rb @@ -10,10 +10,7 @@ class ActivityPub::OutboxesController < Api::BaseController before_action :set_cache_headers def show - unless page_requested? - skip_session! - expires_in 1.minute, public: true - end + expires_in 1.minute, public: true unless page_requested? render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json' end diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index e7795e95c..b0d45ce47 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -48,13 +48,13 @@ module Admin def approve authorize @account.user, :approve? @account.user.approve! - redirect_to admin_accounts_path(pending: '1') + redirect_to admin_pending_accounts_path end def reject authorize @account.user, :reject? SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true) - redirect_to admin_accounts_path(pending: '1') + redirect_to admin_pending_accounts_path end def unsilence diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5401b9d59..333082f68 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -228,11 +228,6 @@ class ApplicationController < ActionController::Base end def mark_cacheable! - skip_session! expires_in 0, public: true end - - def skip_session! - request.session_options[:skip] = true - end end diff --git a/app/controllers/concerns/account_controller_concern.rb b/app/controllers/concerns/account_controller_concern.rb index 4f28941ae..1c422096c 100644 --- a/app/controllers/concerns/account_controller_concern.rb +++ b/app/controllers/concerns/account_controller_concern.rb @@ -70,7 +70,6 @@ module AccountControllerConcern def check_account_suspension if @account.suspended? - skip_session! expires_in(3.minutes, public: true) gone end diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb index 31e501609..be768c089 100644 --- a/app/controllers/custom_css_controller.rb +++ b/app/controllers/custom_css_controller.rb @@ -4,7 +4,6 @@ class CustomCssController < ApplicationController before_action :set_cache_headers def show - skip_session! render plain: Setting.custom_css || '', content_type: 'text/css' end end diff --git a/app/controllers/emojis_controller.rb b/app/controllers/emojis_controller.rb index 5d306e600..3feb08132 100644 --- a/app/controllers/emojis_controller.rb +++ b/app/controllers/emojis_controller.rb @@ -7,8 +7,6 @@ class EmojisController < ApplicationController def show respond_to do |format| format.json do - skip_session! - render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter) end diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb index 1462b94fc..fab9c8462 100644 --- a/app/controllers/follower_accounts_controller.rb +++ b/app/controllers/follower_accounts_controller.rb @@ -20,10 +20,7 @@ class FollowerAccountsController < ApplicationController format.json do raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network? - if params[:page].blank? - skip_session! - expires_in 3.minutes, public: true - end + expires_in 3.minutes, public: true if params[:page].blank? render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb index 181f85221..272116040 100644 --- a/app/controllers/following_accounts_controller.rb +++ b/app/controllers/following_accounts_controller.rb @@ -20,10 +20,7 @@ class FollowingAccountsController < ApplicationController format.json do raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network? - if params[:page].blank? - skip_session! - expires_in 3.minutes, public: true - end + expires_in 3.minutes, public: true if params[:page].blank? render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index 28eebda28..66ba260aa 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -29,10 +29,7 @@ class StatusesController < ApplicationController format.html do use_pack 'public' - unless user_signed_in? - skip_session! - expires_in 10.seconds, public: true - end + expires_in 10.seconds, public: true if current_account.nil? @body_classes = 'with-modals' @@ -43,8 +40,6 @@ class StatusesController < ApplicationController end format.json do - mark_cacheable! unless @stream_entry.hidden? - render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter) end @@ -53,8 +48,6 @@ class StatusesController < ApplicationController end def activity - skip_session! - render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter) end @@ -64,7 +57,6 @@ class StatusesController < ApplicationController use_pack 'embed' raise ActiveRecord::RecordNotFound if @status.hidden? - skip_session! expires_in 180, public: true response.headers['X-Frame-Options'] = 'ALLOWALL' @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay]) @@ -73,8 +65,6 @@ class StatusesController < ApplicationController end def replies - skip_session! - render json: replies_collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb index 1e16c5157..1ee85592c 100644 --- a/app/controllers/stream_entries_controller.rb +++ b/app/controllers/stream_entries_controller.rb @@ -17,19 +17,13 @@ class StreamEntriesController < ApplicationController format.html do use_pack 'public' - unless user_signed_in? - skip_session! - expires_in 5.minutes, public: true - end + expires_in 5.minutes, public: true unless @stream_entry.hidden? - redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status' + redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) end format.atom do - unless @stream_entry.hidden? - skip_session! - expires_in 3.minutes, public: true - end + expires_in 3.minutes, public: true unless @stream_entry.hidden? render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true)) end @@ -57,7 +51,7 @@ class StreamEntriesController < ApplicationController def set_stream_entry @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id]) - @type = @stream_entry.activity_type.downcase + @type = 'status' raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil? authorize @stream_entry.activity, :show? if @stream_entry.hidden? || @stream_entry.local_only? diff --git a/app/javascript/mastodon/components/autosuggest_textarea.js b/app/javascript/mastodon/components/autosuggest_textarea.js index 5cad43e82..4c50294ba 100644 --- a/app/javascript/mastodon/components/autosuggest_textarea.js +++ b/app/javascript/mastodon/components/autosuggest_textarea.js @@ -138,8 +138,11 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { this.setState({ suggestionsHidden: true, focused: false }); } - onFocus = () => { + onFocus = (e) => { this.setState({ focused: true }); + if (this.props.onFocus) { + this.props.onFocus(e); + } } onSuggestionClick = (e) => { diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js index ff6c521f2..ff22a2953 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.js +++ b/app/javascript/mastodon/features/compose/components/compose_form.js @@ -34,6 +34,10 @@ const messages = defineMessages({ export default @injectIntl class ComposeForm extends ImmutablePureComponent { + setRef = c => { + this.composeForm = c; + }; + static contextTypes = { router: PropTypes.object, }; @@ -115,6 +119,10 @@ class ComposeForm extends ImmutablePureComponent { this.props.onChangeSpoilerText(e.target.value); } + handleFocus = () => { + this.composeForm.scrollIntoView(); + } + componentDidUpdate (prevProps) { // This statement does several things: // - If we're beginning a reply, and, @@ -178,7 +186,7 @@ class ComposeForm extends ImmutablePureComponent { } return ( -