From efef36447f244275b9781842622c9e3ba5f0860e Mon Sep 17 00:00:00 2001 From: Olivier Humbert Date: Wed, 6 Sep 2017 22:32:49 +0200 Subject: [PATCH 01/27] Update fr.json (#4830) typo --- app/javascript/mastodon/locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index fa8ea6c736..17f07c8a67 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -62,7 +62,7 @@ "confirmations.mute.confirm": "Masquer", "confirmations.mute.message": "Confirmez vous le masquage de {name} ?", "confirmations.unfollow.confirm": "Ne plus suivre", - "confirmations.unfollow.message": "Vous voulez-vous arrêter de suivre {name} ?", + "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Here is what it will look like:", "emoji_button.activity": "Activités", From e489378e223a07ce4956de1f3b9a02abcedd5c8b Mon Sep 17 00:00:00 2001 From: Quent-in Date: Thu, 7 Sep 2017 01:55:03 +0200 Subject: [PATCH 02/27] i10n update OC and FR files (#4824) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Onboarding: corrections Some missing letters and spaces or better wording * Embed Translated as Intégrer in FR / Embarcar in OC --- app/javascript/mastodon/locales/fr.json | 4 ++-- app/javascript/mastodon/locales/oc.json | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 17f07c8a67..a4cb2cdd0c 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -63,8 +63,8 @@ "confirmations.mute.message": "Confirmez vous le masquage de {name} ?", "confirmations.unfollow.confirm": "Ne plus suivre", "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "embed.instructions": "Intégrez ce statut à votre site en copiant ce code ci-dessous.", + "embed.preview": "Il apparaîtra comme cela : ", "emoji_button.activity": "Activités", "emoji_button.flags": "Drapeaux", "emoji_button.food": "Boire et manger", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index a86033e6f6..52f4b7d64c 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -87,7 +87,7 @@ "getting_started.appsshort": "Apps", "getting_started.faq": "FAQ", "getting_started.heading": "Per començar", - "getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via{github} sus GitHub.", + "getting_started.open_source_notice": "Mastodon es un logicial liure. Podètz contribuir e mandar vòstres comentaris e rapòrt de bug via {github} sus GitHub.", "getting_started.userguide": "Guida d’utilizacion", "home.column_settings.advanced": "Avançat", "home.column_settings.basic": "Basic", @@ -126,21 +126,21 @@ "notifications.column_settings.reblog": "Partatges :", "notifications.column_settings.show": "Mostrar dins la colomna", "notifications.column_settings.sound": "Emetre un son", - "onboarding.done": "Fach", + "onboarding.done": "Sortir", "onboarding.next": "Seguent", - "onboarding.page_five.public_timelines": "Lo flux local mòstra los estatuts publics del monde de vòstra instància, aquí {domain}. Lo flux federat mòstra los estatuts publics de tot lo mond sus {domain} sègon. Son los fluxes publics, un bon biais de trobar de mond.", + "onboarding.page_five.public_timelines": "Lo flux local mòstra los estatuts publics del monde de vòstra instància, aquí {domain}. Lo flux federat mòstra los estatuts publics de la gent que los de {domain} sègon. Son los fluxes publics, un bon biais de trobar de mond.", "onboarding.page_four.home": "Lo flux d’acuèlh mòstra los estatuts del mond que seguètz.", "onboarding.page_four.notifications": "La colomna de notificacions vos fa veire quand qualqu’un interagís amb vos", - "onboarding.page_one.federation": "Mastodon es un malhum de servidors independents que comunican per bastir un malhum ma larg. Òm los apèla instàncias.", + "onboarding.page_one.federation": "Mastodon es un malhum de servidors independents que comunican per bastir un malhum mai larg. Òm los apèla instàncias.", "onboarding.page_one.handle": "Sètz sus {domain}, doncas vòstre identificant complet es {handle}", "onboarding.page_one.welcome": "Benvengut a Mastodon !", "onboarding.page_six.admin": "Vòstre administrator d’instància es {admin}.", "onboarding.page_six.almost_done": "Gaireben acabat…", - "onboarding.page_six.appetoot": "Bon Appetut!", + "onboarding.page_six.appetoot": "Bon Appetut !", "onboarding.page_six.apps_available": "I a d’aplicacions per mobil per iOS, Android e mai.", "onboarding.page_six.github": "Mastodon es un logicial liure e open-source. Podètz senhalar de bugs, demandar de foncionalitats e contribuir al còdi sus {github}.", "onboarding.page_six.guidelines": "guida de la comunitat", - "onboarding.page_six.read_guidelines": "Mercés de legir la {guidelines} a {domain} !", + "onboarding.page_six.read_guidelines": "Mercés de legir la {guidelines} de {domain} !", "onboarding.page_six.various_app": "aplicacions per mobil", "onboarding.page_three.profile": "Modificatz vòstre perfil per cambiar vòstre avatar, bio e escais-nom. I a enlà totas las preferéncias.", "onboarding.page_three.search": "Emplegatz la barra de recèrca per trobar de mond e engachatz las etiquetas coma {illustration} e {introductions}. Per trobar una persona d’una autra instància, picatz son identificant complet.", @@ -183,7 +183,7 @@ "status.show_less": "Tornar plegar", "status.show_more": "Desplegar", "status.unmute_conversation": "Conversacions amb silenci levat", - "status.unpin": "Despenjar del perfil", + "status.unpin": "Tirar del perfil", "tabs_bar.compose": "Compausar", "tabs_bar.federated_timeline": "Flux public global", "tabs_bar.home": "Acuèlh", From c69b1432640d60f9104e026479c92a4a9395888d Mon Sep 17 00:00:00 2001 From: Joseph Mingrone Date: Wed, 6 Sep 2017 22:55:06 -0300 Subject: [PATCH 03/27] Use casecmp() instead of casecmp?() for now (#4832) * Use casecmp() instead of casecmp?() for now casecmp?() is only available in ruby 2.4.0. Users running earlier ruby versions would see errors, e.g., running RAILS_ENV=production rails mastodon:maintenance:remove_deprecated_preview_cards. * Correctly check whether casecmp() returns 0 --- lib/tasks/mastodon.rake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index 307bc240db..3c65ece4be 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -47,7 +47,7 @@ namespace :mastodon do confirm = STDIN.gets.chomp puts - if confirm.casecmp?('y') + if confirm.casecmp('y').zero? password = SecureRandom.hex user = User.new(email: email, password: password, account_attributes: { username: username }) if user.save @@ -289,13 +289,13 @@ namespace :mastodon do puts 'Delete records and associated files from deprecated preview cards? [y/N]: ' confirm = STDIN.gets.chomp - if confirm.casecmp?('y') + if confirm.casecmp('y').zero? DeprecatedPreviewCard.in_batches.destroy_all puts 'Drop deprecated preview cards table? [y/N]: ' confirm = STDIN.gets.chomp - if confirm.casecmp?('y') + if confirm.casecmp('y').zero? ActiveRecord::Migration.drop_table :deprecated_preview_cards end end From ac63da77324b99b05ca19ecb44a89208745b6d4a Mon Sep 17 00:00:00 2001 From: voidSatisfaction Date: Thu, 7 Sep 2017 16:55:42 +0900 Subject: [PATCH 04/27] Feat add validation for report comment: characters under 1000 valid (#4833) --- app/models/report.rb | 2 ++ spec/models/report_spec.rb | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/app/models/report.rb b/app/models/report.rb index 4d2552d30a..479aa17bb1 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -22,6 +22,8 @@ class Report < ApplicationRecord scope :unresolved, -> { where(action_taken: false) } scope :resolved, -> { where(action_taken: true) } + validates :comment, length: { maximum: 1000 } + def statuses Status.where(id: status_ids).includes(:account, :media_attachments, :mentions) end diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb index 6c27238457..d40ebf6dc3 100644 --- a/spec/models/report_spec.rb +++ b/spec/models/report_spec.rb @@ -21,4 +21,18 @@ describe Report do expect(report.media_attachments).to eq [media_attachment] end end + + describe 'validatiions' do + it 'has a valid fabricator' do + report = Fabricate(:report) + report.valid? + expect(report).to be_valid + end + + it 'is invalid if comment is longer than 1000 characters' do + report = Fabricate.build(:report, comment: Faker::Lorem.characters(1001)) + report.valid? + expect(report).to model_have_error_on_field(:comment) + end + end end From d766cb0c3c5dac79122a07332a1b14f21a84022f Mon Sep 17 00:00:00 2001 From: voidSatisfaction Date: Thu, 7 Sep 2017 16:58:11 +0900 Subject: [PATCH 05/27] Add Pinned toot column (#4817) * Add Pinned_toot_section * Fix add frozen_string_literal * Fix delete no need controller and tests * Fix replace query strings to axios params * Fix change value to accountId and disabling more button --- .../mastodon/actions/pin_statuses.js | 39 ++++++++++++ .../features/getting_started/index.js | 8 ++- .../features/pinned_statuses/index.js | 59 +++++++++++++++++++ app/javascript/mastodon/features/ui/index.js | 2 + .../features/ui/util/async-components.js | 4 ++ app/javascript/mastodon/locales/en.json | 2 + app/javascript/mastodon/locales/ja.json | 2 + app/javascript/mastodon/locales/ko.json | 2 + .../mastodon/reducers/status_lists.js | 16 +++++ app/javascript/mastodon/reducers/statuses.js | 4 ++ 10 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 app/javascript/mastodon/actions/pin_statuses.js create mode 100644 app/javascript/mastodon/features/pinned_statuses/index.js diff --git a/app/javascript/mastodon/actions/pin_statuses.js b/app/javascript/mastodon/actions/pin_statuses.js new file mode 100644 index 0000000000..01bf8930b2 --- /dev/null +++ b/app/javascript/mastodon/actions/pin_statuses.js @@ -0,0 +1,39 @@ +import api from '../api'; + +export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST'; +export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS'; +export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL'; + +export function fetchPinnedStatuses() { + return (dispatch, getState) => { + dispatch(fetchPinnedStatusesRequest()); + + const accountId = getState().getIn(['meta', 'me']); + api(getState).get(`/api/v1/accounts/${accountId}/statuses`, { params: { pinned: true } }).then(response => { + dispatch(fetchPinnedStatusesSuccess(response.data, null)); + }).catch(error => { + dispatch(fetchPinnedStatusesFail(error)); + }); + }; +}; + +export function fetchPinnedStatusesRequest() { + return { + type: PINNED_STATUSES_FETCH_REQUEST, + }; +}; + +export function fetchPinnedStatusesSuccess(statuses, next) { + return { + type: PINNED_STATUSES_FETCH_SUCCESS, + statuses, + next, + }; +}; + +export function fetchPinnedStatusesFail(error) { + return { + type: PINNED_STATUSES_FETCH_FAIL, + error, + }; +}; diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index f8ea010247..973c8a4aef 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -23,6 +23,7 @@ const messages = defineMessages({ blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }, + pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, }); const mapStateToProps = state => ({ @@ -66,15 +67,16 @@ export default class GettingStarted extends ImmutablePureComponent { navItems = navItems.concat([ , + , ]); if (me.get('locked')) { - navItems.push(); + navItems.push(); } navItems = navItems.concat([ - , - , + , + , ]); return ( diff --git a/app/javascript/mastodon/features/pinned_statuses/index.js b/app/javascript/mastodon/features/pinned_statuses/index.js new file mode 100644 index 0000000000..b4a6c1e527 --- /dev/null +++ b/app/javascript/mastodon/features/pinned_statuses/index.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { fetchPinnedStatuses } from '../../actions/pin_statuses'; +import Column from '../ui/components/column'; +import ColumnBackButtonSlim from '../../components/column_back_button_slim'; +import StatusList from '../../components/status_list'; +import { defineMessages, injectIntl } from 'react-intl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; + +const messages = defineMessages({ + heading: { id: 'column.pins', defaultMessage: 'Pinned toot' }, +}); + +const mapStateToProps = state => ({ + statusIds: state.getIn(['status_lists', 'pins', 'items']), + hasMore: !!state.getIn(['status_lists', 'pins', 'next']), +}); + +@connect(mapStateToProps) +@injectIntl +export default class PinnedStatuses extends ImmutablePureComponent { + + static propTypes = { + dispatch: PropTypes.func.isRequired, + statusIds: ImmutablePropTypes.list.isRequired, + intl: PropTypes.object.isRequired, + hasMore: PropTypes.bool.isRequired, + }; + + componentWillMount () { + this.props.dispatch(fetchPinnedStatuses()); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + + setRef = c => { + this.column = c; + } + + render () { + const { intl, statusIds, hasMore } = this.props; + + return ( + + + + + ); + } + +} diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index 8f971ae675..41ce0f8b54 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -35,6 +35,7 @@ import { FavouritedStatuses, Blocks, Mutes, + PinnedStatuses, } from './util/async-components'; // Dummy import, to make sure that ends up in the application bundle. @@ -208,6 +209,7 @@ export default class UI extends React.PureComponent { + diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 0882beb7fe..0b4e2df22b 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -34,6 +34,10 @@ export function GettingStarted () { return import(/* webpackChunkName: "features/getting_started" */'../../getting_started'); } +export function PinnedStatuses () { + return import(/* webpackChunkName: "features/pinned_statuses" */'../../pinned_statuses'); +} + export function AccountTimeline () { return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline'); } diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 6d9b9c2087..f42851f459 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -34,6 +34,7 @@ "column.mutes": "Muted users", "column.notifications": "Notifications", "column.public": "Federated timeline", + "column.pins": "Pinned toots", "column_back_button.label": "Back", "column_header.hide_settings": "Hide settings", "column_header.moveLeft_settings": "Move column to the left", @@ -111,6 +112,7 @@ "navigation_bar.mutes": "Muted users", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.pins": "Pinned toots", "notification.favourite": "{name} favourited your status", "notification.follow": "{name} followed you", "notification.mention": "{name} mentioned you", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 560d2b6684..65838a3f80 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -34,6 +34,7 @@ "column.mutes": "ミュートしたユーザー", "column.notifications": "通知", "column.public": "連合タイムライン", + "column.pins": "固定されたトゥート", "column_back_button.label": "戻る", "column_header.hide_settings": "設定を隠す", "column_header.moveLeft_settings": "カラムを左に移動する", @@ -111,6 +112,7 @@ "navigation_bar.mutes": "ミュートしたユーザー", "navigation_bar.preferences": "ユーザー設定", "navigation_bar.public_timeline": "連合タイムライン", + "navigation_bar.pins": "固定されたトゥート", "notification.favourite": "{name}さんがあなたのトゥートをお気に入りに登録しました", "notification.follow": "{name}さんにフォローされました", "notification.mention": "{name}さんがあなたに返信しました", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 7d573506cf..8393e82e57 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -34,6 +34,7 @@ "column.mutes": "뮤트 중인 사용자", "column.notifications": "알림", "column.public": "연합 타임라인", + "column.pins": "고정된 Toot", "column_back_button.label": "돌아가기", "column_header.hide_settings": "Hide settings", "column_header.moveLeft_settings": "Move column to the left", @@ -111,6 +112,7 @@ "navigation_bar.mutes": "뮤트 중인 사용자", "navigation_bar.preferences": "사용자 설정", "navigation_bar.public_timeline": "연합 타임라인", + "navigation_bar.pins": "고정된 Toot", "notification.favourite": "{name}님이 즐겨찾기 했습니다", "notification.follow": "{name}님이 나를 팔로우 했습니다", "notification.mention": "{name}님이 답글을 보냈습니다", diff --git a/app/javascript/mastodon/reducers/status_lists.js b/app/javascript/mastodon/reducers/status_lists.js index 2ce27a4545..c4aeb338f4 100644 --- a/app/javascript/mastodon/reducers/status_lists.js +++ b/app/javascript/mastodon/reducers/status_lists.js @@ -2,10 +2,15 @@ import { FAVOURITED_STATUSES_FETCH_SUCCESS, FAVOURITED_STATUSES_EXPAND_SUCCESS, } from '../actions/favourites'; +import { + PINNED_STATUSES_FETCH_SUCCESS, +} from '../actions/pin_statuses'; import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; import { FAVOURITE_SUCCESS, UNFAVOURITE_SUCCESS, + PIN_SUCCESS, + UNPIN_SUCCESS, } from '../actions/interactions'; const initialState = ImmutableMap({ @@ -14,6 +19,11 @@ const initialState = ImmutableMap({ loaded: false, items: ImmutableList(), }), + pins: ImmutableMap({ + next: null, + loaded: false, + items: ImmutableList(), + }), }); const normalizeList = (state, listType, statuses, next) => { @@ -53,6 +63,12 @@ export default function statusLists(state = initialState, action) { return prependOneToList(state, 'favourites', action.status); case UNFAVOURITE_SUCCESS: return removeOneFromList(state, 'favourites', action.status); + case PINNED_STATUSES_FETCH_SUCCESS: + return normalizeList(state, 'pins', action.statuses, action.next); + case PIN_SUCCESS: + return prependOneToList(state, 'pins', action.status); + case UNPIN_SUCCESS: + return removeOneFromList(state, 'pins', action.status); default: return state; } diff --git a/app/javascript/mastodon/reducers/statuses.js b/app/javascript/mastodon/reducers/statuses.js index 38691dc430..eec2a5f165 100644 --- a/app/javascript/mastodon/reducers/statuses.js +++ b/app/javascript/mastodon/reducers/statuses.js @@ -36,6 +36,9 @@ import { FAVOURITED_STATUSES_FETCH_SUCCESS, FAVOURITED_STATUSES_EXPAND_SUCCESS, } from '../actions/favourites'; +import { + PINNED_STATUSES_FETCH_SUCCESS, +} from '../actions/pin_statuses'; import { SEARCH_FETCH_SUCCESS } from '../actions/search'; import emojify from '../emoji'; import { Map as ImmutableMap, fromJS } from 'immutable'; @@ -138,6 +141,7 @@ export default function statuses(state = initialState, action) { case NOTIFICATIONS_EXPAND_SUCCESS: case FAVOURITED_STATUSES_FETCH_SUCCESS: case FAVOURITED_STATUSES_EXPAND_SUCCESS: + case PINNED_STATUSES_FETCH_SUCCESS: case SEARCH_FETCH_SUCCESS: return normalizeStatuses(state, action.statuses); case TIMELINE_DELETE: From 3c816b0a779e8651b3b7fd608862bf43981dd73c Mon Sep 17 00:00:00 2001 From: PFM Date: Thu, 7 Sep 2017 23:18:41 +0900 Subject: [PATCH 06/27] Use ); } else { return ( -
+
+ ); } } if (this.state.preview && !autoplay) { return ( -
+
+ ); } diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index 7fd16f6b3d..75485d6b62 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -2347,22 +2347,6 @@ button.icon-button.active i.fa-retweet { height: 100%; } -.media-spoiler__video { - align-items: center; - background: $base-overlay-background; - color: $primary-text-color; - cursor: pointer; - display: flex; - flex-direction: column; - border: 0; - width: 100%; - height: 100%; - justify-content: center; - position: relative; - text-align: center; - z-index: 100; -} - .media-spoiler__warning { display: block; font-size: 14px; @@ -3821,6 +3805,8 @@ button.icon-button.active i.fa-retweet { cursor: pointer; margin-top: 8px; position: relative; + border: 0; + display: block; } .media-spoiler-video-play-icon { From 0080804f4447c46cdeca34d4fa16431afce55a3a Mon Sep 17 00:00:00 2001 From: abcang Date: Thu, 7 Sep 2017 23:44:15 +0900 Subject: [PATCH 07/27] Enable UniqueRetryJobMiddleware even when called from sidekiq worker (#4836) --- config/initializers/sidekiq.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 61e1313364..0ee77730e8 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -9,6 +9,9 @@ end Sidekiq.configure_server do |config| config.redis = redis_params + config.client_middleware do |chain| + chain.add Mastodon::UniqueRetryJobMiddleware + end end Sidekiq.configure_client do |config| From 8bb036350a8b4af2ed6a92e4ec53986a256dc909 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 7 Sep 2017 20:18:34 +0200 Subject: [PATCH 08/27] Fix #4834 - Adjust Status#local and Status#remote scopes (#4839) --- app/models/status.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/status.rb b/app/models/status.rb index fdc230d8f6..514cab2e4d 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -63,8 +63,8 @@ class Status < ApplicationRecord default_scope { recent } scope :recent, -> { reorder(id: :desc) } - scope :remote, -> { where.not(uri: nil) } - scope :local, -> { where(uri: nil) } + scope :remote, -> { where(local: false).or(where.not(uri: nil)) } + scope :local, -> { where(local: true).or(where(uri: nil)) } scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') } scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') } From cbe9eb3f2e12febf0da92a229cb55ef419c00fe3 Mon Sep 17 00:00:00 2001 From: Quent-in Date: Thu, 7 Sep 2017 22:07:03 +0200 Subject: [PATCH 09/27] i10n OC / FR update Pinned toots (#4842) * Added column.pins New strings * Added column.pins * Update confirmation_instructions.oc.html.erb * Update confirmation_instructions.oc.text.erb * Update password_change.oc.html.erb * Update password_change.oc.text.erb * Update reset_password_instructions.oc.html.erb * Update reset_password_instructions.oc.text.erb * Update confirmation_instructions.oc.html.erb * Update confirmation_instructions.oc.text.erb --- app/javascript/mastodon/locales/fr.json | 1 + app/javascript/mastodon/locales/oc.json | 1 + app/views/user_mailer/confirmation_instructions.oc.html.erb | 4 ++-- app/views/user_mailer/confirmation_instructions.oc.text.erb | 4 ++-- app/views/user_mailer/password_change.oc.html.erb | 4 ++-- app/views/user_mailer/password_change.oc.text.erb | 4 ++-- app/views/user_mailer/reset_password_instructions.oc.html.erb | 2 +- app/views/user_mailer/reset_password_instructions.oc.text.erb | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index a4cb2cdd0c..628b887860 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -34,6 +34,7 @@ "column.mutes": "Comptes masqués", "column.notifications": "Notifications", "column.public": "Fil public global", + "column.pins": "Pouets épinglés", "column_back_button.label": "Retour", "column_header.hide_settings": "Masquer les paramètres", "column_header.moveLeft_settings": "Déplacer la colonne vers la gauche", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 52f4b7d64c..a04cbb51c9 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -34,6 +34,7 @@ "column.mutes": "Personas en silenci", "column.notifications": "Notificacions", "column.public": "Flux public global", + "column.pins": "Tuts penjats", "column_back_button.label": "Tornar", "column_header.hide_settings": "Amagar los paramètres", "column_header.moveLeft_settings": "Desplaçar la colomna a man drecha", diff --git a/app/views/user_mailer/confirmation_instructions.oc.html.erb b/app/views/user_mailer/confirmation_instructions.oc.html.erb index 9e9732bd8b..ed1428a55c 100644 --- a/app/views/user_mailer/confirmation_instructions.oc.html.erb +++ b/app/views/user_mailer/confirmation_instructions.oc.html.erb @@ -1,8 +1,8 @@ -

Bonjorn <%= @resource.email %> !

+

Bonjorn <%= @resource.email %> ! 

Venètz de vos crear un compte sus <%= @instance %> e vos mercegem :)

-

Per confirmar vòstre inscripcion, mercés de clicar sul ligam seguent :
+

Per confirmar vòstre inscripcion, mercés de clicar sul ligam seguent : 
<%= link_to 'Confirmar mon compte', confirmation_url(@resource, confirmation_token: @token) %>

Aprèp vòstra primièra connexion, poiretz accedir a la documentacion de l’aisina.

diff --git a/app/views/user_mailer/confirmation_instructions.oc.text.erb b/app/views/user_mailer/confirmation_instructions.oc.text.erb index ff1abf62dd..444d296ce6 100644 --- a/app/views/user_mailer/confirmation_instructions.oc.text.erb +++ b/app/views/user_mailer/confirmation_instructions.oc.text.erb @@ -1,8 +1,8 @@ -Bonjorn <%= @resource.email %> ! +Bonjorn <%= @resource.email %> !  Venètz de vos crear un compte sus <%= @instance %> e vos mercegem :) -er confirmar vòstre inscripcion, mercés de clicar sul ligam seguent : +er confirmar vòstre inscripcion, mercés de clicar sul ligam seguent :  <%= link_to 'Confirmar mon compte', confirmation_url(@resource, confirmation_token: @token) %> Aprèp vòstra primièra connexion, poiretz accedir a la documentacion de l’aisina. diff --git a/app/views/user_mailer/password_change.oc.html.erb b/app/views/user_mailer/password_change.oc.html.erb index a6b506f5e0..476db95366 100644 --- a/app/views/user_mailer/password_change.oc.html.erb +++ b/app/views/user_mailer/password_change.oc.html.erb @@ -1,3 +1,3 @@ -

Bonjorn <%= @resource.email %> !

+

Bonjorn <%= @resource.email %> ! 

-

Vos contactem per vos avisar que vòstre senhal per Mastodon es ben estat cambiat.

+

Vos contactem per vos avisar qu’avèm ben cambiat vòstre senhal Mastodon.

diff --git a/app/views/user_mailer/password_change.oc.text.erb b/app/views/user_mailer/password_change.oc.text.erb index 1caebde69a..e6caa045cd 100644 --- a/app/views/user_mailer/password_change.oc.text.erb +++ b/app/views/user_mailer/password_change.oc.text.erb @@ -1,3 +1,3 @@ -Bonjorn <%= @resource.email %> ! +Bonjorn <%= @resource.email %> !  -Vos contactem per vos avisar que vòstre senhal per Mastodon es ben estat cambiat. +Vos contactem per vos avisar qu’avèm ben cambiat vòstre senhal Mastodon. diff --git a/app/views/user_mailer/reset_password_instructions.oc.html.erb b/app/views/user_mailer/reset_password_instructions.oc.html.erb index acf2c0abde..7363ee4b6a 100644 --- a/app/views/user_mailer/reset_password_instructions.oc.html.erb +++ b/app/views/user_mailer/reset_password_instructions.oc.html.erb @@ -1,4 +1,4 @@ -

Bonjorn <%= @resource.email %> !

+

Bonjorn <%= @resource.email %> ! 

Qualqu’un a demandat una reĩnicializacion de vòstre senhal per Mastodon. Podètz realizar la reĩnicializacion en clicant sul ligam çai-jos.

diff --git a/app/views/user_mailer/reset_password_instructions.oc.text.erb b/app/views/user_mailer/reset_password_instructions.oc.text.erb index 211974cc27..a95a1ae8cd 100644 --- a/app/views/user_mailer/reset_password_instructions.oc.text.erb +++ b/app/views/user_mailer/reset_password_instructions.oc.text.erb @@ -1,4 +1,4 @@ -Bonjorn <%= @resource.email %> ! +Bonjorn <%= @resource.email %> !  Qualqu’un a demandat una reĩnicializacion de vòstre senhal per Mastodon. Podètz realizar la reĩnicializacion en clicant sul ligam çai-jos.

From 1a4beb3122ba5952a735417d6798115b442f4749 Mon Sep 17 00:00:00 2001 From: m4sk1n Date: Thu, 7 Sep 2017 22:51:48 +0200 Subject: [PATCH 10/27] i18n: Update Polish translation (#4845) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Mikołajczak --- app/javascript/mastodon/locales/pl.json | 8 +++++--- config/locales/pl.yml | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index e3e6529700..daa60128d5 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -12,7 +12,7 @@ "account.mute": "Wycisz @{name}", "account.posts": "Wpisy", "account.report": "Zgłoś @{name}", - "account.requested": "Oczekująca prośba", + "account.requested": "Oczekująca prośba, kliknij aby anulować", "account.share": "Udostępnij profil @{name}", "account.unblock": "Odblokuj @{name}", "account.unblock_domain": "Odblokuj domenę {domain}", @@ -33,6 +33,7 @@ "column.home": "Strona główna", "column.mutes": "Wyciszeni użytkownicy", "column.notifications": "Powiadomienia", + "column.pins": "Przypięte wpisy", "column.public": "Globalna oś czasu", "column_back_button.label": "Wróć", "column_header.hide_settings": "Ukryj ustawienia", @@ -109,6 +110,7 @@ "navigation_bar.info": "Szczegółowe informacje", "navigation_bar.logout": "Wyloguj", "navigation_bar.mutes": "Wyciszeni użytkownicy", + "navigation_bar.pins": "Przypięte wpisy", "navigation_bar.preferences": "Preferencje", "navigation_bar.public_timeline": "Oś czasu federacji", "notification.favourite": "{name} dodał Twój status do ulubionych", @@ -153,8 +155,8 @@ "privacy.private.short": "Tylko dla śledzących", "privacy.public.long": "Widoczny na publicznych osiach czasu", "privacy.public.short": "Publiczny", - "privacy.unlisted.long": "Niewidoczne na publicznych osiach czasu", - "privacy.unlisted.short": "Niewidoczne", + "privacy.unlisted.long": "Niewidoczny na publicznych osiach czasu", + "privacy.unlisted.short": "Niewidoczny", "reply_indicator.cancel": "Anuluj", "report.placeholder": "Dodatkowe komentarze", "report.submit": "Wyślij", diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 842baef451..88125f6923 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -451,11 +451,11 @@ pl: show_more: Pokaż więcej visibilities: private: Tylko dla śledzących - private_long: Widoczny tylko dla osób, które Cię śledzą - public: Publiczny - public_long: Widoczny dla wszystkich użytkowników - unlisted: Niewypisany - unlisted_long: Widoczny dla wszystkich, ale nie wyświetlany na publicznych osiach czasu + private_long: Widoczne tylko dla osób, które Cię śledzą + public: Publiczne + public_long: Widoczne dla wszystkich użytkowników + unlisted: Niewypisane + unlisted_long: Widoczne dla wszystkich, ale nie wyświetlane na publicznych osiach czasu stream_entries: click_to_show: Naciśnij aby wyświetlić pinned: Przypięty wpis From 6fb8be482bb42e87ed39f5fb180335a528c442bf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 8 Sep 2017 12:00:17 +0200 Subject: [PATCH 11/27] Fetch statuses/following/followers numbers from ActivityPub collections (#4840) --- .../activitypub/process_account_service.rb | 37 ++++++++++++++++--- spec/lib/activitypub/activity/update_spec.rb | 8 +++- .../fetch_remote_account_service_spec.rb | 2 +- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 29eb1c2e10..c63577fe5d 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -8,11 +8,12 @@ class ActivityPub::ProcessAccountService < BaseService def call(username, domain, json) return if json['inbox'].blank? - @json = json - @uri = @json['id'] - @username = username - @domain = domain - @account = Account.find_by(uri: @uri) + @json = json + @uri = @json['id'] + @username = username + @domain = domain + @account = Account.find_by(uri: @uri) + @collections = {} create_account if @account.nil? upgrade_account if @account.ostatus? @@ -51,6 +52,9 @@ class ActivityPub::ProcessAccountService < BaseService @account.header_remote_url = image_url('image') @account.public_key = public_key || '' @account.locked = @json['manuallyApprovesFollowers'] || false + @account.statuses_count = outbox_total_items if outbox_total_items.present? + @account.following_count = following_total_items if following_total_items.present? + @account.followers_count = followers_total_items if followers_total_items.present? @account.save! end @@ -88,6 +92,29 @@ class ActivityPub::ProcessAccountService < BaseService value['href'] end + def outbox_total_items + collection_total_items('outbox') + end + + def following_total_items + collection_total_items('following') + end + + def followers_total_items + collection_total_items('followers') + end + + def collection_total_items(type) + return if @json[type].blank? + return @collections[type] if @collections.key?(type) + + collection = fetch_resource(@json[type]) + + @collections[type] = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil + rescue HTTP::Error, OpenSSL::SSL::SSLError + @collections[type] = nil + end + def auto_suspend? domain_block && domain_block.suspend? end diff --git a/spec/lib/activitypub/activity/update_spec.rb b/spec/lib/activitypub/activity/update_spec.rb index 0bd6d00d9c..ea308e35cd 100644 --- a/spec/lib/activitypub/activity/update_spec.rb +++ b/spec/lib/activitypub/activity/update_spec.rb @@ -2,12 +2,16 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Update do let!(:sender) { Fabricate(:account) } - + before do + stub_request(:get, actor_json[:outbox]).to_return(status: 404) + stub_request(:get, actor_json[:followers]).to_return(status: 404) + stub_request(:get, actor_json[:following]).to_return(status: 404) + sender.update!(uri: ActivityPub::TagManager.instance.uri_for(sender)) end - let(:modified_sender) do + let(:modified_sender) do sender.dup.tap do |modified_sender| modified_sender.display_name = 'Totally modified now' end diff --git a/spec/services/activitypub/fetch_remote_account_service_spec.rb b/spec/services/activitypub/fetch_remote_account_service_spec.rb index 391d051c1a..ed7e9bba83 100644 --- a/spec/services/activitypub/fetch_remote_account_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_account_service_spec.rb @@ -41,7 +41,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService do before do actor[:inbox] = nil - + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end From 904ab54cf331c180eba055814bd64378c80087cc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 8 Sep 2017 12:00:30 +0200 Subject: [PATCH 12/27] "Mute conversation" option on all own toots, not just in notifications (#4844) That way you can mute notifications for a toot before you get replies to it or boosts or favourites --- app/javascript/mastodon/components/status_action_bar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index 850f3f8c40..692b1ef2bc 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -134,7 +134,7 @@ export default class StatusActionBar extends ImmutablePureComponent { menu.push(null); - if (withDismiss) { + if (status.getIn(['account', 'id']) === me || withDismiss) { menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); } From a27821f725e9bc47961d6474f0270ac91052fa13 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 8 Sep 2017 12:32:22 +0200 Subject: [PATCH 13/27] Fix language filter codes (#4841) * Fix language filter codes CLD3 returns BCP-47 language identifier, filter settings expect identifiers in the ISO 639-1 format. Convert between formats, and exclude duplicate languages from filter choices (zh-CN->zh) * Fix zh name --- Gemfile | 1 + Gemfile.lock | 2 ++ app/helpers/settings_helper.rb | 5 +++++ app/lib/language_detector.rb | 11 ++++++++++- app/views/settings/preferences/show.html.haml | 2 +- spec/helpers/settings_helper_spec.rb | 4 ++-- 6 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 486e72cc4a..637bf53eeb 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,7 @@ gem 'addressable', '~> 2.5' gem 'bootsnap' gem 'browser' gem 'charlock_holmes', '~> 0.7.5' +gem 'iso-639' gem 'cld3', '~> 3.1' gem 'devise', '~> 4.2' gem 'devise-two-factor', '~> 3.0' diff --git a/Gemfile.lock b/Gemfile.lock index ef99e0d7b3..ddb97dd940 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -225,6 +225,7 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.0) ipaddress (0.8.3) + iso-639 (0.2.8) jmespath (1.3.1) json (2.1.0) json-ld (2.1.5) @@ -560,6 +561,7 @@ DEPENDENCIES httplog (~> 0.99) i18n-tasks (~> 0.9) idn-ruby + iso-639 json-ld-preloaded (~> 2.2.1) kaminari (~> 1.0) letter_opener (~> 1.4) diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index af950aa634..369a456809 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -30,6 +30,7 @@ module SettingsHelper th: 'ภาษาไทย', tr: 'Türkçe', uk: 'Українська', + zh: '中文', 'zh-CN': '简体中文', 'zh-HK': '繁體中文(香港)', 'zh-TW': '繁體中文(臺灣)', @@ -39,6 +40,10 @@ module SettingsHelper HUMAN_LOCALES[locale] end + def filterable_languages + I18n.available_locales.map { |locale| locale.to_s.split('-').first.to_sym }.uniq + end + def hash_to_object(hash) HashObject.new(hash) end diff --git a/app/lib/language_detector.rb b/app/lib/language_detector.rb index cc7509fdc8..1d9932b528 100644 --- a/app/lib/language_detector.rb +++ b/app/lib/language_detector.rb @@ -20,7 +20,16 @@ class LanguageDetector private def detected_language_code - result.language.to_sym if detected_language_reliable? + iso6391(result.language).to_sym if detected_language_reliable? + end + + def iso6391(bcp47) + iso639 = bcp47.split('-').first + + # CLD3 returns grandfathered language code for Hebrew + return 'he' if iso639 == 'iw' + + ISO_639.find(iso639).alpha2 end def result diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml index fae6090c81..f42f925080 100644 --- a/app/views/settings/preferences/show.html.haml +++ b/app/views/settings/preferences/show.html.haml @@ -13,7 +13,7 @@ selected: I18n.locale = f.input :filtered_languages, - collection: I18n.available_locales, + collection: filterable_languages, wrapper: :with_block_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }, diff --git a/spec/helpers/settings_helper_spec.rb b/spec/helpers/settings_helper_spec.rb index 5a51e0ef1f..092c375836 100644 --- a/spec/helpers/settings_helper_spec.rb +++ b/spec/helpers/settings_helper_spec.rb @@ -4,10 +4,10 @@ require 'rails_helper' describe SettingsHelper do describe 'the HUMAN_LOCALES constant' do - it 'has the same number of keys as I18n locales exist' do + it 'includes all I18n locales' do options = I18n.available_locales - expect(described_class::HUMAN_LOCALES.keys).to eq(options) + expect(described_class::HUMAN_LOCALES.keys).to include(*options) end end From df9c7584c959bf8a66e0dbf1d24c43f46ccca53c Mon Sep 17 00:00:00 2001 From: Quent-in Date: Fri, 8 Sep 2017 13:55:47 +0200 Subject: [PATCH 14/27] i10n update OC and FR (#4849) * Missing "navigation_bar.pins" * Missing "navigation_bar.pins" --- app/javascript/mastodon/locales/fr.json | 1 + app/javascript/mastodon/locales/oc.json | 1 + 2 files changed, 2 insertions(+) diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 628b887860..8ca632accd 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -112,6 +112,7 @@ "navigation_bar.mutes": "Comptes masqués", "navigation_bar.preferences": "Préférences", "navigation_bar.public_timeline": "Fil public global", + "navigation_bar.pins": "Pouets épinglés", "notification.favourite": "{name} a ajouté à ses favoris :", "notification.follow": "{name} vous suit.", "notification.mention": "{name} vous a mentionné⋅e :", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index a04cbb51c9..d2b2dd48f7 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -112,6 +112,7 @@ "navigation_bar.mutes": "Personas rescondudas", "navigation_bar.preferences": "Preferéncias", "navigation_bar.public_timeline": "Flux public global", + "navigation_bar.pins": "Tuts penjats", "notification.favourite": "{name} a ajustat a sos favorits :", "notification.follow": "{name} vos sèc", "notification.mention": "{name} vos a mencionat :", From 05ef0ead4adbe2fa5a802efd511853fa1335232c Mon Sep 17 00:00:00 2001 From: unarist Date: Sat, 9 Sep 2017 01:20:03 +0900 Subject: [PATCH 15/27] Handle stream_entry URL correctly in ActivityPub (#4854) In before, the method uses stream_entry id as status id, so replied status was wrongly selected. This PR uses StatusFinder which was introduced with `Api::Web::EmbedsController`. --- app/lib/activitypub/tag_manager.rb | 4 +++- spec/lib/activitypub/tag_manager_spec.rb | 28 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index de575d9e6f..929e87852c 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -96,12 +96,14 @@ class ActivityPub::TagManager when 'Account' klass.find_local(uri_to_local_id(uri, :username)) else - klass.find_by(id: uri_to_local_id(uri)) + StatusFinder.new(uri).status end elsif ::TagManager.instance.local_id?(uri) klass.find_by(id: ::TagManager.instance.unique_tag_to_local_id(uri, klass.to_s)) else klass.find_by(uri: uri.split('#').first) end + rescue ActiveRecord::RecordNotFound + nil end end diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb index 8f7662e24a..dea8abc655 100644 --- a/spec/lib/activitypub/tag_manager_spec.rb +++ b/spec/lib/activitypub/tag_manager_spec.rb @@ -91,9 +91,35 @@ RSpec.describe ActivityPub::TagManager do end describe '#uri_to_resource' do - it 'returns the local resource' do + it 'returns the local account' do account = Fabricate(:account) expect(subject.uri_to_resource(subject.uri_for(account), Account)).to eq account end + + it 'returns the remote account by matching URI without fragment part' do + account = Fabricate(:account, uri: 'https://example.com/123') + expect(subject.uri_to_resource('https://example.com/123#456', Account)).to eq account + end + + it 'returns the local status for ActivityPub URI' do + status = Fabricate(:status) + expect(subject.uri_to_resource(subject.uri_for(status), Status)).to eq status + end + + it 'returns the local status for OStatus tag: URI' do + status = Fabricate(:status) + expect(subject.uri_to_resource(::TagManager.instance.uri_for(status), Status)).to eq status + end + + it 'returns the local status for OStatus StreamEntry URL' do + status = Fabricate(:status) + stream_entry_url = account_stream_entry_url(status.account, status.stream_entry) + expect(subject.uri_to_resource(stream_entry_url, Status)).to eq status + end + + it 'returns the remote status by matching URI without fragment part' do + status = Fabricate(:status, uri: 'https://example.com/123') + expect(subject.uri_to_resource('https://example.com/123#456', Status)).to eq status + end end end From d29f2a30e4c21c11c63070d3850c10bcd7a01d5f Mon Sep 17 00:00:00 2001 From: unarist Date: Sat, 9 Sep 2017 04:43:34 +0900 Subject: [PATCH 16/27] Refresh timeline after toot while the timeline is disconnected (#4858) To reflect status posting immediately, we've inserted the status into timelines directly. However, status insertion changes "latest status", and it means next timeline refresh only fetches statuses since the inserted status. This behavior is very bad for disconnected timeline and mobile views. After this patch, it refreshes timeline for disconnected timelines, instead of direct insertion. --- app/javascript/mastodon/actions/compose.js | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index ebb75f36e9..1f26907f24 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -1,6 +1,11 @@ import api from '../api'; -import { updateTimeline } from './timelines'; +import { + updateTimeline, + refreshHomeTimeline, + refreshCommunityTimeline, + refreshPublicTimeline, +} from './timelines'; export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST'; @@ -95,16 +100,20 @@ export function submitCompose() { dispatch(submitComposeSuccess({ ...response.data })); // To make the app more responsive, immediately get the status into the columns - dispatch(updateTimeline('home', { ...response.data })); - if (response.data.in_reply_to_id === null && response.data.visibility === 'public') { - if (getState().getIn(['timelines', 'community', 'loaded'])) { - dispatch(updateTimeline('community', { ...response.data })); + const insertOrRefresh = (timelineId, refreshAction) => { + if (getState().getIn(['timelines', timelineId, 'online'])) { + dispatch(updateTimeline(timelineId, { ...response.data })); + } else if (getState().getIn(['timelines', timelineId, 'loaded'])) { + dispatch(refreshAction()); } + }; - if (getState().getIn(['timelines', 'public', 'loaded'])) { - dispatch(updateTimeline('public', { ...response.data })); - } + insertOrRefresh('home', refreshHomeTimeline); + + if (response.data.in_reply_to_id === null && response.data.visibility === 'public') { + insertOrRefresh('community', refreshCommunityTimeline); + insertOrRefresh('public', refreshPublicTimeline); } }).catch(function (error) { dispatch(submitComposeFail(error)); From cc4bc2709d421deeec93246a32620d99d5b23f9c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 02:02:29 +0200 Subject: [PATCH 17/27] Fix #4850 - When visibility missing from API call to toot, fallback to user preference (#4861) --- app/services/post_status_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 568f5a9e7f..97c55c4b2b 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -27,9 +27,10 @@ class PostStatusService < BaseService thread: in_reply_to, sensitive: options[:sensitive], spoiler_text: options[:spoiler_text] || '', - visibility: options[:visibility], + visibility: options[:visibility] || account.user&.setting_default_privacy, language: detect_language_for(text, account), application: options[:application]) + attach_media(status, media) end From 1a5442204bcd854fc34053e07287da4baf42dab7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 02:02:44 +0200 Subject: [PATCH 18/27] Fix #4852 - Check if already requested from FollowService (#4855) --- 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 a92eb6b888..941556b604 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -12,7 +12,7 @@ class FollowService < BaseService raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended? raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) - return if source_account.following?(target_account) + return if source_account.following?(target_account) || source_account.requested?(target_account) if target_account.locked? || target_account.activitypub? request_follow(source_account, target_account) From f79eba165083b90dbeb26120772b858d462c3533 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 02:26:41 +0200 Subject: [PATCH 19/27] Fix #1004 - Temporarily pause timeline if there's been recent mouse movement (#4859) --- .../mastodon/components/scrollable_list.js | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index e47b1e9aa5..42763ddd3d 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -27,6 +27,10 @@ export default class ScrollableList extends PureComponent { trackScroll: true, }; + state = { + lastMouseMove: null, + }; + intersectionObserverWrapper = new IntersectionObserverWrapper(); handleScroll = throttle(() => { @@ -47,6 +51,14 @@ export default class ScrollableList extends PureComponent { trailing: true, }); + handleMouseMove = throttle(() => { + this.setState({ lastMouseMove: new Date() }); + }, 300); + + handleMouseLeave = () => { + this.setState({ lastMouseMove: null }); + } + componentDidMount () { this.attachScrollListener(); this.attachIntersectionObserver(); @@ -58,9 +70,10 @@ export default class ScrollableList extends PureComponent { componentDidUpdate (prevProps) { // Reset the scroll position when a new child comes in in order not to // jerk the scrollbar around if you're already scrolled down the page. - if (React.Children.count(prevProps.children) < React.Children.count(this.props.children) && this._oldScrollPosition && this.node.scrollTop > 0) { + if (React.Children.count(prevProps.children) < React.Children.count(this.props.children) && this._oldScrollPosition && (this.node.scrollTop > 0 || this._recentlyMoved())) { if (this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props)) { const newScrollTop = this.node.scrollHeight - this._oldScrollPosition; + if (this.node.scrollTop !== newScrollTop) { this.node.scrollTop = newScrollTop; } @@ -114,6 +127,10 @@ export default class ScrollableList extends PureComponent { this.props.onScrollToBottom(); } + _recentlyMoved () { + return this.state.lastMouseMove === null || ((new Date()) - this.state.lastMouseMove < 600); + } + handleKeyDown = (e) => { if (['PageDown', 'PageUp'].includes(e.key) || (e.ctrlKey && ['End', 'Home'].includes(e.key))) { const article = (() => { @@ -149,7 +166,7 @@ export default class ScrollableList extends PureComponent { if (isLoading || childrenCount > 0 || !emptyMessage) { scrollableArea = ( -
+
{prepend} From c268118e5b7b7fe72fefa2988c75433c5408995a Mon Sep 17 00:00:00 2001 From: Lynx Kotoura Date: Sat, 9 Sep 2017 09:26:58 +0900 Subject: [PATCH 20/27] Scrollable tables in settings pages (#4857) * Scrollable tables in settings pages * Add space before curly brace --- app/javascript/styles/admin.scss | 8 +- app/javascript/styles/tables.scss | 19 ++- app/views/admin/accounts/_card.html.haml | 31 ++-- app/views/admin/accounts/index.html.haml | 23 +-- app/views/admin/accounts/show.html.haml | 136 +++++++++--------- app/views/admin/domain_blocks/index.html.haml | 19 +-- app/views/admin/instances/index.html.haml | 15 +- app/views/admin/reports/index.html.haml | 25 ++-- app/views/admin/subscriptions/index.html.haml | 21 +-- .../auth/registrations/_sessions.html.haml | 47 +++--- .../authorized_applications/index.html.haml | 39 ++--- .../settings/applications/index.html.haml | 25 ++-- .../settings/applications/show.html.haml | 33 ++--- app/views/settings/exports/show.html.haml | 37 ++--- .../settings/follower_domains/show.html.haml | 27 ++-- 15 files changed, 259 insertions(+), 246 deletions(-) diff --git a/app/javascript/styles/admin.scss b/app/javascript/styles/admin.scss index b86de75b67..fa7859e38f 100644 --- a/app/javascript/styles/admin.scss +++ b/app/javascript/styles/admin.scss @@ -190,11 +190,15 @@ .filters { display: flex; - margin-bottom: 20px; + flex-wrap: wrap; .filter-subset { flex: 0 0 auto; - margin-right: 40px; + margin: 0 40px 10px 0; + + &:last-child { + margin-bottom: 20px; + } ul { margin-top: 5px; diff --git a/app/javascript/styles/tables.scss b/app/javascript/styles/tables.scss index f6e57e1961..ad46f5f9f5 100644 --- a/app/javascript/styles/tables.scss +++ b/app/javascript/styles/tables.scss @@ -3,7 +3,6 @@ max-width: 100%; border-spacing: 0; border-collapse: collapse; - margin-bottom: 20px; th, td { @@ -43,19 +42,17 @@ font-weight: 500; } - &.inline-table { - td, - th { - padding: 8px 2px; - } - - & > tbody > tr:nth-child(odd) > td, - & > tbody > tr:nth-child(odd) > th { - background: transparent; - } + &.inline-table > tbody > tr:nth-child(odd) > td, + &.inline-table > tbody > tr:nth-child(odd) > th { + background: transparent; } } +.table-wrapper { + overflow: auto; + margin-bottom: 20px; +} + samp { font-family: 'mastodon-font-monospace', monospace; } diff --git a/app/views/admin/accounts/_card.html.haml b/app/views/admin/accounts/_card.html.haml index bb33582eba..2f59550113 100644 --- a/app/views/admin/accounts/_card.html.haml +++ b/app/views/admin/accounts/_card.html.haml @@ -1,16 +1,17 @@ -%table.table - %tbody - %tr - %td= t('admin.accounts.show.created_reports') - %td= link_to pluralize(account.reports.count, t('admin.accounts.show.report')), admin_reports_path(account_id: account.id) - %tr - %td= t('admin.accounts.show.targeted_reports') - %td= link_to pluralize(account.targeted_reports.count, t('admin.accounts.show.report')), admin_reports_path(target_account_id: account.id) - - if account.silenced? || account.suspended? +.table-wrapper + %table.table + %tbody %tr - %td= t('admin.accounts.moderation.title') - %td - - if account.silenced? - %p= t('admin.accounts.moderation.silenced') - - if account.suspended? - %p= t('admin.accounts.moderation.suspended') + %td= t('admin.accounts.show.created_reports') + %td= link_to pluralize(account.reports.count, t('admin.accounts.show.report')), admin_reports_path(account_id: account.id) + %tr + %td= t('admin.accounts.show.targeted_reports') + %td= link_to pluralize(account.targeted_reports.count, t('admin.accounts.show.report')), admin_reports_path(target_account_id: account.id) + - if account.silenced? || account.suspended? + %tr + %td= t('admin.accounts.moderation.title') + %td + - if account.silenced? + %p= t('admin.accounts.moderation.silenced') + - if account.suspended? + %p= t('admin.accounts.moderation.suspended') diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 1f36aeb312..1b56a3a316 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -50,16 +50,17 @@ %button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative' -%table.table - %thead - %tr - %th= t('admin.accounts.username') - %th= t('admin.accounts.domain') - %th= t('admin.accounts.protocol') - %th= t('admin.accounts.confirmed') - %th= fa_icon 'paper-plane-o' - %th - %tbody - = render @accounts +.table-wrapper + %table.table + %thead + %tr + %th= t('admin.accounts.username') + %th= t('admin.accounts.domain') + %th= t('admin.accounts.protocol') + %th= t('admin.accounts.confirmed') + %th= fa_icon 'paper-plane-o' + %th + %tbody + = render @accounts = paginate @accounts diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index dc2f16cc99..89355281a3 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -1,86 +1,86 @@ - content_for :page_title do = @account.acct -%table.table - %tbody - %tr - %th= t('admin.accounts.username') - %td= @account.username - %tr - %th= t('admin.accounts.domain') - %td= @account.domain - %tr - %th= t('admin.accounts.display_name') - %td= @account.display_name - - - if @account.local? - %tr - %th= t('admin.accounts.email') - %td= @account.user_email +.table-wrapper + %table.table + %tbody %tr - %th= t('admin.accounts.most_recent_ip') - %td= @account.user_current_sign_in_ip - %tr - %th= t('admin.accounts.most_recent_activity') - %td - - if @account.user_current_sign_in_at - %time.formatted{ datetime: @account.user_current_sign_in_at.iso8601, title: l(@account.user_current_sign_in_at) } - = l @account.user_current_sign_in_at - - else - Never - - else + %th= t('admin.accounts.username') + %td= @account.username %tr - %th= t('admin.accounts.profile_url') - %td= link_to @account.url, @account.url + %th= t('admin.accounts.domain') + %td= @account.domain %tr - %th= t('admin.accounts.protocol') - %td= @account.protocol.humanize + %th= t('admin.accounts.display_name') + %td= @account.display_name - - if @account.ostatus? + - if @account.local? %tr - %th= t('admin.accounts.feed_url') - %td= link_to @account.remote_url, @account.remote_url + %th= t('admin.accounts.email') + %td= @account.user_email %tr - %th= t('admin.accounts.push_subscription_expires') + %th= t('admin.accounts.most_recent_ip') + %td= @account.user_current_sign_in_ip + %tr + %th= t('admin.accounts.most_recent_activity') %td - - if @account.subscribed? - %time.formatted{ datetime: @account.subscription_expires_at.iso8601, title: l(@account.subscription_expires_at) } - = l @account.subscription_expires_at + - if @account.user_current_sign_in_at + %time.formatted{ datetime: @account.user_current_sign_in_at.iso8601, title: l(@account.user_current_sign_in_at) } + = l @account.user_current_sign_in_at - else - = t('admin.accounts.not_subscribed') - %tr - %th= t('admin.accounts.salmon_url') - %td= link_to @account.salmon_url, @account.salmon_url - - elsif @account.activitypub? + Never + - else %tr - %th= t('admin.accounts.inbox_url') - %td= link_to @account.inbox_url, @account.inbox_url + %th= t('admin.accounts.profile_url') + %td= link_to @account.url, @account.url %tr - %th= t('admin.accounts.outbox_url') - %td= link_to @account.outbox_url, @account.outbox_url + %th= t('admin.accounts.protocol') + %td= @account.protocol.humanize - %tr - %th= t('admin.accounts.follows') - %td= @account.following_count - %tr - %th= t('admin.accounts.followers') - %td= @account.followers_count - %tr - %th= t('admin.accounts.statuses') - %td= link_to @account.statuses_count, admin_account_statuses_path(@account.id) - %tr - %th= t('admin.accounts.media_attachments') - %td - = link_to @account.media_attachments.count, admin_account_statuses_path(@account.id, { media: true }) - = surround '(', ')' do - = number_to_human_size @account.media_attachments.sum('file_file_size') - %tr - %th= t('.created_reports') - %td= link_to pluralize(@account.reports.count, t('.report')), admin_reports_path(account_id: @account.id) - %tr - %th= t('.targeted_reports') - %td= link_to pluralize(@account.targeted_reports.count, t('.report')), admin_reports_path(target_account_id: @account.id) + - if @account.ostatus? + %tr + %th= t('admin.accounts.feed_url') + %td= link_to @account.remote_url, @account.remote_url + %tr + %th= t('admin.accounts.push_subscription_expires') + %td + - if @account.subscribed? + %time.formatted{ datetime: @account.subscription_expires_at.iso8601, title: l(@account.subscription_expires_at) } + = l @account.subscription_expires_at + - else + = t('admin.accounts.not_subscribed') + %tr + %th= t('admin.accounts.salmon_url') + %td= link_to @account.salmon_url, @account.salmon_url + - elsif @account.activitypub? + %tr + %th= t('admin.accounts.inbox_url') + %td= link_to @account.inbox_url, @account.inbox_url + %tr + %th= t('admin.accounts.outbox_url') + %td= link_to @account.outbox_url, @account.outbox_url + %tr + %th= t('admin.accounts.follows') + %td= @account.following_count + %tr + %th= t('admin.accounts.followers') + %td= @account.followers_count + %tr + %th= t('admin.accounts.statuses') + %td= link_to @account.statuses_count, admin_account_statuses_path(@account.id) + %tr + %th= t('admin.accounts.media_attachments') + %td + = link_to @account.media_attachments.count, admin_account_statuses_path(@account.id, { media: true }) + = surround '(', ')' do + = number_to_human_size @account.media_attachments.sum('file_file_size') + %tr + %th= t('.created_reports') + %td= link_to pluralize(@account.reports.count, t('.report')), admin_reports_path(account_id: @account.id) + %tr + %th= t('.targeted_reports') + %td= link_to pluralize(@account.targeted_reports.count, t('.report')), admin_reports_path(target_account_id: @account.id) %div{ style: 'float: right' } - if @account.local? diff --git a/app/views/admin/domain_blocks/index.html.haml b/app/views/admin/domain_blocks/index.html.haml index 5ae9fec530..42b8ca53f4 100644 --- a/app/views/admin/domain_blocks/index.html.haml +++ b/app/views/admin/domain_blocks/index.html.haml @@ -1,15 +1,16 @@ - content_for :page_title do = t('admin.domain_blocks.title') -%table.table - %thead - %tr - %th= t('admin.domain_blocks.domain') - %th= t('admin.domain_blocks.severity') - %th= t('admin.domain_blocks.reject_media') - %th - %tbody - = render @domain_blocks +.table-wrapper + %table.table + %thead + %tr + %th= t('admin.domain_blocks.domain') + %th= t('admin.domain_blocks.severity') + %th= t('admin.domain_blocks.reject_media') + %th + %tbody + = render @domain_blocks = paginate @domain_blocks = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path, class: 'button' diff --git a/app/views/admin/instances/index.html.haml b/app/views/admin/instances/index.html.haml index be21d6bf7b..edbd3b2173 100644 --- a/app/views/admin/instances/index.html.haml +++ b/app/views/admin/instances/index.html.haml @@ -1,12 +1,13 @@ - content_for :page_title do = t('admin.instances.title') -%table.table - %thead - %tr - %th= t('admin.instances.domain_name') - %th= t('admin.instances.account_count') - %tbody - = render @instances +.table-wrapper + %table.table + %thead + %tr + %th= t('admin.instances.domain_name') + %th= t('admin.instances.account_count') + %tbody + = render @instances = paginate paginated_instances diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index f1c4a93c47..577c68a864 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -10,17 +10,18 @@ = form_tag do - %table.table - %thead - %tr - -# %th - %th= t('admin.reports.id') - %th= t('admin.reports.target') - %th= t('admin.reports.reported_by') - %th= t('admin.reports.comment.label') - %th= t('admin.reports.report_contents') - %th - %tbody - = render @reports + .table-wrapper + %table.table + %thead + %tr + -# %th + %th= t('admin.reports.id') + %th= t('admin.reports.target') + %th= t('admin.reports.reported_by') + %th= t('admin.reports.comment.label') + %th= t('admin.reports.report_contents') + %th + %tbody + = render @reports = paginate @reports diff --git a/app/views/admin/subscriptions/index.html.haml b/app/views/admin/subscriptions/index.html.haml index 21b3238a6b..83704c8ee5 100644 --- a/app/views/admin/subscriptions/index.html.haml +++ b/app/views/admin/subscriptions/index.html.haml @@ -1,15 +1,16 @@ - content_for :page_title do = t('admin.subscriptions.title') -%table.table - %thead - %tr - %th= t('admin.subscriptions.topic') - %th= t('admin.subscriptions.callback_url') - %th= t('admin.subscriptions.confirmed') - %th= t('admin.subscriptions.expires_in') - %th= t('admin.subscriptions.last_delivery') - %tbody - = render @subscriptions +.table-wrapper + %table.table + %thead + %tr + %th= t('admin.subscriptions.topic') + %th= t('admin.subscriptions.callback_url') + %th= t('admin.subscriptions.confirmed') + %th= t('admin.subscriptions.expires_in') + %th= t('admin.subscriptions.last_delivery') + %tbody + = render @subscriptions = paginate @subscriptions diff --git a/app/views/auth/registrations/_sessions.html.haml b/app/views/auth/registrations/_sessions.html.haml index 7ac578bb17..c1e9764b3c 100644 --- a/app/views/auth/registrations/_sessions.html.haml +++ b/app/views/auth/registrations/_sessions.html.haml @@ -1,28 +1,29 @@ %h6= t 'sessions.title' %p.muted-hint= t 'sessions.explanation' -%table.table.inline-table - %thead - %tr - %th= t 'sessions.browser' - %th= t 'sessions.ip' - %th= t 'sessions.activity' - %td - %tbody - - @sessions.each do |session| +.table-wrapper + %table.table.inline-table + %thead %tr + %th= t 'sessions.browser' + %th= t 'sessions.ip' + %th= t 'sessions.activity' %td - %span{ title: session.user_agent }< - = fa_icon "#{session_device_icon(session)} fw", 'aria-label' => session_device_icon(session) - = ' ' - = t 'sessions.description', browser: t("sessions.browsers.#{session.browser}"), platform: t("sessions.platforms.#{session.platform}") - %td - %samp= session.ip - %td - - if current_session.session_id == session.session_id - = t 'sessions.current_session' - - else - %time.time-ago{ datetime: session.updated_at.iso8601, title: l(session.updated_at) }= l(session.updated_at) - %td - - if current_session.session_id != session.session_id - = table_link_to 'times', t('sessions.revoke'), settings_session_path(session), method: :delete + %tbody + - @sessions.each do |session| + %tr + %td + %span{ title: session.user_agent }< + = fa_icon "#{session_device_icon(session)} fw", 'aria-label' => session_device_icon(session) + = ' ' + = t 'sessions.description', browser: t("sessions.browsers.#{session.browser}"), platform: t("sessions.platforms.#{session.platform}") + %td + %samp= session.ip + %td + - if current_session.session_id == session.session_id + = t 'sessions.current_session' + - else + %time.time-ago{ datetime: session.updated_at.iso8601, title: l(session.updated_at) }= l(session.updated_at) + %td + - if current_session.session_id != session.session_id + = table_link_to 'times', t('sessions.revoke'), settings_session_path(session), method: :delete diff --git a/app/views/oauth/authorized_applications/index.html.haml b/app/views/oauth/authorized_applications/index.html.haml index ba0c084950..19af5f55db 100644 --- a/app/views/oauth/authorized_applications/index.html.haml +++ b/app/views/oauth/authorized_applications/index.html.haml @@ -1,23 +1,24 @@ - content_for :page_title do = t('doorkeeper.authorized_applications.index.title') -%table.table - %thead - %tr - %th= t('doorkeeper.authorized_applications.index.application') - %th= t('doorkeeper.authorized_applications.index.scopes') - %th= t('doorkeeper.authorized_applications.index.created_at') - %th - %tbody - - @applications.each do |application| +.table-wrapper + %table.table + %thead %tr - %td - - if application.website.blank? - = application.name - - else - = link_to application.name, application.website, target: '_blank', rel: 'noopener' - %th!= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('
') - %td= l application.created_at - %td - - unless application.superapp? - = table_link_to 'times', t('doorkeeper.authorized_applications.buttons.revoke'), oauth_authorized_application_path(application), method: :delete, data: { confirm: t('doorkeeper.authorized_applications.confirmations.revoke') } + %th= t('doorkeeper.authorized_applications.index.application') + %th= t('doorkeeper.authorized_applications.index.scopes') + %th= t('doorkeeper.authorized_applications.index.created_at') + %th + %tbody + - @applications.each do |application| + %tr + %td + - if application.website.blank? + = application.name + - else + = link_to application.name, application.website, target: '_blank', rel: 'noopener' + %th!= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('
') + %td= l application.created_at + %td + - unless application.superapp? + = table_link_to 'times', t('doorkeeper.authorized_applications.buttons.revoke'), oauth_authorized_application_path(application), method: :delete, data: { confirm: t('doorkeeper.authorized_applications.confirmations.revoke') } diff --git a/app/views/settings/applications/index.html.haml b/app/views/settings/applications/index.html.haml index eea550388a..919472c2e8 100644 --- a/app/views/settings/applications/index.html.haml +++ b/app/views/settings/applications/index.html.haml @@ -1,19 +1,20 @@ - content_for :page_title do = t('doorkeeper.applications.index.title') -%table.table - %thead - %tr - %th= t('doorkeeper.applications.index.application') - %th= t('doorkeeper.applications.index.scopes') - %th - %tbody - - @applications.each do |application| +.table-wrapper + %table.table + %thead %tr - %td= link_to application.name, settings_application_path(application) - %th= application.scopes - %td - = table_link_to 'times', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') } + %th= t('doorkeeper.applications.index.application') + %th= t('doorkeeper.applications.index.scopes') + %th + %tbody + - @applications.each do |application| + %tr + %td= link_to application.name, settings_application_path(application) + %th= application.scopes + %td + = table_link_to 'times', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') } = paginate @applications = link_to t('doorkeeper.applications.index.new'), new_settings_application_path, class: 'button' diff --git a/app/views/settings/applications/show.html.haml b/app/views/settings/applications/show.html.haml index 4d85551111..12baed0881 100644 --- a/app/views/settings/applications/show.html.haml +++ b/app/views/settings/applications/show.html.haml @@ -3,22 +3,23 @@ %p.hint= t('applications.warning') -%table.table - %tbody - %tr - %th= t('doorkeeper.applications.show.application_id') - %td - %code= @application.uid - %tr - %th= t('doorkeeper.applications.show.secret') - %td - %code= @application.secret - %tr - %th{ rowspan: 2}= t('applications.your_token') - %td - %code= current_user.token_for_app(@application).token - %tr - %td= table_link_to 'refresh', t('applications.regenerate_token'), regenerate_settings_application_path(@application), method: :post +.table-wrapper + %table.table + %tbody + %tr + %th= t('doorkeeper.applications.show.application_id') + %td + %code= @application.uid + %tr + %th= t('doorkeeper.applications.show.secret') + %td + %code= @application.secret + %tr + %th{ rowspan: 2}= t('applications.your_token') + %td + %code= current_user.token_for_app(@application).token + %tr + %td= table_link_to 'refresh', t('applications.regenerate_token'), regenerate_settings_application_path(@application), method: :post %hr/ diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml index f2f6f95563..e0df1c4802 100644 --- a/app/views/settings/exports/show.html.haml +++ b/app/views/settings/exports/show.html.haml @@ -1,21 +1,22 @@ - content_for :page_title do = t('settings.export') -%table.table - %tbody - %tr - %th= t('exports.storage') - %td= number_to_human_size @export.total_storage - %td - %tr - %th= t('exports.follows') - %td= @export.total_follows - %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv) - %tr - %th= t('exports.blocks') - %td= @export.total_blocks - %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv) - %tr - %th= t('exports.mutes') - %td= @export.total_mutes - %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) +.table-wrapper + %table.table + %tbody + %tr + %th= t('exports.storage') + %td= number_to_human_size @export.total_storage + %td + %tr + %th= t('exports.follows') + %td= @export.total_follows + %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv) + %tr + %th= t('exports.blocks') + %td= @export.total_blocks + %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv) + %tr + %th= t('exports.mutes') + %td= @export.total_mutes + %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) diff --git a/app/views/settings/follower_domains/show.html.haml b/app/views/settings/follower_domains/show.html.haml index dad2770f10..f1687d4d2f 100644 --- a/app/views/settings/follower_domains/show.html.haml +++ b/app/views/settings/follower_domains/show.html.haml @@ -12,20 +12,21 @@ %p= t('followers.explanation_html') %p= t('followers.true_privacy_html') - %table.table - %thead - %tr - %th - %th= t('followers.domain') - %th= t('followers.followers_count') - %tbody - - @domains.each do |domain| + .table-wrapper + %table.table + %thead %tr - %td - = check_box_tag 'select[]', domain.domain, false, disabled: !@account.locked? unless domain.domain.nil? - %td - %samp= domain.domain.presence || Rails.configuration.x.local_domain - %td= number_with_delimiter domain.accounts_from_domain + %th + %th= t('followers.domain') + %th= t('followers.followers_count') + %tbody + - @domains.each do |domain| + %tr + %td + = check_box_tag 'select[]', domain.domain, false, disabled: !@account.locked? unless domain.domain.nil? + %td + %samp= domain.domain.presence || Rails.configuration.x.local_domain + %td= number_with_delimiter domain.accounts_from_domain .action-pagination .actions From dfd9eed84c538664a7c8929ca833e68a91f16dcc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 13:41:45 +0200 Subject: [PATCH 21/27] Add missing reject_media check before avatar download via ActivityPub (#4862) --- app/services/activitypub/process_account_service.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index c63577fe5d..b54e447ad0 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -48,14 +48,14 @@ class ActivityPub::ProcessAccountService < BaseService @account.url = url || @uri @account.display_name = @json['name'] || '' @account.note = @json['summary'] || '' - @account.avatar_remote_url = image_url('icon') - @account.header_remote_url = image_url('image') + @account.avatar_remote_url = image_url('icon') unless skip_download? + @account.header_remote_url = image_url('image') unless skip_download? @account.public_key = public_key || '' @account.locked = @json['manuallyApprovesFollowers'] || false @account.statuses_count = outbox_total_items if outbox_total_items.present? @account.following_count = following_total_items if following_total_items.present? @account.followers_count = followers_total_items if followers_total_items.present? - @account.save! + @account.save_with_optional_media! end def upgrade_account @@ -115,6 +115,10 @@ class ActivityPub::ProcessAccountService < BaseService @collections[type] = nil end + def skip_download? + @account.suspended? || domain_block&.reject_media? + end + def auto_suspend? domain_block && domain_block.suspend? end From f551b2ca7aa49e0a9750a776febc82f45f62730d Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Sat, 9 Sep 2017 20:42:48 +0900 Subject: [PATCH 22/27] Fix second report (regression from 2cc31b3194eafdf915e497dc3b56cadb926eeb54) (#4863) --- app/javascript/mastodon/reducers/reports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/reducers/reports.js b/app/javascript/mastodon/reducers/reports.js index 283c5b6f5e..a08bbec387 100644 --- a/app/javascript/mastodon/reducers/reports.js +++ b/app/javascript/mastodon/reducers/reports.js @@ -28,7 +28,7 @@ export default function reports(state = initialState, action) { if (state.getIn(['new', 'account_id']) !== action.account.get('id')) { map.setIn(['new', 'status_ids'], action.status ? ImmutableSet([action.status.getIn(['reblog', 'id'], action.status.get('id'))]) : ImmutableSet()); map.setIn(['new', 'comment'], ''); - } else { + } else if (action.status) { map.updateIn(['new', 'status_ids'], ImmutableSet(), set => set.add(action.status.getIn(['reblog', 'id'], action.status.get('id')))); } }); From 64eb868c4a4e77f3bc724e4f9676b9055b8777b3 Mon Sep 17 00:00:00 2001 From: unarist Date: Sat, 9 Sep 2017 21:16:11 +0900 Subject: [PATCH 23/27] Fix scroll behavior and others on paused timeline (#4864) Resolved: * Lot of redundant renders while mouse moving * Scroll jumping when timeline loaded * Scroll position isn't kept when statuses below the scrollTop was deleted then new status arrived Unresolved: * Scroll position isn't kept when statuses over the scrollTop was deleted then new status arrived -> It needs to know which statuses are over the scrollTop * New status indicator should be active when new statuses arrived while mouse moved recently -> It needs a) update indicator in ScrollableList, or b) set scrollTop status while mouse moving --- .../mastodon/components/scrollable_list.js | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index 42763ddd3d..aeb0b0f4b5 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -52,11 +52,11 @@ export default class ScrollableList extends PureComponent { }); handleMouseMove = throttle(() => { - this.setState({ lastMouseMove: new Date() }); + this._lastMouseMove = new Date(); }, 300); handleMouseLeave = () => { - this.setState({ lastMouseMove: null }); + this._lastMouseMove = null; } componentDidMount () { @@ -68,18 +68,20 @@ export default class ScrollableList extends PureComponent { } componentDidUpdate (prevProps) { + const someItemInserted = React.Children.count(prevProps.children) > 0 && + React.Children.count(prevProps.children) < React.Children.count(this.props.children) && + this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); + // Reset the scroll position when a new child comes in in order not to // jerk the scrollbar around if you're already scrolled down the page. - if (React.Children.count(prevProps.children) < React.Children.count(this.props.children) && this._oldScrollPosition && (this.node.scrollTop > 0 || this._recentlyMoved())) { - if (this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props)) { - const newScrollTop = this.node.scrollHeight - this._oldScrollPosition; + if (someItemInserted && this._oldScrollPosition && (this.node.scrollTop > 0 || this._recentlyMoved())) { + const newScrollTop = this.node.scrollHeight - this._oldScrollPosition; - if (this.node.scrollTop !== newScrollTop) { - this.node.scrollTop = newScrollTop; - } - } else { - this._oldScrollPosition = this.node.scrollHeight - this.node.scrollTop; + if (this.node.scrollTop !== newScrollTop) { + this.node.scrollTop = newScrollTop; } + } else { + this._oldScrollPosition = this.node.scrollHeight - this.node.scrollTop; } } @@ -128,7 +130,7 @@ export default class ScrollableList extends PureComponent { } _recentlyMoved () { - return this.state.lastMouseMove === null || ((new Date()) - this.state.lastMouseMove < 600); + return this._lastMouseMove !== null && ((new Date()) - this._lastMouseMove < 600); } handleKeyDown = (e) => { From fafd9d8bae2cf9241722f2c7bd839854fe9ced0f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 14:53:49 +0200 Subject: [PATCH 24/27] Bump version to 1.6.0rc4 --- lib/mastodon/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index de2516d6c2..3ab705e260 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -21,7 +21,7 @@ module Mastodon end def flags - 'rc2' + 'rc4' end def to_a From d8bbe7cf7c06684b628f27a56c4738414ff7fe0f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 15:09:50 +0200 Subject: [PATCH 25/27] Disable mouse-based pause from #4859 (#4865) It wasn't working ideally and introduced some annoying false positivies --- app/javascript/mastodon/components/scrollable_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index aeb0b0f4b5..723dd322b0 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -74,7 +74,7 @@ export default class ScrollableList extends PureComponent { // Reset the scroll position when a new child comes in in order not to // jerk the scrollbar around if you're already scrolled down the page. - if (someItemInserted && this._oldScrollPosition && (this.node.scrollTop > 0 || this._recentlyMoved())) { + if (someItemInserted && this._oldScrollPosition && this.node.scrollTop > 0) { const newScrollTop = this.node.scrollHeight - this._oldScrollPosition; if (this.node.scrollTop !== newScrollTop) { From 2303725f7dcdaa1dd58052c84827a1d1029bb187 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 9 Sep 2017 16:23:44 +0200 Subject: [PATCH 26/27] Add script to make embedded iframes autosize (#4853) --- .../features/ui/components/embed_modal.js | 4 +- app/javascript/packs/public.js | 34 ++++++++++++--- app/javascript/styles/basics.scss | 1 + app/serializers/oembed_serializer.rb | 4 +- public/embed.js | 43 +++++++++++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 public/embed.js diff --git a/app/javascript/mastodon/features/ui/components/embed_modal.js b/app/javascript/mastodon/features/ui/components/embed_modal.js index 992aed8a3f..1afffb51bc 100644 --- a/app/javascript/mastodon/features/ui/components/embed_modal.js +++ b/app/javascript/mastodon/features/ui/components/embed_modal.js @@ -33,7 +33,8 @@ export default class EmbedModal extends ImmutablePureComponent { iframeDocument.close(); iframeDocument.body.style.margin = 0; - this.iframe.height = iframeDocument.body.scrollHeight + 'px'; + this.iframe.width = iframeDocument.body.scrollWidth; + this.iframe.height = iframeDocument.body.scrollHeight; }); } @@ -71,7 +72,6 @@ export default class EmbedModal extends ImmutablePureComponent {