Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/controllers/statuses_controller.rb - app/controllers/stream_entries_controller.rb
This commit is contained in:
		
						commit
						00552d2f79
					
				
					 63 changed files with 239 additions and 535 deletions
				
			
		| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
 | 
					require:
 | 
				
			||||||
 | 
					  - rubocop-rails
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AllCops:
 | 
					AllCops:
 | 
				
			||||||
  TargetRubyVersion: 2.3
 | 
					  TargetRubyVersion: 2.3
 | 
				
			||||||
  Exclude:
 | 
					  Exclude:
 | 
				
			||||||
| 
						 | 
					@ -82,6 +85,9 @@ Rails/Exit:
 | 
				
			||||||
    - 'lib/mastodon/*'
 | 
					    - 'lib/mastodon/*'
 | 
				
			||||||
    - 'lib/cli.rb'
 | 
					    - 'lib/cli.rb'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Rails/HelperInstanceVariable:
 | 
				
			||||||
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Style/ClassAndModuleChildren:
 | 
					Style/ClassAndModuleChildren:
 | 
				
			||||||
  Enabled: false
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										281
									
								
								.sass-lint.yml
									
									
									
									
									
								
							
							
						
						
									
										281
									
								
								.sass-lint.yml
									
									
									
									
									
								
							| 
						 | 
					@ -4,261 +4,34 @@
 | 
				
			||||||
files:
 | 
					files:
 | 
				
			||||||
  include: app/javascript/styles/**/*.scss
 | 
					  include: app/javascript/styles/**/*.scss
 | 
				
			||||||
  ignore:
 | 
					  ignore:
 | 
				
			||||||
    - app/javascript/styles/reset.scss
 | 
					    - app/javascript/styles/mastodon/reset.scss
 | 
				
			||||||
 | 
					
 | 
				
			||||||
linters:
 | 
					rules:
 | 
				
			||||||
  # Reports when you use improper spacing around ! (the "bang") in !default,
 | 
					  # Disallows
 | 
				
			||||||
  # !global, !important, and !optional flags.
 | 
					  no-color-literals: 0
 | 
				
			||||||
  BangFormat:
 | 
					  no-css-comments: 0
 | 
				
			||||||
    enabled: false
 | 
					  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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Whether or not to prefer `border: 0` over `border: none`.
 | 
					  # Nesting
 | 
				
			||||||
  BorderZero:
 | 
					  force-element-nesting: 0
 | 
				
			||||||
    enabled: false
 | 
					  force-attribute-nesting: 0
 | 
				
			||||||
 | 
					  force-pseudo-nesting: 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Reports when you define a rule set using a selector with chained classes
 | 
					  # Name Formats
 | 
				
			||||||
  # (a.k.a. adjoining classes).
 | 
					  class-name-format: 0
 | 
				
			||||||
  ChainedClasses:
 | 
					  leading-zero: 0
 | 
				
			||||||
    enabled: false
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Prefer hexadecimal color codes over color keywords.
 | 
					  # Style Guide
 | 
				
			||||||
  # (e.g. `color: green` is a color keyword)
 | 
					  attribute-quotes: 0
 | 
				
			||||||
  ColorKeyword:
 | 
					  hex-length: 0
 | 
				
			||||||
    enabled: false
 | 
					  indentation: 0
 | 
				
			||||||
 | 
					  nesting-depth: 0
 | 
				
			||||||
  # Prefer color literals (keywords or hexadecimal codes) to be used only in
 | 
					  property-sort-order: 0
 | 
				
			||||||
  # variable declarations. They should be referred to via variables everywhere
 | 
					  quotes: 0
 | 
				
			||||||
  # 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
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							| 
						 | 
					@ -132,6 +132,7 @@ group :development do
 | 
				
			||||||
  gem 'letter_opener_web', '~> 1.3'
 | 
					  gem 'letter_opener_web', '~> 1.3'
 | 
				
			||||||
  gem 'memory_profiler'
 | 
					  gem 'memory_profiler'
 | 
				
			||||||
  gem 'rubocop', '~> 0.71', require: false
 | 
					  gem 'rubocop', '~> 0.71', require: false
 | 
				
			||||||
 | 
					  gem 'rubocop-rails', '~> 2.0', require: false
 | 
				
			||||||
  gem 'brakeman', '~> 4.5', require: false
 | 
					  gem 'brakeman', '~> 4.5', require: false
 | 
				
			||||||
  gem 'bundler-audit', '~> 0.6', require: false
 | 
					  gem 'bundler-audit', '~> 0.6', require: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -534,6 +534,9 @@ GEM
 | 
				
			||||||
      rainbow (>= 2.2.2, < 4.0)
 | 
					      rainbow (>= 2.2.2, < 4.0)
 | 
				
			||||||
      ruby-progressbar (~> 1.7)
 | 
					      ruby-progressbar (~> 1.7)
 | 
				
			||||||
      unicode-display_width (>= 1.4.0, < 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-progressbar (1.10.1)
 | 
				
			||||||
    ruby-saml (1.9.0)
 | 
					    ruby-saml (1.9.0)
 | 
				
			||||||
      nokogiri (>= 1.5.10)
 | 
					      nokogiri (>= 1.5.10)
 | 
				
			||||||
| 
						 | 
					@ -740,6 +743,7 @@ DEPENDENCIES
 | 
				
			||||||
  rspec-rails (~> 3.8)
 | 
					  rspec-rails (~> 3.8)
 | 
				
			||||||
  rspec-sidekiq (~> 3.0)
 | 
					  rspec-sidekiq (~> 3.0)
 | 
				
			||||||
  rubocop (~> 0.71)
 | 
					  rubocop (~> 0.71)
 | 
				
			||||||
 | 
					  rubocop-rails (~> 2.0)
 | 
				
			||||||
  sanitize (~> 5.0)
 | 
					  sanitize (~> 5.0)
 | 
				
			||||||
  sidekiq (~> 5.2)
 | 
					  sidekiq (~> 5.2)
 | 
				
			||||||
  sidekiq-bulk (~> 0.2.0)
 | 
					  sidekiq-bulk (~> 0.2.0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,8 +47,6 @@ class AccountsController < ApplicationController
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      format.json do
 | 
					      format.json do
 | 
				
			||||||
        mark_cacheable!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do
 | 
					        render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do
 | 
				
			||||||
          ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)
 | 
					          ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,6 @@ class ActivityPub::CollectionsController < Api::BaseController
 | 
				
			||||||
  before_action :set_cache_headers
 | 
					  before_action :set_cache_headers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def show
 | 
					  def show
 | 
				
			||||||
    skip_session!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do
 | 
					    render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do
 | 
				
			||||||
      ActiveModelSerializers::SerializableResource.new(
 | 
					      ActiveModelSerializers::SerializableResource.new(
 | 
				
			||||||
        collection_presenter,
 | 
					        collection_presenter,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,10 +10,7 @@ class ActivityPub::OutboxesController < Api::BaseController
 | 
				
			||||||
  before_action :set_cache_headers
 | 
					  before_action :set_cache_headers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def show
 | 
					  def show
 | 
				
			||||||
    unless page_requested?
 | 
					    expires_in 1.minute, public: true unless page_requested?
 | 
				
			||||||
      skip_session!
 | 
					 | 
				
			||||||
      expires_in 1.minute, public: true
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
 | 
					    render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,13 +48,13 @@ module Admin
 | 
				
			||||||
    def approve
 | 
					    def approve
 | 
				
			||||||
      authorize @account.user, :approve?
 | 
					      authorize @account.user, :approve?
 | 
				
			||||||
      @account.user.approve!
 | 
					      @account.user.approve!
 | 
				
			||||||
      redirect_to admin_accounts_path(pending: '1')
 | 
					      redirect_to admin_pending_accounts_path
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def reject
 | 
					    def reject
 | 
				
			||||||
      authorize @account.user, :reject?
 | 
					      authorize @account.user, :reject?
 | 
				
			||||||
      SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)
 | 
					      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
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def unsilence
 | 
					    def unsilence
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -228,11 +228,6 @@ class ApplicationController < ActionController::Base
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def mark_cacheable!
 | 
					  def mark_cacheable!
 | 
				
			||||||
    skip_session!
 | 
					 | 
				
			||||||
    expires_in 0, public: true
 | 
					    expires_in 0, public: true
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					 | 
				
			||||||
  def skip_session!
 | 
					 | 
				
			||||||
    request.session_options[:skip] = true
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,6 @@ module AccountControllerConcern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def check_account_suspension
 | 
					  def check_account_suspension
 | 
				
			||||||
    if @account.suspended?
 | 
					    if @account.suspended?
 | 
				
			||||||
      skip_session!
 | 
					 | 
				
			||||||
      expires_in(3.minutes, public: true)
 | 
					      expires_in(3.minutes, public: true)
 | 
				
			||||||
      gone
 | 
					      gone
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@ class CustomCssController < ApplicationController
 | 
				
			||||||
  before_action :set_cache_headers
 | 
					  before_action :set_cache_headers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def show
 | 
					  def show
 | 
				
			||||||
    skip_session!
 | 
					 | 
				
			||||||
    render plain: Setting.custom_css || '', content_type: 'text/css'
 | 
					    render plain: Setting.custom_css || '', content_type: 'text/css'
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,6 @@ class EmojisController < ApplicationController
 | 
				
			||||||
  def show
 | 
					  def show
 | 
				
			||||||
    respond_to do |format|
 | 
					    respond_to do |format|
 | 
				
			||||||
      format.json do
 | 
					      format.json do
 | 
				
			||||||
        skip_session!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do
 | 
					        render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do
 | 
				
			||||||
          ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter)
 | 
					          ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,10 +20,7 @@ class FollowerAccountsController < ApplicationController
 | 
				
			||||||
      format.json do
 | 
					      format.json do
 | 
				
			||||||
        raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
 | 
					        raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if params[:page].blank?
 | 
					        expires_in 3.minutes, public: true if params[:page].blank?
 | 
				
			||||||
          skip_session!
 | 
					 | 
				
			||||||
          expires_in 3.minutes, public: true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        render json: collection_presenter,
 | 
					        render json: collection_presenter,
 | 
				
			||||||
               serializer: ActivityPub::CollectionSerializer,
 | 
					               serializer: ActivityPub::CollectionSerializer,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,10 +20,7 @@ class FollowingAccountsController < ApplicationController
 | 
				
			||||||
      format.json do
 | 
					      format.json do
 | 
				
			||||||
        raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
 | 
					        raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if params[:page].blank?
 | 
					        expires_in 3.minutes, public: true if params[:page].blank?
 | 
				
			||||||
          skip_session!
 | 
					 | 
				
			||||||
          expires_in 3.minutes, public: true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        render json: collection_presenter,
 | 
					        render json: collection_presenter,
 | 
				
			||||||
               serializer: ActivityPub::CollectionSerializer,
 | 
					               serializer: ActivityPub::CollectionSerializer,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,10 +29,7 @@ class StatusesController < ApplicationController
 | 
				
			||||||
      format.html do
 | 
					      format.html do
 | 
				
			||||||
        use_pack 'public'
 | 
					        use_pack 'public'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unless user_signed_in?
 | 
					        expires_in 10.seconds, public: true if current_account.nil?
 | 
				
			||||||
          skip_session!
 | 
					 | 
				
			||||||
          expires_in 10.seconds, public: true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @body_classes = 'with-modals'
 | 
					        @body_classes = 'with-modals'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,8 +40,6 @@ class StatusesController < ApplicationController
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      format.json do
 | 
					      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
 | 
					        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)
 | 
					          ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -53,8 +48,6 @@ class StatusesController < ApplicationController
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def activity
 | 
					  def activity
 | 
				
			||||||
    skip_session!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do
 | 
					    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)
 | 
					      ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					@ -64,7 +57,6 @@ class StatusesController < ApplicationController
 | 
				
			||||||
    use_pack 'embed'
 | 
					    use_pack 'embed'
 | 
				
			||||||
    raise ActiveRecord::RecordNotFound if @status.hidden?
 | 
					    raise ActiveRecord::RecordNotFound if @status.hidden?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    skip_session!
 | 
					 | 
				
			||||||
    expires_in 180, public: true
 | 
					    expires_in 180, public: true
 | 
				
			||||||
    response.headers['X-Frame-Options'] = 'ALLOWALL'
 | 
					    response.headers['X-Frame-Options'] = 'ALLOWALL'
 | 
				
			||||||
    @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay])
 | 
					    @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay])
 | 
				
			||||||
| 
						 | 
					@ -73,8 +65,6 @@ class StatusesController < ApplicationController
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def replies
 | 
					  def replies
 | 
				
			||||||
    skip_session!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    render json: replies_collection_presenter,
 | 
					    render json: replies_collection_presenter,
 | 
				
			||||||
           serializer: ActivityPub::CollectionSerializer,
 | 
					           serializer: ActivityPub::CollectionSerializer,
 | 
				
			||||||
           adapter: ActivityPub::Adapter,
 | 
					           adapter: ActivityPub::Adapter,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,19 +17,13 @@ class StreamEntriesController < ApplicationController
 | 
				
			||||||
      format.html do
 | 
					      format.html do
 | 
				
			||||||
        use_pack 'public'
 | 
					        use_pack 'public'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unless user_signed_in?
 | 
					        expires_in 5.minutes, public: true unless @stream_entry.hidden?
 | 
				
			||||||
          skip_session!
 | 
					 | 
				
			||||||
          expires_in 5.minutes, public: true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      format.atom do
 | 
					      format.atom do
 | 
				
			||||||
        unless @stream_entry.hidden?
 | 
					        expires_in 3.minutes, public: true unless @stream_entry.hidden?
 | 
				
			||||||
          skip_session!
 | 
					 | 
				
			||||||
          expires_in 3.minutes, public: true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true))
 | 
					        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true))
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
| 
						 | 
					@ -57,7 +51,7 @@ class StreamEntriesController < ApplicationController
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def set_stream_entry
 | 
					  def set_stream_entry
 | 
				
			||||||
    @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id])
 | 
					    @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?
 | 
					    raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil?
 | 
				
			||||||
    authorize @stream_entry.activity, :show? if @stream_entry.hidden? || @stream_entry.local_only?
 | 
					    authorize @stream_entry.activity, :show? if @stream_entry.hidden? || @stream_entry.local_only?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,8 +138,11 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
 | 
				
			||||||
    this.setState({ suggestionsHidden: true, focused: false });
 | 
					    this.setState({ suggestionsHidden: true, focused: false });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onFocus = () => {
 | 
					  onFocus = (e) => {
 | 
				
			||||||
    this.setState({ focused: true });
 | 
					    this.setState({ focused: true });
 | 
				
			||||||
 | 
					    if (this.props.onFocus) {
 | 
				
			||||||
 | 
					      this.props.onFocus(e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onSuggestionClick = (e) => {
 | 
					  onSuggestionClick = (e) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,10 @@ const messages = defineMessages({
 | 
				
			||||||
export default @injectIntl
 | 
					export default @injectIntl
 | 
				
			||||||
class ComposeForm extends ImmutablePureComponent {
 | 
					class ComposeForm extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setRef = c => {
 | 
				
			||||||
 | 
					    this.composeForm = c;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static contextTypes = {
 | 
					  static contextTypes = {
 | 
				
			||||||
    router: PropTypes.object,
 | 
					    router: PropTypes.object,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
| 
						 | 
					@ -115,6 +119,10 @@ class ComposeForm extends ImmutablePureComponent {
 | 
				
			||||||
    this.props.onChangeSpoilerText(e.target.value);
 | 
					    this.props.onChangeSpoilerText(e.target.value);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleFocus = () => {
 | 
				
			||||||
 | 
					    this.composeForm.scrollIntoView();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentDidUpdate (prevProps) {
 | 
					  componentDidUpdate (prevProps) {
 | 
				
			||||||
    // This statement does several things:
 | 
					    // This statement does several things:
 | 
				
			||||||
    // - If we're beginning a reply, and,
 | 
					    // - If we're beginning a reply, and,
 | 
				
			||||||
| 
						 | 
					@ -178,7 +186,7 @@ class ComposeForm extends ImmutablePureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='compose-form'>
 | 
					      <div className='compose-form' ref={this.setRef}>
 | 
				
			||||||
        <WarningContainer />
 | 
					        <WarningContainer />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <ReplyIndicatorContainer />
 | 
					        <ReplyIndicatorContainer />
 | 
				
			||||||
| 
						 | 
					@ -201,7 +209,7 @@ class ComposeForm extends ImmutablePureComponent {
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='emoji-picker-wrapper'>
 | 
					        <div className={`emoji-picker-wrapper ${this.props.showSearch ? 'emoji-picker-wrapper--hidden' : ''}`}>
 | 
				
			||||||
          <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
 | 
					          <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,6 +220,7 @@ class ComposeForm extends ImmutablePureComponent {
 | 
				
			||||||
          value={this.props.text}
 | 
					          value={this.props.text}
 | 
				
			||||||
          onChange={this.handleChange}
 | 
					          onChange={this.handleChange}
 | 
				
			||||||
          suggestions={this.props.suggestions}
 | 
					          suggestions={this.props.suggestions}
 | 
				
			||||||
 | 
					          onFocus={this.handleFocus}
 | 
				
			||||||
          onKeyDown={this.handleKeyDown}
 | 
					          onKeyDown={this.handleKeyDown}
 | 
				
			||||||
          onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
 | 
					          onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
 | 
				
			||||||
          onSuggestionsClearRequested={this.onSuggestionsClearRequested}
 | 
					          onSuggestionsClearRequested={this.onSuggestionsClearRequested}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ class SearchPopout extends React.PureComponent {
 | 
				
			||||||
    const { style } = this.props;
 | 
					    const { style } = this.props;
 | 
				
			||||||
    const extraInformation = searchEnabled ? <FormattedMessage id='search_popout.tips.full_text' defaultMessage='Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' /> : <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' />;
 | 
					    const extraInformation = searchEnabled ? <FormattedMessage id='search_popout.tips.full_text' defaultMessage='Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' /> : <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' />;
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div style={{ ...style, position: 'absolute', width: 285 }}>
 | 
					      <div style={{ ...style, position: 'absolute', width: 285, zIndex: 2 }}>
 | 
				
			||||||
        <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
 | 
					        <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
 | 
				
			||||||
          {({ opacity, scaleX, scaleY }) => (
 | 
					          {({ opacity, scaleX, scaleY }) => (
 | 
				
			||||||
            <div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
 | 
					            <div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +75,23 @@ class ListTimeline extends React.PureComponent {
 | 
				
			||||||
    this.disconnect = dispatch(connectListStream(id));
 | 
					    this.disconnect = dispatch(connectListStream(id));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
 | 
					    const { id } = nextProps.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (id !== this.props.params.id) {
 | 
				
			||||||
 | 
					      if (this.disconnect) {
 | 
				
			||||||
 | 
					        this.disconnect();
 | 
				
			||||||
 | 
					        this.disconnect = null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      dispatch(fetchList(id));
 | 
				
			||||||
 | 
					      dispatch(expandListTimeline(id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.disconnect = dispatch(connectListStream(id));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillUnmount () {
 | 
					  componentWillUnmount () {
 | 
				
			||||||
    if (this.disconnect) {
 | 
					    if (this.disconnect) {
 | 
				
			||||||
      this.disconnect();
 | 
					      this.disconnect();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -338,6 +338,7 @@ export default function compose(state = initialState, action) {
 | 
				
			||||||
      map.set('focusDate', new Date());
 | 
					      map.set('focusDate', new Date());
 | 
				
			||||||
      map.set('caretPosition', null);
 | 
					      map.set('caretPosition', null);
 | 
				
			||||||
      map.set('idempotencyKey', uuid());
 | 
					      map.set('idempotencyKey', uuid());
 | 
				
			||||||
 | 
					      map.set('sensitive', action.status.get('sensitive'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (action.status.get('spoiler_text').length > 0) {
 | 
					      if (action.status.get('spoiler_text').length > 0) {
 | 
				
			||||||
        map.set('spoiler', true);
 | 
					        map.set('spoiler', true);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,14 +35,12 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!next && !isLoadingRecent) mMap.set('hasMore', false);
 | 
					    if (!next && !isLoadingRecent) mMap.set('hasMore', false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!statuses.isEmpty()) {
 | 
					    if (timeline.endsWith(':pinned')) {
 | 
				
			||||||
 | 
					      mMap.set('items', statuses.map(status => status.get('id')));
 | 
				
			||||||
 | 
					    } else if (!statuses.isEmpty()) {
 | 
				
			||||||
      mMap.update('items', ImmutableList(), oldIds => {
 | 
					      mMap.update('items', ImmutableList(), oldIds => {
 | 
				
			||||||
        const newIds = statuses.map(status => status.get('id'));
 | 
					        const newIds = statuses.map(status => status.get('id'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (timeline.indexOf(':pinned') !== -1) {
 | 
					 | 
				
			||||||
          return newIds;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const lastIndex = oldIds.findLastIndex(id => id !== null && compareId(id, newIds.last()) >= 0) + 1;
 | 
					        const lastIndex = oldIds.findLastIndex(id => id !== null && compareId(id, newIds.last()) >= 0) + 1;
 | 
				
			||||||
        const firstIndex = oldIds.take(lastIndex).findLastIndex(id => id !== null && compareId(id, newIds.first()) > 0);
 | 
					        const firstIndex = oldIds.take(lastIndex).findLastIndex(id => id !== null && compareId(id, newIds.first()) > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
      &-description {
 | 
					      &-description {
 | 
				
			||||||
        input {
 | 
					        input {
 | 
				
			||||||
          &::placeholder {
 | 
					          &::placeholder {
 | 
				
			||||||
            opacity: 1.0;
 | 
					            opacity: 1;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,5 +20,5 @@ $highlight-text-color: $classic-highlight-color !default;
 | 
				
			||||||
$action-button-color: #8d9ac2;
 | 
					$action-button-color: #8d9ac2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$inverted-text-color: $black !default;
 | 
					$inverted-text-color: $black !default;
 | 
				
			||||||
$lighter-text-color: darken($ui-base-color,6%) !default;
 | 
					$lighter-text-color: darken($ui-base-color, 6%) !default;
 | 
				
			||||||
$light-text-color: darken($ui-primary-color, 40%) !default;
 | 
					$light-text-color: darken($ui-primary-color, 40%) !default;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -279,6 +279,8 @@ h5 {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.hero-with-button {
 | 
					.hero-with-button {
 | 
				
			||||||
 | 
					  padding-bottom: 16px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  h1 {
 | 
					  h1 {
 | 
				
			||||||
    margin-bottom: 4px;
 | 
					    margin-bottom: 4px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -286,8 +288,6 @@ h5 {
 | 
				
			||||||
  p.lead {
 | 
					  p.lead {
 | 
				
			||||||
    margin-bottom: 32px;
 | 
					    margin-bottom: 32px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  padding-bottom: 16px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.header {
 | 
					.header {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,21 +1,21 @@
 | 
				
			||||||
@mixin avatar-radius() {
 | 
					@mixin avatar-radius {
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  background: transparent no-repeat;
 | 
					  background: transparent no-repeat;
 | 
				
			||||||
  background-position: 50%;
 | 
					  background-position: 50%;
 | 
				
			||||||
  background-clip: padding-box;
 | 
					  background-clip: padding-box;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@mixin avatar-size($size:48px) {
 | 
					@mixin avatar-size($size: 48px) {
 | 
				
			||||||
  width: $size;
 | 
					  width: $size;
 | 
				
			||||||
  height: $size;
 | 
					  height: $size;
 | 
				
			||||||
  background-size: $size $size;
 | 
					  background-size: $size $size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@mixin search-input() {
 | 
					@mixin search-input {
 | 
				
			||||||
  outline: 0;
 | 
					  outline: 0;
 | 
				
			||||||
  box-sizing: border-box;
 | 
					  box-sizing: border-box;
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  border: none;
 | 
					  border: 0;
 | 
				
			||||||
  box-shadow: none;
 | 
					  box-shadow: none;
 | 
				
			||||||
  font-family: inherit;
 | 
					  font-family: inherit;
 | 
				
			||||||
  background: $ui-base-color;
 | 
					  background: $ui-base-color;
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@mixin search-popout() {
 | 
					@mixin search-popout {
 | 
				
			||||||
  background: $simple-background-color;
 | 
					  background: $simple-background-color;
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  padding: 10px 14px;
 | 
					  padding: 10px 14px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,7 +171,7 @@ $content-width: 840px;
 | 
				
			||||||
      text-transform: none;
 | 
					      text-transform: none;
 | 
				
			||||||
      padding-bottom: 0;
 | 
					      padding-bottom: 0;
 | 
				
			||||||
      margin-bottom: 0;
 | 
					      margin-bottom: 0;
 | 
				
			||||||
      border-bottom: none;
 | 
					      border-bottom: 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    & > p {
 | 
					    & > p {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,8 @@
 | 
				
			||||||
  @if type-of($color) == 'color' {
 | 
					  @if type-of($color) == 'color' {
 | 
				
			||||||
    $color: str-slice(ie-hex-str($color), 4);
 | 
					    $color: str-slice(ie-hex-str($color), 4);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  @return '%23' + unquote($color)
 | 
					
 | 
				
			||||||
 | 
					  @return '%23' + unquote($color);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
body {
 | 
					body {
 | 
				
			||||||
| 
						 | 
					@ -15,7 +16,7 @@ body {
 | 
				
			||||||
  text-rendering: optimizelegibility;
 | 
					  text-rendering: optimizelegibility;
 | 
				
			||||||
  font-feature-settings: "kern";
 | 
					  font-feature-settings: "kern";
 | 
				
			||||||
  text-size-adjust: none;
 | 
					  text-size-adjust: none;
 | 
				
			||||||
  -webkit-tap-highlight-color: rgba(0,0,0,0);
 | 
					  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
 | 
				
			||||||
  -webkit-tap-highlight-color: transparent;
 | 
					  -webkit-tap-highlight-color: transparent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &.system-font {
 | 
					  &.system-font {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -128,7 +128,7 @@
 | 
				
			||||||
  display: inline-block;
 | 
					  display: inline-block;
 | 
				
			||||||
  padding: 0;
 | 
					  padding: 0;
 | 
				
			||||||
  color: $action-button-color;
 | 
					  color: $action-button-color;
 | 
				
			||||||
  border: none;
 | 
					  border: 0;
 | 
				
			||||||
  background: transparent;
 | 
					  background: transparent;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  transition: color 100ms ease-in;
 | 
					  transition: color 100ms ease-in;
 | 
				
			||||||
| 
						 | 
					@ -196,7 +196,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.text-icon-button {
 | 
					.text-icon-button {
 | 
				
			||||||
  color: $lighter-text-color;
 | 
					  color: $lighter-text-color;
 | 
				
			||||||
  border: none;
 | 
					  border: 0;
 | 
				
			||||||
  background: transparent;
 | 
					  background: transparent;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  font-weight: 600;
 | 
					  font-weight: 600;
 | 
				
			||||||
| 
						 | 
					@ -353,12 +353,12 @@
 | 
				
			||||||
  .spoiler-input {
 | 
					  .spoiler-input {
 | 
				
			||||||
    height: 0;
 | 
					    height: 0;
 | 
				
			||||||
    transform-origin: bottom;
 | 
					    transform-origin: bottom;
 | 
				
			||||||
    opacity: 0.0;
 | 
					    opacity: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &.spoiler-input--visible {
 | 
					    &.spoiler-input--visible {
 | 
				
			||||||
      height: 36px;
 | 
					      height: 36px;
 | 
				
			||||||
      margin-bottom: 11px;
 | 
					      margin-bottom: 11px;
 | 
				
			||||||
      opacity: 1.0;
 | 
					      opacity: 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -408,12 +408,20 @@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .emoji-picker-wrapper,
 | 
					 | 
				
			||||||
  .autosuggest-textarea__suggestions-wrapper {
 | 
					  .autosuggest-textarea__suggestions-wrapper {
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    height: 0;
 | 
					    height: 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .emoji-picker-wrapper {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    height: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.emoji-picker-wrapper--hidden {
 | 
				
			||||||
 | 
					      display: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .autosuggest-textarea__suggestions {
 | 
					  .autosuggest-textarea__suggestions {
 | 
				
			||||||
    box-sizing: border-box;
 | 
					    box-sizing: border-box;
 | 
				
			||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
| 
						 | 
					@ -1185,7 +1193,7 @@
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.account__avatar {
 | 
					.account__avatar {
 | 
				
			||||||
  @include avatar-radius();
 | 
					  @include avatar-radius;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &-inline {
 | 
					  &-inline {
 | 
				
			||||||
| 
						 | 
					@ -1195,11 +1203,11 @@
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &-composite {
 | 
					  &-composite {
 | 
				
			||||||
    @include avatar-radius();
 | 
					    @include avatar-radius;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    & > div {
 | 
					    & > div {
 | 
				
			||||||
      @include avatar-radius();
 | 
					      @include avatar-radius;
 | 
				
			||||||
      float: left;
 | 
					      float: left;
 | 
				
			||||||
      position: relative;
 | 
					      position: relative;
 | 
				
			||||||
      box-sizing: border-box;
 | 
					      box-sizing: border-box;
 | 
				
			||||||
| 
						 | 
					@ -1215,12 +1223,12 @@ a .account__avatar {
 | 
				
			||||||
  @include avatar-size(48px);
 | 
					  @include avatar-size(48px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &-base {
 | 
					  &-base {
 | 
				
			||||||
    @include avatar-radius();
 | 
					    @include avatar-radius;
 | 
				
			||||||
    @include avatar-size(36px);
 | 
					    @include avatar-size(36px);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &-overlay {
 | 
					  &-overlay {
 | 
				
			||||||
    @include avatar-radius();
 | 
					    @include avatar-radius;
 | 
				
			||||||
    @include avatar-size(24px);
 | 
					    @include avatar-size(24px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    position: absolute;
 | 
					    position: absolute;
 | 
				
			||||||
| 
						 | 
					@ -1598,13 +1606,13 @@ a.account__display-name {
 | 
				
			||||||
    .icon-button.close {
 | 
					    .icon-button.close {
 | 
				
			||||||
      position: absolute;
 | 
					      position: absolute;
 | 
				
			||||||
      pointer-events: none;
 | 
					      pointer-events: none;
 | 
				
			||||||
      transform: scale(0.0, 1.0) translate(-100%, 0);
 | 
					      transform: scale(0, 1) translate(-100%, 0);
 | 
				
			||||||
      opacity: 0;
 | 
					      opacity: 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .compose__action-bar .icon-button {
 | 
					    .compose__action-bar .icon-button {
 | 
				
			||||||
      pointer-events: auto;
 | 
					      pointer-events: auto;
 | 
				
			||||||
      transform: scale(1.0, 1.0) translate(0, 0);
 | 
					      transform: scale(1, 1) translate(0, 0);
 | 
				
			||||||
      opacity: 1;
 | 
					      opacity: 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -2071,6 +2079,10 @@ a.account__display-name {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .account {
 | 
					    .account {
 | 
				
			||||||
      padding: 15px 10px;
 | 
					      padding: 15px 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      &__header__bio {
 | 
				
			||||||
 | 
					        margin: 0 -10px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .notification {
 | 
					    .notification {
 | 
				
			||||||
| 
						 | 
					@ -2699,7 +2711,7 @@ a.account__display-name {
 | 
				
			||||||
.setting-text {
 | 
					.setting-text {
 | 
				
			||||||
  color: $darker-text-color;
 | 
					  color: $darker-text-color;
 | 
				
			||||||
  background: transparent;
 | 
					  background: transparent;
 | 
				
			||||||
  border: none;
 | 
					  border: 0;
 | 
				
			||||||
  border-bottom: 2px solid $ui-primary-color;
 | 
					  border-bottom: 2px solid $ui-primary-color;
 | 
				
			||||||
  box-sizing: border-box;
 | 
					  box-sizing: border-box;
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
| 
						 | 
					@ -3037,7 +3049,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  & > button {
 | 
					  & > button {
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    border: none;
 | 
					    border: 0;
 | 
				
			||||||
    padding: 15px 0 15px 15px;
 | 
					    padding: 15px 0 15px 15px;
 | 
				
			||||||
    color: inherit;
 | 
					    color: inherit;
 | 
				
			||||||
    background: transparent;
 | 
					    background: transparent;
 | 
				
			||||||
| 
						 | 
					@ -3202,11 +3214,11 @@ a.status-card.compact:hover {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.no-reduce-motion .loading-indicator span {
 | 
					.no-reduce-motion .loading-indicator span {
 | 
				
			||||||
  animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000);
 | 
					  animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.no-reduce-motion .loading-indicator__figure {
 | 
					.no-reduce-motion .loading-indicator__figure {
 | 
				
			||||||
  animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000);
 | 
					  animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@keyframes loader-figure {
 | 
					@keyframes loader-figure {
 | 
				
			||||||
| 
						 | 
					@ -3373,7 +3385,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .column-select {
 | 
					  .column-select {
 | 
				
			||||||
    &__control {
 | 
					    &__control {
 | 
				
			||||||
      @include search-input();
 | 
					      @include search-input;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &__placeholder {
 | 
					    &__placeholder {
 | 
				
			||||||
| 
						 | 
					@ -3424,7 +3436,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &__menu {
 | 
					    &__menu {
 | 
				
			||||||
      @include search-popout();
 | 
					      @include search-popout;
 | 
				
			||||||
      padding: 0;
 | 
					      padding: 0;
 | 
				
			||||||
      background: $ui-secondary-color;
 | 
					      background: $ui-secondary-color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -3585,7 +3597,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.no-reduce-motion .shake-bottom {
 | 
					.no-reduce-motion .shake-bottom {
 | 
				
			||||||
  transform-origin: 50% 100%;
 | 
					  transform-origin: 50% 100%;
 | 
				
			||||||
  animation: shake-bottom 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) 2s 2 both;
 | 
					  animation: shake-bottom 0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955) 2s 2 both;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.emoji-picker-dropdown__menu {
 | 
					.emoji-picker-dropdown__menu {
 | 
				
			||||||
| 
						 | 
					@ -3880,10 +3892,11 @@ a.status-card.compact:hover {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.search__input {
 | 
					.search__input {
 | 
				
			||||||
 | 
					  @include search-input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  padding: 10px;
 | 
					  padding: 10px;
 | 
				
			||||||
  padding-right: 30px;
 | 
					  padding-right: 30px;
 | 
				
			||||||
  @include search-input();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.search__icon {
 | 
					.search__icon {
 | 
				
			||||||
| 
						 | 
					@ -4491,14 +4504,14 @@ a.status-card.compact:hover {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.actions-modal {
 | 
					.actions-modal {
 | 
				
			||||||
 | 
					  max-height: 80vh;
 | 
				
			||||||
 | 
					  max-width: 80vw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .status {
 | 
					  .status {
 | 
				
			||||||
    overflow-y: auto;
 | 
					    overflow-y: auto;
 | 
				
			||||||
    max-height: 300px;
 | 
					    max-height: 300px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  max-height: 80vh;
 | 
					 | 
				
			||||||
  max-width: 80vw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .actions-modal__item-label {
 | 
					  .actions-modal__item-label {
 | 
				
			||||||
    font-weight: 500;
 | 
					    font-weight: 500;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -4713,7 +4726,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.media-gallery__item {
 | 
					.media-gallery__item {
 | 
				
			||||||
  border: none;
 | 
					  border: 0;
 | 
				
			||||||
  box-sizing: border-box;
 | 
					  box-sizing: border-box;
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  float: left;
 | 
					  float: left;
 | 
				
			||||||
| 
						 | 
					@ -5173,7 +5186,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.account-gallery__item {
 | 
					.account-gallery__item {
 | 
				
			||||||
  border: none;
 | 
					  border: 0;
 | 
				
			||||||
  box-sizing: border-box;
 | 
					  box-sizing: border-box;
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
| 
						 | 
					@ -5247,7 +5260,7 @@ a.status-card.compact:hover {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.search-popout {
 | 
					.search-popout {
 | 
				
			||||||
  @include search-popout();
 | 
					  @include search-popout;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noscript {
 | 
					noscript {
 | 
				
			||||||
| 
						 | 
					@ -5349,14 +5362,14 @@ noscript {
 | 
				
			||||||
        .icon-button.close {
 | 
					        .icon-button.close {
 | 
				
			||||||
          pointer-events: auto;
 | 
					          pointer-events: auto;
 | 
				
			||||||
          opacity: 1;
 | 
					          opacity: 1;
 | 
				
			||||||
          transform: scale(1.0, 1.0) translate(0, 0);
 | 
					          transform: scale(1, 1) translate(0, 0);
 | 
				
			||||||
          bottom: 5px;
 | 
					          bottom: 5px;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .compose__action-bar .icon-button {
 | 
					        .compose__action-bar .icon-button {
 | 
				
			||||||
          pointer-events: none;
 | 
					          pointer-events: none;
 | 
				
			||||||
          opacity: 0;
 | 
					          opacity: 0;
 | 
				
			||||||
          transform: scale(0.0, 1.0) translate(100%, 0);
 | 
					          transform: scale(0, 1) translate(100%, 0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -5386,7 +5399,7 @@ noscript {
 | 
				
			||||||
      box-sizing: border-box;
 | 
					      box-sizing: border-box;
 | 
				
			||||||
      display: block;
 | 
					      display: block;
 | 
				
			||||||
      width: 100%;
 | 
					      width: 100%;
 | 
				
			||||||
      border: none;
 | 
					      border: 0;
 | 
				
			||||||
      padding: 10px;
 | 
					      padding: 10px;
 | 
				
			||||||
      font-family: $font-monospace, monospace;
 | 
					      font-family: $font-monospace, monospace;
 | 
				
			||||||
      background: $ui-base-color;
 | 
					      background: $ui-base-color;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,7 @@
 | 
				
			||||||
  grid-auto-rows: max-content;
 | 
					  grid-auto-rows: max-content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .column-0 {
 | 
					  .column-0 {
 | 
				
			||||||
    grid-column: 1/3;
 | 
					    grid-column: 1 / 3;
 | 
				
			||||||
    grid-row: 1;
 | 
					    grid-row: 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,7 +136,7 @@
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .column-3 {
 | 
					  .column-3 {
 | 
				
			||||||
    grid-column: 1/3;
 | 
					    grid-column: 1 / 3;
 | 
				
			||||||
    grid-row: 3;
 | 
					    grid-row: 3;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,14 @@
 | 
				
			||||||
.emoji-mart {
 | 
					.emoji-mart {
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  color: $inverted-text-color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &,
 | 
					  &,
 | 
				
			||||||
  * {
 | 
					  * {
 | 
				
			||||||
    box-sizing: border-box;
 | 
					    box-sizing: border-box;
 | 
				
			||||||
    line-height: 1.15;
 | 
					    line-height: 1.15;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  font-size: 13px;
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  color: $inverted-text-color;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .emoji-mart-emoji {
 | 
					  .emoji-mart-emoji {
 | 
				
			||||||
    padding: 6px;
 | 
					    padding: 6px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -553,7 +553,7 @@ code {
 | 
				
			||||||
    box-sizing: border-box;
 | 
					    box-sizing: border-box;
 | 
				
			||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    border: none;
 | 
					    border: 0;
 | 
				
			||||||
    padding: 10px;
 | 
					    padding: 10px;
 | 
				
			||||||
    font-family: $font-monospace, monospace;
 | 
					    font-family: $font-monospace, monospace;
 | 
				
			||||||
    background: $ui-base-color;
 | 
					    background: $ui-base-color;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,7 +47,6 @@
 | 
				
			||||||
      width: 100%;
 | 
					      width: 100%;
 | 
				
			||||||
      font-size: 14px;
 | 
					      font-size: 14px;
 | 
				
			||||||
      color: $inverted-text-color;
 | 
					      color: $inverted-text-color;
 | 
				
			||||||
      display: block;
 | 
					 | 
				
			||||||
      outline: 0;
 | 
					      outline: 0;
 | 
				
			||||||
      font-family: inherit;
 | 
					      font-family: inherit;
 | 
				
			||||||
      background: $simple-background-color;
 | 
					      background: $simple-background-color;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,7 +180,6 @@ body.rtl {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .fa-ul {
 | 
					  .fa-ul {
 | 
				
			||||||
    margin-left: 0;
 | 
					 | 
				
			||||||
    margin-left: 2.14285714em;
 | 
					    margin-left: 2.14285714em;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,7 +143,7 @@ class ActivityPub::Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # If the boosted toot is embedded and it is a self-boost, handle it like a Create
 | 
					    # If the boosted toot is embedded and it is a self-boost, handle it like a Create
 | 
				
			||||||
    unless unsupported_object_type?
 | 
					    unless unsupported_object_type?
 | 
				
			||||||
      actor_id = value_or_id(first_of_value(@object['attributedTo'])) || @account.uri
 | 
					      actor_id = value_or_id(first_of_value(@object['attributedTo']))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if actor_id == @account.uri
 | 
					      if actor_id == @account.uri
 | 
				
			||||||
        return ActivityPub::Activity.factory({ 'type' => 'Create', 'actor' => actor_id, 'object' => @object }, @account).perform
 | 
					        return ActivityPub::Activity.factory({ 'type' => 'Create', 'actor' => actor_id, 'object' => @object }, @account).perform
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityPub::Activity::Follow < ActivityPub::Activity
 | 
					class ActivityPub::Activity::Follow < ActivityPub::Activity
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def perform
 | 
					  def perform
 | 
				
			||||||
    target_account = account_from_uri(object_uri)
 | 
					    target_account = account_from_uri(object_uri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +30,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def reject_follow_request!(target_account)
 | 
					  def reject_follow_request!(target_account)
 | 
				
			||||||
    json = ActiveModelSerializers::SerializableResource.new(FollowRequest.new(account: @account, target_account: target_account, uri: @json['id']), serializer: ActivityPub::RejectFollowSerializer, adapter: ActivityPub::Adapter).to_json
 | 
					    json = Oj.dump(serialize_payload(FollowRequest.new(account: @account, target_account: target_account, uri: @json['id']), ActivityPub::RejectFollowSerializer))
 | 
				
			||||||
    ActivityPub::DeliveryWorker.perform_async(json, target_account.id, @account.inbox_url)
 | 
					    ActivityPub::DeliveryWorker.perform_async(json, target_account.id, @account.inbox_url)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,6 +208,10 @@ class Account < ApplicationRecord
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def sign?
 | 
				
			||||||
 | 
					    true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def keypair
 | 
					  def keypair
 | 
				
			||||||
    @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
 | 
					    @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
class Form::AccountBatch
 | 
					class Form::AccountBatch
 | 
				
			||||||
  include ActiveModel::Model
 | 
					  include ActiveModel::Model
 | 
				
			||||||
  include Authorization
 | 
					  include Authorization
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  attr_accessor :account_ids, :action, :current_account
 | 
					  attr_accessor :account_ids, :action, :current_account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,13 +55,7 @@ class Form::AccountBatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return unless follow.account.activitypub?
 | 
					    return unless follow.account.activitypub?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    json = ActiveModelSerializers::SerializableResource.new(
 | 
					    ActivityPub::DeliveryWorker.perform_async(Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer)), current_account.id, follow.account.inbox_url)
 | 
				
			||||||
      follow,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::RejectFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ActivityPub::DeliveryWorker.perform_async(json, current_account.id, follow.account.inbox_url)
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def approve!
 | 
					  def approve!
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -211,6 +211,8 @@ class Status < ApplicationRecord
 | 
				
			||||||
    public_visibility? || unlisted_visibility?
 | 
					    public_visibility? || unlisted_visibility?
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  alias sign? distributable?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def with_media?
 | 
					  def with_media?
 | 
				
			||||||
    media_attachments.any?
 | 
					    media_attachments.any?
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					@ -529,7 +531,7 @@ class Status < ApplicationRecord
 | 
				
			||||||
    return if direct_visibility?
 | 
					    return if direct_visibility?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    account&.increment_count!(:statuses_count)
 | 
					    account&.increment_count!(:statuses_count)
 | 
				
			||||||
    reblog&.increment_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
 | 
					    reblog&.increment_count!(:reblogs_count) if reblog?
 | 
				
			||||||
    thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
 | 
					    thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -537,7 +539,7 @@ class Status < ApplicationRecord
 | 
				
			||||||
    return if direct_visibility? || marked_for_mass_destruction?
 | 
					    return if direct_visibility? || marked_for_mass_destruction?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    account&.decrement_count!(:statuses_count)
 | 
					    account&.decrement_count!(:statuses_count)
 | 
				
			||||||
    reblog&.decrement_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
 | 
					    reblog&.decrement_count!(:reblogs_count) if reblog?
 | 
				
			||||||
    thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
 | 
					    thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AfterBlockDomainFromAccountService < BaseService
 | 
					class AfterBlockDomainFromAccountService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # This service does not create an AccountDomainBlock record,
 | 
					  # This service does not create an AccountDomainBlock record,
 | 
				
			||||||
  # it's meant to be called after such a record has been created
 | 
					  # it's meant to be called after such a record has been created
 | 
				
			||||||
  # synchronously, to "clean up"
 | 
					  # synchronously, to "clean up"
 | 
				
			||||||
| 
						 | 
					@ -31,12 +33,6 @@ class AfterBlockDomainFromAccountService < BaseService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return unless follow.account.activitypub?
 | 
					    return unless follow.account.activitypub?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    json = ActiveModelSerializers::SerializableResource.new(
 | 
					    ActivityPub::DeliveryWorker.perform_async(Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer)), @account.id, follow.account.inbox_url)
 | 
				
			||||||
      follow,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::RejectFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ActivityPub::DeliveryWorker.perform_async(json, @account.id, follow.account.inbox_url)
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthorizeFollowService < BaseService
 | 
					class AuthorizeFollowService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(source_account, target_account, **options)
 | 
					  def call(source_account, target_account, **options)
 | 
				
			||||||
    if options[:skip_follow_request]
 | 
					    if options[:skip_follow_request]
 | 
				
			||||||
      follow_request = FollowRequest.new(account: source_account, target_account: target_account, uri: options[:follow_request_uri])
 | 
					      follow_request = FollowRequest.new(account: source_account, target_account: target_account, uri: options[:follow_request_uri])
 | 
				
			||||||
| 
						 | 
					@ -24,11 +26,7 @@ class AuthorizeFollowService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(follow_request)
 | 
					  def build_json(follow_request)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(follow_request, ActivityPub::AcceptFollowSerializer))
 | 
				
			||||||
      follow_request,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::AcceptFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(follow_request)
 | 
					  def build_xml(follow_request)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BlockService < BaseService
 | 
					class BlockService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(account, target_account)
 | 
					  def call(account, target_account)
 | 
				
			||||||
    return if account.id == target_account.id
 | 
					    return if account.id == target_account.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,11 +28,7 @@ class BlockService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(block)
 | 
					  def build_json(block)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(block, ActivityPub::BlockSerializer))
 | 
				
			||||||
      block,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::BlockSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(block)
 | 
					  def build_xml(block)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								app/services/concerns/payloadable.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/services/concerns/payloadable.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Payloadable
 | 
				
			||||||
 | 
					  def serialize_payload(record, serializer, options = {})
 | 
				
			||||||
 | 
					    signer    = options.delete(:signer)
 | 
				
			||||||
 | 
					    sign_with = options.delete(:sign_with)
 | 
				
			||||||
 | 
					    payload   = ActiveModelSerializers::SerializableResource.new(record, options.merge(serializer: serializer, adapter: ActivityPub::Adapter)).as_json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (record.respond_to?(:sign?) && record.sign?) && signer && signing_enabled?
 | 
				
			||||||
 | 
					      ActivityPub::LinkedDataSignature.new(payload).sign!(signer, sign_with: sign_with)
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      payload
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def signing_enabled?
 | 
				
			||||||
 | 
					    true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FavouriteService < BaseService
 | 
					class FavouriteService < BaseService
 | 
				
			||||||
  include Authorization
 | 
					  include Authorization
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Favourite a status and notify remote user
 | 
					  # Favourite a status and notify remote user
 | 
				
			||||||
  # @param [Account] account
 | 
					  # @param [Account] account
 | 
				
			||||||
| 
						 | 
					@ -43,11 +44,7 @@ class FavouriteService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(favourite)
 | 
					  def build_json(favourite)
 | 
				
			||||||
    Oj.dump(ActivityPub::LinkedDataSignature.new(ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(favourite, ActivityPub::LikeSerializer))
 | 
				
			||||||
      favourite,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::LikeSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json).sign!(favourite.account))
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(favourite)
 | 
					  def build_xml(favourite)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FollowService < BaseService
 | 
					class FollowService < BaseService
 | 
				
			||||||
  include Redisable
 | 
					  include Redisable
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Follow a remote user, notify remote user about the follow
 | 
					  # Follow a remote user, notify remote user about the follow
 | 
				
			||||||
  # @param [Account] source_account From which to follow
 | 
					  # @param [Account] source_account From which to follow
 | 
				
			||||||
| 
						 | 
					@ -78,10 +79,6 @@ class FollowService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(follow_request)
 | 
					  def build_json(follow_request)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(follow_request, ActivityPub::FollowSerializer))
 | 
				
			||||||
      follow_request,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::FollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProcessMentionsService < BaseService
 | 
					class ProcessMentionsService < BaseService
 | 
				
			||||||
  include StreamEntryRenderer
 | 
					  include StreamEntryRenderer
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Scan status for mentions and fetch remote mentioned users, create
 | 
					  # Scan status for mentions and fetch remote mentioned users, create
 | 
				
			||||||
  # local mention pointers, send Salmon notifications to mentioned
 | 
					  # local mention pointers, send Salmon notifications to mentioned
 | 
				
			||||||
| 
						 | 
					@ -61,12 +62,7 @@ class ProcessMentionsService < BaseService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def activitypub_json
 | 
					  def activitypub_json
 | 
				
			||||||
    return @activitypub_json if defined?(@activitypub_json)
 | 
					    return @activitypub_json if defined?(@activitypub_json)
 | 
				
			||||||
    payload = ActiveModelSerializers::SerializableResource.new(
 | 
					    @activitypub_json = Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @status.account))
 | 
				
			||||||
      @status,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::ActivitySerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
    @activitypub_json = Oj.dump(@status.distributable? ? ActivityPub::LinkedDataSignature.new(payload).sign!(@status.account) : payload)
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def resolve_account_service
 | 
					  def resolve_account_service
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
class ReblogService < BaseService
 | 
					class ReblogService < BaseService
 | 
				
			||||||
  include Authorization
 | 
					  include Authorization
 | 
				
			||||||
  include StreamEntryRenderer
 | 
					  include StreamEntryRenderer
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Reblog a status and notify its remote author
 | 
					  # Reblog a status and notify its remote author
 | 
				
			||||||
  # @param [Account] account Account to reblog from
 | 
					  # @param [Account] account Account to reblog from
 | 
				
			||||||
| 
						 | 
					@ -56,10 +57,6 @@ class ReblogService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(reblog)
 | 
					  def build_json(reblog)
 | 
				
			||||||
    Oj.dump(ActivityPub::LinkedDataSignature.new(ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(reblog, ActivityPub::ActivitySerializer, signer: reblog.account))
 | 
				
			||||||
      reblog,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::ActivitySerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json).sign!(reblog.account))
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RejectFollowService < BaseService
 | 
					class RejectFollowService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(source_account, target_account)
 | 
					  def call(source_account, target_account)
 | 
				
			||||||
    follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)
 | 
					    follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account)
 | 
				
			||||||
    follow_request.reject!
 | 
					    follow_request.reject!
 | 
				
			||||||
| 
						 | 
					@ -19,11 +21,7 @@ class RejectFollowService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(follow_request)
 | 
					  def build_json(follow_request)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(follow_request, ActivityPub::RejectFollowSerializer))
 | 
				
			||||||
      follow_request,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::RejectFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(follow_request)
 | 
					  def build_xml(follow_request)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
class RemoveStatusService < BaseService
 | 
					class RemoveStatusService < BaseService
 | 
				
			||||||
  include StreamEntryRenderer
 | 
					  include StreamEntryRenderer
 | 
				
			||||||
  include Redisable
 | 
					  include Redisable
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(status, **options)
 | 
					  def call(status, **options)
 | 
				
			||||||
    @payload      = Oj.dump(event: :delete, payload: status.id.to_s)
 | 
					    @payload      = Oj.dump(event: :delete, payload: status.id.to_s)
 | 
				
			||||||
| 
						 | 
					@ -116,15 +117,7 @@ class RemoveStatusService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def signed_activity_json
 | 
					  def signed_activity_json
 | 
				
			||||||
    @signed_activity_json ||= Oj.dump(ActivityPub::LinkedDataSignature.new(activity_json).sign!(@account))
 | 
					    @signed_activity_json ||= Oj.dump(serialize_payload(@status, @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer, signer: @account))
 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def activity_json
 | 
					 | 
				
			||||||
    @activity_json ||= ActiveModelSerializers::SerializableResource.new(
 | 
					 | 
				
			||||||
      @status,
 | 
					 | 
				
			||||||
      serializer: @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def remove_reblogs
 | 
					  def remove_reblogs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReportService < BaseService
 | 
					class ReportService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(source_account, target_account, options = {})
 | 
					  def call(source_account, target_account, options = {})
 | 
				
			||||||
    @source_account = source_account
 | 
					    @source_account = source_account
 | 
				
			||||||
    @target_account = target_account
 | 
					    @target_account = target_account
 | 
				
			||||||
| 
						 | 
					@ -44,12 +46,7 @@ class ReportService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def payload
 | 
					  def payload
 | 
				
			||||||
    Oj.dump(ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(@report, ActivityPub::FlagSerializer, account: some_local_account))
 | 
				
			||||||
      @report,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::FlagSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter,
 | 
					 | 
				
			||||||
      account: some_local_account
 | 
					 | 
				
			||||||
    ).as_json)
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def some_local_account
 | 
					  def some_local_account
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SuspendAccountService < BaseService
 | 
					class SuspendAccountService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ASSOCIATIONS_ON_SUSPEND = %w(
 | 
					  ASSOCIATIONS_ON_SUSPEND = %w(
 | 
				
			||||||
    account_pins
 | 
					    account_pins
 | 
				
			||||||
    active_relationships
 | 
					    active_relationships
 | 
				
			||||||
| 
						 | 
					@ -118,23 +120,11 @@ class SuspendAccountService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def delete_actor_json
 | 
					  def delete_actor_json
 | 
				
			||||||
    return @delete_actor_json if defined?(@delete_actor_json)
 | 
					    @delete_actor_json ||= Oj.dump(serialize_payload(@account, ActivityPub::DeleteActorSerializer, signer: @account))
 | 
				
			||||||
 | 
					 | 
				
			||||||
    payload = ActiveModelSerializers::SerializableResource.new(
 | 
					 | 
				
			||||||
      @account,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::DeleteActorSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @delete_actor_json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account))
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_reject_json(follow)
 | 
					  def build_reject_json(follow)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))
 | 
				
			||||||
      follow,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::RejectFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def delivery_inboxes
 | 
					  def delivery_inboxes
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UnblockService < BaseService
 | 
					class UnblockService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(account, target_account)
 | 
					  def call(account, target_account)
 | 
				
			||||||
    return unless account.blocking?(target_account)
 | 
					    return unless account.blocking?(target_account)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,11 +22,7 @@ class UnblockService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(unblock)
 | 
					  def build_json(unblock)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(unblock, ActivityPub::UndoBlockSerializer))
 | 
				
			||||||
      unblock,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::UndoBlockSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(block)
 | 
					  def build_xml(block)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UnfavouriteService < BaseService
 | 
					class UnfavouriteService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(account, status)
 | 
					  def call(account, status)
 | 
				
			||||||
    favourite = Favourite.find_by!(account: account, status: status)
 | 
					    favourite = Favourite.find_by!(account: account, status: status)
 | 
				
			||||||
    favourite.destroy!
 | 
					    favourite.destroy!
 | 
				
			||||||
| 
						 | 
					@ -21,11 +23,7 @@ class UnfavouriteService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(favourite)
 | 
					  def build_json(favourite)
 | 
				
			||||||
    Oj.dump(ActivityPub::LinkedDataSignature.new(ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(favourite, ActivityPub::UndoLikeSerializer))
 | 
				
			||||||
      favourite,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::UndoLikeSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json).sign!(favourite.account))
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(favourite)
 | 
					  def build_xml(favourite)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UnfollowService < BaseService
 | 
					class UnfollowService < BaseService
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Unfollow and notify the remote user
 | 
					  # Unfollow and notify the remote user
 | 
				
			||||||
  # @param [Account] source_account Where to unfollow from
 | 
					  # @param [Account] source_account Where to unfollow from
 | 
				
			||||||
  # @param [Account] target_account Which to unfollow
 | 
					  # @param [Account] target_account Which to unfollow
 | 
				
			||||||
| 
						 | 
					@ -50,19 +52,11 @@ class UnfollowService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(follow)
 | 
					  def build_json(follow)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(follow, ActivityPub::UndoFollowSerializer))
 | 
				
			||||||
      follow,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::UndoFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_reject_json(follow)
 | 
					  def build_reject_json(follow)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer))
 | 
				
			||||||
      follow,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::RejectFollowSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_xml(follow)
 | 
					  def build_xml(follow)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VoteService < BaseService
 | 
					class VoteService < BaseService
 | 
				
			||||||
  include Authorization
 | 
					  include Authorization
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(account, poll, choices)
 | 
					  def call(account, poll, choices)
 | 
				
			||||||
    authorize_with account, poll, :vote?
 | 
					    authorize_with account, poll, :vote?
 | 
				
			||||||
| 
						 | 
					@ -50,10 +51,6 @@ class VoteService < BaseService
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def build_json(vote)
 | 
					  def build_json(vote)
 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					    Oj.dump(serialize_payload(vote, ActivityPub::VoteSerializer))
 | 
				
			||||||
      vote,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::VoteSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).to_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,8 @@
 | 
				
			||||||
        = "(@#{account.username})"
 | 
					        = "(@#{account.username})"
 | 
				
			||||||
      %br/
 | 
					      %br/
 | 
				
			||||||
      = account.user_current_sign_in_ip
 | 
					      = account.user_current_sign_in_ip
 | 
				
			||||||
 | 
					      •
 | 
				
			||||||
 | 
					      = t 'admin.accounts.time_in_queue', time: time_ago_in_words(account.user&.created_at)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - if account.user&.invite_request&.text&.present?
 | 
					    - if account.user&.invite_request&.text&.present?
 | 
				
			||||||
      .pending-account__body
 | 
					      .pending-account__body
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityPub::DistributePollUpdateWorker
 | 
					class ActivityPub::DistributePollUpdateWorker
 | 
				
			||||||
  include Sidekiq::Worker
 | 
					  include Sidekiq::Worker
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sidekiq_options queue: 'push', unique: :until_executed, retry: 0
 | 
					  sidekiq_options queue: 'push', unique: :until_executed, retry: 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,20 +42,8 @@ class ActivityPub::DistributePollUpdateWorker
 | 
				
			||||||
    @inboxes
 | 
					    @inboxes
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def signed_payload
 | 
					 | 
				
			||||||
    Oj.dump(ActivityPub::LinkedDataSignature.new(unsigned_payload).sign!(@account))
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def unsigned_payload
 | 
					 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					 | 
				
			||||||
      @status,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::UpdatePollSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def payload
 | 
					  def payload
 | 
				
			||||||
    @payload ||= @status.distributable? ? signed_payload : Oj.dump(unsigned_payload)
 | 
					    @payload ||= Oj.dump(serialize_payload(@status, ActivityPub::UpdatePollSerializer, signer: @account))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def relay!
 | 
					  def relay!
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityPub::DistributionWorker
 | 
					class ActivityPub::DistributionWorker
 | 
				
			||||||
  include Sidekiq::Worker
 | 
					  include Sidekiq::Worker
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sidekiq_options queue: 'push'
 | 
					  sidekiq_options queue: 'push'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,20 +42,8 @@ class ActivityPub::DistributionWorker
 | 
				
			||||||
                 end
 | 
					                 end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def signed_payload
 | 
					 | 
				
			||||||
    Oj.dump(ActivityPub::LinkedDataSignature.new(unsigned_payload).sign!(@account))
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def unsigned_payload
 | 
					 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					 | 
				
			||||||
      @status,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::ActivitySerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def payload
 | 
					  def payload
 | 
				
			||||||
    @payload ||= @status.distributable? ? signed_payload : Oj.dump(unsigned_payload)
 | 
					    @payload ||= Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @account))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def relay!
 | 
					  def relay!
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityPub::ReplyDistributionWorker
 | 
					class ActivityPub::ReplyDistributionWorker
 | 
				
			||||||
  include Sidekiq::Worker
 | 
					  include Sidekiq::Worker
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sidekiq_options queue: 'push'
 | 
					  sidekiq_options queue: 'push'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,19 +28,7 @@ class ActivityPub::ReplyDistributionWorker
 | 
				
			||||||
    @inboxes ||= @account.followers.inboxes
 | 
					    @inboxes ||= @account.followers.inboxes
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def signed_payload
 | 
					 | 
				
			||||||
    Oj.dump(ActivityPub::LinkedDataSignature.new(unsigned_payload).sign!(@status.account))
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def unsigned_payload
 | 
					 | 
				
			||||||
    ActiveModelSerializers::SerializableResource.new(
 | 
					 | 
				
			||||||
      @status,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::ActivitySerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def payload
 | 
					  def payload
 | 
				
			||||||
    @payload ||= @status.distributable? ? signed_payload : Oj.dump(unsigned_payload)
 | 
					    @payload ||= Oj.dump(serialize_payload(@status, ActivityPub::ActivitySerializer, signer: @status.account))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityPub::UpdateDistributionWorker
 | 
					class ActivityPub::UpdateDistributionWorker
 | 
				
			||||||
  include Sidekiq::Worker
 | 
					  include Sidekiq::Worker
 | 
				
			||||||
 | 
					  include Payloadable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sidekiq_options queue: 'push'
 | 
					  sidekiq_options queue: 'push'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,14 +28,6 @@ class ActivityPub::UpdateDistributionWorker
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def signed_payload
 | 
					  def signed_payload
 | 
				
			||||||
    @signed_payload ||= Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account, sign_with: @options[:sign_with]))
 | 
					    @signed_payload ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account, sign_with: @options[:sign_with]))
 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def payload
 | 
					 | 
				
			||||||
    @payload ||= ActiveModelSerializers::SerializableResource.new(
 | 
					 | 
				
			||||||
      @account,
 | 
					 | 
				
			||||||
      serializer: ActivityPub::UpdateSerializer,
 | 
					 | 
				
			||||||
      adapter: ActivityPub::Adapter
 | 
					 | 
				
			||||||
    ).as_json
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,6 +174,7 @@ en:
 | 
				
			||||||
      statuses: Statuses
 | 
					      statuses: Statuses
 | 
				
			||||||
      subscribe: Subscribe
 | 
					      subscribe: Subscribe
 | 
				
			||||||
      suspended: Suspended
 | 
					      suspended: Suspended
 | 
				
			||||||
 | 
					      time_in_queue: Waiting in queue %{time}
 | 
				
			||||||
      title: Accounts
 | 
					      title: Accounts
 | 
				
			||||||
      unconfirmed_email: Unconfirmed email
 | 
					      unconfirmed_email: Unconfirmed email
 | 
				
			||||||
      undo_silenced: Undo silence
 | 
					      undo_silenced: Undo silence
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,9 +10,10 @@
 | 
				
			||||||
    "build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
 | 
					    "build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
 | 
				
			||||||
    "manage:translations": "node ./config/webpack/translationRunner.js",
 | 
					    "manage:translations": "node ./config/webpack/translationRunner.js",
 | 
				
			||||||
    "start": "node ./streaming/index.js",
 | 
					    "start": "node ./streaming/index.js",
 | 
				
			||||||
    "test": "${npm_execpath} run test:lint && ${npm_execpath} run test:jest",
 | 
					    "test": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:jest",
 | 
				
			||||||
    "test:lint": "eslint --ext=js .",
 | 
					    "test:lint": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:lint:sass",
 | 
				
			||||||
    "test:lint:sass": "sass-lint .",
 | 
					    "test:lint:js": "eslint --ext=js .",
 | 
				
			||||||
 | 
					    "test:lint:sass": "sass-lint -v",
 | 
				
			||||||
    "test:jest": "cross-env NODE_ENV=test jest --coverage"
 | 
					    "test:jest": "cross-env NODE_ENV=test jest --coverage"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,21 +58,6 @@ RSpec.describe ActivityPub::Activity::Announce do
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'self-boost of a previously unknown status with missing attributedTo' do
 | 
					 | 
				
			||||||
        let(:object_json) do
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            id: 'https://example.com/actor#bar',
 | 
					 | 
				
			||||||
            type: 'Note',
 | 
					 | 
				
			||||||
            content: 'Lorem ipsum',
 | 
					 | 
				
			||||||
            to: 'http://example.com/followers',
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it 'creates a reblog by sender of status' do
 | 
					 | 
				
			||||||
          expect(sender.reblogged?(sender.statuses.first)).to be true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context 'self-boost of a previously unknown status with correct attributedTo' do
 | 
					      context 'self-boost of a previously unknown status with correct attributedTo' do
 | 
				
			||||||
        let(:object_json) do
 | 
					        let(:object_json) do
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
| 
						 | 
					@ -122,6 +107,7 @@ RSpec.describe ActivityPub::Activity::Announce do
 | 
				
			||||||
            type: 'Note',
 | 
					            type: 'Note',
 | 
				
			||||||
            content: 'Lorem ipsum',
 | 
					            content: 'Lorem ipsum',
 | 
				
			||||||
            to: 'http://example.com/followers',
 | 
					            to: 'http://example.com/followers',
 | 
				
			||||||
 | 
					            attributedTo: 'https://example.com/actor',
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,6 +127,7 @@ RSpec.describe ActivityPub::Activity::Announce do
 | 
				
			||||||
            type: 'Note',
 | 
					            type: 'Note',
 | 
				
			||||||
            content: 'Lorem ipsum',
 | 
					            content: 'Lorem ipsum',
 | 
				
			||||||
            to: 'http://example.com/followers',
 | 
					            to: 'http://example.com/followers',
 | 
				
			||||||
 | 
					            attributedTo: 'https://example.com/actor',
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,6 +148,7 @@ RSpec.describe ActivityPub::Activity::Announce do
 | 
				
			||||||
          type: 'Note',
 | 
					          type: 'Note',
 | 
				
			||||||
          content: 'Lorem ipsum',
 | 
					          content: 'Lorem ipsum',
 | 
				
			||||||
          to: 'http://example.com/followers',
 | 
					          to: 'http://example.com/followers',
 | 
				
			||||||
 | 
					          attributedTo: 'https://example.com/actor',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue