Merge tag 'v3.3.0' into instance_only_statuses
This commit is contained in:
commit
cb085b4c44
@ -27,10 +27,10 @@ plugins:
|
|||||||
enabled: true
|
enabled: true
|
||||||
eslint:
|
eslint:
|
||||||
enabled: true
|
enabled: true
|
||||||
channel: eslint-6
|
channel: eslint-7
|
||||||
rubocop:
|
rubocop:
|
||||||
enabled: true
|
enabled: true
|
||||||
channel: rubocop-0-82
|
channel: rubocop-0-92
|
||||||
sass-lint:
|
sass-lint:
|
||||||
enabled: true
|
enabled: true
|
||||||
exclude_patterns:
|
exclude_patterns:
|
||||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: If something isn't working as expected
|
about: If something isn't working as expected
|
||||||
|
labels: bug
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Make sure that you are submitting a new bug that was not previously reported or already fixed -->
|
<!-- Make sure that you are submitting a new bug that was not previously reported or already fixed -->
|
||||||
|
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
about: I have a suggestion
|
about: I have a suggestion
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please use a concise and distinct title for the issue -->
|
<!-- Please use a concise and distinct title for the issue -->
|
||||||
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -11,7 +11,7 @@ updates:
|
|||||||
interval: weekly
|
interval: weekly
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
allow:
|
allow:
|
||||||
- dependency-type: all
|
- dependency-type: direct
|
||||||
|
|
||||||
- package-ecosystem: bundler
|
- package-ecosystem: bundler
|
||||||
directory: "/"
|
directory: "/"
|
||||||
@ -19,4 +19,4 @@ updates:
|
|||||||
interval: weekly
|
interval: weekly
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
allow:
|
allow:
|
||||||
- dependency-type: all
|
- dependency-type: direct
|
||||||
|
185
.rubocop.yml
185
.rubocop.yml
@ -25,30 +25,68 @@ Layout/AccessModifierIndentation:
|
|||||||
Layout/EmptyLineAfterMagicComment:
|
Layout/EmptyLineAfterMagicComment:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/EmptyLineAfterGuardClause:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/EmptyLinesAroundAttributeAccessor:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Layout/HashAlignment:
|
||||||
|
Enabled: false
|
||||||
|
# EnforcedHashRocketStyle: table
|
||||||
|
# EnforcedColonStyle: table
|
||||||
|
|
||||||
|
Layout/SpaceAroundMethodCallOperator:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
Layout/SpaceInsideHashLiteralBraces:
|
Layout/SpaceInsideHashLiteralBraces:
|
||||||
EnforcedStyle: space
|
EnforcedStyle: space
|
||||||
|
|
||||||
|
Lint/DeprecatedOpenSSLConstant:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Lint/DuplicateElsifCondition:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Lint/MixedRegexpCaptureTypes:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Lint/RaiseException:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Lint/StructNewOverride:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
Lint/UselessAccessModifier:
|
Lint/UselessAccessModifier:
|
||||||
ContextCreatingMethods:
|
ContextCreatingMethods:
|
||||||
- class_methods
|
- class_methods
|
||||||
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 100
|
Max: 100
|
||||||
|
Exclude:
|
||||||
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
Metrics/BlockLength:
|
Metrics/BlockLength:
|
||||||
Max: 35
|
Max: 55
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/tasks/**/*'
|
- 'lib/tasks/**/*'
|
||||||
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
Metrics/BlockNesting:
|
Metrics/BlockNesting:
|
||||||
Max: 3
|
Max: 3
|
||||||
|
Exclude:
|
||||||
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
CountComments: false
|
CountComments: false
|
||||||
Max: 300
|
Max: 400
|
||||||
|
Exclude:
|
||||||
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
Max: 25
|
Max: 25
|
||||||
|
Exclude:
|
||||||
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
Layout/LineLength:
|
Layout/LineLength:
|
||||||
AllowURI: true
|
AllowURI: true
|
||||||
@ -56,7 +94,9 @@ Layout/LineLength:
|
|||||||
|
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
CountComments: false
|
CountComments: false
|
||||||
Max: 55
|
Max: 65
|
||||||
|
Exclude:
|
||||||
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
CountComments: false
|
CountComments: false
|
||||||
@ -67,34 +107,90 @@ Metrics/ParameterLists:
|
|||||||
CountKeywordArgs: true
|
CountKeywordArgs: true
|
||||||
|
|
||||||
Metrics/PerceivedComplexity:
|
Metrics/PerceivedComplexity:
|
||||||
Max: 20
|
Max: 25
|
||||||
|
|
||||||
Naming/MemoizedInstanceVariableName:
|
Naming/MemoizedInstanceVariableName:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Naming/MethodParameterName:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
Rails:
|
Rails:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
|
Rails/ApplicationController:
|
||||||
|
Enabled: false
|
||||||
|
Exclude:
|
||||||
|
- 'app/controllers/well_known/**/*.rb'
|
||||||
|
|
||||||
|
Rails/BelongsTo:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/ContentTag:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Rails/EnumHash:
|
Rails/EnumHash:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Rails/HasAndBelongsToMany:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Rails/SkipsModelValidations:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Rails/HttpStatus:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Rails/Exit:
|
Rails/Exit:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/mastodon/*'
|
- 'lib/mastodon/*'
|
||||||
- 'lib/cli.rb'
|
- 'lib/cli.rb'
|
||||||
|
|
||||||
|
Rails/FilePath:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/HasAndBelongsToMany:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/HasManyOrHasOneDependent:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Rails/HelperInstanceVariable:
|
Rails/HelperInstanceVariable:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/HttpStatus:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/IndexBy:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/InverseOf:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/LexicallyScopedActionFilter:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/OutputSafety:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Rails/RakeEnvironment:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/RedundantForeignKey:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/SkipsModelValidations:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Rails/UniqueValidationWithoutIndex:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/AccessorGrouping:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/AccessModifierDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/ArrayCoercion:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/BisectedAttrAccessor:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/CaseLikeIf:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
@ -109,6 +205,15 @@ Style/Documentation:
|
|||||||
Style/DoubleNegation:
|
Style/DoubleNegation:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
|
Style/ExpandPathArguments:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/ExponentialNotation:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/FormatString:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Style/FormatStringToken:
|
Style/FormatStringToken:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
@ -118,9 +223,33 @@ Style/FrozenStringLiteralComment:
|
|||||||
Style/GuardClause:
|
Style/GuardClause:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Style/HashAsLastArrayItem:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/HashEachMethods:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/HashLikeCase:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/HashTransformKeys:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/HashTransformValues:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/IfUnlessModifier:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/InverseMethods:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Style/Lambda:
|
Style/Lambda:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Style/MutableConstant:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Style/PercentLiteralDelimiters:
|
Style/PercentLiteralDelimiters:
|
||||||
PreferredDelimiters:
|
PreferredDelimiters:
|
||||||
'%i': '()'
|
'%i': '()'
|
||||||
@ -129,9 +258,36 @@ Style/PercentLiteralDelimiters:
|
|||||||
Style/PerlBackrefs:
|
Style/PerlBackrefs:
|
||||||
AutoCorrect: false
|
AutoCorrect: false
|
||||||
|
|
||||||
|
Style/RedundantAssignment:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/RedundantFetchBlock:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/RedundantFileExtensionInRequire:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Style/RedundantRegexpCharacterClass:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/RedundantRegexpEscape:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/RedundantReturn:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
Style/RegexpLiteral:
|
Style/RegexpLiteral:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Style/RescueStandardError:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/SignalException:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/SlicingWithRange:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
Style/SymbolArray:
|
Style/SymbolArray:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
@ -140,3 +296,6 @@ Style/TrailingCommaInArrayLiteral:
|
|||||||
|
|
||||||
Style/TrailingCommaInHashLiteral:
|
Style/TrailingCommaInHashLiteral:
|
||||||
EnforcedStyleForMultiline: 'comma'
|
EnforcedStyleForMultiline: 'comma'
|
||||||
|
|
||||||
|
Style/UnpackFirst:
|
||||||
|
Enabled: false
|
||||||
|
@ -1 +1 @@
|
|||||||
2.6.6
|
2.7.2
|
||||||
|
669
AUTHORS.md
669
AUTHORS.md
@ -5,38 +5,39 @@ Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon)
|
|||||||
and provided thanks to the work of the following contributors:
|
and provided thanks to the work of the following contributors:
|
||||||
|
|
||||||
* [Gargron](https://github.com/Gargron)
|
* [Gargron](https://github.com/Gargron)
|
||||||
* [dependabot-preview[bot]](https://github.com/apps/dependabot-preview)
|
|
||||||
* [ThibG](https://github.com/ThibG)
|
* [ThibG](https://github.com/ThibG)
|
||||||
* [ykzts](https://github.com/ykzts)
|
* [dependabot-preview[bot]](https://github.com/apps/dependabot-preview)
|
||||||
* [dependabot[bot]](https://github.com/apps/dependabot)
|
* [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
|
* [ykzts](https://github.com/ykzts)
|
||||||
* [akihikodaki](https://github.com/akihikodaki)
|
* [akihikodaki](https://github.com/akihikodaki)
|
||||||
* [mjankowski](https://github.com/mjankowski)
|
* [mjankowski](https://github.com/mjankowski)
|
||||||
* [unarist](https://github.com/unarist)
|
* [unarist](https://github.com/unarist)
|
||||||
* [yiskah](https://github.com/yiskah)
|
* [yiskah](https://github.com/yiskah)
|
||||||
* [nolanlawson](https://github.com/nolanlawson)
|
* [nolanlawson](https://github.com/nolanlawson)
|
||||||
* [abcang](https://github.com/abcang)
|
* [abcang](https://github.com/abcang)
|
||||||
* [ysksn](https://github.com/ysksn)
|
|
||||||
* [mayaeh](https://github.com/mayaeh)
|
* [mayaeh](https://github.com/mayaeh)
|
||||||
|
* [ysksn](https://github.com/ysksn)
|
||||||
* [sorin-davidoi](https://github.com/sorin-davidoi)
|
* [sorin-davidoi](https://github.com/sorin-davidoi)
|
||||||
|
* [noellabo](https://github.com/noellabo)
|
||||||
* [lynlynlynx](https://github.com/lynlynlynx)
|
* [lynlynlynx](https://github.com/lynlynlynx)
|
||||||
* [m4sk1n](mailto:me@m4sk.in)
|
* [m4sk1n](mailto:me@m4sk.in)
|
||||||
* [Marcin Mikołajczak](mailto:me@m4sk.in)
|
* [Marcin Mikołajczak](mailto:me@m4sk.in)
|
||||||
* [Kjwon15](https://github.com/Kjwon15)
|
* [Kjwon15](https://github.com/Kjwon15)
|
||||||
* [noellabo](https://github.com/noellabo)
|
|
||||||
* [renatolond](https://github.com/renatolond)
|
* [renatolond](https://github.com/renatolond)
|
||||||
* [alpaca-tc](https://github.com/alpaca-tc)
|
* [alpaca-tc](https://github.com/alpaca-tc)
|
||||||
* [jeroenpraat](https://github.com/jeroenpraat)
|
* [jeroenpraat](https://github.com/jeroenpraat)
|
||||||
* [nclm](https://github.com/nclm)
|
* [nclm](https://github.com/nclm)
|
||||||
* [ineffyble](https://github.com/ineffyble)
|
* [ineffyble](https://github.com/ineffyble)
|
||||||
* [shleeable](https://github.com/shleeable)
|
|
||||||
* [zunda](https://github.com/zunda)
|
* [zunda](https://github.com/zunda)
|
||||||
|
* [shleeable](https://github.com/shleeable)
|
||||||
* [Masoud Abkenar](mailto:ampbox@gmail.com)
|
* [Masoud Abkenar](mailto:ampbox@gmail.com)
|
||||||
* [blackle](https://github.com/blackle)
|
* [blackle](https://github.com/blackle)
|
||||||
* [Quent-in](https://github.com/Quent-in)
|
* [Quent-in](https://github.com/Quent-in)
|
||||||
* [JantsoP](https://github.com/JantsoP)
|
* [JantsoP](https://github.com/JantsoP)
|
||||||
* [nullkal](https://github.com/nullkal)
|
* [nullkal](https://github.com/nullkal)
|
||||||
* [yookoala](https://github.com/yookoala)
|
* [yookoala](https://github.com/yookoala)
|
||||||
* [Sasha-Sorokin](https://github.com/Sasha-Sorokin)
|
* [Brawaru](https://github.com/Brawaru)
|
||||||
|
* [ariasuni](https://github.com/ariasuni)
|
||||||
* [Aditoo17](https://github.com/Aditoo17)
|
* [Aditoo17](https://github.com/Aditoo17)
|
||||||
* [Quenty31](https://github.com/Quenty31)
|
* [Quenty31](https://github.com/Quenty31)
|
||||||
* [marek-lach](https://github.com/marek-lach)
|
* [marek-lach](https://github.com/marek-lach)
|
||||||
@ -45,9 +46,9 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [danhunsaker](https://github.com/danhunsaker)
|
* [danhunsaker](https://github.com/danhunsaker)
|
||||||
* [eramdam](https://github.com/eramdam)
|
* [eramdam](https://github.com/eramdam)
|
||||||
* [takayamaki](https://github.com/takayamaki)
|
* [takayamaki](https://github.com/takayamaki)
|
||||||
* [ariasuni](https://github.com/ariasuni)
|
|
||||||
* [masarakki](https://github.com/masarakki)
|
* [masarakki](https://github.com/masarakki)
|
||||||
* [ticky](https://github.com/ticky)
|
* [ticky](https://github.com/ticky)
|
||||||
|
* [trwnh](https://github.com/trwnh)
|
||||||
* [ThisIsMissEm](https://github.com/ThisIsMissEm)
|
* [ThisIsMissEm](https://github.com/ThisIsMissEm)
|
||||||
* [hinaloe](https://github.com/hinaloe)
|
* [hinaloe](https://github.com/hinaloe)
|
||||||
* [hcmiya](https://github.com/hcmiya)
|
* [hcmiya](https://github.com/hcmiya)
|
||||||
@ -57,10 +58,10 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [yukimochi](https://github.com/yukimochi)
|
* [yukimochi](https://github.com/yukimochi)
|
||||||
* [palindromordnilap](https://github.com/palindromordnilap)
|
* [palindromordnilap](https://github.com/palindromordnilap)
|
||||||
* [rkarabut](https://github.com/rkarabut)
|
* [rkarabut](https://github.com/rkarabut)
|
||||||
* [trwnh](https://github.com/trwnh)
|
|
||||||
* [nightpool](https://github.com/nightpool)
|
* [nightpool](https://github.com/nightpool)
|
||||||
* [Artoria2e5](https://github.com/Artoria2e5)
|
* [Artoria2e5](https://github.com/Artoria2e5)
|
||||||
* [marrus-sh](https://github.com/marrus-sh)
|
* [marrus-sh](https://github.com/marrus-sh)
|
||||||
|
* [dunn](https://github.com/dunn)
|
||||||
* [krainboltgreene](https://github.com/krainboltgreene)
|
* [krainboltgreene](https://github.com/krainboltgreene)
|
||||||
* [pfigel](https://github.com/pfigel)
|
* [pfigel](https://github.com/pfigel)
|
||||||
* [BoFFire](https://github.com/BoFFire)
|
* [BoFFire](https://github.com/BoFFire)
|
||||||
@ -84,25 +85,25 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [ashleyhull-versent](https://github.com/ashleyhull-versent)
|
* [ashleyhull-versent](https://github.com/ashleyhull-versent)
|
||||||
* [yhirano55](https://github.com/yhirano55)
|
* [yhirano55](https://github.com/yhirano55)
|
||||||
* [rinsuki](https://github.com/rinsuki)
|
* [rinsuki](https://github.com/rinsuki)
|
||||||
* [dunn](https://github.com/dunn)
|
|
||||||
* [devkral](https://github.com/devkral)
|
* [devkral](https://github.com/devkral)
|
||||||
* [camponez](https://github.com/camponez)
|
* [camponez](https://github.com/camponez)
|
||||||
* [hugogameiro](https://github.com/hugogameiro)
|
* [hugogameiro](https://github.com/hugogameiro)
|
||||||
* [SerCom_KC](mailto:szescxz@gmail.com)
|
* [SerCom_KC](mailto:szescxz@gmail.com)
|
||||||
* [aschmitz](https://github.com/aschmitz)
|
* [aschmitz](https://github.com/aschmitz)
|
||||||
|
* [mfmfuyu](https://github.com/mfmfuyu)
|
||||||
|
* [kedamaDQ](https://github.com/kedamaDQ)
|
||||||
* [fpiesche](https://github.com/fpiesche)
|
* [fpiesche](https://github.com/fpiesche)
|
||||||
* [gandaro](https://github.com/gandaro)
|
* [gandaro](https://github.com/gandaro)
|
||||||
* [johnsudaar](https://github.com/johnsudaar)
|
* [johnsudaar](https://github.com/johnsudaar)
|
||||||
* [trebmuh](https://github.com/trebmuh)
|
* [trebmuh](https://github.com/trebmuh)
|
||||||
* [rmhasan](https://github.com/rmhasan)
|
* [rmhasan](https://github.com/rmhasan)
|
||||||
* [kedamaDQ](https://github.com/kedamaDQ)
|
|
||||||
* [lindwurm](https://github.com/lindwurm)
|
* [lindwurm](https://github.com/lindwurm)
|
||||||
* [victorhck](mailto:victorhck@geeko.site)
|
* [victorhck](mailto:victorhck@geeko.site)
|
||||||
* [voidsatisfaction](https://github.com/voidsatisfaction)
|
* [voidsatisfaction](https://github.com/voidsatisfaction)
|
||||||
|
* [mkljczk](https://github.com/mkljczk)
|
||||||
* [hikari-no-yume](https://github.com/hikari-no-yume)
|
* [hikari-no-yume](https://github.com/hikari-no-yume)
|
||||||
* [seefood](https://github.com/seefood)
|
* [seefood](https://github.com/seefood)
|
||||||
* [jackjennings](https://github.com/jackjennings)
|
* [jackjennings](https://github.com/jackjennings)
|
||||||
* [mfmfuyu](https://github.com/mfmfuyu)
|
|
||||||
* [puckipedia](https://github.com/puckipedia)
|
* [puckipedia](https://github.com/puckipedia)
|
||||||
* [spla](mailto:spla@mastodont.cat)
|
* [spla](mailto:spla@mastodont.cat)
|
||||||
* [walf443](https://github.com/walf443)
|
* [walf443](https://github.com/walf443)
|
||||||
@ -111,14 +112,15 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [Ashley](mailto:expenses@airmail.cc)
|
* [Ashley](mailto:expenses@airmail.cc)
|
||||||
* [xqus](https://github.com/xqus)
|
* [xqus](https://github.com/xqus)
|
||||||
* [pfm-eyesightjp](https://github.com/pfm-eyesightjp)
|
* [pfm-eyesightjp](https://github.com/pfm-eyesightjp)
|
||||||
* [Samy KACIMI](mailto:samy.kacimi@gmail.com)
|
* [fakenine](https://github.com/fakenine)
|
||||||
* [tsuwatch](https://github.com/tsuwatch)
|
* [tsuwatch](https://github.com/tsuwatch)
|
||||||
* [victorhck](https://github.com/victorhck)
|
* [victorhck](https://github.com/victorhck)
|
||||||
* [mkljczk](https://github.com/mkljczk)
|
|
||||||
* [manuelviens](https://github.com/manuelviens)
|
* [manuelviens](https://github.com/manuelviens)
|
||||||
|
* [tateisu](https://github.com/tateisu)
|
||||||
* [fvh-P](https://github.com/fvh-P)
|
* [fvh-P](https://github.com/fvh-P)
|
||||||
* [rtucker](https://github.com/rtucker)
|
* [rtucker](https://github.com/rtucker)
|
||||||
* [Anna e só](mailto:contraexemplos@gmail.com)
|
* [Anna e só](mailto:contraexemplos@gmail.com)
|
||||||
|
* [dariusk](https://github.com/dariusk)
|
||||||
* [kazu9su](https://github.com/kazu9su)
|
* [kazu9su](https://github.com/kazu9su)
|
||||||
* [Komic](https://github.com/Komic)
|
* [Komic](https://github.com/Komic)
|
||||||
* [lmorchard](https://github.com/lmorchard)
|
* [lmorchard](https://github.com/lmorchard)
|
||||||
@ -145,9 +147,9 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [fhemberger](https://github.com/fhemberger)
|
* [fhemberger](https://github.com/fhemberger)
|
||||||
* [Gomasy](https://github.com/Gomasy)
|
* [Gomasy](https://github.com/Gomasy)
|
||||||
* [greysteil](https://github.com/greysteil)
|
* [greysteil](https://github.com/greysteil)
|
||||||
* [hencatsmith](https://github.com/hencatsmith)
|
* [hendotcat](https://github.com/hendotcat)
|
||||||
* [d6rkaiz](https://github.com/d6rkaiz)
|
* [d6rkaiz](https://github.com/d6rkaiz)
|
||||||
* [Reverite](https://github.com/Reverite)
|
* [ladyisatis](https://github.com/ladyisatis)
|
||||||
* [JohnD28](https://github.com/JohnD28)
|
* [JohnD28](https://github.com/JohnD28)
|
||||||
* [znz](https://github.com/znz)
|
* [znz](https://github.com/znz)
|
||||||
* [saper](https://github.com/saper)
|
* [saper](https://github.com/saper)
|
||||||
@ -160,14 +162,14 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [leopku](https://github.com/leopku)
|
* [leopku](https://github.com/leopku)
|
||||||
* [SansPseudoFix](https://github.com/SansPseudoFix)
|
* [SansPseudoFix](https://github.com/SansPseudoFix)
|
||||||
* [spla](mailto:sp@mastodont.cat)
|
* [spla](mailto:sp@mastodont.cat)
|
||||||
* [tateisu](https://github.com/tateisu)
|
|
||||||
* [tomfhowe](https://github.com/tomfhowe)
|
* [tomfhowe](https://github.com/tomfhowe)
|
||||||
* [noraworld](https://github.com/noraworld)
|
* [noraworld](https://github.com/noraworld)
|
||||||
* [lfuelling](https://github.com/lfuelling)
|
* [lfuelling](https://github.com/lfuelling)
|
||||||
* [theboss](https://github.com/theboss)
|
* [aji-su](https://github.com/aji-su)
|
||||||
* [nzws](https://github.com/nzws)
|
* [nzws](https://github.com/nzws)
|
||||||
* [duxovni](https://github.com/duxovni)
|
* [duxovni](https://github.com/duxovni)
|
||||||
* [smorimoto](https://github.com/smorimoto)
|
* [smorimoto](https://github.com/smorimoto)
|
||||||
|
* [mashirozx](https://github.com/mashirozx)
|
||||||
* [178inaba](https://github.com/178inaba)
|
* [178inaba](https://github.com/178inaba)
|
||||||
* [acid-chicken](https://github.com/acid-chicken)
|
* [acid-chicken](https://github.com/acid-chicken)
|
||||||
* [xgess](https://github.com/xgess)
|
* [xgess](https://github.com/xgess)
|
||||||
@ -175,7 +177,6 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [aablinov](https://github.com/aablinov)
|
* [aablinov](https://github.com/aablinov)
|
||||||
* [stalker314314](https://github.com/stalker314314)
|
* [stalker314314](https://github.com/stalker314314)
|
||||||
* [cutls](https://github.com/cutls)
|
* [cutls](https://github.com/cutls)
|
||||||
* [dariusk](https://github.com/dariusk)
|
|
||||||
* [huertanix](https://github.com/huertanix)
|
* [huertanix](https://github.com/huertanix)
|
||||||
* [eleboucher](https://github.com/eleboucher)
|
* [eleboucher](https://github.com/eleboucher)
|
||||||
* [halkeye](https://github.com/halkeye)
|
* [halkeye](https://github.com/halkeye)
|
||||||
@ -183,7 +184,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [treby](https://github.com/treby)
|
* [treby](https://github.com/treby)
|
||||||
* [jpdevries](https://github.com/jpdevries)
|
* [jpdevries](https://github.com/jpdevries)
|
||||||
* [gdpelican](https://github.com/gdpelican)
|
* [gdpelican](https://github.com/gdpelican)
|
||||||
* [kmichl](https://github.com/kmichl)
|
* [Korbinian](mailto:kontakt@korbinian-michl.de)
|
||||||
* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
|
* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
|
||||||
* [panarom](https://github.com/panarom)
|
* [panarom](https://github.com/panarom)
|
||||||
* [Dar13](https://github.com/Dar13)
|
* [Dar13](https://github.com/Dar13)
|
||||||
@ -225,6 +226,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [aaribaud](https://github.com/aaribaud)
|
* [aaribaud](https://github.com/aaribaud)
|
||||||
* [pointlessone](https://github.com/pointlessone)
|
* [pointlessone](https://github.com/pointlessone)
|
||||||
* [Andrew](mailto:andrewlchronister@gmail.com)
|
* [Andrew](mailto:andrewlchronister@gmail.com)
|
||||||
|
* [arielrodrigues](https://github.com/arielrodrigues)
|
||||||
* [aurelien-reeves](https://github.com/aurelien-reeves)
|
* [aurelien-reeves](https://github.com/aurelien-reeves)
|
||||||
* [elegaanz](https://github.com/elegaanz)
|
* [elegaanz](https://github.com/elegaanz)
|
||||||
* [estuans](https://github.com/estuans)
|
* [estuans](https://github.com/estuans)
|
||||||
@ -238,6 +240,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [muffinista](https://github.com/muffinista)
|
* [muffinista](https://github.com/muffinista)
|
||||||
* [cdutson](https://github.com/cdutson)
|
* [cdutson](https://github.com/cdutson)
|
||||||
* [farlistener](https://github.com/farlistener)
|
* [farlistener](https://github.com/farlistener)
|
||||||
|
* [divergentdave](https://github.com/divergentdave)
|
||||||
* [DavidLibeau](https://github.com/DavidLibeau)
|
* [DavidLibeau](https://github.com/DavidLibeau)
|
||||||
* [dmerejkowsky](https://github.com/dmerejkowsky)
|
* [dmerejkowsky](https://github.com/dmerejkowsky)
|
||||||
* [ddevault](https://github.com/ddevault)
|
* [ddevault](https://github.com/ddevault)
|
||||||
@ -276,7 +279,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [xPaw](https://github.com/xPaw)
|
* [xPaw](https://github.com/xPaw)
|
||||||
* [petzah](https://github.com/petzah)
|
* [petzah](https://github.com/petzah)
|
||||||
* [ignisf](https://github.com/ignisf)
|
* [ignisf](https://github.com/ignisf)
|
||||||
* [raymestalez](https://github.com/raymestalez)
|
* [lumenwrites](https://github.com/lumenwrites)
|
||||||
* [remram44](https://github.com/remram44)
|
* [remram44](https://github.com/remram44)
|
||||||
* [sts10](https://github.com/sts10)
|
* [sts10](https://github.com/sts10)
|
||||||
* [SuperSandro2000](https://github.com/SuperSandro2000)
|
* [SuperSandro2000](https://github.com/SuperSandro2000)
|
||||||
@ -286,8 +289,9 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [Sir-Boops](https://github.com/Sir-Boops)
|
* [Sir-Boops](https://github.com/Sir-Boops)
|
||||||
* [stemid](https://github.com/stemid)
|
* [stemid](https://github.com/stemid)
|
||||||
* [sumdog](https://github.com/sumdog)
|
* [sumdog](https://github.com/sumdog)
|
||||||
|
* [OmmyZhang](https://github.com/OmmyZhang)
|
||||||
* [ThomasLeister](https://github.com/ThomasLeister)
|
* [ThomasLeister](https://github.com/ThomasLeister)
|
||||||
* [mcat-ee](https://github.com/mcat-ee)
|
* [Tom McAtee](mailto:a1608768@student.adelaide.edu.au)
|
||||||
* [tototoshi](https://github.com/tototoshi)
|
* [tototoshi](https://github.com/tototoshi)
|
||||||
* [TrashMacNugget](https://github.com/TrashMacNugget)
|
* [TrashMacNugget](https://github.com/TrashMacNugget)
|
||||||
* [VirtuBox](https://github.com/VirtuBox)
|
* [VirtuBox](https://github.com/VirtuBox)
|
||||||
@ -314,11 +318,13 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [matsurai25](https://github.com/matsurai25)
|
* [matsurai25](https://github.com/matsurai25)
|
||||||
* [mecab](https://github.com/mecab)
|
* [mecab](https://github.com/mecab)
|
||||||
* [nicobz25](https://github.com/nicobz25)
|
* [nicobz25](https://github.com/nicobz25)
|
||||||
|
* [niwatori24](https://github.com/niwatori24)
|
||||||
* [oliverkeeble](https://github.com/oliverkeeble)
|
* [oliverkeeble](https://github.com/oliverkeeble)
|
||||||
* [partev](https://github.com/partev)
|
* [partev](https://github.com/partev)
|
||||||
* [pinfort](https://github.com/pinfort)
|
* [pinfort](https://github.com/pinfort)
|
||||||
* [rbaumert](https://github.com/rbaumert)
|
* [rbaumert](https://github.com/rbaumert)
|
||||||
* [rhoio](https://github.com/rhoio)
|
* [rhoio](https://github.com/rhoio)
|
||||||
|
* [santiagorodriguez96](https://github.com/santiagorodriguez96)
|
||||||
* [sclaire-1](https://github.com/sclaire-1)
|
* [sclaire-1](https://github.com/sclaire-1)
|
||||||
* [umonaca](https://github.com/umonaca)
|
* [umonaca](https://github.com/umonaca)
|
||||||
* [usagi-f](https://github.com/usagi-f)
|
* [usagi-f](https://github.com/usagi-f)
|
||||||
@ -327,7 +333,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [wxcafe](https://github.com/wxcafe)
|
* [wxcafe](https://github.com/wxcafe)
|
||||||
* [Grawl](https://github.com/Grawl)
|
* [Grawl](https://github.com/Grawl)
|
||||||
* [新都心(Neet Shin)](mailto:nucx@dio-vox.com)
|
* [新都心(Neet Shin)](mailto:nucx@dio-vox.com)
|
||||||
* [clarfon](https://github.com/clarfon)
|
* [clarfonthey](https://github.com/clarfonthey)
|
||||||
* [cygnan](https://github.com/cygnan)
|
* [cygnan](https://github.com/cygnan)
|
||||||
* [Awea](https://github.com/Awea)
|
* [Awea](https://github.com/Awea)
|
||||||
* [eai04191](https://github.com/eai04191)
|
* [eai04191](https://github.com/eai04191)
|
||||||
@ -358,11 +364,11 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [schas002](https://github.com/schas002)
|
* [schas002](https://github.com/schas002)
|
||||||
* [contraexemplo](https://github.com/contraexemplo)
|
* [contraexemplo](https://github.com/contraexemplo)
|
||||||
* [abackstrom](https://github.com/abackstrom)
|
* [abackstrom](https://github.com/abackstrom)
|
||||||
* [arielrodrigues](https://github.com/arielrodrigues)
|
|
||||||
* [orlea](https://github.com/orlea)
|
* [orlea](https://github.com/orlea)
|
||||||
* [armandfardeau](https://github.com/armandfardeau)
|
* [armandfardeau](https://github.com/armandfardeau)
|
||||||
* [raboof](https://github.com/raboof)
|
* [raboof](https://github.com/raboof)
|
||||||
* [jumbosushi](https://github.com/jumbosushi)
|
* [jumbosushi](https://github.com/jumbosushi)
|
||||||
|
* [acuteaura](https://github.com/acuteaura)
|
||||||
* [ayumin](https://github.com/ayumin)
|
* [ayumin](https://github.com/ayumin)
|
||||||
* [bzg](https://github.com/bzg)
|
* [bzg](https://github.com/bzg)
|
||||||
* [BastienDurel](https://github.com/BastienDurel)
|
* [BastienDurel](https://github.com/BastienDurel)
|
||||||
@ -389,7 +395,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [colindean](https://github.com/colindean)
|
* [colindean](https://github.com/colindean)
|
||||||
* [DeeUnderscore](https://github.com/DeeUnderscore)
|
* [DeeUnderscore](https://github.com/DeeUnderscore)
|
||||||
* [dachinat](https://github.com/dachinat)
|
* [dachinat](https://github.com/dachinat)
|
||||||
* [shapeshifter-system](https://github.com/shapeshifter-system)
|
* [monsterpit-firedemon](https://github.com/monsterpit-firedemon)
|
||||||
* [watilde](https://github.com/watilde)
|
* [watilde](https://github.com/watilde)
|
||||||
* [daprice](https://github.com/daprice)
|
* [daprice](https://github.com/daprice)
|
||||||
* [da2x](https://github.com/da2x)
|
* [da2x](https://github.com/da2x)
|
||||||
@ -400,14 +406,13 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [singingwolfboy](https://github.com/singingwolfboy)
|
* [singingwolfboy](https://github.com/singingwolfboy)
|
||||||
* [caldwell](https://github.com/caldwell)
|
* [caldwell](https://github.com/caldwell)
|
||||||
* [davidcelis](https://github.com/davidcelis)
|
* [davidcelis](https://github.com/davidcelis)
|
||||||
* [divergentdave](https://github.com/divergentdave)
|
|
||||||
* [davefp](https://github.com/davefp)
|
* [davefp](https://github.com/davefp)
|
||||||
* [yipdw](https://github.com/yipdw)
|
* [yipdw](https://github.com/yipdw)
|
||||||
* [debanshuk](https://github.com/debanshuk)
|
* [debanshuk](https://github.com/debanshuk)
|
||||||
* [mascali33](https://github.com/mascali33)
|
* [mascali33](https://github.com/mascali33)
|
||||||
* [DerekNonGeneric](https://github.com/DerekNonGeneric)
|
* [DerekNonGeneric](https://github.com/DerekNonGeneric)
|
||||||
* [dblandin](https://github.com/dblandin)
|
* [dblandin](https://github.com/dblandin)
|
||||||
* [Drew Gates](mailto:aranaur@users.noreply.github.com)
|
* [Aranaur](https://github.com/Aranaur)
|
||||||
* [dtschust](https://github.com/dtschust)
|
* [dtschust](https://github.com/dtschust)
|
||||||
* [Dryusdan](https://github.com/Dryusdan)
|
* [Dryusdan](https://github.com/Dryusdan)
|
||||||
* [d3vgru](https://github.com/d3vgru)
|
* [d3vgru](https://github.com/d3vgru)
|
||||||
@ -451,22 +456,25 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [J Yeary](mailto:usbsnowcrash@users.noreply.github.com)
|
* [J Yeary](mailto:usbsnowcrash@users.noreply.github.com)
|
||||||
* [jack-michaud](https://github.com/jack-michaud)
|
* [jack-michaud](https://github.com/jack-michaud)
|
||||||
* [Floppy](https://github.com/Floppy)
|
* [Floppy](https://github.com/Floppy)
|
||||||
* [loomchild](https://github.com/loomchild)
|
* [Jarek Lipski](mailto:pub@loomchild.net)
|
||||||
* [jglauche](https://github.com/jglauche)
|
* [Jennifer Glauche](mailto:=^.^=@github19.jglauche.de)
|
||||||
* [jenkr55](https://github.com/jenkr55)
|
* [Jennifer Kruse](mailto:jenkr55@gmail.com)
|
||||||
* [hyenagirl64](https://github.com/hyenagirl64)
|
* [Jeremy Rose](mailto:nornagon@nornagon.net)
|
||||||
* [press5](https://github.com/press5)
|
* [Jessica](mailto:46502909+hyenagirl64@users.noreply.github.com)
|
||||||
* [TrollDecker](https://github.com/TrollDecker)
|
* [Jessica K. Litwin](mailto:jessica@litw.in)
|
||||||
* [jmontane](https://github.com/jmontane)
|
* [Jo Decker](mailto:trolldecker@users.noreply.github.com)
|
||||||
|
* [Joan Montané](mailto:jmontane@users.noreply.github.com)
|
||||||
* [Jonathan Klee](mailto:klee.jonathan@gmail.com)
|
* [Jonathan Klee](mailto:klee.jonathan@gmail.com)
|
||||||
* [Jordan Guerder](mailto:jguerder@fr.pulseheberg.net)
|
* [Jordan Guerder](mailto:jguerder@fr.pulseheberg.net)
|
||||||
* [Joseph Mingrone](mailto:jehops@users.noreply.github.com)
|
* [Joseph Mingrone](mailto:jehops@users.noreply.github.com)
|
||||||
|
* [Josh Leeb-du Toit](mailto:mail@joshleeb.com)
|
||||||
* [Joshua Wood](mailto:josh@joshuawood.net)
|
* [Joshua Wood](mailto:josh@joshuawood.net)
|
||||||
* [Julien](mailto:tiwy57@users.noreply.github.com)
|
* [Julien](mailto:tiwy57@users.noreply.github.com)
|
||||||
* [Julien Deswaef](mailto:juego@requiem4tv.com)
|
* [Julien Deswaef](mailto:juego@requiem4tv.com)
|
||||||
* [June Sallou](mailto:jnsll@users.noreply.github.com)
|
* [June Sallou](mailto:jnsll@users.noreply.github.com)
|
||||||
* [Jérémy Benoist](mailto:j0k3r@users.noreply.github.com)
|
* [Jérémy Benoist](mailto:j0k3r@users.noreply.github.com)
|
||||||
* [KEINOS](mailto:github@keinos.com)
|
* [KEINOS](mailto:github@keinos.com)
|
||||||
|
* [Kairui Song | 宋恺睿](mailto:ryncsn@gmail.com)
|
||||||
* [Keiji Matsuzaki](mailto:futoase@gmail.com)
|
* [Keiji Matsuzaki](mailto:futoase@gmail.com)
|
||||||
* [Kevin Liu](mailto:kevin@potatofrom.space)
|
* [Kevin Liu](mailto:kevin@potatofrom.space)
|
||||||
* [Kit Redgrave](mailto:qwertyitis@gmail.com)
|
* [Kit Redgrave](mailto:qwertyitis@gmail.com)
|
||||||
@ -482,7 +490,6 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [Lukas Burk](mailto:jemus42@users.noreply.github.com)
|
* [Lukas Burk](mailto:jemus42@users.noreply.github.com)
|
||||||
* [Manato Kameya](mailto:grabacr07+github@gmail.com)
|
* [Manato Kameya](mailto:grabacr07+github@gmail.com)
|
||||||
* [Mantas](mailto:mistermantas@users.noreply.github.com)
|
* [Mantas](mailto:mistermantas@users.noreply.github.com)
|
||||||
* [Marcin Mikołajczak](mailto:me@mkljczk.pl)
|
|
||||||
* [Mareena Kunjachan](mailto:mareenakunjachan@gmail.com)
|
* [Mareena Kunjachan](mailto:mareenakunjachan@gmail.com)
|
||||||
* [Marek Lach](mailto:marek.brohatwack.lach@gmail.com)
|
* [Marek Lach](mailto:marek.brohatwack.lach@gmail.com)
|
||||||
* [Markus R](mailto:wirehack7@users.noreply.github.com)
|
* [Markus R](mailto:wirehack7@users.noreply.github.com)
|
||||||
@ -529,10 +536,12 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [Norayr Chilingarian](mailto:norayr@arnet.am)
|
* [Norayr Chilingarian](mailto:norayr@arnet.am)
|
||||||
* [Noëlle Anthony](mailto:noelle.d.anthony@gmail.com)
|
* [Noëlle Anthony](mailto:noelle.d.anthony@gmail.com)
|
||||||
* [N氏](mailto:uenok.htc@gmail.com)
|
* [N氏](mailto:uenok.htc@gmail.com)
|
||||||
|
* [OSAMU SATO](mailto:satosamu@gmail.com)
|
||||||
* [Olivier Nicole](mailto:olivierthnicole@gmail.com)
|
* [Olivier Nicole](mailto:olivierthnicole@gmail.com)
|
||||||
* [Oskari Noppa](mailto:noppa@users.noreply.github.com)
|
* [Oskari Noppa](mailto:noppa@users.noreply.github.com)
|
||||||
* [Otakan](mailto:otakan951@gmail.com)
|
* [Otakan](mailto:otakan951@gmail.com)
|
||||||
* [Padraig Fahy](mailto:tech@padraigfahy.com)
|
* [Padraig Fahy](mailto:tech@padraigfahy.com)
|
||||||
|
* [Patrice Ferlet](mailto:metal3d@gmail.com)
|
||||||
* [PatrickRWells](mailto:32802366+patrickrwells@users.noreply.github.com)
|
* [PatrickRWells](mailto:32802366+patrickrwells@users.noreply.github.com)
|
||||||
* [Paul](mailto:naydex.mc+github@gmail.com)
|
* [Paul](mailto:naydex.mc+github@gmail.com)
|
||||||
* [Pete Keen](mailto:pete@petekeen.net)
|
* [Pete Keen](mailto:pete@petekeen.net)
|
||||||
@ -574,7 +583,6 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [TakesxiSximada](mailto:takesxi.sximada@gmail.com)
|
* [TakesxiSximada](mailto:takesxi.sximada@gmail.com)
|
||||||
* [Tao Bror Bojlén](mailto:brortao@users.noreply.github.com)
|
* [Tao Bror Bojlén](mailto:brortao@users.noreply.github.com)
|
||||||
* [Taras Gogol](mailto:taras2358@gmail.com)
|
* [Taras Gogol](mailto:taras2358@gmail.com)
|
||||||
* [Tdxdxoz](mailto:tdxdxoz@gmail.com)
|
|
||||||
* [TheInventrix](mailto:theinventrix@users.noreply.github.com)
|
* [TheInventrix](mailto:theinventrix@users.noreply.github.com)
|
||||||
* [TheMainOne](mailto:50847364+theevilskeleton@users.noreply.github.com)
|
* [TheMainOne](mailto:50847364+theevilskeleton@users.noreply.github.com)
|
||||||
* [Thomas Alberola](mailto:thomas@needacoffee.fr)
|
* [Thomas Alberola](mailto:thomas@needacoffee.fr)
|
||||||
@ -594,6 +602,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [Wesley Ellis](mailto:tahnok@gmail.com)
|
* [Wesley Ellis](mailto:tahnok@gmail.com)
|
||||||
* [Wiktor](mailto:wiktor@metacode.biz)
|
* [Wiktor](mailto:wiktor@metacode.biz)
|
||||||
* [Wonderfall](mailto:wonderfall@schrodinger.io)
|
* [Wonderfall](mailto:wonderfall@schrodinger.io)
|
||||||
|
* [Y.Yamashiro](mailto:shukukei@mojizuri.jp)
|
||||||
* [YDrogen](mailto:ydrogen45@gmail.com)
|
* [YDrogen](mailto:ydrogen45@gmail.com)
|
||||||
* [YMHuang](mailto:ymhuang@fmbase.tw)
|
* [YMHuang](mailto:ymhuang@fmbase.tw)
|
||||||
* [YOSHIOKA Eiichiro](mailto:yoshioka.eiichiro@gmail.com)
|
* [YOSHIOKA Eiichiro](mailto:yoshioka.eiichiro@gmail.com)
|
||||||
@ -638,6 +647,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [jumoru](mailto:jumoru@mailbox.org)
|
* [jumoru](mailto:jumoru@mailbox.org)
|
||||||
* [kaiyou](mailto:pierre@jaury.eu)
|
* [kaiyou](mailto:pierre@jaury.eu)
|
||||||
* [karlyeurl](mailto:karl.yeurl@gmail.com)
|
* [karlyeurl](mailto:karl.yeurl@gmail.com)
|
||||||
|
* [kawaguchi](mailto:jiikko@users.noreply.github.com)
|
||||||
* [kedama](mailto:32974885+kedamadq@users.noreply.github.com)
|
* [kedama](mailto:32974885+kedamadq@users.noreply.github.com)
|
||||||
* [kuro5hin](mailto:rusty@kuro5hin.org)
|
* [kuro5hin](mailto:rusty@kuro5hin.org)
|
||||||
* [leo60228](mailto:leo@60228.dev)
|
* [leo60228](mailto:leo@60228.dev)
|
||||||
@ -655,6 +665,7 @@ and provided thanks to the work of the following contributors:
|
|||||||
* [notozeki](mailto:notozeki@users.noreply.github.com)
|
* [notozeki](mailto:notozeki@users.noreply.github.com)
|
||||||
* [ntl-purism](mailto:57806346+ntl-purism@users.noreply.github.com)
|
* [ntl-purism](mailto:57806346+ntl-purism@users.noreply.github.com)
|
||||||
* [nzws](mailto:git-yuzu@svk.jp)
|
* [nzws](mailto:git-yuzu@svk.jp)
|
||||||
|
* [proxy](mailto:51172302+3n-k1@users.noreply.github.com)
|
||||||
* [rch850](mailto:rich850@gmail.com)
|
* [rch850](mailto:rich850@gmail.com)
|
||||||
* [roikale](mailto:roikale@users.noreply.github.com)
|
* [roikale](mailto:roikale@users.noreply.github.com)
|
||||||
* [rysiekpl](mailto:rysiek@hackerspace.pl)
|
* [rysiekpl](mailto:rysiek@hackerspace.pl)
|
||||||
@ -694,308 +705,414 @@ This document is provided for informational purposes only. Since it is only upda
|
|||||||
|
|
||||||
Following people have contributed to translation of Mastodon:
|
Following people have contributed to translation of Mastodon:
|
||||||
|
|
||||||
- ᏦᏁᎢᎵᏫ 😷 (*Spanish, Argentina*)
|
- ᏦᏁᎢᎵᏫ 😷 (KNTRO) (*Spanish, Argentina*)
|
||||||
- Sveinn í Felli (*Icelandic*)
|
- Sveinn í Felli (sveinki) (*Icelandic*)
|
||||||
|
- qezwan (*Persian, Sorani (Kurdish)*)
|
||||||
|
- Hồ Nhất Duy (kantcer) (*Vietnamese*)
|
||||||
- taicv (*Vietnamese*)
|
- taicv (*Vietnamese*)
|
||||||
- ButterflyOfFire (*Arabic; French; Kabyle*)
|
- Zoltán Gera (gerazo) (*Hungarian*)
|
||||||
- Duy (*Vietnamese*)
|
- ButterflyOfFire (BoFFire) (*French, Arabic, Kabyle*)
|
||||||
- Evert Prants (*Estonian*)
|
|
||||||
- Zoltán Gera (*Hungarian*)
|
|
||||||
- Daniele Lira Mereb (*Portuguese, Brazilian*)
|
|
||||||
- Kristijan Tkalec (*Slovenian*)
|
|
||||||
- stan ionut (*Romanian*)
|
|
||||||
- Ramdziana F Y (*Indonesian*)
|
|
||||||
- Michal Stanke (*Czech*)
|
|
||||||
- Xosé M. (*Galician; Spanish*)
|
|
||||||
- 奈卜拉 (*Chinese Simplified*)
|
|
||||||
- borys_sh (*Ukrainian*)
|
|
||||||
- Miguel Mayol (*Spanish; Catalan*)
|
|
||||||
- Besnik_b (*Albanian*)
|
|
||||||
- Thai Localization (*Thai*)
|
|
||||||
- Emanuel Pina (*Portuguese*)
|
|
||||||
- Jeong Arm (*Korean; Esperanto; Japanese*)
|
|
||||||
- Imre Kristoffer Eilertsen (*Norwegian*)
|
|
||||||
- Danial Behzadi (*Persian*)
|
|
||||||
- Osoitz (*Basque*)
|
|
||||||
- Peterandre (*Norwegian Nynorsk; Norwegian*)
|
|
||||||
- Jeroen (*Dutch*)
|
|
||||||
- spla (*Catalan; Spanish*)
|
|
||||||
- Iváns (*Galician*)
|
|
||||||
- koyu (*German*)
|
|
||||||
- Sasha Sorokin (*Russian; Vietnamese; Swedish; Catalan; Greek; Hungarian; Armenian; Albanian; Galician; French; Danish; German; Korean; Ukrainian*)
|
|
||||||
- enolp (*Asturian*)
|
|
||||||
- Masoud Abkenar (*Persian*)
|
|
||||||
- lamnatos (*Greek*)
|
|
||||||
- Alix Rossi (*Corsican; French*)
|
|
||||||
- arshat (*Kazakh*)
|
|
||||||
- FédiQuébec (*French*)
|
|
||||||
- Marek Ľach (*Slovak; Polish*)
|
|
||||||
- Muha Aliss (*Turkish*)
|
|
||||||
- tolstoevsky (*Russian*)
|
|
||||||
- Emyn-Russell Nt Nefydd (*Welsh*)
|
|
||||||
- Aditoo17 (*Czech*)
|
|
||||||
- Maya Minatsuki (*Japanese*)
|
|
||||||
- ariasuni (*French; Esperanto*)
|
|
||||||
- Roboron (*Spanish*)
|
|
||||||
- Alessandro Levati (*Italian*)
|
|
||||||
- Diluns (*Occitan*)
|
|
||||||
- regulartranslator (*Portuguese, Brazilian*)
|
|
||||||
- vishnuvaratharajan (*Tamil*)
|
|
||||||
- Marcin Mikołajczak (*Polish*)
|
|
||||||
- Yi-Jyun Pan (*Chinese Traditional*)
|
|
||||||
- adrmzz (*Sardinian*)
|
- adrmzz (*Sardinian*)
|
||||||
|
- Ramdziana F Y (rafeyu) (*Indonesian*)
|
||||||
|
- Evert Prants (IcyDiamond) (*Estonian*)
|
||||||
|
- Daniele Lira Mereb (danilmereb) (*Portuguese, Brazilian*)
|
||||||
|
- Xosé M. (XoseM) (*Spanish, Galician*)
|
||||||
|
- Kristijan Tkalec (lapor) (*Slovenian*)
|
||||||
|
- stan ionut (stanionut12) (*Romanian*)
|
||||||
|
- Besnik_b (*Albanian*)
|
||||||
|
- Emanuel Pina (emanuelpina) (*Portuguese*)
|
||||||
|
- Thai Localization (thl10n) (*Thai*)
|
||||||
|
- 奈卜拉 (nebula_moe) (*Chinese Simplified*)
|
||||||
|
- Jeong Arm (Kjwon15) (*Japanese, Korean, Esperanto*)
|
||||||
|
- Michal Stanke (mstanke) (*Czech*)
|
||||||
|
- Alix Rossi (palindromordnilap) (*French, Corsican*)
|
||||||
|
- spla (*Spanish, Catalan*)
|
||||||
|
- Imre Kristoffer Eilertsen (DandelionSprout) (*Norwegian*)
|
||||||
|
- Jeroen (jeroenpraat) (*Dutch*)
|
||||||
|
- borys_sh (*Ukrainian*)
|
||||||
|
- Miguel Mayol (mitcoes) (*Spanish, Catalan*)
|
||||||
|
- Danial Behzadi (danialbehzadi) (*Persian*)
|
||||||
|
- yeft (*Chinese Traditional, Chinese Traditional, Hong Kong*)
|
||||||
|
- koyu (*German*)
|
||||||
|
- Koala Yeung (yookoala) (*Chinese Traditional, Hong Kong*)
|
||||||
|
- Osoitz (*Basque*)
|
||||||
|
- Peterandre (*Norwegian, Norwegian Nynorsk*)
|
||||||
|
- tzium (*Sardinian*)
|
||||||
|
- Iváns (Ivans_translator) (*Galician*)
|
||||||
|
- Sasha Sorokin (Sasha-Sorokin) (*French, Catalan, Danish, German, Greek, Hungarian, Armenian, Korean, Russian, Albanian, Swedish, Ukrainian, Vietnamese, Galician*)
|
||||||
|
- kamee (*Armenian*)
|
||||||
|
- tolstoevsky (*Russian*)
|
||||||
|
- enolp (*Asturian*)
|
||||||
|
- FédiQuébec (manuelviens) (*French*)
|
||||||
|
- lamnatos (*Greek*)
|
||||||
|
- Maya Minatsuki (mayaeh) (*Japanese*)
|
||||||
|
- Masoud Abkenar (mabkenar) (*Persian*)
|
||||||
|
- Alessandro Levati (Oct326) (*Italian*)
|
||||||
|
- arshat (*Kazakh*)
|
||||||
|
- Roboron (*Spanish*)
|
||||||
|
- ariasuni (*French, Arabic, Czech, German, Greek, Hungarian, Slovenian, Ukrainian, Chinese Simplified, Portuguese, Brazilian, Persian, Norwegian Nynorsk, Esperanto, Breton, Corsican, Sardinian, Kabyle*)
|
||||||
|
- Ali Demirtaş (alidemirtas) (*Turkish*)
|
||||||
|
- Em St Cenydd (cancennau) (*Welsh*)
|
||||||
|
- Marek Ľach (mareklach) (*Polish, Slovak*)
|
||||||
|
- Muha Aliss (muhaaliss) (*Turkish*)
|
||||||
|
- Jurica (ahjk) (*Croatian*)
|
||||||
|
- Aditoo17 (*Czech*)
|
||||||
|
- Diluns (*Occitan*)
|
||||||
|
- gagik_ (*Armenian*)
|
||||||
|
- vishnuvaratharajan (*Tamil*)
|
||||||
|
- Marcin Mikołajczak (mkljczkk) (*Czech, Polish, Russian*)
|
||||||
|
- regulartranslator (*Portuguese, Brazilian*)
|
||||||
|
- Akarshan Biswas (biswasab) (*Bengali, Sanskrit*)
|
||||||
|
- Yi-Jyun Pan (pan93412) (*Chinese Traditional*)
|
||||||
- d5Ziif3K (*Ukrainian*)
|
- d5Ziif3K (*Ukrainian*)
|
||||||
- GiorgioHerbie (*Italian*)
|
- GiorgioHerbie (*Italian*)
|
||||||
|
- Rafael H L Moretti (Moretti) (*Portuguese, Brazilian*)
|
||||||
|
- Saederup92 (*Danish*)
|
||||||
- christalleras (*Norwegian Nynorsk*)
|
- christalleras (*Norwegian Nynorsk*)
|
||||||
|
- cybergene (cyber-gene) (*Japanese*)
|
||||||
- Taloran (*Norwegian Nynorsk*)
|
- Taloran (*Norwegian Nynorsk*)
|
||||||
- ThibG (*French; Icelandic*)
|
- ThibG (*French, Icelandic*)
|
||||||
- Akarshan Biswas (*Bengali*)
|
- xatier (*Chinese Traditional*)
|
||||||
|
- otrapersona (*Spanish, Spanish, Mexico*)
|
||||||
- atarashiako (*Chinese Simplified*)
|
- atarashiako (*Chinese Simplified*)
|
||||||
- 101010 (*Polish*)
|
- 101010 (101010pl) (*Polish*)
|
||||||
- silkevicious (*Italian*)
|
- silkevicious (*Italian*)
|
||||||
- Bertil Hedkvist (*Swedish*)
|
- Floxu (fredrikdim1) (*Norwegian Nynorsk*)
|
||||||
- cybergene (*Japanese*)
|
- Bertil Hedkvist (Berrahed) (*Swedish*)
|
||||||
|
- William(ѕ)ⁿ (wmlgr) (*Spanish*)
|
||||||
- norayr (*Armenian*)
|
- norayr (*Armenian*)
|
||||||
- William(ѕ)ⁿ (*Spanish*)
|
- Tiago Epifânio (tfve) (*Portuguese*)
|
||||||
- Tiago Epifânio (*Portuguese*)
|
- Ryo (DrRyo) (*Korean*)
|
||||||
- Mentor Gashi (*Albanian*)
|
- Mentor Gashi (mentorgashi.com) (*Albanian*)
|
||||||
- Jaz-Michael King (*Welsh*)
|
- Jaz-Michael King (jazmichaelking) (*Welsh*)
|
||||||
- carolinagiorno (*Portuguese, Brazilian*)
|
- carolinagiorno (*Portuguese, Brazilian*)
|
||||||
- Roby Thomas (*Malayalam*)
|
- Roby Thomas (roby.thomas) (*Malayalam*)
|
||||||
- Bharat Kumar (*Hindi*)
|
- Bharat Kumar (Marwari) (*Hindi*)
|
||||||
|
- ThonyVezbe (*Breton*)
|
||||||
|
- dkdarshan760 (*Sanskrit*)
|
||||||
|
- Tagomago (tagomago) (*French, Spanish*)
|
||||||
- tykayn (*French*)
|
- tykayn (*French*)
|
||||||
- axi (*Finnish*)
|
- axi (*Finnish*)
|
||||||
- Selyan Slimane AMIRI (*Kabyle*)
|
- Selyan Slimane AMIRI (slimane_AMIRI) (*Kabyle*)
|
||||||
|
- Balázs Meskó (mesko.balazs) (*Hungarian*)
|
||||||
- taoxvx (*Danish*)
|
- taoxvx (*Danish*)
|
||||||
- Hrach Mkrtchyan (*Armenian*)
|
- Hrach Mkrtchyan (mhrach87) (*Armenian*)
|
||||||
- sabri (*Spanish; Spanish, Argentina*)
|
- sabri (thetomatoisavegetable) (*Spanish, Spanish, Argentina*)
|
||||||
- Dewi (*Breton; French*)
|
- Dewi (Unkorneg) (*French, Breton*)
|
||||||
|
- Coelacanthus (*Chinese Simplified*)
|
||||||
|
- syncopams (*Chinese Simplified, Chinese Traditional, Chinese Traditional, Hong Kong*)
|
||||||
- SteinarK (*Norwegian Nynorsk*)
|
- SteinarK (*Norwegian Nynorsk*)
|
||||||
- Mathias B. Vagnes (*Norwegian*)
|
- Sokratis Alichanidis (alichani) (*Greek*)
|
||||||
- dashersyed (*Urdu*)
|
- Mathias B. Vagnes (vagnes) (*Norwegian*)
|
||||||
- ThonyVezbe (*Breton*)
|
- dashersyed (*Urdu (Pakistan)*)
|
||||||
- Acolyte (*Ukrainian*)
|
- Acolyte (666noob404) (*Ukrainian*)
|
||||||
- Conight Wang (*Chinese Simplified*)
|
- Conight Wang (xfddwhh) (*Chinese Simplified*)
|
||||||
- Damjan Dimitrioski (*Macedonian*)
|
|
||||||
- PPNplus (*Thai*)
|
|
||||||
- Tagomago (*Spanish; French*)
|
|
||||||
- shioko (*Chinese Simplified*)
|
|
||||||
- Balázs Meskó (*Hungarian*)
|
|
||||||
- Evgeny Petrov (*Russian*)
|
|
||||||
- Gwenn (*Breton*)
|
|
||||||
- Ryo (*Korean*)
|
|
||||||
- Rafael H L Moretti (*Portuguese, Brazilian*)
|
|
||||||
- jaranta (*Finnish*)
|
|
||||||
- gagik_ (*Armenian*)
|
|
||||||
- Felicia (*Swedish*)
|
|
||||||
- Jess Rafn (*Danish*)
|
|
||||||
- Stasiek Michalski (*Polish*)
|
|
||||||
- liffon (*Swedish*)
|
- liffon (*Swedish*)
|
||||||
- dxwc (*Bengali*)
|
- Damjan Dimitrioski (gnud) (*Macedonian*)
|
||||||
- Saederup92 (*Danish*)
|
- PPNplus (*Thai*)
|
||||||
- Vanege (*Esperanto*)
|
- shioko (*Chinese Simplified*)
|
||||||
- jmontane (*Catalan*)
|
- v4vachan (*Malayalam*)
|
||||||
- Johan Schiff (*Swedish*)
|
- Hakim Oubouali (zenata1) (*Standard Moroccan Tamazight*)
|
||||||
- Arunmozhi (*Tamil*)
|
- Evgeny Petrov (kondra007) (*Russian*)
|
||||||
- kat (*Ukrainian; Russian*)
|
- Gwenn (Belvar) (*Breton*)
|
||||||
- Laura (*Polish*)
|
|
||||||
- oti4500 (*Hungarian; Ukrainian*)
|
|
||||||
- diazepan (*Spanish; Spanish, Argentina*)
|
|
||||||
- Sokratis Alichanidis (*Greek*)
|
|
||||||
- Rikard Linde (*Swedish*)
|
|
||||||
- Juan José Salvador Piedra (*Spanish*)
|
|
||||||
- marzuquccen (*Kabyle*)
|
|
||||||
- BurekzFinezt (*Serbian*)
|
|
||||||
- SHeija (*Finnish*)
|
|
||||||
- Jack R (*Spanish*)
|
|
||||||
- andruhov (*Ukrainian; Russian*)
|
|
||||||
- 森の子リスのミーコの大冒険 (*Japanese*)
|
|
||||||
- るいーね (*Japanese*)
|
|
||||||
- Sam Tux (*Bengali*)
|
|
||||||
- Unmual (*Spanish*)
|
|
||||||
- AW Unad (*Indonesian*)
|
|
||||||
- Cutls (*Japanese*)
|
|
||||||
- Ray (*Spanish*)
|
|
||||||
- Falling Snowdin (*Vietnamese*)
|
|
||||||
- Andrea Lo Iacono (*Italian*)
|
|
||||||
- EPEMA (*German*)
|
|
||||||
- Kinshuk Sunil (*Hindi*)
|
|
||||||
- Ullas Joseph (*Malayalam*)
|
|
||||||
- Yu-Pai Liu (*Chinese Traditional*)
|
|
||||||
- Amarin Cemthong (*Thai*)
|
|
||||||
- juanda097 (*Spanish*)
|
|
||||||
- Anunnakey (*Macedonian*)
|
|
||||||
- StanleyFrew (*French*)
|
- StanleyFrew (*French*)
|
||||||
|
- Hayk Khachatryan (brutusromanus123) (*Armenian*)
|
||||||
|
- jaranta (*Finnish*)
|
||||||
|
- Felicia (midsommar) (*Swedish*)
|
||||||
|
- Denys (dector) (*Ukrainian*)
|
||||||
|
- Pukima (pukimaaa) (*German*)
|
||||||
|
- Vanege (*Esperanto*)
|
||||||
|
- Jess Rafn (therealyez) (*Danish*)
|
||||||
|
- strubbl (*German*)
|
||||||
|
- Stasiek Michalski (hellcp) (*Polish*)
|
||||||
|
- dxwc (*Bengali*)
|
||||||
|
- jmontane (*Catalan*)
|
||||||
|
- Liboide (*Spanish*)
|
||||||
|
- Johan Schiff (schyffel) (*Swedish*)
|
||||||
|
- Arunmozhi (tecoholic) (*Tamil*)
|
||||||
|
- kat (katktv) (*Russian, Ukrainian*)
|
||||||
|
- Rikard Linde (rikardlinde) (*Swedish*)
|
||||||
|
- oti4500 (*Hungarian, Ukrainian*)
|
||||||
|
- Laura (selfisekai) (*Polish*)
|
||||||
|
- Rachida S. (ZiriSut) (*Kabyle*)
|
||||||
|
- diazepan (*Spanish, Spanish, Argentina*)
|
||||||
|
- marzuquccen (*Kabyle*)
|
||||||
|
- Juan José Salvador Piedra (JuanjoSalvador) (*Spanish*)
|
||||||
|
- Tigran (tigransimonyan) (*Armenian*)
|
||||||
|
- BurekzFinezt (*Serbian (Cyrillic)*)
|
||||||
|
- SHeija (*Finnish*)
|
||||||
|
- atriix (*Swedish*)
|
||||||
|
- Jack R (isaac.97_WT) (*Spanish*)
|
||||||
|
- antonyho (*Chinese Traditional, Hong Kong*)
|
||||||
|
- andruhov (*Russian, Ukrainian*)
|
||||||
|
- Aryamik Sharma (Aryamik) (*Swedish, Hindi*)
|
||||||
|
- phena109 (*Chinese Traditional, Hong Kong*)
|
||||||
|
- 森の子リスのミーコの大冒険 (Phroneris) (*Japanese*)
|
||||||
|
- るいーね (ruine) (*Japanese*)
|
||||||
|
- ahangarha (*Persian*)
|
||||||
|
- Sam Tux (imahbub) (*Bengali*)
|
||||||
|
- igordrozniak (*Polish*)
|
||||||
|
- Unmual (*Spanish*)
|
||||||
|
- Isaac Huang (caasih) (*Chinese Traditional*)
|
||||||
|
- AW Unad (awcodify) (*Indonesian*)
|
||||||
|
- Allen Zhong (AstroProfundis) (*Chinese Simplified*)
|
||||||
|
- Cutls (cutls) (*Japanese*)
|
||||||
|
- Ray (Ipsumry) (*Spanish*)
|
||||||
|
- Falling Snowdin (tghgg) (*Vietnamese*)
|
||||||
|
- coxde (*Chinese Simplified*)
|
||||||
|
- Rasmus Lindroth (RasmusLindroth) (*Swedish*)
|
||||||
|
- Andrea Lo Iacono (niels0n) (*Italian*)
|
||||||
|
- Kinshuk Sunil (kinshuksunil) (*Hindi*)
|
||||||
|
- Ullas Joseph (ullasjoseph) (*Malayalam*)
|
||||||
|
- Goudarz Jafari (Goudarz) (*Persian*)
|
||||||
|
- Yu-Pai Liu (tedliou) (*Chinese Traditional*)
|
||||||
|
- Amarin Cemthong (acitmaster) (*Thai*)
|
||||||
|
- juanda097 (juanda-097) (*Spanish*)
|
||||||
|
- Anunnakey (*Macedonian*)
|
||||||
|
- fragola (*Italian*)
|
||||||
- erikstl (*Esperanto*)
|
- erikstl (*Esperanto*)
|
||||||
|
- twpenguin (*Chinese Traditional*)
|
||||||
|
- bobchao (*Chinese Traditional*)
|
||||||
|
- Esther (esthermations) (*Portuguese*)
|
||||||
- MadeInSteak (*Finnish*)
|
- MadeInSteak (*Finnish*)
|
||||||
- Heimen Stoffels (*Dutch*)
|
- Heimen Stoffels (vistausss) (*Dutch*)
|
||||||
- Rajarshi Guha (*Bengali*)
|
- Rajarshi Guha (rajarshiguha) (*Bengali*)
|
||||||
- Andrew (*Romanian*)
|
- Andrew (iAndrew3) (*Romanian*)
|
||||||
- Goudarz Jafari (*Persian*)
|
- Gopal Sharma (gopalvirat) (*Hindi*)
|
||||||
- arethsu (*Swedish*)
|
- arethsu (*Swedish*)
|
||||||
- Carlos Solís (*Esperanto*)
|
- Tofiq Abdula (Xwla) (*Sorani (Kurdish)*)
|
||||||
- Parthan S Ramanujam (*Tamil*)
|
- Carlos Solís (csolisr) (*Esperanto*)
|
||||||
- Ali Demirtaş (*Turkish*)
|
- Parthan S Ramanujam (parthan) (*Tamil*)
|
||||||
- Kasper Nymand (*Danish*)
|
- Kasper Nymand (KasperNymand) (*Danish*)
|
||||||
- TS (*Finnish*)
|
- TS (morte) (*Finnish*)
|
||||||
|
- subram (*Turkish*)
|
||||||
- SensDeViata (*Ukrainian*)
|
- SensDeViata (*Ukrainian*)
|
||||||
|
- Ptrcmd (ptrcmd) (*Chinese Traditional*)
|
||||||
- SergioFMiranda (*Portuguese, Brazilian*)
|
- SergioFMiranda (*Portuguese, Brazilian*)
|
||||||
- OctolinGamer (*Portuguese, Brazilian*)
|
- Scvoet (scvoet) (*Chinese Simplified*)
|
||||||
|
- hiroTS (*Chinese Traditional*)
|
||||||
|
- johne32rus23 (*Russian*)
|
||||||
- AzureNya (*Chinese Simplified*)
|
- AzureNya (*Chinese Simplified*)
|
||||||
- Ram varma (*Tamil*)
|
- OctolinGamer (octolingamer) (*Portuguese, Brazilian*)
|
||||||
- 北䑓如法 (*Japanese*)
|
- Ram varma (ram4varma) (*Tamil*)
|
||||||
|
- Hexandcube (hexandcube) (*Polish*)
|
||||||
|
- 北䑓如法 (Nyoho) (*Japanese*)
|
||||||
- frumble (*German*)
|
- frumble (*German*)
|
||||||
- kekkepikkuni (*Tamil*)
|
- kekkepikkuni (*Tamil*)
|
||||||
|
- Neo_Chen (NeoChen1024) (*Chinese Traditional*)
|
||||||
- oorsutri (*Tamil*)
|
- oorsutri (*Tamil*)
|
||||||
- Nithin V (*Tamil*)
|
- Rhys Harrison (rhedders) (*Esperanto*)
|
||||||
- Miro Rauhala (*Finnish*)
|
- Nithin V (Nithin896) (*Tamil*)
|
||||||
|
- Miro Rauhala (mirorauhala) (*Finnish*)
|
||||||
- diorama (*Italian*)
|
- diorama (*Italian*)
|
||||||
- Rhys Harrison (*Esperanto*)
|
- AlexKoala (alexkoala) (*Korean*)
|
||||||
- Guillaume Turchini (*French*)
|
- Aswin C (officialcjunior) (*Malayalam*)
|
||||||
- Ganesh D (*Marathi*)
|
- Guillaume Turchini (orion78fr) (*French*)
|
||||||
|
- Ganesh D (auntgd) (*Marathi*)
|
||||||
- dragnucs2 (*Arabic*)
|
- dragnucs2 (*Arabic*)
|
||||||
- Pedro Henrique (*Portuguese, Brazilian*)
|
- Ryan Ho (koungho) (*Chinese Traditional*)
|
||||||
- Tejas Harad (*Marathi*)
|
- Pedro Henrique (exploronauta) (*Portuguese, Brazilian*)
|
||||||
- Vasanthan (*Tamil*)
|
- Tejas Harad (h_tejas) (*Marathi*)
|
||||||
- 硫酸鶏 (*Japanese*)
|
- Vasanthan (vasanthan) (*Tamil*)
|
||||||
|
- 硫酸鶏 (acid_chicken) (*Japanese*)
|
||||||
|
- clarmin b8 (clarminb8) (*Sorani (Kurdish)*)
|
||||||
- manukp (*Malayalam*)
|
- manukp (*Malayalam*)
|
||||||
- psymyn (*Hebrew*)
|
- psymyn (*Hebrew*)
|
||||||
- earth dweller (*Marathi*)
|
- earth dweller (sanethoughtyt) (*Marathi*)
|
||||||
- meijerivoi (*Finnish*)
|
- meijerivoi (toilet) (*Finnish*)
|
||||||
- essaar (*Tamil*)
|
- essaar (*Tamil*)
|
||||||
- serubeena (*Swedish*)
|
- serubeena (*Swedish*)
|
||||||
|
- Karol Kosek (krkkPL) (*Polish*)
|
||||||
- Rintan (*Japanese*)
|
- Rintan (*Japanese*)
|
||||||
- Karol Kosek (*Polish*)
|
|
||||||
- valarivan (*Tamil*)
|
- valarivan (*Tamil*)
|
||||||
- Sebastián Andil (*Slovak*)
|
- Hernik (hernik27) (*Czech*)
|
||||||
- v4vachan (*Malayalam*)
|
- Sebastián Andil (Selrond) (*Slovak*)
|
||||||
- KEINOS (*Japanese*)
|
- Hinaloe (hinaloe) (*Japanese*)
|
||||||
- Ivan T. (*Chinese Traditional, Hong Kong*)
|
|
||||||
- filippodb (*Italian*)
|
- filippodb (*Italian*)
|
||||||
- Balázs Meskó (*Hungarian*)
|
- KEINOS (*Japanese*)
|
||||||
|
- Balázs Meskó (meskobalazs) (*Hungarian*)
|
||||||
|
- Bottle (suryasalem2010) (*Tamil*)
|
||||||
- JzshAC (*Chinese Simplified*)
|
- JzshAC (*Chinese Simplified*)
|
||||||
- Bottle (*Tamil*)
|
- Wrya ali (John12) (*Sorani (Kurdish)*)
|
||||||
- Khóo (*Chinese Traditional*)
|
- Khóo (khootiatling) (*Chinese Traditional*)
|
||||||
- Steven Tappert (*German*)
|
- Steven Tappert (sammy8806) (*German*)
|
||||||
- Antillion (*Spanish*)
|
- Antillion (antillion99) (*Spanish*)
|
||||||
- ZiriSut (*Kabyle*)
|
- Pukima (Pukimaa) (*German*)
|
||||||
- gowthamanb (*Tamil*)
|
|
||||||
- hiphipvargas (*Portuguese*)
|
|
||||||
- Arttu Ylhävuori (*Finnish*)
|
|
||||||
- Ch. (*Korean*)
|
|
||||||
- tctovsli (*Norwegian Nynorsk*)
|
|
||||||
- Hinaloe (*Japanese*)
|
|
||||||
- strubbl (*German*)
|
|
||||||
- vjasiegd (*Polish*)
|
|
||||||
- SamitiMed (*Thai*)
|
|
||||||
- Reg3xp (*Persian*)
|
- Reg3xp (*Persian*)
|
||||||
- AlexKoala (*Korean*)
|
- hiphipvargas (*Portuguese*)
|
||||||
|
- gowthamanb (*Tamil*)
|
||||||
|
- Ch. (sftblw) (*Korean*)
|
||||||
|
- Jeff Huang (s8321414) (*Chinese Traditional*)
|
||||||
|
- Arttu Ylhävuori (arttu.ylhavuori) (*Finnish*)
|
||||||
|
- tctovsli (*Norwegian Nynorsk*)
|
||||||
|
- Timo Tijhof (Krinkle) (*Dutch*)
|
||||||
|
- Yamagishi Kazutoshi (ykzts) (*Japanese, Icelandic, Sorani (Kurdish)*)
|
||||||
|
- vjasiegd (*Polish*)
|
||||||
|
- SamitiMed (samiti3d) (*Thai*)
|
||||||
|
- Rekan Adl (rekan-adl1) (*Sorani (Kurdish)*)
|
||||||
- umelard (*Hebrew*)
|
- umelard (*Hebrew*)
|
||||||
|
- Antara2Cinta (Se7enTime) (*Indonesian*)
|
||||||
- VSx86 (*Russian*)
|
- VSx86 (*Russian*)
|
||||||
- Daniel Dimitrov (*Bulgarian*)
|
- Daniel Dimitrov (danny-dimitrov) (*Bulgarian*)
|
||||||
- mynameismonkey (*Welsh*)
|
|
||||||
- parnikkapore (*Thai*)
|
- parnikkapore (*Thai*)
|
||||||
- Mo_der Steven (*Chinese Simplified*)
|
- mynameismonkey (*Welsh*)
|
||||||
|
- Sherwan Othman (sherwanothman11) (*Sorani (Kurdish)*)
|
||||||
|
- Yassine Aït-El-Mouden (yaitelmouden) (*Standard Moroccan Tamazight*)
|
||||||
- SKELET (*Danish*)
|
- SKELET (*Danish*)
|
||||||
- Renato "Lond" Cerqueira (*Portuguese, Brazilian*)
|
- Mo_der Steven (SakuraPuare) (*Chinese Simplified*)
|
||||||
|
- Fei Yang (Fei1Yang) (*Chinese Traditional*)
|
||||||
|
- ALEM FARID (faridatcemlulaqbayli) (*Kabyle*)
|
||||||
- enipra (*Armenian*)
|
- enipra (*Armenian*)
|
||||||
- musix (*Persian*)
|
- musix (*Persian*)
|
||||||
- ギャラ (*Chinese Simplified; Japanese*)
|
- Renato "Lond" Cerqueira (renatolond) (*Portuguese, Brazilian*)
|
||||||
- ALEM FARID (*Kabyle*)
|
- ギャラ (gyara) (*Japanese, Chinese Simplified*)
|
||||||
|
- Hougo (hougo) (*French*)
|
||||||
- ybardapurkar (*Marathi*)
|
- ybardapurkar (*Marathi*)
|
||||||
- Adrián Lattes (*Spanish*)
|
- Adrián Lattes (haztecaso) (*Spanish*)
|
||||||
|
- TracyJacks (*Chinese Simplified*)
|
||||||
- rasheedgm (*Kannada*)
|
- rasheedgm (*Kannada*)
|
||||||
- omquylzu (*Latvian*)
|
|
||||||
- Belkacem Mohammed (*Kabyle*)
|
|
||||||
- Navjot Singh (*Hindi*)
|
|
||||||
- Ozai (*German*)
|
|
||||||
- Sahak Petrosyan (*Armenian*)
|
|
||||||
- siamano (*Thai; Esperanto*)
|
|
||||||
- se7entime (*Indonesian*)
|
|
||||||
- Viorel-Cătălin Răpițeanu (*Romanian*)
|
|
||||||
- Siddhartha Sarathi Basu (*Bengali*)
|
|
||||||
- Pachara Chantawong (*Thai*)
|
|
||||||
- Skew (*French*)
|
|
||||||
- Zijian Zhao (*Chinese Simplified*)
|
|
||||||
- Guru Prasath Anandapadmanaban (*Tamil*)
|
|
||||||
- turtle836 (*German*)
|
|
||||||
- GatoOscuro (*Spanish*)
|
- GatoOscuro (*Spanish*)
|
||||||
- Lamin (*Japanese*)
|
- mecqor labi (mecqorlabi) (*Persian*)
|
||||||
- Marcepanek_ (*Polish*)
|
- Belkacem Mohammed (belkacem77) (*Kabyle*)
|
||||||
- Yann Aguettaz (*French*)
|
- Navjot Singh (nspeaks) (*Hindi*)
|
||||||
- Feruz Oripov (*Russian*)
|
- omquylzu (*Latvian*)
|
||||||
- Mick Onio (*Asturian*)
|
- Ozai (*German*)
|
||||||
- hg6 (*Hindi*)
|
- Sahak Petrosyan (petrosyan) (*Armenian*)
|
||||||
- Malik Mann (*German*)
|
- siamano (*Thai, Esperanto*)
|
||||||
- padulafacundo (*Spanish*)
|
- Viorel-Cătălin Răpițeanu (rapiteanu) (*Romanian*)
|
||||||
|
- Siddhartha Sarathi Basu (quinoa_biryani) (*Bengali*)
|
||||||
|
- Pachara Chantawong (pachara2202) (*Thai*)
|
||||||
|
- mkljczk (*Polish*)
|
||||||
|
- Skew (noan.perrot) (*French*)
|
||||||
|
- Zijian Zhao (jobs2512821228) (*Chinese Simplified*)
|
||||||
|
- turtle836 (*German*)
|
||||||
|
- Guru Prasath Anandapadmanaban (guruprasath) (*Tamil*)
|
||||||
|
- Lamin (laminne) (*Japanese*)
|
||||||
|
- Marcepanek_ (thekingmarcepan) (*Polish*)
|
||||||
|
- Feruz Oripov (FeruzOripov) (*Russian*)
|
||||||
|
- Yann Aguettaz (yann-a) (*French*)
|
||||||
|
- Mick Onio (xgc.redes) (*Asturian*)
|
||||||
|
- Tianqi Zhang (tina.zhang040609) (*Chinese Simplified*)
|
||||||
|
- Malik Mann (dermalikmann) (*German*)
|
||||||
|
- dadosch (*German*)
|
||||||
- r3dsp1 (*Chinese Traditional, Hong Kong*)
|
- r3dsp1 (*Chinese Traditional, Hong Kong*)
|
||||||
- Tianqi Zhang (*Chinese Simplified*)
|
- padulafacundo (*Spanish*)
|
||||||
- Padraic Calpin (*Slovenian*)
|
- hg6 (*Hindi*)
|
||||||
- cenegd (*Chinese Simplified*)
|
- Orlando Murcio (Atos20) (*Spanish, Mexico*)
|
||||||
- piupiupiudiu (*Chinese Simplified*)
|
- piupiupiudiu (*Chinese Simplified*)
|
||||||
- Hugh Liu (*Chinese Simplified*)
|
- shdy (*German*)
|
||||||
- Rakino (*Chinese Simplified*)
|
- Padraic Calpin (padraic-padraic) (*Slovenian*)
|
||||||
- Jothipazhani Nagarajan (*Tamil*)
|
- Ильзира Рахматуллина (rahmatullinailzira53) (*Tatar*)
|
||||||
- Miquel Sabaté Solà (*Catalan*)
|
- cenegd (*Chinese Simplified*)
|
||||||
|
- Hugh Liu (youloveonlymeh) (*Chinese Simplified*)
|
||||||
|
- Pixelcode (realpixelcode) (*German*)
|
||||||
|
- Yogesh K S (yogi) (*Kannada*)
|
||||||
|
- Rakino (rakino) (*Chinese Simplified*)
|
||||||
|
- Miquel Sabaté Solà (mssola) (*Catalan*)
|
||||||
- AmazighNM (*Kabyle*)
|
- AmazighNM (*Kabyle*)
|
||||||
- Solid Rhino (*Dutch*)
|
- Jothipazhani Nagarajan (jothipazhani.n) (*Tamil*)
|
||||||
|
- Clash Clans (KURD12345) (*Sorani (Kurdish)*)
|
||||||
- hallomaurits (*Dutch*)
|
- hallomaurits (*Dutch*)
|
||||||
|
- alnd hezh (alndhezh) (*Sorani (Kurdish)*)
|
||||||
|
- Solid Rhino (SolidRhino) (*Dutch*)
|
||||||
|
- k_taka (peaceroad) (*Japanese*)
|
||||||
|
- Hallo Abdullah (hallo_hamza12) (*Sorani (Kurdish)*)
|
||||||
- hussama (*Portuguese, Brazilian*)
|
- hussama (*Portuguese, Brazilian*)
|
||||||
- shafouz (*Portuguese, Brazilian*)
|
- Sébastien Feugère (smonff) (*French*)
|
||||||
- Tagada (*French*)
|
- 林水溶 (shuiRong) (*Chinese Simplified*)
|
||||||
- Tom_ (*Czech*)
|
|
||||||
- SnDer (*Dutch*)
|
|
||||||
- eichkat3r (*German*)
|
- eichkat3r (*German*)
|
||||||
- PifyZ (*French*)
|
|
||||||
- OminousCry (*Russian*)
|
- OminousCry (*Russian*)
|
||||||
- Shrinivasan T (*Tamil*)
|
- SnDer (*Dutch*)
|
||||||
- Nathaël Noguès (*French*)
|
- PifyZ (*French*)
|
||||||
- Daniel M. (*Catalan*)
|
- Tom_ (*Czech*)
|
||||||
- Swati Sani (*Urdu*)
|
- Tagada (Tagadda) (*French*)
|
||||||
- Kk (*Kannada*)
|
- shafouz (*Portuguese, Brazilian*)
|
||||||
- SusVersiva (*Catalan*)
|
- Kahina Mess (K_hina) (*Kabyle*)
|
||||||
- Robin van der Vliet (*Esperanto*)
|
- Nathaël Noguès (NatNgs) (*French*)
|
||||||
- Zinkokooo (*Basque*)
|
- Kk (kishorkumara3) (*Kannada*)
|
||||||
- Tradjincal (*French*)
|
- Swati Sani (swatisani) (*Urdu (Pakistan)*)
|
||||||
|
- Shrinivasan T (tshrinivasan) (*Tamil*)
|
||||||
|
- さっかりんにーさん (saccharin23) (*Japanese*)
|
||||||
|
- 夜楓Yoka (Yoka2627) (*Chinese Simplified*)
|
||||||
|
- Daniel M. (daniconil) (*Catalan*)
|
||||||
- Vikatakavi (*Kannada*)
|
- Vikatakavi (*Kannada*)
|
||||||
- prabhjot (*Hindi*)
|
- SusVersiva (*Catalan*)
|
||||||
- twpenguin (*Chinese Traditional*)
|
- Tradjincal (tradjincal) (*French*)
|
||||||
|
- pullopen (*Chinese Simplified*)
|
||||||
|
- Robin van der Vliet (RobinvanderVliet) (*Esperanto*)
|
||||||
|
- Zinkokooo (*Basque*)
|
||||||
- mmokhi (*Persian*)
|
- mmokhi (*Persian*)
|
||||||
|
- Livingston Samuel (livingston) (*Tamil*)
|
||||||
|
- prabhjot (*Hindi*)
|
||||||
- sergioaraujo1 (*Portuguese, Brazilian*)
|
- sergioaraujo1 (*Portuguese, Brazilian*)
|
||||||
- Livingston Samuel (*Tamil*)
|
- CyberAmoeba (pseudoobscura) (*Chinese Simplified*)
|
||||||
- tsundoker (*Malayalam*)
|
- tsundoker (*Malayalam*)
|
||||||
- skaaarrr (*German*)
|
- skaaarrr (*German*)
|
||||||
- 夜楓Yoka (*Chinese Simplified*)
|
- Ricardo Colin (rysard) (*Spanish*)
|
||||||
- kiwi0 (*Italian*)
|
- mkljczk (mykylyjczyk) (*Polish*)
|
||||||
|
- Philipp Fischbeck (PFischbeck) (*German*)
|
||||||
- fedot (*Russian*)
|
- fedot (*Russian*)
|
||||||
- mkljczk (*Polish*)
|
- Paz Galindo (paz.almendra.g) (*Spanish*)
|
||||||
- igordrozniak (*Polish*)
|
- GaggiX (*Italian*)
|
||||||
- Ricardo Colin (*Spanish*)
|
|
||||||
- Esther (*Portuguese*)
|
|
||||||
- Paz Galindo (*Spanish*)
|
|
||||||
- Philipp Fischbeck (*German*)
|
|
||||||
- ralozkolya (*Georgian*)
|
- ralozkolya (*Georgian*)
|
||||||
- JackXu (*Chinese Simplified*)
|
- Zoé Bőle (zoe1337) (*German*)
|
||||||
- Allen Zhong (*Chinese Simplified*)
|
- Lukas Fülling (lfuelling) (*German*)
|
||||||
- Zoé Bőle (*German*)
|
- JackXu (Merman-Jack) (*Chinese Simplified*)
|
||||||
- Lukas Fülling (*German*)
|
- Aymeric (AymBroussier) (*French*)
|
||||||
- Albatroz Jeremias (*Portuguese*)
|
- Anoop (anoopp) (*Malayalam*)
|
||||||
- Samir Tighzert (*Kabyle*)
|
|
||||||
- Nocta (*French*)
|
|
||||||
- Anoop (*Malayalam*)
|
|
||||||
- pezcurrel (*Italian*)
|
- pezcurrel (*Italian*)
|
||||||
- Dremski (*Bulgarian*)
|
- Dremski (*Bulgarian*)
|
||||||
- Aymeric (*French*)
|
- Xurxo Guerra (xguerrap) (*Galician*)
|
||||||
- tamaina (*Japanese*)
|
- mashirozx (*Chinese Simplified*)
|
||||||
- Doug (*Portuguese, Brazilian*)
|
- Albatroz Jeremias (albjeremias) (*Portuguese*)
|
||||||
- Matias Lavik (*Norwegian Nynorsk*)
|
- Samir Tighzert (samir_t7) (*Kabyle*)
|
||||||
- Fleva (*Sardinian*)
|
- Apple (blackteaovo) (*Chinese Simplified*)
|
||||||
|
- Nocta (*French*)
|
||||||
- OpenAlgeria (*Arabic*)
|
- OpenAlgeria (*Arabic*)
|
||||||
- koppe-pan (*Japanese*)
|
- tamaina (*Japanese*)
|
||||||
- Amith Raj Shetty (*Kannada*)
|
- abidin toumi (Zet24) (*Arabic*)
|
||||||
|
- xpac1985 (xpac) (*German*)
|
||||||
|
- Kaede (kaedech) (*Japanese*)
|
||||||
|
- ÀŘǾŚ PÀŚĦÀÍ (arospashai) (*Sorani (Kurdish)*)
|
||||||
|
- Matias Lavik (matiaslavik) (*Norwegian Nynorsk*)
|
||||||
- smedvedev (*Russian*)
|
- smedvedev (*Russian*)
|
||||||
- Trond Boksasp (*Norwegian*)
|
- mikel (mikelalas) (*Spanish*)
|
||||||
|
- Doug (douglasalvespe) (*Portuguese, Brazilian*)
|
||||||
|
- Trond Boksasp (boksasp) (*Norwegian*)
|
||||||
|
- Fleva (*Sardinian*)
|
||||||
|
- Mohammad Adnan Mahmood (adnanmig) (*Arabic*)
|
||||||
|
- Sais Lakshmanan (Saislakshmanan) (*Tamil*)
|
||||||
|
- Amith Raj Shetty (amithraj1989) (*Kannada*)
|
||||||
- random_person (*Spanish*)
|
- random_person (*Spanish*)
|
||||||
- Sais Lakshmanan (*Tamil*)
|
- djoerd (*Dutch*)
|
||||||
- mikel (*Spanish*)
|
- Baban Abdulrahman (baban.abdulrehman) (*Sorani (Kurdish)*)
|
||||||
- Mohammad Adnan Mahmood (*Arabic*)
|
- ebrezhoneg (*Breton*)
|
||||||
|
- dashty (*Sorani (Kurdish)*)
|
||||||
|
- Salh_haji6 (*Sorani (Kurdish)*)
|
||||||
|
- Amir Kurdo (kuraking202) (*Sorani (Kurdish)*)
|
||||||
|
- おさ (osapon) (*Japanese*)
|
||||||
|
- Ranj A Abdulqadir (RanjAhmed) (*Sorani (Kurdish)*)
|
||||||
|
- umonaca (*Chinese Simplified*)
|
||||||
|
- Bartek Fijałkowski (brateq) (*Polish*)
|
||||||
|
- tateisu (*Japanese*)
|
||||||
|
- centumix (*Japanese*)
|
||||||
|
- Jari Ronkainen (ronchaine) (*Finnish*)
|
||||||
|
- Savarín Electrográfico Marmota Intergalactica (herrero.maty) (*Spanish*)
|
||||||
|
- Torsten Högel (torstenhoegel) (*German*)
|
||||||
|
- Abijeet Patro (Abijeet) (*Basque*)
|
||||||
|
- Ács Zoltán (acszoltan111) (*Hungarian*)
|
||||||
|
- Benjamin Cobb (benjamincobb) (*German*)
|
||||||
|
- waweic (*German*)
|
||||||
|
- Aries (orlea) (*Japanese*)
|
||||||
|
- silverscat_3 (SilversCat) (*Japanese*)
|
||||||
|
- kavitha129 (*Tamil*)
|
||||||
|
- dcapillae (*Spanish*)
|
||||||
|
- SamOak (*Portuguese, Brazilian*)
|
||||||
|
- capiscuas (*Spanish*)
|
||||||
|
- NeverMine17 (*Russian*)
|
||||||
|
- Nithya Mary (nithyamary25) (*Tamil*)
|
||||||
|
- t_aus_m (*German*)
|
||||||
|
- dobrado (*Portuguese, Brazilian*)
|
||||||
|
- Hannah (Aniqueper1) (*Chinese Simplified*)
|
||||||
|
- Jiniux (*Italian*)
|
||||||
|
- 于晚霞 (xissshawww) (*Chinese Simplified*)
|
||||||
|
1
Aptfile
1
Aptfile
@ -5,7 +5,6 @@ libidn11
|
|||||||
libidn11-dev
|
libidn11-dev
|
||||||
libpq-dev
|
libpq-dev
|
||||||
libprotobuf-dev
|
libprotobuf-dev
|
||||||
libssl-dev
|
|
||||||
libxdamage1
|
libxdamage1
|
||||||
libxfixes3
|
libxfixes3
|
||||||
protobuf-compiler
|
protobuf-compiler
|
||||||
|
208
CHANGELOG.md
208
CHANGELOG.md
@ -3,6 +3,208 @@ Changelog
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [3.3.0] - 2020-12-27
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Add hotkeys for audio/video control in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/15158), [Gargron](https://github.com/tootsuite/mastodon/pull/15198))
|
||||||
|
- `Space` and `k` to toggle playback
|
||||||
|
- `m` to toggle mute
|
||||||
|
- `f` to toggle fullscreen
|
||||||
|
- `j` and `l` to go back and forward by 10 seconds
|
||||||
|
- `.` and `,` to go back and forward by a frame (video only)
|
||||||
|
- Add expand/compress button on media modal in web UI ([mashirozx](https://github.com/tootsuite/mastodon/pull/15068), [mashirozx](https://github.com/tootsuite/mastodon/pull/15088), [mashirozx](https://github.com/tootsuite/mastodon/pull/15094))
|
||||||
|
- Add border around 🕺 emoji in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14769))
|
||||||
|
- Add border around 🐞 emoji in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14712))
|
||||||
|
- Add home link to the getting started column when home isn't mounted ([ThibG](https://github.com/tootsuite/mastodon/pull/14707))
|
||||||
|
- Add option to disable swiping motions across the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13885))
|
||||||
|
- **Add pop-out player for audio/video in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/14870), [Gargron](https://github.com/tootsuite/mastodon/pull/15157), [Gargron](https://github.com/tootsuite/mastodon/pull/14915), [noellabo](https://github.com/tootsuite/mastodon/pull/15309))
|
||||||
|
- Continue watching/listening when you scroll away
|
||||||
|
- Action bar to interact with/open toot from the pop-out player
|
||||||
|
- Add unread notification markers in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14818), [ThibG](https://github.com/tootsuite/mastodon/pull/14960), [ThibG](https://github.com/tootsuite/mastodon/pull/14954), [noellabo](https://github.com/tootsuite/mastodon/pull/14897), [noellabo](https://github.com/tootsuite/mastodon/pull/14907))
|
||||||
|
- Add paragraph about browser add-ons when encountering errors in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14801))
|
||||||
|
- Add import and export for bookmarks ([ThibG](https://github.com/tootsuite/mastodon/pull/14956))
|
||||||
|
- Add cache buster feature for media files ([Gargron](https://github.com/tootsuite/mastodon/pull/15155))
|
||||||
|
- If you have a proxy cache in front of object storage, deleted files will persist until the cache expires
|
||||||
|
- If enabled, cache buster will make a special request to the proxy to signal a cache reset
|
||||||
|
- Add duration option to the mute function ([aquarla](https://github.com/tootsuite/mastodon/pull/13831))
|
||||||
|
- Add replies policy option to the list function ([ThibG](https://github.com/tootsuite/mastodon/pull/9205), [trwnh](https://github.com/tootsuite/mastodon/pull/15304))
|
||||||
|
- Add `og:published_time` OpenGraph tags on toots ([nornagon](https://github.com/tootsuite/mastodon/pull/14865))
|
||||||
|
- **Add option to be notified when a followed user posts** ([Gargron](https://github.com/tootsuite/mastodon/pull/13546), [ThibG](https://github.com/tootsuite/mastodon/pull/14896), [Gargron](https://github.com/tootsuite/mastodon/pull/14822))
|
||||||
|
- If you don't want to miss a toot, click the bell button!
|
||||||
|
- Add client-side validation in password change forms ([ThibG](https://github.com/tootsuite/mastodon/pull/14564))
|
||||||
|
- Add client-side validation in the registration form ([ThibG](https://github.com/tootsuite/mastodon/pull/14560), [ThibG](https://github.com/tootsuite/mastodon/pull/14599))
|
||||||
|
- Add support for Gemini URLs ([joshleeb](https://github.com/tootsuite/mastodon/pull/15013))
|
||||||
|
- Add app shortcuts to web app manifest ([mkljczk](https://github.com/tootsuite/mastodon/pull/15234))
|
||||||
|
- Add WebAuthn as an alternative 2FA method ([santiagorodriguez96](https://github.com/tootsuite/mastodon/pull/14466), [jiikko](https://github.com/tootsuite/mastodon/pull/14806))
|
||||||
|
- Add honeypot fields and minimum fill-out time for sign-up form ([ThibG](https://github.com/tootsuite/mastodon/pull/15276))
|
||||||
|
- Add icon for mutual relationships in relationship manager ([noellabo](https://github.com/tootsuite/mastodon/pull/15149))
|
||||||
|
- Add follow selected followers button in relationship manager ([noellabo](https://github.com/tootsuite/mastodon/pull/15148))
|
||||||
|
- **Add subresource integrity for JS and CSS assets** ([Gargron](https://github.com/tootsuite/mastodon/pull/15096))
|
||||||
|
- If you use a CDN for static assets (JavaScript, CSS, and so on), you have to trust that the CDN does not modify the assets maliciously
|
||||||
|
- Subresource integrity compares server-generated asset digests with what's actually served from the CDN and prevents such attacks
|
||||||
|
- Add `ku`, `sa`, `sc`, `zgh` to available locales ([ykzts](https://github.com/tootsuite/mastodon/pull/15138))
|
||||||
|
- Add ability to force an account to mark media as sensitive ([noellabo](https://github.com/tootsuite/mastodon/pull/14361))
|
||||||
|
- **Add ability to block access or limit sign-ups from chosen IPs** ([Gargron](https://github.com/tootsuite/mastodon/pull/14963), [ThibG](https://github.com/tootsuite/mastodon/pull/15263))
|
||||||
|
- Add rules for IPs or CIDR ranges that automatically expire after a configurable amount of time
|
||||||
|
- Choose the severity of the rule, either blocking all access or merely limiting sign-ups
|
||||||
|
- **Add support for reversible suspensions through ActivityPub** ([Gargron](https://github.com/tootsuite/mastodon/pull/14989))
|
||||||
|
- Servers can signal that one of their accounts has been suspended
|
||||||
|
- During suspension, the account can only delete its own content
|
||||||
|
- A reversal of the suspension can be signalled the same way
|
||||||
|
- A local suspension always overrides a remote one
|
||||||
|
- Add indication to admin UI of whether a report has been forwarded ([ThibG](https://github.com/tootsuite/mastodon/pull/13237))
|
||||||
|
- Add display of reasons for joining of an account in admin UI ([mashirozx](https://github.com/tootsuite/mastodon/pull/15265))
|
||||||
|
- Add option to obfuscate domain name in public list of domain blocks ([Gargron](https://github.com/tootsuite/mastodon/pull/15355))
|
||||||
|
- Add option to make reasons for joining required on sign-up ([ThibG](https://github.com/tootsuite/mastodon/pull/15326), [ThibG](https://github.com/tootsuite/mastodon/pull/15358), [ThibG](https://github.com/tootsuite/mastodon/pull/15385), [ThibG](https://github.com/tootsuite/mastodon/pull/15405))
|
||||||
|
- Add ActivityPub follower synchronization mechanism ([ThibG](https://github.com/tootsuite/mastodon/pull/14510), [ThibG](https://github.com/tootsuite/mastodon/pull/15026))
|
||||||
|
- Add outbox attribute to instance actor ([ThibG](https://github.com/tootsuite/mastodon/pull/14721))
|
||||||
|
- Add featured hashtags as an ActivityPub collection ([Gargron](https://github.com/tootsuite/mastodon/pull/11595), [noellabo](https://github.com/tootsuite/mastodon/pull/15277))
|
||||||
|
- Add support for dereferencing objects through bearcaps ([Gargron](https://github.com/tootsuite/mastodon/pull/14683), [noellabo](https://github.com/tootsuite/mastodon/pull/14981))
|
||||||
|
- Add `S3_READ_TIMEOUT` environment variable ([tateisu](https://github.com/tootsuite/mastodon/pull/14952))
|
||||||
|
- Add `ALLOWED_PRIVATE_ADDRESSES` environment variable ([ThibG](https://github.com/tootsuite/mastodon/pull/14722))
|
||||||
|
- Add `--fix-permissions` option to `tootctl media remove-orphans` ([Gargron](https://github.com/tootsuite/mastodon/pull/14383), [uist1idrju3i](https://github.com/tootsuite/mastodon/pull/14715))
|
||||||
|
- Add `tootctl accounts merge` ([Gargron](https://github.com/tootsuite/mastodon/pull/15201), [ThibG](https://github.com/tootsuite/mastodon/pull/15264), [ThibG](https://github.com/tootsuite/mastodon/pull/15256))
|
||||||
|
- Has someone changed their domain or subdomain thereby creating two accounts where there should be one?
|
||||||
|
- This command will fix it on your end
|
||||||
|
- Add `tootctl maintenance fix-duplicates` ([ThibG](https://github.com/tootsuite/mastodon/pull/14860), [Gargron](https://github.com/tootsuite/mastodon/pull/15223), [ThibG](https://github.com/tootsuite/mastodon/pull/15373))
|
||||||
|
- Index corruption in the database?
|
||||||
|
- This command is for you
|
||||||
|
- **Add support for managing multiple stream subscriptions in a single connection** ([Gargron](https://github.com/tootsuite/mastodon/pull/14524), [Gargron](https://github.com/tootsuite/mastodon/pull/14566), [mfmfuyu](https://github.com/tootsuite/mastodon/pull/14859), [zunda](https://github.com/tootsuite/mastodon/pull/14608))
|
||||||
|
- Previously, getting live updates for multiple timelines required opening a HTTP or WebSocket connection for each
|
||||||
|
- More connections means more resource consumption on both ends, not to mention the (ever so slight) delay when establishing a new connection
|
||||||
|
- Now, with just a single WebSocket connection you can subscribe and unsubscribe to and from multiple streams
|
||||||
|
- Add support for limiting results by both `min_id` and `max_id` at the same time in REST API ([tateisu](https://github.com/tootsuite/mastodon/pull/14776))
|
||||||
|
- Add `GET /api/v1/accounts/:id/featured_tags` to REST API ([noellabo](https://github.com/tootsuite/mastodon/pull/11817), [noellabo](https://github.com/tootsuite/mastodon/pull/15270))
|
||||||
|
- Add stoplight for object storage failures, return HTTP 503 in REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/13043))
|
||||||
|
- Add optional `tootctl remove media` cronjob in Helm chart ([dunn](https://github.com/tootsuite/mastodon/pull/14396))
|
||||||
|
- Add clean error message when `RAILS_ENV` is unset ([ThibG](https://github.com/tootsuite/mastodon/pull/15381))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Change media modals look in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/15217), [Gargron](https://github.com/tootsuite/mastodon/pull/15221), [Gargron](https://github.com/tootsuite/mastodon/pull/15284), [Gargron](https://github.com/tootsuite/mastodon/pull/15283), [Kjwon15](https://github.com/tootsuite/mastodon/pull/15308), [noellabo](https://github.com/tootsuite/mastodon/pull/15305), [ThibG](https://github.com/tootsuite/mastodon/pull/15417))
|
||||||
|
- Background of the overlay matches the color of the image
|
||||||
|
- Action bar to interact with or open the toot from the modal
|
||||||
|
- Change order of announcements in admin UI to be newest-first ([ThibG](https://github.com/tootsuite/mastodon/pull/15091))
|
||||||
|
- **Change account suspensions to be reversible by default** ([Gargron](https://github.com/tootsuite/mastodon/pull/14726), [ThibG](https://github.com/tootsuite/mastodon/pull/15152), [ThibG](https://github.com/tootsuite/mastodon/pull/15106), [ThibG](https://github.com/tootsuite/mastodon/pull/15100), [ThibG](https://github.com/tootsuite/mastodon/pull/15099), [noellabo](https://github.com/tootsuite/mastodon/pull/14855), [ThibG](https://github.com/tootsuite/mastodon/pull/15380), [Gargron](https://github.com/tootsuite/mastodon/pull/15420), [Gargron](https://github.com/tootsuite/mastodon/pull/15414))
|
||||||
|
- Suspensions no longer equal deletions
|
||||||
|
- A suspended account can be unsuspended with minimal consequences for 30 days
|
||||||
|
- Immediate deletion of data is still available as an explicit option
|
||||||
|
- Suspended accounts can request an archive of their data through the UI
|
||||||
|
- Change REST API to return empty data for suspended accounts (14765)
|
||||||
|
- Change web UI to show empty profile for suspended accounts ([Gargron](https://github.com/tootsuite/mastodon/pull/14766), [Gargron](https://github.com/tootsuite/mastodon/pull/15345))
|
||||||
|
- Change featured hashtag suggestions to be recently used instead of most used ([abcang](https://github.com/tootsuite/mastodon/pull/14760))
|
||||||
|
- Change direct toots to appear in the home feed again ([Gargron](https://github.com/tootsuite/mastodon/pull/14711), [ThibG](https://github.com/tootsuite/mastodon/pull/15182), [noellabo](https://github.com/tootsuite/mastodon/pull/14727))
|
||||||
|
- Return to treating all toots the same instead of trying to retrofit direct visibility into an instant messaging model
|
||||||
|
- Change email address validation to return more specific errors ([ThibG](https://github.com/tootsuite/mastodon/pull/14565))
|
||||||
|
- Change HTTP signature requirements to include `Digest` header on `POST` requests ([ThibG](https://github.com/tootsuite/mastodon/pull/15069))
|
||||||
|
- Change click area of video/audio player buttons to be bigger in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/15049))
|
||||||
|
- Change order of filters by alphabetic by "keyword or phrase" ([ariasuni](https://github.com/tootsuite/mastodon/pull/15050))
|
||||||
|
- Change suspension of remote accounts to also undo outgoing follows ([ThibG](https://github.com/tootsuite/mastodon/pull/15188))
|
||||||
|
- Change string "Home" to "Home and lists" in the filter creation screen ([ariasuni](https://github.com/tootsuite/mastodon/pull/15139))
|
||||||
|
- Change string "Boost to original audience" to "Boost with original visibility" in web UI ([3n-k1](https://github.com/tootsuite/mastodon/pull/14598))
|
||||||
|
- Change string "Show more" to "Show newer" and "Show older" on public pages ([ariasuni](https://github.com/tootsuite/mastodon/pull/15052))
|
||||||
|
- Change order of announcements to be reverse chronological in web UI ([dariusk](https://github.com/tootsuite/mastodon/pull/15065), [dariusk](https://github.com/tootsuite/mastodon/pull/15070))
|
||||||
|
- Change RTL detection to rely on unicode-bidi paragraph by paragraph in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/14573))
|
||||||
|
- Change visibility icon next to timestamp to be clickable in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/15053), [mayaeh](https://github.com/tootsuite/mastodon/pull/15055))
|
||||||
|
- Change public thread view to hide "Show thread" link ([ThibG](https://github.com/tootsuite/mastodon/pull/15266))
|
||||||
|
- Change number format on about page from full to shortened ([Gargron](https://github.com/tootsuite/mastodon/pull/15327))
|
||||||
|
- Change how scheduled tasks run in multi-process environments ([noellabo](https://github.com/tootsuite/mastodon/pull/15314))
|
||||||
|
- New dedicated queue `scheduler`
|
||||||
|
- Runs by default when Sidekiq is executed with no options
|
||||||
|
- Has to be added manually in a multi-process environment
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove fade-in animation from modals in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/15199))
|
||||||
|
- Remove auto-redirect to direct messages in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/15142))
|
||||||
|
- Remove obsolete IndexedDB operations from web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/14730))
|
||||||
|
- Remove dependency on unused and unmaintained http_parser.rb gem ([ThibG](https://github.com/tootsuite/mastodon/pull/14574))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix layout on about page when contact account has a long username ([ThibG](https://github.com/tootsuite/mastodon/pull/15357))
|
||||||
|
- Fix follow limit preventing re-following of a moved account ([Gargron](https://github.com/tootsuite/mastodon/pull/14207), [ThibG](https://github.com/tootsuite/mastodon/pull/15384))
|
||||||
|
- **Fix deletes not reaching every server that interacted with toot** ([Gargron](https://github.com/tootsuite/mastodon/pull/15200))
|
||||||
|
- Previously, delete of a toot would be primarily sent to the followers of its author, people mentioned in the toot, and people who reblogged the toot
|
||||||
|
- Now, additionally, it is ensured that it is sent to people who replied to it, favourited it, and to the person it replies to even if that person is not mentioned
|
||||||
|
- Fix resolving an account through its non-canonical form (i.e. alternate domain) ([ThibG](https://github.com/tootsuite/mastodon/pull/15187))
|
||||||
|
- Fix sending redundant ActivityPub events when processing remote account deletion ([ThibG](https://github.com/tootsuite/mastodon/pull/15104))
|
||||||
|
- Fix Move handler not being triggered when failing to fetch target account ([ThibG](https://github.com/tootsuite/mastodon/pull/15107))
|
||||||
|
- Fix downloading remote media files when server returns empty filename ([ThibG](https://github.com/tootsuite/mastodon/pull/14867))
|
||||||
|
- Fix account processing failing because of large collections ([ThibG](https://github.com/tootsuite/mastodon/pull/15027))
|
||||||
|
- Fix not being able to unfavorite toots one has lost access to ([ThibG](https://github.com/tootsuite/mastodon/pull/15192))
|
||||||
|
- Fix not being able to unbookmark toots one has lost access to ([ThibG](https://github.com/tootsuite/mastodon/pull/14604))
|
||||||
|
- Fix possible casing inconsistencies in hashtag search ([ThibG](https://github.com/tootsuite/mastodon/pull/14906))
|
||||||
|
- Fix updating account counters when association is not yet created ([Gargron](https://github.com/tootsuite/mastodon/pull/15108))
|
||||||
|
- Fix cookies not having a SameSite attribute ([Gargron](https://github.com/tootsuite/mastodon/pull/15098))
|
||||||
|
- Fix poll ending notifications being created for each vote ([ThibG](https://github.com/tootsuite/mastodon/pull/15071))
|
||||||
|
- Fix multiple boosts of a same toot erroneously appearing in TL ([ThibG](https://github.com/tootsuite/mastodon/pull/14759))
|
||||||
|
- Fix asset builds not picking up `CDN_HOST` change ([ThibG](https://github.com/tootsuite/mastodon/pull/14381))
|
||||||
|
- Fix desktop notifications permission prompt in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/14985), [Gargron](https://github.com/tootsuite/mastodon/pull/15141), [ThibG](https://github.com/tootsuite/mastodon/pull/13543), [ThibG](https://github.com/tootsuite/mastodon/pull/15176))
|
||||||
|
- Some time ago, browsers added a requirement that desktop notification prompts could only be displayed in response to a user-generated event (such as a click)
|
||||||
|
- This means that for some time, users who haven't already given the permission before were not getting a prompt and as such were not receiving desktop notifications
|
||||||
|
- Fix "Mark media as sensitive" string not supporting pluralizations in other languages in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/15051))
|
||||||
|
- Fix glitched image uploads when canvas read access is blocked in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/15180))
|
||||||
|
- Fix some account gallery items having empty labels in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/15073))
|
||||||
|
- Fix alt-key hotkeys activating while typing in a text field in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14942))
|
||||||
|
- Fix wrong seek bar width on media player in web UI ([mfmfuyu](https://github.com/tootsuite/mastodon/pull/15060))
|
||||||
|
- Fix logging out on mobile in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14901))
|
||||||
|
- Fix wrong click area for GIFVs in media modal in web UI ([noellabo](https://github.com/tootsuite/mastodon/pull/14615))
|
||||||
|
- Fix unreadable placeholder text color in high contrast theme in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/14803))
|
||||||
|
- Fix scrolling issues when closing some dropdown menus in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14606))
|
||||||
|
- Fix notification filter bar incorrectly filtering gaps in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14808))
|
||||||
|
- Fix disabled boost icon being replaced by private boost icon on hover in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14456))
|
||||||
|
- Fix hashtag detection in compose form being different to server-side in web UI ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/14484), [ThibG](https://github.com/tootsuite/mastodon/pull/14513))
|
||||||
|
- Fix home last read marker mishandling gaps in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14809))
|
||||||
|
- Fix unnecessary re-rendering of various components when typing in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/15286))
|
||||||
|
- Fix notifications being unnecessarily re-rendered in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/15312))
|
||||||
|
- Fix column swiping animation logic in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/15301))
|
||||||
|
- Fix inefficiency when fetching hashtag timeline ([noellabo](https://github.com/tootsuite/mastodon/pull/14861), [akihikodaki](https://github.com/tootsuite/mastodon/pull/14662))
|
||||||
|
- Fix inefficiency when fetching bookmarks ([akihikodaki](https://github.com/tootsuite/mastodon/pull/14674))
|
||||||
|
- Fix inefficiency when fetching favourites ([akihikodaki](https://github.com/tootsuite/mastodon/pull/14673))
|
||||||
|
- Fix inefficiency when fetching media-only account timeline ([akihikodaki](https://github.com/tootsuite/mastodon/pull/14675))
|
||||||
|
- Fix inefficieny when deleting accounts ([Gargron](https://github.com/tootsuite/mastodon/pull/15387), [ThibG](https://github.com/tootsuite/mastodon/pull/15409), [ThibG](https://github.com/tootsuite/mastodon/pull/15407), [ThibG](https://github.com/tootsuite/mastodon/pull/15408), [ThibG](https://github.com/tootsuite/mastodon/pull/15402), [ThibG](https://github.com/tootsuite/mastodon/pull/15416), [Gargron](https://github.com/tootsuite/mastodon/pull/15421))
|
||||||
|
- Fix redundant query when processing batch actions on custom emojis ([niwatori24](https://github.com/tootsuite/mastodon/pull/14534))
|
||||||
|
- Fix slow distinct queries where grouped queries are faster ([Gargron](https://github.com/tootsuite/mastodon/pull/15287))
|
||||||
|
- Fix performance on instances list in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/15282))
|
||||||
|
- Fix server actor appearing in list of accounts in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/14567))
|
||||||
|
- Fix "bootstrap timeline accounts" toggle in site settings in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/15325))
|
||||||
|
- Fix PostgreSQL secret name for cronjob in Helm chart ([metal3d](https://github.com/tootsuite/mastodon/pull/15072))
|
||||||
|
- Fix Procfile not being compatible with herokuish ([acuteaura](https://github.com/tootsuite/mastodon/pull/12685))
|
||||||
|
- Fix installation of tini being split into multiple steps in Dockerfile ([ryncsn](https://github.com/tootsuite/mastodon/pull/14686))
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix streaming API allowing connections to persist after access token invalidation ([Gargron](https://github.com/tootsuite/mastodon/pull/15111))
|
||||||
|
- Fix 2FA/sign-in token sessions being valid after password change ([Gargron](https://github.com/tootsuite/mastodon/pull/14802))
|
||||||
|
- Fix resolving accounts sometimes creating duplicate records for a given ActivityPub identifier ([ThibG](https://github.com/tootsuite/mastodon/pull/15364))
|
||||||
|
|
||||||
|
## [3.2.2] - 2020-12-19
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `tootctl maintenance fix-duplicates` ([ThibG](https://github.com/tootsuite/mastodon/pull/14860), [Gargron](https://github.com/tootsuite/mastodon/pull/15223))
|
||||||
|
- Index corruption in the database?
|
||||||
|
- This command is for you
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove dependency on unused and unmaintained http_parser.rb gem ([ThibG](https://github.com/tootsuite/mastodon/pull/14574))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix Move handler not being triggered when failing to fetch target account ([ThibG](https://github.com/tootsuite/mastodon/pull/15107))
|
||||||
|
- Fix downloading remote media files when server returns empty filename ([ThibG](https://github.com/tootsuite/mastodon/pull/14867))
|
||||||
|
- Fix possible casing inconsistencies in hashtag search ([ThibG](https://github.com/tootsuite/mastodon/pull/14906))
|
||||||
|
- Fix updating account counters when association is not yet created ([Gargron](https://github.com/tootsuite/mastodon/pull/15108))
|
||||||
|
- Fix account processing failing because of large collections ([ThibG](https://github.com/tootsuite/mastodon/pull/15027))
|
||||||
|
- Fix resolving an account through its non-canonical form (i.e. alternate domain) ([ThibG](https://github.com/tootsuite/mastodon/pull/15187))
|
||||||
|
- Fix slow distinct queries where grouped queries are faster ([Gargron](https://github.com/tootsuite/mastodon/pull/15287))
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix 2FA/sign-in token sessions being valid after password change ([Gargron](https://github.com/tootsuite/mastodon/pull/14802))
|
||||||
|
- Fix resolving accounts sometimes creating duplicate records for a given ActivityPub identifier ([ThibG](https://github.com/tootsuite/mastodon/pull/15364))
|
||||||
|
|
||||||
## [3.2.1] - 2020-10-19
|
## [3.2.1] - 2020-10-19
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
@ -185,14 +387,14 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Only then proceed to start removing their data (slow)
|
- Only then proceed to start removing their data (slow)
|
||||||
- Clear out media attachments in a separate worker (slow)
|
- Clear out media attachments in a separate worker (slow)
|
||||||
|
|
||||||
## [v3.1.5] - 2020-07-07
|
## [3.1.5] - 2020-07-07
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- Fix media attachment enumeration ([ThibG](https://github.com/tootsuite/mastodon/pull/14254))
|
- Fix media attachment enumeration ([ThibG](https://github.com/tootsuite/mastodon/pull/14254))
|
||||||
- Change rate limits for various paths ([Gargron](https://github.com/tootsuite/mastodon/pull/14253))
|
- Change rate limits for various paths ([Gargron](https://github.com/tootsuite/mastodon/pull/14253))
|
||||||
- Fix other sessions not being logged out on password change ([Gargron](https://github.com/tootsuite/mastodon/pull/14252))
|
- Fix other sessions not being logged out on password change ([Gargron](https://github.com/tootsuite/mastodon/pull/14252))
|
||||||
|
|
||||||
## [v3.1.4] - 2020-05-14
|
## [3.1.4] - 2020-05-14
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `vi` to available locales ([taicv](https://github.com/tootsuite/mastodon/pull/13542))
|
- Add `vi` to available locales ([taicv](https://github.com/tootsuite/mastodon/pull/13542))
|
||||||
@ -259,7 +461,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- For apps that self-register on behalf of every individual user (such as most mobile apps), this is a non-issue
|
- For apps that self-register on behalf of every individual user (such as most mobile apps), this is a non-issue
|
||||||
- The issue only affects developers of apps who are shared between multiple users, such as server-side apps like cross-posters
|
- The issue only affects developers of apps who are shared between multiple users, such as server-side apps like cross-posters
|
||||||
|
|
||||||
## [v3.1.3] - 2020-04-05
|
## [3.1.3] - 2020-04-05
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add ability to filter audit log in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13381))
|
- Add ability to filter audit log in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13381))
|
||||||
|
23
Dockerfile
23
Dockerfile
@ -4,7 +4,7 @@ FROM ubuntu:20.04 as build-dep
|
|||||||
SHELL ["bash", "-c"]
|
SHELL ["bash", "-c"]
|
||||||
|
|
||||||
# Install Node v12 (LTS)
|
# Install Node v12 (LTS)
|
||||||
ENV NODE_VER="12.16.3"
|
ENV NODE_VER="12.20.0"
|
||||||
RUN ARCH= && \
|
RUN ARCH= && \
|
||||||
dpkgArch="$(dpkg --print-architecture)" && \
|
dpkgArch="$(dpkg --print-architecture)" && \
|
||||||
case "${dpkgArch##*-}" in \
|
case "${dpkgArch##*-}" in \
|
||||||
@ -36,10 +36,11 @@ RUN apt update && \
|
|||||||
./autogen.sh && \
|
./autogen.sh && \
|
||||||
./configure --prefix=/opt/jemalloc && \
|
./configure --prefix=/opt/jemalloc && \
|
||||||
make -j$(nproc) > /dev/null && \
|
make -j$(nproc) > /dev/null && \
|
||||||
make install_bin install_include install_lib
|
make install_bin install_include install_lib && \
|
||||||
|
cd .. && rm -rf jemalloc-$JE_VER $JE_VER.tar.gz
|
||||||
|
|
||||||
# Install Ruby
|
# Install Ruby
|
||||||
ENV RUBY_VER="2.6.6"
|
ENV RUBY_VER="2.7.2"
|
||||||
ENV CPPFLAGS="-I/opt/jemalloc/include"
|
ENV CPPFLAGS="-I/opt/jemalloc/include"
|
||||||
ENV LDFLAGS="-L/opt/jemalloc/lib/"
|
ENV LDFLAGS="-L/opt/jemalloc/lib/"
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
@ -56,7 +57,8 @@ RUN apt update && \
|
|||||||
--disable-install-doc && \
|
--disable-install-doc && \
|
||||||
ln -s /opt/jemalloc/lib/* /usr/lib/ && \
|
ln -s /opt/jemalloc/lib/* /usr/lib/ && \
|
||||||
make -j$(nproc) > /dev/null && \
|
make -j$(nproc) > /dev/null && \
|
||||||
make install
|
make install && \
|
||||||
|
cd .. && rm -rf ruby-$RUBY_VER.tar.gz ruby-$RUBY_VER
|
||||||
|
|
||||||
ENV PATH="${PATH}:/opt/ruby/bin:/opt/node/bin"
|
ENV PATH="${PATH}:/opt/ruby/bin:/opt/node/bin"
|
||||||
|
|
||||||
@ -107,11 +109,14 @@ RUN apt -y --no-install-recommends install \
|
|||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Add tini
|
# Add tini
|
||||||
ENV TINI_VERSION="0.18.0"
|
ENV TINI_VERSION="0.19.0"
|
||||||
ENV TINI_SUM="12d20136605531b09a2c2dac02ccee85e1b874eb322ef6baf7561cd93f93c855"
|
RUN dpkgArch="$(dpkg --print-architecture)" && \
|
||||||
ADD https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini /tini
|
ARCH=$dpkgArch && \
|
||||||
RUN echo "$TINI_SUM tini" | sha256sum -c -
|
wget https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$ARCH \
|
||||||
RUN chmod +x /tini
|
https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$ARCH.sha256sum && \
|
||||||
|
cat tini-$ARCH.sha256sum | sha256sum -c - && \
|
||||||
|
mv tini-$ARCH /tini && rm tini-$ARCH.sha256sum && \
|
||||||
|
chmod +x /tini
|
||||||
|
|
||||||
# Copy over mastodon source, and dependencies from building, and set permissions
|
# Copy over mastodon source, and dependencies from building, and set permissions
|
||||||
COPY --chown=mastodon:mastodon . /opt/mastodon
|
COPY --chown=mastodon:mastodon . /opt/mastodon
|
||||||
|
62
Gemfile
62
Gemfile
@ -5,22 +5,19 @@ ruby '>= 2.5.0', '< 3.0.0'
|
|||||||
|
|
||||||
gem 'pkg-config', '~> 1.4'
|
gem 'pkg-config', '~> 1.4'
|
||||||
|
|
||||||
gem 'puma', '~> 4.3'
|
gem 'puma', '~> 5.0'
|
||||||
gem 'rails', '~> 5.2.4.3'
|
gem 'rails', '~> 5.2.4.4'
|
||||||
gem 'sprockets', '~> 3.7.2'
|
gem 'sprockets', '~> 3.7.2'
|
||||||
gem 'thor', '~> 0.20'
|
gem 'thor', '~> 1.0'
|
||||||
gem 'rack', '~> 2.2.3'
|
gem 'rack', '~> 2.2.3'
|
||||||
|
|
||||||
gem 'thwait', '~> 0.1.0'
|
|
||||||
gem 'e2mmap', '~> 0.1.0'
|
|
||||||
|
|
||||||
gem 'hamlit-rails', '~> 0.2'
|
gem 'hamlit-rails', '~> 0.2'
|
||||||
gem 'pg', '~> 1.2'
|
gem 'pg', '~> 1.2'
|
||||||
gem 'makara', '~> 0.4'
|
gem 'makara', '~> 0.4'
|
||||||
gem 'pghero', '~> 2.5'
|
gem 'pghero', '~> 2.7'
|
||||||
gem 'dotenv-rails', '~> 2.7'
|
gem 'dotenv-rails', '~> 2.7'
|
||||||
|
|
||||||
gem 'aws-sdk-s3', '~> 1.73', require: false
|
gem 'aws-sdk-s3', '~> 1.85', require: false
|
||||||
gem 'fog-core', '<= 2.1.0'
|
gem 'fog-core', '<= 2.1.0'
|
||||||
gem 'fog-openstack', '~> 0.3', require: false
|
gem 'fog-openstack', '~> 0.3', require: false
|
||||||
gem 'paperclip', '~> 6.0'
|
gem 'paperclip', '~> 6.0'
|
||||||
@ -30,7 +27,7 @@ gem 'blurhash', '~> 0.1'
|
|||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.7'
|
gem 'addressable', '~> 2.7'
|
||||||
gem 'bootsnap', '~> 1.4', require: false
|
gem 'bootsnap', '~> 1.5', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'iso-639'
|
gem 'iso-639'
|
||||||
@ -44,9 +41,10 @@ group :pam_authentication, optional: true do
|
|||||||
end
|
end
|
||||||
|
|
||||||
gem 'net-ldap', '~> 0.16'
|
gem 'net-ldap', '~> 0.16'
|
||||||
gem 'omniauth-cas', '~> 1.1'
|
gem 'omniauth-cas', '~> 2.0'
|
||||||
gem 'omniauth-saml', '~> 1.10'
|
gem 'omniauth-saml', '~> 1.10'
|
||||||
gem 'omniauth', '~> 1.9'
|
gem 'omniauth', '~> 1.9'
|
||||||
|
gem 'omniauth-rails_csrf_protection', '~> 0.1'
|
||||||
|
|
||||||
gem 'color_diff', '~> 0.1'
|
gem 'color_diff', '~> 0.1'
|
||||||
gem 'discard', '~> 1.2'
|
gem 'discard', '~> 1.2'
|
||||||
@ -55,12 +53,11 @@ gem 'ed25519', '~> 1.2'
|
|||||||
gem 'fast_blank', '~> 1.0'
|
gem 'fast_blank', '~> 1.0'
|
||||||
gem 'fastimage'
|
gem 'fastimage'
|
||||||
gem 'hiredis', '~> 0.6'
|
gem 'hiredis', '~> 0.6'
|
||||||
gem 'redis-namespace', '~> 1.7'
|
gem 'redis-namespace', '~> 1.8'
|
||||||
gem 'health_check', git: 'https://github.com/ianheggie/health_check', ref: '0b799ead604f900ed50685e9b2d469cd2befba5b'
|
gem 'health_check', git: 'https://github.com/ianheggie/health_check', ref: '0b799ead604f900ed50685e9b2d469cd2befba5b'
|
||||||
gem 'htmlentities', '~> 4.3'
|
gem 'htmlentities', '~> 4.3'
|
||||||
gem 'http', '~> 4.4'
|
gem 'http', '~> 4.4'
|
||||||
gem 'http_accept_language', '~> 2.1'
|
gem 'http_accept_language', '~> 2.1'
|
||||||
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2', submodules: true
|
|
||||||
gem 'httplog', '~> 1.4.3'
|
gem 'httplog', '~> 1.4.3'
|
||||||
gem 'idn-ruby', require: 'idn'
|
gem 'idn-ruby', require: 'idn'
|
||||||
gem 'kaminari', '~> 1.2'
|
gem 'kaminari', '~> 1.2'
|
||||||
@ -72,8 +69,8 @@ gem 'nsa', '~> 0.2'
|
|||||||
gem 'oj', '~> 3.10'
|
gem 'oj', '~> 3.10'
|
||||||
gem 'ox', '~> 2.13'
|
gem 'ox', '~> 2.13'
|
||||||
gem 'parslet'
|
gem 'parslet'
|
||||||
gem 'parallel', '~> 1.19'
|
gem 'parallel', '~> 1.20'
|
||||||
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
|
gem 'posix-spawn'
|
||||||
gem 'pundit', '~> 2.1'
|
gem 'pundit', '~> 2.1'
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
gem 'rack-attack', '~> 6.3'
|
gem 'rack-attack', '~> 6.3'
|
||||||
@ -85,20 +82,22 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
|||||||
gem 'rqrcode', '~> 1.1'
|
gem 'rqrcode', '~> 1.1'
|
||||||
gem 'ruby-progressbar', '~> 1.10'
|
gem 'ruby-progressbar', '~> 1.10'
|
||||||
gem 'sanitize', '~> 5.2'
|
gem 'sanitize', '~> 5.2'
|
||||||
gem 'sidekiq', '~> 6.0'
|
gem 'scenic', '~> 1.5'
|
||||||
|
gem 'sidekiq', '~> 6.1'
|
||||||
gem 'sidekiq-scheduler', '~> 3.0'
|
gem 'sidekiq-scheduler', '~> 3.0'
|
||||||
gem 'sidekiq-unique-jobs', '~> 6.0'
|
gem 'sidekiq-unique-jobs', '~> 6.0'
|
||||||
gem 'sidekiq-bulk', '~>0.2.0'
|
gem 'sidekiq-bulk', '~>0.2.0'
|
||||||
gem 'simple-navigation', '~> 4.1'
|
gem 'simple-navigation', '~> 4.1'
|
||||||
gem 'simple_form', '~> 5.0'
|
gem 'simple_form', '~> 5.0'
|
||||||
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
|
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
|
||||||
gem 'stoplight', '~> 2.2.0'
|
gem 'stoplight', '~> 2.2.1'
|
||||||
gem 'strong_migrations', '~> 0.6'
|
gem 'strong_migrations', '~> 0.7'
|
||||||
gem 'tty-prompt', '~> 0.21', require: false
|
gem 'tty-prompt', '~> 0.22', require: false
|
||||||
gem 'twitter-text', '~> 1.14'
|
gem 'twitter-text', '~> 1.14'
|
||||||
gem 'tzinfo-data', '~> 1.2020'
|
gem 'tzinfo-data', '~> 1.2020'
|
||||||
gem 'webpacker', '~> 5.1'
|
gem 'webpacker', '~> 5.2'
|
||||||
gem 'webpush'
|
gem 'webpush'
|
||||||
|
gem 'webauthn', '~> 3.0.0.alpha1'
|
||||||
|
|
||||||
gem 'json-ld'
|
gem 'json-ld'
|
||||||
gem 'json-ld-preloaded', '~> 3.1'
|
gem 'json-ld-preloaded', '~> 3.1'
|
||||||
@ -120,33 +119,33 @@ end
|
|||||||
group :test do
|
group :test do
|
||||||
gem 'capybara', '~> 3.33'
|
gem 'capybara', '~> 3.33'
|
||||||
gem 'climate_control', '~> 0.2'
|
gem 'climate_control', '~> 0.2'
|
||||||
gem 'faker', '~> 2.13'
|
gem 'faker', '~> 2.14'
|
||||||
gem 'microformats', '~> 4.2'
|
gem 'microformats', '~> 4.2'
|
||||||
gem 'rails-controller-testing', '~> 1.0'
|
gem 'rails-controller-testing', '~> 1.0'
|
||||||
gem 'rspec-sidekiq', '~> 3.1'
|
gem 'rspec-sidekiq', '~> 3.1'
|
||||||
gem 'simplecov', '~> 0.18', require: false
|
gem 'simplecov', '~> 0.19', require: false
|
||||||
gem 'webmock', '~> 3.8'
|
gem 'webmock', '~> 3.10'
|
||||||
gem 'parallel_tests', '~> 3.0'
|
gem 'parallel_tests', '~> 3.4'
|
||||||
gem 'rspec_junit_formatter', '~> 0.4'
|
gem 'rspec_junit_formatter', '~> 0.4'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'active_record_query_trace', '~> 1.7'
|
gem 'active_record_query_trace', '~> 1.8'
|
||||||
gem 'annotate', '~> 3.1'
|
gem 'annotate', '~> 3.1'
|
||||||
gem 'better_errors', '~> 2.7'
|
gem 'better_errors', '~> 2.9'
|
||||||
gem 'binding_of_caller', '~> 0.7'
|
gem 'binding_of_caller', '~> 0.7'
|
||||||
gem 'bullet', '~> 6.1'
|
gem 'bullet', '~> 6.1'
|
||||||
gem 'letter_opener', '~> 1.7'
|
gem 'letter_opener', '~> 1.7'
|
||||||
gem 'letter_opener_web', '~> 1.4'
|
gem 'letter_opener_web', '~> 1.4'
|
||||||
gem 'memory_profiler'
|
gem 'memory_profiler'
|
||||||
gem 'rubocop', '~> 0.86', require: false
|
gem 'rubocop', '~> 1.3', require: false
|
||||||
gem 'rubocop-rails', '~> 2.6', require: false
|
gem 'rubocop-rails', '~> 2.8', require: false
|
||||||
gem 'brakeman', '~> 4.8', require: false
|
gem 'brakeman', '~> 4.10', require: false
|
||||||
gem 'bundler-audit', '~> 0.7', require: false
|
gem 'bundler-audit', '~> 0.7', require: false
|
||||||
|
|
||||||
gem 'capistrano', '~> 3.14'
|
gem 'capistrano', '~> 3.14'
|
||||||
gem 'capistrano-rails', '~> 1.5'
|
gem 'capistrano-rails', '~> 1.6'
|
||||||
gem 'capistrano-rbenv', '~> 2.1'
|
gem 'capistrano-rbenv', '~> 2.2'
|
||||||
gem 'capistrano-yarn', '~> 2.0'
|
gem 'capistrano-yarn', '~> 2.0'
|
||||||
|
|
||||||
gem 'stackprof'
|
gem 'stackprof'
|
||||||
@ -159,3 +158,6 @@ end
|
|||||||
|
|
||||||
gem 'concurrent-ruby', require: false
|
gem 'concurrent-ruby', require: false
|
||||||
gem 'connection_pool', require: false
|
gem 'connection_pool', require: false
|
||||||
|
|
||||||
|
gem 'xorcist', '~> 1.1'
|
||||||
|
gem 'pluck_each', '~> 0.1.3'
|
||||||
|
386
Gemfile.lock
386
Gemfile.lock
@ -6,21 +6,6 @@ GIT
|
|||||||
health_check (4.0.0.pre)
|
health_check (4.0.0.pre)
|
||||||
rails (>= 4.0)
|
rails (>= 4.0)
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/rtomayko/posix-spawn
|
|
||||||
revision: 58465d2e213991f8afb13b984854a49fcdcc980c
|
|
||||||
ref: 58465d2e213991f8afb13b984854a49fcdcc980c
|
|
||||||
specs:
|
|
||||||
posix-spawn (0.3.13)
|
|
||||||
|
|
||||||
GIT
|
|
||||||
remote: https://github.com/tmm1/http_parser.rb
|
|
||||||
revision: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
|
|
||||||
ref: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
|
|
||||||
submodules: true
|
|
||||||
specs:
|
|
||||||
http_parser.rb (0.6.1)
|
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/witgo/nilsimsa
|
remote: https://github.com/witgo/nilsimsa
|
||||||
revision: fd184883048b922b176939f851338d0a4971a532
|
revision: fd184883048b922b176939f851338d0a4971a532
|
||||||
@ -31,25 +16,25 @@ GIT
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (5.2.4.3)
|
actioncable (5.2.4.4)
|
||||||
actionpack (= 5.2.4.3)
|
actionpack (= 5.2.4.4)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailer (5.2.4.3)
|
actionmailer (5.2.4.4)
|
||||||
actionpack (= 5.2.4.3)
|
actionpack (= 5.2.4.4)
|
||||||
actionview (= 5.2.4.3)
|
actionview (= 5.2.4.4)
|
||||||
activejob (= 5.2.4.3)
|
activejob (= 5.2.4.4)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (5.2.4.3)
|
actionpack (5.2.4.4)
|
||||||
actionview (= 5.2.4.3)
|
actionview (= 5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
rack (~> 2.0, >= 2.0.8)
|
rack (~> 2.0, >= 2.0.8)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
actionview (5.2.4.3)
|
actionview (5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
@ -59,21 +44,21 @@ GEM
|
|||||||
activemodel (>= 4.1, < 6.1)
|
activemodel (>= 4.1, < 6.1)
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
active_record_query_trace (1.7)
|
active_record_query_trace (1.8)
|
||||||
activejob (5.2.4.3)
|
activejob (5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (5.2.4.3)
|
activemodel (5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
activerecord (5.2.4.3)
|
activerecord (5.2.4.4)
|
||||||
activemodel (= 5.2.4.3)
|
activemodel (= 5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
arel (>= 9.0)
|
arel (>= 9.0)
|
||||||
activestorage (5.2.4.3)
|
activestorage (5.2.4.4)
|
||||||
actionpack (= 5.2.4.3)
|
actionpack (= 5.2.4.4)
|
||||||
activerecord (= 5.2.4.3)
|
activerecord (= 5.2.4.4)
|
||||||
marcel (~> 0.3.1)
|
marcel (~> 0.3.1)
|
||||||
activesupport (5.2.4.3)
|
activesupport (5.2.4.4)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
@ -82,6 +67,7 @@ GEM
|
|||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
airbrussh (1.4.0)
|
airbrussh (1.4.0)
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
sshkit (>= 1.6.1, != 1.7.0)
|
||||||
|
android_key_attestation (0.3.0)
|
||||||
annotate (3.1.1)
|
annotate (3.1.1)
|
||||||
activerecord (>= 3.2, < 7.0)
|
activerecord (>= 3.2, < 7.0)
|
||||||
rake (>= 10.4, < 14.0)
|
rake (>= 10.4, < 14.0)
|
||||||
@ -91,34 +77,36 @@ GEM
|
|||||||
encryptor (~> 3.0.0)
|
encryptor (~> 3.0.0)
|
||||||
av (0.9.0)
|
av (0.9.0)
|
||||||
cocaine (~> 0.5.3)
|
cocaine (~> 0.5.3)
|
||||||
|
awrence (1.1.1)
|
||||||
aws-eventstream (1.1.0)
|
aws-eventstream (1.1.0)
|
||||||
aws-partitions (1.338.0)
|
aws-partitions (1.397.0)
|
||||||
aws-sdk-core (3.103.0)
|
aws-sdk-core (3.109.3)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.239.0)
|
aws-partitions (~> 1, >= 1.239.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-kms (1.36.0)
|
aws-sdk-kms (1.39.0)
|
||||||
aws-sdk-core (~> 3, >= 3.99.0)
|
aws-sdk-core (~> 3, >= 3.109.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.73.0)
|
aws-sdk-s3 (1.85.0)
|
||||||
aws-sdk-core (~> 3, >= 3.102.1)
|
aws-sdk-core (~> 3, >= 3.109.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sigv4 (1.2.1)
|
aws-sigv4 (1.2.2)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
bcrypt (3.1.13)
|
bcrypt (3.1.16)
|
||||||
better_errors (2.7.1)
|
better_errors (2.9.1)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
erubi (>= 1.0.0)
|
erubi (>= 1.0.0)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
|
bindata (2.4.8)
|
||||||
binding_of_caller (0.8.0)
|
binding_of_caller (0.8.0)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
blurhash (0.1.4)
|
blurhash (0.1.4)
|
||||||
ffi (~> 1.10.0)
|
ffi (~> 1.10.0)
|
||||||
bootsnap (1.4.6)
|
bootsnap (1.5.1)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
brakeman (4.8.2)
|
brakeman (4.10.0)
|
||||||
browser (4.2.0)
|
browser (4.2.0)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
bullet (6.1.0)
|
bullet (6.1.0)
|
||||||
@ -133,12 +121,12 @@ GEM
|
|||||||
i18n
|
i18n
|
||||||
rake (>= 10.0.0)
|
rake (>= 10.0.0)
|
||||||
sshkit (>= 1.9.0)
|
sshkit (>= 1.9.0)
|
||||||
capistrano-bundler (1.6.0)
|
capistrano-bundler (2.0.1)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-rails (1.5.0)
|
capistrano-rails (1.6.1)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-bundler (~> 1.1)
|
capistrano-bundler (>= 1.1, < 3)
|
||||||
capistrano-rbenv (2.1.6)
|
capistrano-rbenv (2.2.0)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
sshkit (~> 1.3)
|
sshkit (~> 1.3)
|
||||||
capistrano-yarn (2.0.2)
|
capistrano-yarn (2.0.2)
|
||||||
@ -153,12 +141,13 @@ GEM
|
|||||||
xpath (~> 3.2)
|
xpath (~> 3.2)
|
||||||
case_transform (0.2)
|
case_transform (0.2)
|
||||||
activesupport
|
activesupport
|
||||||
|
cbor (0.5.9.6)
|
||||||
charlock_holmes (0.7.7)
|
charlock_holmes (0.7.7)
|
||||||
chewy (5.1.0)
|
chewy (5.1.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
elasticsearch (>= 2.0.0)
|
elasticsearch (>= 2.0.0)
|
||||||
elasticsearch-dsl
|
elasticsearch-dsl
|
||||||
chunky_png (1.3.11)
|
chunky_png (1.3.12)
|
||||||
cld3 (3.3.0)
|
cld3 (3.3.0)
|
||||||
ffi (>= 1.1.0, < 1.12.0)
|
ffi (>= 1.1.0, < 1.12.0)
|
||||||
climate_control (0.2.0)
|
climate_control (0.2.0)
|
||||||
@ -166,15 +155,17 @@ GEM
|
|||||||
climate_control (>= 0.0.3, < 1.0)
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
color_diff (0.1)
|
color_diff (0.1)
|
||||||
concurrent-ruby (1.1.6)
|
concurrent-ruby (1.1.7)
|
||||||
connection_pool (2.2.3)
|
connection_pool (2.2.3)
|
||||||
crack (0.4.3)
|
cose (1.0.0)
|
||||||
safe_yaml (~> 1.0.0)
|
cbor (~> 0.5.9)
|
||||||
|
openssl-signature_algorithm (~> 0.4.0)
|
||||||
|
crack (0.4.4)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
css_parser (1.7.1)
|
css_parser (1.7.1)
|
||||||
addressable
|
addressable
|
||||||
debug_inspector (0.0.3)
|
debug_inspector (0.0.3)
|
||||||
devise (4.7.2)
|
devise (4.7.3)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
@ -197,34 +188,33 @@ GEM
|
|||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
doorkeeper (5.4.0)
|
doorkeeper (5.4.0)
|
||||||
railties (>= 5)
|
railties (>= 5)
|
||||||
dotenv (2.7.5)
|
dotenv (2.7.6)
|
||||||
dotenv-rails (2.7.5)
|
dotenv-rails (2.7.6)
|
||||||
dotenv (= 2.7.5)
|
dotenv (= 2.7.6)
|
||||||
railties (>= 3.2, < 6.1)
|
railties (>= 3.2)
|
||||||
e2mmap (0.1.0)
|
e2mmap (0.1.0)
|
||||||
ed25519 (1.2.4)
|
ed25519 (1.2.4)
|
||||||
elasticsearch (7.8.0)
|
elasticsearch (7.9.0)
|
||||||
elasticsearch-api (= 7.8.0)
|
elasticsearch-api (= 7.9.0)
|
||||||
elasticsearch-transport (= 7.8.0)
|
elasticsearch-transport (= 7.9.0)
|
||||||
elasticsearch-api (7.8.0)
|
elasticsearch-api (7.9.0)
|
||||||
multi_json
|
multi_json
|
||||||
elasticsearch-dsl (0.1.9)
|
elasticsearch-dsl (0.1.9)
|
||||||
elasticsearch-transport (7.8.0)
|
elasticsearch-transport (7.9.0)
|
||||||
faraday (~> 1)
|
faraday (~> 1)
|
||||||
multi_json
|
multi_json
|
||||||
encryptor (3.0.0)
|
encryptor (3.0.0)
|
||||||
equatable (0.6.1)
|
|
||||||
erubi (1.9.0)
|
erubi (1.9.0)
|
||||||
et-orbi (1.2.4)
|
et-orbi (1.2.4)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.75.0)
|
excon (0.76.0)
|
||||||
fabrication (2.21.1)
|
fabrication (2.21.1)
|
||||||
faker (2.13.0)
|
faker (2.14.0)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
faraday (1.0.1)
|
faraday (1.0.1)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
fast_blank (1.0.0)
|
fast_blank (1.0.0)
|
||||||
fastimage (2.1.7)
|
fastimage (2.2.0)
|
||||||
ffi (1.10.0)
|
ffi (1.10.0)
|
||||||
ffi-compiler (1.0.1)
|
ffi-compiler (1.0.1)
|
||||||
ffi (>= 1.0.0)
|
ffi (>= 1.0.0)
|
||||||
@ -242,7 +232,7 @@ GEM
|
|||||||
fog-json (>= 1.0)
|
fog-json (>= 1.0)
|
||||||
ipaddress (>= 0.8)
|
ipaddress (>= 0.8)
|
||||||
formatador (0.2.5)
|
formatador (0.2.5)
|
||||||
fugit (1.3.6)
|
fugit (1.3.9)
|
||||||
et-orbi (~> 1.1, >= 1.1.8)
|
et-orbi (~> 1.1, >= 1.1.8)
|
||||||
raabro (~> 1.3)
|
raabro (~> 1.3)
|
||||||
fuubar (2.5.0)
|
fuubar (2.5.0)
|
||||||
@ -250,7 +240,7 @@ GEM
|
|||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.4)
|
||||||
globalid (0.4.2)
|
globalid (0.4.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
hamlit (2.11.0)
|
hamlit (2.13.0)
|
||||||
temple (>= 0.8.2)
|
temple (>= 0.8.2)
|
||||||
thor
|
thor
|
||||||
tilt
|
tilt
|
||||||
@ -281,7 +271,7 @@ GEM
|
|||||||
httplog (1.4.3)
|
httplog (1.4.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.8.3)
|
i18n (1.8.5)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (0.9.31)
|
i18n-tasks (0.9.31)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
@ -299,7 +289,7 @@ GEM
|
|||||||
jmespath (1.4.0)
|
jmespath (1.4.0)
|
||||||
json (2.3.1)
|
json (2.3.1)
|
||||||
json-canonicalization (0.2.0)
|
json-canonicalization (0.2.0)
|
||||||
json-ld (3.1.4)
|
json-ld (3.1.5)
|
||||||
htmlentities (~> 4.3)
|
htmlentities (~> 4.3)
|
||||||
json-canonicalization (~> 0.2)
|
json-canonicalization (~> 0.2)
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
@ -310,7 +300,7 @@ GEM
|
|||||||
json-ld (~> 3.1)
|
json-ld (~> 3.1)
|
||||||
rdf (~> 3.1)
|
rdf (~> 3.1)
|
||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
jwt (2.2.1)
|
jwt (2.2.2)
|
||||||
kaminari (1.2.1)
|
kaminari (1.2.1)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
kaminari-actionview (= 1.2.1)
|
kaminari-actionview (= 1.2.1)
|
||||||
@ -337,7 +327,7 @@ GEM
|
|||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.6.0)
|
loofah (2.7.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
@ -350,7 +340,7 @@ GEM
|
|||||||
redis (>= 3.0.5)
|
redis (>= 3.0.5)
|
||||||
memory_profiler (0.9.14)
|
memory_profiler (0.9.14)
|
||||||
method_source (1.0.0)
|
method_source (1.0.0)
|
||||||
microformats (4.2.0)
|
microformats (4.2.1)
|
||||||
json (~> 2.2)
|
json (~> 2.2)
|
||||||
nokogiri (~> 1.10)
|
nokogiri (~> 1.10)
|
||||||
mime-types (3.3.1)
|
mime-types (3.3.1)
|
||||||
@ -359,17 +349,16 @@ GEM
|
|||||||
mimemagic (0.3.5)
|
mimemagic (0.3.5)
|
||||||
mini_mime (1.0.2)
|
mini_mime (1.0.2)
|
||||||
mini_portile2 (2.4.0)
|
mini_portile2 (2.4.0)
|
||||||
minitest (5.14.1)
|
minitest (5.14.2)
|
||||||
msgpack (1.3.3)
|
msgpack (1.3.3)
|
||||||
multi_json (1.14.1)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
necromancer (0.5.1)
|
net-ldap (0.16.3)
|
||||||
net-ldap (0.16.2)
|
|
||||||
net-scp (3.0.0)
|
net-scp (3.0.0)
|
||||||
net-ssh (>= 2.6.5, < 7.0.0)
|
net-ssh (>= 2.6.5, < 7.0.0)
|
||||||
net-ssh (6.1.0)
|
net-ssh (6.1.0)
|
||||||
nio4r (2.5.2)
|
nio4r (2.5.4)
|
||||||
nokogiri (1.10.9)
|
nokogiri (1.10.10)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
nokogumbo (2.0.2)
|
nokogumbo (2.0.2)
|
||||||
nokogiri (~> 1.8, >= 1.8.4)
|
nokogiri (~> 1.8, >= 1.8.4)
|
||||||
@ -378,19 +367,24 @@ GEM
|
|||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
sidekiq (>= 3.5)
|
sidekiq (>= 3.5)
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.10.6)
|
oj (3.10.16)
|
||||||
omniauth (1.9.1)
|
omniauth (1.9.1)
|
||||||
hashie (>= 3.4.6)
|
hashie (>= 3.4.6)
|
||||||
rack (>= 1.6.2, < 3)
|
rack (>= 1.6.2, < 3)
|
||||||
omniauth-cas (1.1.1)
|
omniauth-cas (2.0.0)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
nokogiri (~> 1.5)
|
nokogiri (~> 1.5)
|
||||||
omniauth (~> 1.2)
|
omniauth (~> 1.2)
|
||||||
omniauth-saml (1.10.2)
|
omniauth-rails_csrf_protection (0.1.2)
|
||||||
|
actionpack (>= 4.2)
|
||||||
|
omniauth (>= 1.3.1)
|
||||||
|
omniauth-saml (1.10.3)
|
||||||
omniauth (~> 1.3, >= 1.3.2)
|
omniauth (~> 1.3, >= 1.3.2)
|
||||||
ruby-saml (~> 1.9)
|
ruby-saml (~> 1.9)
|
||||||
|
openssl (2.2.0)
|
||||||
|
openssl-signature_algorithm (0.4.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ox (2.13.2)
|
ox (2.13.4)
|
||||||
paperclip (6.0.0)
|
paperclip (6.0.0)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 4.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
@ -400,20 +394,23 @@ GEM
|
|||||||
paperclip-av-transcoder (0.6.4)
|
paperclip-av-transcoder (0.6.4)
|
||||||
av (~> 0.9.0)
|
av (~> 0.9.0)
|
||||||
paperclip (>= 2.5.2)
|
paperclip (>= 2.5.2)
|
||||||
parallel (1.19.2)
|
parallel (1.20.1)
|
||||||
parallel_tests (3.0.0)
|
parallel_tests (3.4.0)
|
||||||
parallel
|
parallel
|
||||||
parser (2.7.1.4)
|
parser (2.7.2.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
pastel (0.7.4)
|
pastel (0.8.0)
|
||||||
equatable (~> 0.6)
|
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
pg (1.2.3)
|
pg (1.2.3)
|
||||||
pghero (2.5.1)
|
pghero (2.7.2)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
pkg-config (1.4.1)
|
pkg-config (1.4.4)
|
||||||
premailer (1.11.1)
|
pluck_each (0.1.3)
|
||||||
|
activerecord (> 3.2.0)
|
||||||
|
activesupport (> 3.0.0)
|
||||||
|
posix-spawn (0.3.15)
|
||||||
|
premailer (1.14.2)
|
||||||
addressable
|
addressable
|
||||||
css_parser (>= 1.6.0)
|
css_parser (>= 1.6.0)
|
||||||
htmlentities (>= 4.0.0)
|
htmlentities (>= 4.0.0)
|
||||||
@ -429,12 +426,12 @@ GEM
|
|||||||
pry (~> 0.13.0)
|
pry (~> 0.13.0)
|
||||||
pry-rails (0.3.9)
|
pry-rails (0.3.9)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.10.4)
|
||||||
public_suffix (4.0.5)
|
public_suffix (4.0.6)
|
||||||
puma (4.3.5)
|
puma (5.0.4)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.1.0)
|
pundit (2.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.3.1)
|
raabro (1.3.3)
|
||||||
rack (2.2.3)
|
rack (2.2.3)
|
||||||
rack-attack (6.3.1)
|
rack-attack (6.3.1)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
@ -444,18 +441,18 @@ GEM
|
|||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (5.2.4.3)
|
rails (5.2.4.4)
|
||||||
actioncable (= 5.2.4.3)
|
actioncable (= 5.2.4.4)
|
||||||
actionmailer (= 5.2.4.3)
|
actionmailer (= 5.2.4.4)
|
||||||
actionpack (= 5.2.4.3)
|
actionpack (= 5.2.4.4)
|
||||||
actionview (= 5.2.4.3)
|
actionview (= 5.2.4.4)
|
||||||
activejob (= 5.2.4.3)
|
activejob (= 5.2.4.4)
|
||||||
activemodel (= 5.2.4.3)
|
activemodel (= 5.2.4.4)
|
||||||
activerecord (= 5.2.4.3)
|
activerecord (= 5.2.4.4)
|
||||||
activestorage (= 5.2.4.3)
|
activestorage (= 5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
bundler (>= 1.3.0)
|
bundler (>= 1.3.0)
|
||||||
railties (= 5.2.4.3)
|
railties (= 5.2.4.4)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
@ -471,20 +468,20 @@ GEM
|
|||||||
railties (>= 5.0, < 6)
|
railties (>= 5.0, < 6)
|
||||||
rails-settings-cached (0.6.6)
|
rails-settings-cached (0.6.6)
|
||||||
rails (>= 4.2.0)
|
rails (>= 4.2.0)
|
||||||
railties (5.2.4.3)
|
railties (5.2.4.4)
|
||||||
actionpack (= 5.2.4.3)
|
actionpack (= 5.2.4.4)
|
||||||
activesupport (= 5.2.4.3)
|
activesupport (= 5.2.4.4)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.19.0, < 2.0)
|
thor (>= 0.19.0, < 2.0)
|
||||||
rainbow (3.0.0)
|
rainbow (3.0.0)
|
||||||
rake (13.0.1)
|
rake (13.0.1)
|
||||||
rdf (3.1.4)
|
rdf (3.1.7)
|
||||||
hamster (~> 3.0)
|
hamster (~> 3.0)
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
rdf-normalize (0.4.0)
|
rdf-normalize (0.4.0)
|
||||||
rdf (~> 3.1)
|
rdf (~> 3.1)
|
||||||
redis (4.2.1)
|
redis (4.2.5)
|
||||||
redis-actionpack (5.2.0)
|
redis-actionpack (5.2.0)
|
||||||
actionpack (>= 5, < 7)
|
actionpack (>= 5, < 7)
|
||||||
redis-rack (>= 2.1.0, < 3)
|
redis-rack (>= 2.1.0, < 3)
|
||||||
@ -492,9 +489,9 @@ GEM
|
|||||||
redis-activesupport (5.2.0)
|
redis-activesupport (5.2.0)
|
||||||
activesupport (>= 3, < 7)
|
activesupport (>= 3, < 7)
|
||||||
redis-store (>= 1.3, < 2)
|
redis-store (>= 1.3, < 2)
|
||||||
redis-namespace (1.7.0)
|
redis-namespace (1.8.0)
|
||||||
redis (>= 3.0.4)
|
redis (>= 3.0.4)
|
||||||
redis-rack (2.1.2)
|
redis-rack (2.1.3)
|
||||||
rack (>= 2.0.8, < 3)
|
rack (>= 2.0.8, < 3)
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-rails (5.0.2)
|
redis-rails (5.0.2)
|
||||||
@ -503,7 +500,7 @@ GEM
|
|||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-store (1.9.0)
|
redis-store (1.9.0)
|
||||||
redis (>= 4, < 5)
|
redis (>= 4, < 5)
|
||||||
regexp_parser (1.7.1)
|
regexp_parser (1.8.2)
|
||||||
request_store (1.5.0)
|
request_store (1.5.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.0.1)
|
responders (3.0.1)
|
||||||
@ -516,7 +513,7 @@ GEM
|
|||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rqrcode_core (~> 0.1)
|
rqrcode_core (~> 0.1)
|
||||||
rqrcode_core (0.1.2)
|
rqrcode_core (0.1.2)
|
||||||
rspec-core (3.9.2)
|
rspec-core (3.9.3)
|
||||||
rspec-support (~> 3.9.3)
|
rspec-support (~> 3.9.3)
|
||||||
rspec-expectations (3.9.2)
|
rspec-expectations (3.9.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
@ -538,33 +535,38 @@ GEM
|
|||||||
rspec-support (3.9.3)
|
rspec-support (3.9.3)
|
||||||
rspec_junit_formatter (0.4.1)
|
rspec_junit_formatter (0.4.1)
|
||||||
rspec-core (>= 2, < 4, != 2.12.0)
|
rspec-core (>= 2, < 4, != 2.12.0)
|
||||||
rubocop (0.86.0)
|
rubocop (1.3.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.7.0.1)
|
parser (>= 2.7.1.5)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.7)
|
regexp_parser (>= 1.8)
|
||||||
rexml
|
rexml
|
||||||
rubocop-ast (>= 0.0.3, < 1.0)
|
rubocop-ast (>= 1.1.1)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 2.0)
|
unicode-display_width (>= 1.4.0, < 2.0)
|
||||||
rubocop-ast (0.1.0)
|
rubocop-ast (1.1.1)
|
||||||
parser (>= 2.7.0.1)
|
parser (>= 2.7.1.5)
|
||||||
rubocop-rails (2.6.0)
|
rubocop-rails (2.8.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 0.82.0)
|
rubocop (>= 0.87.0)
|
||||||
ruby-progressbar (1.10.1)
|
ruby-progressbar (1.10.1)
|
||||||
ruby-saml (1.11.0)
|
ruby-saml (1.11.0)
|
||||||
nokogiri (>= 1.5.10)
|
nokogiri (>= 1.5.10)
|
||||||
rufus-scheduler (3.6.0)
|
rufus-scheduler (3.6.0)
|
||||||
fugit (~> 1.1, >= 1.1.6)
|
fugit (~> 1.1, >= 1.1.6)
|
||||||
safe_yaml (1.0.5)
|
safety_net_attestation (0.4.0)
|
||||||
|
jwt (~> 2.0)
|
||||||
sanitize (5.2.1)
|
sanitize (5.2.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.8.0)
|
nokogiri (>= 1.8.0)
|
||||||
nokogumbo (~> 2.0)
|
nokogumbo (~> 2.0)
|
||||||
|
scenic (1.5.4)
|
||||||
|
activerecord (>= 4.0.0)
|
||||||
|
railties (>= 4.0.0)
|
||||||
|
securecompare (1.0.0)
|
||||||
semantic_range (2.3.0)
|
semantic_range (2.3.0)
|
||||||
sidekiq (6.1.0)
|
sidekiq (6.1.2)
|
||||||
connection_pool (>= 2.2.2)
|
connection_pool (>= 2.2.2)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
redis (>= 4.2.0)
|
redis (>= 4.2.0)
|
||||||
@ -577,74 +579,87 @@ GEM
|
|||||||
sidekiq (>= 3)
|
sidekiq (>= 3)
|
||||||
thwait
|
thwait
|
||||||
tilt (>= 1.4.0)
|
tilt (>= 1.4.0)
|
||||||
sidekiq-unique-jobs (6.0.22)
|
sidekiq-unique-jobs (6.0.25)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
sidekiq (>= 4.0, < 7.0)
|
sidekiq (>= 4.0, < 7.0)
|
||||||
thor (~> 0)
|
thor (>= 0.20, < 2.0)
|
||||||
simple-navigation (4.1.0)
|
simple-navigation (4.1.0)
|
||||||
activesupport (>= 2.3.2)
|
activesupport (>= 2.3.2)
|
||||||
simple_form (5.0.2)
|
simple_form (5.0.3)
|
||||||
actionpack (>= 5.0)
|
actionpack (>= 5.0)
|
||||||
activemodel (>= 5.0)
|
activemodel (>= 5.0)
|
||||||
simplecov (0.18.5)
|
simplecov (0.19.1)
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov-html (0.12.2)
|
simplecov-html (0.12.3)
|
||||||
sprockets (3.7.2)
|
sprockets (3.7.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (> 1, < 3)
|
rack (> 1, < 3)
|
||||||
sprockets-rails (3.2.1)
|
sprockets-rails (3.2.2)
|
||||||
actionpack (>= 4.0)
|
actionpack (>= 4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sshkit (1.21.0)
|
sshkit (1.21.0)
|
||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
stackprof (0.2.15)
|
stackprof (0.2.16)
|
||||||
statsd-ruby (1.4.0)
|
statsd-ruby (1.4.0)
|
||||||
stoplight (2.2.0)
|
stoplight (2.2.1)
|
||||||
streamio-ffmpeg (3.0.2)
|
streamio-ffmpeg (3.0.2)
|
||||||
multi_json (~> 1.8)
|
multi_json (~> 1.8)
|
||||||
strong_migrations (0.6.8)
|
strong_migrations (0.7.2)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
temple (0.8.2)
|
temple (0.8.2)
|
||||||
terminal-table (1.8.0)
|
terminal-table (1.8.0)
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
terrapin (0.6.0)
|
terrapin (0.6.0)
|
||||||
climate_control (>= 0.0.3, < 1.0)
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
thor (0.20.3)
|
thor (1.0.1)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
thwait (0.1.0)
|
thwait (0.2.0)
|
||||||
|
e2mmap
|
||||||
tilt (2.0.10)
|
tilt (2.0.10)
|
||||||
tty-color (0.5.1)
|
tpm-key_attestation (0.9.0)
|
||||||
|
bindata (~> 2.4)
|
||||||
|
openssl-signature_algorithm (~> 0.4.0)
|
||||||
|
tty-color (0.5.2)
|
||||||
tty-cursor (0.7.1)
|
tty-cursor (0.7.1)
|
||||||
tty-prompt (0.21.0)
|
tty-prompt (0.22.0)
|
||||||
necromancer (~> 0.5.0)
|
pastel (~> 0.8)
|
||||||
pastel (~> 0.7.0)
|
tty-reader (~> 0.8)
|
||||||
tty-reader (~> 0.7.0)
|
tty-reader (0.8.0)
|
||||||
tty-reader (0.7.0)
|
|
||||||
tty-cursor (~> 0.7)
|
tty-cursor (~> 0.7)
|
||||||
tty-screen (~> 0.7)
|
tty-screen (~> 0.8)
|
||||||
wisper (~> 2.0.0)
|
wisper (~> 2.0)
|
||||||
tty-screen (0.8.0)
|
tty-screen (0.8.1)
|
||||||
twitter-text (1.14.7)
|
twitter-text (1.14.7)
|
||||||
unf (~> 0.1.0)
|
unf (~> 0.1.0)
|
||||||
tzinfo (1.2.7)
|
tzinfo (1.2.7)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
tzinfo-data (1.2020.1)
|
tzinfo-data (1.2020.4)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.7)
|
unf_ext (0.0.7.7)
|
||||||
unicode-display_width (1.7.0)
|
unicode-display_width (1.7.0)
|
||||||
uniform_notifier (1.13.0)
|
uniform_notifier (1.13.0)
|
||||||
warden (1.2.8)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.6)
|
rack (>= 2.0.9)
|
||||||
webmock (3.8.3)
|
webauthn (3.0.0.alpha1)
|
||||||
|
android_key_attestation (~> 0.3.0)
|
||||||
|
awrence (~> 1.1)
|
||||||
|
bindata (~> 2.4)
|
||||||
|
cbor (~> 0.5.9)
|
||||||
|
cose (~> 1.0)
|
||||||
|
openssl (~> 2.0)
|
||||||
|
safety_net_attestation (~> 0.4.0)
|
||||||
|
securecompare (~> 1.0)
|
||||||
|
tpm-key_attestation (~> 0.9.0)
|
||||||
|
webmock (3.10.0)
|
||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
webpacker (5.1.1)
|
webpacker (5.2.1)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
rack-proxy (>= 0.6.1)
|
rack-proxy (>= 0.6.1)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
@ -652,10 +667,11 @@ GEM
|
|||||||
webpush (0.3.8)
|
webpush (0.3.8)
|
||||||
hkdf (~> 0.2)
|
hkdf (~> 0.2)
|
||||||
jwt (~> 2.0)
|
jwt (~> 2.0)
|
||||||
websocket-driver (0.7.2)
|
websocket-driver (0.7.3)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
wisper (2.0.1)
|
wisper (2.0.1)
|
||||||
|
xorcist (1.1.2)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
|
|
||||||
@ -664,21 +680,21 @@ PLATFORMS
|
|||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_model_serializers (~> 0.10)
|
active_model_serializers (~> 0.10)
|
||||||
active_record_query_trace (~> 1.7)
|
active_record_query_trace (~> 1.8)
|
||||||
addressable (~> 2.7)
|
addressable (~> 2.7)
|
||||||
annotate (~> 3.1)
|
annotate (~> 3.1)
|
||||||
aws-sdk-s3 (~> 1.73)
|
aws-sdk-s3 (~> 1.85)
|
||||||
better_errors (~> 2.7)
|
better_errors (~> 2.9)
|
||||||
binding_of_caller (~> 0.7)
|
binding_of_caller (~> 0.7)
|
||||||
blurhash (~> 0.1)
|
blurhash (~> 0.1)
|
||||||
bootsnap (~> 1.4)
|
bootsnap (~> 1.5)
|
||||||
brakeman (~> 4.8)
|
brakeman (~> 4.10)
|
||||||
browser
|
browser
|
||||||
bullet (~> 6.1)
|
bullet (~> 6.1)
|
||||||
bundler-audit (~> 0.7)
|
bundler-audit (~> 0.7)
|
||||||
capistrano (~> 3.14)
|
capistrano (~> 3.14)
|
||||||
capistrano-rails (~> 1.5)
|
capistrano-rails (~> 1.6)
|
||||||
capistrano-rbenv (~> 2.1)
|
capistrano-rbenv (~> 2.2)
|
||||||
capistrano-yarn (~> 2.0)
|
capistrano-yarn (~> 2.0)
|
||||||
capybara (~> 3.33)
|
capybara (~> 3.33)
|
||||||
charlock_holmes (~> 0.7.7)
|
charlock_holmes (~> 0.7.7)
|
||||||
@ -694,10 +710,9 @@ DEPENDENCIES
|
|||||||
discard (~> 1.2)
|
discard (~> 1.2)
|
||||||
doorkeeper (~> 5.4)
|
doorkeeper (~> 5.4)
|
||||||
dotenv-rails (~> 2.7)
|
dotenv-rails (~> 2.7)
|
||||||
e2mmap (~> 0.1.0)
|
|
||||||
ed25519 (~> 1.2)
|
ed25519 (~> 1.2)
|
||||||
fabrication (~> 2.21)
|
fabrication (~> 2.21)
|
||||||
faker (~> 2.13)
|
faker (~> 2.14)
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fastimage
|
fastimage
|
||||||
fog-core (<= 2.1.0)
|
fog-core (<= 2.1.0)
|
||||||
@ -709,7 +724,6 @@ DEPENDENCIES
|
|||||||
htmlentities (~> 4.3)
|
htmlentities (~> 4.3)
|
||||||
http (~> 4.4)
|
http (~> 4.4)
|
||||||
http_accept_language (~> 2.1)
|
http_accept_language (~> 2.1)
|
||||||
http_parser.rb (~> 0.6)!
|
|
||||||
httplog (~> 1.4.3)
|
httplog (~> 1.4.3)
|
||||||
i18n-tasks (~> 0.9)
|
i18n-tasks (~> 0.9)
|
||||||
idn-ruby
|
idn-ruby
|
||||||
@ -732,61 +746,65 @@ DEPENDENCIES
|
|||||||
nsa (~> 0.2)
|
nsa (~> 0.2)
|
||||||
oj (~> 3.10)
|
oj (~> 3.10)
|
||||||
omniauth (~> 1.9)
|
omniauth (~> 1.9)
|
||||||
omniauth-cas (~> 1.1)
|
omniauth-cas (~> 2.0)
|
||||||
|
omniauth-rails_csrf_protection (~> 0.1)
|
||||||
omniauth-saml (~> 1.10)
|
omniauth-saml (~> 1.10)
|
||||||
ox (~> 2.13)
|
ox (~> 2.13)
|
||||||
paperclip (~> 6.0)
|
paperclip (~> 6.0)
|
||||||
paperclip-av-transcoder (~> 0.6)
|
paperclip-av-transcoder (~> 0.6)
|
||||||
parallel (~> 1.19)
|
parallel (~> 1.20)
|
||||||
parallel_tests (~> 3.0)
|
parallel_tests (~> 3.4)
|
||||||
parslet
|
parslet
|
||||||
pg (~> 1.2)
|
pg (~> 1.2)
|
||||||
pghero (~> 2.5)
|
pghero (~> 2.7)
|
||||||
pkg-config (~> 1.4)
|
pkg-config (~> 1.4)
|
||||||
posix-spawn!
|
pluck_each (~> 0.1.3)
|
||||||
|
posix-spawn
|
||||||
premailer-rails
|
premailer-rails
|
||||||
private_address_check (~> 0.5)
|
private_address_check (~> 0.5)
|
||||||
pry-byebug (~> 3.9)
|
pry-byebug (~> 3.9)
|
||||||
pry-rails (~> 0.3)
|
pry-rails (~> 0.3)
|
||||||
puma (~> 4.3)
|
puma (~> 5.0)
|
||||||
pundit (~> 2.1)
|
pundit (~> 2.1)
|
||||||
rack (~> 2.2.3)
|
rack (~> 2.2.3)
|
||||||
rack-attack (~> 6.3)
|
rack-attack (~> 6.3)
|
||||||
rack-cors (~> 1.1)
|
rack-cors (~> 1.1)
|
||||||
rails (~> 5.2.4.3)
|
rails (~> 5.2.4.4)
|
||||||
rails-controller-testing (~> 1.0)
|
rails-controller-testing (~> 1.0)
|
||||||
rails-i18n (~> 5.1)
|
rails-i18n (~> 5.1)
|
||||||
rails-settings-cached (~> 0.6)
|
rails-settings-cached (~> 0.6)
|
||||||
rdf-normalize (~> 0.4)
|
rdf-normalize (~> 0.4)
|
||||||
redis (~> 4.2)
|
redis (~> 4.2)
|
||||||
redis-namespace (~> 1.7)
|
redis-namespace (~> 1.8)
|
||||||
redis-rails (~> 5.0)
|
redis-rails (~> 5.0)
|
||||||
rqrcode (~> 1.1)
|
rqrcode (~> 1.1)
|
||||||
rspec-rails (~> 4.0)
|
rspec-rails (~> 4.0)
|
||||||
rspec-sidekiq (~> 3.1)
|
rspec-sidekiq (~> 3.1)
|
||||||
rspec_junit_formatter (~> 0.4)
|
rspec_junit_formatter (~> 0.4)
|
||||||
rubocop (~> 0.86)
|
rubocop (~> 1.3)
|
||||||
rubocop-rails (~> 2.6)
|
rubocop-rails (~> 2.8)
|
||||||
ruby-progressbar (~> 1.10)
|
ruby-progressbar (~> 1.10)
|
||||||
sanitize (~> 5.2)
|
sanitize (~> 5.2)
|
||||||
sidekiq (~> 6.0)
|
scenic (~> 1.5)
|
||||||
|
sidekiq (~> 6.1)
|
||||||
sidekiq-bulk (~> 0.2.0)
|
sidekiq-bulk (~> 0.2.0)
|
||||||
sidekiq-scheduler (~> 3.0)
|
sidekiq-scheduler (~> 3.0)
|
||||||
sidekiq-unique-jobs (~> 6.0)
|
sidekiq-unique-jobs (~> 6.0)
|
||||||
simple-navigation (~> 4.1)
|
simple-navigation (~> 4.1)
|
||||||
simple_form (~> 5.0)
|
simple_form (~> 5.0)
|
||||||
simplecov (~> 0.18)
|
simplecov (~> 0.19)
|
||||||
sprockets (~> 3.7.2)
|
sprockets (~> 3.7.2)
|
||||||
sprockets-rails (~> 3.2)
|
sprockets-rails (~> 3.2)
|
||||||
stackprof
|
stackprof
|
||||||
stoplight (~> 2.2.0)
|
stoplight (~> 2.2.1)
|
||||||
streamio-ffmpeg (~> 3.0)
|
streamio-ffmpeg (~> 3.0)
|
||||||
strong_migrations (~> 0.6)
|
strong_migrations (~> 0.7)
|
||||||
thor (~> 0.20)
|
thor (~> 1.0)
|
||||||
thwait (~> 0.1.0)
|
tty-prompt (~> 0.22)
|
||||||
tty-prompt (~> 0.21)
|
|
||||||
twitter-text (~> 1.14)
|
twitter-text (~> 1.14)
|
||||||
tzinfo-data (~> 1.2020)
|
tzinfo-data (~> 1.2020)
|
||||||
webmock (~> 3.8)
|
webauthn (~> 3.0.0.alpha1)
|
||||||
webpacker (~> 5.1)
|
webmock (~> 3.10)
|
||||||
|
webpacker (~> 5.2)
|
||||||
webpush
|
webpush
|
||||||
|
xorcist (~> 1.1)
|
||||||
|
2
Procfile
2
Procfile
@ -1,4 +1,4 @@
|
|||||||
web: if [ "$RUN_STREAMING" != "true" ]; then BIND=0.0.0.0 bundle exec puma -C config/puma.rb; else BIND=0.0.0.0 node ./streaming; fi
|
web: bin/heroku-web
|
||||||
worker: bundle exec sidekiq
|
worker: bundle exec sidekiq
|
||||||
|
|
||||||
# For the streaming API, you need a separate app that shares Postgres and Redis:
|
# For the streaming API, you need a separate app that shares Postgres and Redis:
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AboutController < ApplicationController
|
class AboutController < ApplicationController
|
||||||
|
include RegistrationSpamConcern
|
||||||
|
|
||||||
layout 'public'
|
layout 'public'
|
||||||
|
|
||||||
before_action :require_open_federation!, only: [:show, :more]
|
before_action :require_open_federation!, only: [:show, :more]
|
||||||
before_action :set_body_classes, only: :show
|
before_action :set_body_classes, only: :show
|
||||||
before_action :set_instance_presenter
|
before_action :set_instance_presenter
|
||||||
before_action :set_expires_in, only: [:show, :more, :terms]
|
before_action :set_expires_in, only: [:more, :terms]
|
||||||
|
before_action :set_registration_form_time, only: :show
|
||||||
|
|
||||||
skip_before_action :require_functional!, only: [:more, :terms]
|
skip_before_action :require_functional!, only: [:more, :terms]
|
||||||
|
|
||||||
|
@ -29,8 +29,7 @@ class AccountsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
|
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
|
||||||
@statuses = filtered_status_page
|
@statuses = cached_filtered_status_page
|
||||||
@statuses = cache_collection(@statuses, Status)
|
|
||||||
@rss_url = rss_url
|
@rss_url = rss_url
|
||||||
|
|
||||||
unless @statuses.empty?
|
unless @statuses.empty?
|
||||||
@ -86,7 +85,7 @@ class AccountsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def account_media_status_ids
|
def account_media_status_ids
|
||||||
@account.media_attachments.attached.reorder(nil).select(:status_id).distinct
|
@account.media_attachments.attached.reorder(nil).select(:status_id).group(:status_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def no_replies_scope
|
def no_replies_scope
|
||||||
@ -107,6 +106,10 @@ class AccountsController < ApplicationController
|
|||||||
params[:username]
|
params[:username]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def skip_temporary_suspension_response?
|
||||||
|
request.format == :json
|
||||||
|
end
|
||||||
|
|
||||||
def rss_url
|
def rss_url
|
||||||
if tag_requested?
|
if tag_requested?
|
||||||
short_account_tag_url(@account, params[:tag], format: 'rss')
|
short_account_tag_url(@account, params[:tag], format: 'rss')
|
||||||
@ -147,8 +150,13 @@ class AccountsController < ApplicationController
|
|||||||
request.path.split('.').first.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
|
request.path.split('.').first.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
|
||||||
end
|
end
|
||||||
|
|
||||||
def filtered_status_page
|
def cached_filtered_status_page
|
||||||
filtered_statuses.paginate_by_id(PAGE_SIZE, params_slice(:max_id, :min_id, :since_id))
|
cache_collection_paginated_by_id(
|
||||||
|
filtered_statuses,
|
||||||
|
Status,
|
||||||
|
PAGE_SIZE,
|
||||||
|
params_slice(:max_id, :min_id, :since_id)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def params_slice(*keys)
|
def params_slice(*keys)
|
||||||
|
@ -8,4 +8,8 @@ class ActivityPub::BaseController < Api::BaseController
|
|||||||
def set_cache_headers
|
def set_cache_headers
|
||||||
response.headers['Vary'] = 'Signature' if authorized_fetch_mode?
|
response.headers['Vary'] = 'Signature' if authorized_fetch_mode?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def skip_temporary_suspension_response?
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -12,7 +12,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
|||||||
|
|
||||||
def show
|
def show
|
||||||
expires_in 3.minutes, public: public_fetch_mode?
|
expires_in 3.minutes, public: public_fetch_mode?
|
||||||
render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, skip_activities: true
|
render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -20,17 +20,9 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
|||||||
def set_items
|
def set_items
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'featured'
|
when 'featured'
|
||||||
@items = begin
|
@items = for_signed_account { cache_collection(@account.pinned_statuses, Status) }
|
||||||
# Because in public fetch mode we cache the response, there would be no
|
when 'tags'
|
||||||
# benefit from performing the check below, since a blocked account or domain
|
@items = for_signed_account { @account.featured_tags }
|
||||||
# would likely be served the cache from the reverse proxy anyway
|
|
||||||
|
|
||||||
if authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
|
|
||||||
[]
|
|
||||||
else
|
|
||||||
cache_collection(@account.pinned_statuses, Status)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
when 'devices'
|
when 'devices'
|
||||||
@items = @account.devices
|
@items = @account.devices
|
||||||
else
|
else
|
||||||
@ -40,7 +32,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
|||||||
|
|
||||||
def set_size
|
def set_size
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'featured', 'devices'
|
when 'featured', 'devices', 'tags'
|
||||||
@size = @items.size
|
@size = @items.size
|
||||||
else
|
else
|
||||||
not_found
|
not_found
|
||||||
@ -51,7 +43,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
|||||||
case params[:id]
|
case params[:id]
|
||||||
when 'featured'
|
when 'featured'
|
||||||
@type = :ordered
|
@type = :ordered
|
||||||
when 'devices'
|
when 'devices', 'tags'
|
||||||
@type = :unordered
|
@type = :unordered
|
||||||
else
|
else
|
||||||
not_found
|
not_found
|
||||||
@ -66,4 +58,16 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
|||||||
items: @items
|
items: @items
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def for_signed_account
|
||||||
|
# Because in public fetch mode we cache the response, there would be no
|
||||||
|
# benefit from performing the check below, since a blocked account or domain
|
||||||
|
# would likely be served the cache from the reverse proxy anyway
|
||||||
|
|
||||||
|
if authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseController
|
||||||
|
include SignatureVerification
|
||||||
|
include AccountOwnedConcern
|
||||||
|
|
||||||
|
before_action :require_signature!
|
||||||
|
before_action :set_items
|
||||||
|
before_action :set_cache_headers
|
||||||
|
|
||||||
|
def show
|
||||||
|
expires_in 0, public: false
|
||||||
|
render json: collection_presenter,
|
||||||
|
serializer: ActivityPub::CollectionSerializer,
|
||||||
|
adapter: ActivityPub::Adapter,
|
||||||
|
content_type: 'application/activity+json'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def uri_prefix
|
||||||
|
signed_request_account.uri[/http(s?):\/\/[^\/]+\//]
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_items
|
||||||
|
@items = @account.followers.where(Account.arel_table[:uri].matches(uri_prefix + '%', false, true)).pluck(:uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
def collection_presenter
|
||||||
|
ActivityPub::CollectionPresenter.new(
|
||||||
|
id: account_followers_synchronization_url(@account),
|
||||||
|
type: :ordered,
|
||||||
|
items: @items
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
@ -11,6 +11,7 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
upgrade_account
|
upgrade_account
|
||||||
|
process_collection_synchronization
|
||||||
process_payload
|
process_payload
|
||||||
head 202
|
head 202
|
||||||
end
|
end
|
||||||
@ -32,6 +33,10 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||||||
params[:account_username].present?
|
params[:account_username].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def skip_temporary_suspension_response?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def body
|
def body
|
||||||
return @body if defined?(@body)
|
return @body if defined?(@body)
|
||||||
|
|
||||||
@ -52,6 +57,19 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||||||
DeliveryFailureTracker.reset!(signed_request_account.inbox_url)
|
DeliveryFailureTracker.reset!(signed_request_account.inbox_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process_collection_synchronization
|
||||||
|
raw_params = request.headers['Collection-Synchronization']
|
||||||
|
return if raw_params.blank? || ENV['DISABLE_FOLLOWERS_SYNCHRONIZATION'] == 'true'
|
||||||
|
|
||||||
|
# Re-using the syntax for signature parameters
|
||||||
|
tree = SignatureParamsParser.new.parse(raw_params)
|
||||||
|
params = SignatureParamsTransformer.new.apply(tree)
|
||||||
|
|
||||||
|
ActivityPub::PrepareFollowersSynchronizationService.new.call(signed_request_account, params)
|
||||||
|
rescue Parslet::ParseFailed
|
||||||
|
Rails.logger.warn 'Error parsing Collection-Synchronization header'
|
||||||
|
end
|
||||||
|
|
||||||
def process_payload
|
def process_payload
|
||||||
ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body, @account&.id)
|
ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body, @account&.id)
|
||||||
end
|
end
|
||||||
|
@ -20,9 +20,9 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||||||
def outbox_presenter
|
def outbox_presenter
|
||||||
if page_requested?
|
if page_requested?
|
||||||
ActivityPub::CollectionPresenter.new(
|
ActivityPub::CollectionPresenter.new(
|
||||||
id: account_outbox_url(@account, page_params),
|
id: outbox_url(page_params),
|
||||||
type: :ordered,
|
type: :ordered,
|
||||||
part_of: account_outbox_url(@account),
|
part_of: outbox_url,
|
||||||
prev: prev_page,
|
prev: prev_page,
|
||||||
next: next_page,
|
next: next_page,
|
||||||
items: @statuses
|
items: @statuses
|
||||||
@ -32,12 +32,20 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||||||
id: account_outbox_url(@account),
|
id: account_outbox_url(@account),
|
||||||
type: :ordered,
|
type: :ordered,
|
||||||
size: @account.statuses_count,
|
size: @account.statuses_count,
|
||||||
first: account_outbox_url(@account, page: true),
|
first: outbox_url(page: true),
|
||||||
last: account_outbox_url(@account, page: true, min_id: 0)
|
last: outbox_url(page: true, min_id: 0)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def outbox_url(**kwargs)
|
||||||
|
if params[:account_username].present?
|
||||||
|
account_outbox_url(@account, **kwargs)
|
||||||
|
else
|
||||||
|
instance_actor_outbox_url(**kwargs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def next_page
|
def next_page
|
||||||
account_outbox_url(@account, page: true, max_id: @statuses.last.id) if @statuses.size == LIMIT
|
account_outbox_url(@account, page: true, max_id: @statuses.last.id) if @statuses.size == LIMIT
|
||||||
end
|
end
|
||||||
@ -49,9 +57,12 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||||||
def set_statuses
|
def set_statuses
|
||||||
return unless page_requested?
|
return unless page_requested?
|
||||||
|
|
||||||
@statuses = @account.statuses.permitted_for(@account, signed_request_account)
|
@statuses = cache_collection_paginated_by_id(
|
||||||
@statuses = @statuses.paginate_by_id(LIMIT, params_slice(:max_id, :min_id, :since_id))
|
@account.statuses.permitted_for(@account, signed_request_account),
|
||||||
@statuses = cache_collection(@statuses, Status)
|
Status,
|
||||||
|
LIMIT,
|
||||||
|
params_slice(:max_id, :min_id, :since_id)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def page_requested?
|
def page_requested?
|
||||||
@ -61,4 +72,8 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||||||
def page_params
|
def page_params
|
||||||
{ page: true, max_id: params[:max_id], min_id: params[:min_id] }.compact
|
{ page: true, max_id: params[:max_id], min_id: params[:min_id] }.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = params[:account_username].present? ? Account.find_local!(username_param) : Account.representative
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -31,7 +31,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_replies
|
def set_replies
|
||||||
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id) : @account.statuses
|
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses
|
||||||
@replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
|
@replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
|
||||||
@replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
|
@replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class AccountsController < BaseController
|
class AccountsController < BaseController
|
||||||
before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
|
before_action :set_account, except: [:index]
|
||||||
before_action :require_remote_account!, only: [:redownload]
|
before_action :require_remote_account!, only: [:redownload]
|
||||||
before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
|
before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
|
||||||
|
|
||||||
@ -14,49 +14,65 @@ module Admin
|
|||||||
def show
|
def show
|
||||||
authorize @account, :show?
|
authorize @account, :show?
|
||||||
|
|
||||||
|
@deletion_request = @account.deletion_request
|
||||||
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
|
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
|
||||||
@moderation_notes = @account.targeted_moderation_notes.latest
|
@moderation_notes = @account.targeted_moderation_notes.latest
|
||||||
@warnings = @account.targeted_account_warnings.latest.custom
|
@warnings = @account.targeted_account_warnings.latest.custom
|
||||||
|
@domain_block = DomainBlock.rule_for(@account.domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
def memorialize
|
def memorialize
|
||||||
authorize @account, :memorialize?
|
authorize @account, :memorialize?
|
||||||
@account.memorialize!
|
@account.memorialize!
|
||||||
log_action :memorialize, @account
|
log_action :memorialize, @account
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.memorialized_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable
|
def enable
|
||||||
authorize @account.user, :enable?
|
authorize @account.user, :enable?
|
||||||
@account.user.enable!
|
@account.user.enable!
|
||||||
log_action :enable, @account.user
|
log_action :enable, @account.user
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.enabled_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def approve
|
def approve
|
||||||
authorize @account.user, :approve?
|
authorize @account.user, :approve?
|
||||||
@account.user.approve!
|
@account.user.approve!
|
||||||
redirect_to admin_pending_accounts_path
|
redirect_to admin_pending_accounts_path, notice: I18n.t('admin.accounts.approved_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reject
|
def reject
|
||||||
authorize @account.user, :reject?
|
authorize @account.user, :reject?
|
||||||
SuspendAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
||||||
redirect_to admin_pending_accounts_path
|
redirect_to admin_pending_accounts_path, notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize @account, :destroy?
|
||||||
|
Admin::AccountDeletionWorker.perform_async(@account.id)
|
||||||
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.destroyed_msg', username: @account.acct)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unsensitive
|
||||||
|
authorize @account, :unsensitive?
|
||||||
|
@account.unsensitize!
|
||||||
|
log_action :unsensitive, @account
|
||||||
|
redirect_to admin_account_path(@account.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsilence
|
def unsilence
|
||||||
authorize @account, :unsilence?
|
authorize @account, :unsilence?
|
||||||
@account.unsilence!
|
@account.unsilence!
|
||||||
log_action :unsilence, @account
|
log_action :unsilence, @account
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.unsilenced_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsuspend
|
def unsuspend
|
||||||
authorize @account, :unsuspend?
|
authorize @account, :unsuspend?
|
||||||
@account.unsuspend!
|
@account.unsuspend!
|
||||||
|
Admin::UnsuspensionWorker.perform_async(@account.id)
|
||||||
log_action :unsuspend, @account
|
log_action :unsuspend, @account
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.unsuspended_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def redownload
|
def redownload
|
||||||
@ -65,7 +81,7 @@ module Admin
|
|||||||
@account.update!(last_webfingered_at: nil)
|
@account.update!(last_webfingered_at: nil)
|
||||||
ResolveAccountService.new.call(@account)
|
ResolveAccountService.new.call(@account)
|
||||||
|
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.redownloaded_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_avatar
|
def remove_avatar
|
||||||
@ -76,7 +92,7 @@ module Admin
|
|||||||
|
|
||||||
log_action :remove_avatar, @account.user
|
log_action :remove_avatar, @account.user
|
||||||
|
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.removed_avatar_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_header
|
def remove_header
|
||||||
@ -87,7 +103,7 @@ module Admin
|
|||||||
|
|
||||||
log_action :remove_header, @account.user
|
log_action :remove_header, @account.user
|
||||||
|
|
||||||
redirect_to admin_account_path(@account.id)
|
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.removed_header_msg', username: @account.acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -71,7 +71,7 @@ class Admin::AnnouncementsController < Admin::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_announcements
|
def set_announcements
|
||||||
@announcements = AnnouncementFilter.new(filter_params).results.page(params[:page])
|
@announcements = AnnouncementFilter.new(filter_params).results.reverse_chronological.page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_announcement
|
def set_announcement
|
||||||
|
@ -29,6 +29,7 @@ module Admin
|
|||||||
@domain_block = existing_domain_block
|
@domain_block = existing_domain_block
|
||||||
@domain_block.update(resource_params)
|
@domain_block.update(resource_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
if @domain_block.save
|
if @domain_block.save
|
||||||
DomainBlockWorker.perform_async(@domain_block.id)
|
DomainBlockWorker.perform_async(@domain_block.id)
|
||||||
log_action :create, @domain_block
|
log_action :create, @domain_block
|
||||||
@ -40,7 +41,7 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
authorize :domain_block, :create?
|
authorize :domain_block, :update?
|
||||||
|
|
||||||
@domain_block.update(update_params)
|
@domain_block.update(update_params)
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ module Admin
|
|||||||
|
|
||||||
if @domain_block.save
|
if @domain_block.save
|
||||||
DomainBlockWorker.perform_async(@domain_block.id, severity_changed)
|
DomainBlockWorker.perform_async(@domain_block.id, severity_changed)
|
||||||
log_action :create, @domain_block
|
log_action :update, @domain_block
|
||||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')
|
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')
|
||||||
else
|
else
|
||||||
render :edit
|
render :edit
|
||||||
@ -73,11 +74,11 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update_params
|
def update_params
|
||||||
params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment)
|
params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment)
|
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,7 +27,7 @@ module Admin
|
|||||||
ips = []
|
ips = []
|
||||||
|
|
||||||
Resolv::DNS.open do |dns|
|
Resolv::DNS.open do |dns|
|
||||||
dns.timeouts = 1
|
dns.timeouts = 5
|
||||||
|
|
||||||
hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
|
hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
|
||||||
|
|
||||||
|
@ -2,65 +2,31 @@
|
|||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class InstancesController < BaseController
|
class InstancesController < BaseController
|
||||||
before_action :set_domain_block, only: :show
|
before_action :set_instances, only: :index
|
||||||
before_action :set_domain_allow, only: :show
|
|
||||||
before_action :set_instance, only: :show
|
before_action :set_instance, only: :show
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :instance, :index?
|
authorize :instance, :index?
|
||||||
|
|
||||||
@instances = ordered_instances
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize :instance, :show?
|
authorize :instance, :show?
|
||||||
|
|
||||||
@following_count = Follow.where(account: Account.where(domain: params[:id])).count
|
|
||||||
@followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count
|
|
||||||
@reports_count = Report.where(target_account: Account.where(domain: params[:id])).count
|
|
||||||
@blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count
|
|
||||||
@available = DeliveryFailureTracker.available?(params[:id])
|
|
||||||
@media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size)
|
|
||||||
@private_comment = @domain_block&.private_comment
|
|
||||||
@public_comment = @domain_block&.public_comment
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_domain_block
|
|
||||||
@domain_block = DomainBlock.rule_for(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_domain_allow
|
|
||||||
@domain_allow = DomainAllow.rule_for(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_instance
|
def set_instance
|
||||||
resource = Account.by_domain_accounts.find_by(domain: params[:id])
|
@instance = Instance.find(params[:id])
|
||||||
resource ||= @domain_block
|
|
||||||
resource ||= @domain_allow
|
|
||||||
|
|
||||||
if resource
|
|
||||||
@instance = Instance.new(resource)
|
|
||||||
else
|
|
||||||
not_found
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_instances
|
||||||
|
@instances = filtered_instances.page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def filtered_instances
|
def filtered_instances
|
||||||
InstanceFilter.new(whitelist_mode? ? { allowed: true } : filter_params).results
|
InstanceFilter.new(whitelist_mode? ? { allowed: true } : filter_params).results
|
||||||
end
|
end
|
||||||
|
|
||||||
def paginated_instances
|
|
||||||
filtered_instances.page(params[:page])
|
|
||||||
end
|
|
||||||
|
|
||||||
helper_method :paginated_instances
|
|
||||||
|
|
||||||
def ordered_instances
|
|
||||||
paginated_instances.map { |resource| Instance.new(resource) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.slice(*InstanceFilter::KEYS).permit(*InstanceFilter::KEYS)
|
params.slice(*InstanceFilter::KEYS).permit(*InstanceFilter::KEYS)
|
||||||
end
|
end
|
||||||
|
56
app/controllers/admin/ip_blocks_controller.rb
Normal file
56
app/controllers/admin/ip_blocks_controller.rb
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class IpBlocksController < BaseController
|
||||||
|
def index
|
||||||
|
authorize :ip_block, :index?
|
||||||
|
|
||||||
|
@ip_blocks = IpBlock.page(params[:page])
|
||||||
|
@form = Form::IpBlockBatch.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
authorize :ip_block, :create?
|
||||||
|
|
||||||
|
@ip_block = IpBlock.new(ip: '', severity: :no_access, expires_in: 1.year)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize :ip_block, :create?
|
||||||
|
|
||||||
|
@ip_block = IpBlock.new(resource_params)
|
||||||
|
|
||||||
|
if @ip_block.save
|
||||||
|
log_action :create, @ip_block
|
||||||
|
redirect_to admin_ip_blocks_path, notice: I18n.t('admin.ip_blocks.created_msg')
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def batch
|
||||||
|
@form = Form::IpBlockBatch.new(form_ip_block_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
|
@form.save
|
||||||
|
rescue ActionController::ParameterMissing
|
||||||
|
flash[:alert] = I18n.t('admin.ip_blocks.no_ip_block_selected')
|
||||||
|
rescue Mastodon::NotPermittedError
|
||||||
|
flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
|
||||||
|
ensure
|
||||||
|
redirect_to admin_ip_blocks_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def resource_params
|
||||||
|
params.require(:ip_block).permit(:ip, :severity, :comment, :expires_in)
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_from_button
|
||||||
|
'delete' if params[:delete]
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_ip_block_batch_params
|
||||||
|
params.require(:form_ip_block_batch).permit(ip_block_ids: [])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -14,7 +14,7 @@ module Admin
|
|||||||
@statuses = @account.statuses.where(visibility: [:public, :unlisted])
|
@statuses = @account.statuses.where(visibility: [:public, :unlisted])
|
||||||
|
|
||||||
if params[:media]
|
if params[:media]
|
||||||
account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
|
account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).group(:status_id)
|
||||||
@statuses.merge!(Status.where(id: account_media_status_ids))
|
@statuses.merge!(Status.where(id: account_media_status_ids))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class Api::BaseController < ApplicationController
|
|||||||
render json: { error: 'This action is not allowed' }, status: 403
|
render json: { error: 'This action is not allowed' }, status: 403
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue_from Mastodon::RaceConditionError do
|
rescue_from Mastodon::RaceConditionError, Seahorse::Client::NetworkingError, Stoplight::Error::RedLight do
|
||||||
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -71,6 +71,7 @@ class Api::BaseController < ApplicationController
|
|||||||
|
|
||||||
def limit_param(default_limit)
|
def limit_param(default_limit)
|
||||||
return default_limit unless params[:limit]
|
return default_limit unless params[:limit]
|
||||||
|
|
||||||
[params[:limit].to_i.abs, default_limit * 2].min
|
[params[:limit].to_i.abs, default_limit * 2].min
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -95,14 +96,14 @@ class Api::BaseController < ApplicationController
|
|||||||
def require_user!
|
def require_user!
|
||||||
if !current_user
|
if !current_user
|
||||||
render json: { error: 'This method requires an authenticated user' }, status: 422
|
render json: { error: 'This method requires an authenticated user' }, status: 422
|
||||||
elsif current_user.disabled?
|
|
||||||
render json: { error: 'Your login is currently disabled' }, status: 403
|
|
||||||
elsif !current_user.confirmed?
|
elsif !current_user.confirmed?
|
||||||
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
|
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
|
||||||
elsif !current_user.approved?
|
elsif !current_user.approved?
|
||||||
render json: { error: 'Your login is currently pending approval' }, status: 403
|
render json: { error: 'Your login is currently pending approval' }, status: 403
|
||||||
|
elsif !current_user.functional?
|
||||||
|
render json: { error: 'Your login is currently disabled' }, status: 403
|
||||||
else
|
else
|
||||||
set_user_activity
|
update_user_sign_in
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
22
app/controllers/api/v1/accounts/featured_tags_controller.rb
Normal file
22
app/controllers/api/v1/accounts/featured_tags_controller.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Accounts::FeaturedTagsController < Api::BaseController
|
||||||
|
before_action :set_account
|
||||||
|
before_action :set_featured_tags
|
||||||
|
|
||||||
|
respond_to :json
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: @featured_tags, each_serializer: REST::FeaturedTagSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = Account.find(params[:account_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_featured_tags
|
||||||
|
@featured_tags = @account.suspended? ? [] : @account.featured_tags
|
||||||
|
end
|
||||||
|
end
|
@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def hide_results?
|
def hide_results?
|
||||||
(@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
@account.suspended? || (@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
|
@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def hide_results?
|
def hide_results?
|
||||||
(@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
@account.suspended? || (@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
|
@ -5,7 +5,7 @@ class Api::V1::Accounts::IdentityProofsController < Api::BaseController
|
|||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@proofs = @account.identity_proofs.active
|
@proofs = @account.suspended? ? [] : @account.identity_proofs.active
|
||||||
render json: @proofs, each_serializer: REST::IdentityProofSerializer
|
render json: @proofs, each_serializer: REST::IdentityProofSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ class Api::V1::Accounts::ListsController < Api::BaseController
|
|||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@lists = @account.lists.where(account: current_account)
|
@lists = @account.suspended? ? [] : @account.lists.where(account: current_account)
|
||||||
render json: @lists, each_serializer: REST::ListSerializer
|
render json: @lists, each_serializer: REST::ListSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
|
|||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
def index
|
def index
|
||||||
accounts = Account.where(id: account_ids).select('id')
|
accounts = Account.without_suspended.where(id: account_ids).select('id')
|
||||||
# .where doesn't guarantee that our results are in the same order
|
# .where doesn't guarantee that our results are in the same order
|
||||||
# we requested them, so return the "right" order to the requestor.
|
# we requested them, so return the "right" order to the requestor.
|
||||||
@accounts = accounts.index_by(&:id).values_at(*account_ids).compact
|
@accounts = accounts.index_by(&:id).values_at(*account_ids).compact
|
||||||
|
@ -18,14 +18,10 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def load_statuses
|
def load_statuses
|
||||||
cached_account_statuses
|
@account.suspended? ? [] : cached_account_statuses
|
||||||
end
|
end
|
||||||
|
|
||||||
def cached_account_statuses
|
def cached_account_statuses
|
||||||
cache_collection account_statuses, Status
|
|
||||||
end
|
|
||||||
|
|
||||||
def account_statuses
|
|
||||||
statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses
|
statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses
|
||||||
|
|
||||||
statuses.merge!(only_media_scope) if truthy_param?(:only_media)
|
statuses.merge!(only_media_scope) if truthy_param?(:only_media)
|
||||||
@ -33,7 +29,12 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
|
statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
|
||||||
statuses.merge!(hashtag_scope) if params[:tagged].present?
|
statuses.merge!(hashtag_scope) if params[:tagged].present?
|
||||||
|
|
||||||
statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id))
|
cache_collection_paginated_by_id(
|
||||||
|
statuses,
|
||||||
|
Status,
|
||||||
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted_account_statuses
|
def permitted_account_statuses
|
||||||
@ -41,17 +42,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def only_media_scope
|
def only_media_scope
|
||||||
Status.where(id: account_media_status_ids)
|
Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id)
|
||||||
end
|
|
||||||
|
|
||||||
def account_media_status_ids
|
|
||||||
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
|
|
||||||
# Also, Avoid getting slow by not narrowing down by `statuses.account_id`.
|
|
||||||
# When narrowing down by `statuses.account_id`, `index_statuses_20180106` will be used
|
|
||||||
# and the table will be joined by `Merge Semi Join`, so the query will be slow.
|
|
||||||
@account.statuses.joins(:media_attachments).merge(@account.media_attachments).permitted_for(@account, current_account)
|
|
||||||
.paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id])
|
|
||||||
.reorder(id: :desc).distinct(:id).pluck(:id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def pinned_scope
|
def pinned_scope
|
||||||
|
@ -9,7 +9,6 @@ class Api::V1::AccountsController < Api::BaseController
|
|||||||
|
|
||||||
before_action :require_user!, except: [:show, :create]
|
before_action :require_user!, except: [:show, :create]
|
||||||
before_action :set_account, except: [:create]
|
before_action :set_account, except: [:create]
|
||||||
before_action :check_account_suspension, only: [:show]
|
|
||||||
before_action :check_enabled_registrations, only: [:create]
|
before_action :check_enabled_registrations, only: [:create]
|
||||||
|
|
||||||
skip_before_action :require_authenticated_user!, only: :create
|
skip_before_action :require_authenticated_user!, only: :create
|
||||||
@ -21,7 +20,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
token = AppSignUpService.new.call(doorkeeper_token.application, account_params)
|
token = AppSignUpService.new.call(doorkeeper_token.application, request.remote_ip, account_params)
|
||||||
response = Doorkeeper::OAuth::TokenResponse.new(token)
|
response = Doorkeeper::OAuth::TokenResponse.new(token)
|
||||||
|
|
||||||
headers.merge!(response.headers)
|
headers.merge!(response.headers)
|
||||||
@ -31,9 +30,8 @@ class Api::V1::AccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def follow
|
def follow
|
||||||
FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs), with_rate_limit: true)
|
follow = FollowService.new.call(current_user.account, @account, reblogs: params.key?(:reblogs) ? truthy_param?(:reblogs) : nil, notify: params.key?(:notify) ? truthy_param?(:notify) : nil, with_rate_limit: true)
|
||||||
|
options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify? } }, requested_map: { @account.id => false } }
|
||||||
options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
|
|
||||||
|
|
||||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
|
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
|
||||||
end
|
end
|
||||||
@ -44,7 +42,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def mute
|
def mute
|
||||||
MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications))
|
MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications), duration: (params[:duration] || 0))
|
||||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -73,10 +71,6 @@ class Api::V1::AccountsController < Api::BaseController
|
|||||||
AccountRelationshipsPresenter.new([@account.id], current_user.account_id, options)
|
AccountRelationshipsPresenter.new([@account.id], current_user.account_id, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_account_suspension
|
|
||||||
gone if @account.suspended?
|
|
||||||
end
|
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
params.permit(:username, :email, :password, :agreement, :locale, :reason)
|
params.permit(:username, :email, :password, :agreement, :locale, :reason)
|
||||||
end
|
end
|
||||||
|
@ -22,6 +22,7 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||||||
active
|
active
|
||||||
pending
|
pending
|
||||||
disabled
|
disabled
|
||||||
|
sensitized
|
||||||
silenced
|
silenced
|
||||||
suspended
|
suspended
|
||||||
username
|
username
|
||||||
@ -58,7 +59,20 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||||||
|
|
||||||
def reject
|
def reject
|
||||||
authorize @account.user, :reject?
|
authorize @account.user, :reject?
|
||||||
SuspendAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
||||||
|
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize @account, :destroy?
|
||||||
|
Admin::AccountDeletionWorker.perform_async(@account.id)
|
||||||
|
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def unsensitive
|
||||||
|
authorize @account, :unsensitive?
|
||||||
|
@account.unsensitize!
|
||||||
|
log_action :unsensitive, @account
|
||||||
render json: @account, serializer: REST::Admin::AccountSerializer
|
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -72,6 +86,7 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||||||
def unsuspend
|
def unsuspend
|
||||||
authorize @account, :unsuspend?
|
authorize @account, :unsuspend?
|
||||||
@account.unsuspend!
|
@account.unsuspend!
|
||||||
|
Admin::UnsuspensionWorker.perform_async(@account.id)
|
||||||
log_action :unsuspend, @account
|
log_action :unsuspend, @account
|
||||||
render json: @account, serializer: REST::Admin::AccountSerializer
|
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||||
end
|
end
|
||||||
@ -79,7 +94,7 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_accounts
|
def set_accounts
|
||||||
@accounts = filtered_accounts.order(id: :desc).includes(user: [:invite_request, :invite]).paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
@accounts = filtered_accounts.order(id: :desc).includes(user: [:invite_request, :invite]).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
@ -63,7 +63,7 @@ class Api::V1::Admin::ReportsController < Api::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_reports
|
def set_reports
|
||||||
@reports = filtered_reports.order(id: :desc).with_accounts.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
@reports = filtered_reports.order(id: :desc).with_accounts.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_report
|
def set_report
|
||||||
|
@ -18,6 +18,8 @@ class Api::V1::BlocksController < Api::BaseController
|
|||||||
|
|
||||||
def paginated_blocks
|
def paginated_blocks
|
||||||
@paginated_blocks ||= Block.eager_load(target_account: :account_stat)
|
@paginated_blocks ||= Block.eager_load(target_account: :account_stat)
|
||||||
|
.joins(:target_account)
|
||||||
|
.merge(Account.without_suspended)
|
||||||
.where(account: current_account)
|
.where(account: current_account)
|
||||||
.paginate_by_max_id(
|
.paginate_by_max_id(
|
||||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||||
|
@ -17,14 +17,11 @@ class Api::V1::BookmarksController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def cached_bookmarks
|
def cached_bookmarks
|
||||||
cache_collection(
|
cache_collection(results.map(&:status), Status)
|
||||||
Status.reorder(nil).joins(:bookmarks).merge(results),
|
|
||||||
Status
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def results
|
def results
|
||||||
@_results ||= account_bookmarks.paginate_by_id(
|
@_results ||= account_bookmarks.eager_load(:status).to_a_paginated_by_id(
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
|
@ -32,7 +32,7 @@ class Api::V1::ConversationsController < Api::BaseController
|
|||||||
|
|
||||||
def paginated_conversations
|
def paginated_conversations
|
||||||
AccountConversation.where(account: current_account)
|
AccountConversation.where(account: current_account)
|
||||||
.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -26,7 +26,7 @@ class Api::V1::Crypto::EncryptedMessagesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_encrypted_messages
|
def set_encrypted_messages
|
||||||
@encrypted_messages = @current_device.encrypted_messages.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
@encrypted_messages = @current_device.encrypted_messages.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -25,7 +25,7 @@ class Api::V1::EndorsementsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def endorsed_accounts
|
def endorsed_accounts
|
||||||
current_account.endorsed_accounts.includes(:account_stat)
|
current_account.endorsed_accounts.includes(:account_stat).without_suspended
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -17,14 +17,11 @@ class Api::V1::FavouritesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def cached_favourites
|
def cached_favourites
|
||||||
cache_collection(
|
cache_collection(results.map(&:status), Status)
|
||||||
Status.reorder(nil).joins(:favourites).merge(results),
|
|
||||||
Status
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def results
|
def results
|
||||||
@_results ||= account_favourites.paginate_by_id(
|
@_results ||= account_favourites.eager_load(:status).to_a_paginated_by_id(
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
|
@ -3,15 +3,15 @@
|
|||||||
class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
|
class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
|
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_most_used_tags, only: :index
|
before_action :set_recently_used_tags, only: :index
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @most_used_tags, each_serializer: REST::TagSerializer
|
render json: @recently_used_tags, each_serializer: REST::TagSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_most_used_tags
|
def set_recently_used_tags
|
||||||
@most_used_tags = Tag.most_used(current_account).where.not(id: current_account.featured_tags).limit(10)
|
@recently_used_tags = Tag.recently_used(current_account).where.not(id: current_account.featured_tags).limit(10)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -13,7 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController
|
|||||||
|
|
||||||
def authorize
|
def authorize
|
||||||
AuthorizeFollowService.new.call(account, current_account)
|
AuthorizeFollowService.new.call(account, current_account)
|
||||||
NotifyService.new.call(current_account, Follow.find_by(account: account, target_account: current_account))
|
NotifyService.new.call(current_account, :follow, Follow.find_by(account: account, target_account: current_account))
|
||||||
render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
|
render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ class Api::V1::FollowRequestsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
Account.includes(:follow_requests, :account_stat).references(:follow_requests)
|
Account.without_suspended.includes(:follow_requests, :account_stat).references(:follow_requests)
|
||||||
end
|
end
|
||||||
|
|
||||||
def paginated_follow_requests
|
def paginated_follow_requests
|
||||||
|
@ -8,7 +8,7 @@ class Api::V1::Instances::PeersController < Api::BaseController
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
expires_in 1.day, public: true
|
expires_in 1.day, public: true
|
||||||
render_with_cache(expires_in: 1.day) { Account.remote.domains }
|
render_with_cache(expires_in: 1.day) { Instance.where.not(domain: DomainBlock.select(:domain)).pluck(:domain) }
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -37,9 +37,9 @@ class Api::V1::Lists::AccountsController < Api::BaseController
|
|||||||
|
|
||||||
def load_accounts
|
def load_accounts
|
||||||
if unlimited?
|
if unlimited?
|
||||||
@list.accounts.includes(:account_stat).all
|
@list.accounts.without_suspended.includes(:account_stat).all
|
||||||
else
|
else
|
||||||
@list.accounts.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
|
@list.accounts.without_suspended.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,6 +38,6 @@ class Api::V1::ListsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def list_params
|
def list_params
|
||||||
params.permit(:title)
|
params.permit(:title, :replies_policy)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,7 +7,7 @@ class Api::V1::MutesController < Api::BaseController
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::MutedAccountSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -18,6 +18,8 @@ class Api::V1::MutesController < Api::BaseController
|
|||||||
|
|
||||||
def paginated_mutes
|
def paginated_mutes
|
||||||
@paginated_mutes ||= Mute.eager_load(:target_account)
|
@paginated_mutes ||= Mute.eager_load(:target_account)
|
||||||
|
.joins(:target_account)
|
||||||
|
.merge(Account.without_suspended)
|
||||||
.where(account: current_account)
|
.where(account: current_account)
|
||||||
.paginate_by_max_id(
|
.paginate_by_max_id(
|
||||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||||
|
@ -14,7 +14,7 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@notification = current_account.notifications.find(params[:id])
|
@notification = current_account.notifications.without_suspended.find(params[:id])
|
||||||
render json: @notification, serializer: REST::NotificationSerializer
|
render json: @notification, serializer: REST::NotificationSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -31,18 +31,16 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def load_notifications
|
def load_notifications
|
||||||
cache_collection paginated_notifications, Notification
|
cache_collection_paginated_by_id(
|
||||||
end
|
browserable_account_notifications,
|
||||||
|
Notification,
|
||||||
def paginated_notifications
|
|
||||||
browserable_account_notifications.paginate_by_id(
|
|
||||||
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def browserable_account_notifications
|
def browserable_account_notifications
|
||||||
current_account.notifications.browserable(exclude_types, from_account)
|
current_account.notifications.without_suspended.browserable(exclude_types, from_account)
|
||||||
end
|
end
|
||||||
|
|
||||||
def target_statuses_from_notifications
|
def target_statuses_from_notifications
|
||||||
|
@ -52,6 +52,6 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
|||||||
def data_params
|
def data_params
|
||||||
return {} if params[:data].blank?
|
return {} if params[:data].blank?
|
||||||
|
|
||||||
params.require(:data).permit(alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll])
|
params.require(:data).permit(alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll, :status])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -32,7 +32,7 @@ class Api::V1::ScheduledStatusesController < Api::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_statuses
|
def set_statuses
|
||||||
@statuses = current_account.scheduled_statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id))
|
@statuses = current_account.scheduled_statuses.to_a_paginated_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_status
|
def set_status
|
||||||
|
@ -5,7 +5,7 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController
|
|||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' }
|
before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
before_action :set_status, only: [:create]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
||||||
@ -13,10 +13,20 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
bookmark = current_account.bookmarks.find_by(status: @status)
|
bookmark = current_account.bookmarks.find_by(status_id: params[:status_id])
|
||||||
|
|
||||||
|
if bookmark
|
||||||
|
@status = bookmark.status
|
||||||
|
else
|
||||||
|
@status = Status.find(params[:status_id])
|
||||||
|
authorize @status, :show?
|
||||||
|
end
|
||||||
|
|
||||||
bookmark&.destroy!
|
bookmark&.destroy!
|
||||||
|
|
||||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
|
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
|
||||||
|
rescue Mastodon::NotPermittedError
|
||||||
|
not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -22,6 +22,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
|||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
Account
|
Account
|
||||||
|
.without_suspended
|
||||||
.includes(:favourites, :account_stat)
|
.includes(:favourites, :account_stat)
|
||||||
.references(:favourites)
|
.references(:favourites)
|
||||||
.where(favourites: { status_id: @status.id })
|
.where(favourites: { status_id: @status.id })
|
||||||
|
@ -5,7 +5,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
|||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
before_action :set_status, only: [:create]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
FavouriteService.new.call(current_account, @status)
|
FavouriteService.new.call(current_account, @status)
|
||||||
@ -13,8 +13,19 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
|
fav = current_account.favourites.find_by(status_id: params[:status_id])
|
||||||
|
|
||||||
|
if fav
|
||||||
|
@status = fav.status
|
||||||
UnfavouriteWorker.perform_async(current_account.id, @status.id)
|
UnfavouriteWorker.perform_async(current_account.id, @status.id)
|
||||||
|
else
|
||||||
|
@status = Status.find(params[:status_id])
|
||||||
|
authorize @status, :show?
|
||||||
|
end
|
||||||
|
|
||||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false })
|
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false })
|
||||||
|
rescue Mastodon::NotPermittedError
|
||||||
|
not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -21,7 +21,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
Account.includes(:statuses, :account_stat).references(:statuses)
|
Account.without_suspended.includes(:statuses, :account_stat).references(:statuses)
|
||||||
end
|
end
|
||||||
|
|
||||||
def paginated_statuses
|
def paginated_statuses
|
||||||
|
@ -16,30 +16,29 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def load_statuses
|
def load_statuses
|
||||||
cached_public_statuses
|
cached_public_statuses_page
|
||||||
end
|
end
|
||||||
|
|
||||||
def cached_public_statuses
|
def cached_public_statuses_page
|
||||||
cache_collection public_statuses, Status
|
cache_collection(public_statuses, Status)
|
||||||
end
|
end
|
||||||
|
|
||||||
def public_statuses
|
def public_statuses
|
||||||
statuses = public_timeline_statuses.paginate_by_id(
|
public_feed.get(
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params[:max_id],
|
||||||
|
params[:since_id],
|
||||||
|
params[:min_id]
|
||||||
)
|
)
|
||||||
|
|
||||||
if truthy_param?(:only_media)
|
|
||||||
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
|
|
||||||
status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id)
|
|
||||||
statuses.where(id: status_ids)
|
|
||||||
else
|
|
||||||
statuses
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def public_timeline_statuses
|
def public_feed
|
||||||
Status.as_public_timeline(current_account, truthy_param?(:remote) ? :remote : truthy_param?(:local))
|
PublicFeed.new(
|
||||||
|
current_account,
|
||||||
|
local: truthy_param?(:local),
|
||||||
|
remote: truthy_param?(:remote),
|
||||||
|
only_media: truthy_param?(:only_media)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -20,30 +20,29 @@ class Api::V1::Timelines::TagController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def cached_tagged_statuses
|
def cached_tagged_statuses
|
||||||
cache_collection tagged_statuses, Status
|
@tag.nil? ? [] : cache_collection(tag_timeline_statuses, Status)
|
||||||
end
|
|
||||||
|
|
||||||
def tagged_statuses
|
|
||||||
if @tag.nil?
|
|
||||||
[]
|
|
||||||
else
|
|
||||||
statuses = tag_timeline_statuses.paginate_by_id(
|
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
if truthy_param?(:only_media)
|
|
||||||
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
|
|
||||||
status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id)
|
|
||||||
statuses.where(id: status_ids)
|
|
||||||
else
|
|
||||||
statuses
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def tag_timeline_statuses
|
def tag_timeline_statuses
|
||||||
HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none), current_account, truthy_param?(:local))
|
tag_feed.get(
|
||||||
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
|
params[:max_id],
|
||||||
|
params[:since_id],
|
||||||
|
params[:min_id]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag_feed
|
||||||
|
TagFeed.new(
|
||||||
|
@tag,
|
||||||
|
current_account,
|
||||||
|
any: params[:any],
|
||||||
|
all: params[:all],
|
||||||
|
none: params[:none],
|
||||||
|
local: truthy_param?(:local),
|
||||||
|
remote: truthy_param?(:remote),
|
||||||
|
only_media: truthy_param?(:only_media)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -22,6 +22,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
|||||||
reblog: alerts_enabled,
|
reblog: alerts_enabled,
|
||||||
mention: alerts_enabled,
|
mention: alerts_enabled,
|
||||||
poll: alerts_enabled,
|
poll: alerts_enabled,
|
||||||
|
status: alerts_enabled,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +58,6 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def data_params
|
def data_params
|
||||||
@data_params ||= params.require(:data).permit(alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll])
|
@data_params ||= params.require(:data).permit(alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll, :status])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -28,7 +28,7 @@ class ApplicationController < ActionController::Base
|
|||||||
rescue_from ActiveRecord::RecordNotFound, with: :not_found
|
rescue_from ActiveRecord::RecordNotFound, with: :not_found
|
||||||
rescue_from Mastodon::NotPermittedError, with: :forbidden
|
rescue_from Mastodon::NotPermittedError, with: :forbidden
|
||||||
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
||||||
rescue_from Mastodon::RaceConditionError, with: :service_unavailable
|
rescue_from Mastodon::RaceConditionError, Seahorse::Client::NetworkingError, Stoplight::Error::RedLight, with: :service_unavailable
|
||||||
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
||||||
|
|
||||||
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
|
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
class Auth::RegistrationsController < Devise::RegistrationsController
|
class Auth::RegistrationsController < Devise::RegistrationsController
|
||||||
include Devise::Controllers::Rememberable
|
include Devise::Controllers::Rememberable
|
||||||
|
include RegistrationSpamConcern
|
||||||
|
|
||||||
layout :determine_layout
|
layout :determine_layout
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||||||
before_action :set_body_classes, only: [:new, :create, :edit, :update]
|
before_action :set_body_classes, only: [:new, :create, :edit, :update]
|
||||||
before_action :require_not_suspended!, only: [:update]
|
before_action :require_not_suspended!, only: [:update]
|
||||||
before_action :set_cache_headers, only: [:edit, :update]
|
before_action :set_cache_headers, only: [:edit, :update]
|
||||||
|
before_action :set_registration_form_time, only: :new
|
||||||
|
|
||||||
skip_before_action :require_functional!, only: [:edit, :update]
|
skip_before_action :require_functional!, only: [:edit, :update]
|
||||||
|
|
||||||
@ -47,14 +49,15 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||||||
|
|
||||||
resource.locale = I18n.locale
|
resource.locale = I18n.locale
|
||||||
resource.invite_code = params[:invite_code] if resource.invite_code.blank?
|
resource.invite_code = params[:invite_code] if resource.invite_code.blank?
|
||||||
resource.current_sign_in_ip = request.remote_ip
|
resource.registration_form_time = session[:registration_form_time]
|
||||||
|
resource.sign_up_ip = request.remote_ip
|
||||||
|
|
||||||
resource.build_account if resource.account.nil?
|
resource.build_account if resource.account.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def configure_sign_up_params
|
def configure_sign_up_params
|
||||||
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
||||||
u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement)
|
u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
|
|
||||||
skip_before_action :require_no_authentication, only: [:create]
|
skip_before_action :require_no_authentication, only: [:create]
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
skip_before_action :update_user_sign_in
|
||||||
|
|
||||||
include TwoFactorAuthenticationConcern
|
include TwoFactorAuthenticationConcern
|
||||||
include SignInTokenAuthenticationConcern
|
include SignInTokenAuthenticationConcern
|
||||||
@ -24,6 +25,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
super do |resource|
|
super do |resource|
|
||||||
|
resource.update_sign_in!(request, new_sign_in: true)
|
||||||
remember_me(resource)
|
remember_me(resource)
|
||||||
flash.delete(:notice)
|
flash.delete(:notice)
|
||||||
end
|
end
|
||||||
@ -37,11 +39,27 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
store_location_for(:user, tmp_stored_location) if continue_after?
|
store_location_for(:user, tmp_stored_location) if continue_after?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def webauthn_options
|
||||||
|
user = find_user
|
||||||
|
|
||||||
|
if user.webauthn_enabled?
|
||||||
|
options_for_get = WebAuthn::Credential.options_for_get(
|
||||||
|
allow: user.webauthn_credentials.pluck(:external_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
session[:webauthn_challenge] = options_for_get.challenge
|
||||||
|
|
||||||
|
render json: options_for_get, status: :ok
|
||||||
|
else
|
||||||
|
render json: { error: t('webauthn_credentials.not_enabled') }, status: :unauthorized
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def find_user
|
def find_user
|
||||||
if session[:attempt_user_id]
|
if session[:attempt_user_id]
|
||||||
User.find(session[:attempt_user_id])
|
User.find_by(id: session[:attempt_user_id])
|
||||||
else
|
else
|
||||||
user = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
|
user = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
|
||||||
user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
|
user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
|
||||||
@ -51,7 +69,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:email, :password, :otp_attempt, :sign_in_token_attempt)
|
params.require(:user).permit(:email, :password, :otp_attempt, :sign_in_token_attempt, credential: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_sign_in_path_for(resource)
|
def after_sign_in_path_for(resource)
|
||||||
@ -74,6 +92,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
|
|
||||||
def require_no_authentication
|
def require_no_authentication
|
||||||
super
|
super
|
||||||
|
|
||||||
# Delete flash message that isn't entirely useful and may be confusing in
|
# Delete flash message that isn't entirely useful and may be confusing in
|
||||||
# most cases because /web doesn't display/clear flash messages.
|
# most cases because /web doesn't display/clear flash messages.
|
||||||
flash.delete(:alert) if flash[:alert] == I18n.t('devise.failure.already_authenticated')
|
flash.delete(:alert) if flash[:alert] == I18n.t('devise.failure.already_authenticated')
|
||||||
@ -91,13 +110,30 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
|
|
||||||
def home_paths(resource)
|
def home_paths(resource)
|
||||||
paths = [about_path]
|
paths = [about_path]
|
||||||
|
|
||||||
if single_user_mode? && resource.is_a?(User)
|
if single_user_mode? && resource.is_a?(User)
|
||||||
paths << short_account_path(username: resource.account)
|
paths << short_account_path(username: resource.account)
|
||||||
end
|
end
|
||||||
|
|
||||||
paths
|
paths
|
||||||
end
|
end
|
||||||
|
|
||||||
def continue_after?
|
def continue_after?
|
||||||
truthy_param?(:continue)
|
truthy_param?(:continue)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def restart_session
|
||||||
|
clear_attempt_from_session
|
||||||
|
redirect_to new_user_session_path, alert: I18n.t('devise.failure.timeout')
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_attempt_session(user)
|
||||||
|
session[:attempt_user_id] = user.id
|
||||||
|
session[:attempt_user_updated_at] = user.updated_at.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_attempt_from_session
|
||||||
|
session.delete(:attempt_user_id)
|
||||||
|
session.delete(:attempt_user_updated_at)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -29,6 +29,24 @@ module AccountOwnedConcern
|
|||||||
end
|
end
|
||||||
|
|
||||||
def check_account_suspension
|
def check_account_suspension
|
||||||
expires_in(3.minutes, public: true) && gone if @account.suspended?
|
if @account.suspended_permanently?
|
||||||
|
permanent_suspension_response
|
||||||
|
elsif @account.suspended? && !skip_temporary_suspension_response?
|
||||||
|
temporary_suspension_response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def skip_temporary_suspension_response?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def permanent_suspension_response
|
||||||
|
expires_in(3.minutes, public: true)
|
||||||
|
gone
|
||||||
|
end
|
||||||
|
|
||||||
|
def temporary_suspension_response
|
||||||
|
expires_in(3.minutes, public: true)
|
||||||
|
forbidden
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,4 +47,8 @@ module CacheConcern
|
|||||||
|
|
||||||
raw.map { |item| cached_keys_with_value[item.id] || uncached[item.id] }.compact
|
raw.map { |item| cached_keys_with_value[item.id] || uncached[item.id] }.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cache_collection_paginated_by_id(raw, klass, limit, options)
|
||||||
|
cache_collection raw.cache_ids.to_a_paginated_by_id(limit, options), klass
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -32,7 +32,6 @@ module ChallengableConcern
|
|||||||
if params.key?(:form_challenge)
|
if params.key?(:form_challenge)
|
||||||
if challenge_passed?
|
if challenge_passed?
|
||||||
session[:challenge_passed_at] = Time.now.utc
|
session[:challenge_passed_at] = Time.now.utc
|
||||||
return
|
|
||||||
else
|
else
|
||||||
flash.now[:alert] = I18n.t('challenge.invalid_password')
|
flash.now[:alert] = I18n.t('challenge.invalid_password')
|
||||||
render_challenge
|
render_challenge
|
||||||
|
@ -5,7 +5,6 @@ module ExportControllerConcern
|
|||||||
|
|
||||||
included do
|
included do
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :require_not_suspended!
|
|
||||||
before_action :load_export
|
before_action :load_export
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
@ -30,8 +29,4 @@ module ExportControllerConcern
|
|||||||
def export_filename
|
def export_filename
|
||||||
"#{controller_name}.csv"
|
"#{controller_name}.csv"
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_not_suspended!
|
|
||||||
forbidden if current_account.suspended?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
9
app/controllers/concerns/registration_spam_concern.rb
Normal file
9
app/controllers/concerns/registration_spam_concern.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module RegistrationSpamConcern
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def set_registration_form_time
|
||||||
|
session[:registration_form_time] = Time.now.utc
|
||||||
|
end
|
||||||
|
end
|
@ -18,7 +18,9 @@ module SignInTokenAuthenticationConcern
|
|||||||
def authenticate_with_sign_in_token
|
def authenticate_with_sign_in_token
|
||||||
user = self.resource = find_user
|
user = self.resource = find_user
|
||||||
|
|
||||||
if user_params[:sign_in_token_attempt].present? && session[:attempt_user_id]
|
if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
|
||||||
|
restart_session
|
||||||
|
elsif user_params.key?(:sign_in_token_attempt) && session[:attempt_user_id]
|
||||||
authenticate_with_sign_in_token_attempt(user)
|
authenticate_with_sign_in_token_attempt(user)
|
||||||
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
||||||
prompt_for_sign_in_token(user)
|
prompt_for_sign_in_token(user)
|
||||||
@ -27,7 +29,7 @@ module SignInTokenAuthenticationConcern
|
|||||||
|
|
||||||
def authenticate_with_sign_in_token_attempt(user)
|
def authenticate_with_sign_in_token_attempt(user)
|
||||||
if valid_sign_in_token_attempt?(user)
|
if valid_sign_in_token_attempt?(user)
|
||||||
session.delete(:attempt_user_id)
|
clear_attempt_from_session
|
||||||
remember_me(user)
|
remember_me(user)
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
else
|
else
|
||||||
@ -42,10 +44,10 @@ module SignInTokenAuthenticationConcern
|
|||||||
UserMailer.sign_in_token(user, request.remote_ip, request.user_agent, Time.now.utc.to_s).deliver_later!
|
UserMailer.sign_in_token(user, request.remote_ip, request.user_agent, Time.now.utc.to_s).deliver_later!
|
||||||
end
|
end
|
||||||
|
|
||||||
set_locale do
|
set_attempt_session(user)
|
||||||
session[:attempt_user_id] = user.id
|
|
||||||
@body_classes = 'lighter'
|
@body_classes = 'lighter'
|
||||||
render :sign_in_token
|
|
||||||
end
|
set_locale { render :sign_in_token }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -76,6 +76,7 @@ module SignatureVerification
|
|||||||
raise SignatureVerificationError, 'Signed request date outside acceptable time window' unless matches_time_window?
|
raise SignatureVerificationError, 'Signed request date outside acceptable time window' unless matches_time_window?
|
||||||
|
|
||||||
verify_signature_strength!
|
verify_signature_strength!
|
||||||
|
verify_body_digest!
|
||||||
|
|
||||||
account = account_from_key_id(signature_params['keyId'])
|
account = account_from_key_id(signature_params['keyId'])
|
||||||
|
|
||||||
@ -126,12 +127,21 @@ module SignatureVerification
|
|||||||
def verify_signature_strength!
|
def verify_signature_strength!
|
||||||
raise SignatureVerificationError, 'Mastodon requires the Date header or (created) pseudo-header to be signed' unless signed_headers.include?('date') || signed_headers.include?('(created)')
|
raise SignatureVerificationError, 'Mastodon requires the Date header or (created) pseudo-header to be signed' unless signed_headers.include?('date') || signed_headers.include?('(created)')
|
||||||
raise SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(Request::REQUEST_TARGET) || signed_headers.include?('digest')
|
raise SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(Request::REQUEST_TARGET) || signed_headers.include?('digest')
|
||||||
raise SignatureVerificationError, 'Mastodon requires the Host header to be signed' unless signed_headers.include?('host')
|
raise SignatureVerificationError, 'Mastodon requires the Host header to be signed when doing a GET request' if request.get? && !signed_headers.include?('host')
|
||||||
raise SignatureVerificationError, 'Mastodon requires the Digest header to be signed when doing a POST request' if request.post? && !signed_headers.include?('digest')
|
raise SignatureVerificationError, 'Mastodon requires the Digest header to be signed when doing a POST request' if request.post? && !signed_headers.include?('digest')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def verify_body_digest!
|
||||||
|
return unless signed_headers.include?('digest')
|
||||||
|
|
||||||
|
digests = request.headers['Digest'].split(',').map { |digest| digest.split('=', 2) }.map { |key, value| [key.downcase, value] }
|
||||||
|
sha256 = digests.assoc('sha-256')
|
||||||
|
raise SignatureVerificationError, "Mastodon only supports SHA-256 in Digest header. Offered algorithms: #{digests.map(&:first).join(', ')}" if sha256.nil?
|
||||||
|
raise SignatureVerificationError, "Invalid Digest value. Computed SHA-256 digest: #{body_digest}; given: #{sha256[1]}" if body_digest != sha256[1]
|
||||||
|
end
|
||||||
|
|
||||||
def verify_signature(account, signature, compare_signed_string)
|
def verify_signature(account, signature, compare_signed_string)
|
||||||
if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string)
|
if account.keypair.public_key.verify(OpenSSL::Digest.new('SHA256'), signature, compare_signed_string)
|
||||||
@signed_request_account = account
|
@signed_request_account = account
|
||||||
@signed_request_account
|
@signed_request_account
|
||||||
end
|
end
|
||||||
@ -153,8 +163,6 @@ module SignatureVerification
|
|||||||
raise SignatureVerificationError, 'Pseudo-header (expires) used but corresponding argument missing' if signature_params['expires'].blank?
|
raise SignatureVerificationError, 'Pseudo-header (expires) used but corresponding argument missing' if signature_params['expires'].blank?
|
||||||
|
|
||||||
"(expires): #{signature_params['expires']}"
|
"(expires): #{signature_params['expires']}"
|
||||||
elsif signed_header == 'digest'
|
|
||||||
"digest: #{body_digest}"
|
|
||||||
else
|
else
|
||||||
"#{signed_header}: #{request.headers[to_header_name(signed_header)]}"
|
"#{signed_header}: #{request.headers[to_header_name(signed_header)]}"
|
||||||
end
|
end
|
||||||
@ -187,7 +195,7 @@ module SignatureVerification
|
|||||||
end
|
end
|
||||||
|
|
||||||
def body_digest
|
def body_digest
|
||||||
"SHA-256=#{Digest::SHA256.base64digest(request_body)}"
|
@body_digest ||= Digest::SHA256.base64digest(request_body)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_header_name(name)
|
def to_header_name(name)
|
||||||
|
@ -8,7 +8,23 @@ module TwoFactorAuthenticationConcern
|
|||||||
end
|
end
|
||||||
|
|
||||||
def two_factor_enabled?
|
def two_factor_enabled?
|
||||||
find_user&.otp_required_for_login?
|
find_user&.two_factor_enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_webauthn_credential?(user, webauthn_credential)
|
||||||
|
user_credential = user.webauthn_credentials.find_by!(external_id: webauthn_credential.id)
|
||||||
|
|
||||||
|
begin
|
||||||
|
webauthn_credential.verify(
|
||||||
|
session[:webauthn_challenge],
|
||||||
|
public_key: user_credential.public_key,
|
||||||
|
sign_count: user_credential.sign_count
|
||||||
|
)
|
||||||
|
|
||||||
|
user_credential.update!(sign_count: webauthn_credential.sign_count)
|
||||||
|
rescue WebAuthn::Error
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_otp_attempt?(user)
|
def valid_otp_attempt?(user)
|
||||||
@ -21,16 +37,33 @@ module TwoFactorAuthenticationConcern
|
|||||||
def authenticate_with_two_factor
|
def authenticate_with_two_factor
|
||||||
user = self.resource = find_user
|
user = self.resource = find_user
|
||||||
|
|
||||||
if user_params[:otp_attempt].present? && session[:attempt_user_id]
|
if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
|
||||||
authenticate_with_two_factor_attempt(user)
|
restart_session
|
||||||
|
elsif user.webauthn_enabled? && user_params.key?(:credential) && session[:attempt_user_id]
|
||||||
|
authenticate_with_two_factor_via_webauthn(user)
|
||||||
|
elsif user_params.key?(:otp_attempt) && session[:attempt_user_id]
|
||||||
|
authenticate_with_two_factor_via_otp(user)
|
||||||
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
||||||
prompt_for_two_factor(user)
|
prompt_for_two_factor(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_with_two_factor_attempt(user)
|
def authenticate_with_two_factor_via_webauthn(user)
|
||||||
|
webauthn_credential = WebAuthn::Credential.from_get(user_params[:credential])
|
||||||
|
|
||||||
|
if valid_webauthn_credential?(user, webauthn_credential)
|
||||||
|
clear_attempt_from_session
|
||||||
|
remember_me(user)
|
||||||
|
sign_in(user)
|
||||||
|
render json: { redirect_path: root_path }, status: :ok
|
||||||
|
else
|
||||||
|
render json: { error: t('webauthn_credentials.invalid_credential') }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate_with_two_factor_via_otp(user)
|
||||||
if valid_otp_attempt?(user)
|
if valid_otp_attempt?(user)
|
||||||
session.delete(:attempt_user_id)
|
clear_attempt_from_session
|
||||||
remember_me(user)
|
remember_me(user)
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
else
|
else
|
||||||
@ -40,10 +73,18 @@ module TwoFactorAuthenticationConcern
|
|||||||
end
|
end
|
||||||
|
|
||||||
def prompt_for_two_factor(user)
|
def prompt_for_two_factor(user)
|
||||||
set_locale do
|
set_attempt_session(user)
|
||||||
session[:attempt_user_id] = user.id
|
|
||||||
@body_classes = 'lighter'
|
@body_classes = 'lighter'
|
||||||
render :two_factor
|
@webauthn_enabled = user.webauthn_enabled?
|
||||||
|
@scheme_type = begin
|
||||||
|
if user.webauthn_enabled? && user_params[:otp_attempt].blank?
|
||||||
|
'webauthn'
|
||||||
|
else
|
||||||
|
'totp'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_locale { render :two_factor }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -6,14 +6,13 @@ module UserTrackingConcern
|
|||||||
UPDATE_SIGN_IN_HOURS = 24
|
UPDATE_SIGN_IN_HOURS = 24
|
||||||
|
|
||||||
included do
|
included do
|
||||||
before_action :set_user_activity
|
before_action :update_user_sign_in
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_user_activity
|
def update_user_sign_in
|
||||||
return unless user_needs_sign_in_update?
|
current_user.update_sign_in!(request) if user_needs_sign_in_update?
|
||||||
current_user.update_tracked_fields!(request)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_needs_sign_in_update?
|
def user_needs_sign_in_update?
|
||||||
|
@ -9,7 +9,7 @@ class FiltersController < ApplicationController
|
|||||||
before_action :set_body_classes
|
before_action :set_body_classes
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@filters = current_account.custom_filters
|
@filters = current_account.custom_filters.order(:phrase)
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@ -52,6 +52,14 @@ class FollowerAccountsController < ApplicationController
|
|||||||
account_followers_url(@account, page: page) unless page.nil?
|
account_followers_url(@account, page: page) unless page.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def next_page_url
|
||||||
|
page_url(follows.next_page) if follows.respond_to?(:next_page)
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_page_url
|
||||||
|
page_url(follows.prev_page) if follows.respond_to?(:prev_page)
|
||||||
|
end
|
||||||
|
|
||||||
def collection_presenter
|
def collection_presenter
|
||||||
if page_requested?
|
if page_requested?
|
||||||
ActivityPub::CollectionPresenter.new(
|
ActivityPub::CollectionPresenter.new(
|
||||||
@ -60,8 +68,8 @@ class FollowerAccountsController < ApplicationController
|
|||||||
size: @account.followers_count,
|
size: @account.followers_count,
|
||||||
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
|
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
|
||||||
part_of: account_followers_url(@account),
|
part_of: account_followers_url(@account),
|
||||||
next: page_url(follows.next_page),
|
next: next_page_url,
|
||||||
prev: page_url(follows.prev_page)
|
prev: prev_page_url
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
ActivityPub::CollectionPresenter.new(
|
ActivityPub::CollectionPresenter.new(
|
||||||
|
@ -52,6 +52,14 @@ class FollowingAccountsController < ApplicationController
|
|||||||
account_following_index_url(@account, page: page) unless page.nil?
|
account_following_index_url(@account, page: page) unless page.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def next_page_url
|
||||||
|
page_url(follows.next_page) if follows.respond_to?(:next_page)
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_page_url
|
||||||
|
page_url(follows.prev_page) if follows.respond_to?(:prev_page)
|
||||||
|
end
|
||||||
|
|
||||||
def collection_presenter
|
def collection_presenter
|
||||||
if page_requested?
|
if page_requested?
|
||||||
ActivityPub::CollectionPresenter.new(
|
ActivityPub::CollectionPresenter.new(
|
||||||
@ -60,8 +68,8 @@ class FollowingAccountsController < ApplicationController
|
|||||||
size: @account.following_count,
|
size: @account.following_count,
|
||||||
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
|
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
|
||||||
part_of: account_following_index_url(@account),
|
part_of: account_following_index_url(@account),
|
||||||
next: page_url(follows.next_page),
|
next: next_page_url,
|
||||||
prev: page_url(follows.prev_page)
|
prev: prev_page_url
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
ActivityPub::CollectionPresenter.new(
|
ActivityPub::CollectionPresenter.new(
|
||||||
|
@ -17,6 +17,6 @@ class InstanceActorsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def restrict_fields_to
|
def restrict_fields_to
|
||||||
%i(id type preferred_username inbox public_key endpoints url manually_approves_followers)
|
%i(id type preferred_username inbox outbox public_key endpoints url manually_approves_followers)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,6 +5,7 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
|
|||||||
|
|
||||||
before_action :store_current_location
|
before_action :store_current_location
|
||||||
before_action :authenticate_resource_owner!
|
before_action :authenticate_resource_owner!
|
||||||
|
before_action :require_not_suspended!, only: :destroy
|
||||||
before_action :set_body_classes
|
before_action :set_body_classes
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
@ -25,4 +26,8 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
|
|||||||
def store_current_location
|
def store_current_location
|
||||||
store_location_for(:user, request.url)
|
store_location_for(:user, request.url)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def require_not_suspended!
|
||||||
|
forbidden if current_account.suspended?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,6 +5,7 @@ class RelationshipsController < ApplicationController
|
|||||||
|
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_accounts, only: :show
|
before_action :set_accounts, only: :show
|
||||||
|
before_action :set_relationships, only: :show
|
||||||
before_action :set_body_classes
|
before_action :set_body_classes
|
||||||
|
|
||||||
helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship?
|
helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship?
|
||||||
@ -28,6 +29,10 @@ class RelationshipsController < ApplicationController
|
|||||||
@accounts = RelationshipFilter.new(current_account, filter_params).results.page(params[:page]).per(40)
|
@accounts = RelationshipFilter.new(current_account, filter_params).results.page(params[:page]).per(40)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_relationships
|
||||||
|
@relationships = AccountRelationshipsPresenter.new(@accounts.pluck(:id), current_user.account_id)
|
||||||
|
end
|
||||||
|
|
||||||
def form_account_batch_params
|
def form_account_batch_params
|
||||||
params.require(:form_account_batch).permit(:action, account_ids: [])
|
params.require(:form_account_batch).permit(:action, account_ids: [])
|
||||||
end
|
end
|
||||||
@ -49,7 +54,9 @@ class RelationshipsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def action_from_button
|
def action_from_button
|
||||||
if params[:unfollow]
|
if params[:follow]
|
||||||
|
'follow'
|
||||||
|
elsif params[:unfollow]
|
||||||
'unfollow'
|
'unfollow'
|
||||||
elsif params[:remove_from_followers]
|
elsif params[:remove_from_followers]
|
||||||
'remove_from_followers'
|
'remove_from_followers'
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::AliasesController < Settings::BaseController
|
class Settings::AliasesController < Settings::BaseController
|
||||||
layout 'admin'
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
before_action :authenticate_user!
|
before_action :require_not_suspended!
|
||||||
before_action :set_aliases, except: :destroy
|
before_action :set_aliases, except: :destroy
|
||||||
before_action :set_alias, only: :destroy
|
before_action :set_alias, only: :destroy
|
||||||
|
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::ApplicationsController < Settings::BaseController
|
class Settings::ApplicationsController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :set_application, only: [:show, :update, :destroy, :regenerate]
|
before_action :set_application, only: [:show, :update, :destroy, :regenerate]
|
||||||
before_action :prepare_scopes, only: [:create, :update]
|
before_action :prepare_scopes, only: [:create, :update]
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::BaseController < ApplicationController
|
class Settings::BaseController < ApplicationController
|
||||||
|
layout 'admin'
|
||||||
|
|
||||||
|
before_action :authenticate_user!
|
||||||
before_action :set_body_classes
|
before_action :set_body_classes
|
||||||
before_action :set_cache_headers
|
before_action :set_cache_headers
|
||||||
|
|
||||||
@ -13,4 +16,8 @@ class Settings::BaseController < ApplicationController
|
|||||||
def set_cache_headers
|
def set_cache_headers
|
||||||
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def require_not_suspended!
|
||||||
|
forbidden if current_account.suspended?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::DeletesController < Settings::BaseController
|
class Settings::DeletesController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :check_enabled_deletion
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :require_not_suspended!
|
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
|
before_action :require_not_suspended!
|
||||||
|
before_action :check_enabled_deletion
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@confirmation = Form::DeleteConfirmation.new
|
@confirmation = Form::DeleteConfirmation.new
|
||||||
end
|
end
|
||||||
@ -45,8 +42,8 @@ class Settings::DeletesController < Settings::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def destroy_account!
|
def destroy_account!
|
||||||
current_account.suspend!
|
current_account.suspend!(origin: :local)
|
||||||
Admin::SuspensionWorker.perform_async(current_user.account_id, true)
|
AccountDeletionWorker.perform_async(current_user.account_id)
|
||||||
sign_out
|
sign_out
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
module Exports
|
module Exports
|
||||||
class BlockedAccountsController < ApplicationController
|
class BlockedAccountsController < BaseController
|
||||||
include ExportControllerConcern
|
include ExportControllerConcern
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
module Exports
|
module Exports
|
||||||
class BlockedDomainsController < ApplicationController
|
class BlockedDomainsController < BaseController
|
||||||
include ExportControllerConcern
|
include ExportControllerConcern
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
19
app/controllers/settings/exports/bookmarks_controller.rb
Normal file
19
app/controllers/settings/exports/bookmarks_controller.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Settings
|
||||||
|
module Exports
|
||||||
|
class BookmarksController < BaseController
|
||||||
|
include ExportControllerConcern
|
||||||
|
|
||||||
|
def index
|
||||||
|
send_export_file
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def export_data
|
||||||
|
@export.to_bookmarks_csv
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
module Exports
|
module Exports
|
||||||
class FollowingAccountsController < ApplicationController
|
class FollowingAccountsController < BaseController
|
||||||
include ExportControllerConcern
|
include ExportControllerConcern
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
module Exports
|
module Exports
|
||||||
class ListsController < ApplicationController
|
class ListsController < BaseController
|
||||||
include ExportControllerConcern
|
include ExportControllerConcern
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
module Exports
|
module Exports
|
||||||
class MutedAccountsController < ApplicationController
|
class MutedAccountsController < BaseController
|
||||||
include ExportControllerConcern
|
include ExportControllerConcern
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -3,11 +3,6 @@
|
|||||||
class Settings::ExportsController < Settings::BaseController
|
class Settings::ExportsController < Settings::BaseController
|
||||||
include Authorization
|
include Authorization
|
||||||
|
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :require_not_suspended!
|
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@ -16,8 +11,6 @@ class Settings::ExportsController < Settings::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
raise Mastodon::NotPermittedError unless user_signed_in?
|
|
||||||
|
|
||||||
backup = nil
|
backup = nil
|
||||||
|
|
||||||
RedisLock.acquire(lock_options) do |lock|
|
RedisLock.acquire(lock_options) do |lock|
|
||||||
@ -37,8 +30,4 @@ class Settings::ExportsController < Settings::BaseController
|
|||||||
def lock_options
|
def lock_options
|
||||||
{ redis: Redis.current, key: "backup:#{current_user.id}" }
|
{ redis: Redis.current, key: "backup:#{current_user.id}" }
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_not_suspended!
|
|
||||||
forbidden if current_account.suspended?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::FeaturedTagsController < Settings::BaseController
|
class Settings::FeaturedTagsController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :set_featured_tags, only: :index
|
before_action :set_featured_tags, only: :index
|
||||||
before_action :set_featured_tag, except: [:index, :create]
|
before_action :set_featured_tag, except: [:index, :create]
|
||||||
before_action :set_most_used_tags, only: :index
|
before_action :set_recently_used_tags, only: :index
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@featured_tag = FeaturedTag.new
|
@featured_tag = FeaturedTag.new
|
||||||
@ -20,7 +17,7 @@ class Settings::FeaturedTagsController < Settings::BaseController
|
|||||||
redirect_to settings_featured_tags_path
|
redirect_to settings_featured_tags_path
|
||||||
else
|
else
|
||||||
set_featured_tags
|
set_featured_tags
|
||||||
set_most_used_tags
|
set_recently_used_tags
|
||||||
|
|
||||||
render :index
|
render :index
|
||||||
end
|
end
|
||||||
@ -41,8 +38,8 @@ class Settings::FeaturedTagsController < Settings::BaseController
|
|||||||
@featured_tags = current_account.featured_tags.order(statuses_count: :desc).reject(&:new_record?)
|
@featured_tags = current_account.featured_tags.order(statuses_count: :desc).reject(&:new_record?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_most_used_tags
|
def set_recently_used_tags
|
||||||
@most_used_tags = Tag.most_used(current_account).where.not(id: @featured_tags.map(&:id)).limit(10)
|
@recently_used_tags = Tag.recently_used(current_account).where.not(id: @featured_tags.map(&:id)).limit(10)
|
||||||
end
|
end
|
||||||
|
|
||||||
def featured_tag_params
|
def featured_tag_params
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::IdentityProofsController < Settings::BaseController
|
class Settings::IdentityProofsController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :check_required_params, only: :new
|
before_action :check_required_params, only: :new
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::ImportsController < Settings::BaseController
|
class Settings::ImportsController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::Migration::RedirectsController < Settings::BaseController
|
class Settings::Migration::RedirectsController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :require_not_suspended!
|
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
|
before_action :require_not_suspended!
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@redirect = Form::Redirect.new
|
@redirect = Form::Redirect.new
|
||||||
end
|
end
|
||||||
@ -38,8 +35,4 @@ class Settings::Migration::RedirectsController < Settings::BaseController
|
|||||||
def resource_params
|
def resource_params
|
||||||
params.require(:form_redirect).permit(:acct, :current_password, :current_username)
|
params.require(:form_redirect).permit(:acct, :current_password, :current_username)
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_not_suspended!
|
|
||||||
forbidden if current_account.suspended?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::MigrationsController < Settings::BaseController
|
class Settings::MigrationsController < Settings::BaseController
|
||||||
layout 'admin'
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :require_not_suspended!
|
before_action :require_not_suspended!
|
||||||
before_action :set_migrations
|
before_action :set_migrations
|
||||||
before_action :set_cooldown
|
before_action :set_cooldown
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@migration = current_account.migrations.build
|
@migration = current_account.migrations.build
|
||||||
end
|
end
|
||||||
@ -44,8 +41,4 @@ class Settings::MigrationsController < Settings::BaseController
|
|||||||
def on_cooldown?
|
def on_cooldown?
|
||||||
@cooldown.present?
|
@cooldown.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_not_suspended!
|
|
||||||
forbidden if current_account.suspended?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
module Settings
|
module Settings
|
||||||
class PicturesController < BaseController
|
class PicturesController < BaseController
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
before_action :set_picture
|
before_action :set_picture
|
||||||
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::PreferencesController < Settings::BaseController
|
class Settings::PreferencesController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
|
|
||||||
def show; end
|
def show; end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@ -48,6 +44,7 @@ class Settings::PreferencesController < Settings::BaseController
|
|||||||
:setting_display_media,
|
:setting_display_media,
|
||||||
:setting_expand_spoilers,
|
:setting_expand_spoilers,
|
||||||
:setting_reduce_motion,
|
:setting_reduce_motion,
|
||||||
|
:setting_disable_swiping,
|
||||||
:setting_system_font_ui,
|
:setting_system_font_ui,
|
||||||
:setting_noindex,
|
:setting_noindex,
|
||||||
:setting_theme,
|
:setting_theme,
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::ProfilesController < Settings::BaseController
|
class Settings::ProfilesController < Settings::BaseController
|
||||||
layout 'admin'
|
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Settings::SessionsController < Settings::BaseController
|
class Settings::SessionsController < Settings::BaseController
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :set_session, only: :destroy
|
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
|
before_action :require_not_suspended!
|
||||||
|
before_action :set_session, only: :destroy
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@session.destroy!
|
@session.destroy!
|
||||||
flash[:notice] = I18n.t('sessions.revoke_success')
|
flash[:notice] = I18n.t('sessions.revoke_success')
|
||||||
|
@ -5,31 +5,31 @@ module Settings
|
|||||||
class ConfirmationsController < BaseController
|
class ConfirmationsController < BaseController
|
||||||
include ChallengableConcern
|
include ChallengableConcern
|
||||||
|
|
||||||
layout 'admin'
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
before_action :authenticate_user!
|
|
||||||
before_action :require_challenge!
|
before_action :require_challenge!
|
||||||
before_action :ensure_otp_secret
|
before_action :ensure_otp_secret
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
|
||||||
|
|
||||||
def new
|
def new
|
||||||
prepare_two_factor_form
|
prepare_two_factor_form
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
if current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt])
|
if current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt], otp_secret: session[:new_otp_secret])
|
||||||
flash.now[:notice] = I18n.t('two_factor_authentication.enabled_success')
|
flash.now[:notice] = I18n.t('two_factor_authentication.enabled_success')
|
||||||
|
|
||||||
current_user.otp_required_for_login = true
|
current_user.otp_required_for_login = true
|
||||||
|
current_user.otp_secret = session[:new_otp_secret]
|
||||||
@recovery_codes = current_user.generate_otp_backup_codes!
|
@recovery_codes = current_user.generate_otp_backup_codes!
|
||||||
current_user.save!
|
current_user.save!
|
||||||
|
|
||||||
UserMailer.two_factor_enabled(current_user).deliver_later!
|
UserMailer.two_factor_enabled(current_user).deliver_later!
|
||||||
|
|
||||||
|
session.delete(:new_otp_secret)
|
||||||
|
|
||||||
render 'settings/two_factor_authentication/recovery_codes/index'
|
render 'settings/two_factor_authentication/recovery_codes/index'
|
||||||
else
|
else
|
||||||
flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')
|
flash.now[:alert] = I18n.t('otp_authentication.wrong_code')
|
||||||
prepare_two_factor_form
|
prepare_two_factor_form
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
@ -43,12 +43,15 @@ module Settings
|
|||||||
|
|
||||||
def prepare_two_factor_form
|
def prepare_two_factor_form
|
||||||
@confirmation = Form::TwoFactorConfirmation.new
|
@confirmation = Form::TwoFactorConfirmation.new
|
||||||
@provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Rails.configuration.x.local_domain)
|
@new_otp_secret = session[:new_otp_secret]
|
||||||
|
@provision_url = current_user.otp_provisioning_uri(current_user.email,
|
||||||
|
otp_secret: @new_otp_secret,
|
||||||
|
issuer: Rails.configuration.x.local_domain)
|
||||||
@qrcode = RQRCode::QRCode.new(@provision_url)
|
@qrcode = RQRCode::QRCode.new(@provision_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_otp_secret
|
def ensure_otp_secret
|
||||||
redirect_to settings_two_factor_authentication_path unless current_user.otp_secret
|
redirect_to settings_otp_authentication_path if session[:new_otp_secret].blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user