From e9fa557ead8a52a8c8549435e3e2858acd2bcc0b Mon Sep 17 00:00:00 2001 From: Neville Park Date: Thu, 9 Feb 2017 17:57:56 -0500 Subject: [PATCH 01/18] Added awoo.space --- docs/Using-Mastodon/List-of-Mastodon-instances.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Using-Mastodon/List-of-Mastodon-instances.md b/docs/Using-Mastodon/List-of-Mastodon-instances.md index 2f15df083..73e7ded1d 100644 --- a/docs/Using-Mastodon/List-of-Mastodon-instances.md +++ b/docs/Using-Mastodon/List-of-Mastodon-instances.md @@ -8,5 +8,6 @@ List of Mastodon instances * [socially.constructed.space](https://socially.constructed.space) * [epiktistes.com](https://epiktistes.com) * [toot.zone](https://toot.zone) +* [awoo.space](https://awoo.space/) Let me know if you start running one so I can add it to the list! From c9f42a7b851ed80442cbfba8ba4a3a0ec062f8da Mon Sep 17 00:00:00 2001 From: Lorenz Diener Date: Fri, 10 Feb 2017 15:35:19 +0000 Subject: [PATCH 02/18] Move more inline colours to scss --- .../components/column_collapsable.jsx | 5 ++-- .../components/loading_indicator.jsx | 3 +-- .../components/components/media_gallery.jsx | 6 ++--- .../components/components/video_player.jsx | 6 ++--- .../components/clear_column_button.jsx | 3 +-- app/assets/stylesheets/components.scss | 24 ++++++++++++++++++- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/components/components/column_collapsable.jsx b/app/assets/javascripts/components/components/column_collapsable.jsx index 90c561bce..676759055 100644 --- a/app/assets/javascripts/components/components/column_collapsable.jsx +++ b/app/assets/javascripts/components/components/column_collapsable.jsx @@ -40,10 +40,11 @@ const ColumnCollapsable = React.createClass({ render () { const { icon, fullHeight, children } = this.props; const { collapsed } = this.state; - + const collapsedClassName = collapsed ? 'collapsable-collapsed' : 'collapsable'; + return (
-
+
{({ opacity, height }) => diff --git a/app/assets/javascripts/components/components/loading_indicator.jsx b/app/assets/javascripts/components/components/loading_indicator.jsx index c8a263924..913a4bf99 100644 --- a/app/assets/javascripts/components/components/loading_indicator.jsx +++ b/app/assets/javascripts/components/components/loading_indicator.jsx @@ -4,12 +4,11 @@ const style = { textAlign: 'center', fontSize: '16px', fontWeight: '500', - color: '#616b86', paddingTop: '120px' }; const LoadingIndicator = () => ( -
+
); diff --git a/app/assets/javascripts/components/components/media_gallery.jsx b/app/assets/javascripts/components/components/media_gallery.jsx index a13448d0b..b0e397e80 100644 --- a/app/assets/javascripts/components/components/media_gallery.jsx +++ b/app/assets/javascripts/components/components/media_gallery.jsx @@ -16,8 +16,6 @@ const outerStyle = { }; const spoilerStyle = { - background: '#000', - color: '#fff', textAlign: 'center', height: '100%', cursor: 'pointer', @@ -84,14 +82,14 @@ const MediaGallery = React.createClass({ if (!this.state.visible) { if (sensitive) { children = ( -
+
); } else { children = ( -
+
diff --git a/app/assets/javascripts/components/components/video_player.jsx b/app/assets/javascripts/components/components/video_player.jsx index 3edc8f672..ccd67ddf0 100644 --- a/app/assets/javascripts/components/components/video_player.jsx +++ b/app/assets/javascripts/components/components/video_player.jsx @@ -28,8 +28,6 @@ const muteStyle = { const spoilerStyle = { marginTop: '8px', - background: '#000', - color: '#fff', textAlign: 'center', height: '100%', cursor: 'pointer', @@ -122,7 +120,7 @@ const VideoPlayer = React.createClass({ if (!this.state.visible) { if (sensitive) { return ( -
+
{spoilerButton} @@ -130,7 +128,7 @@ const VideoPlayer = React.createClass({ ); } else { return ( -
+
{spoilerButton} diff --git a/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx b/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx index d20a4d170..0b7c737c6 100644 --- a/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx +++ b/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx @@ -4,8 +4,7 @@ const iconStyle = { position: 'absolute', right: '48px', top: '0', - cursor: 'pointer', - background: '#2f3441' + cursor: 'pointer' }; const ClearColumnButton = ({ onClick }) => ( diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index 6bb683f17..6c2e45755 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -34,7 +34,8 @@ .column-icon { color: $color3; - + background: lighten($color1, 4%); + &:hover { color: lighten($color3, 7%); } @@ -883,6 +884,7 @@ a.status__content__spoiler-link { .autosuggest-textarea__textarea { height: 100px; + background: $color5; } .autosuggest-textarea__suggestions { @@ -1020,3 +1022,23 @@ button.active i.fa-retweet { font-size: 14px; margin: 0; } + +.loading-indicator { + color: #616b86; + color: #00FF00; +} + +.collapsable-collapsed { + color: $color3; + background: lighten($color1, 4%); +} + +.collapsable { + color: $color5; + background: lighten($color1, 6%); +} + +.media-spoiler { + background: $color8; + color: $color5; +} From cbb962fd77db1a7deb79128ae777c3bc647ad089 Mon Sep 17 00:00:00 2001 From: Lorenz Diener Date: Fri, 10 Feb 2017 16:30:06 +0000 Subject: [PATCH 03/18] Move more colours to scss --- .../features/account/components/header.jsx | 2 +- .../components/account_authorize.jsx | 7 +-- .../components/column_settings.jsx | 8 ++- .../components/column_settings.jsx | 12 ++--- .../components/setting_toggle.jsx | 5 +- .../status/components/detailed_status.jsx | 2 +- .../features/ui/components/column_link.jsx | 1 - .../ui/containers/modal_container.jsx | 9 ++-- app/assets/stylesheets/components.scss | 54 +++++++++++++++---- 9 files changed, 61 insertions(+), 39 deletions(-) diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx index b2d943c1c..a4f0ca768 100644 --- a/app/assets/javascripts/components/features/account/components/header.jsx +++ b/app/assets/javascripts/components/features/account/components/header.jsx @@ -35,7 +35,7 @@ const Header = React.createClass({ } if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) { - info = + info = } if (me !== account.get('id')) { diff --git a/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx b/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx index 0d41d192f..1766655c2 100644 --- a/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx +++ b/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx @@ -16,11 +16,8 @@ const outerStyle = { }; const panelStyle = { - background: '#2f3441', display: 'flex', flexDirection: 'row', - borderTop: '1px solid #363c4b', - borderBottom: '1px solid #363c4b', padding: '10px 0' }; @@ -40,10 +37,10 @@ const AccountAuthorize = ({ intl, account, onAuthorize, onReject }) => { -
+
-
+
diff --git a/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx b/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx index 714be309b..3317210bf 100644 --- a/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx +++ b/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx @@ -10,7 +10,6 @@ const messages = defineMessages({ }); const outerStyle = { - background: '#373b4a', padding: '15px' }; @@ -18,7 +17,6 @@ const sectionStyle = { cursor: 'default', display: 'block', fontWeight: '500', - color: '#9baec8', marginBottom: '10px' }; @@ -42,8 +40,8 @@ const ColumnSettings = React.createClass({ return ( -
- +
+
} /> @@ -53,7 +51,7 @@ const ColumnSettings = React.createClass({ } />
- +
diff --git a/app/assets/javascripts/components/features/notifications/components/column_settings.jsx b/app/assets/javascripts/components/features/notifications/components/column_settings.jsx index b63c1881a..f1b8ef57f 100644 --- a/app/assets/javascripts/components/features/notifications/components/column_settings.jsx +++ b/app/assets/javascripts/components/features/notifications/components/column_settings.jsx @@ -5,7 +5,6 @@ import ColumnCollapsable from '../../../components/column_collapsable'; import SettingToggle from './setting_toggle'; const outerStyle = { - background: '#373b4a', padding: '15px' }; @@ -13,7 +12,6 @@ const sectionStyle = { cursor: 'default', display: 'block', fontWeight: '500', - color: '#9baec8', marginBottom: '10px' }; @@ -40,8 +38,8 @@ const ColumnSettings = React.createClass({ return ( -
- +
+
@@ -49,7 +47,7 @@ const ColumnSettings = React.createClass({
- +
@@ -57,7 +55,7 @@ const ColumnSettings = React.createClass({
- +
@@ -65,7 +63,7 @@ const ColumnSettings = React.createClass({
- +
diff --git a/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx b/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx index c2438f716..eae3c2be2 100644 --- a/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx +++ b/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx @@ -11,14 +11,13 @@ const labelSpanStyle = { display: 'inline-block', verticalAlign: 'middle', marginBottom: '14px', - marginLeft: '8px', - color: '#9baec8' + marginLeft: '8px' }; const SettingToggle = ({ settings, settingKey, label, onChange }) => ( ); diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx index f2d6ae48a..6080c9ccd 100644 --- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx +++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx @@ -52,7 +52,7 @@ const DetailedStatus = React.createClass({ } return ( -
+
diff --git a/app/assets/javascripts/components/features/ui/components/column_link.jsx b/app/assets/javascripts/components/features/ui/components/column_link.jsx index 901a29f5c..2bd1e1017 100644 --- a/app/assets/javascripts/components/features/ui/components/column_link.jsx +++ b/app/assets/javascripts/components/features/ui/components/column_link.jsx @@ -4,7 +4,6 @@ const outerStyle = { display: 'block', padding: '15px', fontSize: '16px', - color: '#fff', textDecoration: 'none' }; diff --git a/app/assets/javascripts/components/features/ui/containers/modal_container.jsx b/app/assets/javascripts/components/features/ui/containers/modal_container.jsx index 334e5c199..4c47fb8c5 100644 --- a/app/assets/javascripts/components/features/ui/containers/modal_container.jsx +++ b/app/assets/javascripts/components/features/ui/containers/modal_container.jsx @@ -41,13 +41,12 @@ const imageStyle = { }; const loadingStyle = { - background: '#373b4a', width: '400px', paddingBottom: '120px' }; const preloader = () => ( -
+
); @@ -57,7 +56,6 @@ const leftNavStyle = { background: 'rgba(0, 0, 0, 0.5)', padding: '30px 15px', cursor: 'pointer', - color: '#fff', fontSize: '24px', top: '0', left: '-61px', @@ -72,7 +70,6 @@ const rightNavStyle = { background: 'rgba(0, 0, 0, 0.5)', padding: '30px 15px', cursor: 'pointer', - color: '#fff', fontSize: '24px', top: '0', right: '-61px', @@ -143,11 +140,11 @@ const Modal = React.createClass({ leftNav = rightNav = ''; if (hasLeft) { - leftNav =
; + leftNav =
; } if (hasRight) { - rightNav =
; + rightNav =
; } return ( diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index 6c2e45755..faad9ee58 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -227,6 +227,8 @@ a.status__content__spoiler-link { } .detailed-status { + background: lighten($color1, 4%); + .status__content { font-size: 19px; line-height: 24px; @@ -299,7 +301,8 @@ a.status__content__spoiler-link { word-wrap: break-word; font-weight: 400; overflow: hidden; - + color: $color3; + p { margin-bottom: 20px; @@ -852,7 +855,8 @@ a.status__content__spoiler-link { .column-link { background: lighten($color1, 6%); - + color: $color5; + &:hover { background: lighten($color1, 11%); } @@ -1024,21 +1028,51 @@ button.active i.fa-retweet { } .loading-indicator { - color: #616b86; - color: #00FF00; + color: $color2; } .collapsable-collapsed { - color: $color3; - background: lighten($color1, 4%); + color: $color3; + background: lighten($color1, 4%); } .collapsable { - color: $color5; - background: lighten($color1, 6%); + color: $color5; + background: lighten($color1, 6%); } .media-spoiler { - background: $color8; - color: $color5; + background: $color8; + color: $color5; } + +.modal-container--preloader { + background: lighten($color1, 6%); +} + +.account--panel { + background: lighten($color1, 4%); + border-top: 1px solid lighten($color1, 6%); + border-bottom: 1px solid lighten($color1, 6%); +} + +.column-settings--outer { + background: lighten($color1, 6%); +} + +.column-settings--section { + color: $color3; +} + +.modal-container--nav { + color: $color5; +} + +.account--follows-info { + color: $color5; +} + +.setting-toggle { + color: $color3; +} + From 63a18efb27e4446f453af420a4a6a1c5308ee2d0 Mon Sep 17 00:00:00 2001 From: shel Date: Fri, 10 Feb 2017 11:37:35 -0500 Subject: [PATCH 04/18] Change List of Instances to Table Change list of known instances to a table with additional information per instance. Add awoo.space and gay.crime.team --- .../List-of-Mastodon-instances.md | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/Using-Mastodon/List-of-Mastodon-instances.md b/docs/Using-Mastodon/List-of-Mastodon-instances.md index 2f15df083..43ddd7f96 100644 --- a/docs/Using-Mastodon/List-of-Mastodon-instances.md +++ b/docs/Using-Mastodon/List-of-Mastodon-instances.md @@ -1,12 +1,18 @@ -List of Mastodon instances +List of Known Mastodon instances ========================== -* [mastodon.social](https://mastodon.social) -* [social.tchncs.de](https://social.tchncs.de) -* [on.vu](https://on.vu) -* [animalliberation.social](https://animalliberation.social) -* [socially.constructed.space](https://socially.constructed.space) -* [epiktistes.com](https://epiktistes.com) -* [toot.zone](https://toot.zone) -Let me know if you start running one so I can add it to the list! +| Name | Theme/Notes, if applicable | Open Registrations | +| ------------- |:-------------:| -----:| +| [mastodon.social](https://mastodon.social) | Flagship, quick updates | $Yes | +| [awoo.space](https://awoo.space) | Intentionally moderated, only federates with mastodon.social | $Yes | +| [social.tchncs.de](https://social.tchncs.de) | Technology | $Yes | +| [animalliberation.social](https://animalliberation.social) | Animal Rights | $Yes | +| [socially.constructed.space](https://socially.constructed.space) | Single user | $No | +| [epiktistes.com](https://epiktistes.com) | N/A | $Yes | +| [toot.zone](https://toot.zone) | N/A | $Yes | +| [on.vu](https://on.vu) | Appears defunct | $No | +| [gay.crime.team](https://gay.crime.team) | N/A | $Yes(?) | + + +Let me know if you start running one so I can add it to the list! (Alternatively, add it yourself as a pull request). From a0e6c80b60375497c7770e8ac22d125317ff3e48 Mon Sep 17 00:00:00 2001 From: shel Date: Fri, 10 Feb 2017 12:14:49 -0500 Subject: [PATCH 05/18] Clean up markdown There were some markdown processing errors which I've cleaned up --- .../List-of-Mastodon-instances.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/Using-Mastodon/List-of-Mastodon-instances.md b/docs/Using-Mastodon/List-of-Mastodon-instances.md index 43ddd7f96..39e34b8a0 100644 --- a/docs/Using-Mastodon/List-of-Mastodon-instances.md +++ b/docs/Using-Mastodon/List-of-Mastodon-instances.md @@ -2,17 +2,17 @@ List of Known Mastodon instances ========================== -| Name | Theme/Notes, if applicable | Open Registrations | -| ------------- |:-------------:| -----:| -| [mastodon.social](https://mastodon.social) | Flagship, quick updates | $Yes | -| [awoo.space](https://awoo.space) | Intentionally moderated, only federates with mastodon.social | $Yes | -| [social.tchncs.de](https://social.tchncs.de) | Technology | $Yes | -| [animalliberation.social](https://animalliberation.social) | Animal Rights | $Yes | -| [socially.constructed.space](https://socially.constructed.space) | Single user | $No | -| [epiktistes.com](https://epiktistes.com) | N/A | $Yes | -| [toot.zone](https://toot.zone) | N/A | $Yes | -| [on.vu](https://on.vu) | Appears defunct | $No | -| [gay.crime.team](https://gay.crime.team) | N/A | $Yes(?) | +| Name | Theme/Notes, if applicable | Open Registrations | +| -------------|-------------|---| +| [mastodon.social](https://mastodon.social) |Flagship, quick updates|Yes| +| [awoo.space](https://awoo.space) |Intentionally moderated, only federates with mastodon.social|Yes| +| [social.tchncs.de](https://social.tchncs.de)|N/A|Yes| +| [animalliberation.social](https://animalliberation.social) |Animal Rights|Yes| +| [socially.constructed.space](https://socially.constructed.space) |Single user|No| +| [epiktistes.com](https://epiktistes.com) |N/A|Yes| +| [toot.zone](https://toot.zone) |N/A|Yes| +| [on.vu](https://on.vu) | Appears defunct|No| +| [gay.crime.team](https://gay.crime.team) |N/A|Yes(?)| Let me know if you start running one so I can add it to the list! (Alternatively, add it yourself as a pull request). From 3f1f3d0827969a7bc46c3f905cf6a65b9eed621e Mon Sep 17 00:00:00 2001 From: shel Date: Fri, 10 Feb 2017 13:06:38 -0500 Subject: [PATCH 06/18] Add link to other instances list This should help federation --- app/views/about/index.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/about/index.html.haml b/app/views/about/index.html.haml index 88bfe3d61..022a3a9e4 100644 --- a/app/views/about/index.html.haml +++ b/app/views/about/index.html.haml @@ -32,6 +32,7 @@ = link_to t('about.learn_more'), about_more_path = link_to t('about.terms'), terms_path = link_to t('about.source_code'), 'https://github.com/tootsuite/mastodon' + = link_to t('about.other_instances'), 'https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md' = link_to t('about.get_started'), new_user_registration_path, class: 'button webapp-btn' = link_to t('auth.login'), new_user_session_path, class: 'button webapp-btn' From 2d6f603c2bc3ec34c2e50ebacaccc6676bf1fa55 Mon Sep 17 00:00:00 2001 From: shel Date: Fri, 10 Feb 2017 13:08:47 -0500 Subject: [PATCH 07/18] Add link to other instances text Text for link to other instances --- config/locales/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index b1b1e7995..018c923df 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -10,6 +10,7 @@ en: get_started: Get started learn_more: Learn more links: Links + other_instances: Other Instances source_code: Source code status_count_after: statuses status_count_before: Who authored From 894a0515d946da761f51605cbde077e8c5bb806f Mon Sep 17 00:00:00 2001 From: shel Date: Fri, 10 Feb 2017 15:07:44 -0500 Subject: [PATCH 08/18] Add gnusocial.me to instance list I'm never going to get tired of saying "gnusocial.me is a mastodon instance" --- docs/Using-Mastodon/List-of-Mastodon-instances.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Using-Mastodon/List-of-Mastodon-instances.md b/docs/Using-Mastodon/List-of-Mastodon-instances.md index 04a326ad9..c4e228769 100644 --- a/docs/Using-Mastodon/List-of-Mastodon-instances.md +++ b/docs/Using-Mastodon/List-of-Mastodon-instances.md @@ -12,6 +12,7 @@ List of Known Mastodon instances | [toot.zone](https://toot.zone) |N/A|Yes| | [on.vu](https://on.vu) | Appears defunct|No| | [gay.crime.team](https://gay.crime.team) |N/A|Yes(?)| +| [gnusocial.me](https://gnusocial.me) |Yes, it's a mastodon instance now|Yes| Let me know if you start running one so I can add it to the list! (Alternatively, add it yourself as a pull request). From d2619e0b53aeed2949ed0e492c5fbedcb8d9a820 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Feb 2017 22:37:11 +0100 Subject: [PATCH 09/18] Site title is now a setting --- app/views/admin/settings/index.html.haml | 6 +++++- app/views/layouts/application.html.haml | 2 +- config/locales/en.yml | 2 +- config/settings.yml | 1 + 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/views/admin/settings/index.html.haml b/app/views/admin/settings/index.html.haml index 5b482213b..1429dbd9e 100644 --- a/app/views/admin/settings/index.html.haml +++ b/app/views/admin/settings/index.html.haml @@ -15,6 +15,10 @@ %td= best_in_place @settings['site_contact_username'], :value, url: admin_setting_path(@settings['site_contact_username']), place_holder: 'Enter a username' %tr %td= best_in_place @settings['site_contact_email'], :value, url: admin_setting_path(@settings['site_contact_email']), place_holder: 'Enter a public e-mail address' + %tr + %td + %strong Site title + %td= best_in_place @settings['site_title'], :value, url: admin_setting_path(@settings['site_title']) %tr %td %strong Site description @@ -33,4 +37,4 @@ Displayed on extended information page %br/ You can use HTML tags - %td= best_in_place @settings['site_extended_description'], :value, as: :textarea, url: admin_setting_path(@settings['site_extended_description']) \ No newline at end of file + %td= best_in_place @settings['site_extended_description'], :value, as: :textarea, url: admin_setting_path(@settings['site_extended_description']) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index e122e1c55..7eae6982b 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -13,7 +13,7 @@ %title = "#{yield(:page_title)} - " if content_for?(:page_title) - Mastodon + = Setting.site_title = stylesheet_link_tag 'application', media: 'all' = csrf_meta_tags diff --git a/config/locales/en.yml b/config/locales/en.yml index 018c923df..c6c7c236e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -10,7 +10,7 @@ en: get_started: Get started learn_more: Learn more links: Links - other_instances: Other Instances + other_instances: Other instances source_code: Source code status_count_after: statuses status_count_before: Who authored diff --git a/config/settings.yml b/config/settings.yml index a78bd067d..71ce12e63 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -1,5 +1,6 @@ # config/app.yml for rails-settings-cached defaults: &defaults + site_title: 'Mastodon' site_description: '' site_extended_description: '' site_contact_username: '' From 5c4c046132da522887b11143d06eb5bec0f5f677 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Feb 2017 22:58:29 +0100 Subject: [PATCH 10/18] Finish up moving colors from JSX to Sass (#584, #348) --- .../notifications/components/notification.jsx | 20 +--- .../features/status/components/card.jsx | 43 ++------- .../status/components/detailed_status.jsx | 2 +- app/assets/stylesheets/components.scss | 96 ++++++++++++++----- app/assets/stylesheets/stream_entries.scss | 8 +- 5 files changed, 89 insertions(+), 80 deletions(-) diff --git a/app/assets/javascripts/components/features/notifications/components/notification.jsx b/app/assets/javascripts/components/features/notifications/components/notification.jsx index 140ba9134..fa8466140 100644 --- a/app/assets/javascripts/components/features/notifications/components/notification.jsx +++ b/app/assets/javascripts/components/features/notifications/components/notification.jsx @@ -7,16 +7,6 @@ import Permalink from '../../../components/permalink'; import emojify from '../../../emoji'; import escapeTextContentForBrowser from 'react/lib/escapeTextContentForBrowser'; -const messageStyle = { - marginLeft: '68px', - padding: '8px 0', - paddingBottom: '0', - cursor: 'default', - color: '#d9e1e8', - fontSize: '15px', - position: 'relative' -}; - const linkStyle = { fontWeight: '500' }; @@ -32,9 +22,9 @@ const Notification = React.createClass({ renderFollow (account, link) { return (
-
+
- +
@@ -52,7 +42,7 @@ const Notification = React.createClass({ renderFavourite (notification, link) { return (
-
+
@@ -68,9 +58,9 @@ const Notification = React.createClass({ renderReblog (notification, link) { return (
-
+
- +
diff --git a/app/assets/javascripts/components/features/status/components/card.jsx b/app/assets/javascripts/components/features/status/components/card.jsx index ccb06dfd5..1bb281c70 100644 --- a/app/assets/javascripts/components/features/status/components/card.jsx +++ b/app/assets/javascripts/components/features/status/components/card.jsx @@ -1,18 +1,6 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -const outerStyle = { - display: 'flex', - cursor: 'pointer', - fontSize: '14px', - border: '1px solid #363c4b', - borderRadius: '4px', - color: '#616b86', - marginTop: '14px', - textDecoration: 'none', - overflow: 'hidden' -}; - const contentStyle = { flex: '1 1 auto', padding: '8px', @@ -20,25 +8,6 @@ const contentStyle = { overflow: 'hidden' }; -const titleStyle = { - display: 'block', - fontWeight: '500', - marginBottom: '5px', - color: '#d9e1e8', - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap' -}; - -const descriptionStyle = { - color: '#d9e1e8' -}; - -const imageOuterStyle = { - flex: '0 0 100px', - background: '#373b4a' -}; - const imageStyle = { display: 'block', width: '100%', @@ -77,20 +46,20 @@ const Card = React.createClass({ if (card.get('image')) { image = ( -
+
{card.get('title')}
); } return ( - + {image} -
- {card.get('title')} -

{card.get('description').substring(0, 50)}

- {getHostname(card.get('url'))} +
+ {card.get('title')} +

{card.get('description').substring(0, 50)}

+ {getHostname(card.get('url'))}
); diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx index 6080c9ccd..8a7c0c5d5 100644 --- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx +++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx @@ -62,7 +62,7 @@ const DetailedStatus = React.createClass({ {media} -
+
{applicationLink} · ·
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index faad9ee58..c60ca0291 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -35,7 +35,7 @@ .column-icon { color: $color3; background: lighten($color1, 4%); - + &:hover { color: lighten($color3, 7%); } @@ -188,7 +188,7 @@ a.status__content__spoiler-link { display: inline-block; border-radius: 2px; - color: lighten($color1, 6%); + color: lighten($color1, 8%); font-weight: 500; font-size: 11px; padding: 0px 6px; @@ -201,7 +201,7 @@ a.status__content__spoiler-link { padding-left: 68px; position: relative; min-height: 48px; - border-bottom: 1px solid lighten($color1, 6%); + border-bottom: 1px solid lighten($color1, 8%); cursor: default; .status__relative-time { @@ -228,7 +228,7 @@ a.status__content__spoiler-link { .detailed-status { background: lighten($color1, 4%); - + .status__content { font-size: 19px; line-height: 24px; @@ -240,12 +240,19 @@ a.status__content__spoiler-link { } } +.detailed-status__meta { + margin-top: 15px; + color: lighten($color1, 26%); + font-size: 14px; + line-height: 18px; +} + .detailed-status__action-bar { background: lighten($color1, 4%); display: flex; flex-direction: row; - border-top: 1px solid lighten($color1, 6%); - border-bottom: 1px solid lighten($color1, 6%); + border-top: 1px solid lighten($color1, 8%); + border-bottom: 1px solid lighten($color1, 8%); padding: 10px 0; } @@ -260,7 +267,7 @@ a.status__content__spoiler-link { .account { padding: 10px; - border-bottom: 1px solid lighten($color1, 6%); + border-bottom: 1px solid lighten($color1, 8%); .account__display-name { flex: 1 1 auto; @@ -302,7 +309,7 @@ a.status__content__spoiler-link { font-weight: 400; overflow: hidden; color: $color3; - + p { margin-bottom: 20px; @@ -329,8 +336,8 @@ a.status__content__spoiler-link { } .account__action-bar { - border-top: 1px solid lighten($color1, 6%); - border-bottom: 1px solid lighten($color1, 6%); + border-top: 1px solid lighten($color1, 8%); + border-bottom: 1px solid lighten($color1, 8%); line-height: 36px; overflow: hidden; flex: 0 0 auto; @@ -341,7 +348,7 @@ a.status__content__spoiler-link { text-decoration: none; overflow: hidden; width: 80px; - border-left: 1px solid lighten($color1, 6%); + border-left: 1px solid lighten($color1, 8%); padding: 10px 5px; & > span { @@ -426,6 +433,20 @@ a.status__content__spoiler-link { } } +.notification__message { + margin-left: 68px; + padding: 8px 0; + padding-bottom: 0; + cursor: default; + color: $color3; + font-size: 15px; + position: relative; + + .fa { + color: $color4; + } +} + .notification__display-name { color: inherit; text-decoration: none; @@ -650,7 +671,7 @@ a.status__content__spoiler-link { .tabs-bar { display: flex; - background: lighten($color1, 6%); + background: lighten($color1, 8%); flex: 0 0 auto; overflow-y: auto; } @@ -664,7 +685,7 @@ a.status__content__spoiler-link { text-align: center; font-size:12px; font-weight: 500; - border-bottom: 2px solid lighten($color1, 6%); + border-bottom: 2px solid lighten($color1, 8%); &.active { border-bottom: 2px solid $color4; @@ -854,9 +875,9 @@ a.status__content__spoiler-link { } .column-link { - background: lighten($color1, 6%); + background: lighten($color1, 8%); color: $color5; - + &:hover { background: lighten($color1, 11%); } @@ -974,11 +995,40 @@ button.active i.fa-retweet { } .status-card { + display: flex; + cursor: pointer; + font-size: 14px; + border: 1px solid lighten($color1, 8%); + border-radius: 4px; + color: lighten($color1, 26%); + margin-top: 14px; + text-decoration: none; + overflow: hidden; + &:hover { - background: lighten($color1, 6%); + background: lighten($color1, 8%); } } +.status-card__title { + display: block; + font-weight: 500; + margin-bottom: 5px; + color: $color3; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.status-card__description { + color: $color3; +} + +.status-card__image { + flex: 0 0 100px; + background: lighten($color1, 8%); +} + .load-more { display: block; color: lighten($color1, 26%); @@ -987,7 +1037,7 @@ button.active i.fa-retweet { text-decoration: none; &:hover { - background: lighten($color1, 6%); + background: lighten($color1, 8%); } } @@ -1037,8 +1087,8 @@ button.active i.fa-retweet { } .collapsable { - color: $color5; - background: lighten($color1, 6%); + color: $color5; + background: lighten($color1, 8%); } .media-spoiler { @@ -1047,17 +1097,17 @@ button.active i.fa-retweet { } .modal-container--preloader { - background: lighten($color1, 6%); + background: lighten($color1, 8%); } .account--panel { background: lighten($color1, 4%); - border-top: 1px solid lighten($color1, 6%); - border-bottom: 1px solid lighten($color1, 6%); + border-top: 1px solid lighten($color1, 8%); + border-bottom: 1px solid lighten($color1, 8%); } .column-settings--outer { - background: lighten($color1, 6%); + background: lighten($color1, 8%); } .column-settings--section { diff --git a/app/assets/stylesheets/stream_entries.scss b/app/assets/stylesheets/stream_entries.scss index 595275527..d427c1466 100644 --- a/app/assets/stylesheets/stream_entries.scss +++ b/app/assets/stylesheets/stream_entries.scss @@ -5,24 +5,24 @@ .entry { background: lighten($color2, 8%); - &, .detailed-status.light { + .detailed-status.light, .status.light { border-bottom: 1px solid $color2; } &:last-child { - &, .detailed-status.light { + &, .detailed-status.light, .status.light { border-bottom: 0; border-radius: 0 0 4px 4px; } } &:first-child { - &, .detailed-status.light { + &, .detailed-status.light, .status.light { border-radius: 4px 4px 0 0; } &:last-child { - &, .detailed-status.light { + &, .detailed-status.light, .status.light { border-radius: 4px; } } From 8cca6bc58c1d5b42e5acdce294ddbe048f0c5e85 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Feb 2017 23:01:02 +0100 Subject: [PATCH 11/18] Fix spoiler link color in muted context --- app/assets/stylesheets/components.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index c60ca0291..f0948b0f3 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -423,8 +423,9 @@ a.status__content__spoiler-link { opacity: 0.5; } - .status__content__spoiler-link { + a.status__content__spoiler-link { background: lighten($color1, 26%); + color: lighten($color1, 4%); &:hover { background: lighten($color1, 29%); From d551e43a9bc35b4785285e78f5ecd3157636b447 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 10 Feb 2017 23:21:01 +0100 Subject: [PATCH 12/18] Improve public tag page --- app/assets/stylesheets/application.scss | 29 +++++++++++++++++++++++++ app/views/tags/show.html.haml | 14 +++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index c4c876e30..c590f7038 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -256,6 +256,35 @@ button:focus { } } +.compact-header { + h1 { + font-size: 24px; + line-height: 28px; + color: $color3; + overflow: hidden; + font-weight: 500; + margin-bottom: 20px; + + a { + color: inherit; + text-decoration: none; + } + + small { + font-weight: 400; + color: $color2; + } + + img { + display: inline-block; + margin-bottom: -5px; + margin-right: 15px; + width: 36px; + height: 36px; + } + } +} + @import 'forms'; @import 'accounts'; @import 'stream_entries'; diff --git a/app/views/tags/show.html.haml b/app/views/tags/show.html.haml index 412ec4fa5..32a50e158 100644 --- a/app/views/tags/show.html.haml +++ b/app/views/tags/show.html.haml @@ -1,10 +1,18 @@ +- content_for :page_title do + = "##{@tag.name}" + +.compact-header + %h1< + = link_to 'Mastodon', root_path + %small= "##{@tag.name}" + - if @statuses.empty? .accounts-grid = render partial: 'accounts/nothing_here' - else .activity-stream.h-feed - = render partial: 'stream_entries/status', collection: @statuses, as: :status, cached: true + = render partial: 'stream_entries/status', collection: @statuses, as: :status -.pagination - - if @statuses.size == 20 +- if @statuses.size == 20 + .pagination = link_to safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), tag_url(@tag, max_id: @statuses.last.id), class: 'next_page', rel: 'next' From 149887a0ffc81b588520ff82ab9fda8dff7bce6c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Feb 2017 02:12:05 +0100 Subject: [PATCH 13/18] Make follow requests federate --- .../api/v1/follow_requests_controller.rb | 4 +-- .../concerns/obfuscate_filename.rb | 1 + app/helpers/atom_builder_helper.rb | 8 +++++ app/lib/tag_manager.rb | 22 +++++++----- app/models/favourite.rb | 4 +-- app/models/follow_request.rb | 36 +++++++++++++++++++ app/models/stream_entry.rb | 2 +- app/services/authorize_follow_service.rb | 11 ++++++ app/services/block_service.rb | 4 ++- .../concerns/stream_entry_renderer.rb | 8 +++++ app/services/favourite_service.rb | 4 ++- app/services/follow_service.rb | 13 ++++--- app/services/process_interaction_service.rb | 14 ++++++++ app/services/process_mentions_service.rb | 4 ++- app/services/reblog_service.rb | 10 ++---- app/services/reject_follow_service.rb | 11 ++++++ app/services/remove_status_service.rb | 4 ++- app/services/send_interaction_service.rb | 19 +++------- app/services/unblock_service.rb | 4 ++- app/services/unfavourite_service.rb | 4 ++- app/services/unfollow_service.rb | 4 ++- app/services/update_remote_profile_service.rb | 1 + app/workers/notification_worker.rb | 4 +-- app/workers/push_notification_worker.rb | 11 ------ spec/helpers/atom_builder_helper_spec.rb | 2 +- 25 files changed, 148 insertions(+), 61 deletions(-) create mode 100644 app/services/authorize_follow_service.rb create mode 100644 app/services/concerns/stream_entry_renderer.rb create mode 100644 app/services/reject_follow_service.rb delete mode 100644 app/workers/push_notification_worker.rb diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index a30e97e71..740083735 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -18,12 +18,12 @@ class Api::V1::FollowRequestsController < ApiController end def authorize - FollowRequest.find_by!(account_id: params[:id], target_account: current_account).authorize! + AuthorizeFollowService.new.call(Account.find(params[:id]), current_account) render_empty end def reject - FollowRequest.find_by!(account_id: params[:id], target_account: current_account).reject! + RejectFollowService.new.call(Account.find(params[:id]), current_account) render_empty end end diff --git a/app/controllers/concerns/obfuscate_filename.rb b/app/controllers/concerns/obfuscate_filename.rb index 9f12cb7e9..dde7ce8c6 100644 --- a/app/controllers/concerns/obfuscate_filename.rb +++ b/app/controllers/concerns/obfuscate_filename.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module ObfuscateFilename extend ActiveSupport::Concern diff --git a/app/helpers/atom_builder_helper.rb b/app/helpers/atom_builder_helper.rb index fb8f0976c..5d20f8c2d 100644 --- a/app/helpers/atom_builder_helper.rb +++ b/app/helpers/atom_builder_helper.rb @@ -143,6 +143,10 @@ module AtomBuilderHelper xml.link(:rel => 'mentioned', :href => TagManager::COLLECTIONS[:public], 'ostatus:object-type' => TagManager::TYPES[:collection]) end + def privacy_scope(xml, level) + xml['mastodon'].scope(level) + end + def include_author(xml, account) object_type xml, :person uri xml, TagManager.instance.uri_for(account) @@ -152,6 +156,7 @@ module AtomBuilderHelper link_alternate xml, TagManager.instance.url_for(account) link_avatar xml, account portable_contact xml, account + privacy_scope xml, account.locked? ? :private : :public end def rich_content(xml, activity) @@ -216,6 +221,7 @@ module AtomBuilderHelper end category(xml, 'nsfw') if stream_entry.target.sensitive? + privacy_scope(xml, stream_entry.target.visibility) end end end @@ -237,6 +243,7 @@ module AtomBuilderHelper end category(xml, 'nsfw') if stream_entry.activity.sensitive? + privacy_scope(xml, stream_entry.activity.visibility) end private @@ -249,6 +256,7 @@ module AtomBuilderHelper 'xmlns:poco' => TagManager::POCO_XMLNS, 'xmlns:media' => TagManager::MEDIA_XMLNS, 'xmlns:ostatus' => TagManager::OS_XMLNS, + 'xmlns:mastodon' => TagManager::MTDN_XMLNS, }, &block) end diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb index 2508eea97..9fef70fda 100644 --- a/app/lib/tag_manager.rb +++ b/app/lib/tag_manager.rb @@ -7,15 +7,18 @@ class TagManager include RoutingHelper VERBS = { - post: 'http://activitystrea.ms/schema/1.0/post', - share: 'http://activitystrea.ms/schema/1.0/share', - favorite: 'http://activitystrea.ms/schema/1.0/favorite', - unfavorite: 'http://activitystrea.ms/schema/1.0/unfavorite', - delete: 'http://activitystrea.ms/schema/1.0/delete', - follow: 'http://activitystrea.ms/schema/1.0/follow', - unfollow: 'http://ostatus.org/schema/1.0/unfollow', - block: 'http://mastodon.social/schema/1.0/block', - unblock: 'http://mastodon.social/schema/1.0/unblock', + post: 'http://activitystrea.ms/schema/1.0/post', + share: 'http://activitystrea.ms/schema/1.0/share', + favorite: 'http://activitystrea.ms/schema/1.0/favorite', + unfavorite: 'http://activitystrea.ms/schema/1.0/unfavorite', + delete: 'http://activitystrea.ms/schema/1.0/delete', + follow: 'http://activitystrea.ms/schema/1.0/follow', + request_friend: 'http://activitystrea.ms/schema/1.0/request-friend', + authorize: 'http://activitystrea.ms/schema/1.0/authorize', + reject: 'http://activitystrea.ms/schema/1.0/reject', + unfollow: 'http://ostatus.org/schema/1.0/unfollow', + block: 'http://mastodon.social/schema/1.0/block', + unblock: 'http://mastodon.social/schema/1.0/unblock', }.freeze TYPES = { @@ -38,6 +41,7 @@ class TagManager POCO_XMLNS = 'http://portablecontacts.net/spec/1.0' DFRN_XMLNS = 'http://purl.org/macgirvin/dfrn/1.0' OS_XMLNS = 'http://ostatus.org/schema/1.0' + MTDN_XMLNS = 'http://mastodon.social/schema/1.0' def unique_tag(date, id, type) "tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}" diff --git a/app/models/favourite.rb b/app/models/favourite.rb index 3f3616dce..cd8e2098c 100644 --- a/app/models/favourite.rb +++ b/app/models/favourite.rb @@ -12,11 +12,11 @@ class Favourite < ApplicationRecord validates :status_id, uniqueness: { scope: :account_id } def verb - :favorite + destroyed? ? :unfavorite : :favorite end def title - "#{account.acct} favourited a status by #{status.account.acct}" + destroyed? ? "#{account.acct} no longer favourites a status by #{status.account.acct}" : "#{account.acct} favourited a status by #{status.account.acct}" end delegate :object_type, to: :target diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb index 936ad0691..989c2c2a2 100644 --- a/app/models/follow_request.rb +++ b/app/models/follow_request.rb @@ -2,6 +2,7 @@ class FollowRequest < ApplicationRecord include Paginable + include Streamable belongs_to :account belongs_to :target_account, class_name: 'Account' @@ -12,12 +13,47 @@ class FollowRequest < ApplicationRecord validates :account_id, uniqueness: { scope: :target_account_id } def authorize! + @verb = :authorize + account.follow!(target_account) MergeWorker.perform_async(target_account.id, account.id) + destroy! end def reject! + @verb = :reject destroy! end + + def verb + destroyed? ? (@verb || :delete) : :request_friend + end + + def target + target_account + end + + def object_type + :person + end + + def hidden? + true + end + + def title + if destroyed? + case @verb + when :authorize + "#{target_account.acct} authorized #{account.acct}'s request to follow" + when :reject + "#{target_account.acct} rejected #{account.acct}'s request to follow" + else + "#{account.acct} withdrew the request to follow #{target_account.acct}" + end + else + "#{account.acct} requested to follow #{target_account.acct}" + end + end end diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb index fcc691bef..e0b85be15 100644 --- a/app/models/stream_entry.rb +++ b/app/models/stream_entry.rb @@ -30,7 +30,7 @@ class StreamEntry < ApplicationRecord end def targeted? - [:follow, :unfollow, :block, :unblock, :share, :favorite].include? verb + [:follow, :request_friend, :authorize, :unfollow, :block, :unblock, :share, :favorite].include? verb end def target diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb new file mode 100644 index 000000000..1590d8433 --- /dev/null +++ b/app/services/authorize_follow_service.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class AuthorizeFollowService < BaseService + include StreamEntryRenderer + + def call(source_account, target_account) + follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account) + follow_request.authorize! + NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), target_account.id, source_account.id) unless source_account.local? + end +end diff --git a/app/services/block_service.rb b/app/services/block_service.rb index e04b6cc39..095d2a8eb 100644 --- a/app/services/block_service.rb +++ b/app/services/block_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class BlockService < BaseService + include StreamEntryRenderer + def call(account, target_account) return if account.id == target_account.id @@ -10,6 +12,6 @@ class BlockService < BaseService block = account.block!(target_account) BlockWorker.perform_async(account.id, target_account.id) - NotificationWorker.perform_async(block.stream_entry.id, target_account.id) unless target_account.local? + NotificationWorker.perform_async(stream_entry_to_xml(block.stream_entry), account.id, target_account.id) unless target_account.local? end end diff --git a/app/services/concerns/stream_entry_renderer.rb b/app/services/concerns/stream_entry_renderer.rb new file mode 100644 index 000000000..a4255daea --- /dev/null +++ b/app/services/concerns/stream_entry_renderer.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module StreamEntryRenderer + def stream_entry_to_xml(stream_entry) + renderer = StreamEntriesController.renderer.new(method: 'get', http_host: Rails.configuration.x.local_domain, https: Rails.configuration.x.use_https) + renderer.render(:show, assigns: { stream_entry: stream_entry }, formats: [:atom]) + end +end diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb index d5fbd29e9..ce1722b77 100644 --- a/app/services/favourite_service.rb +++ b/app/services/favourite_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class FavouriteService < BaseService + include StreamEntryRenderer + # Favourite a status and notify remote user # @param [Account] account # @param [Status] status @@ -15,7 +17,7 @@ class FavouriteService < BaseService if status.local? NotifyService.new.call(favourite.status.account, favourite) else - NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id) + NotificationWorker.perform_async(stream_entry_to_xml(favourite.stream_entry), account.id, status.account_id) end favourite diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 9f34cb6ac..45b7895b6 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class FollowService < BaseService + include StreamEntryRenderer + # Follow a remote user, notify remote user about the follow # @param [Account] source_account From which to follow # @param [String] uri User URI to follow in the form of username@domain @@ -20,10 +22,13 @@ class FollowService < BaseService private def request_follow(source_account, target_account) - return unless target_account.local? - follow_request = FollowRequest.create!(account: source_account, target_account: target_account) - NotifyService.new.call(target_account, follow_request) + + if target_account.local? + NotifyService.new.call(target_account, follow_request) + else + NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), source_account.id, target_account.id) + end follow_request end @@ -35,7 +40,7 @@ class FollowService < BaseService NotifyService.new.call(target_account, follow) else subscribe_service.call(target_account) - NotificationWorker.perform_async(follow.stream_entry.id, target_account.id) + NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id) end MergeWorker.perform_async(target_account.id, source_account.id) diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb index 5f91e3127..27f0758ce 100644 --- a/app/services/process_interaction_service.rb +++ b/app/services/process_interaction_service.rb @@ -29,6 +29,10 @@ class ProcessInteractionService < BaseService case verb(xml) when :follow follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account) + when :request_friend + follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) + when :authorize + authorize_follow_request!(account, target_account) when :unfollow unfollow!(account, target_account) when :favorite @@ -72,6 +76,16 @@ class ProcessInteractionService < BaseService NotifyService.new.call(target_account, follow) end + def follow_request(account, target_account) + follow_request = FollowRequest.create!(account: account, target_account: target_account) + NotifyService.new.call(target_account, follow_request) + end + + def authorize_target_account!(account, target_account) + follow_request = FollowRequest.find_by(account: target_account, target_account: account) + follow_request&.authorize! + end + def unfollow!(account, target_account) account.unfollow!(target_account) end diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index 72568e702..67fd3dcf7 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ProcessMentionsService < BaseService + include StreamEntryRenderer + # Scan status for mentions and fetch remote mentioned users, create # local mention pointers, send Salmon notifications to mentioned # remote users @@ -33,7 +35,7 @@ class ProcessMentionsService < BaseService if mentioned_account.local? NotifyService.new.call(mentioned_account, mention) else - NotificationWorker.perform_async(status.stream_entry.id, mentioned_account.id) + NotificationWorker.perform_async(stream_entry_to_xml(status.stream_entry), status.account_id, mentioned_account.id) end end end diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb index 4ea0dbf6c..7a52f041f 100644 --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ReblogService < BaseService + include StreamEntryRenderer + # Reblog a status and notify its remote author # @param [Account] account Account to reblog from # @param [Status] reblogged_status Status to be reblogged @@ -18,15 +20,9 @@ class ReblogService < BaseService if reblogged_status.local? NotifyService.new.call(reblog.reblog.account, reblog) else - NotificationWorker.perform_async(reblog.stream_entry.id, reblog.reblog.account_id) + NotificationWorker.perform_async(stream_entry_to_xml(reblog.stream_entry), account.id, reblog.reblog.account_id) end reblog end - - private - - def send_interaction_service - @send_interaction_service ||= SendInteractionService.new - end end diff --git a/app/services/reject_follow_service.rb b/app/services/reject_follow_service.rb new file mode 100644 index 000000000..0c568b981 --- /dev/null +++ b/app/services/reject_follow_service.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class RejectFollowService < BaseService + include StreamEntryRenderer + + def call(source_account, target_account) + follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account) + follow_request.reject! + NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), target_account.id, source_account.id) unless source_account.local? + end +end diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb index 48e8dd3b8..b1a646b14 100644 --- a/app/services/remove_status_service.rb +++ b/app/services/remove_status_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class RemoveStatusService < BaseService + include StreamEntryRenderer + def call(status) remove_from_self(status) if status.account.local? remove_from_followers(status) @@ -43,7 +45,7 @@ class RemoveStatusService < BaseService def send_delete_salmon(account, status) return unless status.local? - NotificationWorker.perform_async(status.stream_entry.id, account.id) + NotificationWorker.perform_async(stream_entry_to_xml(status.stream_entry), status.account_id, account.id) end def remove_reblogs(status) diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb index 05a1e77e3..99113eeca 100644 --- a/app/services/send_interaction_service.rb +++ b/app/services/send_interaction_service.rb @@ -2,27 +2,16 @@ class SendInteractionService < BaseService # Send an Atom representation of an interaction to a remote Salmon endpoint - # @param [StreamEntry] stream_entry + # @param [String] Entry XML + # @param [Account] source_account # @param [Account] target_account - def call(stream_entry, target_account) - envelope = salmon.pack(entry_xml(stream_entry), stream_entry.account.keypair) + def call(xml, source_account, target_account) + envelope = salmon.pack(xml, source_account.keypair) salmon.post(target_account.salmon_url, envelope) end private - def entry_xml(stream_entry) - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - author(xml) do - include_author xml, stream_entry.account - end - - include_entry xml, stream_entry - end - end.to_xml - end - def salmon @salmon ||= OStatus2::Salmon.new end diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb index f389364f9..84b1050c1 100644 --- a/app/services/unblock_service.rb +++ b/app/services/unblock_service.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true class UnblockService < BaseService + include StreamEntryRenderer + def call(account, target_account) return unless account.blocking?(target_account) unblock = account.unblock!(target_account) - NotificationWorker.perform_async(unblock.stream_entry.id, target_account.id) unless target_account.local? + NotificationWorker.perform_async(stream_entry_to_xml(unblock.stream_entry), account.id, target_account.id) unless target_account.local? end end diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb index de6e84e7d..04293ee08 100644 --- a/app/services/unfavourite_service.rb +++ b/app/services/unfavourite_service.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true class UnfavouriteService < BaseService + include StreamEntryRenderer + def call(account, status) favourite = Favourite.find_by!(account: account, status: status) favourite.destroy! unless status.local? - NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id) + NotificationWorker.perform_async(stream_entry_to_xml(favourite.stream_entry), account.id, status.account_id) end favourite diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb index f469793c1..178da4da3 100644 --- a/app/services/unfollow_service.rb +++ b/app/services/unfollow_service.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true class UnfollowService < BaseService + include StreamEntryRenderer + # Unfollow and notify the remote user # @param [Account] source_account Where to unfollow from # @param [Account] target_account Which to unfollow def call(source_account, target_account) follow = source_account.unfollow!(target_account) - NotificationWorker.perform_async(follow.stream_entry.id, target_account.id) unless target_account.local? + NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id) unless target_account.local? UnmergeWorker.perform_async(target_account.id, source_account.id) end end diff --git a/app/services/update_remote_profile_service.rb b/app/services/update_remote_profile_service.rb index ad9c56540..dc315db19 100644 --- a/app/services/update_remote_profile_service.rb +++ b/app/services/update_remote_profile_service.rb @@ -10,6 +10,7 @@ class UpdateRemoteProfileService < BaseService unless author_xml.nil? account.display_name = author_xml.at_xpath('./poco:displayName', poco: TagManager::POCO_XMLNS).content unless author_xml.at_xpath('./poco:displayName', poco: TagManager::POCO_XMLNS).nil? account.note = author_xml.at_xpath('./poco:note', poco: TagManager::POCO_XMLNS).content unless author_xml.at_xpath('./poco:note', poco: TagManager::POCO_XMLNS).nil? + account.locked = author_xml.at_xpath('./mastodon:scope', mastodon: TagManager::MTDN_XMLNS)&.content == 'private' unless account.suspended? || DomainBlock.find_by(domain: account.domain)&.reject_media? account.avatar_remote_url = author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS)['href'] unless author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS).nil? || author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS)['href'].blank? diff --git a/app/workers/notification_worker.rb b/app/workers/notification_worker.rb index e4c38d384..1a2faefd8 100644 --- a/app/workers/notification_worker.rb +++ b/app/workers/notification_worker.rb @@ -5,7 +5,7 @@ class NotificationWorker sidekiq_options retry: 5 - def perform(stream_entry_id, target_account_id) - SendInteractionService.new.call(StreamEntry.find(stream_entry_id), Account.find(target_account_id)) + def perform(xml, source_account_id, target_account_id) + SendInteractionService.new.call(xml, Account.find(source_account_id), Account.find(target_account_id)) end end diff --git a/app/workers/push_notification_worker.rb b/app/workers/push_notification_worker.rb deleted file mode 100644 index a61d0e349..000000000 --- a/app/workers/push_notification_worker.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -class PushNotificationWorker - include Sidekiq::Worker - - def perform(notification_id) - SendPushNotificationService.new.call(Notification.find(notification_id)) - rescue ActiveRecord::RecordNotFound - true - end -end diff --git a/spec/helpers/atom_builder_helper_spec.rb b/spec/helpers/atom_builder_helper_spec.rb index 3d3bd56a1..0aca58ee7 100644 --- a/spec/helpers/atom_builder_helper_spec.rb +++ b/spec/helpers/atom_builder_helper_spec.rb @@ -13,7 +13,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do describe '#feed' do it 'creates a feed' do - expect(used_in_builder { |xml| helper.feed(xml) }).to match '' + expect(used_in_builder { |xml| helper.feed(xml) }).to match '' end end From 514fdfa268989fad3a6dcf1a0bc5077ec23be6df Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Feb 2017 13:48:28 +0100 Subject: [PATCH 14/18] Don't PuSH-resubscribe if already subscribed --- app/services/follow_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 45b7895b6..6ca834c19 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -39,7 +39,7 @@ class FollowService < BaseService if target_account.local? NotifyService.new.call(target_account, follow) else - subscribe_service.call(target_account) + subscribe_service.call(target_account) unless target_account.subscribed? NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id) end From e610555e10356374d1f4e0e7ca11056580ec9f3b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Feb 2017 13:55:07 +0100 Subject: [PATCH 15/18] Fix processing of incoming authorizations/rejections --- app/services/process_interaction_service.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb index 27f0758ce..8420ca351 100644 --- a/app/services/process_interaction_service.rb +++ b/app/services/process_interaction_service.rb @@ -33,6 +33,8 @@ class ProcessInteractionService < BaseService follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) when :authorize authorize_follow_request!(account, target_account) + when :reject + reject_follow_request!(account, target_account) when :unfollow unfollow!(account, target_account) when :favorite @@ -76,14 +78,20 @@ class ProcessInteractionService < BaseService NotifyService.new.call(target_account, follow) end - def follow_request(account, target_account) + def follow_request!(account, target_account) follow_request = FollowRequest.create!(account: account, target_account: target_account) NotifyService.new.call(target_account, follow_request) end - def authorize_target_account!(account, target_account) + def authorize_follow_request!(account, target_account) follow_request = FollowRequest.find_by(account: target_account, target_account: account) follow_request&.authorize! + SubscribeService.new.call(account) unless account.subscribed? + end + + def reject_follow_request!(account, target_account) + follow_request = FollowRequest.find_by(account: target_account, target_account: account) + follow_request&.reject! end def unfollow!(account, target_account) From 00b5731ecb2c29dd5c79a233f046a9655031ec71 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Feb 2017 14:12:29 +0100 Subject: [PATCH 16/18] After FollowService, re-fetch remote account asynchronously, do nothing if account lock info was up to date, otherwise re-do the FollowService with now updated information --- app/services/fetch_remote_account_service.rb | 4 +++- app/services/follow_service.rb | 2 ++ .../after_remote_follow_request_worker.rb | 17 +++++++++++++++++ app/workers/after_remote_follow_worker.rb | 17 +++++++++++++++++ .../api/v1/follows_controller_spec.rb | 1 + 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 app/workers/after_remote_follow_request_worker.rb create mode 100644 app/workers/after_remote_follow_worker.rb diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb index 3c3694a65..baefa3a86 100644 --- a/app/services/fetch_remote_account_service.rb +++ b/app/services/fetch_remote_account_service.rb @@ -22,7 +22,9 @@ class FetchRemoteAccountService < BaseService Rails.logger.debug "Going to webfinger #{username}@#{domain}" - return FollowRemoteAccountService.new.call("#{username}@#{domain}") + account = FollowRemoteAccountService.new.call("#{username}@#{domain}") + UpdateRemoteProfileService.new.call(xml, account) unless account.nil? + account rescue TypeError Rails.logger.debug "Unparseable URL given: #{url}" nil diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 6ca834c19..ac0392d16 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -28,6 +28,7 @@ class FollowService < BaseService NotifyService.new.call(target_account, follow_request) else NotificationWorker.perform_async(stream_entry_to_xml(follow_request.stream_entry), source_account.id, target_account.id) + AfterRemoteFollowRequestWorker.perform_async(follow_request.id) end follow_request @@ -41,6 +42,7 @@ class FollowService < BaseService else subscribe_service.call(target_account) unless target_account.subscribed? NotificationWorker.perform_async(stream_entry_to_xml(follow.stream_entry), source_account.id, target_account.id) + AfterRemoteFollowWorker.perform_async(follow.id) end MergeWorker.perform_async(target_account.id, source_account.id) diff --git a/app/workers/after_remote_follow_request_worker.rb b/app/workers/after_remote_follow_request_worker.rb new file mode 100644 index 000000000..ad94d2769 --- /dev/null +++ b/app/workers/after_remote_follow_request_worker.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AfterRemoteFollowRequestWorker + include Sidekiq::Worker + + sidekiq_options retry: 5 + + def perform(follow_request_id) + follow_request = FollowRequest.find(follow_request_id) + updated_account = FetchRemoteAccountService.new.call(follow_request.target_account.remote_url) + + return if updated_account.locked? + + follow_request.destroy + FollowService.new.call(follow_request.account, updated_account.acct) + end +end diff --git a/app/workers/after_remote_follow_worker.rb b/app/workers/after_remote_follow_worker.rb new file mode 100644 index 000000000..496aaf73e --- /dev/null +++ b/app/workers/after_remote_follow_worker.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AfterRemoteFollowWorker + include Sidekiq::Worker + + sidekiq_options retry: 5 + + def perform(follow_id) + follow = Follow.find(follow_id) + updated_account = FetchRemoteAccountService.new.call(follow.target_account.remote_url) + + return unless updated_account.locked? + + follow.destroy + FollowService.new.call(follow.account, updated_account.acct) + end +end diff --git a/spec/controllers/api/v1/follows_controller_spec.rb b/spec/controllers/api/v1/follows_controller_spec.rb index 97d69ab7b..cc4958ab5 100644 --- a/spec/controllers/api/v1/follows_controller_spec.rb +++ b/spec/controllers/api/v1/follows_controller_spec.rb @@ -14,6 +14,7 @@ RSpec.describe Api::V1::FollowsController, type: :controller do before do stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt')) stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt')) + stub_request(:head, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(:status => 405, :body => "", :headers => {}) stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt')) stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt')) stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {}) From dc851c922ee1c244146baf1415a7bce4a25cccef Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Feb 2017 15:10:22 +0100 Subject: [PATCH 17/18] Mentions in private statuses allow mentioned people to see them --- app/lib/feed_manager.rb | 1 - app/models/status.rb | 10 +++++++++- app/services/process_feed_service.rb | 18 +++++++----------- app/services/process_mentions_service.rb | 2 -- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index f0928a945..623a1af03 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -107,7 +107,6 @@ class FeedManager should_filter ||= receiver.blocking?(status.account) # or it's from someone I blocked should_filter ||= receiver.blocking?(status.mentions.includes(:account).map(&:account)) # or if it mentions someone I blocked should_filter ||= (status.account.silenced? && !receiver.following?(status.account)) # of if the account is silenced and I'm not following them - should_filter ||= (status.private_visibility? && !receiver.following?(status.account)) # or if the mentioned account is not permitted to see the private status if status.reply? && !status.in_reply_to_account_id.nil? # or it's a reply should_filter ||= receiver.blocking?(status.in_reply_to_account) # to a user I blocked diff --git a/app/models/status.rb b/app/models/status.rb index d2be72308..93594ec8f 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -76,7 +76,11 @@ class Status < ApplicationRecord end def permitted?(other_account = nil) - private_visibility? ? (account.id == other_account&.id || other_account&.following?(account)) : other_account.nil? || !account.blocking?(other_account) + if private_visibility? + (account.id == other_account&.id || other_account&.following?(account) || mentions.include?(other_account)) + else + other_account.nil? || !account.blocking?(other_account) + end end def ancestors(account = nil) @@ -153,6 +157,10 @@ class Status < ApplicationRecord where('1 = 1') elsif !account.nil? && target_account.blocking?(account) where('1 = 0') + elsif !account.nil? + joins('LEFT OUTER JOIN mentions ON statuses.id = mentions.status_id') + .where('mentions.account_id = ?', account.id) + .where('statuses.visibility != ? OR mentions.id IS NOT NULL', Status.visibilities[:private]) else where.not(visibility: :private) end diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb index c411e3e82..f0a62aa14 100644 --- a/app/services/process_feed_service.rb +++ b/app/services/process_feed_service.rb @@ -106,7 +106,8 @@ class ProcessFeedService < BaseService text: content(entry), spoiler_text: content_warning(entry), created_at: published(entry), - reply: thread?(entry) + reply: thread?(entry), + visibility: visibility_scope(entry) ) if thread?(entry) @@ -144,15 +145,9 @@ class ProcessFeedService < BaseService def mentions_from_xml(parent, xml) processed_account_ids = [] - public_visibility = false xml.xpath('./xmlns:link[@rel="mentioned"]', xmlns: TagManager::XMLNS).each do |link| - if link['ostatus:object-type'] == TagManager::TYPES[:collection] && link['href'] == TagManager::COLLECTIONS[:public] - public_visibility = true - next - elsif link['ostatus:object-type'] == TagManager::TYPES[:group] - next - end + next if [TagManager::TYPES[:group], TagManager::TYPES[:collection]].include? link['ostatus:object-type'] url = Addressable::URI.parse(link['href']) @@ -172,9 +167,6 @@ class ProcessFeedService < BaseService # So we can skip duplicate mentions processed_account_ids << mentioned_account.id end - - parent.visibility = public_visibility ? :public : :unlisted - parent.save! end def hashtags_from_xml(parent, xml) @@ -230,6 +222,10 @@ class ProcessFeedService < BaseService xml.at_xpath('./xmlns:summary', xmlns: TagManager::XMLNS)&.content || '' end + def visibility_scope(xml = @xml) + xml.at_xpath('./mastodon:scope', mastodon: TagManager::MTDN_XMLNS)&.content&.to_sym || :public + end + def published(xml = @xml) xml.at_xpath('./xmlns:published', xmlns: TagManager::XMLNS).content end diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index 67fd3dcf7..d3d3af8af 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -30,8 +30,6 @@ class ProcessMentionsService < BaseService status.mentions.each do |mention| mentioned_account = mention.account - next if status.private_visibility? && (!mentioned_account.following?(status.account) || !mentioned_account.local?) - if mentioned_account.local? NotifyService.new.call(mentioned_account, mention) else From 446aad4ce2cb7afd0ba8e4b508e4dcba57eac790 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Feb 2017 15:41:39 +0100 Subject: [PATCH 18/18] Make PuSH only distribute to subscriptions that match follower domains Allow PuSH to distribute private toots with that condition --- app/models/account.rb | 4 ++++ app/workers/pubsubhubbub/distribution_worker.rb | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index c2a41c4c6..ed5c46197 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -95,6 +95,10 @@ class Account < ApplicationRecord follow_requests.where(target_account: other_account).exists? end + def followers_domains + followers.reorder('').select('DISTINCT accounts.domain').map(&:domain) + end + def local? domain.nil? end diff --git a/app/workers/pubsubhubbub/distribution_worker.rb b/app/workers/pubsubhubbub/distribution_worker.rb index d5437bf6b..4576dc4a2 100644 --- a/app/workers/pubsubhubbub/distribution_worker.rb +++ b/app/workers/pubsubhubbub/distribution_worker.rb @@ -8,13 +8,18 @@ class Pubsubhubbub::DistributionWorker def perform(stream_entry_id) stream_entry = StreamEntry.find(stream_entry_id) - return if stream_entry.hidden? + # Most hidden stream entries should not be PuSHed, + # but statuses need to be distributed to trusted + # followers even when they are hidden + return if stream_entry.hidden? && stream_entry.activity_type != 'Status' account = stream_entry.account renderer = AccountsController.renderer.new(method: 'get', http_host: Rails.configuration.x.local_domain, https: Rails.configuration.x.use_https) payload = renderer.render(:show, assigns: { account: account, entries: [stream_entry] }, formats: [:atom]) + domains = account.followers_domains - Subscription.where(account: account).active.select('id').find_each do |subscription| + Subscription.where(account: account).active.select('id, callback_url').find_each do |subscription| + next unless domains.include?(Addressable::URI.parse(subscription.callback_url).host) Pubsubhubbub::DeliveryWorker.perform_async(subscription.id, payload) end rescue ActiveRecord::RecordNotFound