Browse Source

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

No conflicts.
Thibaut Girka 1 month ago
parent
commit
5e0cf92fd1
57 changed files with 1105 additions and 446 deletions
  1. 242
    218
      CHANGELOG.md
  2. 2
    2
      Dockerfile
  3. 3
    3
      Gemfile
  4. 12
    12
      Gemfile.lock
  5. 1
    1
      app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
  6. 2
    0
      app/controllers/tags_controller.rb
  7. 5
    1
      app/javascript/mastodon/common.js
  8. 10
    2
      app/javascript/mastodon/components/display_name.js
  9. 1
    1
      app/javascript/mastodon/components/status.js
  10. 57
    29
      app/javascript/mastodon/features/standalone/hashtag_timeline/index.js
  11. 107
    25
      app/javascript/mastodon/features/status/components/detailed_status.js
  12. 172
    0
      app/javascript/mastodon/features/status/containers/detailed_status_container.js
  13. 4
    1
      app/javascript/mastodon/features/status/index.js
  14. 1
    1
      app/javascript/mastodon/features/ui/components/columns_area.js
  15. 6
    0
      app/javascript/mastodon/features/ui/index.js
  16. 1
    1
      app/javascript/mastodon/locales/ca.json
  17. 11
    11
      app/javascript/mastodon/locales/cy.json
  18. 37
    0
      app/javascript/mastodon/locales/defaultMessages.json
  19. 1
    1
      app/javascript/mastodon/locales/ro.json
  20. 1
    1
      app/javascript/mastodon/locales/sk.json
  21. 8
    0
      app/javascript/packs/public.js
  22. 1
    1
      app/javascript/styles/mastodon/about.scss
  23. 1
    1
      app/javascript/styles/mastodon/containers.scss
  24. 1
    1
      app/javascript/styles/mastodon/forms.scss
  25. 90
    0
      app/javascript/styles/mastodon/widgets.scss
  26. 13
    1
      app/lib/activitypub/activity/announce.rb
  27. 6
    3
      app/lib/activitypub/activity/create.rb
  28. 18
    2
      app/lib/activitypub/activity/delete.rb
  29. 2
    2
      app/models/status.rb
  30. 16
    0
      app/models/tombstone.rb
  31. 2
    1
      app/models/user.rb
  32. 6
    0
      app/services/activitypub/process_account_service.rb
  33. 1
    0
      app/services/precompute_feed_service.rb
  34. 15
    0
      app/services/unfollow_service.rb
  35. 16
    2
      app/views/directories/index.html.haml
  36. 0
    25
      app/views/tags/_features.html.haml
  37. 4
    28
      app/views/tags/show.html.haml
  38. 1
    1
      config/deploy.rb
  39. 3
    0
      config/initializers/paperclip.rb
  40. 3
    3
      config/locales/cs.yml
  41. 36
    36
      config/locales/de.yml
  42. 22
    0
      config/locales/devise.sr.yml
  43. 1
    1
      config/locales/doorkeeper.cs.yml
  44. 3
    0
      config/locales/en.yml
  45. 3
    1
      config/locales/ro.yml
  46. 13
    13
      config/locales/simple_form.de.yml
  47. 14
    0
      config/locales/simple_form.sr.yml
  48. 12
    0
      db/migrate/20190117114553_create_tombstones.rb
  49. 11
    1
      db/schema.rb
  50. 8
    0
      lib/cli.rb
  51. 2
    9
      lib/mastodon/domains_cli.rb
  52. 1
    1
      lib/mastodon/version.rb
  53. 48
    2
      lib/tasks/repo.rake
  54. 1
    0
      package.json
  55. 1
    1
      spec/controllers/tags_controller_spec.rb
  56. 18
    0
      spec/services/unfollow_service_spec.rb
  57. 28
    0
      yarn.lock

+ 242
- 218
CHANGELOG.md View File

@@ -6,301 +6,325 @@ All notable changes to this project will be documented in this file.
6 6
 ## [Unreleased]
7 7
 ### Added
8 8
 
9
-- Add link for adding a user to a list from their profile (#9062)
10
-- Add joining several hashtags in a single column (#8904)
11
-- Add volume sliders for videos (#9366)
12
-- Add a tooltip explaining what a locked account is (#9403)
13
-- Add preloaded cache for common JSON-LD contexts (#9412)
14
-- Add profile directory (#9427)
15
-- Add setting to not group reblogs in home feed (#9248)
16
-- Add admin ability to remove a user's header image (#9495)
17
-- Add account hashtags to ActivityPub actor JSON (#9450)
18
-- Add error message for avatar image that's too large (#9518)
19
-- Add notification quick-filter bar (#9399)
20
-- Add new first-time tutorial (#9531)
21
-- Add moderation warnings (#9519)
22
-- Add emoji codepoint mappings for v11.0 (#9618)
23
-- Add REST API for creating an account (#9572)
24
-- Add support for Malayalam in language filter (#9624)
25
-- Add exclude_reblogs option to account statuses API (#9640)
26
-- Add local followers page to admin account UI (#9610)
27
-- Add healthcheck commands to docker-compose.yml (#9143)
28
-- Add handler for Move activity to migrate followers (#9629)
29
-- Add CSV export for lists and domain blocks (#9677)
30
-- Add `tootctl accounts follow ACCT` (#9414)
31
-- Add scheduled statuses (#9706)
32
-- Add immutable caching for S3 objects (#9722)
33
-- Add cache to custom emojis API (#9732)
34
-- Add preview cards to non-detailed statuses on public pages (#9714)
35
-- Add `mod` and `moderator` to list of default reserved usernames (#9713)
36
-- Add quick links to the admin interface in the web UI (#8545)
9
+- Add link for adding a user to a list from their profile ([namelessGonbai](https://github.com/tootsuite/mastodon/pull/9062))
10
+- Add joining several hashtags in a single column ([gdpelican](https://github.com/tootsuite/mastodon/pull/8904))
11
+- Add volume sliders for videos ([sumdog](https://github.com/tootsuite/mastodon/pull/9366))
12
+- Add a tooltip explaining what a locked account is ([pawelngei](https://github.com/tootsuite/mastodon/pull/9403))
13
+- Add preloaded cache for common JSON-LD contexts ([ThibG](https://github.com/tootsuite/mastodon/pull/9412))
14
+- Add profile directory ([Gargron](https://github.com/tootsuite/mastodon/pull/9427))
15
+- Add setting to not group reblogs in home feed ([ThibG](https://github.com/tootsuite/mastodon/pull/9248))
16
+- Add admin ability to remove a user's header image ([ThibG](https://github.com/tootsuite/mastodon/pull/9495))
17
+- Add account hashtags to ActivityPub actor JSON ([Gargron](https://github.com/tootsuite/mastodon/pull/9450))
18
+- Add error message for avatar image that's too large ([sumdog](https://github.com/tootsuite/mastodon/pull/9518))
19
+- Add notification quick-filter bar ([pawelngei](https://github.com/tootsuite/mastodon/pull/9399))
20
+- Add new first-time tutorial ([Gargron](https://github.com/tootsuite/mastodon/pull/9531))
21
+- Add moderation warnings ([Gargron](https://github.com/tootsuite/mastodon/pull/9519))
22
+- Add emoji codepoint mappings for v11.0 ([Gargron](https://github.com/tootsuite/mastodon/pull/9618))
23
+- Add REST API for creating an account ([Gargron](https://github.com/tootsuite/mastodon/pull/9572))
24
+- Add support for Malayalam in language filter ([tachyons](https://github.com/tootsuite/mastodon/pull/9624))
25
+- Add exclude_reblogs option to account statuses API ([Gargron](https://github.com/tootsuite/mastodon/pull/9640))
26
+- Add local followers page to admin account UI ([chr-1x](https://github.com/tootsuite/mastodon/pull/9610))
27
+- Add healthcheck commands to docker-compose.yml ([BenLubar](https://github.com/tootsuite/mastodon/pull/9143))
28
+- Add handler for Move activity to migrate followers ([Gargron](https://github.com/tootsuite/mastodon/pull/9629))
29
+- Add CSV export for lists and domain blocks ([Gargron](https://github.com/tootsuite/mastodon/pull/9677))
30
+- Add `tootctl accounts follow ACCT` ([Gargron](https://github.com/tootsuite/mastodon/pull/9414))
31
+- Add scheduled statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/9706))
32
+- Add immutable caching for S3 objects ([nolanlawson](https://github.com/tootsuite/mastodon/pull/9722))
33
+- Add cache to custom emojis API ([Gargron](https://github.com/tootsuite/mastodon/pull/9732))
34
+- Add preview cards to non-detailed statuses on public pages ([Gargron](https://github.com/tootsuite/mastodon/pull/9714))
35
+- Add `mod` and `moderator` to list of default reserved usernames ([Gargron](https://github.com/tootsuite/mastodon/pull/9713))
36
+- Add quick links to the admin interface in the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/8545))
37
+- Add `tootctl domains crawl` ([Gargron](https://github.com/tootsuite/mastodon/pull/9809))
38
+- Add attachment list fallback to public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/9780))
39
+- Add `tootctl --version` ([Gargron](https://github.com/tootsuite/mastodon/pull/9835))
40
+- Add information about how to opt-in to the directory on the directory ([Gargron](https://github.com/tootsuite/mastodon/pull/9834))
41
+- Add timeouts for S3 ([Gargron](https://github.com/tootsuite/mastodon/pull/9842))
42
+- Add support for non-public reblogs from ActivityPub ([Gargron](https://github.com/tootsuite/mastodon/pull/9841))
43
+- Add sending of `Reject` activity when sending a `Block` activity ([ThibG](https://github.com/tootsuite/mastodon/pull/9811))
37 44
 
38 45
 ### Changed
39 46
 
40
-- Temporarily pause timeline if mouse moved recently (#9200)
41
-- Change the password form order (#9267)
42
-- Redesign admin UI for accounts (#9340, #9643)
43
-- Redesign admin UI for instances/domain blocks (#9645)
44
-- Swap avatar and header input fields in profile page (#9271)
45
-- When posting in mobile mode, go back to previous history location (#9502)
46
-- Split out is_changing_upload from is_submitting (#9536)
47
-- Back to the getting-started when pins the timeline. (#9561)
48
-- Allow unauthenticated REST API access to GET /api/v1/accounts/:id/statuses (#9573)
49
-- Limit maximum visibility of local silenced users to unlisted (#9583)
50
-- Change API error message for unconfirmed accounts (#9625)
51
-- Change the icon to "reply-all" when it's a reply to other accounts (#9378)
52
-- Do not ignore federated reports targetting already-reported accounts (#9534)
53
-- Upgrade default Ruby version to 2.6.0 (#9688)
54
-- Change e-mail digest frequency (#9689)
55
-- Change Docker images for Tor support in docker-compose.yml (#9438)
56
-- Display fallback link card thumbnail when none is given (#9715)
57
-- Change account bio length validation to ignore mention domains and URLs (#9717)
58
-- Use configured contact user for "anonymous" federation activities (#9661)
59
-- Change remote interaction dialog to use specific actions instead of generic "interact" (#9743)
60
-- Always re-fetch public key when signature verification fails to support blind key rotation (#9667)
61
-- Make replies to boosts impossible, connect reply to original status instead (#9129)
62
-- Change e-mail MX validation to check both A and MX records against blacklist (#9489)
47
+- Temporarily pause timeline if mouse moved recently ([lmorchard](https://github.com/tootsuite/mastodon/pull/9200))
48
+- Change the password form order ([mayaeh](https://github.com/tootsuite/mastodon/pull/9267))
49
+- Redesign admin UI for accounts ([Gargron](https://github.com/tootsuite/mastodon/pull/9340), [Gargron](https://github.com/tootsuite/mastodon/pull/9643))
50
+- Redesign admin UI for instances/domain blocks ([Gargron](https://github.com/tootsuite/mastodon/pull/9645))
51
+- Swap avatar and header input fields in profile page ([ThibG](https://github.com/tootsuite/mastodon/pull/9271))
52
+- When posting in mobile mode, go back to previous history location ([ThibG](https://github.com/tootsuite/mastodon/pull/9502))
53
+- Split out is_changing_upload from is_submitting ([ThibG](https://github.com/tootsuite/mastodon/pull/9536))
54
+- Back to the getting-started when pins the timeline. ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/9561))
55
+- Allow unauthenticated REST API access to GET /api/v1/accounts/:id/statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/9573))
56
+- Limit maximum visibility of local silenced users to unlisted ([ThibG](https://github.com/tootsuite/mastodon/pull/9583))
57
+- Change API error message for unconfirmed accounts ([noellabo](https://github.com/tootsuite/mastodon/pull/9625))
58
+- Change the icon to "reply-all" when it's a reply to other accounts ([mayaeh](https://github.com/tootsuite/mastodon/pull/9378))
59
+- Do not ignore federated reports targetting already-reported accounts ([ThibG](https://github.com/tootsuite/mastodon/pull/9534))
60
+- Upgrade default Ruby version to 2.6.0 ([Gargron](https://github.com/tootsuite/mastodon/pull/9688))
61
+- Change e-mail digest frequency ([Gargron](https://github.com/tootsuite/mastodon/pull/9689))
62
+- Change Docker images for Tor support in docker-compose.yml ([Sir-Boops](https://github.com/tootsuite/mastodon/pull/9438))
63
+- Display fallback link card thumbnail when none is given ([Gargron](https://github.com/tootsuite/mastodon/pull/9715))
64
+- Change account bio length validation to ignore mention domains and URLs ([Gargron](https://github.com/tootsuite/mastodon/pull/9717))
65
+- Use configured contact user for "anonymous" federation activities ([yukimochi](https://github.com/tootsuite/mastodon/pull/9661))
66
+- Change remote interaction dialog to use specific actions instead of generic "interact" ([Gargron](https://github.com/tootsuite/mastodon/pull/9743))
67
+- Always re-fetch public key when signature verification fails to support blind key rotation ([ThibG](https://github.com/tootsuite/mastodon/pull/9667))
68
+- Make replies to boosts impossible, connect reply to original status instead ([valerauko](https://github.com/tootsuite/mastodon/pull/9129))
69
+- Change e-mail MX validation to check both A and MX records against blacklist ([Gargron](https://github.com/tootsuite/mastodon/pull/9489))
70
+- Hide floating action button on search and getting started pages ([tmm576](https://github.com/tootsuite/mastodon/pull/9826))
71
+- Redesign public hashtag page to use a masonry layout ([Gargron](https://github.com/tootsuite/mastodon/pull/9822))
72
+- Use `summary` as summary instead of content warning for converted ActivityPub objects ([Gargron](https://github.com/tootsuite/mastodon/pull/9823))
73
+- Display a double reply arrow on public pages for toots that are replies ([ThibG](https://github.com/tootsuite/mastodon/pull/9808))
74
+- Change admin UI right panel size to be wider ([Kjwon15](https://github.com/tootsuite/mastodon/pull/9768))
63 75
 
64 76
 ### Removed
65 77
 
66
-- Remove links to bridge.joinmastodon.org (non-functional) (#9608)
67
-- Remove LD-Signatures from activities that do not need them (#9659)
78
+- Remove links to bridge.joinmastodon.org (non-functional) ([Gargron](https://github.com/tootsuite/mastodon/pull/9608))
79
+- Remove LD-Signatures from activities that do not need them ([ThibG](https://github.com/tootsuite/mastodon/pull/9659))
68 80
 
69 81
 ### Fixed
70 82
 
71
-- Remove unused computation of reblog references from updateTimeline (#9244)
72
-- Fix loaded embeds resetting if a status arrives from API again (#9270)
73
-- Fix race condition causing shallow status with only a "favourited" attribute (#9272)
74
-- Remove intermediary arrays when creating hash maps from results (#9291)
75
-- Extract counters from accounts table to account_stats table to improve performance (#9295)
76
-- Change identities id column to a bigint (#9371)
77
-- Fix conversations API pagination (#9407)
78
-- Improve account suspension speed and completeness (#9290)
79
-- Fix thread depth computation in statuses_controller (#9426)
80
-- Fix database deadlocks by moving account stats update outside transaction (#9437)
81
-- Escape HTML in profile name preview in profile settings (#9446)
82
-- Use same CORS policy for /@:username and /users/:username (#9485)
83
-- Make custom emoji domains case insensitive (#9474)
84
-- Various fixes to scrollable lists and media gallery (#9501)
85
-- Fix bootsnap cache directory being declared relatively (#9511)
86
-- Fix timeline pagination in the web UI (#9516)
87
-- Fix padding on dropdown elements in preferences (#9517)
88
-- Make avatar and headers respect GIF autoplay settings (#9515)
89
-- Do no retry Web Push workers if the server returns a 4xx response (#9434)
90
-- Minor scrollable list fixes (#9551)
91
-- Ignore low-confidence CharlockHolmes guesses when parsing link cards (#9510)
92
-- Fix `tootctl accounts rotate` not updating public keys (#9556)
93
-- Fix CSP / X-Frame-Options for media players (#9558)
94
-- Fix unnecessary loadMore calls when the end of a timeline has been reached (#9581)
95
-- Skip mailer job retries when a record no longer exists (#9590)
96
-- Fix composer not getting focus after reply confirmation dialog (#9602)
97
-- Fix signature verification stoplight triggering on non-timeout errors (#9617)
98
-- Fix ThreadResolveWorker getting queued with invalid URLs (#9628)
99
-- Fix crash when clearing uninitialized timeline (#9662)
100
-- Avoid duplicate work by merging ReplyDistributionWorker into DistributionWorker (#9660)
101
-- Skip full text search if it fails, instead of erroring out completely (#9654)
102
-- Fix profile metadata links not verifying correctly sometimes (#9673)
103
-- Ensure blocked user unfollows blocker if Block/Undo-Block activities are processed out of order (#9687)
104
-- Fix unreadable text color in report modal for some statuses (#9716)
105
-- Stop GIFV timeline preview explicitly when it's opened in modal (#9749)
83
+- Remove unused computation of reblog references from updateTimeline ([ThibG](https://github.com/tootsuite/mastodon/pull/9244))
84
+- Fix loaded embeds resetting if a status arrives from API again ([ThibG](https://github.com/tootsuite/mastodon/pull/9270))
85
+- Fix race condition causing shallow status with only a "favourited" attribute ([ThibG](https://github.com/tootsuite/mastodon/pull/9272))
86
+- Remove intermediary arrays when creating hash maps from results ([Gargron](https://github.com/tootsuite/mastodon/pull/9291))
87
+- Extract counters from accounts table to account_stats table to improve performance ([Gargron](https://github.com/tootsuite/mastodon/pull/9295))
88
+- Change identities id column to a bigint ([Gargron](https://github.com/tootsuite/mastodon/pull/9371))
89
+- Fix conversations API pagination ([ThibG](https://github.com/tootsuite/mastodon/pull/9407))
90
+- Improve account suspension speed and completeness ([Gargron](https://github.com/tootsuite/mastodon/pull/9290))
91
+- Fix thread depth computation in statuses_controller ([ThibG](https://github.com/tootsuite/mastodon/pull/9426))
92
+- Fix database deadlocks by moving account stats update outside transaction ([ThibG](https://github.com/tootsuite/mastodon/pull/9437))
93
+- Escape HTML in profile name preview in profile settings ([pawelngei](https://github.com/tootsuite/mastodon/pull/9446))
94
+- Use same CORS policy for /@:username and /users/:username ([ThibG](https://github.com/tootsuite/mastodon/pull/9485))
95
+- Make custom emoji domains case insensitive ([Esteth](https://github.com/tootsuite/mastodon/pull/9474))
96
+- Various fixes to scrollable lists and media gallery ([ThibG](https://github.com/tootsuite/mastodon/pull/9501))
97
+- Fix bootsnap cache directory being declared relatively ([Gargron](https://github.com/tootsuite/mastodon/pull/9511))
98
+- Fix timeline pagination in the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9516))
99
+- Fix padding on dropdown elements in preferences ([ThibG](https://github.com/tootsuite/mastodon/pull/9517))
100
+- Make avatar and headers respect GIF autoplay settings ([ThibG](https://github.com/tootsuite/mastodon/pull/9515))
101
+- Do no retry Web Push workers if the server returns a 4xx response ([Gargron](https://github.com/tootsuite/mastodon/pull/9434))
102
+- Minor scrollable list fixes ([ThibG](https://github.com/tootsuite/mastodon/pull/9551))
103
+- Ignore low-confidence CharlockHolmes guesses when parsing link cards ([ThibG](https://github.com/tootsuite/mastodon/pull/9510))
104
+- Fix `tootctl accounts rotate` not updating public keys ([Gargron](https://github.com/tootsuite/mastodon/pull/9556))
105
+- Fix CSP / X-Frame-Options for media players ([jomo](https://github.com/tootsuite/mastodon/pull/9558))
106
+- Fix unnecessary loadMore calls when the end of a timeline has been reached ([ThibG](https://github.com/tootsuite/mastodon/pull/9581))
107
+- Skip mailer job retries when a record no longer exists ([Gargron](https://github.com/tootsuite/mastodon/pull/9590))
108
+- Fix composer not getting focus after reply confirmation dialog ([ThibG](https://github.com/tootsuite/mastodon/pull/9602))
109
+- Fix signature verification stoplight triggering on non-timeout errors ([Gargron](https://github.com/tootsuite/mastodon/pull/9617))
110
+- Fix ThreadResolveWorker getting queued with invalid URLs ([Gargron](https://github.com/tootsuite/mastodon/pull/9628))
111
+- Fix crash when clearing uninitialized timeline ([ThibG](https://github.com/tootsuite/mastodon/pull/9662))
112
+- Avoid duplicate work by merging ReplyDistributionWorker into DistributionWorker ([ThibG](https://github.com/tootsuite/mastodon/pull/9660))
113
+- Skip full text search if it fails, instead of erroring out completely ([Kjwon15](https://github.com/tootsuite/mastodon/pull/9654))
114
+- Fix profile metadata links not verifying correctly sometimes ([shrft](https://github.com/tootsuite/mastodon/pull/9673))
115
+- Ensure blocked user unfollows blocker if Block/Undo-Block activities are processed out of order ([ThibG](https://github.com/tootsuite/mastodon/pull/9687))
116
+- Fix unreadable text color in report modal for some statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/9716))
117
+- Stop GIFV timeline preview explicitly when it's opened in modal ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/9749))
118
+- Fix scrollbar width compensation ([ThibG](https://github.com/tootsuite/mastodon/pull/9824))
119
+- Fix race conditions when processing deleted toots ([ThibG](https://github.com/tootsuite/mastodon/pull/9815))
120
+- Fix SSO issues on WebKit browsers by disabling Same-Site cookie again ([moritzheiber](https://github.com/tootsuite/mastodon/pull/9819))
121
+- Fix empty OEmbed error ([renatolond](https://github.com/tootsuite/mastodon/pull/9807))
122
+- Fix drag & drop modal not disappearing sometimes ([hinaloe](https://github.com/tootsuite/mastodon/pull/9797))
123
+- Fix statuses with content warnings being displayed in web push notifications sometimes ([ThibG](https://github.com/tootsuite/mastodon/pull/9778))
124
+- Fix scroll-to-detailed status not working on public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/9773))
125
+- Fix media modal loading indicator ([ThibG](https://github.com/tootsuite/mastodon/pull/9771))
126
+- Fix hashtag search results not having a permalink fallback in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9810))
127
+- Fix slightly cropped font on settings page dropdowns when using system font ([ariasuni](https://github.com/tootsuite/mastodon/pull/9839))
128
+- Fix not being able to drag & drop text into forms ([tmm576](https://github.com/tootsuite/mastodon/pull/9840))
106 129
 
107 130
 ### Security
108 131
 
109
-- Sanitize and sandbox toot embeds in web UI (#9552)
132
+- Sanitize and sandbox toot embeds in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9552))
133
+- Add tombstones for remote statuses to prevent replay attacks ([ThibG](https://github.com/tootsuite/mastodon/pull/9830))
110 134
 
111 135
 ## [2.6.5] - 2018-12-01
112 136
 ### Changed
113 137
 
114
-- Change lists to display replies to others on the list and list owner (#9324)
138
+- Change lists to display replies to others on the list and list owner ([ThibG](https://github.com/tootsuite/mastodon/pull/9324))
115 139
 
116 140
 ### Fixed
117 141
 
118
-- Fix failures caused by commonly-used JSON-LD contexts being unavailable (#9412)
142
+- Fix failures caused by commonly-used JSON-LD contexts being unavailable ([ThibG](https://github.com/tootsuite/mastodon/pull/9412))
119 143
 
120 144
 ## [2.6.4] - 2018-11-30
121 145
 ### Fixed
122 146
 
123
-- Fix yarn dependencies not installing due to yanked event-stream package (#9401)
147
+- Fix yarn dependencies not installing due to yanked event-stream package ([Gargron](https://github.com/tootsuite/mastodon/pull/9401))
124 148
 
125 149
 ## [2.6.3] - 2018-11-30
126 150
 ### Added
127 151
 
128
-- Add hyphen to characters allowed in remote usernames (#9345)
152
+- Add hyphen to characters allowed in remote usernames ([ThibG](https://github.com/tootsuite/mastodon/pull/9345))
129 153
 
130 154
 ### Changed
131 155
 
132
-- Change server user count to exclude suspended accounts (#9380)
156
+- Change server user count to exclude suspended accounts ([Gargron](https://github.com/tootsuite/mastodon/pull/9380))
133 157
 
134 158
 ### Fixed
135 159
 
136
-- Fix ffmpeg processing sometimes stalling due to overfilled stdout buffer (#9368)
137
-- Fix missing DNS records raising the wrong kind of exception (#9379)
138
-- Fix already queued deliveries still trying to reach inboxes marked as unavailable (#9358)
160
+- Fix ffmpeg processing sometimes stalling due to overfilled stdout buffer ([hugogameiro](https://github.com/tootsuite/mastodon/pull/9368))
161
+- Fix missing DNS records raising the wrong kind of exception ([Gargron](https://github.com/tootsuite/mastodon/pull/9379))
162
+- Fix already queued deliveries still trying to reach inboxes marked as unavailable ([Gargron](https://github.com/tootsuite/mastodon/pull/9358))
139 163
 
140 164
 ### Security
141 165
 
142
-- Fix TLS handshake timeout not being enforced (#9381)
166
+- Fix TLS handshake timeout not being enforced ([Gargron](https://github.com/tootsuite/mastodon/pull/9381))
143 167
 
144 168
 ## [2.6.2] - 2018-11-23
145 169
 ### Added
146 170
 
147
-- Add Page to whitelisted ActivityPub types (#9188)
148
-- Add 20px to column width in web UI (#9227)
149
-- Add amount of freed disk space in `tootctl media remove` (#9229, #9239, #9288)
150
-- Add "Show thread" link to self-replies (#9228)
171
+- Add Page to whitelisted ActivityPub types ([mbajur](https://github.com/tootsuite/mastodon/pull/9188))
172
+- Add 20px to column width in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/9227))
173
+- Add amount of freed disk space in `tootctl media remove` ([Gargron](https://github.com/tootsuite/mastodon/pull/9229), [Gargron](https://github.com/tootsuite/mastodon/pull/9239), [mayaeh](https://github.com/tootsuite/mastodon/pull/9288))
174
+- Add "Show thread" link to self-replies ([Gargron](https://github.com/tootsuite/mastodon/pull/9228))
151 175
 
152 176
 ### Changed
153 177
 
154
-- Change order of Atom and RSS links so Atom is first (#9302)
155
-- Change Nginx configuration for Nanobox apps (#9310)
156
-- Change the follow action to appear instant in web UI (#9220)
157
-- Change how the ActiveRecord connection is instantiated in on_worker_boot (#9238)
158
-- Change `tootctl accounts cull` to always touch accounts so they can be skipped (#9293)
159
-- Change mime type comparison to ignore JSON-LD profile (#9179)
178
+- Change order of Atom and RSS links so Atom is first ([Alkarex](https://github.com/tootsuite/mastodon/pull/9302))
179
+- Change Nginx configuration for Nanobox apps ([danhunsaker](https://github.com/tootsuite/mastodon/pull/9310))
180
+- Change the follow action to appear instant in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/9220))
181
+- Change how the ActiveRecord connection is instantiated in on_worker_boot ([Gargron](https://github.com/tootsuite/mastodon/pull/9238))
182
+- Change `tootctl accounts cull` to always touch accounts so they can be skipped ([renatolond](https://github.com/tootsuite/mastodon/pull/9293))
183
+- Change mime type comparison to ignore JSON-LD profile ([valerauko](https://github.com/tootsuite/mastodon/pull/9179))
160 184
 
161 185
 ### Fixed
162 186
 
163
-- Fix web UI crash when conversation has no last status (#9207)
164
-- Fix follow limit validator reporting lower number past threshold (#9230)
165
-- Fix form validation flash message color and input borders (#9235)
166
-- Fix invalid twitter:player cards being displayed (#9254)
167
-- Fix emoji update date being processed incorrectly (#9255)
168
-- Fix playing embed resetting if status is reloaded in web UI (#9270, #9275)
169
-- Fix web UI crash when favouriting a deleted status (#9272)
170
-- Fix intermediary arrays being created for hash maps (#9291)
171
-- Fix filter ID not being a string in REST API (#9303)
187
+- Fix web UI crash when conversation has no last status ([sammy8806](https://github.com/tootsuite/mastodon/pull/9207))
188
+- Fix follow limit validator reporting lower number past threshold ([Gargron](https://github.com/tootsuite/mastodon/pull/9230))
189
+- Fix form validation flash message color and input borders ([Gargron](https://github.com/tootsuite/mastodon/pull/9235))
190
+- Fix invalid twitter:player cards being displayed ([ThibG](https://github.com/tootsuite/mastodon/pull/9254))
191
+- Fix emoji update date being processed incorrectly ([ThibG](https://github.com/tootsuite/mastodon/pull/9255))
192
+- Fix playing embed resetting if status is reloaded in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9270), [Gargron](https://github.com/tootsuite/mastodon/pull/9275))
193
+- Fix web UI crash when favouriting a deleted status ([ThibG](https://github.com/tootsuite/mastodon/pull/9272))
194
+- Fix intermediary arrays being created for hash maps ([Gargron](https://github.com/tootsuite/mastodon/pull/9291))
195
+- Fix filter ID not being a string in REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/9303))
172 196
 
173 197
 ### Security
174 198
 
175
-- Fix multiple remote account deletions being able to deadlock the database (#9292)
176
-- Fix HTTP connection timeout of 10s not being enforced (#9329)
199
+- Fix multiple remote account deletions being able to deadlock the database ([Gargron](https://github.com/tootsuite/mastodon/pull/9292))
200
+- Fix HTTP connection timeout of 10s not being enforced ([Gargron](https://github.com/tootsuite/mastodon/pull/9329))
177 201
 
178 202
 ## [2.6.1] - 2018-10-30
179 203
 ### Fixed
180 204
 
181
-- Fix resolving resources by URL not working due to a regression in #9132 (#9171)
182
-- Fix reducer error in web UI when a conversation has no last status (#9173)
205
+- Fix resolving resources by URL not working due to a regression in [valerauko](https://github.com/tootsuite/mastodon/pull/9132) ([Gargron](https://github.com/tootsuite/mastodon/pull/9171))
206
+- Fix reducer error in web UI when a conversation has no last status ([Gargron](https://github.com/tootsuite/mastodon/pull/9173))
183 207
 
184 208
 ## [2.6.0] - 2018-10-30
185 209
 ### Added
186 210
 
187
-- Add link ownership verification (#8703)
188
-- Add conversations API (#8832)
189
-- Add limit for the number of people that can be followed from one account (#8807)
190
-- Add admin setting to customize mascot (#8766)
191
-- Add support for more granular ActivityPub audiences from other software, i.e. circles (#8950, #9093, #9150)
192
-- Add option to block all reports from a domain (#8830)
193
-- Add user preference to always expand toots marked with content warnings (#8762)
194
-- Add user preference to always hide all media (#8569)
195
-- Add `force_login` param to OAuth authorize page (#8655)
196
-- Add `tootctl accounts backup` (#8642, #8811)
197
-- Add `tootctl accounts create` (#8642, #8811)
198
-- Add `tootctl accounts cull` (#8642, #8811)
199
-- Add `tootctl accounts delete` (#8642, #8811)
200
-- Add `tootctl accounts modify` (#8642, #8811)
201
-- Add `tootctl accounts refresh` (#8642, #8811)
202
-- Add `tootctl feeds build` (#8642, #8811)
203
-- Add `tootctl feeds clear` (#8642, #8811)
204
-- Add `tootctl settings registrations open` (#8642, #8811)
205
-- Add `tootctl settings registrations close` (#8642, #8811)
206
-- Add `min_id` param to REST API to support backwards pagination (#8736)
207
-- Add a confirmation dialog when hitting reply and the compose box isn't empty (#8893)
208
-- Add PostgreSQL disk space growth tracking in PGHero (#8906)
209
-- Add button for disabling local account to report quick actions bar (#9024)
210
-- Add Czech language (#8594)
211
-- Add `same-site` (`lax`) attribute to cookies (#8626)
212
-- Add support for styled scrollbars in Firefox Nightly (#8653)
213
-- Add highlight to the active tab in web UI profiles (#8673)
214
-- Add auto-focus for comment textarea in report modal (#8689)
215
-- Add auto-focus for emoji picker's search field (#8688)
216
-- Add nginx and systemd templates to `dist/` directory (#8770)
217
-- Add support for `/.well-known/change-password` (#8828)
218
-- Add option to override FFMPEG binary path (#8855)
219
-- Add `dns-prefetch` tag when using different host for assets or uploads (#8942)
220
-- Add `description` meta tag (#8941)
221
-- Add `Content-Security-Policy` header (#8957)
222
-- Add cache for the instance info API (#8765)
223
-- Add suggested follows to search screen in mobile layout (#9010)
224
-- Add CORS header to `/.well-known/*` routes (#9083)
225
-- Add `card` attribute to statuses returned from REST API (#9120)
226
-- Add in-stream link preview (#9120)
227
-- Add support for ActivityPub `Page` objects (#9121)
211
+- Add link ownership verification ([Gargron](https://github.com/tootsuite/mastodon/pull/8703))
212
+- Add conversations API ([Gargron](https://github.com/tootsuite/mastodon/pull/8832))
213
+- Add limit for the number of people that can be followed from one account ([Gargron](https://github.com/tootsuite/mastodon/pull/8807))
214
+- Add admin setting to customize mascot ([ashleyhull-versent](https://github.com/tootsuite/mastodon/pull/8766))
215
+- Add support for more granular ActivityPub audiences from other software, i.e. circles ([Gargron](https://github.com/tootsuite/mastodon/pull/8950), [Gargron](https://github.com/tootsuite/mastodon/pull/9093), [Gargron](https://github.com/tootsuite/mastodon/pull/9150))
216
+- Add option to block all reports from a domain ([Gargron](https://github.com/tootsuite/mastodon/pull/8830))
217
+- Add user preference to always expand toots marked with content warnings ([webroo](https://github.com/tootsuite/mastodon/pull/8762))
218
+- Add user preference to always hide all media ([fvh-P](https://github.com/tootsuite/mastodon/pull/8569))
219
+- Add `force_login` param to OAuth authorize page ([Gargron](https://github.com/tootsuite/mastodon/pull/8655))
220
+- Add `tootctl accounts backup` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
221
+- Add `tootctl accounts create` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
222
+- Add `tootctl accounts cull` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
223
+- Add `tootctl accounts delete` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
224
+- Add `tootctl accounts modify` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
225
+- Add `tootctl accounts refresh` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
226
+- Add `tootctl feeds build` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
227
+- Add `tootctl feeds clear` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
228
+- Add `tootctl settings registrations open` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
229
+- Add `tootctl settings registrations close` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811))
230
+- Add `min_id` param to REST API to support backwards pagination ([Gargron](https://github.com/tootsuite/mastodon/pull/8736))
231
+- Add a confirmation dialog when hitting reply and the compose box isn't empty ([ThibG](https://github.com/tootsuite/mastodon/pull/8893))
232
+- Add PostgreSQL disk space growth tracking in PGHero ([Gargron](https://github.com/tootsuite/mastodon/pull/8906))
233
+- Add button for disabling local account to report quick actions bar ([Gargron](https://github.com/tootsuite/mastodon/pull/9024))
234
+- Add Czech language ([Aditoo17](https://github.com/tootsuite/mastodon/pull/8594))
235
+- Add `same-site` (`lax`) attribute to cookies ([sorin-davidoi](https://github.com/tootsuite/mastodon/pull/8626))
236
+- Add support for styled scrollbars in Firefox Nightly ([sorin-davidoi](https://github.com/tootsuite/mastodon/pull/8653))
237
+- Add highlight to the active tab in web UI profiles ([rhoio](https://github.com/tootsuite/mastodon/pull/8673))
238
+- Add auto-focus for comment textarea in report modal ([ThibG](https://github.com/tootsuite/mastodon/pull/8689))
239
+- Add auto-focus for emoji picker's search field ([ThibG](https://github.com/tootsuite/mastodon/pull/8688))
240
+- Add nginx and systemd templates to `dist/` directory ([Gargron](https://github.com/tootsuite/mastodon/pull/8770))
241
+- Add support for `/.well-known/change-password` ([Gargron](https://github.com/tootsuite/mastodon/pull/8828))
242
+- Add option to override FFMPEG binary path ([sascha-sl](https://github.com/tootsuite/mastodon/pull/8855))
243
+- Add `dns-prefetch` tag when using different host for assets or uploads ([Gargron](https://github.com/tootsuite/mastodon/pull/8942))
244
+- Add `description` meta tag ([Gargron](https://github.com/tootsuite/mastodon/pull/8941))
245
+- Add `Content-Security-Policy` header ([ThibG](https://github.com/tootsuite/mastodon/pull/8957))
246
+- Add cache for the instance info API ([ykzts](https://github.com/tootsuite/mastodon/pull/8765))
247
+- Add suggested follows to search screen in mobile layout ([Gargron](https://github.com/tootsuite/mastodon/pull/9010))
248
+- Add CORS header to `/.well-known/*` routes ([BenLubar](https://github.com/tootsuite/mastodon/pull/9083))
249
+- Add `card` attribute to statuses returned from REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/9120))
250
+- Add in-stream link preview ([Gargron](https://github.com/tootsuite/mastodon/pull/9120))
251
+- Add support for ActivityPub `Page` objects ([mbajur](https://github.com/tootsuite/mastodon/pull/9121))
228 252
 
229 253
 ### Changed
230 254
 
231
-- Change forms design (#8703)
232
-- Change reports overview to group by target account (#8674)
233
-- Change web UI to show "read more" link on overly long in-stream statuses (#8205)
234
-- Change design of direct messages column (#8832, #9022)
235
-- Change home timelines to exclude DMs (#8940)
236
-- Change list timelines to exclude all replies (#8683)
237
-- Change admin accounts UI default sort to most recent (#8813)
238
-- Change documentation URL in the UI (#8898)
239
-- Change style of success and failure messages (#8973)
240
-- Change DM filtering to always allow DMs from staff (#8993)
241
-- Change recommended Ruby version to 2.5.3 (#9003)
242
-- Change docker-compose default to persist volumes in current directory (#9055)
243
-- Change character counters on edit profile page to input length limit (#9100)
244
-- Change notification filtering to always let through messages from staff (#9152)
245
-- Change "hide boosts from user" function also hiding notifications about boosts (#9147)
246
-- Change CSS `detailed-status__wrapper` class actually wrap the detailed status (#8547)
255
+- Change forms design ([Gargron](https://github.com/tootsuite/mastodon/pull/8703))
256
+- Change reports overview to group by target account ([Gargron](https://github.com/tootsuite/mastodon/pull/8674))
257
+- Change web UI to show "read more" link on overly long in-stream statuses ([lanodan](https://github.com/tootsuite/mastodon/pull/8205))
258
+- Change design of direct messages column ([Gargron](https://github.com/tootsuite/mastodon/pull/8832), [Gargron](https://github.com/tootsuite/mastodon/pull/9022))
259
+- Change home timelines to exclude DMs ([Gargron](https://github.com/tootsuite/mastodon/pull/8940))
260
+- Change list timelines to exclude all replies ([cbayerlein](https://github.com/tootsuite/mastodon/pull/8683))
261
+- Change admin accounts UI default sort to most recent ([Gargron](https://github.com/tootsuite/mastodon/pull/8813))
262
+- Change documentation URL in the UI ([Gargron](https://github.com/tootsuite/mastodon/pull/8898))
263
+- Change style of success and failure messages ([Gargron](https://github.com/tootsuite/mastodon/pull/8973))
264
+- Change DM filtering to always allow DMs from staff ([qguv](https://github.com/tootsuite/mastodon/pull/8993))
265
+- Change recommended Ruby version to 2.5.3 ([zunda](https://github.com/tootsuite/mastodon/pull/9003))
266
+- Change docker-compose default to persist volumes in current directory ([Gargron](https://github.com/tootsuite/mastodon/pull/9055))
267
+- Change character counters on edit profile page to input length limit ([Gargron](https://github.com/tootsuite/mastodon/pull/9100))
268
+- Change notification filtering to always let through messages from staff ([Gargron](https://github.com/tootsuite/mastodon/pull/9152))
269
+- Change "hide boosts from user" function also hiding notifications about boosts ([ThibG](https://github.com/tootsuite/mastodon/pull/9147))
270
+- Change CSS `detailed-status__wrapper` class actually wrap the detailed status ([trwnh](https://github.com/tootsuite/mastodon/pull/8547))
247 271
 
248 272
 ### Deprecated
249 273
 
250
-- `GET /api/v1/timelines/direct` → `GET /api/v1/conversations` (#8832)
251
-- `POST /api/v1/notifications/dismiss` → `POST /api/v1/notifications/:id/dismiss` (#8905)
252
-- `GET /api/v1/statuses/:id/card` → `card` attributed included in status (#9120)
274
+- `GET /api/v1/timelines/direct` → `GET /api/v1/conversations` ([Gargron](https://github.com/tootsuite/mastodon/pull/8832))
275
+- `POST /api/v1/notifications/dismiss` → `POST /api/v1/notifications/:id/dismiss` ([Gargron](https://github.com/tootsuite/mastodon/pull/8905))
276
+- `GET /api/v1/statuses/:id/card` → `card` attributed included in status ([Gargron](https://github.com/tootsuite/mastodon/pull/9120))
253 277
 
254 278
 ### Removed
255 279
 
256
-- Remove "on this device" label in column push settings (#8704)
257
-- Remove rake tasks in favour of tootctl commands (#8675)
280
+- Remove "on this device" label in column push settings ([rhoio](https://github.com/tootsuite/mastodon/pull/8704))
281
+- Remove rake tasks in favour of tootctl commands ([Gargron](https://github.com/tootsuite/mastodon/pull/8675))
258 282
 
259 283
 ### Fixed
260 284
 
261
-- Fix remote statuses using instance's default locale if no language given (#8861)
262
-- Fix streaming API not exiting when port or socket is unavailable (#9023)
263
-- Fix network calls being performed in database transaction in ActivityPub handler (#8951)
264
-- Fix dropdown arrow position (#8637)
265
-- Fix first element of dropdowns being focused even if not using keyboard (#8679)
266
-- Fix tootctl requiring `bundle exec` invocation (#8619)
267
-- Fix public pages not using animation preference for avatars (#8614)
268
-- Fix OEmbed/OpenGraph cards not understanding relative URLs (#8669)
269
-- Fix some dark emojis not having a white outline (#8597)
270
-- Fix media description not being displayed in various media modals (#8678)
271
-- Fix generated URLs of desktop notifications missing base URL (#8758)
272
-- Fix RTL styles (#8764, #8767, #8823, #8897, #9005, #9007, #9018, #9021, #9145, #9146)
273
-- Fix crash in streaming API when tag param missing (#8955)
274
-- Fix hotkeys not working when no element is focused (#8998)
275
-- Fix some hotkeys not working on detailed status view (#9006)
276
-- Fix og:url on status pages (#9047)
277
-- Fix upload option buttons only being visible on hover (#9074)
278
-- Fix tootctl not returning exit code 1 on wrong arguments (#9094)
279
-- Fix preview cards for appearing for profiles mentioned in toot (#6934, #9158)
280
-- Fix local accounts sometimes being duplicated as faux-remote (#9109)
281
-- Fix emoji search when the shortcode has multiple separators (#9124)
282
-- Fix dropdowns sometimes being partially obscured by other elements (#9126)
283
-- Fix cache not updating when reply/boost/favourite counters or media sensitivity update (#9119)
284
-- Fix empty display name precedence over username in web UI (#9163)
285
-- Fix td instead of th in sessions table header (#9162)
286
-- Fix handling of content types with profile (#9132)
285
+- Fix remote statuses using instance's default locale if no language given ([Kjwon15](https://github.com/tootsuite/mastodon/pull/8861))
286
+- Fix streaming API not exiting when port or socket is unavailable ([Gargron](https://github.com/tootsuite/mastodon/pull/9023))
287
+- Fix network calls being performed in database transaction in ActivityPub handler ([Gargron](https://github.com/tootsuite/mastodon/pull/8951))
288
+- Fix dropdown arrow position ([ThibG](https://github.com/tootsuite/mastodon/pull/8637))
289
+- Fix first element of dropdowns being focused even if not using keyboard ([ThibG](https://github.com/tootsuite/mastodon/pull/8679))
290
+- Fix tootctl requiring `bundle exec` invocation ([abcang](https://github.com/tootsuite/mastodon/pull/8619))
291
+- Fix public pages not using animation preference for avatars ([renatolond](https://github.com/tootsuite/mastodon/pull/8614))
292
+- Fix OEmbed/OpenGraph cards not understanding relative URLs ([ThibG](https://github.com/tootsuite/mastodon/pull/8669))
293
+- Fix some dark emojis not having a white outline ([ThibG](https://github.com/tootsuite/mastodon/pull/8597))
294
+- Fix media description not being displayed in various media modals ([ThibG](https://github.com/tootsuite/mastodon/pull/8678))
295
+- Fix generated URLs of desktop notifications missing base URL ([GenbuHase](https://github.com/tootsuite/mastodon/pull/8758))
296
+- Fix RTL styles ([mabkenar](https://github.com/tootsuite/mastodon/pull/8764), [mabkenar](https://github.com/tootsuite/mastodon/pull/8767), [mabkenar](https://github.com/tootsuite/mastodon/pull/8823), [mabkenar](https://github.com/tootsuite/mastodon/pull/8897), [mabkenar](https://github.com/tootsuite/mastodon/pull/9005), [mabkenar](https://github.com/tootsuite/mastodon/pull/9007), [mabkenar](https://github.com/tootsuite/mastodon/pull/9018), [mabkenar](https://github.com/tootsuite/mastodon/pull/9021), [mabkenar](https://github.com/tootsuite/mastodon/pull/9145), [mabkenar](https://github.com/tootsuite/mastodon/pull/9146))
297
+- Fix crash in streaming API when tag param missing ([Gargron](https://github.com/tootsuite/mastodon/pull/8955))
298
+- Fix hotkeys not working when no element is focused ([ThibG](https://github.com/tootsuite/mastodon/pull/8998))
299
+- Fix some hotkeys not working on detailed status view ([ThibG](https://github.com/tootsuite/mastodon/pull/9006))
300
+- Fix og:url on status pages ([ThibG](https://github.com/tootsuite/mastodon/pull/9047))
301
+- Fix upload option buttons only being visible on hover ([Gargron](https://github.com/tootsuite/mastodon/pull/9074))
302
+- Fix tootctl not returning exit code 1 on wrong arguments ([sascha-sl](https://github.com/tootsuite/mastodon/pull/9094))
303
+- Fix preview cards for appearing for profiles mentioned in toot ([ThibG](https://github.com/tootsuite/mastodon/pull/6934), [ThibG](https://github.com/tootsuite/mastodon/pull/9158))
304
+- Fix local accounts sometimes being duplicated as faux-remote ([Gargron](https://github.com/tootsuite/mastodon/pull/9109))
305
+- Fix emoji search when the shortcode has multiple separators ([ThibG](https://github.com/tootsuite/mastodon/pull/9124))
306
+- Fix dropdowns sometimes being partially obscured by other elements ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/9126))
307
+- Fix cache not updating when reply/boost/favourite counters or media sensitivity update ([Gargron](https://github.com/tootsuite/mastodon/pull/9119))
308
+- Fix empty display name precedence over username in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/9163))
309
+- Fix td instead of th in sessions table header ([Gargron](https://github.com/tootsuite/mastodon/pull/9162))
310
+- Fix handling of content types with profile ([valerauko](https://github.com/tootsuite/mastodon/pull/9132))
287 311
 
288 312
 ## [2.5.2] - 2018-10-12
289 313
 ### Security
290 314
 
291
-- Fix XSS vulnerability (#8959)
315
+- Fix XSS vulnerability ([Gargron](https://github.com/tootsuite/mastodon/pull/8959))
292 316
 
293 317
 ## [2.5.1] - 2018-10-07
294 318
 ### Fixed
295 319
 
296
-- Fix database migrations for PostgreSQL below 9.5 (#8903)
297
-- Fix class autoloading issue in ActivityPub Create handler (#8820)
298
-- Fix cache statistics not being sent via statsd when statsd enabled (#8831)
299
-- Bump puma from 3.11.4 to 3.12.0 (#8883)
320
+- Fix database migrations for PostgreSQL below 9.5 ([Gargron](https://github.com/tootsuite/mastodon/pull/8903))
321
+- Fix class autoloading issue in ActivityPub Create handler ([Gargron](https://github.com/tootsuite/mastodon/pull/8820))
322
+- Fix cache statistics not being sent via statsd when statsd enabled ([ykzts](https://github.com/tootsuite/mastodon/pull/8831))
323
+- Bump puma from 3.11.4 to 3.12.0 ([dependabot[bot]](https://github.com/tootsuite/mastodon/pull/8883))
300 324
 
301 325
 ### Security
302 326
 
303
-- Fix some local images not having their EXIF metadata stripped on upload (#8714)
304
-- Fix being able to enable a disabled relay via ActivityPub Accept handler (#8864)
305
-- Bump nokogiri from 1.8.4 to 1.8.5 (#8881)
306
-- Fix being able to report statuses not belonging to the reported account (#8916)
327
+- Fix some local images not having their EXIF metadata stripped on upload ([ThibG](https://github.com/tootsuite/mastodon/pull/8714))
328
+- Fix being able to enable a disabled relay via ActivityPub Accept handler ([ThibG](https://github.com/tootsuite/mastodon/pull/8864))
329
+- Bump nokogiri from 1.8.4 to 1.8.5 ([dependabot[bot]](https://github.com/tootsuite/mastodon/pull/8881))
330
+- Fix being able to report statuses not belonging to the reported account ([ThibG](https://github.com/tootsuite/mastodon/pull/8916))

+ 2
- 2
Dockerfile View File

@@ -1,5 +1,5 @@
1
-FROM node:8.14.0-alpine as node
2
-FROM ruby:2.4.5-alpine3.8
1
+FROM node:8.15-alpine as node
2
+FROM ruby:2.6-alpine3.8
3 3
 
4 4
 LABEL maintainer="https://github.com/tootsuite/mastodon" \
5 5
       description="Your self-hosted, globally interconnected microblogging community"

+ 3
- 3
Gemfile View File

@@ -90,7 +90,7 @@ gem 'tzinfo-data', '~> 1.2018'
90 90
 gem 'webpacker', '~> 3.5'
91 91
 gem 'webpush'
92 92
 
93
-gem 'json-ld', '~> 2.2'
93
+gem 'json-ld', '~> 3.0'
94 94
 gem 'json-ld-preloaded', '~> 3.0'
95 95
 gem 'rdf-normalize', '~> 0.3'
96 96
 
@@ -128,8 +128,8 @@ group :development do
128 128
   gem 'letter_opener', '~> 1.7'
129 129
   gem 'letter_opener_web', '~> 1.3'
130 130
   gem 'memory_profiler'
131
-  gem 'rubocop', '~> 0.62', require: false
132
-  gem 'brakeman', '~> 4.3', require: false
131
+  gem 'rubocop', '~> 0.63', require: false
132
+  gem 'brakeman', '~> 4.4', require: false
133 133
   gem 'bundler-audit', '~> 0.6', require: false
134 134
   gem 'scss_lint', '~> 0.57', require: false
135 135
 

+ 12
- 12
Gemfile.lock View File

@@ -100,14 +100,14 @@ GEM
100 100
       debug_inspector (>= 0.0.1)
101 101
     bootsnap (1.3.2)
102 102
       msgpack (~> 1.0)
103
-    brakeman (4.3.1)
103
+    brakeman (4.4.0)
104 104
     browser (2.5.3)
105 105
     builder (3.2.3)
106 106
     bullet (5.9.0)
107 107
       activesupport (>= 3.0.0)
108 108
       uniform_notifier (~> 1.11)
109
-    bundler-audit (0.6.0)
110
-      bundler (~> 1.2)
109
+    bundler-audit (0.6.1)
110
+      bundler (>= 1.2.0, < 3)
111 111
       thor (~> 0.18)
112 112
     byebug (10.0.2)
113 113
     capistrano (3.11.0)
@@ -286,10 +286,10 @@ GEM
286 286
     idn-ruby (0.1.0)
287 287
     ipaddress (0.8.3)
288 288
     iso-639 (0.2.8)
289
-    jaro_winkler (1.5.1)
289
+    jaro_winkler (1.5.2)
290 290
     jmespath (1.4.0)
291 291
     json (2.1.0)
292
-    json-ld (2.2.1)
292
+    json-ld (3.0.2)
293 293
       multi_json (~> 1.12)
294 294
       rdf (>= 2.2.8, < 4.0)
295 295
     json-ld-preloaded (3.0.0)
@@ -365,7 +365,7 @@ GEM
365 365
       concurrent-ruby (~> 1.0, >= 1.0.2)
366 366
       sidekiq (>= 3.5)
367 367
       statsd-ruby (~> 1.4, >= 1.4.0)
368
-    oj (3.7.6)
368
+    oj (3.7.7)
369 369
     omniauth (1.9.0)
370 370
       hashie (>= 3.4.6, < 3.7.0)
371 371
       rack (>= 1.6.2, < 3)
@@ -394,7 +394,7 @@ GEM
394 394
     parallel (1.12.1)
395 395
     parallel_tests (2.27.1)
396 396
       parallel
397
-    parser (2.5.3.0)
397
+    parser (2.6.0.0)
398 398
       ast (~> 2.4.0)
399 399
     pastel (0.7.2)
400 400
       equatable (~> 0.5.0)
@@ -473,7 +473,7 @@ GEM
473 473
     rb-fsevent (0.10.3)
474 474
     rb-inotify (0.9.10)
475 475
       ffi (>= 0.5.0, < 2)
476
-    rdf (3.0.7)
476
+    rdf (3.0.9)
477 477
       hamster (~> 3.0)
478 478
       link_header (~> 0.0, >= 0.0.8)
479 479
     rdf-normalize (0.3.3)
@@ -527,7 +527,7 @@ GEM
527 527
       rspec-core (~> 3.0, >= 3.0.0)
528 528
       sidekiq (>= 2.4.0)
529 529
     rspec-support (3.8.0)
530
-    rubocop (0.62.0)
530
+    rubocop (0.63.0)
531 531
       jaro_winkler (~> 1.5.1)
532 532
       parallel (~> 1.10)
533 533
       parser (>= 2.5, != 2.5.1.1)
@@ -663,7 +663,7 @@ DEPENDENCIES
663 663
   better_errors (~> 2.5)
664 664
   binding_of_caller (~> 0.7)
665 665
   bootsnap (~> 1.3)
666
-  brakeman (~> 4.3)
666
+  brakeman (~> 4.4)
667 667
   browser
668 668
   bullet (~> 5.9)
669 669
   bundler-audit (~> 0.6)
@@ -702,7 +702,7 @@ DEPENDENCIES
702 702
   i18n-tasks (~> 0.9)
703 703
   idn-ruby
704 704
   iso-639
705
-  json-ld (~> 2.2)
705
+  json-ld (~> 3.0)
706 706
   json-ld-preloaded (~> 3.0)
707 707
   kaminari (~> 1.1)
708 708
   letter_opener (~> 1.7)
@@ -749,7 +749,7 @@ DEPENDENCIES
749 749
   rqrcode (~> 0.10)
750 750
   rspec-rails (~> 3.8)
751 751
   rspec-sidekiq (~> 3.0)
752
-  rubocop (~> 0.62)
752
+  rubocop (~> 0.63)
753 753
   sanitize (~> 5.0)
754 754
   scss_lint (~> 0.57)
755 755
   sidekiq (~> 5.2)

+ 1
- 1
app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb View File

@@ -25,7 +25,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
25 25
   end
26 26
 
27 27
   def paginated_statuses
28
-    Status.where(reblog_of_id: @status.id).paginate_by_max_id(
28
+    Status.where(reblog_of_id: @status.id).where(visibility: [:public, :unlisted]).paginate_by_max_id(
29 29
       limit_param(DEFAULT_ACCOUNTS_LIMIT),
30 30
       params[:max_id],
31 31
       params[:since_id]

+ 2
- 0
app/controllers/tags_controller.rb View File

@@ -3,6 +3,8 @@
3 3
 class TagsController < ApplicationController
4 4
   PAGE_SIZE = 20
5 5
 
6
+  layout 'public'
7
+
6 8
   before_action :set_body_classes
7 9
   before_action :set_instance_presenter
8 10
 

+ 5
- 1
app/javascript/mastodon/common.js View File

@@ -4,5 +4,9 @@ export function start() {
4 4
   require('font-awesome/css/font-awesome.css');
5 5
   require.context('../images/', true);
6 6
 
7
-  Rails.start();
7
+  try {
8
+    Rails.start();
9
+  } catch (e) {
10
+    // If called twice
11
+  }
8 12
 };

+ 10
- 2
app/javascript/mastodon/components/display_name.js View File

@@ -1,15 +1,17 @@
1 1
 import React from 'react';
2 2
 import ImmutablePropTypes from 'react-immutable-proptypes';
3
+import PropTypes from 'prop-types';
3 4
 
4 5
 export default class DisplayName extends React.PureComponent {
5 6
 
6 7
   static propTypes = {
7 8
     account: ImmutablePropTypes.map.isRequired,
8 9
     others: ImmutablePropTypes.list,
10
+    localDomain: PropTypes.string,
9 11
   };
10 12
 
11 13
   render () {
12
-    const { account, others } = this.props;
14
+    const { account, others, localDomain } = this.props;
13 15
     const displayNameHtml = { __html: account.get('display_name_html') };
14 16
 
15 17
     let suffix;
@@ -17,7 +19,13 @@ export default class DisplayName extends React.PureComponent {
17 19
     if (others && others.size > 1) {
18 20
       suffix = `+${others.size}`;
19 21
     } else {
20
-      suffix = <span className='display-name__account'>@{account.get('acct')}</span>;
22
+      let acct = account.get('acct');
23
+
24
+      if (acct.indexOf('@') === -1 && localDomain) {
25
+        acct = `${acct}@${localDomain}`;
26
+      }
27
+
28
+      suffix = <span className='display-name__account'>@{acct}</span>;
21 29
     }
22 30
 
23 31
     return (

+ 1
- 1
app/javascript/mastodon/components/status.js View File

@@ -77,7 +77,7 @@ class Status extends ImmutablePureComponent {
77 77
     'account',
78 78
     'muted',
79 79
     'hidden',
80
-  ]
80
+  ];
81 81
 
82 82
   handleClick = () => {
83 83
     if (this.props.onClick) {

+ 57
- 29
app/javascript/mastodon/features/standalone/hashtag_timeline/index.js View File

@@ -1,28 +1,32 @@
1 1
 import React from 'react';
2 2
 import { connect } from 'react-redux';
3 3
 import PropTypes from 'prop-types';
4
-import StatusListContainer from '../../ui/containers/status_list_container';
4
+import ImmutablePropTypes from 'react-immutable-proptypes';
5 5
 import { expandHashtagTimeline } from '../../../actions/timelines';
6
-import Column from '../../../components/column';
7
-import ColumnHeader from '../../../components/column_header';
8 6
 import { connectHashtagStream } from '../../../actions/streaming';
7
+import Masonry from 'react-masonry-infinite';
8
+import { List as ImmutableList } from 'immutable';
9
+import DetailedStatusContainer from '../../status/containers/detailed_status_container';
10
+import { debounce } from 'lodash';
11
+import LoadingIndicator from '../../../components/loading_indicator';
9 12
 
10
-export default @connect()
13
+const mapStateToProps = (state, { hashtag }) => ({
14
+  statusIds: state.getIn(['timelines', `hashtag:${hashtag}`, 'items'], ImmutableList()),
15
+  isLoading: state.getIn(['timelines', `hashtag:${hashtag}`, 'isLoading'], false),
16
+  hasMore: state.getIn(['timelines', `hashtag:${hashtag}`, 'hasMore'], false),
17
+});
18
+
19
+export default @connect(mapStateToProps)
11 20
 class HashtagTimeline extends React.PureComponent {
12 21
 
13 22
   static propTypes = {
14 23
     dispatch: PropTypes.func.isRequired,
24
+    statusIds: ImmutablePropTypes.list.isRequired,
25
+    isLoading: PropTypes.bool.isRequired,
26
+    hasMore: PropTypes.bool.isRequired,
15 27
     hashtag: PropTypes.string.isRequired,
16 28
   };
17 29
 
18
-  handleHeaderClick = () => {
19
-    this.column.scrollTop();
20
-  }
21
-
22
-  setRef = c => {
23
-    this.column = c;
24
-  }
25
-
26 30
   componentDidMount () {
27 31
     const { dispatch, hashtag } = this.props;
28 32
 
@@ -37,28 +41,52 @@ class HashtagTimeline extends React.PureComponent {
37 41
     }
38 42
   }
39 43
 
40
-  handleLoadMore = maxId => {
41
-    this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));
44
+  handleLoadMore = () => {
45
+    const maxId = this.props.statusIds.last();
46
+
47
+    if (maxId) {
48
+      this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));
49
+    }
50
+  }
51
+
52
+  setRef = c => {
53
+    this.masonry = c;
42 54
   }
43 55
 
56
+  handleHeightChange = debounce(() => {
57
+    if (!this.masonry) {
58
+      return;
59
+    }
60
+
61
+    this.masonry.forcePack();
62
+  }, 50)
63
+
44 64
   render () {
45
-    const { hashtag } = this.props;
65
+    const { statusIds, hasMore, isLoading } = this.props;
66
+
67
+    const sizes = [
68
+      { columns: 1, gutter: 0 },
69
+      { mq: '415px', columns: 1, gutter: 10 },
70
+      { mq: '640px', columns: 2, gutter: 10 },
71
+      { mq: '960px', columns: 3, gutter: 10 },
72
+      { mq: '1255px', columns: 3, gutter: 10 },
73
+    ];
74
+
75
+    const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined;
46 76
 
47 77
     return (
48
-      <Column ref={this.setRef}>
49
-        <ColumnHeader
50
-          icon='hashtag'
51
-          title={hashtag}
52
-          onClick={this.handleHeaderClick}
53
-        />
54
-
55
-        <StatusListContainer
56
-          trackScroll={false}
57
-          scrollKey='standalone_hashtag_timeline'
58
-          timelineId={`hashtag:${hashtag}`}
59
-          onLoadMore={this.handleLoadMore}
60
-        />
61
-      </Column>
78
+      <Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}>
79
+        {statusIds.map(statusId => (
80
+          <div className='statuses-grid__item' key={statusId}>
81
+            <DetailedStatusContainer
82
+              id={statusId}
83
+              compact
84
+              measureHeight
85
+              onHeightChange={this.handleHeightChange}
86
+            />
87
+          </div>
88
+        )).toArray()}
89
+      </Masonry>
62 90
     );
63 91
   }
64 92
 

+ 107
- 25
app/javascript/mastodon/features/status/components/detailed_status.js View File

@@ -11,6 +11,8 @@ import { FormattedDate, FormattedNumber } from 'react-intl';
11 11
 import Card from './card';
12 12
 import ImmutablePureComponent from 'react-immutable-pure-component';
13 13
 import Video from '../../video';
14
+import scheduleIdleTask from '../../ui/util/schedule_idle_task';
15
+import classNames from 'classnames';
14 16
 
15 17
 export default class DetailedStatus extends ImmutablePureComponent {
16 18
 
@@ -23,10 +25,18 @@ export default class DetailedStatus extends ImmutablePureComponent {
23 25
     onOpenMedia: PropTypes.func.isRequired,
24 26
     onOpenVideo: PropTypes.func.isRequired,
25 27
     onToggleHidden: PropTypes.func.isRequired,
28
+    measureHeight: PropTypes.bool,
29
+    onHeightChange: PropTypes.func,
30
+    domain: PropTypes.string.isRequired,
31
+    compact: PropTypes.bool,
32
+  };
33
+
34
+  state = {
35
+    height: null,
26 36
   };
27 37
 
28 38
   handleAccountClick = (e) => {
29
-    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
39
+    if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.context.router) {
30 40
       e.preventDefault();
31 41
       this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);
32 42
     }
@@ -42,13 +52,57 @@ export default class DetailedStatus extends ImmutablePureComponent {
42 52
     this.props.onToggleHidden(this.props.status);
43 53
   }
44 54
 
55
+  _measureHeight (heightJustChanged) {
56
+    if (this.props.measureHeight && this.node) {
57
+      scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 }));
58
+
59
+      if (this.props.onHeightChange && heightJustChanged) {
60
+        this.props.onHeightChange();
61
+      }
62
+    }
63
+  }
64
+
65
+  setRef = c => {
66
+    this.node = c;
67
+    this._measureHeight();
68
+  }
69
+
70
+  componentDidUpdate (prevProps, prevState) {
71
+    this._measureHeight(prevState.height !== this.state.height);
72
+  }
73
+
74
+  handleModalLink = e => {
75
+    e.preventDefault();
76
+
77
+    let href;
78
+
79
+    if (e.target.nodeName !== 'A') {
80
+      href = e.target.parentNode.href;
81
+    } else {
82
+      href = e.target.href;
83
+    }
84
+
85
+    window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
86
+  }
87
+
45 88
   render () {
46 89
     const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status;
90
+    const outerStyle = { boxSizing: 'border-box' };
91
+    const { compact } = this.props;
92
+
93
+    if (!status) {
94
+      return null;
95
+    }
47 96
 
48 97
     let media           = '';
49 98
     let applicationLink = '';
50 99
     let reblogLink = '';
51 100
     let reblogIcon = 'retweet';
101
+    let favouriteLink = '';
102
+
103
+    if (this.props.measureHeight) {
104
+      outerStyle.height = `${this.state.height}px`;
105
+    }
52 106
 
53 107
     if (status.get('media_attachments').size > 0) {
54 108
       if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) {
@@ -95,35 +149,63 @@ export default class DetailedStatus extends ImmutablePureComponent {
95 149
 
96 150
     if (status.get('visibility') === 'private') {
97 151
       reblogLink = <i className={`fa fa-${reblogIcon}`} />;
152
+    } else if (this.context.router) {
153
+      reblogLink = (
154
+        <Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>
155
+          <i className={`fa fa-${reblogIcon}`} />
156
+          <span className='detailed-status__reblogs'>
157
+            <FormattedNumber value={status.get('reblogs_count')} />
158
+          </span>
159
+        </Link>
160
+      );
98 161
     } else {
99
-      reblogLink = (<Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>
100
-        <i className={`fa fa-${reblogIcon}`} />
101
-        <span className='detailed-status__reblogs'>
102
-          <FormattedNumber value={status.get('reblogs_count')} />
103
-        </span>
104
-      </Link>);
162
+      reblogLink = (
163
+        <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
164
+          <i className={`fa fa-${reblogIcon}`} />
165
+          <span className='detailed-status__reblogs'>
166
+            <FormattedNumber value={status.get('reblogs_count')} />
167
+          </span>
168
+        </a>
169
+      );
105 170
     }
106 171
 
107
-    return (
108
-      <div className='detailed-status'>
109
-        <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>
110
-          <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
111
-          <DisplayName account={status.get('account')} />
172
+    if (this.context.router) {
173
+      favouriteLink = (
174
+        <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
175
+          <i className='fa fa-star' />
176
+          <span className='detailed-status__favorites'>
177
+            <FormattedNumber value={status.get('favourites_count')} />
178
+          </span>
179
+        </Link>
180
+      );
181
+    } else {
182
+      favouriteLink = (
183
+        <a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
184
+          <i className='fa fa-star' />
185
+          <span className='detailed-status__favorites'>
186
+            <FormattedNumber value={status.get('favourites_count')} />
187
+          </span>
112 188
         </a>
189
+      );
190
+    }
113 191
 
114
-        <StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
115
-
116
-        {media}
117
-
118
-        <div className='detailed-status__meta'>
119
-          <a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'>
120
-            <FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
121
-          </a>{applicationLink} · {reblogLink} · <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
122
-            <i className='fa fa-star' />
123
-            <span className='detailed-status__favorites'>
124
-              <FormattedNumber value={status.get('favourites_count')} />
125
-            </span>
126
-          </Link>
192
+    return (
193
+      <div style={outerStyle}>
194
+        <div ref={this.setRef} className={classNames('detailed-status', { compact })}>
195
+          <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>
196
+            <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
197
+            <DisplayName account={status.get('account')} localDomain={this.props.domain} />
198
+          </a>
199
+
200
+          <StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
201
+
202
+          {media}
203
+
204
+          <div className='detailed-status__meta'>
205
+            <a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'>
206
+              <FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
207
+            </a>{applicationLink} · {reblogLink} · {favouriteLink}
208
+          </div>
127 209
         </div>
128 210
       </div>
129 211
     );

+ 172
- 0
app/javascript/mastodon/features/status/containers/detailed_status_container.js View File

@@ -0,0 +1,172 @@
1
+import React from 'react';
2
+import { connect } from 'react-redux';
3
+import DetailedStatus from '../components/detailed_status';
4
+import { makeGetStatus } from '../../../selectors';
5
+import {
6
+  replyCompose,
7
+  mentionCompose,
8
+  directCompose,
9
+} from '../../../actions/compose';
10
+import {
11
+  reblog,
12
+  favourite,
13
+  unreblog,
14
+  unfavourite,
15
+  pin,
16
+  unpin,
17
+} from '../../../actions/interactions';
18
+import { blockAccount } from '../../../actions/accounts';
19
+import {
20
+  muteStatus,
21
+  unmuteStatus,
22
+  deleteStatus,
23
+  hideStatus,
24
+  revealStatus,
25
+} from '../../../actions/statuses';
26
+import { initMuteModal } from '../../../actions/mutes';
27
+import { initReport } from '../../../actions/reports';
28
+import { openModal } from '../../../actions/modal';
29
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
30
+import { boostModal, deleteModal } from '../../../initial_state';
31
+import { showAlertForError } from '../../../actions/alerts';
32
+
33
+const messages = defineMessages({
34
+  deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
35
+  deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
36
+  redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
37
+  redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' },
38
+  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
39
+  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
40
+  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
41
+});
42
+
43
+const makeMapStateToProps = () => {
44
+  const getStatus = makeGetStatus();
45
+
46
+  const mapStateToProps = (state, props) => ({
47
+    status: getStatus(state, props),
48
+    domain: state.getIn(['meta', 'domain']),
49
+  });
50
+
51
+  return mapStateToProps;
52
+};
53
+
54
+const mapDispatchToProps = (dispatch, { intl }) => ({
55
+
56
+  onReply (status, router) {
57
+    dispatch((_, getState) => {
58
+      let state = getState();
59
+      if (state.getIn(['compose', 'text']).trim().length !== 0) {
60
+        dispatch(openModal('CONFIRM', {
61
+          message: intl.formatMessage(messages.replyMessage),
62
+          confirm: intl.formatMessage(messages.replyConfirm),
63
+          onConfirm: () => dispatch(replyCompose(status, router)),
64
+        }));
65
+      } else {
66
+        dispatch(replyCompose(status, router));
67
+      }
68
+    });
69
+  },
70
+
71
+  onModalReblog (status) {
72
+    dispatch(reblog(status));
73
+  },
74
+
75
+  onReblog (status, e) {
76
+    if (status.get('reblogged')) {
77
+      dispatch(unreblog(status));
78
+    } else {
79
+      if (e.shiftKey || !boostModal) {
80
+        this.onModalReblog(status);
81
+      } else {
82
+        dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
83
+      }
84
+    }
85
+  },
86
+
87
+  onFavourite (status) {
88
+    if (status.get('favourited')) {
89
+      dispatch(unfavourite(status));
90
+    } else {
91
+      dispatch(favourite(status));
92
+    }
93
+  },
94
+
95
+  onPin (status) {
96
+    if (status.get('pinned')) {
97
+      dispatch(unpin(status));
98
+    } else {
99
+      dispatch(pin(status));
100
+    }
101
+  },
102
+
103
+  onEmbed (status) {
104
+    dispatch(openModal('EMBED', {
105
+      url: status.get('url'),
106
+      onError: error => dispatch(showAlertForError(error)),
107
+    }));
108
+  },
109
+
110
+  onDelete (status, history, withRedraft = false) {
111
+    if (!deleteModal) {
112
+      dispatch(deleteStatus(status.get('id'), history, withRedraft));
113
+    } else {
114
+      dispatch(openModal('CONFIRM', {
115
+        message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
116
+        confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
117
+        onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
118
+      }));
119
+    }
120
+  },
121
+
122
+  onDirect (account, router) {
123
+    dispatch(directCompose(account, router));
124
+  },
125
+
126
+  onMention (account, router) {
127
+    dispatch(mentionCompose(account, router));
128
+  },
129
+
130
+  onOpenMedia (media, index) {
131
+    dispatch(openModal('MEDIA', { media, index }));
132
+  },
133
+
134
+  onOpenVideo (media, time) {
135
+    dispatch(openModal('VIDEO', { media, time }));
136
+  },
137
+
138
+  onBlock (account) {
139
+    dispatch(openModal('CONFIRM', {
140
+      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
141
+      confirm: intl.formatMessage(messages.blockConfirm),
142
+      onConfirm: () => dispatch(blockAccount(account.get('id'))),
143
+    }));
144
+  },
145
+
146
+  onReport (status) {
147
+    dispatch(initReport(status.get('account'), status));
148
+  },
149
+
150
+  onMute (account) {
151
+    dispatch(initMuteModal(account));
152
+  },
153
+
154
+  onMuteConversation (status) {
155
+    if (status.get('muted')) {
156
+      dispatch(unmuteStatus(status.get('id')));
157
+    } else {
158
+      dispatch(muteStatus(status.get('id')));
159
+    }
160
+  },
161
+
162
+  onToggleHidden (status) {
163
+    if (status.get('hidden')) {
164
+      dispatch(revealStatus(status.get('id')));
165
+    } else {
166
+      dispatch(hideStatus(status.get('id')));
167
+    }
168
+  },
169
+
170
+});
171
+
172
+export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(DetailedStatus));

+ 4
- 1
app/javascript/mastodon/features/status/index.js View File

@@ -101,6 +101,7 @@ const makeMapStateToProps = () => {
101 101
       ancestorsIds,
102 102
       descendantsIds,
103 103
       askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
104
+      domain: state.getIn(['meta', 'domain']),
104 105
     };
105 106
   };
106 107
 
@@ -123,6 +124,7 @@ class Status extends ImmutablePureComponent {
123 124
     descendantsIds: ImmutablePropTypes.list,
124 125
     intl: PropTypes.object.isRequired,
125 126
     askReplyConfirmation: PropTypes.bool,
127
+    domain: PropTypes.string.isRequired,
126 128
   };
127 129
 
128 130
   state = {
@@ -387,7 +389,7 @@ class Status extends ImmutablePureComponent {
387 389
 
388 390
   render () {
389 391
     let ancestors, descendants;
390
-    const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl } = this.props;
392
+    const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl, domain } = this.props;
391 393
     const { fullscreen } = this.state;
392 394
 
393 395
     if (status === null) {
@@ -438,6 +440,7 @@ class Status extends ImmutablePureComponent {
438 440
                   onOpenVideo={this.handleOpenVideo}
439 441
                   onOpenMedia={this.handleOpenMedia}
440 442
                   onToggleHidden={this.handleToggleHidden}
443
+                  domain={domain}
441 444
                 />
442 445
 
443 446
                 <ActionBar

+ 1
- 1
app/javascript/mastodon/features/ui/components/columns_area.js View File

@@ -33,7 +33,7 @@ const messages = defineMessages({
33 33
   publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
34 34
 });
35 35
 
36
-const shouldHideFAB = path => path.match(/^\/statuses\//);
36
+const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/);
37 37
 
38 38
 export default @(component => injectIntl(component, { withRef: true }))
39 39
 class ColumnsArea extends ImmutablePureComponent {

+ 6
- 0
app/javascript/mastodon/features/ui/index.js View File

@@ -243,6 +243,7 @@ class UI extends React.PureComponent {
243 243
   }
244 244
 
245 245
   handleDragOver = (e) => {
246
+    if (this.dataTransferIsText(e.dataTransfer)) return false;
246 247
     e.preventDefault();
247 248
     e.stopPropagation();
248 249
 
@@ -256,6 +257,7 @@ class UI extends React.PureComponent {
256 257
   }
257 258
 
258 259
   handleDrop = (e) => {
260
+    if (this.dataTransferIsText(e.dataTransfer)) return;
259 261
     e.preventDefault();
260 262
 
261 263
     this.setState({ draggingOver: false });
@@ -279,6 +281,10 @@ class UI extends React.PureComponent {
279 281
     this.setState({ draggingOver: false });
280 282
   }
281 283
 
284
+  dataTransferIsText = (dataTransfer) => {
285
+    return (dataTransfer && Array.from(dataTransfer.types).includes('text/plain') && dataTransfer.items.length === 1);
286
+  }
287
+
282 288
   closeUploadModal = () => {
283 289
     this.setState({ draggingOver: false });
284 290
   }

+ 1
- 1
app/javascript/mastodon/locales/ca.json View File

@@ -8,7 +8,7 @@
8 8
   "account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.",
9 9
   "account.domain_blocked": "Domini ocult",
10 10
   "account.edit_profile": "Editar el perfil",
11
-  "account.endorse": "Característica del perfil",
11
+  "account.endorse": "Recomanar en el teu perfil",
12 12
   "account.follow": "Segueix",
13 13
   "account.followers": "Seguidors",
14 14
   "account.followers.empty": "Encara ningú no segueix aquest usuari.",

+ 11
- 11
app/javascript/mastodon/locales/cy.json View File

@@ -84,7 +84,7 @@
84 84
   "confirmations.block.confirm": "Blocio",
85 85
   "confirmations.block.message": "Ydych chi'n sicr eich bod eisiau blocio {name}?",
86 86
   "confirmations.delete.confirm": "Dileu",
87
-  "confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y statws hwn?",
87
+  "confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y tŵt hwn?",
88 88
   "confirmations.delete_list.confirm": "Dileu",
89 89
   "confirmations.delete_list.message": "Ydych chi'n sicr eich bod eisiau dileu y rhestr hwn am byth?",
90 90
   "confirmations.domain_block.confirm": "Cuddio parth cyfan",
@@ -92,12 +92,12 @@
92 92
   "confirmations.mute.confirm": "Tawelu",
93 93
   "confirmations.mute.message": "Ydych chi'n sicr eich bod am ddistewi {name}?",
94 94
   "confirmations.redraft.confirm": "Dileu & ailddrafftio",
95
-  "confirmations.redraft.message": "Ydych chi'n siwr eich bod eisiau dileu y statws hwn a'i ailddrafftio? Bydd ffefrynnau a bwstiau'n cael ei colli, a bydd ymatebion i'r statws gwreiddiol yn cael eu hamddifadu.",
95
+  "confirmations.redraft.message": "Ydych chi'n siwr eich bod eisiau dileu y tŵt hwn a'i ailddrafftio? Bydd ffefrynnau a bwstiau'n cael ei colli, a bydd ymatebion i'r tŵt gwreiddiol yn cael eu hamddifadu.",
96 96
   "confirmations.reply.confirm": "Ateb",
97 97
   "confirmations.reply.message": "Bydd ateb nawr yn cymryd lle y neges yr ydych yn cyfansoddi ar hyn o bryd. Ydych chi'n sicr yr ydych am barhau?",
98 98
   "confirmations.unfollow.confirm": "Dad-ddilynwch",
99 99
   "confirmations.unfollow.message": "Ydych chi'n sicr eich bod am ddad-ddilyn {name}?",
100
-  "embed.instructions": "Mewnblannwch y statws hwn ar eich gwefan drwy gopïo'r côd isod.",
100
+  "embed.instructions": "Mewnblannwch y tŵt hwn ar eich gwefan drwy gopïo'r côd isod.",
101 101
   "embed.preview": "Dyma sut olwg fydd arno:",
102 102
   "emoji_button.activity": "Gweithgarwch",
103 103
   "emoji_button.custom": "Unigryw",
@@ -169,12 +169,12 @@
169 169
   "keyboard_shortcuts.back": "i lywio nôl",
170 170
   "keyboard_shortcuts.blocked": "i agor rhestr defnyddwyr a flociwyd",
171 171
   "keyboard_shortcuts.boost": "i fŵstio",
172
-  "keyboard_shortcuts.column": "i ffocysu statws yn un o'r colofnau",
172
+  "keyboard_shortcuts.column": "i ffocysu tŵt yn un o'r colofnau",
173 173
   "keyboard_shortcuts.compose": "i ffocysu yr ardal cyfansoddi testun",
174 174
   "keyboard_shortcuts.description": "Disgrifiad",
175 175
   "keyboard_shortcuts.direct": "i agor colofn negeseuon preifat",
176 176
   "keyboard_shortcuts.down": "i symud lawr yn y rhestr",
177
-  "keyboard_shortcuts.enter": "i agor statws",
177
+  "keyboard_shortcuts.enter": "i agor tŵt",
178 178
   "keyboard_shortcuts.favourite": "i hoffi",
179 179
   "keyboard_shortcuts.favourites": "i agor rhestr hoffi",
180 180
   "keyboard_shortcuts.federated": "i agor ffrwd y ffederasiwn",
@@ -234,10 +234,10 @@
234 234
   "navigation_bar.preferences": "Dewisiadau",
235 235
   "navigation_bar.public_timeline": "Ffrwd y ffederasiwn",
236 236
   "navigation_bar.security": "Diogelwch",
237
-  "notification.favourite": "hoffodd {name} eich statws",
237
+  "notification.favourite": "hoffodd {name} eich tŵt",
238 238
   "notification.follow": "dilynodd {name} chi",
239 239
   "notification.mention": "Soniodd {name} amdanoch chi",
240
-  "notification.reblog": "{name} boosted your status",
240
+  "notification.reblog": "Hysbysebodd {name} eich tŵt",
241 241
   "notifications.clear": "Clirio hysbysiadau",
242 242
   "notifications.clear_confirmation": "Ydych chi'n sicr eich bod am glirio'ch holl hysbysiadau am byth?",
243 243
   "notifications.column_settings.alert": "Hysbysiadau bwrdd gwaith",
@@ -257,7 +257,7 @@
257 257
   "notifications.filter.follows": "Yn dilyn",
258 258
   "notifications.filter.mentions": "Mentions",
259 259
   "notifications.group": "{count} o hysbysiadau",
260
-  "privacy.change": "Addasu preifatrwdd y statws",
260
+  "privacy.change": "Addasu preifatrwdd y tŵt",
261 261
   "privacy.direct.long": "Cyhoeddi i'r defnyddwyr sy'n cael eu crybwyll yn unig",
262 262
   "privacy.direct.short": "Uniongyrchol",
263 263
   "privacy.private.long": "Cyhoeddi i ddilynwyr yn unig",
@@ -284,7 +284,7 @@
284 284
   "search_popout.search_format": "Fformat chwilio uwch",
285 285
   "search_popout.tips.full_text": "Mae testun syml yn dychwelyd tŵtiau yr ydych wedi ysgrifennu, hoffi, wedi'u bŵstio, neu wedi'ch crybwyll ynddynt, ynghyd a chyfateb a enwau defnyddwyr, enwau arddangos ac hashnodau.",
286 286
   "search_popout.tips.hashtag": "hashnod",
287
-  "search_popout.tips.status": "statws",
287
+  "search_popout.tips.status": "tŵt",
288 288
   "search_popout.tips.text": "Mae testun syml yn dychwelyd enwau arddangos, enwau defnyddwyr a hashnodau sy'n cyfateb",
289 289
   "search_popout.tips.user": "defnyddiwr",
290 290
   "search_results.accounts": "Pobl",
@@ -293,7 +293,7 @@
293 293
   "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
294 294
   "standalone.public_title": "Golwg tu fewn...",
295 295
   "status.admin_account": "Open moderation interface for @{name}",
296
-  "status.admin_status": "Open this status in the moderation interface",
296
+  "status.admin_status": "Open this tŵt in the moderation interface",
297 297
   "status.block": "Blocio @{name}",
298 298
   "status.cancel_reblog_private": "Dadfŵstio",
299 299
   "status.cannot_reblog": "Ni ellir sbarduno'r tŵt hwn",
@@ -309,7 +309,7 @@
309 309
   "status.more": "Mwy",
310 310
   "status.mute": "Tawelu @{name}",
311 311
   "status.mute_conversation": "Tawelu sgwrs",
312
-  "status.open": "Ehangu'r statws hwn",
312
+  "status.open": "Ehangu'r tŵt hwn",
313 313
   "status.pin": "Pinio ar y proffil",
314 314
   "status.pinned": "Pinio tŵt",
315 315
   "status.read_more": "Darllen mwy",

+ 37
- 0
app/javascript/mastodon/locales/defaultMessages.json View File

@@ -1973,6 +1973,43 @@
1973 1973
         "id": "confirmations.block.confirm"
1974 1974
       },
1975 1975
       {
1976
+        "defaultMessage": "Reply",
1977
+        "id": "confirmations.reply.confirm"
1978
+      },
1979
+      {
1980
+        "defaultMessage": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
1981
+        "id": "confirmations.reply.message"
1982
+      },
1983
+      {
1984
+        "defaultMessage": "Are you sure you want to block {name}?",
1985
+        "id": "confirmations.block.message"
1986
+      }
1987
+    ],
1988
+    "path": "app/javascript/mastodon/features/status/containers/detailed_status_container.json"
1989
+  },
1990
+  {
1991
+    "descriptors": [
1992
+      {
1993
+        "defaultMessage": "Delete",
1994
+        "id": "confirmations.delete.confirm"
1995
+      },
1996
+      {
1997
+        "defaultMessage": "Are you sure you want to delete this status?",
1998
+        "id": "confirmations.delete.message"
1999
+      },
2000
+      {
2001
+        "defaultMessage": "Delete & redraft",
2002
+        "id": "confirmations.redraft.confirm"
2003
+      },
2004
+      {
2005
+        "defaultMessage": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
2006
+        "id": "confirmations.redraft.message"
2007
+      },
2008
+      {
2009
+        "defaultMessage": "Block",
2010
+        "id": "confirmations.block.confirm"
2011
+      },
2012
+      {
1976 2013
         "defaultMessage": "Show more for all",
1977 2014
         "id": "status.show_more_all"
1978 2015
       },

+ 1
- 1
app/javascript/mastodon/locales/ro.json View File

@@ -132,7 +132,7 @@
132 132
   "follow_request.authorize": "Autorizează",
133 133
   "follow_request.reject": "Respinge",
134 134
   "getting_started.developers": "Dezvoltatori",
135
-  "getting_started.directory": "Directorul profilului",
135
+  "getting_started.directory": "Explorează",
136 136
   "getting_started.documentation": "Documentație",
137 137
   "getting_started.heading": "Începe",
138 138
   "getting_started.invite": "Invită prieteni",

+ 1
- 1
app/javascript/mastodon/locales/sk.json View File

@@ -70,7 +70,7 @@
70 70
   "compose_form.direct_message_warning": "Tento príspevok bude videný výhradne iba spomenutými užívateľmi. Ber ale na vedomie že správci tvojej a všetkých iných zahrnutých instancií majú možnosť skontrolovať túto správu.",
71 71
   "compose_form.direct_message_warning_learn_more": "Zistiť viac",
72 72
   "compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.",
73
-  "compose_form.lock_disclaimer": "Váš účet nie je zamknutý. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
73
+  "compose_form.lock_disclaimer": "Váš účet nie je {locked}. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
74 74
   "compose_form.lock_disclaimer.lock": "zamknutý",
75 75
   "compose_form.placeholder": "Čo máš na mysli?",
76 76
   "compose_form.publish": "Pošli",

+ 8
- 0
app/javascript/packs/public.js View File

@@ -91,6 +91,14 @@ function main() {
91 91
     if (parallaxComponents.length > 0 ) {
92 92
       new Rellax('.parallax', { speed: -1 });
93 93
     }
94
+
95
+    if (document.body.classList.contains('with-modals')) {
96
+      const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
97
+      const scrollbarWidthStyle = document.createElement('style');
98
+      scrollbarWidthStyle.id = 'scrollbar-width';
99
+      document.head.appendChild(scrollbarWidthStyle);
100
+      scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0);
101
+    }
94 102
   });
95 103
 }
96 104
 

+ 1
- 1
app/javascript/styles/mastodon/about.scss View File

@@ -364,7 +364,7 @@ $small-breakpoint: 960px;
364 364
 
365 365
   @media screen and (max-width: $column-breakpoint) {
366 366
     .grid {
367
-      grid-template-columns: auto;
367
+      grid-template-columns: 100%;
368 368
 
369 369
       .column-0 {
370 370
         display: block;

+ 1
- 1
app/javascript/styles/mastodon/containers.scss View File

@@ -295,7 +295,7 @@
295 295
         color: $primary-text-color;
296 296
       }
297 297
 
298
-      @media screen and (max-width: $no-gap-breakpoint) {
298
+      @media screen and (max-width: 550px) {
299 299
         &.optional {
300 300
           display: none;
301 301
         }

+ 1
- 1
app/javascript/styles/mastodon/forms.scss View File

@@ -419,7 +419,7 @@ code {
419 419
     background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") no-repeat right 8px center / auto 16px;
420 420
     border: 1px solid darken($ui-base-color, 14%);
421 421
     border-radius: 4px;
422
-    padding: 10px;
422
+    padding-left: 10px;
423 423
     padding-right: 30px;
424 424
     height: 41px;
425 425
   }

+ 90
- 0
app/javascript/styles/mastodon/widgets.scss View File

@@ -425,3 +425,93 @@
425 425
     border-radius: 0;
426 426
   }
427 427
 }
428
+
429
+$maximum-width: 1235px;
430
+$fluid-breakpoint: $maximum-width + 20px;
431
+
432
+.statuses-grid {
433
+  min-height: 600px;
434
+
435
+  @media screen and (max-width: 640px) {
436
+    width: 100% !important; // Masonry layout is unnecessary at this width
437
+  }
438
+
439
+  &__item {
440
+    width: (960px - 20px) / 3;
441
+
442
+    @media screen and (max-width: $fluid-breakpoint) {
443
+      width: (940px - 20px) / 3;
444
+    }
445
+
446
+    @media screen and (max-width: 640px) {
447
+      width: 100%;
448
+    }
449
+
450
+    @media screen and (max-width: $no-gap-breakpoint) {
451
+      width: 100vw;
452
+    }
453
+  }
454
+
455
+  .detailed-status {
456
+    border-radius: 4px;
457
+
458
+    @media screen and (max-width: $no-gap-breakpoint) {
459
+      border-top: 1px solid lighten($ui-base-color, 16%);
460
+    }
461
+
462
+    &.compact {
463
+      .detailed-status__meta {
464
+        margin-top: 15px;
465
+      }
466
+
467
+      .status__content {
468
+        font-size: 15px;
469
+        line-height: 20px;
470
+
471
+        .emojione {
472
+          width: 20px;
473
+          height: 20px;
474
+          margin: -3px 0 0;
475
+        }
476
+
477
+        .status__content__spoiler-link {
478
+          line-height: 20px;
479
+          margin: 0;
480
+        }
481
+      }
482
+
483
+      .media-gallery,
484
+      .status-card,
485
+      .video-player {
486
+        margin-top: 15px;
487
+      }
488
+    }
489
+  }
490
+}
491
+
492
+.notice-widget {
493
+  margin-bottom: 10px;
494
+  color: $darker-text-color;
495
+
496
+  p {
497
+    margin-bottom: 10px;
498
+
499
+    &:last-child {
500
+      margin-bottom: 0;
501
+    }
502
+  }
503
+
504
+  a {
505
+    font-size: 14px;
506
+    line-height: 20px;
507
+    text-decoration: none;
508
+    font-weight: 500;
509
+    color: $ui-highlight-color;
510
+
511
+    &:hover,
512
+    &:focus,
513
+    &:active {
514
+      text-decoration: underline;
515
+    }
516
+  }
517
+}

+ 13
- 1
app/lib/activitypub/activity/announce.rb View File

@@ -17,7 +17,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
17 17
       uri: @json['id'],
18 18
       created_at: @json['published'],
19 19
       override_timestamps: @options[:override_timestamps],
20
-      visibility: original_status.visibility
20
+      visibility: visibility_from_audience
21 21
     )
22 22
 
23 23
     distribute(status)
@@ -26,6 +26,18 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
26 26
 
27 27
   private
28 28
 
29
+  def visibility_from_audience
30
+    if equals_or_includes?(@json['to'], ActivityPub::TagManager::COLLECTIONS[:public])
31
+      :public
32
+    elsif equals_or_includes?(@json['cc'], ActivityPub::TagManager::COLLECTIONS[:public])
33
+      :unlisted
34
+    elsif equals_or_includes?(@json['to'], @account.followers_url)
35
+      :private
36
+    else
37
+      :direct
38
+    end
39
+  end
40
+
29 41
   def announceable?(status)
30 42
     status.account_id == @account.id || status.public_visibility? || status.unlisted_visibility?
31 43
   end

+ 6
- 3
app/lib/activitypub/activity/create.rb View File

@@ -5,10 +5,13 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
5 5
   CONVERTED_TYPES = %w(Image Video Article Page).freeze
6 6
 
7 7
   def perform
8
-    return if delete_arrived_first?(object_uri) || unsupported_object_type? || invalid_origin?(@object['id'])
8
+    return if unsupported_object_type? || invalid_origin?(@object['id'])
9
+    return if Tombstone.exists?(uri: @object['id'])
9 10
 
10 11
     RedisLock.acquire(lock_options) do |lock|
11 12
       if lock.acquired?
13
+        return if delete_arrived_first?(object_uri)
14
+
12 15
         @status = find_existing_status
13 16
 
14 17
         if @status.nil?
@@ -59,7 +62,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
59 62
         account: @account,
60 63
         text: text_from_content || '',
61 64
         language: detected_language,
62
-        spoiler_text: text_from_summary || '',
65
+        spoiler_text: converted_object_type? ? '' : (text_from_summary || ''),
63 66
         created_at: @object['published'],
64 67
         override_timestamps: @options[:override_timestamps],
65 68
         reply: @object['inReplyTo'].present?,
@@ -254,7 +257,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
254 257
   end
255 258
 
256 259
   def text_from_content
257
-    return Formatter.instance.linkify([text_from_name, object_url || @object['id']].join(' ')) if converted_object_type?
260
+    return Formatter.instance.linkify([[text_from_name, text_from_summary.presence].compact.join("\n\n"), object_url || @object['id']].join(' ')) if converted_object_type?
258 261
 
259 262
     if @object['content'].present?
260 263
       @object['content']

+ 18
- 2
app/lib/activitypub/activity/delete.rb View File

@@ -21,11 +21,14 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
21 21
   def delete_note
22 22
     return if object_uri.nil?
23 23
 
24
+    unless invalid_origin?(object_uri)
25
+      RedisLock.acquire(lock_options) { |_lock| delete_later!(object_uri) }
26
+      Tombstone.find_or_create_by(uri: object_uri, account: @account)
27
+    end
28
+
24 29
     @status   = Status.find_by(uri: object_uri, account: @account)
25 30
     @status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
26 31
 
27
-    delete_later!(object_uri)
28
-
29 32
     return if @status.nil?
30 33
 
31 34
     if @status.public_visibility? || @status.unlisted_visibility?
@@ -68,4 +71,17 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
68 71
   def payload
69 72
     @payload ||= Oj.dump(@json)
70 73
   end
74
+
75
+  def lock_options
76
+    { redis: Redis.current, key: "create:#{object_uri}" }
77
+  end
78
+
79
+  def invalid_origin?(url)
80
+    return true if unsupported_uri_scheme?(url)
81
+
82
+    needle   = Addressable::URI.parse(url).host
83
+    haystack = Addressable::URI.parse(@account.uri).host
84
+
85
+    !haystack.casecmp(needle).zero?
86
+  end
71 87
 end

+ 2
- 2
app/models/status.rb View File

@@ -504,7 +504,7 @@ class Status < ApplicationRecord
504 504
     return if direct_visibility?
505 505
 
506 506
     account&.increment_count!(:statuses_count)
507
-    reblog&.increment_count!(:reblogs_count) if reblog?
507
+    reblog&.increment_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
508 508
     thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
509 509
   end
510 510
 
@@ -512,7 +512,7 @@ class Status < ApplicationRecord
512 512
     return if direct_visibility? || marked_for_mass_destruction?
513 513
 
514 514
     account&.decrement_count!(:statuses_count)
515
-    reblog&.decrement_count!(:reblogs_count) if reblog?
515
+    reblog&.decrement_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
516 516
     thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
517 517
   end
518 518
 

+ 16
- 0
app/models/tombstone.rb View File

@@ -0,0 +1,16 @@
1
+# frozen_string_literal: true
2
+
3
+# == Schema Information
4
+#
5
+# Table name: tombstones
6
+#
7
+#  id         :bigint(8)        not null, primary key
8
+#  account_id :bigint(8)
9
+#  uri        :string           not null
10
+#  created_at :datetime         not null
11
+#  updated_at :datetime         not null
12
+#
13
+
14
+class Tombstone < ApplicationRecord
15
+  belongs_to :account
16
+end

+ 2
- 1
app/models/user.rb View File

@@ -362,7 +362,8 @@ class User < ApplicationRecord
362 362
   end
363 363
 
364 364
   def regenerate_feed!
365
-    Redis.current.setnx("account:#{account_id}:regeneration", true) && Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds)
365
+    return unless Redis.current.setnx("account:#{account_id}:regeneration", true)
366
+    Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds)
366 367
     RegenerationWorker.perform_async(account_id)
367 368
   end
368 369
 

+ 6
- 0
app/services/activitypub/process_account_service.rb View File

@@ -33,6 +33,8 @@ class ActivityPub::ProcessAccountService < BaseService
33 33
 
34 34
     after_protocol_change! if protocol_changed?
35 35
     after_key_change! if key_changed? && !@options[:signed_with_known_key]
36
+    clear_tombstones! if key_changed?
37
+
36 38
     unless @options[:only_key]
37 39
       check_featured_collection! if @account.featured_collection_url.present?
38 40
       check_links! unless @account.fields.empty?
@@ -209,6 +211,10 @@ class ActivityPub::ProcessAccountService < BaseService
209 211
     !@old_public_key.nil? && @old_public_key != @account.public_key
210 212
   end
211 213
 
214
+  def clear_tombstones!
215
+    Tombstone.delete_all(account_id: @account.id)
216
+  end
217
+
212 218
   def protocol_changed?
213 219
     !@old_protocol.nil? && @old_protocol != @account.protocol
214 220
   end

+ 1
- 0
app/services/precompute_feed_service.rb View File

@@ -3,6 +3,7 @@
3 3
 class PrecomputeFeedService < BaseService
4 4
   def call(account)
5 5
     FeedManager.instance.populate_feed(account)
6
+  ensure
6 7
     Redis.current.del("account:#{account.id}:regeneration")
7 8
   end
8 9
 end

+ 15
- 0
app/services/unfollow_service.rb View File

@@ -20,6 +20,7 @@ class UnfollowService < BaseService
20 20
 
21 21
     follow.destroy!
22 22
     create_notification(follow) unless @target_account.local?
23
+    create_reject_notification(follow) if @target_account.local? && !@source_account.local?
23 24
     UnmergeWorker.perform_async(@target_account.id, @source_account.id)
24 25
     follow
25 26
   end
@@ -42,6 +43,12 @@ class UnfollowService < BaseService
42 43
     end
43 44
   end
44 45
 
46
+  def create_reject_notification(follow)
47
+    # Rejecting an already-existing follow request
48
+    return unless follow.account.activitypub?
49
+    ActivityPub::DeliveryWorker.perform_async(build_reject_json(follow), follow.target_account_id, follow.account.inbox_url)
50
+  end
51
+
45 52
   def build_json(follow)
46 53
     ActiveModelSerializers::SerializableResource.new(
47 54
       follow,
@@ -50,6 +57,14 @@ class UnfollowService < BaseService
50 57
     ).to_json
51 58
   end
52 59
 
60
+  def build_reject_json(follow)
61
+    ActiveModelSerializers::SerializableResource.new(
62
+      follow,
63
+      serializer: ActivityPub::RejectFollowSerializer,
64
+      adapter: ActivityPub::Adapter
65
+    ).to_json
66
+  end
67
+
53 68
   def build_xml(follow)
54 69
     OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfollow_salmon(follow))
55 70
   end

+ 16
- 2
app/views/directories/index.html.haml View File

@@ -41,8 +41,22 @@
41 41
       = paginate @accounts
42 42
 
43 43
   .column-1
44
-    - if @tags.empty?
45
-      .nothing-here.nothing-here--flexible
44
+    - if user_signed_in?
45
+      .box-widget.notice-widget
46
+        - if current_account.discoverable?
47
+          - if current_account.followers_count < Account::MIN_FOLLOWERS_DISCOVERY
48
+            %p= t('directories.enabled_but_waiting', min_followers: Account::MIN_FOLLOWERS_DISCOVERY)
49
+          - else
50
+            %p= t('directories.enabled')
51
+        - else
52
+          %p= t('directories.how_to_enable')
53
+
54
+          = link_to settings_profile_path do
55
+            = t('settings.edit_profile')
56
+            = fa_icon 'chevron-right fw'
57
+
58
+    - if @tags.empty? && !user_signed_in?
59
+      .nothing-here
46 60
     - else
47 61
       - @tags.each do |tag|
48 62
         .directory__tag{ class: tag.id == @tag&.id ? 'active' : nil }

+ 0
- 25
app/views/tags/_features.html.haml View File

@@ -1,25 +0,0 @@
1
-.features-list
2
-  .features-list__row
3
-    .text
4
-      %h6= t 'about.features.real_conversation_title'
5
-      = t 'about.features.real_conversation_body'
6
-    .visual
7
-      = fa_icon 'fw comments'
8
-  .features-list__row
9
-    .text
10
-      %h6= t 'about.features.not_a_product_title'
11
-      = t 'about.features.not_a_product_body'
12
-    .visual
13
-      = fa_icon 'fw users'
14
-  .features-list__row
15
-    .text
16
-      %h6= t 'about.features.within_reach_title'
17
-      = t 'about.features.within_reach_body'
18
-    .visual
19
-      = fa_icon 'fw mobile'
20
-  .features-list__row
21
-    .text
22
-      %h6= t 'about.features.humane_approach_title'
23
-      = t 'about.features.humane_approach_body'
24
-    .visual
25
-      = fa_icon 'fw leaf'

+ 4
- 28
app/views/tags/show.html.haml View File

@@ -7,33 +7,9 @@
7 7
   %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
8 8
   = render 'og'
9 9
 
10
-.landing-page.tag-page.alternative
11
-  .features
12
-    .container
13
-      .grid
14
-        .column-1
15
-          #mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name)) } }
16
-
17
-        .column-2
18
-          .about-mastodon
19
-            .about-hashtag.landing-page__information
20
-              .brand
21
-                = link_to root_url do
22
-                  = image_tag asset_pack_path('logo_full.svg'), alt: 'Mastodon'
23
-
24
-              %p= t 'about.about_hashtag_html', hashtag: @tag.name
25
-
26
-              .cta
27
-                - if user_signed_in?
28
-                  = link_to t('settings.back'), root_path, class: 'button button-secondary'
29
-                - else
30
-                  = link_to t('auth.login'), new_user_session_path, class: 'button button-secondary'
31
-                = link_to t('about.learn_more'), about_path, class: 'button button-alternative'
32
-
33
-            .landing-page__features.landing-page__information
34
-              %h3= t 'about.what_is_mastodon'
35
-              %p= t 'about.about_mastodon_html'
36
-
37
-              = render 'features'
10
+.page-header
11
+  %h1= "##{@tag.name}"
12
+  %p= t('about.about_hashtag_html', hashtag: @tag.name)
38 13
 
14
+#mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name)) }}
39 15
 #modal-container

+ 1
- 1
config/deploy.rb View File

@@ -1,6 +1,6 @@
1 1
 # frozen_string_literal: true
2 2
 
3
-lock '3.10.2'
3
+lock '3.11.0'
4 4
 
5 5
 set :repo_url, ENV.fetch('REPO', 'https://github.com/tootsuite/mastodon.git')
6 6
 set :branch, ENV.fetch('BRANCH', 'master')

+ 3
- 0
config/initializers/paperclip.rb View File

@@ -36,6 +36,9 @@ if ENV['S3_ENABLED'] == 'true'
36 36
     },
37 37
     s3_options: {
38 38
       signature_version: ENV.fetch('S3_SIGNATURE_VERSION') { 'v4' },
39
+      http_open_timeout: 5,
40
+      http_read_timeout: 5,
41
+      http_idle_timeout: 5,
39 42
     }
40 43
   )
41 44
 

+ 3
- 3
config/locales/cs.yml View File

@@ -2,7 +2,7 @@
2 2
 cs:
3 3
   about:
4 4
     about_hashtag_html: Tohle jsou veřejné tooty označené hashtagem <strong>#%{hashtag}</strong>. Pokud máte účet kdekoliv na fediverse, můžete s nimi interagovat.
5
-    about_mastodon_html: Mastodon je sociální síť založená na otevřených webových protokolech a svobodném, otevřeném softwaru. Je decentrovalizovaná jako e-mail.
5
+    about_mastodon_html: Mastodon je sociální síť založená na otevřených webových protokolech a svobodném, otevřeném softwaru. Je decentralizovaná jako e-mail.
6 6
     about_this: O této instanci
7 7
     administered_by: 'Instanci spravuje:'
8 8
     api: API
@@ -310,7 +310,7 @@ cs:
310 310
     instances:
311 311
       delivery_available: Doručení je k dispozici
312 312
       known_accounts:
313
-        few: "%{count} známých účtů"
313
+        few: "%{count} známé účty"
314 314
         one: "%{count} známý účet"
315 315
         other: "%{count} známých účtů"
316 316
       moderation:
@@ -686,7 +686,7 @@ cs:
686 686
       body: Zde najdete stručný souhrn zpráv, které jste zmeškal/a od vaší poslední návštěvy %{since}
687 687
       mention: "%{name} vás zmínil/a v:"
688 688
       new_followers_summary:
689
-        few: Navíc jste získal/a %{count} nové sledovatele, zatímco jste byl/a pryč! Hurá!
689
+        few: Navíc jste získal/a %{count} nové sledovatele, zatímco jste byl/a pryč! Skvělé!
690 690
         one: Navíc jste získal/a jednoho nového sledovatele, zatímco jste byl/a pryč! Hurá!
691 691
         other: Navíc jste získal/a %{count} nových sledovatelů, zatímco jste byl/a pryč! Úžasné!
692 692
       subject:

+ 36
- 36
config/locales/de.yml View File

@@ -1,7 +1,7 @@
1 1
 ---
2 2
 de:
3 3
   about:
4
-    about_hashtag_html: Dies sind öffentliche Beiträge, die mit <strong>#%{hashtag}</strong> getaggt wurden. Wenn du ein Konto irgendwo im Fediversum besitzt, kannst du mit ihnen interagieren.
4
+    about_hashtag_html: Dies sind öffentliche Beiträge, die mit <strong>#%{hashtag}</strong> getaggt wurden. Wenn du irgendwo im Fediversum ein Konto besitzt, kannst du mit ihnen interagieren.
5 5
     about_mastodon_html: Mastodon ist ein soziales Netzwerk. Es basiert auf offenen Web-Protokollen und freier, quelloffener Software. Es ist dezentral (so wie E-Mail!).
6 6
     about_this: Über diese Instanz
7 7
     administered_by: 'Administriert von:'
@@ -22,7 +22,7 @@ de:
22 22
       not_a_product_title: Du bist ein Mensch und keine Ware
23 23
       real_conversation_body: Mit 500 Zeichen pro Beitrag und Features wie Inhalts- und Bilderwarnungen kannst du dich so ausdrücken, wie du es möchtest.
24 24
       real_conversation_title: Geschaffen für echte Gespräche
25
-      within_reach_body: Verschiedene Apps für iOS, Android und andere Plattformen erlauben dir, dank unseres blühenden API-Ökosystems, dich von überall auf dem Laufenden zu halten.
25
+      within_reach_body: Verschiedene Apps für iOS, Android und andere Plattformen erlauben es dir, dank unseres blühenden API-Ökosystems, dich von überall auf dem Laufenden zu halten.
26 26
       within_reach_title: Immer für dich da
27 27
     generic_description: "%{domain} ist ein Server im Netzwerk"
28 28
     hosted_on: Mastodon, beherbergt auf %{domain}
@@ -44,8 +44,8 @@ de:
44 44
     choices_html: "%{name} empfiehlt:"
45 45
     follow: Folgen
46 46
     followers:
47
-      one: Folgende
48
-      other: Follower
47
+      one: Folgender
48
+      other: Folgende
49 49
     following: Folgt
50 50
     joined: Beigetreten am %{date}
51 51
     last_active: zuletzt aktiv
@@ -81,7 +81,7 @@ de:
81 81
     accounts:
82 82
       are_you_sure: Bist du sicher?
83 83
       avatar: Profilbild
84
-      by_domain: Domäne
84
+      by_domain: Domain
85 85
       change_email:
86 86
         changed_msg: E-Mail-Adresse des Kontos erfolgreich geändert!
87 87
         current_email: Aktuelle E-Mail-Adresse
@@ -105,7 +105,7 @@ de:
105 105
       enable: Freischalten
106 106
       enabled: Freigegeben
107 107
       feed_url: Feed-URL
108
-      followers: Folger
108
+      followers: Folgende
109 109
       followers_local: "(%{local} lokal)"
110 110
       followers_url: URL des Folgenden
111 111
       follows: Folgt
@@ -194,17 +194,17 @@ de:
194 194
         disable_user: "%{name} hat den Login für Benutzer:in  %{target} deaktiviert"
195 195
         enable_custom_emoji: "%{name} hat das %{target} Emoji aktiviert"
196 196
         enable_user: "%{name} hat die Anmeldung für di:en Benutzer:in %{target} aktiviert"
197
-        memorialize_account: "%{name} hat %{target}s Profil in eine Gedenkseite umgewandelt"
197
+        memorialize_account: "%{name} hat %{target}s Konto in eine Gedenkseite umgewandelt"
198 198
         promote_user: "%{name} hat %{target} befördert"
199 199
         remove_avatar_user: "%{name} hat das Profilbild von %{target} entfernt"
200 200
         reopen_report: "%{name} hat die Meldung %{target} wieder geöffnet"
201 201
         reset_password_user: "%{name} hat das Passwort für di:en Benutzer:in %{target} zurückgesetzt"
202 202
         resolve_report: "%{name} hat die Meldung %{target} bearbeitet"
203
-        silence_account: "%{name} hat %{target}s Account stummgeschaltet"
204
-        suspend_account: "%{name} hat %{target}s Account gesperrt"
203
+        silence_account: "%{name} hat %{target}s Konto stummgeschaltet"
204
+        suspend_account: "%{name} hat %{target}s Konto gesperrt"
205 205
         unassigned_report: "%{name} hat die Zuweisung der Meldung %{target} entfernt"
206
-        unsilence_account: "%{name} hat die Stummschaltung von %{target}s Account aufgehoben"
207
-        unsuspend_account: "%{name} hat die Sperrung von %{target}s Account aufgehoben"
206
+        unsilence_account: "%{name} hat die Stummschaltung von %{target}s Konto aufgehoben"
207
+        unsuspend_account: "%{name} hat die Sperrung von %{target}s Konto aufgehoben"
208 208
         update_custom_emoji: "%{name} hat das %{target} Emoji aktualisiert"
209 209
         update_status: "%{name} hat den Status von %{target} aktualisiert"
210 210
       deleted_status: "(gelöschter Beitrag)"
@@ -300,12 +300,12 @@ de:
300 300
         title: Neue E-Mail-Domain-Blockade
301 301
       title: E-Mail-Domain-Blockade
302 302
     followers:
303
-      back_to_account: Zurück zum Account
303
+      back_to_account: Zurück zum Konto
304 304
       title: "%{acct}'s Follower"
305 305
     instances:
306 306
       delivery_available: Zustellung ist verfügbar
307 307
       known_accounts:
308
-        one: "%{count} bekannter Account"
308
+        one: "%{count} bekanntes Konto"
309 309
         other: "%{count} bekannte Accounts"
310 310
       moderation:
311 311
         all: Alle
@@ -506,8 +506,8 @@ de:
506 506
     invalid_reset_password_token: Das Token zum Zurücksetzen des Passworts ist ungültig oder abgelaufen. Bitte fordere ein neues an.
507 507
     login: Anmelden
508 508
     logout: Abmelden
509
-    migrate_account: Ziehe zu einem anderen Account um
510
-    migrate_account_html: Wenn du es wünschst diesen Account zu einem anderen umzuziehen, dann kannst du <a href="%{path}">es hier einstellen</a>.
509
+    migrate_account: Ziehe zu einem anderen Konto um
510
+    migrate_account_html: Wenn du wünschst, dieses Konto zu einem anderen umzuziehen, kannst du <a href="%{path}">dies hier einstellen</a>.
511 511
     or: oder
512 512
     or_log_in_with: Oder anmelden mit
513 513
     providers:
@@ -521,7 +521,7 @@ de:
521 521
     set_new_password: Neues Passwort setzen
522 522
   authorize_follow:
523 523
     already_following: Du folgst diesem Konto bereits
524
-    error: Das Profil konnte nicht geladen werden
524
+    error: Das Remote-Konto konnte nicht geladen werden
525 525
     follow: Folgen
526 526
     follow_request: 'Du hast eine Folgeanfrage gesendet an:'
527 527
     following: 'Erfolg! Du folgst nun:'
@@ -655,7 +655,7 @@ de:
655 655
     table:
656 656
       expires_at: Läuft ab
657 657
       uses: Verwendungen
658
-    title: Leute Einladen
658
+    title: Leute einladen
659 659
   lists:
660 660
     errors:
661 661
       limit: Du hast die maximale Anzahl an Listen erreicht
@@ -664,10 +664,10 @@ de:
664 664
       images_and_video: Es kann kein Video an einen Beitrag, der bereits Bilder enthält, angehängt werden
665 665
       too_many: Es können nicht mehr als 4 Bilder angehängt werden
666 666
   migrations:
667
-    acct: benutzername@domain des neuen Accounts
667
+    acct: benutzername@domain des neuen Kontos
668 668
     currently_redirecting: 'Deine Profilweiterleitung wurde gesetzt auf:'
669 669
     proceed: Speichern
670
-    updated_msg: Deine Account-Migrationseinstellungen wurden erfolgreich aktualisiert!
670
+    updated_msg: Deine Konto-Migrationseinstellungen wurden erfolgreich aktualisiert!
671 671
   moderation:
672 672
     title: Moderation
673 673
   notification_mailer:
@@ -729,7 +729,7 @@ de:
729 729
   remote_follow:
730 730
     acct: Profilname@Domain, von wo aus du dieser Person folgen möchtest
731 731
     missing_resource: Die erforderliche Weiterleitungs-URL für dein Konto konnte nicht gefunden werden
732
-    no_account_html: Noch keinen Account? Du kannst dich <a href='%{sign_up_path}' target='_blank'>hier anmelden</a>
732
+    no_account_html: Noch kein Konto? Du kannst dich <a href='%{sign_up_path}' target='_blank'>hier anmelden</a>
733 733
     proceed: Weiter
734 734
     prompt: 'Du wirst dieser Person folgen:'
735 735
     reason_html: "<strong>Warum ist dieser Schritt erforderlich?</strong><code>%{instance}</code> ist möglicherweise nicht der Server auf dem du registriert bist, also müssen wir dich erst auf deinen Heimserver weiterleiten."
@@ -774,7 +774,7 @@ de:
774 774
       weibo: Weibo
775 775
     current_session: Aktuelle Sitzung
776 776
     description: "%{browser} auf %{platform}"
777
-    explanation: Dies sind die Webbrowser, die derzeit in dein Mastodon-Konto eingeloggt sind.
777
+    explanation: Dies sind die Webbrowser, die derzeit in deinem Mastodon-Konto eingeloggt sind.
778 778
     ip: IP-Adresse
779 779
     platforms:
780 780
       adobe_air: Adobe Air
@@ -801,7 +801,7 @@ de:
801 801
     export: Datenexport
802 802
     followers: Autorisierte Folgende
803 803
     import: Datenimport
804
-    migrate: Account-Umzug
804
+    migrate: Konto-Umzug
805 805
     notifications: Benachrichtigungen
806 806
     preferences: Einstellungen
807 807
     settings: Einstellungen
@@ -842,7 +842,7 @@ de:
842 842
   stream_entries:
843 843
     pinned: Angehefteter Beitrag
844 844
     reblogged: teilte
845
-    sensitive_content: Heikle Inhalte
845
+    sensitive_content: Sensible Inhalte
846 846
   terms:
847 847
     body_html: |
848 848
       <h2>Datenschutzerklärung</h2>
@@ -948,33 +948,33 @@ de:
948 948
     manual_instructions: 'Wenn du den QR-Code nicht einlesen kannst und ihn manuell eingeben musst, ist hier das Klartext-Geheimnis:'
949 949
     recovery_codes: Wiederherstellungs-Codes sichern
950 950
     recovery_codes_regenerated: Wiederherstellungscodes erfolgreich neu generiert
951
-    recovery_instructions_html: Wenn du den Zugang zu deinem Telefon verlieren solltest, kannst du einen untenstehenden Wiederherstellungscodes benutzen, um wieder auf dein Konto zugreifen zu können. <strong>Bewahre die Wiederherstellungscodes gut auf.</strong> Du könntest sie beispielsweise ausdrucken und bei deinen restlichen wichtigen Dokumenten aufbewahren.
951
+    recovery_instructions_html: Wenn du den Zugang zu deinem Telefon verlieren solltest, kannst du einen untenstehenden Wiederherstellungscode benutzen, um wieder auf dein Konto zugreifen zu können. <strong>Bewahre die Wiederherstellungscodes gut auf.</strong> Du könntest sie beispielsweise ausdrucken und bei deinen restlichen wichtigen Dokumenten aufbewahren.
952 952
     setup: Einrichten
953 953
     wrong_code: Der eingegebene Code war ungültig! Stimmen Serverzeit und Gerätezeit?
954 954
   user_mailer:
955 955
     backup_ready:
956
-      explanation: Du hast ein vollständiges Backup von deinem Mastodon-Account angefragt. Es kann jetzt heruntergeladen werden!
956
+      explanation: Du hast ein vollständiges Backup von deinem Mastodon-Konto angefragt. Es kann jetzt heruntergeladen werden!
957 957
       subject: Dein Archiv ist bereit zum Download
958 958
       title: Archiv-Download
959 959
     warning:
960 960
       explanation:
961
-        disable: Solange dein Account eingefroren ist sind deine Benutzerdaten intakt, aber du kannst nichts tun bis dein Account entsperrt wurde.
962
-        silence: Solange dein Account limitiert ist können nur Leute, die dir bereits folgen deine Beiträge auf dem Server sehen und es könnte sein, dass du von verschiedenen öffentlichen Listungen ausgeschlossen wirst. Andererseits können andere dir manuell folgen.
963
-        suspend: Dein Account wurde gesperrt und alle deine Beiträge und hochgeladenen Medien wurden unwiderruflich vom Server und anderen Servern wo du Follower hattest gelöscht.
961
+        disable: Solange dein Konto eingefroren ist, sind deine Benutzerdaten intakt; aber du kannst nichts tun, bis dein Konto entsperrt wurde.
962
+        silence: Solange dein Konto limitiert ist, können nur die Leute, die dir bereits folgen, deine Beiträge auf dem Server sehen und es könnte sein, dass du von verschiedenen öffentlichen Listungen ausgeschlossen wirst. Andererseits können andere dir manuell folgen.
963
+        suspend: Dein Konto wurde gesperrt und alle deine Beiträge und hochgeladenen Medien wurden unwiderruflich vom Server und anderen Servern, bei denen du Folgende hattest, gelöscht.
964 964
       review_server_policies: Serverrichtlinien ansehen
965 965
       subject:
966
-        disable: Dein Account %{acct} wurde eingefroren
966
+        disable: Dein Konto %{acct} wurde eingefroren
967 967
         none: Warnung für %{acct}
968
-        silence: Dein Account %{acct} wurde limitiert
969
-        suspend: Dein Account %{acct} wurde gesperrt
968
+        silence: Dein Konto %{acct} wurde limitiert
969
+        suspend: Dein Konto %{acct} wurde gesperrt
970 970
       title:
971
-        disable: Account eingefroren
971
+        disable: Konto eingefroren
972 972
         none: Warnung
973
-        silence: Account limitiert
974
-        suspend: Account gesperrt
973
+        silence: Konto limitiert
974
+        suspend: Konto gesperrt
975 975
     welcome:
976 976
       edit_profile_action: Profil einstellen
977
-      edit_profile_step: Du kannst dein Profil anpassen, indem du einen Avatar oder ein Titelbild hochlädst oder deinen Anzeigenamen änderst und mehr. Wenn du deine Follower vorher überprüfen möchtest, bevor sie dir folgen können, dann kannst du dein Profil sperren.
977
+      edit_profile_step: Du kannst dein Profil anpassen, indem du einen Avatar oder ein Titelbild hochlädst oder deinen Anzeigenamen änderst und mehr. Wenn du deine Folgenden vorher überprüfen möchtest, bevor sie dir folgen können, dann kannst du dein Profil sperren.
978 978
       explanation: Hier sind ein paar Tipps, um loszulegen
979 979
       final_action: Fang an zu posten
980 980
       final_step: 'Fang an zu posten! Selbst ohne Follower werden deine öffentlichen Beitrage von anderen gesehen, zum Beispiel auf der lokalen Zeitleiste oder in Hashtags. Vielleicht möchtest du dich vorstellen mit dem #introductions-Hashtag.'
@@ -997,5 +997,5 @@ de:
997 997
     seamless_external_login: Du bist angemeldet über einen Drittanbieter-Dienst, weswegen Passwort- und E-Maileinstellungen nicht verfügbar sind.
998 998
     signed_in_as: 'Angemeldet als:'
999 999
   verification:
1000
-    explanation_html: 'Du kannst <strong>bestätigen, dass die Links in deinen Profil-Metadaten dir gehören</strong>. Dafür muss die verlinkte Website einen Link zurück auf dein Mastodon-Profil enthalten. Dieser Link <strong>muss</strong> ein <code>rel="me"</code>-Attribut enthalten. Der Linktext is dabei egal. Hier ist ein Beispiel:'
1000
+    explanation_html: 'Du kannst <strong>bestätigen, dass die Links in deinen Profil-Metadaten dir gehören</strong>. Dafür muss die verlinkte Website einen Link zurück auf dein Mastodon-Profil enthalten. Dieser Link <strong>muss</strong> ein <code>rel="me"</code>-Attribut enthalten. Der Linktext ist dabei egal. Hier ist ein Beispiel:'
1001 1001
     verification: Verifizierung

+ 22
- 0
config/locales/devise.sr.yml View File

@@ -17,11 +17,33 @@ sr:
17 17
       unconfirmed: Пре наставка морате потврдити свој налог.
18 18
     mailer:
19 19
       confirmation_instructions:
20
+        action: Потврдите адресу е-поште
21
+        action_with_app: Потврди и врати се на %{app}
22
+        explanation: Направили сте налог на %{host} са адресом ове е-поште. На један клик сте удаљени од активирања. Ако ово нисте ви, молимо игноришите ову е-пошту.
23
+        extra_html: Молимо да такође проверите <a href="%{terms_path}"> правила ове инстанце и <a href="%{policy_path}"> наше услове коришћења.
20 24
         subject: 'Мастодонт: Упутство за потврду корисничког налога на инстанци %{instance}'
25
+        title: Потврдите адресу е-поште
26
+      email_changed:
27
+        explanation: 'Адреса ове е-поште за ваш налог ће бити промењена у:'
28
+        extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога.
29
+        subject: 'Мастодон: Е-пошта промењена'
30
+        title: Нова адреса е-поште
21 31
       password_change:
32
+        explanation: Лозинка вашег налога је промењена.
33
+        extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога.
22 34
         subject: 'Мастодонт: Лозинка промењена'
35
+        title: Лозинка промењена
36
+      reconfirmation_instructions:
37
+        explanation: Потврдите нову адресу да бисте променили е-пошту.
38
+        extra: Ако ова промена није иницирана са ваше стране, молимо игноришите ову е-пошту. Адреса е-пошта за овај Мастодон налог неће бити промењена док не приступите повезници/линку изнад.
39
+        subject: 'Мастодон: Потврдите е-пошту за %{instance}'
40
+        title: Потврдите адресу е-поште
23 41
       reset_password_instructions:
42
+        action: Лозинка промењена
43
+        explanation: Затражили сте нову лозинку за ваш налог.
44
+        extra: Ако нисте затражили ово, молимо игноришите ову е-пошту. Ваша лозинка неће бити промењена док не приступите повезници/линку изнад и не направите нову.
24 45
         subject: 'Мастодонт: Упутство за ресетовање лозинке'
46
+        title: Лозинка ресетована
25 47
       unlock_instructions:
26 48
         subject: 'Мастодонт: Упутство за откључавање корисничког налога'
27 49
     omniauth_callbacks:

+ 1
- 1
config/locales/doorkeeper.cs.yml View File

@@ -72,7 +72,7 @@ cs:
72 72
       index:
73 73
         application: Aplikace
74 74
         created_at: Autorizováno
75
-        date_format: "%d.%m.%Y %H:%M:%S"
75
+        date_format: "%d. %m. %Y %H:%M:%S"
76 76
         scopes: Rozsahy
77 77
         title: Vaše autorizované aplikace
78 78
     errors:

+ 3
- 0
config/locales/en.yml View File

@@ -556,8 +556,11 @@ en:
556 556
     warning_title: Disseminated content availability
557 557
   directories:
558 558
     directory: Profile directory
559
+    enabled: You are currently listed in the directory.
560
+    enabled_but_waiting: You have opted-in to be listed in the directory, but you do not have the minimum number of followers (%{min_followers}) to be listed yet.
559 561
     explanation: Discover users based on their interests
560 562
     explore_mastodon: Explore %{title}
563
+    how_to_enable: You are not currently opted-in to the directory. You can opt-in below. Use hashtags in your bio text to be listed under specific hashtags!
561 564
     people:
562 565
       one: "%{count} person"
563 566
       other: "%{count} people"

+ 3
- 1
config/locales/ro.yml View File

@@ -1,6 +1,8 @@
1 1
 ---
2 2
 ro:
3 3
   about:
4
+    features:
5
+      not_a_product_title: Ești o persoană, nu un produs
4 6
     hosted_on: Mastodon găzduit de %{domain}
5 7
   accounts:
6 8
     posts:
@@ -64,7 +66,7 @@ ro:
64 66
     success_msg: Contul tău a fost șterg. Nu mai poate fi recuperat :D
65 67
     warning_html: Doar ștergerea conținutului de pe acest server este garantată. Conținutul tău care a fost redistribuit în alte instațe e posibil să lase urme. Serverele deconecate sau care nu mai sunt abonate la actualizările contului tău nu își vor mai actualiza baza de date.
66 68
   directories:
67
-    explanation: Descoperă utilizatori în funcție de interesele lor
69
+    explanation: Descoperă oameni și companii în funcție de interesele lor
68 70
     explore_mastodon: Explorează %{title}
69 71
     people:
70 72
       few: "%{count} persoană"

+ 13
- 13
config/locales/simple_form.de.yml View File

@@ -10,14 +10,14 @@ de:
10 10
         type_html: Wähle aus, was du mit <strong>%{acct}</strong> machen möchtest
11 11
         warning_preset_id: Optional. Du kannst immer noch eigenen Text an das Ende der Vorlage hinzufügen
12 12
       defaults:
13
-        autofollow: Leute die sich über deine Einladung registrieren werden dir automatisch folgen
13
+        autofollow: Leute, die sich über deine Einladung registrieren, werden dir automatisch folgen
14 14
         avatar: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert
15 15
         bot: Dieses Konto führt lediglich automatisierte Aktionen durch und wird möglicherweise nicht überwacht
16 16
         context: Ein oder mehrere Aspekte, wo der Filter greifen soll
17 17
         digest: Wenn du lange Zeit inaktiv bist, wird dir eine Zusammenfassung von Erwähnungen in deiner Abwesenheit zugeschickt
18
-        discoverable_html: Das <a href="%{path}" target="_blank">Verzeichnis</a> lässt dich neue Benutzerkonten finden basierend auf Interessen und Aktivitäten. Dies benötigt mindestens %{min_followers} Follower
19
-        email: Du wirst ein Bestätigungs-E-Mail erhalten
20
-        fields: Du kannst bis zu 4 Elemente als Tabelle dargestellt auf deinem Profil anzeigen lassen
18
+        discoverable_html: Das <a href="%{path}" target="_blank">Verzeichnis</a> lässt dich basierend auf Interessen und Aktivitäten neue Benutzerkonten finden. Dies benötigt mindestens %{min_followers} Follower
19
+        email: Du wirst eine Bestätigungs-E-Mail erhalten
20
+        fields: Du kannst bis zu 4 Elemente auf deinem Profil anzeigen lassen, die als Tabelle dargestellt werden
21 21
         header: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert
22 22
         inbox_url: Kopiere die URL von der Startseite des gewünschten Relays
23 23
         irreversible: Gefilterte Beiträge werden unwiderruflich gefiltert, selbst wenn der Filter später entfernt wurde
@@ -31,11 +31,11 @@ de:
31 31
         setting_display_media_default: Verstecke Medien, die als sensibel markiert sind
32 32
         setting_display_media_hide_all: Alle Medien immer verstecken
33 33
         setting_display_media_show_all: Medien, die als sensibel markiert sind, immer anzeigen
34
-        setting_hide_network: Wem du folgst und wer dir folgt wird in deinem Profil nicht angezeigt
34
+        setting_hide_network: Wem du folgst und wer dir folgt, wird in deinem Profil nicht angezeigt
35 35
         setting_noindex: Betrifft dein öffentliches Profil und deine Beiträge
36 36
         setting_theme: Wirkt sich darauf aus, wie Mastodon aussieht, egal auf welchem Gerät du eingeloggt bist.
37 37
         username: Dein Benutzer:innen-Name wird auf %{domain} nur einmal vorkommen
38
-        whole_word: Wenn das Schlüsselwort oder -phrase nur Buchstaben und Zahlen enthält, wird es nur angewendet werden, wenn es dem ganzen Wort entspricht
38
+        whole_word: Wenn das Schlagwort oder die Phrase nur Buchstaben und Zahlen enthält, wird es nur angewendet, wenn es dem ganzen Wort entspricht
39 39
       imports:
40 40
         data: CSV-Datei, die aus einer anderen Mastodon-Instanz exportiert wurde
41 41
       sessions:
@@ -60,7 +60,7 @@ de:
60 60
           suspend: Deaktivieren und unwiderruflich Benutzerdaten löschen
61 61
         warning_preset_id: Benutze eine Warnungsvorlage
62 62
       defaults:
63
-        autofollow: Einladen, um deinen Account zu folgen
63
+        autofollow: Einladen, um deinem Account zu folgen
64 64
         avatar: Profilbild
65 65
         bot: Dieser Benutzer ist ein Bot
66 66
         chosen_languages: Sprachen filtern
@@ -76,7 +76,7 @@ de:
76 76
         fields: Profil-Metadaten
77 77
         header: Kopfbild
78 78
         inbox_url: Inbox-URL des Relays
79
-        irreversible: Fallen lassen anstatt es zu verstecken
79
+        irreversible: Verwerfen statt verstecken
80 80
         locale: Sprache der Benutzeroberfläche
81 81
         locked: Gesperrtes Profil
82 82
         max_uses: Maximale Verwendungen
@@ -90,28 +90,28 @@ de:
90 90
         setting_boost_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag geteilt wird
91 91
         setting_default_language: Beitragssprache
92 92
         setting_default_privacy: Beitragssichtbarkeit
93