From 8236f942ff3cfb3bdcbdd4c285a1986c92087b9f Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Mon, 29 May 2017 08:49:54 -0700 Subject: [PATCH 001/295] Use travis_retry to reduce spurious test failures (#3418) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 660a7ebf75..2b8c15ff17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,6 +50,6 @@ before_script: - ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++" script: - - bundle exec parallel_test spec/ --group-by filesize --type rspec + - travis_retry bundle exec parallel_test spec/ --group-by filesize --type rspec - npm test - bundle exec i18n-tasks unused -- GitLab From 184325077e25a153e45c44483fcc9e68dd9435fc Mon Sep 17 00:00:00 2001 From: lindwurm Date: Tue, 30 May 2017 00:52:02 +0900 Subject: [PATCH 002/295] l10n: Fix Japanese translation (#3410) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * "メデイア" -> "メディア" Signed-off-by: lindwurm --- app/javascript/mastodon/locales/ja.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 58c33565f8..bb00eefd18 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -146,7 +146,7 @@ "status.delete": "削除", "status.favourite": "お気に入り", "status.load_more": "もっと見る", - "status.media_hidden": "非表示のメデイア", + "status.media_hidden": "非表示のメディア", "status.mention": "返信", "status.mute_conversation": "会話をミュート", "status.open": "詳細を表示", -- GitLab From 4bd327a0c56e87e9b33967089f3ee3601353a939 Mon Sep 17 00:00:00 2001 From: masarakki Date: Tue, 30 May 2017 00:52:26 +0900 Subject: [PATCH 003/295] fix-rails-minor-version (#3403) --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 225e7cf486..9b089f1076 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ ruby '>= 2.3.0', '< 2.5.0' gem 'pkg-config', '~> 1.2' gem 'puma', '~> 3.8' -gem 'rails', '~> 5.0' +gem 'rails', '~> 5.0.0' gem 'uglifier', '~> 3.2' gem 'hamlit-rails', '~> 0.2' -- GitLab From b5e89948441eb245a873260a87bfb49fb334aee1 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Mon, 29 May 2017 08:52:45 -0700 Subject: [PATCH 004/295] Prevent wasted render in load_more.js (#3402) --- .../mastodon/components/load_more.js | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/components/load_more.js b/app/javascript/mastodon/components/load_more.js index 22d9e91c35..fa0caaae99 100644 --- a/app/javascript/mastodon/components/load_more.js +++ b/app/javascript/mastodon/components/load_more.js @@ -2,14 +2,20 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; -const LoadMore = ({ onClick }) => ( - -); - -LoadMore.propTypes = { - onClick: PropTypes.func, -}; +class LoadMore extends React.PureComponent { + + static propTypes = { + onClick: PropTypes.func, + } + + render() { + return ( + + ); + } + +} export default LoadMore; -- GitLab From 402c19a92475014e04df91eca759225f8a89d2ac Mon Sep 17 00:00:00 2001 From: Atsushi Yamamoto Date: Mon, 29 May 2017 11:56:13 -0400 Subject: [PATCH 005/295] Add preference setting for delete toot modal (#3368) * Set delete_modal preference to true by default * Does not show confirmation modal if delete_modal is false * Add ja translation for preference setting page --- .../settings/preferences_controller.rb | 1 + .../mastodon/containers/status_container.js | 15 ++++++++++----- app/javascript/mastodon/features/status/index.js | 16 +++++++++++----- app/lib/user_settings_decorator.rb | 5 +++++ app/models/user.rb | 4 ++++ app/views/home/initial_state.json.rabl | 1 + app/views/settings/preferences/show.html.haml | 1 + config/locales/simple_form.en.yml | 1 + config/locales/simple_form.ja.yml | 1 + config/settings.yml | 1 + .../settings/preferences_controller_spec.rb | 3 +++ spec/lib/user_settings_decorator_spec.rb | 7 +++++++ 12 files changed, 46 insertions(+), 10 deletions(-) diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index 3dc3013c35..71f5a7c04b 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -35,6 +35,7 @@ class Settings::PreferencesController < ApplicationController params.require(:user).permit( :setting_default_privacy, :setting_boost_modal, + :setting_delete_modal, :setting_auto_play_gif, notification_emails: %i(follow follow_request reblog favourite mention digest), interactions: %i(must_be_follower must_be_following) diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js index 141f287aff..2592e9a69c 100644 --- a/app/javascript/mastodon/containers/status_container.js +++ b/app/javascript/mastodon/containers/status_container.js @@ -37,6 +37,7 @@ const makeMapStateToProps = () => { status: getStatus(state, props.id), me: state.getIn(['meta', 'me']), boostModal: state.getIn(['meta', 'boost_modal']), + deleteModal: state.getIn(['meta', 'delete_modal']), autoPlayGif: state.getIn(['meta', 'auto_play_gif']), }); @@ -74,11 +75,15 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onDelete (status) { - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.deleteMessage), - confirm: intl.formatMessage(messages.deleteConfirm), - onConfirm: () => dispatch(deleteStatus(status.get('id'))), - })); + if (!this.deleteModal) { + dispatch(deleteStatus(status.get('id'))); + } else { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => dispatch(deleteStatus(status.get('id'))), + })); + } }, onMention (account, router) { diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 24cf3d1089..7fc55b795c 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -48,6 +48,7 @@ const makeMapStateToProps = () => { descendantsIds: state.getIn(['timelines', 'descendants', Number(props.params.statusId)]), me: state.getIn(['meta', 'me']), boostModal: state.getIn(['meta', 'boost_modal']), + deleteModal: state.getIn(['meta', 'delete_modal']), autoPlayGif: state.getIn(['meta', 'auto_play_gif']), }); @@ -68,6 +69,7 @@ class Status extends ImmutablePureComponent { descendantsIds: ImmutablePropTypes.list, me: PropTypes.number, boostModal: PropTypes.bool, + deleteModal: PropTypes.bool, autoPlayGif: PropTypes.bool, intl: PropTypes.object.isRequired, }; @@ -113,11 +115,15 @@ class Status extends ImmutablePureComponent { handleDeleteClick = (status) => { const { dispatch, intl } = this.props; - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.deleteMessage), - confirm: intl.formatMessage(messages.deleteConfirm), - onConfirm: () => dispatch(deleteStatus(status.get('id'))), - })); + if (!this.props.deleteModal) { + dispatch(deleteStatus(status.get('id'))); + } else { + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => dispatch(deleteStatus(status.get('id'))), + })); + } } handleMentionClick = (account, router) => { diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb index 6104773add..af264bbd53 100644 --- a/app/lib/user_settings_decorator.rb +++ b/app/lib/user_settings_decorator.rb @@ -19,6 +19,7 @@ class UserSettingsDecorator user.settings['interactions'] = merged_interactions user.settings['default_privacy'] = default_privacy_preference user.settings['boost_modal'] = boost_modal_preference + user.settings['delete_modal'] = delete_modal_preference user.settings['auto_play_gif'] = auto_play_gif_preference end @@ -38,6 +39,10 @@ class UserSettingsDecorator boolean_cast_setting 'setting_boost_modal' end + def delete_modal_preference + boolean_cast_setting 'setting_delete_modal' + end + def auto_play_gif_preference boolean_cast_setting 'setting_auto_play_gif' end diff --git a/app/models/user.rb b/app/models/user.rb index 9f2a49b6a8..f367d74aa6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -80,6 +80,10 @@ class User < ApplicationRecord settings.boost_modal end + def setting_delete_modal + settings.delete_modal + end + def setting_auto_play_gif settings.auto_play_gif end diff --git a/app/views/home/initial_state.json.rabl b/app/views/home/initial_state.json.rabl index ac0bee2e27..e305f8e7ae 100644 --- a/app/views/home/initial_state.json.rabl +++ b/app/views/home/initial_state.json.rabl @@ -9,6 +9,7 @@ node(:meta) do me: current_account.id, admin: @admin.try(:id), boost_modal: current_account.user.setting_boost_modal, + delete_modal: current_account.user.setting_delete_modal, auto_play_gif: current_account.user.setting_auto_play_gif, } end diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml index 3771698d19..721ce6a219 100644 --- a/app/views/settings/preferences/show.html.haml +++ b/app/views/settings/preferences/show.html.haml @@ -40,6 +40,7 @@ .fields-group = f.input :setting_boost_modal, as: :boolean, wrapper: :with_label + = f.input :setting_delete_modal, as: :boolean, wrapper: :with_label .fields-group = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 6a888e3fe8..5d1ede9680 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -36,6 +36,7 @@ en: password: Password setting_auto_play_gif: Auto-play animated GIFs setting_boost_modal: Show confirmation dialog before boosting + setting_delete_modal: Show confirmation dialog before deleting a toot setting_default_privacy: Post privacy severity: Severity type: Import type diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index fcf0923e01..343139b64b 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -33,6 +33,7 @@ ja: password: パスワード setting_auto_play_gif: アニメーションGIFを自動再生する setting_boost_modal: ブーストする前に確認ダイアログを表示する + setting_delete_modal: トゥートを削除する前に確認ダイアログを表示する setting_default_privacy: 投稿の公開範囲 severity: 重大性 type: インポートする項目 diff --git a/config/settings.yml b/config/settings.yml index 9813963b28..4811213cbd 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -16,6 +16,7 @@ defaults: &defaults closed_registrations_message: '' boost_modal: false auto_play_gif: true + delete_modal: true notification_emails: follow: false reblog: false diff --git a/spec/controllers/settings/preferences_controller_spec.rb b/spec/controllers/settings/preferences_controller_spec.rb index 38e43f211b..60fa423023 100644 --- a/spec/controllers/settings/preferences_controller_spec.rb +++ b/spec/controllers/settings/preferences_controller_spec.rb @@ -28,12 +28,14 @@ describe Settings::PreferencesController do it 'updates user settings' do user.settings['boost_modal'] = false + user.settings['delete_modal'] = true user.settings['notification_emails'] = user.settings['notification_emails'].merge('follow' => false) user.settings['interactions'] = user.settings['interactions'].merge('must_be_follower' => true) put :update, params: { user: { setting_boost_modal: '1', + setting_delete_modal: '0', notification_emails: { follow: '1' }, interactions: { must_be_follower: '0' }, } @@ -42,6 +44,7 @@ describe Settings::PreferencesController do expect(response).to redirect_to(settings_preferences_path) user.reload expect(user.settings['boost_modal']).to be true + expect(user.settings['delete_modal']).to be false expect(user.settings['notification_emails']['follow']).to be true expect(user.settings['interactions']['must_be_follower']).to be false end diff --git a/spec/lib/user_settings_decorator_spec.rb b/spec/lib/user_settings_decorator_spec.rb index 466c57fa51..66e42fa0ec 100644 --- a/spec/lib/user_settings_decorator_spec.rb +++ b/spec/lib/user_settings_decorator_spec.rb @@ -35,6 +35,13 @@ describe UserSettingsDecorator do expect(user.settings['boost_modal']).to eq true end + it 'updates the user settings value for delete toot modal' do + values = { 'setting_delete_modal' => '0' } + + settings.update(values) + expect(user.settings['delete_modal']).to eq false + end + it 'updates the user settings value for gif auto play' do values = { 'setting_auto_play_gif' => '0' } -- GitLab From 9ead3d1cdbac2cc40d8926be116cbe15cbf7f24d Mon Sep 17 00:00:00 2001 From: Daniel Hunsaker Date: Mon, 29 May 2017 09:59:18 -0600 Subject: [PATCH 006/295] [nanobox] Adjustments for Nanobox development (#3295) Because Nanobox doesn't run data components in the same container as the code, there are a few tweaks that need to be made in the configuration to get WebPack to work properly in development mode. The same differences lead to needing to use `DATABASE_URL` by default in the `.env` file for Rails to work correctly. Limitations of our `.env` loader for Node.js mean the `.env` file needs to be compiled everywhere in order to work, so we compile it in development, now, too. Also, all the `.env.production` tweaks have been consolidated into a single command. Finally, since Nanobox actually creates the database when it sets up the database server, using the existence of the database alone to determine whether to migrate or setup is insufficient. So we add a condition to `rake db:migrate:setup` to check whether any migrations have run - if the database doesn't exist yet, `db:setup` will be called; if it does, but no migrations have been run, `db:migrate` and `db:seed` are called instead (the same basic idea as what `db:setup` does, but it skips `db:create`, which will only cause problems with an existing DB); otherwise, only `db:migrate` is called. None of these changes should affect development, and all are designed not to interfere with existing behaviors in other environments. --- .env.nanobox | 2 ++ boxfile.yml | 5 ++--- config/webpack/configuration.js | 2 +- config/webpack/development.server.js | 3 ++- lib/tasks/db.rake | 5 ++++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.env.nanobox b/.env.nanobox index 4a89e0e41f..73abefdc65 100644 --- a/.env.nanobox +++ b/.env.nanobox @@ -11,6 +11,8 @@ DB_NAME=gonano DB_PASS=$DATA_DB_PASS DB_PORT=5432 +DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano + # Federation # Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects. # LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com. diff --git a/boxfile.yml b/boxfile.yml index 65f5f6c8cd..2fa3fb9ffa 100644 --- a/boxfile.yml +++ b/boxfile.yml @@ -31,7 +31,7 @@ run.config: - yarn.lock extra_steps: - - cp .env.nanobox .env + - envsubst < .env.nanobox > .env - gem install bundler - bundle config build.nokogiri --with-iconv-dir=/data/ --with-zlib-dir=/data/ - bundle config build.nokogumbo --with-iconv-dir=/data/ --with-zlib-dir=/data/ @@ -43,9 +43,8 @@ run.config: deploy.config: extra_steps: - NODE_ENV=production bundle exec rake assets:precompile - - "[ -r /app/.env.production ] || sed 's/LOCAL_HTTPS=.*/LOCAL_HTTPS=true/i' /app/.env.nanobox > /app/.env.production" transform: - - envsubst < /app/.env.production > /tmp/.env.production && mv /tmp/.env.production /app/.env.production + - "sed 's/LOCAL_HTTPS=.*/LOCAL_HTTPS=true/i' /app/.env.nanobox | envsubst > /app/.env.production" - |- if [ -z "$LOCAL_DOMAIN" ] then diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js index 922e8c517e..2a54080cf9 100644 --- a/config/webpack/configuration.js +++ b/config/webpack/configuration.js @@ -12,7 +12,7 @@ const devServer = safeLoad(readFileSync(join(configPath, 'development.server.yml // Compute public path based on environment and CDN_HOST in production const ifHasCDN = env.CDN_HOST !== undefined && env.NODE_ENV === 'production'; -const devServerUrl = `http://${devServer.host}:${devServer.port}/${paths.entry}/`; +const devServerUrl = `http://${env.LOCAL_DOMAIN || devServer.host}:${devServer.port}/${paths.entry}/`; const publicUrl = ifHasCDN ? `${env.CDN_HOST}/${paths.entry}/` : `/${paths.entry}/`; const publicPath = env.NODE_ENV !== 'production' ? devServerUrl : publicUrl; diff --git a/config/webpack/development.server.js b/config/webpack/development.server.js index 296df15046..4e11df4cb3 100644 --- a/config/webpack/development.server.js +++ b/config/webpack/development.server.js @@ -1,13 +1,14 @@ // Note: You must restart bin/webpack-dev-server for changes to take effect const { resolve } = require('path'); +const { env } = require('process'); const merge = require('webpack-merge'); const devConfig = require('./development.js'); const { devServer, publicPath, paths } = require('./configuration.js'); module.exports = merge(devConfig, { devServer: { - host: devServer.host, + host: env.LOCAL_DOMAIN ? '0.0.0.0' : devServer.host, port: devServer.port, headers: { "Access-Control-Allow-Origin": "*" }, compress: true, diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index a1211f0973..7a055bf256 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -5,7 +5,10 @@ namespace :db do desc 'Setup the db or migrate depending on state of db' task setup: :environment do begin - ActiveRecord::Base.connection + if ActiveRecord::Migrator.current_version.zero? + Rake::Task['db:migrate'].invoke + Rake::Task['db:seed'].invoke + end rescue ActiveRecord::NoDatabaseError Rake::Task['db:setup'].invoke else -- GitLab From 91c789ec630757b1de6e0b84aa6b6dac55c6998b Mon Sep 17 00:00:00 2001 From: unarist Date: Tue, 30 May 2017 01:01:08 +0900 Subject: [PATCH 007/295] Don't stream toots from users who have blocked the recipient user (#3300) * Don't stream toots from users who have blocked the recipient user This filter was already applied on the `/api/v1/timelines/public` API, but not yet for the Streaming API. * Boosted status' account_id doesn't need for filtering in streaming/index.js This filtering is only for public/hashtag timelines, but boosts already filtered on FanOutOnWriteService because those timelines don't show boosts. --- streaming/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/streaming/index.js b/streaming/index.js index 52b5ccced7..fe39cf21df 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -240,7 +240,7 @@ const startWorker = (workerId) => { } const unpackedPayload = JSON.parse(payload); - const targetAccountIds = [unpackedPayload.account.id].concat(unpackedPayload.mentions.map(item => item.id)).concat(unpackedPayload.reblog ? [unpackedPayload.reblog.account.id] : []); + const targetAccountIds = [unpackedPayload.account.id].concat(unpackedPayload.mentions.map(item => item.id)); const accountDomain = unpackedPayload.account.acct.split('@')[1]; if (Array.isArray(req.filteredLanguages) && req.filteredLanguages.includes(unpackedPayload.language)) { @@ -250,7 +250,7 @@ const startWorker = (workerId) => { } const queries = [ - client.query(`SELECT 1 FROM blocks WHERE account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 1)}) UNION SELECT 1 FROM mutes WHERE account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 1)})`, [req.accountId].concat(targetAccountIds)), + client.query(`SELECT 1 FROM blocks WHERE (account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})) OR (account_id = $2 AND target_account_id = $1) UNION SELECT 1 FROM mutes WHERE account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})`, [req.accountId, unpackedPayload.account.id].concat(targetAccountIds)), ]; if (accountDomain) { -- GitLab From 7a281c477abacc4886e34a0e90ea0b1f489ceaf5 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:01:37 +0900 Subject: [PATCH 008/295] Cover Admin::PubSubHubHubController more (#3343) --- .../admin/pubsubhubbub_controller_spec.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/spec/controllers/admin/pubsubhubbub_controller_spec.rb b/spec/controllers/admin/pubsubhubbub_controller_spec.rb index c2bab5daca..c8e8e7a842 100644 --- a/spec/controllers/admin/pubsubhubbub_controller_spec.rb +++ b/spec/controllers/admin/pubsubhubbub_controller_spec.rb @@ -5,12 +5,27 @@ RSpec.describe Admin::PubsubhubbubController, type: :controller do render_views describe 'GET #index' do + around do |example| + default_per_page = Subscription.default_per_page + Subscription.paginates_per 1 + example.run + Subscription.paginates_per default_per_page + end + before do sign_in Fabricate(:user, admin: true), scope: :user end - it 'returns http success' do + it 'renders subscriptions' do + Fabricate(:subscription) + specified = Fabricate(:subscription) + get :index + + subscriptions = assigns(:subscriptions) + expect(subscriptions.count).to eq 1 + expect(subscriptions[0]).to eq specified + expect(response).to have_http_status(:success) end end -- GitLab From c8a226f61c91645b0670630ec95cb60e1d8cdde0 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:02:32 +0900 Subject: [PATCH 009/295] Spec HttpHelper (#3416) --- spec/helpers/http_helper_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 spec/helpers/http_helper_spec.rb diff --git a/spec/helpers/http_helper_spec.rb b/spec/helpers/http_helper_spec.rb new file mode 100644 index 0000000000..b8e31b8e6f --- /dev/null +++ b/spec/helpers/http_helper_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe HttpHelper do + describe 'http_client' do + it 'returns HTTP::Client with default options' do + options = helper.http_client.default_options + expect(options.headers['User-Agent']).to match /.+ \(Mastodon\/.+;\ \+http:\/\/cb6e6126\.ngrok\.io\/\)/ + expect(options.timeout_options).to eq read_timeout: 10, write_timeout: 10, connect_timeout: 10 + end + end +end -- GitLab From d24d3fa28317d6a60f2aec361a4ce212d43b85ba Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:02:44 +0900 Subject: [PATCH 010/295] Spec HomeHelper (#3415) --- spec/helpers/home_helper_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb index 8c96387e68..b085e179ca 100644 --- a/spec/helpers/home_helper_spec.rb +++ b/spec/helpers/home_helper_spec.rb @@ -1,5 +1,9 @@ require 'rails_helper' RSpec.describe HomeHelper, type: :helper do - + describe 'default_props' do + it 'returns default properties according to the context' do + expect(helper.default_props).to eq locale: :en + end + end end -- GitLab From 5aacd9d4c79ee3f13cfdf30b9e16e145131a5957 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:03:02 +0900 Subject: [PATCH 011/295] Spec FlashesHelper (#3414) --- spec/helpers/flashes_helper_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 spec/helpers/flashes_helper_spec.rb diff --git a/spec/helpers/flashes_helper_spec.rb b/spec/helpers/flashes_helper_spec.rb new file mode 100644 index 0000000000..ea143eed72 --- /dev/null +++ b/spec/helpers/flashes_helper_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe FlashesHelper, type: :helper do + describe 'user_facing_flashes' do + it 'returns user facing flashes' do + flash[:alert] = 'an alert' + flash[:error] = 'an error' + flash[:notice] = 'a notice' + flash[:success] = 'a success' + flash[:not_user_facing] = 'a not user facing flash' + expect(helper.user_facing_flashes).to eq 'alert' => 'an alert', + 'error' => 'an error', + 'notice' => 'a notice', + 'success' => 'a success' + end + end +end -- GitLab From 52ae83d00862eebe0a79389b1808c034998a1584 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:03:15 +0900 Subject: [PATCH 012/295] Spec Activitystreams2BuilderHelper (#3413) --- .../activitystreams2_builder_helper_spec.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 spec/helpers/activitystreams2_builder_helper_spec.rb diff --git a/spec/helpers/activitystreams2_builder_helper_spec.rb b/spec/helpers/activitystreams2_builder_helper_spec.rb new file mode 100644 index 0000000000..612ce6ad29 --- /dev/null +++ b/spec/helpers/activitystreams2_builder_helper_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Activitystreams2BuilderHelper, type: :helper do + it 'returns display name if present' do + account = Fabricate(:account, display_name: 'display name', username: 'username') + expect(account_name(account)).to eq 'display name' + end + + it 'returns username if display name is not present' do + account = Fabricate(:account, display_name: '', username: 'username') + expect(account_name(account)).to eq 'username' + end +end -- GitLab From dff576b75d11335b3c424b399499c6b1edb4b626 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:03:37 +0900 Subject: [PATCH 013/295] Cover ApplicationHelper more (#3412) --- spec/helpers/application_helper_spec.rb | 61 +++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 81f38d0b02..a3903464b4 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -17,6 +17,59 @@ describe ApplicationHelper do end end + describe 'add_rtl_body_class' do + it 'adds rtl body class if locale is Arabic' do + I18n.locale = :ar + expect(helper.add_rtl_body_class('other classes')).to eq 'other classes rtl' + end + + it 'adds rtl body class if locale is Farsi' do + I18n.locale = :fa + expect(helper.add_rtl_body_class('other classes')).to eq 'other classes rtl' + end + + it 'adds rtl if locale is Hebrew' do + I18n.locale = :he + expect(helper.add_rtl_body_class('other classes')).to eq 'other classes rtl' + end + + it 'does not add rtl if locale is Thai' do + I18n.locale = :th + expect(helper.add_rtl_body_class('other classes')).to eq 'other classes' + end + end + + describe 'fa_icon' do + it 'returns a tag of fixed-width cog' do + expect(helper.fa_icon('cog fw')).to eq '' + end + end + + describe 'favicon_path' do + it 'returns /favicon.ico on production enviromnent' do + expect(Rails.env).to receive(:production?).and_return(true) + expect(helper.favicon_path).to eq '/favicon.ico' + end + end + + describe 'open_registrations?' do + it 'returns true when open for registrations' do + without_partial_double_verification do + expect(Setting).to receive(:open_registrations).and_return(true) + end + + expect(helper.open_registrations?).to eq true + end + + it 'returns false when closed for registrations' do + without_partial_double_verification do + expect(Setting).to receive(:open_registrations).and_return(false) + end + + expect(helper.open_registrations?).to eq false + end + end + describe 'show_landing_strip?', without_verify_partial_doubles: true do describe 'when signed in' do before do @@ -45,4 +98,12 @@ describe ApplicationHelper do end end end + + describe 'title' do + it 'returns site title on production enviroment' do + Setting.site_title = 'site title' + expect(Rails.env).to receive(:production?).and_return(true) + expect(helper.title).to eq 'site title' + end + end end -- GitLab From 7b473d75147b2c19ebbb9677e2011708f8f8e120 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:04:00 +0900 Subject: [PATCH 014/295] Cover Settings::TwoFactorAuthentication::ConfirmationsController more (#3386) --- .../confirmations_controller_spec.rb | 95 +++++++++++++++---- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb index bf555078e4..0676d61613 100644 --- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb @@ -5,41 +5,94 @@ require 'rails_helper' describe Settings::TwoFactorAuthentication::ConfirmationsController do render_views - let(:user) { Fabricate(:user) } - before do - user.otp_secret = User.generate_otp_secret(32) - user.save! + let(:user) { Fabricate(:user, email: 'local-part@domain', otp_secret: 'thisisasecretforthespecofnewview') } - sign_in user, scope: :user + shared_examples 'renders :new' do + it 'renders the new view' do + subject + + expect(assigns(:confirmation)).to be_instance_of Form::TwoFactorConfirmation + expect(assigns(:provision_url)).to eq 'otpauth://totp/local-part@domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io' + expect(assigns(:qrcode)).to be_instance_of RQRCode::QRCode + expect(response).to have_http_status(:success) + expect(response).to render_template(:new) + end end describe 'GET #new' do - it 'returns http success' do - get :new + context 'when signed in' do + subject do + sign_in user, scope: :user + get :new + end - expect(response).to have_http_status(:success) - expect(response).to render_template(:new) + include_examples 'renders :new' + end + + it 'redirects if not signed in' do + get :new + expect(response).to redirect_to('/auth/sign_in') end end describe 'POST #create' do - describe 'when creation succeeds' do - it 'renders page with success' do - allow_any_instance_of(User).to receive(:validate_and_consume_otp!).with('123456').and_return(true) + context 'when signed in' do + before do + sign_in user, scope: :user + end - post :create, params: { form_two_factor_confirmation: { code: '123456' } } - expect(response).to have_http_status(:success) - expect(response).to render_template('settings/two_factor_authentication/recovery_codes/index') + describe 'when form_two_factor_confirmation parameter is not provided' do + it 'raises ActionController::ParameterMissing' do + expect { post :create, params: { } }.to raise_error(ActionController::ParameterMissing) + end + end + + describe 'when creation succeeds' do + it 'renders page with success' do + otp_backup_codes = user.generate_otp_backup_codes! + expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value| + expect(value).to eq user + otp_backup_codes + end + expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, arg| + expect(value).to eq user + expect(arg).to eq '123456' + true + end + + post :create, params: { form_two_factor_confirmation: { code: '123456' } } + + expect(assigns(:recovery_codes)).to eq otp_backup_codes + expect(flash[:notice]).to eq 'Two-factor authentication successfully enabled' + expect(response).to have_http_status(:success) + expect(response).to render_template('settings/two_factor_authentication/recovery_codes/index') + end end - end - describe 'when creation fails' do - it 'renders the new view' do - allow_any_instance_of(User).to receive(:validate_and_consume_otp!).with('123456').and_return(false) + describe 'when creation fails' do + subject do + expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, arg| + expect(value).to eq user + expect(arg).to eq '123456' + false + end + + post :create, params: { form_two_factor_confirmation: { code: '123456' } } + end + + it 'renders the new view' do + subject + expect(response.body).to include 'The entered code was invalid! Are server time and device time correct?' + end + + include_examples 'renders :new' + end + end + context 'when not signed in' do + it 'redirects if not signed in' do post :create, params: { form_two_factor_confirmation: { code: '123456' } } - expect(response).to have_http_status(:success) - expect(response).to render_template(:new) + expect(response).to redirect_to('/auth/sign_in') end end end -- GitLab From fd328cf6e8fac0af2b3ec7f755a734f0fe2385c7 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:04:37 +0900 Subject: [PATCH 015/295] Cover WellKnown::WebfingerController more (#3385) --- .../well_known/webfinger_controller_spec.rb | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/spec/controllers/well_known/webfinger_controller_spec.rb b/spec/controllers/well_known/webfinger_controller_spec.rb index 4d588bf4e3..252c786d4a 100644 --- a/spec/controllers/well_known/webfinger_controller_spec.rb +++ b/spec/controllers/well_known/webfinger_controller_spec.rb @@ -4,7 +4,40 @@ describe WellKnown::WebfingerController, type: :controller do render_views describe 'GET #show' do - let(:alice) { Fabricate(:account, username: 'alice') } + let(:alice) do + Fabricate(:account, username: 'alice') + end + + before do + alice.private_key = < + + acct:alice@cb6e6126.ngrok.io + https://cb6e6126.ngrok.io/@alice + https://cb6e6126.ngrok.io/users/alice + + + + + + +XML end it 'returns http not found when account cannot be found' do @@ -24,13 +79,15 @@ describe WellKnown::WebfingerController, type: :controller do expect(response).to have_http_status(:not_found) end - it 'returns http success when account can be found with alternate domains' do + it 'returns JSON when account can be found with alternate domains' do Rails.configuration.x.alternate_domains = ["foo.org"] username, domain = alice.to_webfinger_s.split("@") get :show, params: { resource: "#{username}@foo.org" }, format: :json expect(response).to have_http_status(:success) + expect(response.content_type).to eq 'application/jrd+json' + expect(response.body).to eq "{\"subject\":\"acct:alice@cb6e6126.ngrok.io\",\"aliases\":[\"https://cb6e6126.ngrok.io/@alice\",\"https://cb6e6126.ngrok.io/users/alice\"],\"links\":[{\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\",\"href\":\"https://cb6e6126.ngrok.io/@alice\"},{\"rel\":\"http://schemas.google.com/g/2010#updates-from\",\"type\":\"application/atom+xml\",\"href\":\"http://test.host/users/alice.atom\"},{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://cb6e6126.ngrok.io/@alice\"},{\"rel\":\"salmon\",\"href\":\"#{api_salmon_url(alice.id)}\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application/magic-public-key,RSA.x4D6DyZa3zGa1XLhd_VG1bLGvK-Dmyz93WJfWNezIKeSuJkmA0f2NmoOfLUoumq9szN2Xt0GLDX06tDajdYPPXgLtDG0o1qqTrIJ7UTyYhbo94Wotl9iJvEwa5IjP1Mn00YJ_KvFrzKCm15PC7up6r-NtHsqoYS8X1KAqcbnptU=.AQAB\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"http://test.host/authorize_follow?acct={uri}\"}]}" end it 'returns http not found when account can not be found with alternate domains' do -- GitLab From c347327d54571f3e3e5ac2a01e6ad9e164e1d802 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:05:01 +0900 Subject: [PATCH 016/295] Spec Settings::Exports (#3384) * Spec output of Settings::Exports::BlockedAccountsController * Spec output of Settings::Exports::FollowingAccountsController * Spec output of Settings::Exports::MutedAccountsController * Spec Settings::Exports::BaseController This commit removes duplicate specs in classes inheriting Settings::Exports::BaseController as well. --- .../settings/exports/base_controller_spec.rb | 29 +++++++++++++++++++ .../blocked_accounts_controller_spec.rb | 12 ++++---- .../following_accounts_controller_spec.rb | 12 ++++---- .../exports/muted_accounts_controller_spec.rb | 12 ++++---- 4 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 spec/controllers/settings/exports/base_controller_spec.rb diff --git a/spec/controllers/settings/exports/base_controller_spec.rb b/spec/controllers/settings/exports/base_controller_spec.rb new file mode 100644 index 0000000000..c924d449ae --- /dev/null +++ b/spec/controllers/settings/exports/base_controller_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Settings::Exports::BaseController do + controller do + def export_data + @export.account.username + end + end + + describe 'GET #index' do + it 'returns a csv of the exported data when signed in' do + user = Fabricate(:user) + sign_in user + get :index, format: :csv + + expect(response).to have_http_status(:success) + expect(response.content_type).to eq 'text/csv' + expect(response.headers['Content-Disposition']).to eq 'attachment; filename="base.csv"' + expect(response.body).to eq user.account.username + end + + it 'returns unauthorized when not signed in' do + get :index, format: :csv + expect(response).to have_http_status(:unauthorized) + end + end +end diff --git a/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb b/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb index e79a6729a6..5ff41b7fcd 100644 --- a/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb +++ b/spec/controllers/settings/exports/blocked_accounts_controller_spec.rb @@ -3,17 +3,15 @@ require 'rails_helper' describe Settings::Exports::BlockedAccountsController do render_views - before do - sign_in Fabricate(:user), scope: :user - end - describe 'GET #index' do it 'returns a csv of the blocking accounts' do + user = Fabricate(:user) + user.account.block!(Fabricate(:account, username: 'username', domain: 'domain')) + + sign_in user, scope: :user get :index, format: :csv - expect(response).to have_http_status(:success) - expect(response.content_type).to eq 'text/csv' - expect(response.headers['Content-Disposition']).to eq 'attachment; filename="blocked_accounts.csv"' + expect(response.body).to eq "username@domain\n" end end end diff --git a/spec/controllers/settings/exports/following_accounts_controller_spec.rb b/spec/controllers/settings/exports/following_accounts_controller_spec.rb index 503455feaa..786769d245 100644 --- a/spec/controllers/settings/exports/following_accounts_controller_spec.rb +++ b/spec/controllers/settings/exports/following_accounts_controller_spec.rb @@ -3,17 +3,15 @@ require 'rails_helper' describe Settings::Exports::FollowingAccountsController do render_views - before do - sign_in Fabricate(:user), scope: :user - end - describe 'GET #index' do it 'returns a csv of the following accounts' do + user = Fabricate(:user) + user.account.follow!(Fabricate(:account, username: 'username', domain: 'domain')) + + sign_in user, scope: :user get :index, format: :csv - expect(response).to have_http_status(:success) - expect(response.content_type).to eq 'text/csv' - expect(response.headers['Content-Disposition']).to eq 'attachment; filename="following_accounts.csv"' + expect(response.body).to eq "username@domain\n" end end end diff --git a/spec/controllers/settings/exports/muted_accounts_controller_spec.rb b/spec/controllers/settings/exports/muted_accounts_controller_spec.rb index 37c3a0fcfe..f42d7881ed 100644 --- a/spec/controllers/settings/exports/muted_accounts_controller_spec.rb +++ b/spec/controllers/settings/exports/muted_accounts_controller_spec.rb @@ -3,17 +3,15 @@ require 'rails_helper' describe Settings::Exports::MutedAccountsController do render_views - before do - sign_in Fabricate(:user), scope: :user - end - describe 'GET #index' do it 'returns a csv of the muting accounts' do + user = Fabricate(:user) + user.account.mute!(Fabricate(:account, username: 'username', domain: 'domain')) + + sign_in user, scope: :user get :index, format: :csv - expect(response).to have_http_status(:success) - expect(response.content_type).to eq 'text/csv' - expect(response.headers['Content-Disposition']).to eq 'attachment; filename="muted_accounts.csv"' + expect(response.body).to eq "username@domain\n" end end end -- GitLab From c778a60e4fe47647d97f64855fa8555fd5a5a0c8 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:05:20 +0900 Subject: [PATCH 017/295] Cover Settings::TwoFactorAuthentication::RecoveryCodesController more (#3383) --- .../recovery_codes_controller_spec.rb | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb index 3d6f5faab1..aa28cdf3f8 100644 --- a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb @@ -5,21 +5,27 @@ require 'rails_helper' describe Settings::TwoFactorAuthentication::RecoveryCodesController do render_views - let(:user) { Fabricate(:user) } - before do - sign_in user, scope: :user - end - describe 'POST #create' do - it 'updates the codes and shows them on a view' do - before = user.otp_backup_codes + it 'updates the codes and shows them on a view when signed in' do + user = Fabricate(:user) + otp_backup_codes = user.generate_otp_backup_codes! + expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value| + expect(value).to eq user + otp_backup_codes + end + sign_in user, scope: :user post :create - user.reload - expect(user.otp_backup_codes).not_to eq(before) + expect(assigns(:recovery_codes)).to eq otp_backup_codes + expect(flash[:notice]).to eq 'Recovery codes successfully regenerated' expect(response).to have_http_status(:success) expect(response).to render_template(:index) end + + it 'redirects when not signed in' do + post :create + expect(response).to redirect_to '/auth/sign_in' + end end end -- GitLab From dde043f6cd1bf4fe97de678992000b1606e2620c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:05:30 +0900 Subject: [PATCH 018/295] Cover WellKnown::HostMetaController more (#3382) --- spec/controllers/well_known/host_meta_controller_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/controllers/well_known/host_meta_controller_spec.rb b/spec/controllers/well_known/host_meta_controller_spec.rb index 8a040021a6..d647dc97a4 100644 --- a/spec/controllers/well_known/host_meta_controller_spec.rb +++ b/spec/controllers/well_known/host_meta_controller_spec.rb @@ -8,6 +8,13 @@ describe WellKnown::HostMetaController, type: :controller do get :show, format: :xml expect(response).to have_http_status(:success) + expect(response.content_type).to eq 'application/xrd+xml' + expect(response.body).to eq < + + + +XML end end end -- GitLab From 0e4ca51951c4cd3ea51e4983bb5c502850d3056f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:07:07 +0900 Subject: [PATCH 019/295] Cover Settings::TwoFactorAuthenticationsController more (#3376) --- ..._factor_authentications_controller_spec.rb | 82 +++++++++++++------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/spec/controllers/settings/two_factor_authentications_controller_spec.rb b/spec/controllers/settings/two_factor_authentications_controller_spec.rb index 25d7a928d1..4d1a01fcfa 100644 --- a/spec/controllers/settings/two_factor_authentications_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentications_controller_spec.rb @@ -6,47 +6,70 @@ describe Settings::TwoFactorAuthenticationsController do render_views let(:user) { Fabricate(:user) } - before do - sign_in user, scope: :user - end describe 'GET #show' do - describe 'when user requires otp for login already' do - it 'returns http success' do - user.update(otp_required_for_login: true) - get :show + context 'when signed in' do + before do + sign_in user, scope: :user + end - expect(response).to have_http_status(:success) + describe 'when user requires otp for login already' do + it 'returns http success' do + user.update(otp_required_for_login: true) + get :show + + expect(response).to have_http_status(:success) + end + end + + describe 'when user does not require otp for login' do + it 'returns http success' do + user.update(otp_required_for_login: false) + get :show + + expect(response).to have_http_status(:success) + end end end - describe 'when user does not require otp for login' do - it 'returns http success' do - user.update(otp_required_for_login: false) + context 'when not signed in' do + it 'redirects' do get :show - - expect(response).to have_http_status(:success) + expect(response).to redirect_to '/auth/sign_in' end end end describe 'POST #create' do - describe 'when user requires otp for login already' do - it 'redirects to show page' do - user.update(otp_required_for_login: true) - post :create + context 'when signed in' do + before do + sign_in user, scope: :user + end - expect(response).to redirect_to(settings_two_factor_authentication_path) + describe 'when user requires otp for login already' do + it 'redirects to show page' do + user.update(otp_required_for_login: true) + post :create + + expect(response).to redirect_to(settings_two_factor_authentication_path) + end end - end - describe 'when creation succeeds' do - it 'updates user secret' do - before = user.otp_secret - post :create + describe 'when creation succeeds' do + it 'updates user secret' do + before = user.otp_secret + post :create - expect(user.reload.otp_secret).not_to eq(before) - expect(response).to redirect_to(new_settings_two_factor_authentication_confirmation_path) + expect(user.reload.otp_secret).not_to eq(before) + expect(response).to redirect_to(new_settings_two_factor_authentication_confirmation_path) + end + end + end + + context 'when not signed in' do + it 'redirects' do + get :show + expect(response).to redirect_to '/auth/sign_in' end end end @@ -55,12 +78,19 @@ describe Settings::TwoFactorAuthenticationsController do before do user.update(otp_required_for_login: true) end - it 'turns off otp requirement' do + + it 'turns off otp requirement if signed in' do + sign_in user, scope: :user post :destroy expect(response).to redirect_to(settings_two_factor_authentication_path) user.reload expect(user.otp_required_for_login).to eq(false) end + + it 'redirects if not signed in' do + get :show + expect(response).to redirect_to '/auth/sign_in' + end end end -- GitLab From aecce5694b1763b9f63341dfe1c469fc14e5a775 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:07:39 +0900 Subject: [PATCH 020/295] Cover Oauth::AuthorizationsController more (#3361) --- .../oauth/authorizations_controller_spec.rb | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index a5997bba33..5c2a62b48c 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -7,21 +7,43 @@ RSpec.describe Oauth::AuthorizationsController, type: :controller do let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/') } - before do - sign_in Fabricate(:user), scope: :user - end - describe 'GET #new' do - before do + subject do get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/' } end - it 'returns http success' do - expect(response).to have_http_status(:success) + shared_examples 'stores location for user' do + it 'stores location for user' do + subject + expect(controller.stored_location_for(:user)).to eq "/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code" + end + end + + context 'when signed in' do + before do + sign_in Fabricate(:user), scope: :user + end + + it 'returns http success' do + subject + expect(response).to have_http_status(:success) + end + + it 'gives options to authorize and deny' do + subject + expect(response.body).to match(/Authorize/) + end + + include_examples 'stores location for user' end - it 'gives options to authorize and deny' do - expect(response.body).to match(/Authorize/) + context 'when not signed in' do + it 'redirects' do + subject + expect(response).to redirect_to '/auth/sign_in' + end + + include_examples 'stores location for user' end end end -- GitLab From 7d33b60f3fd12c20bcc390ae7da9fac5d415ec3c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:08:05 +0900 Subject: [PATCH 021/295] Cover Oauth::AuthorizedApplicationsController (#3359) --- ...authorized_applications_controller_spec.rb | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/spec/controllers/oauth/authorized_applications_controller_spec.rb b/spec/controllers/oauth/authorized_applications_controller_spec.rb index f5d64bd90b..2a2b92283f 100644 --- a/spec/controllers/oauth/authorized_applications_controller_spec.rb +++ b/spec/controllers/oauth/authorized_applications_controller_spec.rb @@ -5,17 +5,38 @@ require 'rails_helper' describe Oauth::AuthorizedApplicationsController do render_views - before do - sign_in Fabricate(:user), scope: :user - end - describe 'GET #index' do - before do + subject do get :index end - it 'returns http success' do - expect(response).to have_http_status(:success) + shared_examples 'stores location for user' do + it 'stores location for user' do + subject + expect(controller.stored_location_for(:user)).to eq "/oauth/authorized_applications" + end + end + + context 'when signed in' do + before do + sign_in Fabricate(:user), scope: :user + end + + it 'returns http success' do + subject + expect(response).to have_http_status(:success) + end + + include_examples 'stores location for user' + end + + context 'when not signed in' do + it 'redirects' do + subject + expect(response).to redirect_to '/auth/sign_in' + end + + include_examples 'stores location for user' end end end -- GitLab From bd4dd4c4a0483b36a73c97badec3f7f3e2292c4b Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:08:26 +0900 Subject: [PATCH 022/295] Cover Settings::ExportsController more (#3358) --- .../settings/exports_controller_spec.rb | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/spec/controllers/settings/exports_controller_spec.rb b/spec/controllers/settings/exports_controller_spec.rb index 2be6e4744f..19cb0abdae 100644 --- a/spec/controllers/settings/exports_controller_spec.rb +++ b/spec/controllers/settings/exports_controller_spec.rb @@ -3,15 +3,29 @@ require 'rails_helper' describe Settings::ExportsController do render_views - before do - sign_in Fabricate(:user), scope: :user - end - describe 'GET #show' do - it 'returns http success' do - get :show + context 'when signed in' do + let(:user) { Fabricate(:user) } + + before do + sign_in user, scope: :user + end + + it 'renders export' do + get :show + + export = assigns(:export) + expect(export).to be_instance_of Export + expect(export.account).to eq user.account + expect(response).to have_http_status(:success) + end + end - expect(response).to have_http_status(:success) + context 'when not signed in' do + it 'redirects' do + get :show + expect(response).to redirect_to '/auth/sign_in' + end end end end -- GitLab From 2c10c5a0696c1ad4f891590abb611643ba592f48 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:08:42 +0900 Subject: [PATCH 023/295] Coever Admin::SilencesController more (#3356) --- spec/controllers/admin/silences_controller_spec.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/controllers/admin/silences_controller_spec.rb b/spec/controllers/admin/silences_controller_spec.rb index 16b326542d..78560eb393 100644 --- a/spec/controllers/admin/silences_controller_spec.rb +++ b/spec/controllers/admin/silences_controller_spec.rb @@ -3,23 +3,30 @@ require 'rails_helper' describe Admin::SilencesController do render_views - let(:account) { Fabricate(:account) } before do sign_in Fabricate(:user, admin: true), scope: :user end describe 'POST #create' do it 'redirects to admin accounts page' do + account = Fabricate(:account, silenced: false) + post :create, params: { account_id: account.id } + account.reload + expect(account.silenced?).to eq true expect(response).to redirect_to(admin_accounts_path) end end describe 'DELETE #destroy' do it 'redirects to admin accounts page' do + account = Fabricate(:account, silenced: true) + delete :destroy, params: { account_id: account.id } + account.reload + expect(account.silenced?).to eq false expect(response).to redirect_to(admin_accounts_path) end end -- GitLab From 2e27ce3b61a21918b5cfcfcfea328c4225c12744 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:08:58 +0900 Subject: [PATCH 024/295] Spec #destroy feature of Admin::TwoFactorAuthenticationsController (#3355) --- .../admin/two_factor_authentications_controller_spec.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/controllers/admin/two_factor_authentications_controller_spec.rb b/spec/controllers/admin/two_factor_authentications_controller_spec.rb index 69f26039a0..4c1aa88d75 100644 --- a/spec/controllers/admin/two_factor_authentications_controller_spec.rb +++ b/spec/controllers/admin/two_factor_authentications_controller_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe Admin::TwoFactorAuthenticationsController do render_views - let(:user) { Fabricate(:user) } + let(:user) { Fabricate(:user, otp_required_for_login: true) } before do sign_in Fabricate(:user, admin: true), scope: :user end @@ -11,6 +11,9 @@ describe Admin::TwoFactorAuthenticationsController do describe 'DELETE #destroy' do it 'redirects to admin accounts page' do delete :destroy, params: { user_id: user.id } + + user.reload + expect(user.otp_required_for_login).to eq false expect(response).to redirect_to(admin_accounts_path) end end -- GitLab From 00dda99789268b1f81a086c6b4a7e89764e59cbd Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:09:17 +0900 Subject: [PATCH 025/295] Spec Admin::ResetsController calls send_reset_password_instructions (#3354) --- spec/controllers/admin/resets_controller_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/controllers/admin/resets_controller_spec.rb b/spec/controllers/admin/resets_controller_spec.rb index a0a77478e0..a20a460bd0 100644 --- a/spec/controllers/admin/resets_controller_spec.rb +++ b/spec/controllers/admin/resets_controller_spec.rb @@ -10,6 +10,10 @@ describe Admin::ResetsController do describe 'POST #create' do it 'redirects to admin accounts page' do + expect_any_instance_of(User).to receive(:send_reset_password_instructions) do |value| + expect(value.account_id).to eq account.id + end + post :create, params: { account_id: account.id } expect(response).to redirect_to(admin_accounts_path) -- GitLab From a7f296162117013b6da752e6bf13409796ac5761 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:10:50 +0900 Subject: [PATCH 026/295] Spec Auth::PasswordsController (#3352) --- spec/controllers/auth/passwords_controller_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 spec/controllers/auth/passwords_controller_spec.rb diff --git a/spec/controllers/auth/passwords_controller_spec.rb b/spec/controllers/auth/passwords_controller_spec.rb new file mode 100644 index 0000000000..60b225efae --- /dev/null +++ b/spec/controllers/auth/passwords_controller_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Auth::PasswordsController, type: :controller do + describe 'GET #new' do + it 'returns http success' do + @request.env['devise.mapping'] = Devise.mappings[:user] + get :new + expect(response).to have_http_status(:success) + end + end +end -- GitLab From 97d7028c3137cb79d10e5b16034b3925808f5a86 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:11:16 +0900 Subject: [PATCH 027/295] Cover Admin::SuspensionsController more (#3350) --- spec/controllers/admin/suspensions_controller_spec.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/controllers/admin/suspensions_controller_spec.rb b/spec/controllers/admin/suspensions_controller_spec.rb index 2d9adc23d6..ddfc938d18 100644 --- a/spec/controllers/admin/suspensions_controller_spec.rb +++ b/spec/controllers/admin/suspensions_controller_spec.rb @@ -3,13 +3,15 @@ require 'rails_helper' describe Admin::SuspensionsController do render_views - let(:account) { Fabricate(:account) } before do sign_in Fabricate(:user, admin: true), scope: :user end describe 'POST #create' do it 'redirects to admin accounts page' do + account = Fabricate(:account, suspended: false) + expect(Admin::SuspensionWorker).to receive(:perform_async).with(account.id) + post :create, params: { account_id: account.id } expect(response).to redirect_to(admin_accounts_path) @@ -18,8 +20,12 @@ describe Admin::SuspensionsController do describe 'DELETE #destroy' do it 'redirects to admin accounts page' do + account = Fabricate(:account, suspended: true) + delete :destroy, params: { account_id: account.id } + account.reload + expect(account.suspended?).to eq false expect(response).to redirect_to(admin_accounts_path) end end -- GitLab From 7b92950f1c43ad009d169ce1792c9afed109b417 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:12:17 +0900 Subject: [PATCH 028/295] Cover InstancesController more (#3342) --- .../admin/instances_controller_spec.rb | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/spec/controllers/admin/instances_controller_spec.rb b/spec/controllers/admin/instances_controller_spec.rb index 37fa8dd9a0..f57e3fa97d 100644 --- a/spec/controllers/admin/instances_controller_spec.rb +++ b/spec/controllers/admin/instances_controller_spec.rb @@ -8,8 +8,23 @@ RSpec.describe Admin::InstancesController, type: :controller do end describe 'GET #index' do - it 'returns http success' do - get :index + around do |example| + default_per_page = Account.default_per_page + Account.paginates_per 1 + example.run + Account.paginates_per default_per_page + end + + it 'renders instances' do + Fabricate(:account, domain: 'popular') + Fabricate(:account, domain: 'popular') + Fabricate(:account, domain: 'less.popular') + + get :index, params: { page: 2 } + + instances = assigns(:instances).to_a + expect(instances.size).to eq 1 + expect(instances[0].domain).to eq 'less.popular' expect(response).to have_http_status(:success) end -- GitLab From 34157d118c03f60df392404e8c617606063c6530 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:12:34 +0900 Subject: [PATCH 029/295] Cover Admin::ReportsController more (#3346) --- .../admin/reports_controller_spec.rb | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb index 89b58ad074..71a185147b 100644 --- a/spec/controllers/admin/reports_controller_spec.rb +++ b/spec/controllers/admin/reports_controller_spec.rb @@ -10,27 +10,38 @@ describe Admin::ReportsController do describe 'GET #index' do it 'returns http success with no filters' do - allow(Report).to receive(:unresolved).and_return(Report.all) + specified = Fabricate(:report, action_taken: false) + Fabricate(:report, action_taken: true) + get :index + reports = assigns(:reports).to_a + expect(reports.size).to eq 1 + expect(reports[0]).to eq specified expect(response).to have_http_status(:success) - expect(Report).to have_received(:unresolved) end it 'returns http success with resolved filter' do - allow(Report).to receive(:resolved).and_return(Report.all) + specified = Fabricate(:report, action_taken: true) + Fabricate(:report, action_taken: false) + get :index, params: { resolved: 1 } + reports = assigns(:reports).to_a + expect(reports.size).to eq 1 + expect(reports[0]).to eq specified + expect(response).to have_http_status(:success) - expect(Report).to have_received(:resolved) end end describe 'GET #show' do - it 'returns http success' do + it 'renders report' do report = Fabricate(:report) get :show, params: { id: report } + + expect(assigns(:report)).to eq report expect(response).to have_http_status(:success) end end -- GitLab From 11e5c965c3934226b5238ba5d85776a36ed83a24 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:12:54 +0900 Subject: [PATCH 030/295] Spec AccountControllerConcern (#3349) --- .../account_controller_concern_spec.rb | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 spec/controllers/concerns/account_controller_concern_spec.rb diff --git a/spec/controllers/concerns/account_controller_concern_spec.rb b/spec/controllers/concerns/account_controller_concern_spec.rb new file mode 100644 index 0000000000..bdc181edcf --- /dev/null +++ b/spec/controllers/concerns/account_controller_concern_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ApplicationController, type: :controller do + controller do + include AccountControllerConcern + + def success + head 200 + end + end + + before do + routes.draw { get 'success' => 'anonymous#success' } + end + + context 'when account is suspended' do + it 'returns http gone' do + account = Fabricate(:account, suspended: true) + get 'success', params: { account_username: account.username } + expect(response).to have_http_status(410) + end + end + + context 'when account is not suspended' do + it 'assigns @account' do + account = Fabricate(:account) + get 'success', params: { account_username: account.username } + expect(assigns(:account)).to eq account + end + + it 'sets link headers' do + account = Fabricate(:account, username: 'username') + get 'success', params: { account_username: 'username' } + expect(response.headers['Link'].to_s).to eq '; rel="lrdd"; type="application/xrd+xml", ; rel="alternate"; type="application/atom+xml"' + end + + it 'returns http success' do + account = Fabricate(:account) + get 'success', params: { account_username: account.username } + expect(response).to have_http_status(:success) + end + end +end -- GitLab From 7bf2d6cb06570d84d96bbd2517da8b5e50d33309 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:13:11 +0900 Subject: [PATCH 031/295] Spec Auth::ConfirmationsController (#3348) --- .../auth/confirmations_controller_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 spec/controllers/auth/confirmations_controller_spec.rb diff --git a/spec/controllers/auth/confirmations_controller_spec.rb b/spec/controllers/auth/confirmations_controller_spec.rb new file mode 100644 index 0000000000..cf7f91e528 --- /dev/null +++ b/spec/controllers/auth/confirmations_controller_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Auth::ConfirmationsController, type: :controller do + describe 'GET #new' do + it 'returns http success' do + @request.env['devise.mapping'] = Devise.mappings[:user] + get :new + expect(response).to have_http_status(:success) + end + end +end -- GitLab From 922fb74197ef65e6f6ebfba627f80eb483486c1c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 01:14:16 +0900 Subject: [PATCH 032/295] Remove methods from ObfuscateFilename and spec (#3347) * Remove methods from ObfuscateFilename * Spec ObfuscateFilename --- .../concerns/obfuscate_filename.rb | 20 +++++-------- .../concerns/obfuscate_filename_spec.rb | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 spec/controllers/concerns/obfuscate_filename_spec.rb diff --git a/app/controllers/concerns/obfuscate_filename.rb b/app/controllers/concerns/obfuscate_filename.rb index 9c896fb098..22736ec3ab 100644 --- a/app/controllers/concerns/obfuscate_filename.rb +++ b/app/controllers/concerns/obfuscate_filename.rb @@ -4,19 +4,13 @@ module ObfuscateFilename extend ActiveSupport::Concern class_methods do - def obfuscate_filename(*args) - before_action { obfuscate_filename(*args) } - end - end - - def obfuscate_filename(path) - file = params.dig(*path) - return if file.nil? + def obfuscate_filename(path) + before_action do + file = params.dig(*path) + next if file.nil? - file.original_filename = secure_token + File.extname(file.original_filename) - end - - def secure_token(length = 16) - SecureRandom.hex(length / 2) + file.original_filename = SecureRandom.hex(8) + File.extname(file.original_filename) + end + end end end diff --git a/spec/controllers/concerns/obfuscate_filename_spec.rb b/spec/controllers/concerns/obfuscate_filename_spec.rb new file mode 100644 index 0000000000..e06d53c038 --- /dev/null +++ b/spec/controllers/concerns/obfuscate_filename_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ApplicationController, type: :controller do + controller do + include ObfuscateFilename + + obfuscate_filename :file + + def file + render plain: params[:file]&.original_filename + end + end + + before do + routes.draw { get 'file' => 'anonymous#file' } + end + + it 'obfusticates filename if the given parameter is specified' do + file = fixture_file_upload('files/imports.txt', 'text/plain') + post 'file', params: { file: file } + expect(response.body).to end_with '.txt' + expect(response.body).not_to include 'imports' + end + + it 'does nothing if the given parameter is not specified' do + post 'file' + end +end -- GitLab From 34a93ccf571426ffaac68c573f231bb679c0ff3b Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Mon, 29 May 2017 09:17:51 -0700 Subject: [PATCH 033/295] Add IntersectionObserverWrapper to cut down on re-renders (#3406) --- app/javascript/mastodon/components/status.js | 66 +++++++++++++------ .../mastodon/components/status_list.js | 65 ++---------------- .../ui/util/intersection_observer_wrapper.js | 48 ++++++++++++++ 3 files changed, 100 insertions(+), 79 deletions(-) create mode 100644 app/javascript/mastodon/features/ui/util/intersection_observer_wrapper.js diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index a9f9c1b6b9..d35642ede8 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -32,16 +32,16 @@ class Status extends ImmutablePureComponent { onOpenMedia: PropTypes.func, onOpenVideo: PropTypes.func, onBlock: PropTypes.func, - onRef: PropTypes.func, - isIntersecting: PropTypes.bool, me: PropTypes.number, boostModal: PropTypes.bool, autoPlayGif: PropTypes.bool, muted: PropTypes.bool, + intersectionObserverWrapper: PropTypes.object, }; state = { - isHidden: false, + isIntersecting: true, // assume intersecting until told otherwise + isHidden: false, // set to true in requestIdleCallback to trigger un-render } // Avoid checking props that are functions (and whose equality will always @@ -59,12 +59,12 @@ class Status extends ImmutablePureComponent { updateOnStates = [] shouldComponentUpdate (nextProps, nextState) { - if (nextProps.isIntersecting === false && nextState.isHidden) { + if (!nextState.isIntersecting && nextState.isHidden) { // It's only if we're not intersecting (i.e. offscreen) and isHidden is true // that either "isIntersecting" or "isHidden" matter, and then they're // the only things that matter. - return this.props.isIntersecting !== false || !this.state.isHidden; - } else if (nextProps.isIntersecting !== false && this.props.isIntersecting === false) { + return this.state.isIntersecting || !this.state.isHidden; + } else if (nextState.isIntersecting && !this.state.isIntersecting) { // If we're going from a non-intersecting state to an intersecting state, // (i.e. offscreen to onscreen), then we definitely need to re-render return true; @@ -73,21 +73,47 @@ class Status extends ImmutablePureComponent { return super.shouldComponentUpdate(nextProps, nextState); } - componentWillReceiveProps (nextProps) { - if (nextProps.isIntersecting === false && this.props.isIntersecting !== false) { - requestIdleCallback(() => this.setState({ isHidden: true })); - } else { - this.setState({ isHidden: !nextProps.isIntersecting }); + componentDidMount () { + if (!this.props.intersectionObserverWrapper) { + // TODO: enable IntersectionObserver optimization for notification statuses. + // These are managed in notifications/index.js rather than status_list.js + return; } + this.props.intersectionObserverWrapper.observe( + this.props.id, + this.node, + this.handleIntersection + ); } - handleRef = (node) => { - if (this.props.onRef) { - this.props.onRef(node); - - if (node && node.children.length !== 0) { - this.height = node.clientHeight; + handleIntersection = (entry) => { + // Edge 15 doesn't support isIntersecting, but we can infer it from intersectionRatio + // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12156111/ + const isIntersecting = entry.intersectionRatio > 0; + this.setState((prevState) => { + if (prevState.isIntersecting && !isIntersecting) { + requestIdleCallback(this.hideIfNotIntersecting); } + return { + isIntersecting: isIntersecting, + isHidden: false, + }; + }); + } + + hideIfNotIntersecting = () => { + // When the browser gets a chance, test if we're still not intersecting, + // and if so, set our isHidden to true to trigger an unrender. The point of + // this is to save DOM nodes and avoid using up too much memory. + // See: https://github.com/tootsuite/mastodon/issues/2900 + this.setState((prevState) => ({ isHidden: !prevState.isIntersecting })); + } + + + handleRef = (node) => { + this.node = node; + if (node && node.children.length !== 0) { + this.height = node.clientHeight; } } @@ -107,14 +133,14 @@ class Status extends ImmutablePureComponent { render () { let media = null; let statusAvatar; - const { status, account, isIntersecting, onRef, ...other } = this.props; - const { isHidden } = this.state; + const { status, account, ...other } = this.props; + const { isIntersecting, isHidden } = this.state; if (status === null) { return null; } - if (isIntersecting === false && isHidden) { + if (!isIntersecting && isHidden) { return (
{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])} diff --git a/app/javascript/mastodon/components/status_list.js b/app/javascript/mastodon/components/status_list.js index 39f663dfb3..9ee3af4d1e 100644 --- a/app/javascript/mastodon/components/status_list.js +++ b/app/javascript/mastodon/components/status_list.js @@ -5,6 +5,7 @@ import PropTypes from 'prop-types'; import StatusContainer from '../containers/status_container'; import LoadMore from './load_more'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper'; class StatusList extends ImmutablePureComponent { @@ -26,12 +27,7 @@ class StatusList extends ImmutablePureComponent { trackScroll: true, }; - state = { - isIntersecting: {}, - intersectionCount: 0, - } - - statusRefQueue = [] + intersectionObserverWrapper = new IntersectionObserverWrapper(); handleScroll = (e) => { const { scrollTop, scrollHeight, clientHeight } = e.target; @@ -64,53 +60,14 @@ class StatusList extends ImmutablePureComponent { } attachIntersectionObserver () { - const onIntersection = (entries) => { - this.setState(state => { - - entries.forEach(entry => { - const statusId = entry.target.getAttribute('data-id'); - - // Edge 15 doesn't support isIntersecting, but we can infer it from intersectionRatio - // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12156111/ - state.isIntersecting[statusId] = entry.intersectionRatio > 0; - }); - - // isIntersecting is a map of DOM data-id's to booleans (true for - // intersecting, false for non-intersecting). - // - // We always want to return true in shouldComponentUpdate() if - // this object changes, because onIntersection() is only called if - // something has changed. - // - // Now, we *could* use an immutable map or some other structure to - // diff the full map, but that would be pointless because the browser - // has already informed us that something has changed. So we can just - // use a regular object, which will be diffed by ImmutablePureComponent - // based on reference equality (i.e. it's always "unchanged") and - // then we just increment intersectionCount to force a change. - - return { - isIntersecting: state.isIntersecting, - intersectionCount: state.intersectionCount + 1, - }; - }); - }; - - const options = { + this.intersectionObserverWrapper.connect({ root: this.node, rootMargin: '300% 0px', - }; - - this.intersectionObserver = new IntersectionObserver(onIntersection, options); - - if (this.statusRefQueue.length) { - this.statusRefQueue.forEach(node => this.intersectionObserver.observe(node)); - this.statusRefQueue = []; - } + }); } detachIntersectionObserver () { - this.intersectionObserver.disconnect(); + this.intersectionObserverWrapper.disconnect(); } attachScrollListener () { @@ -125,15 +82,6 @@ class StatusList extends ImmutablePureComponent { this.node = c; } - handleStatusRef = (node) => { - if (node && this.intersectionObserver) { - const statusId = node.getAttribute('data-id'); - this.intersectionObserver.observe(node); - } else { - this.statusRefQueue.push(node); - } - } - handleLoadMore = (e) => { e.preventDefault(); this.props.onScrollToBottom(); @@ -141,7 +89,6 @@ class StatusList extends ImmutablePureComponent { render () { const { statusIds, onScrollToBottom, scrollKey, shouldUpdateScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props; - const { isIntersecting } = this.state; let loadMore = null; let scrollableArea = null; @@ -164,7 +111,7 @@ class StatusList extends ImmutablePureComponent { {prepend} {statusIds.map((statusId) => { - return ; + return ; })} {loadMore} diff --git a/app/javascript/mastodon/features/ui/util/intersection_observer_wrapper.js b/app/javascript/mastodon/features/ui/util/intersection_observer_wrapper.js new file mode 100644 index 0000000000..0e959f9ae8 --- /dev/null +++ b/app/javascript/mastodon/features/ui/util/intersection_observer_wrapper.js @@ -0,0 +1,48 @@ +// Wrapper for IntersectionObserver in order to make working with it +// a bit easier. We also follow this performance advice: +// "If you need to observe multiple elements, it is both possible and +// advised to observe multiple elements using the same IntersectionObserver +// instance by calling observe() multiple times." +// https://developers.google.com/web/updates/2016/04/intersectionobserver + +class IntersectionObserverWrapper { + + callbacks = {}; + observerBacklog = []; + observer = null; + + connect (options) { + const onIntersection = (entries) => { + entries.forEach(entry => { + const id = entry.target.getAttribute('data-id'); + if (this.callbacks[id]) { + this.callbacks[id](entry); + } + }); + }; + + this.observer = new IntersectionObserver(onIntersection, options); + this.observerBacklog.forEach(([ id, node, callback ]) => { + this.observe(id, node, callback); + }); + this.observerBacklog = null; + } + + observe (id, node, callback) { + if (!this.observer) { + this.observerBacklog.push([ id, node, callback ]); + } else { + this.callbacks[id] = callback; + this.observer.observe(node); + } + } + + disconnect () { + if (this.observer) { + this.observer.disconnect(); + } + } + +} + +export default IntersectionObserverWrapper; -- GitLab From 5e2c5e95b6fceadc73c22d28f35d2c0f7c1f2601 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 May 2017 12:18:06 -0400 Subject: [PATCH 034/295] Version bumps for non-rails gems (#3398) * Update xpath to version 2.1.0 * Update aws-sdk to version 2.9.25 * Update oj to version 3.0.10 * Update brakeman to version 3.6.2 * Update rufus-scheduler to version 3.4.2 * Update doorkeeper to version 4.2.6 * Update rubocop to version 0.49.0 --- Gemfile | 2 +- Gemfile.lock | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 9b089f1076..811dd1f99f 100644 --- a/Gemfile +++ b/Gemfile @@ -86,7 +86,7 @@ group :development do gem 'bullet', '~> 5.5' gem 'letter_opener', '~> 1.4' gem 'letter_opener_web', '~> 1.3' - gem 'rubocop', '~> 0.48', require: false + gem 'rubocop', require: false gem 'brakeman', '~> 3.6', require: false gem 'bundler-audit', '~> 0.5', require: false gem 'scss_lint', '~> 0.53', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 4d27dc9be9..e8c3ba4870 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -52,13 +52,13 @@ GEM encryptor (~> 3.0.0) av (0.9.0) cocaine (~> 0.5.3) - aws-sdk (2.9.21) - aws-sdk-resources (= 2.9.21) - aws-sdk-core (2.9.21) + aws-sdk (2.9.25) + aws-sdk-resources (= 2.9.25) + aws-sdk-core (2.9.25) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.9.21) - aws-sdk-core (= 2.9.21) + aws-sdk-resources (2.9.25) + aws-sdk-core (= 2.9.25) aws-sigv4 (1.0.0) bcrypt (3.1.11) better_errors (2.1.1) @@ -69,7 +69,7 @@ GEM debug_inspector (>= 0.0.1) bootsnap (0.3.0) msgpack (~> 1.0) - brakeman (3.6.1) + brakeman (3.6.2) builder (3.2.3) bullet (5.5.1) activesupport (>= 3.0.0) @@ -130,7 +130,7 @@ GEM docile (1.1.5) domain_name (0.5.20170404) unf (>= 0.0.5, < 1.0.0) - doorkeeper (4.2.5) + doorkeeper (4.2.6) railties (>= 4.2) dotenv (2.2.1) dotenv-rails (2.2.1) @@ -247,7 +247,7 @@ GEM mini_portile2 (~> 2.1.0) nokogumbo (1.4.11) nokogiri - oj (3.0.9) + oj (3.0.10) openssl (2.0.3) orm_adapter (0.5.0) ostatus2 (2.0.0) @@ -374,7 +374,8 @@ GEM rspec-core (~> 3.0, >= 3.0.0) sidekiq (>= 2.4.0) rspec-support (3.6.0) - rubocop (0.48.1) + rubocop (0.49.0) + parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) @@ -382,7 +383,7 @@ GEM unicode-display_width (~> 1.0, >= 1.0.1) ruby-oembed (0.12.0) ruby-progressbar (1.8.1) - rufus-scheduler (3.4.0) + rufus-scheduler (3.4.2) et-orbi (~> 1.0) safe_yaml (1.0.4) sanitize (4.4.0) @@ -461,7 +462,7 @@ GEM websocket-driver (0.6.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) - xpath (2.0.0) + xpath (2.1.0) nokogiri (~> 1.3) PLATFORMS @@ -532,7 +533,7 @@ DEPENDENCIES rqrcode (~> 0.10) rspec-rails (~> 3.6) rspec-sidekiq (~> 3.0) - rubocop (~> 0.48) + rubocop ruby-oembed (~> 0.12) sanitize (~> 4.4) scss_lint (~> 0.53) -- GitLab From 9a81be0d3715eb846d940794f8b34cbbe4ba67a5 Mon Sep 17 00:00:00 2001 From: unarist Date: Tue, 30 May 2017 01:20:53 +0900 Subject: [PATCH 035/295] [RFC] Return 401 for an authentication error on WebSockets (#3411) * Return 401 for an authentication error on WebSocket * Use upgradeReq instead of a custom object --- streaming/index.js | 87 +++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/streaming/index.js b/streaming/index.js index fe39cf21df..0411ae8efe 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -95,7 +95,6 @@ const startWorker = (workerId) => { const app = express(); const pgPool = new pg.Pool(Object.assign(pgConfigs[env], dbUrlToConfig(process.env.DATABASE_URL))); const server = http.createServer(app); - const wss = new WebSocket.Server({ server }); const redisNamespace = process.env.REDIS_NAMESPACE || null; const redisParams = { @@ -186,14 +185,10 @@ const startWorker = (workerId) => { }); }; - const authenticationMiddleware = (req, res, next) => { - if (req.method === 'OPTIONS') { - next(); - return; - } - - const authorization = req.get('Authorization'); - const accessToken = req.query.access_token; + const accountFromRequest = (req, next) => { + const authorization = req.headers.authorization; + const location = url.parse(req.url, true); + const accessToken = location.query.access_token; if (!authorization && !accessToken) { const err = new Error('Missing access token'); @@ -208,6 +203,26 @@ const startWorker = (workerId) => { accountFromToken(token, req, next); }; + const wsVerifyClient = (info, cb) => { + accountFromRequest(info.req, err => { + if (!err) { + cb(true, undefined, undefined); + } else { + log.error(info.req.requestId, err.toString()); + cb(false, 401, 'Unauthorized'); + } + }); + }; + + const authenticationMiddleware = (req, res, next) => { + if (req.method === 'OPTIONS') { + next(); + return; + } + + accountFromRequest(req, next); + }; + const errorMiddleware = (err, req, res, next) => { log.error(req.requestId, err.toString()); res.writeHead(err.statusCode || 500, { 'Content-Type': 'application/json' }); @@ -352,10 +367,12 @@ const startWorker = (workerId) => { streamFrom(`timeline:hashtag:${req.query.tag}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true); }); + const wss = new WebSocket.Server({ server, verifyClient: wsVerifyClient }); + wss.on('connection', ws => { - const location = url.parse(ws.upgradeReq.url, true); - const token = location.query.access_token; - const req = { requestId: uuid.v4() }; + const req = ws.upgradeReq; + const location = url.parse(req.url, true); + req.requestId = uuid.v4(); ws.isAlive = true; @@ -363,33 +380,25 @@ const startWorker = (workerId) => { ws.isAlive = true; }); - accountFromToken(token, req, err => { - if (err) { - log.error(req.requestId, err); - ws.close(); - return; - } - - switch(location.query.stream) { - case 'user': - streamFrom(`timeline:${req.accountId}`, req, streamToWs(req, ws), streamWsEnd(req, ws)); - break; - case 'public': - streamFrom('timeline:public', req, streamToWs(req, ws), streamWsEnd(req, ws), true); - break; - case 'public:local': - streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true); - break; - case 'hashtag': - streamFrom(`timeline:hashtag:${location.query.tag}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); - break; - case 'hashtag:local': - streamFrom(`timeline:hashtag:${location.query.tag}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); - break; - default: - ws.close(); - } - }); + switch(location.query.stream) { + case 'user': + streamFrom(`timeline:${req.accountId}`, req, streamToWs(req, ws), streamWsEnd(req, ws)); + break; + case 'public': + streamFrom('timeline:public', req, streamToWs(req, ws), streamWsEnd(req, ws), true); + break; + case 'public:local': + streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true); + break; + case 'hashtag': + streamFrom(`timeline:hashtag:${location.query.tag}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); + break; + case 'hashtag:local': + streamFrom(`timeline:hashtag:${location.query.tag}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); + break; + default: + ws.close(); + } }); const wsInterval = setInterval(() => { -- GitLab From 3a2003ba863252f305fb32098bcd3f095b10e2ff Mon Sep 17 00:00:00 2001 From: Jack Jennings Date: Mon, 29 May 2017 09:22:22 -0700 Subject: [PATCH 036/295] Extract authorization policy for viewing statuses (#3150) --- Gemfile | 1 + Gemfile.lock | 3 + .../api/activitypub/activities_controller.rb | 4 +- .../api/activitypub/notes_controller.rb | 4 +- app/controllers/api/v1/statuses_controller.rb | 7 +- app/controllers/concerns/authorization.rb | 22 ++++++ app/controllers/media_controller.rb | 7 +- app/controllers/statuses_controller.rb | 7 +- app/controllers/stream_entries_controller.rb | 8 ++- app/models/status.rb | 12 +--- app/policies/status_policy.rb | 20 ++++++ app/services/favourite_service.rb | 4 +- app/services/reblog_service.rb | 4 +- spec/controllers/media_controller_spec.rb | 2 +- spec/models/status_spec.rb | 60 ---------------- spec/policies/status_policy_spec.rb | 70 +++++++++++++++++++ 16 files changed, 155 insertions(+), 80 deletions(-) create mode 100644 app/controllers/concerns/authorization.rb create mode 100644 app/policies/status_policy.rb create mode 100644 spec/policies/status_policy_spec.rb diff --git a/Gemfile b/Gemfile index 811dd1f99f..1246658374 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,7 @@ gem 'nokogiri', '~> 1.7' gem 'oj', '~> 3.0' gem 'ostatus2', '~> 2.0' gem 'ox', '~> 2.5' +gem 'pundit', '~> 1.1' gem 'rabl', '~> 0.13' gem 'rack-attack', '~> 5.0' gem 'rack-cors', '~> 0.4', require: 'rack/cors' diff --git a/Gemfile.lock b/Gemfile.lock index e8c3ba4870..69429c979b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -283,6 +283,8 @@ GEM pry (>= 0.10.4) public_suffix (2.0.5) puma (3.8.2) + pundit (1.1.0) + activesupport (>= 3.0.0) rabl (0.13.1) activesupport (>= 2.3.14) rack (2.0.3) @@ -519,6 +521,7 @@ DEPENDENCIES pkg-config (~> 1.2) pry-rails (~> 0.3) puma (~> 3.8) + pundit (~> 1.1) rabl (~> 0.13) rack-attack (~> 5.0) rack-cors (~> 0.4) diff --git a/app/controllers/api/activitypub/activities_controller.rb b/app/controllers/api/activitypub/activities_controller.rb index ba03738fc9..025ab960e3 100644 --- a/app/controllers/api/activitypub/activities_controller.rb +++ b/app/controllers/api/activitypub/activities_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Api::Activitypub::ActivitiesController < ApiController + include Authorization + # before_action :set_follow, only: [:show_follow] before_action :set_status, only: [:show_status] @@ -8,7 +10,7 @@ class Api::Activitypub::ActivitiesController < ApiController # Show a status in AS2 format, as either an Announce (reblog) or a Create (post) activity. def show_status - return forbidden unless @status.permitted? + authorize @status, :show? if @status.reblog? render :show_status_announce diff --git a/app/controllers/api/activitypub/notes_controller.rb b/app/controllers/api/activitypub/notes_controller.rb index 6489243dc0..ff9383413b 100644 --- a/app/controllers/api/activitypub/notes_controller.rb +++ b/app/controllers/api/activitypub/notes_controller.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true class Api::Activitypub::NotesController < ApiController + include Authorization + before_action :set_status respond_to :activitystreams2 def show - forbidden unless @status.permitted? + authorize @status, :show? end private diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 852ffc3ab1..592540f457 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Api::V1::StatusesController < ApiController + include Authorization + before_action :authorize_if_got_token, except: [:create, :destroy, :reblog, :unreblog, :favourite, :unfavourite, :mute, :unmute] before_action -> { doorkeeper_authorize! :write }, only: [:create, :destroy, :reblog, :unreblog, :favourite, :unfavourite, :mute, :unmute] before_action :require_user!, except: [:show, :context, :card, :reblogged_by, :favourited_by] @@ -130,7 +132,10 @@ class Api::V1::StatusesController < ApiController def set_status @status = Status.find(params[:id]) - raise ActiveRecord::RecordNotFound unless @status.permitted?(current_account) + authorize @status, :show? + rescue Mastodon::NotPermittedError + # Reraise in order to get a 404 instead of a 403 error code + raise ActiveRecord::RecordNotFound end def set_conversation diff --git a/app/controllers/concerns/authorization.rb b/app/controllers/concerns/authorization.rb new file mode 100644 index 0000000000..7828fe48de --- /dev/null +++ b/app/controllers/concerns/authorization.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Authorization + extend ActiveSupport::Concern + include Pundit + + def pundit_user + current_account + end + + def authorize(*) + super + rescue Pundit::NotAuthorizedError + raise Mastodon::NotPermittedError + end + + def authorize_with(user, record, query) + Pundit.authorize(user, record, query) + rescue Pundit::NotAuthorizedError + raise Mastodon::NotPermittedError + end +end diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb index fa1daf012a..f652f5acef 100644 --- a/app/controllers/media_controller.rb +++ b/app/controllers/media_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class MediaController < ApplicationController + include Authorization + before_action :verify_permitted_status def show @@ -14,6 +16,9 @@ class MediaController < ApplicationController end def verify_permitted_status - raise ActiveRecord::RecordNotFound unless media_attachment.status.permitted?(current_account) + authorize media_attachment.status, :show? + rescue Mastodon::NotPermittedError + # Reraise in order to get a 404 instead of a 403 error code + raise ActiveRecord::RecordNotFound end end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index 696bb4f521..59c9d0a87f 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class StatusesController < ApplicationController + include Authorization + layout 'public' before_action :set_account @@ -30,7 +32,10 @@ class StatusesController < ApplicationController @stream_entry = @status.stream_entry @type = @stream_entry.activity_type.downcase - raise ActiveRecord::RecordNotFound unless @status.permitted?(current_account) + authorize @status, :show? + rescue Mastodon::NotPermittedError + # Reraise in order to get a 404 + raise ActiveRecord::RecordNotFound end def check_account_suspension diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb index baff4317a3..314d596190 100644 --- a/app/controllers/stream_entries_controller.rb +++ b/app/controllers/stream_entries_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class StreamEntriesController < ApplicationController + include Authorization + layout 'public' before_action :set_account @@ -42,7 +44,11 @@ class StreamEntriesController < ApplicationController @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id]) @type = @stream_entry.activity_type.downcase - raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil? || (@stream_entry.hidden? && !@stream_entry.activity.permitted?(current_account)) + raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil? + authorize @stream_entry.activity, :show? if @stream_entry.hidden? + rescue Mastodon::NotPermittedError + # Reraise in order to get a 404 + raise ActiveRecord::RecordNotFound end def check_account_suspension diff --git a/app/models/status.rb b/app/models/status.rb index a3dbce9f13..a371083d05 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -113,16 +113,6 @@ class Status < ApplicationRecord private_visibility? || direct_visibility? end - def permitted?(other_account = nil) - if direct_visibility? - account.id == other_account&.id || mentions.where(account: other_account).exists? - elsif private_visibility? - account.id == other_account&.id || other_account&.following?(account) || mentions.where(account: other_account).exists? - else - other_account.nil? || !account.blocking?(other_account) - end - end - def ancestors(account = nil) ids = Rails.cache.fetch("ancestors:#{id}") { (Status.find_by_sql(['WITH RECURSIVE search_tree(id, in_reply_to_id, path) AS (SELECT id, in_reply_to_id, ARRAY[id] FROM statuses WHERE id = ? UNION ALL SELECT statuses.id, statuses.in_reply_to_id, path || statuses.id FROM search_tree JOIN statuses ON statuses.id = search_tree.in_reply_to_id WHERE NOT statuses.id = ANY(path)) SELECT id FROM search_tree ORDER BY path DESC', id]) - [self]).pluck(:id) } find_statuses_from_tree_path(ids, account) @@ -301,7 +291,7 @@ class Status < ApplicationRecord should_filter ||= account&.domain_blocking?(status.account.domain) should_filter ||= account&.muting?(status.account_id) should_filter ||= (status.account.silenced? && !account&.following?(status.account_id)) - should_filter ||= !status.permitted?(account) + should_filter ||= !StatusPolicy.new(account, status).show? should_filter end end diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb new file mode 100644 index 0000000000..658ba6d123 --- /dev/null +++ b/app/policies/status_policy.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class StatusPolicy + attr_reader :account, :status + + def initialize(account, status) + @account = account + @status = status + end + + def show? + if status.direct_visibility? + status.account.id == account&.id || status.mentions.where(account: account).exists? + elsif status.private_visibility? + status.account.id == account&.id || account&.following?(status.account) || status.mentions.where(account: account).exists? + else + account.nil? || !status.account.blocking?(account) + end + end +end diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb index e92aada64f..f27145c961 100644 --- a/app/services/favourite_service.rb +++ b/app/services/favourite_service.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true class FavouriteService < BaseService + include Authorization + # Favourite a status and notify remote user # @param [Account] account # @param [Status] status # @return [Favourite] def call(account, status) - raise Mastodon::NotPermittedError unless status.permitted?(account) + authorize_with account, status, :show? favourite = Favourite.create!(account: account, status: status) diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb index 11446ce28b..9c44b1980e 100644 --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class ReblogService < BaseService + include Authorization include StreamEntryRenderer # Reblog a status and notify its remote author @@ -10,7 +11,8 @@ class ReblogService < BaseService def call(account, reblogged_status) reblogged_status = reblogged_status.reblog if reblogged_status.reblog? - raise Mastodon::NotPermittedError if reblogged_status.direct_visibility? || reblogged_status.private_visibility? || !reblogged_status.permitted?(account) + authorize_with account, reblogged_status, :show? + raise Mastodon::NotPermittedError if reblogged_status.direct_visibility? || reblogged_status.private_visibility? reblog = account.statuses.create!(reblog: reblogged_status, text: '') diff --git a/spec/controllers/media_controller_spec.rb b/spec/controllers/media_controller_spec.rb index 2541df7344..5b03899e4c 100644 --- a/spec/controllers/media_controller_spec.rb +++ b/spec/controllers/media_controller_spec.rb @@ -30,7 +30,7 @@ describe MediaController do it 'raises when not permitted to view' do status = Fabricate(:status) media_attachment = Fabricate(:media_attachment, status: status) - allow_any_instance_of(Status).to receive(:permitted?).and_return(false) + allow_any_instance_of(MediaController).to receive(:authorize).and_raise(ActiveRecord::RecordNotFound) get :show, params: { id: media_attachment.to_param } expect(response).to have_http_status(:missing) diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index d3a66134b2..ec07e61568 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -119,66 +119,6 @@ RSpec.describe Status, type: :model do end end - describe '#permitted?' do - it 'returns true when direct and account is viewer' do - subject.visibility = :direct - expect(subject.permitted?(subject.account)).to be true - end - - it 'returns true when direct and viewer is mentioned' do - subject.visibility = :direct - subject.mentions = [Fabricate(:mention, account: alice)] - - expect(subject.permitted?(alice)).to be true - end - - it 'returns false when direct and viewer is not mentioned' do - viewer = Fabricate(:account) - subject.visibility = :direct - - expect(subject.permitted?(viewer)).to be false - end - - it 'returns true when private and account is viewer' do - subject.visibility = :direct - expect(subject.permitted?(subject.account)).to be true - end - - it 'returns true when private and account is following viewer' do - follow = Fabricate(:follow) - subject.visibility = :private - subject.account = follow.target_account - - expect(subject.permitted?(follow.account)).to be true - end - - it 'returns true when private and viewer is mentioned' do - subject.visibility = :private - subject.mentions = [Fabricate(:mention, account: alice)] - - expect(subject.permitted?(alice)).to be true - end - - it 'returns false when private and viewer is not mentioned or followed' do - viewer = Fabricate(:account) - subject.visibility = :private - - expect(subject.permitted?(viewer)).to be false - end - - it 'returns true when no viewer' do - expect(subject.permitted?).to be true - end - - it 'returns false when viewer is blocked' do - block = Fabricate(:block) - subject.visibility = :private - subject.account = block.target_account - - expect(subject.permitted?(block.account)).to be false - end - end - describe '#ancestors' do let!(:alice) { Fabricate(:account, username: 'alice') } let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb new file mode 100644 index 0000000000..ee7060b989 --- /dev/null +++ b/spec/policies/status_policy_spec.rb @@ -0,0 +1,70 @@ +require 'rails_helper' +require 'pundit/rspec' + +RSpec.describe StatusPolicy, type: :model do + subject { described_class } + + let(:alice) { Fabricate(:account, username: 'alice') } + let(:status) { Fabricate(:status, account: alice) } + + permissions :show? do + it 'grants access when direct and account is viewer' do + status.visibility = :direct + expect(subject).to permit(status.account, status) + end + + it 'grants access when direct and viewer is mentioned' do + status.visibility = :direct + status.mentions = [Fabricate(:mention, account: alice)] + + expect(subject).to permit(alice, status) + end + + it 'denies access when direct and viewer is not mentioned' do + viewer = Fabricate(:account) + status.visibility = :direct + + expect(subject).to_not permit(viewer, status) + end + + it 'grants access when private and account is viewer' do + status.visibility = :direct + + expect(subject).to permit(status.account, status) + end + + it 'grants access when private and account is following viewer' do + follow = Fabricate(:follow) + status.visibility = :private + status.account = follow.target_account + + expect(subject).to permit(follow.account, status) + end + + it 'grants access when private and viewer is mentioned' do + status.visibility = :private + status.mentions = [Fabricate(:mention, account: alice)] + + expect(subject).to permit(alice, status) + end + + it 'denies access when private and viewer is not mentioned or followed' do + viewer = Fabricate(:account) + status.visibility = :private + + expect(subject).to_not permit(viewer, status) + end + + it 'grants access when no viewer' do + expect(subject).to permit(nil, status) + end + + it 'denies access when viewer is blocked' do + block = Fabricate(:block) + status.visibility = :private + status.account = block.target_account + + expect(subject).to_not permit(block.account, status) + end + end +end -- GitLab From e0ada9777006b1d68394fd09afab4c68a4a6529b Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 30 May 2017 01:23:28 +0900 Subject: [PATCH 037/295] Update dependencies of Node.js (#3067) * Update autoprefixer to version 7.1.0 * Update axios to version 0.16.1 * Update babel-cli to version 6.24.1 * Update babel-eslint to version 7.2.3 * Update babel-preset-react to version 6.24.1 * Update coffee-script to version 1.12.6 * Update css-loader to version 0.28.1 * Update express to version 4.15.2 * Update js-yaml to version 3.8.4 * Update mocha to version 3.4.1 * Update jsdom to version 10.1.0 * Update npmlog to version 4.1.0 * Update postcss-smart-import to version 0.7.0 * Update postcss-loader to version 2.0.5 * Update pg to version 6.1.5 * Update prop-types to version 15.5.10 * Update rails-ujs to version 5.1.1 * Update redis to version 2.7.1 * Update sass-loader to version 6.0.5 * Update stringz to version 0.2.0 * Update webpack to version 2.5.1 * Update style-loader to version 0.17.0 * Update sinon to version 2.2.0 * Update react-motion to version 0.5.0 * Update react-notification to version 6.7.0 * Update react-redux-loading-bar to version 2.9.0 * Update react-intl to version 2.3.0 * Update redux-immutable to version 4.0.0 * Update reselect to version 3.0.1 * Update react-toggle to version 3.0.1 * Update react-simple-dropdown to version 3.0.0 * Update react-router to version 3.0.5 * Update react-router-scroll to version 0.4.2 * Update react-toggle to version 4.0.1 * yarn upgrade --- package.json | 65 +- spec/javascript/setup.js | 6 +- yarn.lock | 2324 +++++++++++++++++++------------------- 3 files changed, 1184 insertions(+), 1211 deletions(-) diff --git a/package.json b/package.json index 84e96fca42..c2b2c58669 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,9 @@ }, "dependencies": { "array-includes": "^3.0.3", - "autoprefixer": "^6.7.7", - "axios": "^0.15.3", - "babel-cli": "^6.23.0", + "autoprefixer": "^7.1.0", + "axios": "^0.16.1", + "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-loader": "7.x", "babel-plugin-lodash": "^3.2.11", @@ -36,45 +36,46 @@ "babel-plugin-transform-react-remove-prop-types": "^0.4.5", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.4.0", - "babel-preset-react": "^6.11.1", + "babel-preset-react": "^6.24.1", "classnames": "^2.2.5", "coffee-loader": "^0.7.3", - "coffee-script": "^1.12.5", + "coffee-script": "^1.12.6", "compression-webpack-plugin": "^0.4.0", - "css-loader": "^0.28.0", + "css-loader": "^0.28.1", "dotenv": "^4.0.0", "emojione": "^2.2.7", "emojione-picker": "^2.2.1", "es6-symbol": "^3.1.1", "escape-html": "^1.0.3", - "express": "^4.14.1", + "express": "^4.15.2", "extract-text-webpack-plugin": "^2.1.0", "file-loader": "^0.11.1", "font-awesome": "^4.7.0", "glob": "^7.1.1", + "history": "^3.3.0", "http-link-header": "^0.8.0", "immutable": "^3.8.1", "intersection-observer": "^0.2.1", "intl": "^1.2.5", "intl-relativeformat": "^1.3.0", "is-nan": "^1.2.1", - "js-yaml": "^3.8.3", + "js-yaml": "^3.8.4", "lodash": "^4.17.4", "mark-loader": "^0.1.6", "marky": "^1.2.0", "mkdirp": "^0.5.1", "node-sass": "^4.5.2", - "npmlog": "^4.0.2", + "npmlog": "^4.1.0", "object-assign": "^4.1.1", "path-complete-extname": "^0.1.0", - "pg": "^6.1.2", - "postcss-loader": "^1.3.3", - "postcss-smart-import": "^0.6.12", + "pg": "^6.1.5", + "postcss-loader": "^2.0.5", + "postcss-smart-import": "^0.7.0", "precss": "^1.4.0", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "punycode": "^2.1.0", "rails-erb-loader": "^5.0.0", - "rails-ujs": "^5.1.0", + "rails-ujs": "^5.1.1", "react": "^15.5.4", "react-addons-perf": "^15.4.2", "react-addons-shallow-compare": "^15.5.2", @@ -82,30 +83,30 @@ "react-imageloader": "^2.1.0", "react-immutable-proptypes": "^2.1.0", "react-immutable-pure-component": "^0.0.4", - "react-intl": "^2.1.5", - "react-motion": "^0.4.5", - "react-notification": "^6.6.0", + "react-intl": "^2.3.0", + "react-motion": "^0.5.0", + "react-notification": "^6.7.0", "react-redux": "^5.0.4", - "react-redux-loading-bar": "2.4.1", - "react-router": "^2.8.0", - "react-router-scroll": "^0.3.2", - "react-simple-dropdown": "^1.1.4", + "react-redux-loading-bar": "^2.9.0", + "react-router": "^3.0.5", + "react-router-scroll": "^0.4.2", + "react-simple-dropdown": "^3.0.0", "react-textarea-autosize": "^5.0.6", - "react-toggle": "^2.1.1", - "redis": "^2.6.5", + "react-toggle": "^4.0.1", + "redis": "^2.7.1", "redux": "^3.6.0", - "redux-immutable": "^3.1.0", + "redux-immutable": "^4.0.0", "redux-thunk": "^2.2.0", "requestidlecallback": "^0.3.0", - "reselect": "^2.5.4", + "reselect": "^3.0.1", "rimraf": "^2.6.1", - "sass-loader": "^6.0.3", - "stringz": "^0.1.2", + "sass-loader": "^6.0.5", + "stringz": "^0.2.0", "style-loader": "^0.16.1", "throng": "^4.0.0", "uuid": "^3.0.1", "uws": "^0.14.5", - "webpack": "^2.4.1", + "webpack": "^2.5.1", "webpack-bundle-analyzer": "^2.8.2", "webpack-manifest-plugin": "^1.1.0", "webpack-merge": "^4.1.0", @@ -113,20 +114,20 @@ }, "devDependencies": { "@kadira/storybook": "^2.35.3", - "babel-eslint": "^7.2.2", + "babel-eslint": "^7.2.3", "chai": "^3.5.0", "chai-enzyme": "^0.6.1", "enzyme": "^2.8.2", "eslint": "^3.19.0", "eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-react": "^6.10.3", - "jsdom": "^9.11.0", + "jsdom": "^10.1.0", "minimist": "^1.2.0", - "mocha": "^3.2.0", + "mocha": "^3.4.1", "react-intl-translations-manager": "^5.0.0", "react-storybook-addon-intl": "^0.1.0", "react-test-renderer": "^15.5.4", - "sinon": "^1.17.6", + "sinon": "^2.2.0", "webpack-dev-server": "^2.4.5" }, "optionalDependencies": { diff --git a/spec/javascript/setup.js b/spec/javascript/setup.js index 0d07f74d88..24f21db723 100644 --- a/spec/javascript/setup.js +++ b/spec/javascript/setup.js @@ -1,12 +1,8 @@ +import { jsdom } from 'jsdom/lib/old-api'; import chai from 'chai'; import chaiEnzyme from 'chai-enzyme'; chai.use(chaiEnzyme()); -/** - * http://airbnb.io/enzyme/docs/guides/jsdom.html - */ -var jsdom = require('jsdom').jsdom; - var exposedProperties = ['window', 'navigator', 'document']; global.document = jsdom(''); diff --git a/yarn.lock b/yarn.lock index c155f1a7e9..e8cccedba8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,8 +7,8 @@ resolved "https://registry.yarnpkg.com/@kadira/react-split-pane/-/react-split-pane-1.4.7.tgz#6d753d4a9fe62fe82056e323a6bcef7f026972b5" "@kadira/storybook-addon-actions@^1.0.2": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@kadira/storybook-addon-actions/-/storybook-addon-actions-1.1.1.tgz#5053485583fadea413710d6405454dc168a7efc7" + version "1.1.3" + resolved "https://registry.yarnpkg.com/@kadira/storybook-addon-actions/-/storybook-addon-actions-1.1.3.tgz#e76b2d3215cdf6bba8f153a14a7302d6737fc8ac" dependencies: deep-equal "^1.0.1" json-stringify-safe "^5.0.1" @@ -19,8 +19,8 @@ resolved "https://registry.yarnpkg.com/@kadira/storybook-addon-links/-/storybook-addon-links-1.0.1.tgz#566136a8020b60f82f146ef37d93b0c86de969d8" "@kadira/storybook-addons@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@kadira/storybook-addons/-/storybook-addons-1.5.0.tgz#f92cd2059282a9b4b8bdac4bef28269f85e40be4" + version "1.6.1" + resolved "https://registry.yarnpkg.com/@kadira/storybook-addons/-/storybook-addons-1.6.1.tgz#e84923d298b38c7c1231ddebc219dfb87b2858a6" "@kadira/storybook-channel-postmsg@^2.0.1": version "2.0.1" @@ -104,8 +104,8 @@ abab@^1.0.3: resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d" abbrev@1: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" accepts@~1.3.3: version "1.3.3" @@ -115,8 +115,8 @@ accepts@~1.3.3: negotiator "0.6.1" acorn-dynamic-import@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.1.tgz#23f671eb6e650dab277fef477c321b1178a8cca2" + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" dependencies: acorn "^4.0.3" @@ -137,16 +137,16 @@ acorn@^3.0.0, acorn@^3.0.4: resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" acorn@^4.0.3, acorn@^4.0.4: - version "4.0.11" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" airbnb-js-shims@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.0.1.tgz#7d5a7d772c8c6fdeb624ea3cef62506091b180b5" + version "1.1.1" + resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.1.1.tgz#27224f0030f244e6570442ed1020772c1434aec2" dependencies: array-includes "^3.0.2" es5-shim "^4.5.9" @@ -161,9 +161,16 @@ ajv-keywords@^1.0.0, ajv-keywords@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" -ajv@^4.11.2, ajv@^4.7.0: - version "4.11.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.3.tgz#ce30bdb90d1254f762c75af915fb3a63e7183d22" +ajv@^4.11.2, ajv@^4.7.0, ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.0.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.1.3.tgz#423d1c302c61e617081b30ca05f595ec51408e33" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -181,8 +188,8 @@ alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" amdefine@>=0.0.4: - version "1.0.0" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.0.tgz#fd17474700cb5cc9c2b709f0be9d23ce3c198c33" + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" @@ -193,8 +200,8 @@ ansi-html@0.0.7: resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" ansi-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-styles@^2.2.1: version "2.2.1" @@ -216,15 +223,15 @@ ap@~0.2.0: resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" aproba@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + version "1.1.1" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" are-we-there-yet@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" dependencies: delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" + readable-stream "^2.0.6" argparse@^1.0.7: version "1.0.9" @@ -245,8 +252,8 @@ arr-diff@^2.0.0: arr-flatten "^1.0.1" arr-flatten@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + version "1.0.3" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" array-equal@^1.0.0: version "1.0.0" @@ -297,8 +304,8 @@ asap@~2.0.3: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" asn1.js@^4.0.0: - version "4.8.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.8.1.tgz#3949b7f5fd1e8bedc13be3abebf477f93490c810" + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" dependencies: bn.js "^4.0.0" inherits "^2.0.1" @@ -308,14 +315,14 @@ asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" -assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" @@ -330,9 +337,9 @@ ast-types-flow@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" -ast-types@0.9.5: - version "0.9.5" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.5.tgz#1a660a09945dbceb1f9c9cbb715002617424e04a" +ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-each@^1.0.0: version "1.0.1" @@ -350,13 +357,13 @@ async@^0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -async@^1.3.0, async@^1.4.2, async@^1.5.2: +async@^1.3.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.2, async@^2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" +async@^2.1.2, async@^2.1.4, async@^2.1.5: + version "2.4.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7" dependencies: lodash "^4.14.0" @@ -364,7 +371,7 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" -autoprefixer@^6.3.1, autoprefixer@^6.3.7, autoprefixer@^6.7.7: +autoprefixer@^6.3.1, autoprefixer@^6.3.7: version "6.7.7" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" dependencies: @@ -375,27 +382,38 @@ autoprefixer@^6.3.1, autoprefixer@^6.3.7, autoprefixer@^6.7.7: postcss "^5.2.16" postcss-value-parser "^3.2.3" +autoprefixer@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.1.tgz#97bc854c7d0b979f8d6489de547a0d17fb307f6d" + dependencies: + browserslist "^2.1.3" + caniuse-lite "^1.0.30000670" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^6.0.1" + postcss-value-parser "^3.2.3" + aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" aws4@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -axios@^0.15.3: - version "0.15.3" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.15.3.tgz#2c9d638b2e191a08ea1d6cc988eadd6ba5bdc053" +axios@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.1.tgz#c0b6d26600842384b8f509e57111f0d2df8223ca" dependencies: - follow-redirects "1.0.0" + follow-redirects "^1.2.3" -babel-cli@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.23.0.tgz#52ff946a2b0f64645c35e7bd5eea267aa0948c0f" +babel-cli@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.24.1.tgz#207cd705bba61489b2ea41b5312341cf6aca2283" dependencies: - babel-core "^6.23.0" + babel-core "^6.24.1" babel-polyfill "^6.23.0" - babel-register "^6.23.0" + babel-register "^6.24.1" babel-runtime "^6.22.0" commander "^2.8.1" convert-source-map "^1.1.0" @@ -418,7 +436,7 @@ babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.0" -babel-core@^6.11.4, babel-core@^6.23.0, babel-core@^6.24.1: +babel-core@^6.11.4, babel-core@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" dependencies: @@ -442,14 +460,14 @@ babel-core@^6.11.4, babel-core@^6.23.0, babel-core@^6.24.1: slash "^1.0.0" source-map "^0.5.0" -babel-eslint@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.2.tgz#0da2cbe6554fd0fb069f19674f2db2f9c59270ff" +babel-eslint@^7.2.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" dependencies: babel-code-frame "^6.22.0" babel-traverse "^6.23.1" babel-types "^6.23.0" - babylon "^6.16.1" + babylon "^6.17.0" babel-generator@^6.24.1: version "6.24.1" @@ -464,22 +482,21 @@ babel-generator@^6.24.1: source-map "^0.5.0" trim-right "^1.0.1" -babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" dependencies: - babel-helper-explode-assignable-expression "^6.22.0" + babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" -babel-helper-builder-react-jsx@^6.8.0: - version "6.9.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.9.0.tgz#a633978d669c4c9dcad716cc577ee3e0bb8ae723" +babel-helper-builder-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.24.1.tgz#0ad7917e33c8d751e646daca4e77cc19377d2cbc" dependencies: - babel-runtime "^6.9.0" - babel-types "^6.9.0" + babel-runtime "^6.22.0" + babel-types "^6.24.1" esutils "^2.0.0" - lodash "^4.2.0" babel-helper-call-delegate@^6.24.1, babel-helper-call-delegate@^6.8.0: version "6.24.1" @@ -499,15 +516,15 @@ babel-helper-define-map@^6.24.1: babel-types "^6.24.1" lodash "^4.2.0" -babel-helper-explode-assignable-expression@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" dependencies: babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.24.1, babel-helper-function-name@^6.8.0: +babel-helper-function-name@^6.24.1, babel-helper-function-name@^6.8.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: @@ -538,25 +555,25 @@ babel-helper-optimise-call-expression@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-helper-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" +babel-helper-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" lodash "^4.2.0" -babel-helper-remap-async-to-generator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" dependencies: - babel-helper-function-name "^6.22.0" + babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.24.1: +babel-helper-replace-supers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" dependencies: @@ -583,10 +600,11 @@ babel-loader@7.x: mkdirp "^0.5.1" babel-loader@^6.2.4: - version "6.2.5" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.5.tgz#576d548520689a5e6b70c65b85d76af1ffedd005" + version "6.4.1" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" dependencies: - loader-utils "^0.2.11" + find-cache-dir "^0.1.1" + loader-utils "^0.2.16" mkdirp "^0.5.1" object-assign "^4.0.1" @@ -647,13 +665,13 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" -babel-plugin-syntax-flow@^6.3.13, babel-plugin-syntax-flow@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.13.0.tgz#9af0cd396087bf7677053e1afa52f206c0416f17" +babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.13.0.tgz#e741ff3992c578310be45c571bcd90a2f9c5586e" + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" @@ -663,11 +681,11 @@ babel-plugin-syntax-trailing-function-commas@^6.13.0, babel-plugin-syntax-traili version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" -babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1, babel-plugin-transform-async-to-generator@^6.8.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: - babel-helper-remap-async-to-generator "^6.22.0" + babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" @@ -700,7 +718,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0, babel-plugin-trans dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.22.0, babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.6.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1, babel-plugin-transform-es2015-block-scoping@^6.6.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" dependencies: @@ -710,7 +728,7 @@ babel-plugin-transform-es2015-block-scoping@^6.22.0, babel-plugin-transform-es20 babel-types "^6.24.1" lodash "^4.2.0" -babel-plugin-transform-es2015-classes@^6.22.0, babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.6.0: +babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1, babel-plugin-transform-es2015-classes@^6.6.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: @@ -724,12 +742,12 @@ babel-plugin-transform-es2015-classes@^6.22.0, babel-plugin-transform-es2015-cla babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.3.13: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1, babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" - babel-template "^6.22.0" + babel-template "^6.24.1" babel-plugin-transform-es2015-destructuring@6.16.0: version "6.16.0" @@ -743,12 +761,12 @@ babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es20 dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.6.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1, babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0, babel-plugin-transform-es2015-for-of@^6.6.0: version "6.23.0" @@ -756,13 +774,13 @@ babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for- dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.3.13: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1, babel-plugin-transform-es2015-function-name@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: - babel-helper-function-name "^6.22.0" + babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-literals@^6.22.0, babel-plugin-transform-es2015-literals@^6.3.13: version "6.22.0" @@ -770,15 +788,7 @@ babel-plugin-transform-es2015-literals@^6.22.0, babel-plugin-transform-es2015-li dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-modules-amd@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.24.1, babel-plugin-transform-es2015-modules-amd@^6.8.0: +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1, babel-plugin-transform-es2015-modules-amd@^6.8.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: @@ -786,7 +796,7 @@ babel-plugin-transform-es2015-modules-amd@^6.24.1, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-commonjs@^6.22.0, babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.6.0: +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.6.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" dependencies: @@ -795,7 +805,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.22.0, babel-plugin-transform-e babel-template "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-es2015-modules-systemjs@^6.22.0, babel-plugin-transform-es2015-modules-systemjs@^6.23.0: +babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: @@ -803,7 +813,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-e babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015-modules-umd@^6.22.0, babel-plugin-transform-es2015-modules-umd@^6.23.0: +babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: @@ -811,11 +821,11 @@ babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.3.13: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1, babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: - babel-helper-replace-supers "^6.22.0" + babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@6.17.0: @@ -829,7 +839,7 @@ babel-plugin-transform-es2015-parameters@6.17.0: babel-traverse "^6.16.0" babel-types "^6.16.0" -babel-plugin-transform-es2015-parameters@^6.22.0, babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.6.0: +babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1, babel-plugin-transform-es2015-parameters@^6.6.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: @@ -840,12 +850,12 @@ babel-plugin-transform-es2015-parameters@^6.22.0, babel-plugin-transform-es2015- babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.3.13: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1, babel-plugin-transform-es2015-shorthand-properties@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-spread@^6.22.0, babel-plugin-transform-es2015-spread@^6.3.13: version "6.22.0" @@ -853,13 +863,13 @@ babel-plugin-transform-es2015-spread@^6.22.0, babel-plugin-transform-es2015-spre dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.3.13: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1, babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: - babel-helper-regex "^6.22.0" + babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-template-literals@^6.22.0, babel-plugin-transform-es2015-template-literals@^6.6.0: version "6.22.0" @@ -873,28 +883,28 @@ babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es20 dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.3.13: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1, babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: - babel-helper-regex "^6.22.0" + babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" regexpu-core "^2.0.0" -babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1, babel-plugin-transform-exponentiation-operator@^6.8.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-flow-strip-types@^6.3.13: - version "6.14.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.14.0.tgz#35ceb03f8770934044bab1a76f7e4ee0aa9220f9" +babel-plugin-transform-flow-strip-types@^6.22.0, babel-plugin-transform-flow-strip-types@^6.3.13: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" dependencies: - babel-plugin-syntax-flow "^6.8.0" - babel-runtime "^6.0.0" + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" babel-plugin-transform-object-rest-spread@6.16.0: version "6.16.0" @@ -916,11 +926,11 @@ babel-plugin-transform-react-constant-elements@6.9.1: dependencies: babel-runtime "^6.9.1" -babel-plugin-transform-react-display-name@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.8.0.tgz#f7a084977383d728bdbdc2835bba0159577f660e" +babel-plugin-transform-react-display-name@^6.23.0, babel-plugin-transform-react-display-name@^6.3.13: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz#4398910c358441dc4cef18787264d0412ed36b37" dependencies: - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" babel-plugin-transform-react-jsx-self@6.11.0: version "6.11.0" @@ -950,13 +960,13 @@ babel-plugin-transform-react-jsx-source@^6.22.0, babel-plugin-transform-react-js babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-react-jsx@^6.3.13: - version "6.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.8.0.tgz#94759942f70af18c617189aa7f3593f1644a71ab" +babel-plugin-transform-react-jsx@^6.24.1, babel-plugin-transform-react-jsx@^6.3.13: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" dependencies: - babel-helper-builder-react-jsx "^6.8.0" + babel-helper-builder-react-jsx "^6.24.1" babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.0.0" + babel-runtime "^6.22.0" babel-plugin-transform-react-remove-prop-types@^0.4.5: version "0.4.5" @@ -972,11 +982,11 @@ babel-plugin-transform-regenerator@6.16.1: babel-types "^6.16.0" private "~0.1.5" -babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.6.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" +babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1, babel-plugin-transform-regenerator@^6.6.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" dependencies: - regenerator-transform "0.9.8" + regenerator-transform "0.9.11" babel-plugin-transform-runtime@6.15.0: version "6.15.0" @@ -1039,8 +1049,8 @@ babel-preset-env@0.0.6: browserslist "^1.4.0" babel-preset-env@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" + version "1.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.5.1.tgz#d2eca6af179edf27cdc305a84820f601b456dd0b" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -1069,50 +1079,57 @@ babel-preset-env@^1.4.0: babel-plugin-transform-es2015-unicode-regex "^6.22.0" babel-plugin-transform-exponentiation-operator "^6.22.0" babel-plugin-transform-regenerator "^6.22.0" - browserslist "^1.4.0" + browserslist "^2.1.2" invariant "^2.2.2" + semver "^5.3.0" babel-preset-es2015@^6.16.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835" + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-transform-es2015-arrow-functions "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.22.0" - babel-plugin-transform-es2015-classes "^6.22.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.22.0" - babel-plugin-transform-es2015-modules-systemjs "^6.22.0" - babel-plugin-transform-es2015-modules-umd "^6.22.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.22.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" babel-plugin-transform-es2015-template-literals "^6.22.0" babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" babel-preset-es2016@^6.16.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.22.0.tgz#b061aaa3983d40c9fbacfa3743b5df37f336156c" + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.24.1.tgz#f900bf93e2ebc0d276df9b8ab59724ebfd959f8b" dependencies: - babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.24.1" babel-preset-es2017@^6.16.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.22.0.tgz#de2f9da5a30c50d293fb54a0ba15d6ddc573f0f2" + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.24.1.tgz#597beadfb9f7f208bcfd8a12e9b2b29b8b2f14d1" dependencies: babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-async-to-generator "^6.24.1" + +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" babel-preset-latest@6.16.0: version "6.16.0" @@ -1140,7 +1157,7 @@ babel-preset-react-app@^1.0.0: babel-preset-react "6.16.0" babel-runtime "6.11.6" -babel-preset-react@6.16.0, babel-preset-react@^6.11.1: +babel-preset-react@6.16.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.16.0.tgz#aa117d60de0928607e343c4828906e4661824316" dependencies: @@ -1152,17 +1169,16 @@ babel-preset-react@6.16.0, babel-preset-react@^6.11.1: babel-plugin-transform-react-jsx-self "^6.11.0" babel-plugin-transform-react-jsx-source "^6.3.13" -babel-register@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.23.0.tgz#c9aa3d4cca94b51da34826c4a0f9e08145d74ff3" +babel-preset-react@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" dependencies: - babel-core "^6.23.0" - babel-runtime "^6.22.0" - core-js "^2.4.0" - home-or-tmp "^2.0.0" - lodash "^4.2.0" - mkdirp "^0.5.1" - source-map-support "^0.4.2" + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" babel-register@^6.24.1: version "6.24.1" @@ -1183,21 +1199,14 @@ babel-runtime@6.11.6: core-js "^2.4.0" regenerator-runtime "^0.9.5" -babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.23.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2: +babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-runtime@^6.2.0, babel-runtime@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.10.0" - -babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.24.1: +babel-template@^6.16.0, babel-template@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" dependencies: @@ -1207,7 +1216,7 @@ babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.24.1: babylon "^6.11.0" lodash "^4.2.0" -babel-traverse@^6.16.0, babel-traverse@^6.22.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1: +babel-traverse@^6.16.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" dependencies: @@ -1221,7 +1230,7 @@ babel-traverse@^6.16.0, babel-traverse@^6.22.0, babel-traverse@^6.23.1, babel-tr invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.16.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.9.0: +babel-types@^6.16.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" dependencies: @@ -1230,9 +1239,9 @@ babel-types@^6.16.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23 lodash "^4.2.0" to-fast-properties "^1.0.1" -babylon@^6.11.0, babylon@^6.15.0, babylon@^6.16.1: - version "6.16.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" +babylon@^6.11.0, babylon@^6.15.0, babylon@^6.17.0: + version "6.17.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.1.tgz#17f14fddf361b695981fe679385e4f1c01ebd86f" babylon@~5.8.3: version "5.8.38" @@ -1244,7 +1253,7 @@ backoff@^2.4.1: dependencies: precond "0.2" -balanced-match@0.1.0, balanced-match@~0.1.0: +balanced-match@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" @@ -1265,8 +1274,8 @@ batch@0.5.3: resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" bcrypt-pbkdf@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" @@ -1275,8 +1284,8 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" binary-extensions@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.7.0.tgz#6c1610db163abfb34edfe42fa423343a1e01185d" + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" block-stream@*: version "0.0.9" @@ -1298,9 +1307,9 @@ boom@2.x.x: dependencies: hoek "2.x.x" -brace-expansion@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" +brace-expansion@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" dependencies: balanced-match "^0.4.1" concat-map "0.0.1" @@ -1314,8 +1323,8 @@ braces@^1.8.2: repeat-element "^1.1.2" brorand@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5" + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" browser-stdout@1.3.0: version "1.3.0" @@ -1361,8 +1370,8 @@ browserify-rsa@^4.0.0: randombytes "^2.0.1" browserify-sign@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.0.tgz#10773910c3c206d5420a46aad8694f820b85968f" + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" dependencies: bn.js "^4.1.1" browserify-rsa "^4.0.0" @@ -1378,14 +1387,21 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^1.4.0, browserslist@^1.7.6: +browserslist@^1.3.6, browserslist@^1.4.0, browserslist@^1.5.2, browserslist@^1.7.6: version "1.7.7" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" dependencies: caniuse-db "^1.0.30000639" electron-to-chromium "^1.2.7" -buffer-shims@^1.0.0: +browserslist@^2.1.2, browserslist@^2.1.3: + version "2.1.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.1.4.tgz#cc526af4a1312b7d2e05653e56d0c8ab70c0e053" + dependencies: + caniuse-lite "^1.0.30000670" + electron-to-chromium "^1.3.11" + +buffer-shims@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" @@ -1409,9 +1425,9 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" -builtin-status-codes@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-2.0.0.tgz#6f22003baacf003ccd287afe6872151fddc58579" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" bytes@2.3.0: version "2.3.0" @@ -1446,17 +1462,30 @@ camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" -caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000664" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000664.tgz#e16316e5fdabb9c7209b2bf0744ffc8a14201f22" +caniuse-api@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" + dependencies: + browserslist "^1.3.6" + caniuse-db "^1.0.30000529" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: + version "1.0.30000671" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000671.tgz#9f071bbc7b96994638ccbaf47829d58a1577a8ed" + +caniuse-lite@^1.0.30000670: + version "1.0.30000671" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000671.tgz#c206c2f1a1feb34de46064407c4356818389bf1e" case-sensitive-paths-webpack-plugin@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-1.1.4.tgz#8aaedd5699a86cac2b34cf40d9b4145758978472" -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" center-align@^0.1.1: version "0.1.3" @@ -1512,8 +1541,8 @@ cheerio@^0.22.0: lodash.some "^4.4.0" chokidar@^1.0.0, chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -1526,7 +1555,7 @@ chokidar@^1.0.0, chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1: optionalDependencies: fsevents "^1.0.0" -cipher-base@^1.0.0, cipher-base@^1.0.1: +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" dependencies: @@ -1537,12 +1566,12 @@ circular-json@^0.3.1: resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" clap@^1.0.9: - version "1.1.1" - resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.1.tgz#a8a93e0bfb7581ac199c4f001a5525a724ce696d" + version "1.1.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.3.tgz#b3bd36e93dd4cbfb395a3c26896352445265c05b" dependencies: chalk "^1.1.3" -classnames@^2.1.2, classnames@^2.2.3, classnames@^2.2.5, classnames@~2.2: +classnames@^2.1.2, classnames@^2.2.3, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" @@ -1591,16 +1620,14 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" coa@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" + version "1.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.2.tgz#2ba9fec3b4aa43d7a49d7e6c3561e92061b6bcec" dependencies: q "^1.1.2" code-point-at@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.0.1.tgz#1104cd34f9b5b45d3eba88f1babc1924e1ce35fb" - dependencies: - number-is-nan "^1.0.0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" coffee-loader@^0.7.3: version "0.7.3" @@ -1608,21 +1635,23 @@ coffee-loader@^0.7.3: dependencies: loader-utils "^1.0.2" -coffee-script@^1.12.5: - version "1.12.5" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.5.tgz#809f4585419112bbfe46a073ad7543af18c27346" +coffee-script@^1.12.6: + version "1.12.6" + resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.6.tgz#285a3f7115689065064d6bf9ef4572db66695cbf" collapse-white-space@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.2.tgz#9c463fb9c6d190d2dcae21a356a01bcae9eeef6d" color-convert@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.5.0.tgz#7a2b4efb4488df85bca6443cb038b7100fbe7de1" + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" -color-name@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d" color-string@^0.3.0: version "0.3.0" @@ -1631,8 +1660,8 @@ color-string@^0.3.0: color-name "^1.0.0" color@^0.11.0: - version "0.11.3" - resolved "https://registry.yarnpkg.com/color/-/color-0.11.3.tgz#4bad1d0d52499dd00dbd6f0868442467e49394e6" + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" dependencies: clone "^1.0.2" color-convert "^1.3.0" @@ -1663,10 +1692,10 @@ commander@2.9.0, commander@^2.8.1, commander@^2.9.0: graceful-readlink ">= 1.0.0" common-tags@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.3.1.tgz#35c51f09b08e5a991371638ed4d047341926611b" + version "1.4.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" dependencies: - babel-runtime "^6.9.1" + babel-runtime "^6.18.0" commondir@^1.0.1: version "1.0.1" @@ -1707,12 +1736,12 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" concat-stream@^1.4.7, concat-stream@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" configstore@^2.0.0: version "2.1.0" @@ -1759,8 +1788,8 @@ content-type@~1.0.2: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" convert-source-map@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + version "1.5.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" cookie-signature@1.0.6: version "1.0.6" @@ -1783,9 +1812,10 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" cosmiconfig@^2.1.0, cosmiconfig@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.1.1.tgz#817f2c2039347a1e9bf7d090c0923e53f749ca82" + version "2.1.3" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.1.3.tgz#952771eb0dddc1cb3fa2f6fbe51a522e93b3ee0a" dependencies: + is-directory "^0.3.1" js-yaml "^3.4.3" minimist "^1.2.0" object-assign "^4.1.0" @@ -1800,27 +1830,32 @@ create-ecdh@^4.0.0: bn.js "^4.1.0" elliptic "^6.0.0" -create-hash@^1.1.0, create-hash@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.2.tgz#51210062d7bb7479f6c65bb41a92208b1d61abad" +create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" dependencies: cipher-base "^1.0.1" inherits "^2.0.1" - ripemd160 "^1.0.0" - sha.js "^2.3.6" + ripemd160 "^2.0.0" + sha.js "^2.4.0" -create-hmac@^1.1.0, create-hmac@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.4.tgz#d3fb4ba253eb8b3f56e39ea2fbcb8af747bd3170" +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" dependencies: + cipher-base "^1.0.3" create-hash "^1.1.0" inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" -create-react-class@^15.5.1: - version "15.5.2" - resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.2.tgz#6a8758348df660b88326a0e764d569f274aad681" +create-react-class@^15.5.1, create-react-class@^15.5.2, create-react-class@^15.5.3: + version "15.5.3" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.3.tgz#fb0f7cae79339e9a179e194ef466efa3923820fe" dependencies: fbjs "^0.8.9" + loose-envify "^1.3.1" object-assign "^4.1.1" cross-spawn@^3.0.0: @@ -1874,8 +1909,8 @@ css-color-names@0.0.4: resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" css-loader@^0.26.1: - version "0.26.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.26.2.tgz#a9cd4c2b1a559b45d8efc04fc311ab5d2aaccb9d" + version "0.26.4" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.26.4.tgz#b61e9e30db94303e6ffc892f10ecd09ad025a1fd" dependencies: babel-code-frame "^6.11.0" css-selector-tokenizer "^0.7.0" @@ -1890,9 +1925,9 @@ css-loader@^0.26.1: postcss-modules-values "^1.1.0" source-list-map "^0.1.7" -css-loader@^0.28.0: - version "0.28.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.0.tgz#417cfa9789f8cde59a30ccbf3e4da7a806889bad" +css-loader@^0.28.1: + version "0.28.2" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.2.tgz#0ff48e1d6013afcdb585d46c1e61a5fcd036404e" dependencies: babel-code-frame "^6.11.0" css-selector-tokenizer "^0.7.0" @@ -1905,6 +1940,7 @@ css-loader@^0.28.0: postcss-modules-local-by-default "^1.0.1" postcss-modules-scope "^1.0.0" postcss-modules-values "^1.1.0" + postcss-value-parser "^3.3.0" source-list-map "^0.1.7" css-select@~1.2.0: @@ -1916,14 +1952,6 @@ css-select@~1.2.0: domutils "1.5.1" nth-check "~1.0.1" -css-selector-tokenizer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152" - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" - css-selector-tokenizer@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" @@ -1941,8 +1969,8 @@ cssesc@^0.1.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" "cssnano@>=2.6.1 <4": - version "3.7.7" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.7.7.tgz#27fac611380c6a49d6f722c0537e5a988a785010" + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" dependencies: autoprefixer "^6.3.1" decamelize "^1.1.2" @@ -1977,9 +2005,9 @@ cssesc@^0.1.0: postcss-value-parser "^3.2.3" postcss-zindex "^2.0.1" -csso@~2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/csso/-/csso-2.2.1.tgz#51fbb5347e50e81e6ed51668a48490ae6fe2afe2" +csso@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" dependencies: clap "^1.0.9" source-map "^0.5.3" @@ -2011,8 +2039,8 @@ damerau-levenshtein@^1.0.0: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" dashdash@^1.12.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.0.tgz#29e486c5418bf0f356034a993d51686a33e84141" + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" dependencies: assert-plus "^1.0.0" @@ -2020,11 +2048,11 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.2.0, debug@^2.1.1, debug@^2.2.0, debug@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" +debug@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" dependencies: - ms "0.7.1" + ms "0.7.2" debug@2.6.7: version "2.6.7" @@ -2032,10 +2060,22 @@ debug@2.6.7: dependencies: ms "2.0.0" +debug@^2.1.1, debug@^2.2.0, debug@^2.4.5, debug@^2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" + debug@~0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" +debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2050,13 +2090,13 @@ deep-eql@^0.1.3: dependencies: type-detect "0.1.1" -deep-equal@^1.0.0, deep-equal@^1.0.1: +deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" deep-extend@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" deep-is@~0.1.3: version "0.1.3" @@ -2120,9 +2160,13 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" -diff@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" +detect-node@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" + +diff@3.2.0, diff@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" diffie-hellman@^5.0.0: version "5.0.2" @@ -2146,9 +2190,9 @@ doctrine@^2.0.0: esutils "^2.0.2" isarray "^1.0.0" -dom-helpers@^2.4.0, "dom-helpers@^2.4.0 || ^3.0.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367" +"dom-helpers@^2.4.0 || ^3.0.0", dom-helpers@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" @@ -2170,8 +2214,8 @@ domelementtype@~1.1.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" domhandler@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" + version "2.4.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" dependencies: domelementtype "1" @@ -2207,8 +2251,8 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" editions@^1.1.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.1.tgz#008425f64dc1401db45ec110e06aa602562419c0" + version "1.3.3" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" ee-first@1.1.1: version "1.1.1" @@ -2218,22 +2262,25 @@ ejs@^2.5.6: version "2.5.6" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88" -electron-to-chromium@^1.2.7: - version "1.3.8" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6" +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.11: + version "1.3.11" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.11.tgz#744761df1d67b492b322ce9aa0aba5393260eb61" element-class@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/element-class/-/element-class-0.2.2.tgz#9d3bbd0767f9013ef8e1c8ebe722c1402a60050e" elliptic@^6.0.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48" + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" dependencies: bn.js "^4.4.0" brorand "^1.0.1" hash.js "^1.0.0" + hmac-drbg "^1.0.0" inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" emoji-regex@^6.1.0: version "6.4.2" @@ -2312,12 +2359,12 @@ errno@^0.1.3: prr "~0.0.0" error-ex@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" -es-abstract@^1.3.2, es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.7.0: +es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c" dependencies: @@ -2335,8 +2382,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.15" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" + version "0.10.21" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.21.tgz#19a725f9e51d0300bbc1e8e821109fd9daf55925" dependencies: es6-iterator "2" es6-symbol "~3.1" @@ -2375,8 +2422,8 @@ es6-set@~0.1.5: event-emitter "~0.3.5" es6-shim@^0.35.1: - version "0.35.1" - resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.1.tgz#a23524009005b031ab4a352ac196dfdfd1144ab7" + version "0.35.3" + resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.3.tgz#9bfb7363feffff87a6cdb6cd93e405ec3c4b6f26" es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: version "3.1.1" @@ -2484,8 +2531,8 @@ eslint@^3.19.0: user-home "^2.0.0" espree@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.1.tgz#28a83ab4aaed71ed8fe0f5efe61b76a05c13c4d2" + version "3.4.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" dependencies: acorn "^5.0.1" acorn-jsx "^3.0.0" @@ -2527,10 +2574,6 @@ esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" - etag@~1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" @@ -2615,44 +2658,13 @@ express@^4.13.3, express@^4.15.2: utils-merge "1.0.0" vary "~1.1.1" -express@^4.14.1: - version "4.14.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33" - dependencies: - accepts "~1.3.3" - array-flatten "1.1.1" - content-disposition "0.5.2" - content-type "~1.0.2" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "~2.2.0" - depd "~1.1.0" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.7.0" - finalhandler "0.5.1" - fresh "0.3.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.1" - path-to-regexp "0.1.7" - proxy-addr "~1.1.3" - qs "6.2.0" - range-parser "~1.2.0" - send "0.14.2" - serve-static "~1.11.2" - type-is "~1.6.14" - utils-merge "1.0.0" - vary "~1.1.0" - -extend@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" +extend@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" @@ -2670,8 +2682,8 @@ extsprintf@1.0.2: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" fast-levenshtein@~2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fastparse@^1.1.1: version "1.1.1" @@ -2728,8 +2740,8 @@ file-loader@^0.9.0: loader-utils "~0.2.5" filename-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.5.9: version "3.5.10" @@ -2745,16 +2757,6 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd" - dependencies: - debug "~2.2.0" - escape-html "~1.0.3" - on-finished "~2.3.0" - statuses "~1.3.1" - unpipe "~1.0.0" - finalhandler@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" @@ -2791,29 +2793,33 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -flatten@1.0.2, flatten@^1.0.2: +flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -follow-redirects@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37" +follow-redirects@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.3.tgz#01abaeca85e3609837d9fcda3167a7e42fdaca21" dependencies: - debug "^2.2.0" + debug "^2.4.5" font-awesome@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" -for-in@^0.1.3, for-in@^0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" -for-own@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.3, for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: - for-in "^0.1.5" + for-in "^1.0.1" foreach@^2.0.5: version "2.0.5" @@ -2824,18 +2830,18 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" form-data@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" mime-types "^2.1.12" -formatio@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.1.1.tgz#5ed3ccd636551097383465d996199100e86161e9" +formatio@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb" dependencies: - samsam "~1.1" + samsam "1.x" forwarded@~0.1.0: version "0.1.0" @@ -2845,10 +2851,6 @@ fraction.js@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.0.tgz#73974e2f8b51ef709536d624cc90782e2bb61274" -fresh@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" - fresh@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" @@ -2887,13 +2889,13 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@*, fsevents@^1.0.0: - version "1.0.14" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.14.tgz#558e8cc38643d8ef40fe45158486d0d25758eee4" + version "1.1.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff" dependencies: nan "^2.3.0" node-pre-gyp "^0.6.29" -fstream-ignore@~1.0.5: +fstream-ignore@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" dependencies: @@ -2901,9 +2903,9 @@ fstream-ignore@~1.0.5: inherits "2" minimatch "^3.0.0" -fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -2923,16 +2925,16 @@ function.prototype.name@^1.0.0: is-callable "^1.1.2" fuse.js@^2.2.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.5.0.tgz#98295c2ac1684edbba22250d7049cb6f033e95ce" + version "2.7.4" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9" fuzzysearch@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/fuzzysearch/-/fuzzysearch-1.0.3.tgz#dffc80f6d6b04223f2226aa79dd194231096d008" -gauge@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2941,7 +2943,6 @@ gauge@~2.7.1: signal-exit "^3.0.0" string-width "^1.0.1" strip-ansi "^3.0.1" - supports-color "^0.2.0" wide-align "^1.1.0" gaze@^1.0.0: @@ -2960,9 +2961,9 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" -generic-pool@2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.4.2.tgz#886bc5bf0beb7db96e81bcbba078818de5a62683" +generic-pool@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.4.3.tgz#780c36f69dfad05a5a045dd37be7adca11a4f6ff" get-caller-file@^1.0.1: version "1.0.2" @@ -2973,8 +2974,8 @@ get-stdin@^4.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" getpass@^0.1.1: - version "0.1.6" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" dependencies: assert-plus "^1.0.0" @@ -2991,9 +2992,9 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95" +glob@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3013,19 +3014,19 @@ glob@^5.0.3: path-is-absolute "^1.0.0" glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@~7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.2" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" globals@^9.0.0, globals@^9.14.0: - version "9.14.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + version "9.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" globby@^3.0.1: version "3.0.1" @@ -3063,9 +3064,9 @@ gonzales-pe@^4.0.3: dependencies: minimist "1.1.x" -graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.1.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.9.tgz#baacba37d19d11f9d146d3578bc99958c3787e29" +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" "graceful-readlink@>= 1.0.0": version "1.0.1" @@ -3081,18 +3082,20 @@ gzip-size@^3.0.0: dependencies: duplexer "^0.1.1" -handle-thing@^1.2.4: +handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" + ajv "^4.9.1" + har-schema "^1.0.5" has-ansi@^2.0.0: version "2.0.0" @@ -3114,7 +3117,13 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" -hash.js@^1.0.0: +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573" dependencies: @@ -3129,14 +3138,22 @@ hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" -history@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/history/-/history-2.1.2.tgz#4aa2de897a0e4867e4539843be6ecdb2986bfdec" +history@^3.0.0, history@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c" dependencies: - deep-equal "^1.0.0" - invariant "^2.0.0" - query-string "^3.0.0" - warning "^2.0.0" + invariant "^2.2.1" + loose-envify "^1.2.0" + query-string "^4.2.2" + warning "^3.0.0" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" hoek@2.x.x: version "2.16.3" @@ -3154,8 +3171,8 @@ home-or-tmp@^2.0.0: os-tmpdir "^1.0.1" hosted-git-info@^2.1.4: - version "2.1.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + version "2.4.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" hpack.js@^2.1.6: version "2.1.6" @@ -3177,8 +3194,8 @@ html-encoding-sniffer@^1.0.1: whatwg-encoding "^1.0.1" html-entities@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" html@^1.0.0: version "1.0.0" @@ -3197,11 +3214,11 @@ htmlparser2@^3.9.1: inherits "^2.0.1" readable-stream "^2.0.2" -http-deceiver@^1.2.4: +http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" -http-errors@~1.5.0, http-errors@~1.5.1: +http-errors@~1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" dependencies: @@ -3254,17 +3271,17 @@ iconv-lite@0.4.13, iconv-lite@~0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" -icss-replace-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.2.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd" + version "3.3.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" immutable@^3.8.1: version "3.8.1" @@ -3293,13 +3310,13 @@ indexof@0.0.1: resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflight@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.5.tgz#db3204cd5a9de2e6cd890b85c6e2f66bcf4f620a" + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -3334,25 +3351,25 @@ interpret@^0.6.4: resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" interpret@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + version "1.0.3" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" intersection-observer@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.2.1.tgz#cb55175f4eebef6436d957a7d1774d39a9248e5e" -intl: - version "1.2.5" - resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde" - intl-format-cache@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.0.5.tgz#b484cefcb9353f374f25de389a3ceea1af18d7c9" -intl-messageformat-parser@1.2.0, intl-messageformat-parser@^1.2.0: +intl-messageformat-parser@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.2.0.tgz#5906b7f953ab7470e0dc8549097b648b991892ff" +intl-messageformat-parser@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.3.0.tgz#c5d26ffb894c7d9c2b9fa444c67f417ab2594268" + intl-messageformat@1.3.0, intl-messageformat@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-1.3.0.tgz#f7d926aded7a3ab19b2dc601efd54e99a4bd4eae" @@ -3365,6 +3382,10 @@ intl-relativeformat@^1.3.0: dependencies: intl-messageformat "1.3.0" +intl@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde" + invariant@2.x.x, invariant@^2.0.0, invariant@^2.1.1, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" @@ -3375,17 +3396,13 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ipaddr.js@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" - ipaddr.js@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" is-absolute-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.0.0.tgz#9c4b20b0e5c0cbef9a479a367ede6f991679f359" + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" is-arrayish@^0.2.1: version "0.2.1" @@ -3397,9 +3414,9 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" -is-buffer@^1.0.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" +is-buffer@^1.0.2, is-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" is-builtin-module@^1.0.0: version "1.0.0" @@ -3415,9 +3432,13 @@ is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + is-dom@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.5.tgz#3b4f9eaa7a6014c010b276c645cad85bb3c7b1fd" + version "1.0.9" + resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d" is-dotfile@^1.0.0: version "1.0.2" @@ -3469,9 +3490,9 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" +is-my-json-valid@^2.10.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3533,8 +3554,10 @@ is-property@^1.0.0: resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" is-regex@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.3.tgz#0d55182bddf9f2fde278220aec3a75642c908637" + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" is-regexp@^1.0.0: version "1.0.0" @@ -3555,8 +3578,8 @@ is-subset@^0.1.1: resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" is-svg@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.0.1.tgz#f93ab3bf1d6bbca30e9753cd3485b1300eebc013" + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" dependencies: html-comment-regex "^1.1.0" @@ -3572,13 +3595,17 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" -isexe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^1.0.0: version "1.0.2" @@ -3607,39 +3634,35 @@ jodid25519@^1.0.0: dependencies: jsbn "~0.1.0" -js-base64@^2.1.9: +js-base64@^2.1.8, js-base64@^2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" -js-tokens@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.3.tgz#14e56eb68c8f1a92c43d59f5014ec29dc20f2ae1" - js-tokens@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" -js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" +js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.8.4: + version "3.8.4" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" dependencies: argparse "^1.0.7" esprima "^3.1.1" -js-yaml@~3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" dependencies: argparse "^1.0.7" esprima "^2.6.0" jsbn@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" -jsdom@^9.11.0: - version "9.11.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.11.0.tgz#a95b0304e521a2ca5a63c6ea47bf7708a7a84591" +jsdom@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-10.1.0.tgz#7765e00fd5c3567f34985a1c86ff466a61dacc6a" dependencies: abab "^1.0.3" acorn "^4.0.4" @@ -3652,7 +3675,9 @@ jsdom@^9.11.0: html-encoding-sniffer "^1.0.1" nwmatcher ">= 1.3.9 < 2.0.0" parse5 "^1.5.1" + pn "^1.0.0" request "^2.79.0" + request-promise-native "^1.0.3" sax "^1.2.1" symbol-tree "^3.2.1" tough-cookie "^2.3.2" @@ -3691,11 +3716,7 @@ json3@3.3.2, json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" -json5@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.0.tgz#9b20715b026cbe3778fd769edccd822d8332a5b2" - -json5@^0.5.1: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -3710,26 +3731,25 @@ jsonify@~0.0.0: resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" jsonpointer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jsprim@^1.2.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" dependencies: + assert-plus "1.0.0" extsprintf "1.0.2" json-schema "0.2.3" verror "1.3.6" jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4: - version "1.4.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.0.tgz#5afe38868f56bc8cc7aeaef0100ba8c75bd12591" - dependencies: - object-assign "^4.1.0" + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" keycode@^2.1.1: - version "2.1.7" - resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.7.tgz#7b9255919f6cff562b09a064d222dca70b020f5c" + version "2.1.9" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" kind-of@^2.0.1: version "2.0.1" @@ -3738,10 +3758,10 @@ kind-of@^2.0.1: is-buffer "^1.0.2" kind-of@^3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: - is-buffer "^1.0.2" + is-buffer "^1.1.5" klaw@^1.0.0: version "1.3.1" @@ -3784,16 +3804,16 @@ loader-runner@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" -loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.7, loader-utils@~0.2.5: - version "0.2.16" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" +loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.7, loader-utils@~0.2.5: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" dependencies: big.js "^3.1.3" emojis-list "^2.0.0" json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.1, loader-utils@^1.1.0: +loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.x: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" dependencies: @@ -3801,17 +3821,9 @@ loader-utils@^1.0.1, loader-utils@^1.1.0: emojis-list "^2.0.0" json5 "^0.5.0" -loader-utils@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.0.2.tgz#a9f923c865a974623391a8602d031137fad74830" - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - lodash-es@^4.2.0, lodash-es@^4.2.1: - version "4.16.4" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.16.4.tgz#4dc3e2cf33a8c343028aa7f7e06d1c9697042599" + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" lodash._baseassign@^3.0.0: version "3.2.0" @@ -3828,18 +3840,6 @@ lodash._basecreate@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" -lodash._bindcallback@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - -lodash._createassigner@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" - dependencies: - lodash._bindcallback "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.restparam "^3.0.0" - lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -3848,15 +3848,7 @@ lodash._isiterateecall@^3.0.0: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" -lodash.assign@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" - dependencies: - lodash._baseassign "^3.0.0" - lodash._createassigner "^3.0.0" - lodash.keys "^3.0.0" - -lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: +lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" @@ -3900,10 +3892,6 @@ lodash.foreach@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" -lodash.indexof@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/lodash.indexof/-/lodash.indexof-4.0.5.tgz#53714adc2cddd6ed87638f893aa9b6c24e31ef3c" - lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -3924,6 +3912,10 @@ lodash.map@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + lodash.merge@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" @@ -3944,10 +3936,6 @@ lodash.reject@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - lodash.some@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" @@ -3960,29 +3948,27 @@ lodash.tail@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" -lodash@4.x.x, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash@4.x.x, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" lodash@~4.16.4: - version "4.16.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.4.tgz#01ce306b9bad1319f2a5528674f88297aeb70127" + version "4.16.6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" -lolex@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31" +lolex@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.2.0.tgz#69a65aad3de542cf4ee0f4fe74e8e33c709ccb0f" - dependencies: - js-tokens "^1.0.1" - -loose-envify@^1.3.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -4027,14 +4013,12 @@ marky@^1.2.0: resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.0.tgz#9617ed647bbbea8f45d19526da33dec70606df42" math-expression-evaluator@^1.2.14: - version "1.2.14" - resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz#39511771ed9602405fba9affff17eb4d2a3843ab" - dependencies: - lodash.indexof "^4.0.5" + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" mathjs@^3.11.5: - version "3.12.1" - resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-3.12.1.tgz#a165abdbc6b55da1ec600b85311e2962850551b5" + version "3.13.1" + resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-3.13.1.tgz#591ad98c80e87c5d5997eb626137b1efad44ae71" dependencies: complex.js "2.0.1" decimal.js "7.1.1" @@ -4117,27 +4101,13 @@ miller-rabin@^4.0.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-db@~1.26.0: - version "1.26.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" - -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: - version "2.1.14" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" - dependencies: - mime-db "~1.26.0" - -mime-types@~2.1.15: +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: version "2.1.15" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: mime-db "~1.27.0" -mime@1.2.x: - version "1.2.11" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" - -mime@1.3.4, mime@^1.3.4: +mime@1.3.4, mime@1.3.x, mime@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -4145,11 +4115,15 @@ minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@~3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: - brace-expansion "^1.0.0" + brace-expansion "^1.1.7" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" @@ -4177,19 +4151,19 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi minimist "0.0.8" mobx@^2.3.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mobx/-/mobx-2.6.0.tgz#0ae83a20488b92d10d4ca326e18fe78a5ab7cb36" + version "2.7.0" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-2.7.0.tgz#cf3d82d18c0ca7f458d8f2a240817b3dc7e54a01" -mocha@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.2.0.tgz#7dc4f45e5088075171a68896814e6ae9eb7a85e3" +mocha@^3.4.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.4.2.tgz#d0ef4d332126dbf18d0d640c9b382dd48be97594" dependencies: browser-stdout "1.3.0" commander "2.9.0" - debug "2.2.0" - diff "1.4.0" + debug "2.6.0" + diff "3.2.0" escape-string-regexp "1.0.5" - glob "7.0.5" + glob "7.1.1" growl "1.9.2" json3 "3.3.2" lodash.create "3.1.1" @@ -4213,8 +4187,12 @@ mute-stream@0.0.5: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" nan@^2.0.0, nan@^2.3.0, nan@^2.3.2: - version "2.5.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" + version "2.6.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" + +native-promise-only@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" natural-compare@^1.4.0: version "1.4.0" @@ -4231,15 +4209,15 @@ node-dir@^0.1.10: minimatch "^3.0.2" node-fetch@^1.0.1: - version "1.6.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + version "1.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.0.tgz#3ff6c56544f9b7fb00682338bb55ee6f54a8a0ef" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-gyp@^3.3.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.0.tgz#7474f63a3a0501161dda0b6341f022f14c423fa6" + version "3.6.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.1.tgz#19561067ff185464aded478212681f47fd578cbc" dependencies: fstream "^1.0.0" glob "^7.0.3" @@ -4312,22 +4290,22 @@ node-libs-browser@^2.0.0: vm-browserify "0.0.4" node-pre-gyp@^0.6.29, node-pre-gyp@^0.6.4: - version "0.6.30" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.30.tgz#64d3073a6f573003717ccfe30c89023297babba1" + version "0.6.34" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7" dependencies: - mkdirp "~0.5.0" - nopt "~3.0.1" - npmlog "4.x" - rc "~1.1.0" - request "2.x" - rimraf "~2.5.0" - semver "~5.3.0" - tar "~2.2.0" - tar-pack "~3.1.0" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "^2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" node-sass@^4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.2.tgz#4012fa2bd129b1d6365117e88d9da0500d99da64" + version "4.5.3" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.3.tgz#d09c9d1179641239d1b97ffc6231fdcec53e1568" dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -4357,15 +4335,22 @@ node-zopfli@^2.0.0: nan "^2.0.0" node-pre-gyp "^0.6.4" -"nopt@2 || 3", nopt@~3.0.1: +"nopt@2 || 3": version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.3.5" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + version "2.3.8" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4373,29 +4358,31 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: validate-npm-package-license "^3.0.1" normalize-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" normalize-url@^1.4.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.6.1.tgz#a9f254fa065bbc2934461c0c09423815976155a2" + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" dependencies: object-assign "^4.0.1" prepend-http "^1.0.0" query-string "^4.1.0" sort-keys "^1.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@4.x, npmlog@^4.0.0, npmlog@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" - gauge "~2.7.1" + gauge "~2.7.3" set-blocking "~2.0.0" nth-check@~1.0.1: @@ -4413,8 +4400,8 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" "nwmatcher@>= 1.3.9 < 2.0.0": - version "1.3.9" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a" + version "1.4.0" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.0.tgz#b4389362170e7ef9798c3c7716d80ebc0106fccf" oauth-sign@~0.8.1: version "0.8.2" @@ -4445,12 +4432,12 @@ object.assign@^4.0.4: object-keys "^1.0.10" object.entries@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.3.tgz#f42cc75363a4f9aa7037bcfb3bab3be4ffc78027" + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" dependencies: - define-properties "^1.1.1" - es-abstract "^1.3.2" - function-bind "^1.0.2" + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" has "^1.0.1" object.getownpropertydescriptors@^2.0.3: @@ -4461,22 +4448,22 @@ object.getownpropertydescriptors@^2.0.3: es-abstract "^1.5.1" object.omit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.0.tgz#868597333d54e60662940bb458605dd6ae12fe94" + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: - for-own "^0.1.3" + for-own "^0.1.4" is-extendable "^0.1.1" object.values@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.3.tgz#a7774ba050893fe6a5d5958acd05823e0f426bef" + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" dependencies: - define-properties "^1.1.1" - es-abstract "^1.3.2" - function-bind "^1.0.2" + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" has "^1.0.1" -obuf@^1.0.0, obuf@^1.1.0: +obuf@^1.0.0, obuf@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" @@ -4490,18 +4477,12 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0: +once@^1.3.0, once@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" -once@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -4559,9 +4540,9 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@0, osenv@^0.1.0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217" +osenv@0, osenv@^0.1.0, osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -4574,17 +4555,17 @@ output-file-sync@^1.1.0: mkdirp "^0.5.1" object-assign "^4.1.0" -packet-reader@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.2.0.tgz#819df4d010b82d5ea5671f8a1a3acf039bcd7700" +packet-reader@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.3.1.tgz#cd62e60af8d7fea8a705ec4ff990871c46871f27" pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" parse-asn1@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.0.0.tgz#35060f6d5015d37628c770f4e091a0b5a278bc23" + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -4611,7 +4592,7 @@ parse5@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" -parseurl@~1.3.0, parseurl@~1.3.1: +parseurl@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" @@ -4645,6 +4626,12 @@ path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -4658,24 +4645,32 @@ pbkdf2-compat@2.0.1: resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" pbkdf2@^3.0.3: - version "3.0.9" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693" + version "3.0.12" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2" dependencies: - create-hmac "^1.1.2" + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" -performance-now@^0.2.0, performance-now@~0.2.0: +performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + pg-connection-string@0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" pg-pool@1.*: - version "1.6.0" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.6.0.tgz#2e300199927b6d7db6be71e2e3435dddddf07b41" + version "1.7.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.7.1.tgz#421105cb7469979dcc48d6fc4fe3fe4659437437" dependencies: - generic-pool "2.4.2" + generic-pool "2.4.3" object-assign "4.1.0" pg-types@1.*: @@ -4688,12 +4683,12 @@ pg-types@1.*: postgres-date "~1.0.0" postgres-interval "~1.0.0" -pg@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/pg/-/pg-6.1.2.tgz#2c896a7434502e2b938c100fc085b4e974a186db" +pg@^6.1.5: + version "6.2.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-6.2.3.tgz#8988b7c69a1875a997d73b92036c42590b5f8024" dependencies: buffer-writer "1.0.1" - packet-reader "0.2.0" + packet-reader "0.3.1" pg-connection-string "0.1.3" pg-pool "1.*" pg-types "1.*" @@ -4701,8 +4696,8 @@ pg@^6.1.2: semver "4.3.2" pgpass@1.x: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.1.tgz#0de8b5bef993295d90a7e17d976f568dcd25d49f" + version "1.0.2" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.2.tgz#2a7bb41b6065b67907e91da1b07c1847c877b306" dependencies: split "^1.0.0" @@ -4740,6 +4735,10 @@ pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" + podda@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/podda/-/podda-1.2.2.tgz#15b0edbd334ade145813343f5ecf9c10a71cf500" @@ -4785,16 +4784,16 @@ postcss-color-function@^2.0.0: postcss-value-parser "^3.3.0" postcss-colormin@^2.1.8: - version "2.2.1" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.1.tgz#dc5421b6ae6f779ef6bfd47352b94abe59d0316b" + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" dependencies: colormin "^1.0.5" postcss "^5.0.13" postcss-value-parser "^3.2.3" postcss-convert-values@^2.3.4: - version "2.4.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.4.1.tgz#45dce4d4e33b7d967b97a4d937f270ea98d2fe7a" + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" dependencies: postcss "^5.0.11" postcss-value-parser "^3.1.2" @@ -4827,8 +4826,8 @@ postcss-discard-comments@^2.0.4: postcss "^5.0.14" postcss-discard-duplicates@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.1.tgz#5fae3f1a71df3e19cffb37309d1a7dba56c4589c" + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" dependencies: postcss "^5.0.4" @@ -4845,10 +4844,9 @@ postcss-discard-overridden@^0.1.1: postcss "^5.0.16" postcss-discard-unused@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.1.tgz#5d021f021a6ed6cec7310d4603794a75ddd53232" + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" dependencies: - flatten "1.0.2" postcss "^5.0.14" uniqs "^2.0.0" @@ -4865,7 +4863,7 @@ postcss-filter-plugins@^2.0.0: postcss "^5.0.4" uniqid "^4.0.0" -postcss-load-config@^1.0.0, postcss-load-config@^1.2.0: +postcss-load-config@^1.0.0, postcss-load-config@^1.x: version "1.2.0" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a" dependencies: @@ -4897,14 +4895,14 @@ postcss-loader@1.1.0: postcss "^5.2.5" postcss-load-config "^1.0.0" -postcss-loader@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-1.3.3.tgz#a621ea1fa29062a83972a46f54486771301916eb" +postcss-loader@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.0.5.tgz#c19d3e8b83eb1ac316f5621ef4c0ef5b3d1b8b3a" dependencies: - loader-utils "^1.0.2" - object-assign "^4.1.1" - postcss "^5.2.15" - postcss-load-config "^1.2.0" + loader-utils "^1.x" + postcss "^6.x" + postcss-load-config "^1.x" + schema-utils "^0.x" postcss-media-minmax@^2.1.0: version "2.1.2" @@ -4921,16 +4919,19 @@ postcss-merge-idents@^2.1.5: postcss-value-parser "^3.1.1" postcss-merge-longhand@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.1.tgz#ff59b5dec6d586ce2cea183138f55c5876fa9cdc" + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" dependencies: postcss "^5.0.4" postcss-merge-rules@^2.0.3: - version "2.0.10" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.0.10.tgz#54b360be804e7e69a5c7222635247b92a3569e9b" + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" postcss "^5.0.4" + postcss-selector-parser "^2.2.2" vendors "^1.0.0" postcss-message-helpers@^2.0.0: @@ -4946,15 +4947,15 @@ postcss-minify-font-values@^1.0.2: postcss-value-parser "^3.0.2" postcss-minify-gradients@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.3.tgz#09d228148c942fa8126679de9ff7738b54919fe3" + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" dependencies: postcss "^5.0.12" - postcss-value-parser "^3.1.3" + postcss-value-parser "^3.3.0" postcss-minify-params@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.0.5.tgz#82d602643b8616a61fb3634d7ede0289836d67f9" + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" dependencies: alphanum-sort "^1.0.1" postcss "^5.0.2" @@ -4962,10 +4963,11 @@ postcss-minify-params@^1.0.4: uniqs "^2.0.0" postcss-minify-selectors@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.0.5.tgz#4e1f966fb49c95266804016ba9a3c6645bb601e0" + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" dependencies: alphanum-sort "^1.0.2" + has "^1.0.1" postcss "^5.0.14" postcss-selector-parser "^2.0.0" @@ -4978,31 +4980,31 @@ postcss-mixins@^2.1.0: postcss-simple-vars "^1.0.1" postcss-modules-extract-imports@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz#8fb3fef9a6dd0420d3f6d4353cf1ff73f2b2a341" + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" dependencies: - postcss "^5.0.4" + postcss "^6.0.1" postcss-modules-local-by-default@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz#29a10673fa37d19251265ca2ba3150d9040eb4ce" + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" dependencies: - css-selector-tokenizer "^0.6.0" - postcss "^5.0.4" + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" postcss-modules-scope@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz#ff977395e5e06202d7362290b88b1e8cd049de29" + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" dependencies: - css-selector-tokenizer "^0.6.0" - postcss "^5.0.4" + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" postcss-modules-values@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz#f0e7d476fe1ed88c5e4c7f97533a3e772ad94ca1" + version "1.3.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" dependencies: - icss-replace-symbols "^1.0.2" - postcss "^5.0.14" + icss-replace-symbols "^1.1.0" + postcss "^6.0.1" postcss-nested@^1.0.0: version "1.0.1" @@ -5017,14 +5019,14 @@ postcss-nesting@^2.0.6: postcss "^5.0.19" postcss-normalize-charset@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.0.tgz#2fbd30e12248c442981d31ea2484d46fd0628970" + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" dependencies: postcss "^5.0.5" postcss-normalize-url@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.7.tgz#6bd90d0a4bc5a1df22c26ea65c53257dc3829f4e" + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" dependencies: is-absolute-url "^2.0.0" normalize-url "^1.4.0" @@ -5032,8 +5034,8 @@ postcss-normalize-url@^3.0.7: postcss-value-parser "^3.2.3" postcss-ordered-values@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz#be8b511741fab2dac8e614a2302e9d10267b0771" + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" dependencies: postcss "^5.0.4" postcss-value-parser "^3.0.1" @@ -5057,22 +5059,23 @@ postcss-property-lookup@^1.1.3: tcomb "^2.5.1" postcss-reduce-idents@^2.2.2: - version "2.3.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.3.0.tgz#a697b52953ed6825ffea404e26a4f105d8b8d569" + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" dependencies: postcss "^5.0.4" postcss-value-parser "^3.0.2" postcss-reduce-initial@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.0.tgz#8f739b938289ef2e48936d7101783e4741ca9bbb" + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" dependencies: postcss "^5.0.4" postcss-reduce-transforms@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.3.tgz#fc193e435a973c10f9801c74700a830f79643343" + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" dependencies: + has "^1.0.1" postcss "^5.0.8" postcss-value-parser "^3.0.1" @@ -5084,11 +5087,11 @@ postcss-sass@^0.1.0: mathjs "^3.11.5" postcss "^5.2.6" -postcss-scss@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-0.4.1.tgz#ad771b81f0f72f5f4845d08aa60f93557653d54c" +postcss-scss@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-1.0.0.tgz#4957013097973dfd5bd9b1ad8a6dc13456a5d1ba" dependencies: - postcss "^5.2.13" + postcss "^6.0.1" postcss-selector-matches@^2.0.0: version "2.0.5" @@ -5104,9 +5107,9 @@ postcss-selector-not@^2.0.0: balanced-match "^0.2.0" postcss "^5.0.0" -postcss-selector-parser@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.1.tgz#fdbf696103b12b0a64060e5610507f410491f7c8" +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" dependencies: flatten "^1.0.2" indexes-of "^1.0.1" @@ -5118,25 +5121,25 @@ postcss-simple-vars@^1.0.1: dependencies: postcss "^5.0.13" -postcss-smart-import@^0.6.12: - version "0.6.12" - resolved "https://registry.yarnpkg.com/postcss-smart-import/-/postcss-smart-import-0.6.12.tgz#6bd50846547383d15332206615265b87b4a6ae89" +postcss-smart-import@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/postcss-smart-import/-/postcss-smart-import-0.7.2.tgz#3d37bd5e7501614ba3c809a1b2fe418b26d9c631" dependencies: babel-runtime "^6.23.0" lodash "^4.17.4" object-assign "^4.1.1" - postcss "^5.2.17" + postcss "^6.0.1" postcss-sass "^0.1.0" - postcss-scss "^0.4.1" + postcss-scss "^1.0.0" postcss-value-parser "^3.3.0" promise-each "^2.2.0" read-cache "^1.0.0" resolve "^1.3.3" - sugarss "^0.2.0" + sugarss "^1.0.0" postcss-svgo@^2.1.1: - version "2.1.5" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.5.tgz#46fc0363f01bab6a36a9abb01c229fcc45363094" + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" dependencies: is-svg "^2.0.0" postcss "^5.0.14" @@ -5151,18 +5154,19 @@ postcss-unique-selectors@^2.0.2: postcss "^5.0.4" uniqs "^2.0.0" -postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.1.3, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" postcss-zindex@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.1.1.tgz#ea3fbe656c9738aa8729e2ee96ec2a46089b720f" + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" dependencies: + has "^1.0.1" postcss "^5.0.4" uniqs "^2.0.0" -postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.13, postcss@^5.2.15, postcss@^5.2.16, postcss@^5.2.17, postcss@^5.2.4, postcss@^5.2.5, postcss@^5.2.6: +postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16, postcss@^5.2.17, postcss@^5.2.5, postcss@^5.2.6: version "5.2.17" resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.17.tgz#cf4f597b864d65c8a492b2eabe9d706c879c388b" dependencies: @@ -5171,6 +5175,14 @@ postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0. source-map "^0.5.6" supports-color "^3.2.3" +postcss@^6.0.0, postcss@^6.0.1, postcss@^6.x: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.1.tgz#000dbd1f8eef217aa368b9a212c5fc40b2a8f3f2" + dependencies: + chalk "^1.1.3" + source-map "^0.5.6" + supports-color "^3.2.3" + postgres-array@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-1.0.2.tgz#8e0b32eb03bf77a5c0a7851e0441c169a256a238" @@ -5227,16 +5239,16 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" private@^0.1.6, private@~0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + version "0.1.7" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" process@^0.11.0: - version "0.11.9" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" progress@^1.1.8: version "1.1.8" @@ -5254,18 +5266,12 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.0.0, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7: - version "15.5.8" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.8.tgz#6b7b2e141083be38c8595aa51fc55775c7199394" +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7: + version "15.5.10" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" dependencies: fbjs "^0.8.9" - -proxy-addr@~1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" - dependencies: - forwarded "~0.1.0" - ipaddr.js "1.2.0" + loose-envify "^1.3.1" proxy-addr@~1.1.4: version "1.1.4" @@ -5305,30 +5311,16 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" q@^1.1.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" - -qs@6.2.0, qs@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + version "1.5.0" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@6.4.0, qs@^6.2.0: +qs@6.4.0, qs@^6.1.0, qs@^6.2.0, qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" -qs@~6.3.0: - version "6.3.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.1.tgz#918c0b3bcd36679772baf135b1acb4c1651ed79d" - -query-string@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-3.0.3.tgz#ae2e14b4d05071d4e9b9eb4873c35b0dcd42e638" - dependencies: - strict-uri-encode "^1.0.0" - -query-string@^4.1.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.2.3.tgz#9f27273d207a25a8ee4c7b8c74dcd45d556db822" +query-string@^4.1.0, query-string@^4.2.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" dependencies: object-assign "^4.1.0" strict-uri-encode "^1.0.0" @@ -5345,26 +5337,30 @@ querystringify@0.0.x: version "0.0.4" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" +querystringify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" + raf@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.3.0.tgz#93845eeffc773f8129039f677f80a36044eee2c3" + version "3.3.2" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.3.2.tgz#0c13be0b5b49b46f76d6669248d527cf2b02fe27" dependencies: - performance-now "~0.2.0" + performance-now "^2.1.0" rails-erb-loader@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/rails-erb-loader/-/rails-erb-loader-5.0.0.tgz#33fcfbae3fd4584801283c4d5bc1195ae7b56723" + version "5.0.1" + resolved "https://registry.yarnpkg.com/rails-erb-loader/-/rails-erb-loader-5.0.1.tgz#d044251851e38259f971105e66b8f43ef3488897" dependencies: loader-utils "^1.1.0" lodash.defaults "^4.2.0" -rails-ujs@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/rails-ujs/-/rails-ujs-5.1.0.tgz#23ff5ce4bf21e09b33c4d6d7f8d1a51af05edde7" +rails-ujs@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/rails-ujs/-/rails-ujs-5.1.1.tgz#0d6e660533141f1ac352830b31c5bfe1b58f79aa" randomatic@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b" + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" dependencies: is-number "^2.0.2" kind-of "^3.0.2" @@ -5377,14 +5373,14 @@ range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" -rc@~1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" +rc@^1.1.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" dependencies: deep-extend "~0.4.0" ini "~1.3.0" minimist "^1.2.0" - strip-json-comments "~1.0.4" + strip-json-comments "~2.0.1" react-addons-perf@^15.4.2: version "15.4.2" @@ -5393,13 +5389,6 @@ react-addons-perf@^15.4.2: fbjs "^0.8.4" object-assign "^4.1.0" -react-addons-pure-render-mixin@>=0.14.0: - version "15.4.2" - resolved "https://registry.yarnpkg.com/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.4.2.tgz#a8433c71c45e2368503721921dc47bdaf1fbabcd" - dependencies: - fbjs "^0.8.4" - object-assign "^4.1.0" - react-addons-shallow-compare@>=0.14.0, react-addons-shallow-compare@^15.5.2: version "15.5.2" resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.5.2.tgz#7cb0ee7acc8d7c93fcc202df0bf47ba916a7bdad" @@ -5408,10 +5397,10 @@ react-addons-shallow-compare@>=0.14.0, react-addons-shallow-compare@^15.5.2: object-assign "^4.1.0" react-docgen@^2.12.1: - version "2.13.0" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-2.13.0.tgz#7fcc4a3104ea8d4fd428383ba38df11166837be9" + version "2.15.0" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-2.15.0.tgz#11aced462256e4862b14e6af6e46bdcefacb28bb" dependencies: - async "^1.4.2" + async "^2.1.4" babel-runtime "^6.9.2" babylon "~5.8.3" commander "^2.9.0" @@ -5464,9 +5453,10 @@ react-immutable-pure-component@^0.0.4: react-dom "^15.4.2" react-inspector@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-1.1.0.tgz#8d55bb94ffc9fd3982a222eb257dbe9cdd4f1b87" + version "1.1.2" + resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-1.1.2.tgz#192bc54f2be44f9fa0f29f183386f7f6e380f5ec" dependencies: + babel-runtime "^6.9.2" is-dom "^1.0.5" react-intl-translations-manager@^5.0.0: @@ -5478,9 +5468,9 @@ react-intl-translations-manager@^5.0.0: json-stable-stringify "^1.0.1" mkdirp "^0.5.1" -react-intl@^2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.1.5.tgz#f9795ea34b790dcb5d0d8ef7060dddbe85bf8763" +react-intl@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.3.0.tgz#e1df6af5667fdf01cbe4aab20e137251e2ae5142" dependencies: intl-format-cache "^2.0.5" intl-messageformat "^1.3.0" @@ -5508,56 +5498,65 @@ react-komposer@^2.0.0: shallowequal "^0.2.2" react-modal@^1.2.0, react-modal@^1.2.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-1.5.2.tgz#acd60f19ed93ebbc7b09ea51624c7566fc615245" + version "1.7.7" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-1.7.7.tgz#70205f51c58708c487aff681ba3fed7946e391d9" dependencies: + create-react-class "^15.5.2" element-class "^0.2.0" exenv "1.2.0" - lodash.assign "^3.2.0" + lodash.assign "^4.2.0" + prop-types "^15.5.7" -react-motion@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.4.5.tgz#ecc42f692fec9b2de4c92f85e26375071f779b76" +react-motion@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.0.tgz#1708fc2aee552900d21c1e6bed28346863e017b6" dependencies: performance-now "^0.2.0" + prop-types "^15.5.8" raf "^3.1.0" -react-notification@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-6.6.0.tgz#791302e1522b0d2529daaab3b80839bcafd28fad" +react-notification@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-6.7.0.tgz#58f16976b0850d6a6c70e078796b82032d5301e2" + dependencies: + prop-types "^15.5.8" -react-redux-loading-bar@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/react-redux-loading-bar/-/react-redux-loading-bar-2.4.1.tgz#8df64db362f065b5453fbbb7379a5cf62440129a" +react-redux-loading-bar@^2.9.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/react-redux-loading-bar/-/react-redux-loading-bar-2.9.1.tgz#26d10ff08194e533f088f26fb2d42b1248d61ff8" + dependencies: + prop-types "^15.5.6" react-redux@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.4.tgz#1563babadcfb2672f57f9ceaa439fb16bf85d55b" + version "5.0.5" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.5.tgz#f8e8c7b239422576e52d6b7db06439469be9846a" dependencies: - create-react-class "^15.5.1" + create-react-class "^15.5.3" hoist-non-react-statics "^1.0.3" invariant "^2.0.0" lodash "^4.2.0" lodash-es "^4.2.0" loose-envify "^1.1.0" - prop-types "^15.0.0" + prop-types "^15.5.10" -react-router-scroll@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.3.2.tgz#ba8b1d01b3681dc5a68d72865d35c10e84065e52" +react-router-scroll@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.4.2.tgz#4b90e8707edf96eba7f066d94c5b4338bd6848b7" dependencies: - history "^2.1.2" - scroll-behavior "^0.8.0" + prop-types "^15.5.6" + scroll-behavior "^0.9.3" warning "^3.0.0" -react-router@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.1.tgz#73e9491f6ceb316d0f779829081863e378ee4ed7" +react-router@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.0.5.tgz#c3b7873758045a8bbc9562aef4ff4bc8cce7c136" dependencies: - history "^2.1.2" + create-react-class "^15.5.1" + history "^3.0.0" hoist-non-react-statics "^1.2.0" invariant "^2.2.1" loose-envify "^1.2.0" + prop-types "^15.5.6" warning "^3.0.0" react-simple-di@^1.2.0: @@ -5567,11 +5566,12 @@ react-simple-di@^1.2.0: babel-runtime "6.x.x" hoist-non-react-statics "1.x.x" -react-simple-dropdown@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/react-simple-dropdown/-/react-simple-dropdown-1.1.4.tgz#637738861128c6b5b04b62498d61446f388c5cd6" +react-simple-dropdown@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-simple-dropdown/-/react-simple-dropdown-3.0.0.tgz#5a2cac441748a090a3b7009b4807ea206002b7c3" dependencies: classnames "^2.1.2" + prop-types "^15.5.8" react-storybook-addon-intl@^0.1.0: version "0.1.0" @@ -5596,16 +5596,21 @@ react-textarea-autosize@^5.0.6: dependencies: prop-types "^15.5.8" -react-toggle@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-2.1.1.tgz#80600a64417a1acc8aaa4c1477f7fbdb88b988fb" +react-themeable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e" dependencies: - classnames "~2.2" - react-addons-pure-render-mixin ">=0.14.0" + object-assign "^3.0.0" + +react-toggle@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.0.1.tgz#0e83e8c94d94232debfa21a938ff3d2b2106ec72" + dependencies: + classnames "^2.2.5" react-virtualized@^9.7.4: - version "9.7.4" - resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.7.4.tgz#1b5b25c1397282c6ffc651b416befc69e282df12" + version "9.7.6" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.7.6.tgz#6be9e7ae8b214a848116f1ebd48ff1aac26fcc2f" dependencies: babel-runtime "^6.11.6" classnames "^2.2.3" @@ -5643,27 +5648,16 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@~2.1.4: - version "2.1.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" - dependencies: - buffer-shims "^1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.2.9: + version "2.2.9" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" dependencies: + buffer-shims "~1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" process-nextick-args "~1.0.6" - string_decoder "~0.10.x" + string_decoder "~1.0.0" util-deprecate "~1.0.1" readdirp@^2.0.0: @@ -5684,10 +5678,10 @@ readline2@^1.0.1: mute-stream "0.0.5" recast@^0.11.5: - version "0.11.22" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.22.tgz#dedeb18fb001a2bbc6ac34475fda53dfe3d47dfa" + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: - ast-types "0.9.5" + ast-types "0.9.6" esprima "~3.1.0" private "~0.1.5" source-map "~0.5.0" @@ -5709,17 +5703,17 @@ redis-commands@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.1.tgz#81d826f45fa9c8b2011f4cd7a0fe597d241d442b" -redis-parser@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.4.0.tgz#018ea743077aae944d0b798b2fd12587320bf3c9" +redis-parser@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b" -redis@^2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/redis/-/redis-2.6.5.tgz#87c1eff4a489f94b70871f3d08b6988f23a95687" +redis@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/redis/-/redis-2.7.1.tgz#7d56f7875b98b20410b71539f1d878ed58ebf46a" dependencies: double-ended-queue "^2.1.0-0" redis-commands "^1.2.0" - redis-parser "^2.0.0" + redis-parser "^2.5.0" reduce-css-calc@^1.2.6: version "1.3.0" @@ -5730,16 +5724,14 @@ reduce-css-calc@^1.2.6: reduce-function-call "^1.0.1" reduce-function-call@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.1.tgz#fa02e126e695824263cab91d3a5b0fdc1dd27a9a" + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" dependencies: - balanced-match "~0.1.0" + balanced-match "^0.4.2" -redux-immutable@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-3.1.0.tgz#cafbd686e0711261119b9c28960935dc47a49d0a" - dependencies: - immutable "^3.8.1" +redux-immutable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3" redux-thunk@^2.2.0: version "2.2.0" @@ -5755,20 +5747,20 @@ redux@^3.5.2, redux@^3.6.0: symbol-observable "^1.0.2" regenerate@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.1.tgz#0300203a5d2fdcf89116dce84275d011f5903f33" + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator-runtime@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-runtime@^0.9.5: - version "0.9.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.5.tgz#403d6d40a4bdff9c330dd9392dcbb2d9a8bba1fc" + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" -regenerator-transform@0.9.8: - version "0.9.8" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" +regenerator-transform@0.9.11: + version "0.9.11" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -5807,13 +5799,17 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +remove-trailing-separator@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2: - version "1.5.4" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.5.4.tgz#64ec0c91e0f4b475f90d5b643651e3e6e5b6c2d5" + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^2.0.0: version "2.0.1" @@ -5821,18 +5817,32 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2, request@2.x, request@^2.74.0, request@^2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.4.tgz#86988ec8eee408e45579fce83bfd05b3adf9a155" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.0" + +request@2, request@^2.74.0, request@^2.79.0, request@^2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" - caseless "~0.11.0" + caseless "~0.12.0" combined-stream "~1.0.5" extend "~3.0.0" forever-agent "~0.6.1" form-data "~2.1.1" - har-validator "~2.0.6" + har-validator "~4.2.1" hawk "~3.1.3" http-signature "~1.1.0" is-typedarray "~1.0.0" @@ -5840,10 +5850,12 @@ request@2, request@2.x, request@^2.74.0, request@^2.79.0: json-stringify-safe "~5.0.1" mime-types "~2.1.7" oauth-sign "~0.8.1" - qs "~6.3.0" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" stringstream "~0.0.4" tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" + tunnel-agent "^0.6.0" uuid "^3.0.0" requestidlecallback@^0.3.0: @@ -5873,9 +5885,9 @@ requires-port@1.0.x, requires-port@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" -reselect@^2.5.4: - version "2.5.4" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-2.5.4.tgz#b7d23fdf00b83fa7ad0279546f8dbbbd765c7047" +reselect@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" resolve-from@^1.0.0: version "1.0.1" @@ -5904,25 +5916,22 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.6.1: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" -rimraf@~2.5.0, rimraf@~2.5.1: - version "2.5.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" - dependencies: - glob "^7.0.5" - ripemd160@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" -ripemd160@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" run-async@^0.1.0: version "0.1.0" @@ -5934,25 +5943,26 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" -safe-buffer@~5.0.1: +safe-buffer@5.0.1, safe-buffer@^5.0.1, safe-buffer@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" -samsam@1.1.2, samsam@~1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567" +samsam@1.x, samsam@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.2.1.tgz#edd39093a3184370cb859243b2bdf255e7d8ea67" sass-graph@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b" + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" dependencies: glob "^7.0.0" lodash "^4.0.0" - yargs "^4.7.1" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" -sass-loader@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.3.tgz#33983b1f90d27ddab0e57d0dac403dce9bc7ecfd" +sass-loader@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.5.tgz#a847910f36442aa56c5985879d54eb519e24a328" dependencies: async "^2.1.5" clone-deep "^0.2.4" @@ -5961,16 +5971,29 @@ sass-loader@^6.0.3: pify "^2.3.0" sax@^1.2.1, sax@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + version "1.2.2" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" -scroll-behavior@^0.8.0: - version "0.8.2" - resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.8.2.tgz#ace13e40b001d8d4d007aec0e7fb668cf9043546" +schema-utils@^0.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" dependencies: - dom-helpers "^2.4.0" + ajv "^5.0.0" + +scroll-behavior@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.3.tgz#e48bcc8af364f3f07176e8dbca3968bd5e71557b" + dependencies: + dom-helpers "^3.0.0" invariant "^2.2.1" +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + seed-random@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54" @@ -5979,7 +6002,7 @@ select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" -"semver@2 || 3 || 4 || 5", semver@~5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -5987,24 +6010,6 @@ semver@4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" -send@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.14.2.tgz#39b0438b3f510be5dc6f667a11f71689368cdeef" - dependencies: - debug "~2.2.0" - depd "~1.1.0" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.7.0" - fresh "0.3.0" - http-errors "~1.5.1" - mime "1.3.4" - ms "0.7.2" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" - send@0.15.3: version "0.15.3" resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309" @@ -6024,13 +6029,14 @@ send@0.15.3: statuses "~1.3.1" serve-favicon@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.3.0.tgz#aed36cc6834069a6f189cc7222c6a1a811dc5b39" + version "2.4.3" + resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.3.tgz#5986b17b0502642b641c21f818b1acce32025d23" dependencies: - etag "~1.7.0" - fresh "0.3.0" - ms "0.7.1" - parseurl "~1.3.0" + etag "~1.8.0" + fresh "0.5.0" + ms "2.0.0" + parseurl "~1.3.1" + safe-buffer "5.0.1" serve-index@^1.7.2: version "1.8.0" @@ -6053,15 +6059,6 @@ serve-static@1.12.3: parseurl "~1.3.1" send "0.15.3" -serve-static@~1.11.2: - version "1.11.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.14.2" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -6086,9 +6083,9 @@ sha.js@2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" -sha.js@^2.3.6: - version "2.4.5" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.5.tgz#27d171efcc82a118b99639ff581660242b506e7c" +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" dependencies: inherits "^2.0.1" @@ -6107,15 +6104,7 @@ shallowequal@0.2.x, shallowequal@^0.2.2: dependencies: lodash.keys "^3.1.2" -shelljs@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.4.tgz#b8f04b3a74ddfafea22acf98e0be45ded53d59c8" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -shelljs@^0.7.5: +shelljs@^0.7.4, shelljs@^0.7.5: version "0.7.7" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" dependencies: @@ -6124,17 +6113,21 @@ shelljs@^0.7.5: rechoir "^0.6.2" signal-exit@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.1.tgz#5a4c884992b63a7acd9badb7894c3ee9cfccad81" + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -sinon@^1.17.6: - version "1.17.6" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.6.tgz#a43116db59577c8296356afee13fafc2332e58e1" +sinon@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.3.1.tgz#48c9c758b4d0bb86327486833f1c4298919ce9ee" dependencies: - formatio "1.1.1" - lolex "1.3.2" - samsam "1.1.2" - util ">=0.10.3 <1" + diff "^3.1.0" + formatio "1.2.0" + lolex "^1.6.0" + native-promise-only "^0.8.1" + path-to-regexp "^1.7.0" + samsam "^1.1.3" + text-encoding "0.6.4" + type-detect "^4.0.0" slash@^1.0.0: version "1.0.0" @@ -6185,18 +6178,24 @@ sortobject@^1.0.0: editions "^1.1.1" source-list-map@^0.1.7, source-list-map@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.7.tgz#d4b5ce2a46535c72c7e8527c71a77d250618172e" + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" source-list-map@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.1.tgz#1a33ac210ca144d1e561f906ebccab5669ff4cb4" + version "1.1.2" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1" source-map-support@^0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.3.tgz#693c8383d4389a4569486987c219744dfc601685" + version "0.4.15" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" dependencies: - source-map "^0.5.3" + source-map "^0.5.6" + +source-map@^0.4.2, source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3: version "0.5.6" @@ -6208,12 +6207,6 @@ source-map@~0.2.0: dependencies: amdefine ">=0.0.4" -source-map@~0.4.1: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - dependencies: - amdefine ">=0.0.4" - spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -6228,25 +6221,28 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -spdy-transport@^2.0.15: - version "2.0.18" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.18.tgz#43fc9c56be2cccc12bb3e2754aa971154e836ea6" +spdy-transport@^2.0.18: + version "2.0.20" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.20.tgz#735e72054c486b2354fe89e702256004a39ace4d" dependencies: - debug "^2.2.0" + debug "^2.6.8" + detect-node "^2.0.3" hpack.js "^2.1.6" - obuf "^1.1.0" - readable-stream "^2.0.1" - wbuf "^1.4.0" + obuf "^1.1.1" + readable-stream "^2.2.9" + safe-buffer "^5.0.1" + wbuf "^1.7.2" spdy@^3.4.1: - version "3.4.4" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.4.tgz#e0406407ca90ff01b553eb013505442649f5a819" + version "3.4.7" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" dependencies: - debug "^2.2.0" - handle-thing "^1.2.4" - http-deceiver "^1.2.4" + debug "^2.6.8" + handle-thing "^1.2.5" + http-deceiver "^1.2.7" + safe-buffer "^5.0.1" select-hose "^2.0.0" - spdy-transport "^2.0.15" + spdy-transport "^2.0.18" split@^1.0.0: version "1.0.0" @@ -6259,8 +6255,8 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + version "1.13.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -6283,6 +6279,10 @@ stdout-stream@^1.4.0: dependencies: readable-stream "^2.0.1" +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + store@^1.3.20: version "1.3.20" resolved "https://registry.yarnpkg.com/store/-/store-1.3.20.tgz#13ea7e3fb2d6c239868265d686b1d84e99c5be3e" @@ -6295,12 +6295,12 @@ stream-browserify@^2.0.1: readable-stream "^2.0.2" stream-http@^2.3.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.4.0.tgz#9599aa8e263667ce4190e0dc04a1d065d3595a7e" + version "2.7.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.1.tgz#546a51741ad5a6b07e9e31b0b10441a917df528a" dependencies: - builtin-status-codes "^2.0.0" + builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.1.0" + readable-stream "^2.2.6" to-arraybuffer "^1.0.0" xtend "^4.0.0" @@ -6343,10 +6343,16 @@ string.prototype.padstart@^3.0.0: es-abstract "^1.4.3" function-bind "^1.0.2" -string_decoder@^0.10.25, string_decoder@~0.10.x: +string_decoder@^0.10.25: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +string_decoder@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.1.tgz#62e200f039955a6810d8df0a33ffc0f013662d98" + dependencies: + safe-buffer "^5.0.1" + stringify-object@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-2.4.0.tgz#c62d11023eb21fe2d9b087be039a26df3b22a09d" @@ -6358,9 +6364,9 @@ stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -stringz@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/stringz/-/stringz-0.1.2.tgz#016e9b15d64eecf8ec1a1849b6ed47c5cd91042f" +stringz@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/stringz/-/stringz-0.2.0.tgz#f228f85e108b6da2c9001ecc94c835ca4ee58d1b" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" @@ -6384,10 +6390,6 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" - strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -6404,47 +6406,43 @@ style-loader@^0.16.1: dependencies: loader-utils "^1.0.2" -sugarss@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-0.2.0.tgz#ac34237563327c6ff897b64742bf6aec190ad39e" +sugarss@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.0.tgz#65e51b3958432fb70d5451a68bb33e32d0cf1ef7" dependencies: - postcss "^5.2.4" + postcss "^6.0.0" -supports-color@3.1.2, supports-color@^3.1.0, supports-color@^3.1.1: +supports-color@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" dependencies: has-flag "^1.0.0" -supports-color@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.2.3: +supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: has-flag "^1.0.0" svgo@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034" + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" dependencies: coa "~1.0.1" colors "~1.1.2" - csso "~2.2.1" - js-yaml "~3.6.1" + csso "~2.3.1" + js-yaml "~3.7.0" mkdirp "~0.5.1" sax "~1.2.1" whet.extend "~0.9.9" symbol-observable@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.3.tgz#0fdb005e84f346a899d492beba23068b32d1525a" + version "1.0.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" symbol-tree@^3.2.1: version "3.2.2" @@ -6469,20 +6467,20 @@ tapable@^0.2.5, tapable@~0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d" -tar-pack@~3.1.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.1.4.tgz#bc8cf9a22f5832739f12f3910dac1eb97b49708c" +tar-pack@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" dependencies: - debug "~2.2.0" - fstream "~1.0.10" - fstream-ignore "~1.0.5" - once "~1.3.3" - readable-stream "~2.1.4" - rimraf "~2.5.1" - tar "~2.2.1" - uid-number "~0.0.6" - -tar@^2.0.0, tar@~2.2.0, tar@~2.2.1: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.0.0, tar@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" dependencies: @@ -6494,6 +6492,10 @@ tcomb@^2.5.1: version "2.7.0" resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-2.7.0.tgz#10d62958041669a5d53567b9a4ee8cde22b1c2b0" +text-encoding@0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" + text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6523,10 +6525,10 @@ to-arraybuffer@^1.0.0: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" to-fast-properties@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@^2.3.2, tough-cookie@~2.3.0: +tough-cookie@>=2.3.0, tough-cookie@^2.3.2, tough-cookie@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: @@ -6556,13 +6558,15 @@ tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" -tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.3.tgz#3da382f670f25ded78d7b3d1792119bca0b7132d" + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" type-check@~0.3.2: version "0.3.2" @@ -6578,12 +6582,9 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@~1.6.14: - version "1.6.14" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.13" +type-detect@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea" type-is@~1.6.15: version "1.6.15" @@ -6596,17 +6597,17 @@ typed-function@0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-0.10.5.tgz#2e0f18abd065219fab694a446a65c6d1981832c0" -typedarray@~0.0.5: +typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" ua-parser-js@^0.7.9: - version "0.7.10" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.10.tgz#917559ddcce07cbc09ece7d80495e4c268f4ef9f" + version "0.7.12" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" -uglify-js@^2.8.5: - version "2.8.22" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" +uglify-js@^2.8.27: + version "2.8.27" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -6626,7 +6627,7 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uid-number@~0.0.6: +uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -6639,8 +6640,8 @@ uniq@^1.0.1: resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" uniqid@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.0.tgz#33d9679f65022f48988a03fd24e7dcaf8f109eca" + version "4.1.1" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" dependencies: macaddress "^0.2.8" @@ -6653,11 +6654,11 @@ unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" url-loader@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.7.tgz#67e8779759f8000da74994906680c943a9b0925d" + version "0.5.8" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.8.tgz#b9183b1801e0f847718673673040bc9dc1c715c5" dependencies: - loader-utils "0.2.x" - mime "1.2.x" + loader-utils "^1.0.2" + mime "1.3.x" url-parse@1.0.x: version "1.0.5" @@ -6667,10 +6668,10 @@ url-parse@1.0.x: requires-port "1.0.x" url-parse@^1.1.1: - version "1.1.8" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.8.tgz#7a65b3a8d57a1e86af6b4e2276e34774167c0156" + version "1.1.9" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19" dependencies: - querystringify "0.0.x" + querystringify "~1.0.0" requires-port "1.0.x" url@^0.11.0: @@ -6694,7 +6695,7 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3: +util@0.10.3, util@^0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: @@ -6717,8 +6718,8 @@ uws@^0.14.5: resolved "https://registry.yarnpkg.com/uws/-/uws-0.14.5.tgz#67aaf33c46b2a587a5f6666d00f7691328f149dc" v8flags@^2.0.10: - version "2.0.11" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" dependencies: user-home "^1.1.1" @@ -6729,11 +6730,7 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -vary@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" - -vary@~1.1.1: +vary@~1.1.0, vary@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -6753,12 +6750,6 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" -warning@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901" - dependencies: - loose-envify "^1.0.0" - warning@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" @@ -6781,7 +6772,7 @@ watchpack@^1.3.1: chokidar "^1.4.3" graceful-fs "^4.1.2" -wbuf@^1.1.0, wbuf@^1.4.0: +wbuf@^1.1.0, wbuf@^1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe" dependencies: @@ -6818,7 +6809,7 @@ webpack-core@~0.6.9: source-list-map "~0.1.7" source-map "~0.4.1" -webpack-dev-middleware@^1.10.2: +webpack-dev-middleware@^1.10.2, webpack-dev-middleware@^1.6.0: version "1.10.2" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.2.tgz#2e252ce1dfb020dbda1ccb37df26f30ab014dbd1" dependencies: @@ -6827,15 +6818,6 @@ webpack-dev-middleware@^1.10.2: path-is-absolute "^1.0.0" range-parser "^1.0.3" -webpack-dev-middleware@^1.6.0: - version "1.8.4" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.8.4.tgz#e8765c9122887ce9e3abd4cc9c3eb31b61e0948d" - dependencies: - memory-fs "~0.3.0" - mime "^1.3.4" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - webpack-dev-server@^2.4.5: version "2.4.5" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.4.5.tgz#31384ce81136be1080b4b4cde0eb9b90e54ee6cf" @@ -6859,8 +6841,8 @@ webpack-dev-server@^2.4.5: yargs "^6.0.0" webpack-hot-middleware@^2.13.2: - version "2.17.1" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.17.1.tgz#0c8fbf6f93ff29c095d684b07ab6d6c0f2f951d7" + version "2.18.0" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.18.0.tgz#a16bb535b83a6ac94a78ac5ebce4f3059e8274d3" dependencies: ansi-html "0.0.7" html-entities "^1.2.0" @@ -6895,8 +6877,8 @@ webpack-sources@^0.2.3: source-map "~0.5.3" webpack@^1.13.1: - version "1.14.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823" + version "1.15.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.15.0.tgz#4ff31f53db03339e55164a9d468ee0324968fe98" dependencies: acorn "^3.0.0" async "^1.3.0" @@ -6914,9 +6896,9 @@ webpack@^1.13.1: watchpack "^0.2.1" webpack-core "~0.6.9" -webpack@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.4.1.tgz#15a91dbe34966d8a4b99c7d656efd92a2e5a6f6a" +webpack@^2.5.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -6935,7 +6917,7 @@ webpack@^2.4.1: source-map "^0.5.3" supports-color "^3.1.0" tapable "~0.2.5" - uglify-js "^2.8.5" + uglify-js "^2.8.27" watchpack "^1.3.1" webpack-sources "^0.2.3" yargs "^6.0.0" @@ -6963,12 +6945,12 @@ whatwg-encoding@^1.0.1: iconv-lite "0.4.13" whatwg-fetch@>=0.10.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-1.0.0.tgz#01c2ac4df40e236aaa18480e3be74bd5c8eb798e" + version "2.0.3" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" whatwg-url@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.5.0.tgz#79bb6f0e370a4dda1cbc8f3062a490cf8bbb09ea" + version "4.8.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0" dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -6982,25 +6964,21 @@ which-module@^1.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" which@1, which@^1.2.9: - version "1.2.12" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: - isexe "^1.1.1" + isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" dependencies: - string-width "^1.0.1" + string-width "^1.0.2" window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -7025,10 +7003,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + version "1.3.4" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" dependencies: - graceful-fs "^4.1.2" + graceful-fs "^4.1.11" imurmurhash "^0.1.4" slide "^1.1.5" @@ -7064,15 +7042,8 @@ y18n@^3.2.1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" yallist@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" - -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" yargs-parser@^4.2.0: version "4.2.1" @@ -7080,28 +7051,33 @@ yargs-parser@^4.2.0: dependencies: camelcase "^3.0.0" -yargs@^4.7.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + +yargs@^6.0.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" dependencies: + camelcase "^3.0.0" cliui "^3.2.0" decamelize "^1.1.1" get-caller-file "^1.0.1" - lodash.assign "^4.0.3" os-locale "^1.4.0" read-pkg-up "^1.0.1" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^1.0.1" + string-width "^1.0.2" which-module "^1.0.0" - window-size "^0.2.0" y18n "^3.2.1" - yargs-parser "^2.4.1" + yargs-parser "^4.2.0" -yargs@^6.0.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" dependencies: camelcase "^3.0.0" cliui "^3.2.0" @@ -7115,7 +7091,7 @@ yargs@^6.0.0: string-width "^1.0.2" which-module "^1.0.0" y18n "^3.2.1" - yargs-parser "^4.2.0" + yargs-parser "^5.0.0" yargs@~3.10.0: version "3.10.0" -- GitLab From c49ff7395e911c4254d75ec29702af34d07508a7 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 30 May 2017 10:04:44 +0900 Subject: [PATCH 038/295] Run bundle command (follow up #3403) (#3427) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 69429c979b..eeb7a4a8d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -526,7 +526,7 @@ DEPENDENCIES rack-attack (~> 5.0) rack-cors (~> 0.4) rack-timeout (~> 0.4) - rails (~> 5.0) + rails (~> 5.0.0) rails-controller-testing (~> 1.0) rails-i18n (~> 5.0) rails-settings-cached (~> 0.6) -- GitLab From 2d39560dc1811c29c1663b11a4a351089898e244 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 19:29:48 +0900 Subject: [PATCH 039/295] Use around hook to restore context in ApplicationHelper spec (#3432) --- spec/helpers/application_helper_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index a3903464b4..7b875e21f4 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -100,6 +100,12 @@ describe ApplicationHelper do end describe 'title' do + around do |example| + site_title = Setting.site_title + example.run + Setting.site_title = site_title + end + it 'returns site title on production enviroment' do Setting.site_title = 'site title' expect(Rails.env).to receive(:production?).and_return(true) -- GitLab From 67bc58dd60645a9451899e3368ae40a1edd4806c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 19:32:09 +0900 Subject: [PATCH 040/295] Use around hook to restore context in Admin::SettingsController spec (#3428) --- .../admin/settings_controller_spec.rb | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/spec/controllers/admin/settings_controller_spec.rb b/spec/controllers/admin/settings_controller_spec.rb index 7fd49a0f11..d9dde3c92a 100644 --- a/spec/controllers/admin/settings_controller_spec.rb +++ b/spec/controllers/admin/settings_controller_spec.rb @@ -47,20 +47,36 @@ RSpec.describe Admin::SettingsController, type: :controller do end end - it 'updates a settings value' do - Setting.site_title = 'Original' - patch :update, params: { site_title: 'New title' } + context do + around do |example| + site_title = Setting.site_title + example.run + Setting.site_title = site_title + end - expect(response).to redirect_to(edit_admin_settings_path) - expect(Setting.site_title).to eq 'New title' + it 'updates a settings value' do + Setting.site_title = 'Original' + patch :update, params: { site_title: 'New title' } + + expect(response).to redirect_to(edit_admin_settings_path) + expect(Setting.site_title).to eq 'New title' + end end - it 'typecasts open_registrations to boolean' do - Setting.open_registrations = false - patch :update, params: { open_registrations: 'true' } + context do + around do |example| + open_registrations = Setting.open_registrations + example.run + Setting.open_registrations = open_registrations + end - expect(response).to redirect_to(edit_admin_settings_path) - expect(Setting.open_registrations).to eq true + it 'typecasts open_registrations to boolean' do + Setting.open_registrations = false + patch :update, params: { open_registrations: 'true' } + + expect(response).to redirect_to(edit_admin_settings_path) + expect(Setting.open_registrations).to eq true + end end end end -- GitLab From dfc43a6d3d3279d615b78fe2ac7f4c2060bcbe88 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 19:32:33 +0900 Subject: [PATCH 041/295] Use around hook to restore context in InstanceHelper spec (#3429) --- spec/helpers/instance_helper_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/helpers/instance_helper_spec.rb b/spec/helpers/instance_helper_spec.rb index c42ed69388..c3d28544f2 100644 --- a/spec/helpers/instance_helper_spec.rb +++ b/spec/helpers/instance_helper_spec.rb @@ -4,6 +4,12 @@ require 'rails_helper' describe InstanceHelper do describe 'site_title' do + around do |example| + site_title = Setting.site_title + example.run + Setting.site_title = site_title + end + it 'Uses the Setting.site_title value when it exists' do Setting.site_title = 'New site title' -- GitLab From 76fa9d24882784343476b93769c920bf83e75c2a Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 22:03:35 +0900 Subject: [PATCH 042/295] Use around hook to restore context in InstancePresenter spec (#3430) --- spec/presenters/instance_presenter_spec.rb | 76 +++++++++++++++++----- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/spec/presenters/instance_presenter_spec.rb b/spec/presenters/instance_presenter_spec.rb index 2de63eaccc..7c47aed616 100644 --- a/spec/presenters/instance_presenter_spec.rb +++ b/spec/presenters/instance_presenter_spec.rb @@ -3,37 +3,83 @@ require 'rails_helper' describe InstancePresenter do let(:instance_presenter) { InstancePresenter.new } - it "delegates site_description to Setting" do - Setting.site_description = "Site desc" + context do + around do |example| + site_description = Setting.site_description + example.run + Setting.site_description = site_description + end + + it "delegates site_description to Setting" do + Setting.site_description = "Site desc" - expect(instance_presenter.site_description).to eq "Site desc" + expect(instance_presenter.site_description).to eq "Site desc" + end end - it "delegates site_extended_description to Setting" do - Setting.site_extended_description = "Extended desc" + context do + around do |example| + site_extended_description = Setting.site_extended_description + example.run + Setting.site_extended_description = site_extended_description + end + + it "delegates site_extended_description to Setting" do + Setting.site_extended_description = "Extended desc" - expect(instance_presenter.site_extended_description).to eq "Extended desc" + expect(instance_presenter.site_extended_description).to eq "Extended desc" + end end - it "delegates open_registrations to Setting" do - Setting.open_registrations = false + context do + around do |example| + open_registrations = Setting.open_registrations + example.run + Setting.open_registrations = open_registrations + end + + it "delegates open_registrations to Setting" do + Setting.open_registrations = false - expect(instance_presenter.open_registrations).to eq false + expect(instance_presenter.open_registrations).to eq false + end end - it "delegates closed_registrations_message to Setting" do - Setting.closed_registrations_message = "Closed message" + context do + around do |example| + closed_registrations_message = Setting.closed_registrations_message + example.run + Setting.closed_registrations_message = closed_registrations_message + end + + it "delegates closed_registrations_message to Setting" do + Setting.closed_registrations_message = "Closed message" - expect(instance_presenter.closed_registrations_message).to eq "Closed message" + expect(instance_presenter.closed_registrations_message).to eq "Closed message" + end end - it "delegates contact_email to Setting" do - Setting.site_contact_email = "admin@example.com" + context do + around do |example| + site_contact_email = Setting.site_contact_email + example.run + Setting.site_contact_email = site_contact_email + end + + it "delegates contact_email to Setting" do + Setting.site_contact_email = "admin@example.com" - expect(instance_presenter.site_contact_email).to eq "admin@example.com" + expect(instance_presenter.site_contact_email).to eq "admin@example.com" + end end describe "contact_account" do + around do |example| + site_contact_username = Setting.site_contact_username + example.run + Setting.site_contact_username = site_contact_username + end + it "returns the account for the site contact username" do Setting.site_contact_username = "aaa" account = Fabricate(:account, username: "aaa") -- GitLab From b42bdd80e8a25f0ea5d121431265b428a34d1a65 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Tue, 30 May 2017 06:11:15 -0700 Subject: [PATCH 043/295] Extract polyfill loading into single module (#3421) --- app/javascript/mastodon/load_polyfills.js | 36 +++++++++++++++++++++++ app/javascript/packs/application.js | 34 +++------------------ app/javascript/packs/public.js | 13 +++----- 3 files changed, 44 insertions(+), 39 deletions(-) create mode 100644 app/javascript/mastodon/load_polyfills.js diff --git a/app/javascript/mastodon/load_polyfills.js b/app/javascript/mastodon/load_polyfills.js new file mode 100644 index 0000000000..bc54685953 --- /dev/null +++ b/app/javascript/mastodon/load_polyfills.js @@ -0,0 +1,36 @@ +// Convenience function to load polyfills and return a promise when it's done. +// If there are no polyfills, then this is just Promise.resolve() which means +// it will execute in the same tick of the event loop (i.e. near-instant). + +function importBasePolyfills() { + return import(/* webpackChunkName: "base_polyfills" */ './base_polyfills'); +} + +function importExtraPolyfills() { + return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills'); +} + +function loadPolyfills() { + const needsBasePolyfills = !( + window.Intl && + Object.assign && + Number.isNaN && + window.Symbol && + Array.prototype.includes + ); + + // Latest version of Firefox and Safari do not have IntersectionObserver. + // Edge does not have requestIdleCallback. + // This avoids shipping them all the polyfills. + const needsExtraPolyfills = !( + window.IntersectionObserver && + window.requestIdleCallback + ); + + return Promise.all([ + needsBasePolyfills && importBasePolyfills(), + needsExtraPolyfills && importExtraPolyfills(), + ]); +} + +export default loadPolyfills; diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index be40726c6e..8932dc5138 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -1,32 +1,6 @@ import main from '../mastodon/main'; +import loadPolyfills from '../mastodon/load_polyfills'; -const needsBasePolyfills = !( - window.Intl && - Object.assign && - Number.isNaN && - window.Symbol && - Array.prototype.includes -); - -const needsExtraPolyfills = !( - window.IntersectionObserver && - window.requestIdleCallback -); - -// Latest version of Firefox and Safari do not have IntersectionObserver. -// Edge does not have requestIdleCallback. -// This avoids shipping them all the polyfills. -if (needsBasePolyfills) { - Promise.all([ - import(/* webpackChunkName: "base_polyfills" */ '../mastodon/base_polyfills'), - import(/* webpackChunkName: "extra_polyfills" */ '../mastodon/extra_polyfills'), - ]).then(main).catch(e => { - console.error(e); // eslint-disable-line no-console - }); -} else if (needsExtraPolyfills) { - import(/* webpackChunkName: "extra_polyfills" */ '../mastodon/extra_polyfills').then(main).catch(e => { - console.error(e); // eslint-disable-line no-console - }); -} else { - main(); -} +loadPolyfills().then(main).catch(e => { + console.error(e); // eslint-disable-line no-console +}); diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index 9f71b6dc5a..69c942f342 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -3,6 +3,7 @@ import { getLocale } from 'mastodon/locales'; import { length } from 'stringz'; import IntlRelativeFormat from 'intl-relativeformat'; import { delegate } from 'rails-ujs'; +import loadPolyfills from '../mastodon/load_polyfills'; require.context('../images/', true); @@ -85,12 +86,6 @@ function main() { }); } -if (!window.Intl) { - import(/* webpackChunkName: "base_polyfills" */ 'mastodon/base_polyfills').then(() => { - main(); - }).catch(error => { - console.log(error); // eslint-disable-line no-console - }); -} else { - main(); -} +loadPolyfills().then(main).catch(error => { + console.log(error); // eslint-disable-line no-console +}); -- GitLab From 5ac4d677e9f9697c801649a2f675435f99ac2cfa Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 30 May 2017 22:12:12 +0900 Subject: [PATCH 044/295] Remove unused React Storybook addon (#3434) --- package.json | 1 - storybook/config.js | 2 -- yarn.lock | 10 ---------- 3 files changed, 13 deletions(-) diff --git a/package.json b/package.json index c2b2c58669..9b1303b2aa 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,6 @@ "minimist": "^1.2.0", "mocha": "^3.4.1", "react-intl-translations-manager": "^5.0.0", - "react-storybook-addon-intl": "^0.1.0", "react-test-renderer": "^15.5.4", "sinon": "^2.2.0", "webpack-dev-server": "^2.4.5" diff --git a/storybook/config.js b/storybook/config.js index c81cfa2f76..9b0f531729 100644 --- a/storybook/config.js +++ b/storybook/config.js @@ -1,5 +1,4 @@ import { configure, setAddon } from '@kadira/storybook'; -import IntlAddon from 'react-storybook-addon-intl'; import React from 'react'; import { storiesOf, action } from '@kadira/storybook'; import { addLocaleData } from 'react-intl'; @@ -7,7 +6,6 @@ import en from 'react-intl/locale-data/en'; import '../app/javascript/styles/application.scss'; import './storybook.scss'; -setAddon(IntlAddon); addLocaleData(en); let req = require.context('./stories/', true, /.story.js$/); diff --git a/yarn.lock b/yarn.lock index e8cccedba8..71da80c1a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5573,10 +5573,6 @@ react-simple-dropdown@^3.0.0: classnames "^2.1.2" prop-types "^15.5.8" -react-storybook-addon-intl@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/react-storybook-addon-intl/-/react-storybook-addon-intl-0.1.0.tgz#4d46c9e6c7be0ad4e4f7de72d907ec764743dee8" - react-stubber@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-stubber/-/react-stubber-1.0.0.tgz#41ee2cac72d4d4fd70a63896da98e13739b84628" @@ -5596,12 +5592,6 @@ react-textarea-autosize@^5.0.6: dependencies: prop-types "^15.5.8" -react-themeable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e" - dependencies: - object-assign "^3.0.0" - react-toggle@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.0.1.tgz#0e83e8c94d94232debfa21a938ff3d2b2106ec72" -- GitLab From bc4fad9e22695aae04cf06ada7f1c70887028cde Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 30 May 2017 22:13:04 +0900 Subject: [PATCH 045/295] Change libraries path to relative (#3433) --- app/javascript/packs/public.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index 69c942f342..0e66108bfb 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -1,8 +1,8 @@ -import emojify from 'mastodon/emoji'; -import { getLocale } from 'mastodon/locales'; import { length } from 'stringz'; import IntlRelativeFormat from 'intl-relativeformat'; import { delegate } from 'rails-ujs'; +import emojify from '../mastodon/emoji'; +import { getLocale } from '../mastodon/locales'; import loadPolyfills from '../mastodon/load_polyfills'; require.context('../images/', true); -- GitLab From e031fd60ad9ee492fbbda319eaeb213098898d03 Mon Sep 17 00:00:00 2001 From: Jack Jennings Date: Tue, 30 May 2017 06:16:14 -0700 Subject: [PATCH 046/295] Move status reblog authorization into policy (#3425) --- app/policies/status_policy.rb | 18 ++++++++++++++-- app/services/reblog_service.rb | 3 +-- spec/policies/status_policy_spec.rb | 32 ++++++++++++++++++++++------- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 658ba6d123..41d63fcbcb 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -9,12 +9,26 @@ class StatusPolicy end def show? - if status.direct_visibility? + if direct? status.account.id == account&.id || status.mentions.where(account: account).exists? - elsif status.private_visibility? + elsif private? status.account.id == account&.id || account&.following?(status.account) || status.mentions.where(account: account).exists? else account.nil? || !status.account.blocking?(account) end end + + def reblog? + !direct? && !private? && show? + end + + private + + def direct? + status.direct_visibility? + end + + def private? + status.private_visibility? + end end diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb index 9c44b1980e..a3636a283a 100644 --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@ -11,8 +11,7 @@ class ReblogService < BaseService def call(account, reblogged_status) reblogged_status = reblogged_status.reblog if reblogged_status.reblog? - authorize_with account, reblogged_status, :show? - raise Mastodon::NotPermittedError if reblogged_status.direct_visibility? || reblogged_status.private_visibility? + authorize_with account, reblogged_status, :reblog? reblog = account.statuses.create!(reblog: reblogged_status, text: '') diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb index ee7060b989..b969988e93 100644 --- a/spec/policies/status_policy_spec.rb +++ b/spec/policies/status_policy_spec.rb @@ -7,6 +7,20 @@ RSpec.describe StatusPolicy, type: :model do let(:alice) { Fabricate(:account, username: 'alice') } let(:status) { Fabricate(:status, account: alice) } + permissions :show?, :reblog? do + it 'grants access when no viewer' do + expect(subject).to permit(nil, status) + end + + it 'denies access when viewer is blocked' do + block = Fabricate(:block) + status.visibility = :private + status.account = block.target_account + + expect(subject).to_not permit(block.account, status) + end + end + permissions :show? do it 'grants access when direct and account is viewer' do status.visibility = :direct @@ -54,17 +68,21 @@ RSpec.describe StatusPolicy, type: :model do expect(subject).to_not permit(viewer, status) end + end - it 'grants access when no viewer' do - expect(subject).to permit(nil, status) + permissions :reblog? do + it 'denies access when private' do + viewer = Fabricate(:account) + status.visibility = :private + + expect(subject).to_not permit(viewer, status) end - it 'denies access when viewer is blocked' do - block = Fabricate(:block) - status.visibility = :private - status.account = block.target_account + it 'denies access when direct' do + viewer = Fabricate(:account) + status.visibility = :direct - expect(subject).to_not permit(block.account, status) + expect(subject).to_not permit(viewer, status) end end end -- GitLab From 7db98aa70e44c922bd13d72e78e0ae94826ad29f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 30 May 2017 22:28:56 +0900 Subject: [PATCH 047/295] Refactor User and spec (#3431) * Protect send_devise_notification of User * Improve spec for User --- app/models/user.rb | 10 ++-- spec/models/user_spec.rb | 123 +++++++++++++++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 14 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index f367d74aa6..8840de82d5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -68,10 +68,6 @@ class User < ApplicationRecord save! end - def send_devise_notification(notification, *args) - devise_mailer.send(notification, self, *args).deliver_later - end - def setting_default_privacy settings.default_privacy || (account.locked? ? 'private' : 'public') end @@ -88,6 +84,12 @@ class User < ApplicationRecord settings.auto_play_gif end + protected + + def send_devise_notification(notification, *args) + devise_mailer.send(notification, self, *args).deliver_later + end + private def sanitize_languages diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c3e924fd81..d7ca91e819 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4,6 +4,17 @@ require 'devise_two_factor/spec_helpers' RSpec.describe User, type: :model do it_behaves_like 'two_factor_backupable' + describe 'otp_secret' do + it 'is encrypted with OTP_SECRET environment variable' do + user = Fabricate(:user, + encrypted_otp_secret: "Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n", + encrypted_otp_secret_iv: 'rys3THICkr60BoWC', + encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==') + + expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted' + end + end + describe 'validations' do it 'is invalid without an account' do user = Fabricate.build(:user, account: nil) @@ -85,6 +96,36 @@ RSpec.describe User, type: :model do expect(User.confirmed).to match_array([user_2]) end end + + describe 'inactive' do + it 'returns a relation of inactive users' do + specified = Fabricate(:user, current_sign_in_at: 15.days.ago) + Fabricate(:user, current_sign_in_at: 13.days.ago) + + expect(User.inactive).to match_array([specified]) + end + end + + describe 'matches_email' do + it 'returns a relation of users whose email starts with the given string' do + specified = Fabricate(:user, email: 'specified@spec') + Fabricate(:user, email: 'unspecified@spec') + + expect(User.matches_email('specified')).to match_array([specified]) + end + end + + describe 'with_recent_ip_address' do + it 'returns a relation of users who is, or was at last time, online with the given IP address' do + specifieds = [ + Fabricate(:user, current_sign_in_ip: '0.0.0.42', last_sign_in_ip: '0.0.0.0'), + Fabricate(:user, current_sign_in_ip: nil, last_sign_in_ip: '0.0.0.42') + ] + Fabricate(:user, current_sign_in_ip: '0.0.0.0', last_sign_in_ip: '0.0.0.0') + + expect(User.with_recent_ip_address('0.0.0.42')).to eq specifieds + end + end end let(:account) { Fabricate(:account, username: 'alice') } @@ -133,16 +174,73 @@ RSpec.describe User, type: :model do end describe '#disable_two_factor!' do - it 'sets otp_required_for_login to false' do + it 'saves false for otp_required_for_login' do user = Fabricate.build(:user, otp_required_for_login: true) user.disable_two_factor! - expect(user.otp_required_for_login).to be false + expect(user.reload.otp_required_for_login).to be false end - it 'clears otp_backup_codes' do + it 'saves cleared otp_backup_codes' do user = Fabricate.build(:user, otp_backup_codes: %w[dummy dummy]) user.disable_two_factor! - expect(user.otp_backup_codes.empty?).to be true + expect(user.reload.otp_backup_codes.empty?).to be true + end + end + + describe '#send_confirmation_instructions' do + around do |example| + queue_adapter = ActiveJob::Base.queue_adapter + example.run + ActiveJob::Base.queue_adapter = queue_adapter + end + + it 'delivers confirmation instructions later' do + user = Fabricate(:user) + ActiveJob::Base.queue_adapter = :test + + expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::DeliveryJob) + end + end + + describe '#setting_auto_play_gif' do + it 'returns auto-play gif setting' do + user = Fabricate(:user) + user.settings[:auto_play_gif] = false + expect(user.setting_auto_play_gif).to eq false + end + end + + describe '#setting_boost_modal' do + it 'returns boost modal setting' do + user = Fabricate(:user) + user.settings[:boost_modal] = false + expect(user.setting_boost_modal).to eq false + end + end + + describe '#setting_default_privacy' do + it 'returns default privacy setting if user has configured' do + user = Fabricate(:user) + user.settings[:default_privacy] = 'unlisted' + expect(user.setting_default_privacy).to eq 'unlisted' + end + + it "returns 'private' if user has not configured default privacy setting and account is locked" do + user = Fabricate(:user, account: Fabricate(:account, locked: true)) + expect(user.setting_default_privacy).to eq 'private' + end + + it "returns 'public' if user has not configured default privacy setting and account is not locked" do + user = Fabricate(:user, account: Fabricate(:account, locked: false)) + expect(user.setting_default_privacy).to eq 'public' + end + end + + describe '#setting_delete_modal' do + it 'returns delete modal setting' do + user = Fabricate(:user) + user.settings[:delete_modal] = false + expect(user.setting_delete_modal).to eq false end end @@ -172,14 +270,19 @@ RSpec.describe User, type: :model do expect(user.valid?).to be_falsey end - it 'should not allow a user to be created with a specific blacklisted subdomain even if the top domain is whitelisted' do - old_blacklist = Rails.configuration.x.email_blacklist - Rails.configuration.x.email_domains_blacklist = 'blacklisted.mastodon.space' + context do + around do |example| + old_blacklist = Rails.configuration.x.email_blacklist + example.run + Rails.configuration.x.email_domains_blacklist = old_blacklist + end - user = User.new(email: 'foo@blacklisted.mastodon.space', account: account, password: password) - expect(user.valid?).to be_falsey + it 'should not allow a user to be created with a specific blacklisted subdomain even if the top domain is whitelisted' do + Rails.configuration.x.email_domains_blacklist = 'blacklisted.mastodon.space' - Rails.configuration.x.email_domains_blacklist = old_blacklist + user = User.new(email: 'foo@blacklisted.mastodon.space', account: account, password: password) + expect(user.valid?).to be_falsey + end end end end -- GitLab From 499cc7b803fe6f9bddf0155b2e80cbb0fba4fb6d Mon Sep 17 00:00:00 2001 From: Naouak Date: Tue, 30 May 2017 15:30:59 +0200 Subject: [PATCH 048/295] Fix webpack building on Windows (#3426) * Path should not be constructed manually. Use path.join to ensure compatibility. * Path should not be constructed manually. Use path.join to ensure compatibility. * Fix regexp. * Fix my own stupidity. I forgot to check outside my test script the regexp... --- config/webpack/shared.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/config/webpack/shared.js b/config/webpack/shared.js index 12e05dec21..1744353f7c 100644 --- a/config/webpack/shared.js +++ b/config/webpack/shared.js @@ -4,7 +4,7 @@ /* eslint import/no-dynamic-require: 0 */ const webpack = require('webpack'); -const { basename, dirname, join, relative, resolve } = require('path'); +const { basename, dirname, join, relative, resolve, sep } = require('path'); const { sync } = require('glob'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); @@ -21,7 +21,7 @@ module.exports = { (map, entry) => { const localMap = map; let namespace = relative(join(paths.source, paths.entry), dirname(entry)); - if (namespace === '../../../tmp/packs') { + if (namespace === join('..', '..', '..', 'tmp', 'packs')) { namespace = ''; // generated by generateLocalePacks.js } localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry); @@ -47,14 +47,15 @@ module.exports = { new webpack.optimize.CommonsChunkPlugin({ name: 'common', minChunks: (module, count) => { - if (module.resource && /node_modules\/react-intl/.test(module.resource)) { + const reactIntlPathRegexp = new RegExp(`node_modules\\${sep}react-intl`); + if (module.resource && reactIntlPathRegexp.test(module.resource)) { // skip react-intl because it's useless to put in the common chunk, // e.g. because "shared" modules between zh-TW and zh-CN will never // be loaded together return false; } - - if (module.resource && /node_modules\/font-awesome/.test(module.resource)) { + const fontAwesomePathRegexp = new RegExp(`node_modules\\${sep}font-awesome`); + if (module.resource && fontAwesomePathRegexp.test(module.resource)) { // extract vendor css into common module return true; } -- GitLab From 4c7fe48c402043d04435799ab1f10c67430ef34e Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 30 May 2017 23:11:45 +0900 Subject: [PATCH 049/295] Add "private: true" to package.json (#3441) --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9b1303b2aa..8bdf6f21b9 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "type": "git", "url": "https://github.com/tootsuite/mastodon.git" }, + "private": true, "dependencies": { "array-includes": "^3.0.3", "autoprefixer": "^7.1.0", -- GitLab From 23081bb2994b34108fb06e15d3101849a3077cf9 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 30 May 2017 11:39:28 -0500 Subject: [PATCH 050/295] added 'https://' to CDN_HOST variable example (#3446) --- .env.production.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.production.sample b/.env.production.sample index 23cf18c8ea..394cdedfef 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -65,7 +65,7 @@ SMTP_FROM_ADDRESS=notifications@example.com # PAPERCLIP_ROOT_URL=/system # Optional asset host for multi-server setups -# CDN_HOST=assets.example.com +# CDN_HOST=https://assets.example.com # S3 (optional) # S3_ENABLED=true -- GitLab From 0ebe7d6d236d47bf805a920dc722897bafec7459 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 13:06:01 -0400 Subject: [PATCH 051/295] Remove exports/base controller in favor of shared concern (#3444) --- .../concerns/export_controller_concern.rb | 30 +++++++++++++++++++ .../settings/exports/base_controller.rb | 23 -------------- .../exports/blocked_accounts_controller.rb | 8 ++++- .../exports/following_accounts_controller.rb | 8 ++++- .../exports/muted_accounts_controller.rb | 8 ++++- .../export_controller_concern_spec.rb} | 8 +++-- 6 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 app/controllers/concerns/export_controller_concern.rb delete mode 100644 app/controllers/settings/exports/base_controller.rb rename spec/controllers/{settings/exports/base_controller_spec.rb => concerns/export_controller_concern_spec.rb} (80%) diff --git a/app/controllers/concerns/export_controller_concern.rb b/app/controllers/concerns/export_controller_concern.rb new file mode 100644 index 0000000000..e20b71a303 --- /dev/null +++ b/app/controllers/concerns/export_controller_concern.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module ExportControllerConcern + extend ActiveSupport::Concern + + included do + before_action :authenticate_user! + before_action :load_export + end + + private + + def load_export + @export = Export.new(current_account) + end + + def send_export_file + respond_to do |format| + format.csv { send_data export_data, filename: export_filename } + end + end + + def export_data + raise 'Override in controller' + end + + def export_filename + "#{controller_name}.csv" + end +end diff --git a/app/controllers/settings/exports/base_controller.rb b/app/controllers/settings/exports/base_controller.rb deleted file mode 100644 index c082ed806c..0000000000 --- a/app/controllers/settings/exports/base_controller.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -module Settings - module Exports - class BaseController < ApplicationController - before_action :authenticate_user! - - def index - @export = Export.new(current_account) - - respond_to do |format| - format.csv { send_data export_data, filename: export_filename } - end - end - - private - - def export_filename - "#{controller_name}.csv" - end - end - end -end diff --git a/app/controllers/settings/exports/blocked_accounts_controller.rb b/app/controllers/settings/exports/blocked_accounts_controller.rb index f1115b21e3..2092104e01 100644 --- a/app/controllers/settings/exports/blocked_accounts_controller.rb +++ b/app/controllers/settings/exports/blocked_accounts_controller.rb @@ -2,7 +2,13 @@ module Settings module Exports - class BlockedAccountsController < BaseController + class BlockedAccountsController < ApplicationController + include ExportControllerConcern + + def index + send_export_file + end + private def export_data diff --git a/app/controllers/settings/exports/following_accounts_controller.rb b/app/controllers/settings/exports/following_accounts_controller.rb index 0011d2463a..74281ddca2 100644 --- a/app/controllers/settings/exports/following_accounts_controller.rb +++ b/app/controllers/settings/exports/following_accounts_controller.rb @@ -2,7 +2,13 @@ module Settings module Exports - class FollowingAccountsController < BaseController + class FollowingAccountsController < ApplicationController + include ExportControllerConcern + + def index + send_export_file + end + private def export_data diff --git a/app/controllers/settings/exports/muted_accounts_controller.rb b/app/controllers/settings/exports/muted_accounts_controller.rb index dfe72cfcb9..e511619ca6 100644 --- a/app/controllers/settings/exports/muted_accounts_controller.rb +++ b/app/controllers/settings/exports/muted_accounts_controller.rb @@ -2,7 +2,13 @@ module Settings module Exports - class MutedAccountsController < BaseController + class MutedAccountsController < ApplicationController + include ExportControllerConcern + + def index + send_export_file + end + private def export_data diff --git a/spec/controllers/settings/exports/base_controller_spec.rb b/spec/controllers/concerns/export_controller_concern_spec.rb similarity index 80% rename from spec/controllers/settings/exports/base_controller_spec.rb rename to spec/controllers/concerns/export_controller_concern_spec.rb index c924d449ae..9d6f782b99 100644 --- a/spec/controllers/settings/exports/base_controller_spec.rb +++ b/spec/controllers/concerns/export_controller_concern_spec.rb @@ -2,8 +2,12 @@ require 'rails_helper' -describe Settings::Exports::BaseController do +describe ApplicationController, type: :controller do controller do + include ExportControllerConcern + def index + send_export_file + end def export_data @export.account.username end @@ -17,7 +21,7 @@ describe Settings::Exports::BaseController do expect(response).to have_http_status(:success) expect(response.content_type).to eq 'text/csv' - expect(response.headers['Content-Disposition']).to eq 'attachment; filename="base.csv"' + expect(response.headers['Content-Disposition']).to eq 'attachment; filename="anonymous.csv"' expect(response.body).to eq user.account.username end -- GitLab From 22cf18e16f2ff07e5cd6e90b53d1b038e1956c99 Mon Sep 17 00:00:00 2001 From: Jack Jennings Date: Tue, 30 May 2017 13:14:32 -0700 Subject: [PATCH 052/295] Fix incorrect visibility setter in StatusPolicySpec (#3456) --- spec/policies/status_policy_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb index b969988e93..8e85efb8e3 100644 --- a/spec/policies/status_policy_spec.rb +++ b/spec/policies/status_policy_spec.rb @@ -24,6 +24,7 @@ RSpec.describe StatusPolicy, type: :model do permissions :show? do it 'grants access when direct and account is viewer' do status.visibility = :direct + expect(subject).to permit(status.account, status) end @@ -42,7 +43,7 @@ RSpec.describe StatusPolicy, type: :model do end it 'grants access when private and account is viewer' do - status.visibility = :direct + status.visibility = :private expect(subject).to permit(status.account, status) end -- GitLab From 1dcfb902024a7d4049306d9bc48c499856e2e429 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 16:28:58 -0400 Subject: [PATCH 053/295] Clean up api/salmon controller (#3449) --- app/controllers/api/salmon_controller.rb | 18 ++++--- .../controllers/api/salmon_controller_spec.rb | 53 ++++++++++++------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/app/controllers/api/salmon_controller.rb b/app/controllers/api/salmon_controller.rb index 7fc5e548d6..f611b48a09 100644 --- a/app/controllers/api/salmon_controller.rb +++ b/app/controllers/api/salmon_controller.rb @@ -5,10 +5,8 @@ class Api::SalmonController < ApiController respond_to :txt def update - payload = request.body.read - - if !payload.nil? && verify?(payload) - SalmonWorker.perform_async(@account.id, payload.force_encoding('UTF-8')) + if verify_payload? + process_salmon head 201 else head 202 @@ -21,7 +19,15 @@ class Api::SalmonController < ApiController @account = Account.find(params[:id]) end - def verify?(payload) - VerifySalmonService.new.call(payload) + def payload + @_payload ||= request.body.read + end + + def verify_payload? + payload.present? && VerifySalmonService.new.call(payload) + end + + def process_salmon + SalmonWorker.perform_async(@account.id, payload.force_encoding('UTF-8')) end end diff --git a/spec/controllers/api/salmon_controller_spec.rb b/spec/controllers/api/salmon_controller_spec.rb index 6897caeebb..3e4686200b 100644 --- a/spec/controllers/api/salmon_controller_spec.rb +++ b/spec/controllers/api/salmon_controller_spec.rb @@ -13,29 +13,42 @@ RSpec.describe Api::SalmonController, type: :controller do end describe 'POST #update' do - before do - request.env['RAW_POST_DATA'] = File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) - post :update, params: { id: account.id } + context 'with valid post data' do + before do + request.env['RAW_POST_DATA'] = File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) + post :update, params: { id: account.id } + end + + it 'contains XML in the request body' do + expect(request.body.read).to be_a String + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'creates remote account' do + expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil + end + + it 'creates status' do + expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil + end + + it 'creates mention for target account' do + expect(account.mentions.count).to eq 1 + end end - it 'contains XML in the request body' do - expect(request.body.read).to be_a String - end - - it 'returns http success' do - expect(response).to have_http_status(:success) - end - - it 'creates remote account' do - expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil - end - - it 'creates status' do - expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil - end + context 'with invalid post data' do + before do + request.env['RAW_POST_DATA'] = '' + post :update, params: { id: account.id } + end - it 'creates mention for target account' do - expect(account.mentions.count).to eq 1 + it 'returns http success' do + expect(response).to have_http_status(202) + end end end end -- GitLab From 3576fa0d591db69a1727153a1130ff5bebf37167 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 16:30:06 -0400 Subject: [PATCH 054/295] Improve api oembed controller (#3450) * Add StreamEntryFinder class to parse URLs * Use StreamEntryFinder and clean up api/oembed controller --- app/controllers/api/oembed_controller.rb | 26 ++++------ app/lib/stream_entry_finder.rb | 34 ++++++++++++++ .../controllers/api/oembed_controller_spec.rb | 2 + spec/lib/stream_entry_finder_spec.rb | 47 +++++++++++++++++++ 4 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 app/lib/stream_entry_finder.rb create mode 100644 spec/lib/stream_entry_finder_spec.rb diff --git a/app/controllers/api/oembed_controller.rb b/app/controllers/api/oembed_controller.rb index 656851f43b..5761883531 100644 --- a/app/controllers/api/oembed_controller.rb +++ b/app/controllers/api/oembed_controller.rb @@ -4,30 +4,22 @@ class Api::OEmbedController < ApiController respond_to :json def show - @stream_entry = stream_entry_from_url(params[:url]) - @width = params[:maxwidth].present? ? params[:maxwidth].to_i : 400 - @height = params[:maxheight].present? ? params[:maxheight].to_i : nil + @stream_entry = find_stream_entry.stream_entry + @width = maxwidth_or_default + @height = maxheight_or_default end private - def stream_entry_from_url(url) - params = Rails.application.routes.recognize_path(url) - - raise ActiveRecord::RecordNotFound unless recognized_stream_entry_url?(params) - - stream_entry(params) + def find_stream_entry + StreamEntryFinder.new(params[:url]) end - def recognized_stream_entry_url?(params) - %w(stream_entries statuses).include?(params[:controller]) && params[:action] == 'show' + def maxwidth_or_default + (params[:maxwidth].presence || 400).to_i end - def stream_entry(params) - if params[:controller] == 'stream_entries' - StreamEntry.find(params[:id]) - else - Status.find(params[:id]).stream_entry - end + def maxheight_or_default + params[:maxheight].present? ? params[:maxheight].to_i : nil end end diff --git a/app/lib/stream_entry_finder.rb b/app/lib/stream_entry_finder.rb new file mode 100644 index 0000000000..0ea33229ce --- /dev/null +++ b/app/lib/stream_entry_finder.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class StreamEntryFinder + attr_reader :url + + def initialize(url) + @url = url + end + + def stream_entry + verify_action! + + case recognized_params[:controller] + when 'stream_entries' + StreamEntry.find(recognized_params[:id]) + when 'statuses' + Status.find(recognized_params[:id]).stream_entry + else + raise ActiveRecord::RecordNotFound + end + end + + private + + def recognized_params + Rails.application.routes.recognize_path(url) + end + + def verify_action! + unless recognized_params[:action] == 'show' + raise ActiveRecord::RecordNotFound + end + end +end diff --git a/spec/controllers/api/oembed_controller_spec.rb b/spec/controllers/api/oembed_controller_spec.rb index 511cdb4639..43631a7e5a 100644 --- a/spec/controllers/api/oembed_controller_spec.rb +++ b/spec/controllers/api/oembed_controller_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' RSpec.describe Api::OEmbedController, type: :controller do + render_views + let(:alice) { Fabricate(:account, username: 'alice') } let(:status) { Fabricate(:status, text: 'Hello world', account: alice) } diff --git a/spec/lib/stream_entry_finder_spec.rb b/spec/lib/stream_entry_finder_spec.rb new file mode 100644 index 0000000000..88ba72b115 --- /dev/null +++ b/spec/lib/stream_entry_finder_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe StreamEntryFinder do + include RoutingHelper + + describe '#stream_entry' do + context 'with a status url' do + let(:status) { Fabricate(:status) } + let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) } + subject { described_class.new(url) } + + it 'finds the stream entry' do + expect(subject.stream_entry).to eq(status.stream_entry) + end + end + + context 'with a stream entry url' do + let(:stream_entry) { Fabricate(:stream_entry) } + let(:url) { account_stream_entry_url(stream_entry.account, stream_entry) } + subject { described_class.new(url) } + + it 'finds the stream entry' do + expect(subject.stream_entry).to eq(stream_entry) + end + end + + context 'with a plausible url' do + let(:url) { 'https://example.com/users/test/updates/123/embed' } + subject { described_class.new(url) } + + it 'raises an error' do + expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + context 'with an unrecognized url' do + let(:url) { 'https://example.com/about' } + subject { described_class.new(url) } + + it 'raises an error' do + expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end +end -- GitLab From 33f669a5f851b4095fb6189147ae0fe6f8343d44 Mon Sep 17 00:00:00 2001 From: Jack Jennings Date: Tue, 30 May 2017 13:56:31 -0700 Subject: [PATCH 055/295] Add status destroy authorization to policy (#3453) * Add status destroy authorization to policy * Create explicit unreblog status authorization --- .../admin/reported_statuses_controller.rb | 3 ++ app/controllers/api/v1/statuses_controller.rb | 5 ++++ app/policies/status_policy.rb | 18 +++++++++-- app/services/process_interaction_service.rb | 7 +++-- spec/policies/status_policy_spec.rb | 20 +++++++++++++ .../process_interaction_service_spec.rb | 30 ++++++++++++++++++- 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/app/controllers/admin/reported_statuses_controller.rb b/app/controllers/admin/reported_statuses_controller.rb index 0e7a894370..32434d30f7 100644 --- a/app/controllers/admin/reported_statuses_controller.rb +++ b/app/controllers/admin/reported_statuses_controller.rb @@ -2,6 +2,8 @@ module Admin class ReportedStatusesController < BaseController + include Authorization + before_action :set_report before_action :set_status @@ -11,6 +13,7 @@ module Admin end def destroy + authorize @status, :destroy? RemovalWorker.perform_async(@status.id) redirect_to admin_report_path(@report) end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 592540f457..7386d71582 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -79,7 +79,10 @@ class Api::V1::StatusesController < ApiController def destroy @status = Status.where(account_id: current_user.account).find(params[:id]) + authorize @status, :destroy? + RemovalWorker.perform_async(@status.id) + render_empty end @@ -93,6 +96,8 @@ class Api::V1::StatusesController < ApiController @status = reblog.reblog @reblogs_map = { @status.id => false } + authorize reblog, :unreblog? + RemovalWorker.perform_async(reblog.id) render :show diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 41d63fcbcb..2ded61850a 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -10,9 +10,9 @@ class StatusPolicy def show? if direct? - status.account.id == account&.id || status.mentions.where(account: account).exists? + owned? || status.mentions.where(account: account).exists? elsif private? - status.account.id == account&.id || account&.following?(status.account) || status.mentions.where(account: account).exists? + owned? || account&.following?(status.account) || status.mentions.where(account: account).exists? else account.nil? || !status.account.blocking?(account) end @@ -22,12 +22,26 @@ class StatusPolicy !direct? && !private? && show? end + def destroy? + admin? || owned? + end + + alias unreblog? destroy? + private + def admin? + account&.user&.admin? + end + def direct? status.direct_visibility? end + def owned? + status.account.id == account&.id + end + def private? status.private_visibility? end diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb index bd9afaf2ef..584a109ad4 100644 --- a/app/services/process_interaction_service.rb +++ b/app/services/process_interaction_service.rb @@ -2,6 +2,7 @@ class ProcessInteractionService < BaseService include AuthorExtractor + include Authorization # Record locally the remote interaction with our user # @param [String] envelope Salmon envelope @@ -46,7 +47,7 @@ class ProcessInteractionService < BaseService reflect_unblock!(account, target_account) end end - rescue Goldfinger::Error, HTTP::Error, OStatus2::BadSalmonError + rescue Goldfinger::Error, HTTP::Error, OStatus2::BadSalmonError, Mastodon::NotPermittedError nil end @@ -103,7 +104,9 @@ class ProcessInteractionService < BaseService return if status.nil? - RemovalWorker.perform_async(status.id) if account.id == status.account_id + authorize_with account, status, :destroy? + + RemovalWorker.perform_async(status.id) end def favourite!(xml, from_account) diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb index 8e85efb8e3..bacb8fd9e3 100644 --- a/spec/policies/status_policy_spec.rb +++ b/spec/policies/status_policy_spec.rb @@ -4,7 +4,9 @@ require 'pundit/rspec' RSpec.describe StatusPolicy, type: :model do subject { described_class } + let(:admin) { Fabricate(:user, admin: true) } let(:alice) { Fabricate(:account, username: 'alice') } + let(:bob) { Fabricate(:account, username: 'bob') } let(:status) { Fabricate(:status, account: alice) } permissions :show?, :reblog? do @@ -86,4 +88,22 @@ RSpec.describe StatusPolicy, type: :model do expect(subject).to_not permit(viewer, status) end end + + permissions :destroy?, :unreblog? do + it 'grants access when account is deleter' do + expect(subject).to permit(status.account, status) + end + + it 'grants access when account is admin' do + expect(subject).to permit(admin.account, status) + end + + it 'denies access when account is not deleter' do + expect(subject).to_not permit(bob, status) + end + + it 'denies access when no deleter' do + expect(subject).to_not permit(nil, status) + end + end end diff --git a/spec/services/process_interaction_service_spec.rb b/spec/services/process_interaction_service_spec.rb index f589f690df..3ea7aec59b 100644 --- a/spec/services/process_interaction_service_spec.rb +++ b/spec/services/process_interaction_service_spec.rb @@ -7,6 +7,35 @@ RSpec.describe ProcessInteractionService do subject { ProcessInteractionService.new } + describe 'status delete slap' do + let(:remote_status) { Fabricate(:status, account: remote_sender) } + let(:envelope) { OStatus2::Salmon.new.pack(payload, sender.keypair) } + let(:payload) { + <<~XML + + + carol@localdomain.com + carol + https://webdomain.com/users/carol + + + #{remote_status.id} + http://activitystrea.ms/schema/1.0/delete + + XML + } + + before do + receiver.update(locked: true) + remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key) + end + + it 'deletes a record' do + expect(RemovalWorker).to receive(:perform_async).with(remote_status.id) + subject.call(envelope, receiver) + end + end + describe 'follow request slap' do before do receiver.update(locked: true) @@ -60,7 +89,6 @@ XML end end - describe 'follow request authorization slap' do before do receiver.update(locked: true) -- GitLab From bfdf47bc989d3d690fbf003f0c6503c3c39b834e Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Wed, 31 May 2017 06:09:02 +0900 Subject: [PATCH 056/295] Add zh-TW.json (#3459) --- .../mastodon/locales/whitelist_zh-TW.json | 2 + app/javascript/mastodon/locales/zh-TW.json | 176 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 app/javascript/mastodon/locales/whitelist_zh-TW.json create mode 100644 app/javascript/mastodon/locales/zh-TW.json diff --git a/app/javascript/mastodon/locales/whitelist_zh-TW.json b/app/javascript/mastodon/locales/whitelist_zh-TW.json new file mode 100644 index 0000000000..0d4f101c7a --- /dev/null +++ b/app/javascript/mastodon/locales/whitelist_zh-TW.json @@ -0,0 +1,2 @@ +[ +] diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json new file mode 100644 index 0000000000..6864123aec --- /dev/null +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -0,0 +1,176 @@ +{ + "account.block": "Block @{name}", + "account.block_domain": "Hide everything from {domain}", + "account.disclaimer": "This user is from another instance. This number may be larger.", + "account.edit_profile": "Edit profile", + "account.follow": "Follow", + "account.followers": "Followers", + "account.follows": "Follows", + "account.follows_you": "Follows you", + "account.media": "Media", + "account.mention": "Mention @{name}", + "account.mute": "Mute @{name}", + "account.posts": "Posts", + "account.report": "Report @{name}", + "account.requested": "Awaiting approval", + "account.unblock": "Unblock @{name}", + "account.unblock_domain": "Unhide {domain}", + "account.unfollow": "Unfollow", + "account.unmute": "Unmute @{name}", + "boost_modal.combo": "You can press {combo} to skip this next time", + "column.blocks": "Blocked users", + "column.community": "Local timeline", + "column.favourites": "Favourites", + "column.follow_requests": "Follow requests", + "column.home": "Home", + "column.mutes": "Muted users", + "column.notifications": "Notifications", + "column.public": "Federated timeline", + "column_back_button.label": "Back", + "column_subheading.navigation": "Navigation", + "column_subheading.settings": "Settings", + "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", + "compose_form.lock_disclaimer.lock": "locked", + "compose_form.placeholder": "What is on your mind?", + "compose_form.privacy_disclaimer": "Your post will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is not a public post, and it may be boosted or otherwise made visible to unintended recipients.", + "compose_form.publish": "Toot", + "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive": "Mark media as sensitive", + "compose_form.spoiler": "Hide text behind warning", + "compose_form.spoiler_placeholder": "Content warning", + "confirmation_modal.cancel": "Cancel", + "confirmations.block.confirm": "Block", + "confirmations.block.message": "Are you sure you want to block {name}?", + "confirmations.delete.confirm": "Delete", + "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", + "confirmations.mute.confirm": "Mute", + "confirmations.mute.message": "Are you sure you want to mute {name}?", + "emoji_button.activity": "Activity", + "emoji_button.flags": "Flags", + "emoji_button.food": "Food & Drink", + "emoji_button.label": "Insert emoji", + "emoji_button.nature": "Nature", + "emoji_button.objects": "Objects", + "emoji_button.people": "People", + "emoji_button.search": "Search...", + "emoji_button.symbols": "Symbols", + "emoji_button.travel": "Travel & Places", + "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", + "empty_column.hashtag": "There is nothing in this hashtag yet.", + "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", + "empty_column.home.public_timeline": "the public timeline", + "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", + "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", + "follow_request.authorize": "Authorize", + "follow_request.reject": "Reject", + "getting_started.appsshort": "Apps", + "getting_started.faq": "FAQ", + "getting_started.heading": "Getting started", + "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", + "getting_started.support": "{faq} • {userguide} • {apps}", + "getting_started.userguide": "User Guide", + "home.column_settings.advanced": "Advanced", + "home.column_settings.basic": "Basic", + "home.column_settings.filter_regex": "Filter out by regular expressions", + "home.column_settings.show_reblogs": "Show boosts", + "home.column_settings.show_replies": "Show replies", + "home.settings": "Column settings", + "lightbox.close": "Close", + "loading_indicator.label": "Loading...", + "media_gallery.toggle_visible": "Toggle visibility", + "missing_indicator.label": "Not found", + "navigation_bar.blocks": "Blocked users", + "navigation_bar.community_timeline": "Local timeline", + "navigation_bar.edit_profile": "Edit profile", + "navigation_bar.favourites": "Favourites", + "navigation_bar.follow_requests": "Follow requests", + "navigation_bar.info": "Extended information", + "navigation_bar.logout": "Logout", + "navigation_bar.mutes": "Muted users", + "navigation_bar.preferences": "Preferences", + "navigation_bar.public_timeline": "Federated timeline", + "notification.favourite": "{name} favourited your status", + "notification.follow": "{name} followed you", + "notification.mention": "{name} mentioned you", + "notification.reblog": "{name} boosted your status", + "notifications.clear": "Clear notifications", + "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", + "notifications.column_settings.alert": "Desktop notifications", + "notifications.column_settings.favourite": "Favourites:", + "notifications.column_settings.follow": "New followers:", + "notifications.column_settings.mention": "Mentions:", + "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.show": "Show in column", + "notifications.column_settings.sound": "Play sound", + "notifications.settings": "Column settings", + "onboarding.done": "Done", + "onboarding.next": "Next", + "onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.", + "onboarding.page_four.home": "The home timeline shows posts from people you follow.", + "onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.", + "onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.", + "onboarding.page_one.handle": "You are on {domain}, so your full handle is {handle}", + "onboarding.page_one.welcome": "Welcome to Mastodon!", + "onboarding.page_six.admin": "Your instance's admin is {admin}.", + "onboarding.page_six.almost_done": "Almost done...", + "onboarding.page_six.appetoot": "Bon Appetoot!", + "onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.", + "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.", + "onboarding.page_six.guidelines": "community guidelines", + "onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!", + "onboarding.page_six.various_app": "mobile apps", + "onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.", + "onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.", + "onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.", + "onboarding.skip": "Skip", + "privacy.change": "Adjust status privacy", + "privacy.direct.long": "Post to mentioned users only", + "privacy.direct.short": "Direct", + "privacy.private.long": "Post to followers only", + "privacy.private.short": "Followers-only", + "privacy.public.long": "Post to public timelines", + "privacy.public.short": "Public", + "privacy.unlisted.long": "Do not post to public timelines", + "privacy.unlisted.short": "Unlisted", + "reply_indicator.cancel": "Cancel", + "report.heading": "New report", + "report.placeholder": "Additional comments", + "report.submit": "Submit", + "report.target": "Reporting", + "search.placeholder": "Search", + "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "status.cannot_reblog": "This post cannot be boosted", + "status.delete": "Delete", + "status.favourite": "Favourite", + "status.load_more": "Load more", + "status.media_hidden": "Media hidden", + "status.mention": "Mention @{name}", + "status.mute_conversation": "Mute conversation", + "status.open": "Expand this status", + "status.reblog": "Boost", + "status.reblogged_by": "{name} boosted", + "status.reply": "Reply", + "status.replyAll": "Reply to thread", + "status.report": "Report @{name}", + "status.sensitive_toggle": "Click to view", + "status.sensitive_warning": "Sensitive content", + "status.show_less": "Show less", + "status.show_more": "Show more", + "status.unmute_conversation": "Unmute conversation", + "tabs_bar.compose": "Compose", + "tabs_bar.federated_timeline": "Federated", + "tabs_bar.home": "Home", + "tabs_bar.local_timeline": "Local", + "tabs_bar.notifications": "Notifications", + "upload_area.title": "Drag & drop to upload", + "upload_button.label": "Add media", + "upload_form.undo": "Undo", + "upload_progress.label": "Uploading...", + "video_player.expand": "Expand video", + "video_player.toggle_sound": "Toggle sound", + "video_player.toggle_visible": "Toggle visibility", + "video_player.video_error": "Video could not be played" +} -- GitLab From b1d4b74a44c75cdee8c7faa88e3b5c3396acfa5a Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Wed, 31 May 2017 09:14:26 +0900 Subject: [PATCH 057/295] Change PureComponent to ImmutablePureComponent (#3460) * Change PureComponent to ImmutablePureComponent Change PureComponent to ImmutablePureComponent in AttachmentList. * rm React. --- app/javascript/mastodon/components/attachment_list.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/attachment_list.js b/app/javascript/mastodon/components/attachment_list.js index 54d3643bd9..a57c25ad0b 100644 --- a/app/javascript/mastodon/components/attachment_list.js +++ b/app/javascript/mastodon/components/attachment_list.js @@ -1,9 +1,10 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; const filename = url => url.split('/').pop().split('#')[0].split('?')[0]; -class AttachmentList extends React.PureComponent { +class AttachmentList extends ImmutablePureComponent { static propTypes = { media: ImmutablePropTypes.list.isRequired, -- GitLab From 93de41b39b5aa287671cdf80ee26b5b96e0cf612 Mon Sep 17 00:00:00 2001 From: spla Date: Wed, 31 May 2017 02:14:52 +0200 Subject: [PATCH 058/295] Catalan language updates (#3454) * Add Catalan language * Add Catalan language * Update ca.json * Update ca.json * Update ca.json * Update ca.json * Update ca.json * Update ca.json * Update settings_helper.rb * Update mastodon.js * Update index.js * Update application.rb * Update ca.yml * removed extra spaces at line 225 * Catalan translation update added activerecord.ca.yml * Update activerecord.ca.yml Done * Updated activerecord.ca.yml * Catalan language updated * Catalan language updated * Catalan language updated * Catalan language updated * Catalan language updated --- app/javascript/mastodon/locales/ca.json | 18 ++++++++--------- config/locales/ca.yml | 27 ++++++++++++++++--------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 1f3c465a87..acd2b72163 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -1,6 +1,6 @@ { "account.block": "Bloquejar @{name}", - "account.block_domain": "Hide everything from {domain}", + "account.block_domain": "Amagar tot de {domain}", "account.disclaimer": "Aquest usuari és d'un altra instància. Aquest número podria ser més gran.", "account.edit_profile": "Editar perfil", "account.follow": "Seguir", @@ -14,7 +14,7 @@ "account.report": "Informe @{name}", "account.requested": "Esperant aprovació", "account.unblock": "Desbloquejar @{name}", - "account.unblock_domain": "Unhide {domain}", + "account.unblock_domain": "Mostra {domain}", "account.unfollow": "Deixar de seguir", "account.unmute": "Treure silenci de @{name}", "boost_modal.combo": "Pots premer {combo} per saltar-te això el proper cop", @@ -43,8 +43,8 @@ "confirmations.block.message": "Estàs segur que vols bloquejar {name}?", "confirmations.delete.confirm": "Esborrar", "confirmations.delete.message": "Estàs segur que vols esborrar aquest estat?", - "confirmations.domain_block.confirm": "Hide entire domain", - "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", + "confirmations.domain_block.confirm": "Amagar tot el domini", + "confirmations.domain_block.message": "Estàs realment, realment segur que vols bloquejar totalment {domain}? En la majoria dels casos bloquejar o silenciar és suficient i preferible.", "confirmations.mute.confirm": "Silenciar", "confirmations.mute.message": "Estàs segur que vols silenciar {name}?", "emoji_button.activity": "Activitat", @@ -67,9 +67,9 @@ "follow_request.authorize": "Autoritzar", "follow_request.reject": "Rebutjar", "getting_started.appsshort": "Apps", - "getting_started.faq": "FAQ", - "getting_started.heading": "començant", - "getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir o informar de problemes en GitHub a {github}.", + "getting_started.faq": "PMF", + "getting_started.heading": "Començant", + "getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir o informar de problemes a GitHub de {github}.", "getting_started.support": "{faq} • {userguide} • {apps}", "getting_started.userguide": "Guia de l'usuari", "home.column_settings.advanced": "Avançat", @@ -122,12 +122,12 @@ "onboarding.page_six.guidelines": "Normes de la comunitat", "onboarding.page_six.read_guidelines": "Si us plau llegeix les {guidelines} de {domain}!", "onboarding.page_six.various_app": "aplicacions per mòbils", - "onboarding.page_three.profile": "Edita el teu perfil per canviar el teu avatar, bio i el nom de visualització. Allà també trobaràs altres preferències.", + "onboarding.page_three.profile": "Edita el teu perfil per canviar el teu avatar, bio o el nom de visualització. També hi trobaràs altres preferències.", "onboarding.page_three.search": "Utilitza la barra de cerca per trobar gent i mirar etiquetes, com a {illustration} i {introductions}. Per buscar una persona que no està en aquesta instància, utilitza tot el seu nom d'usuari complert.", "onboarding.page_two.compose": "Escriu missatges en la columna de redacció. Pots pujar imatges, canviar la configuració de privacitat i afegir les advertències de contingut amb les icones de sota.", "onboarding.skip": "Omet", "privacy.change": "Ajusta l'estat de privacitat", - "privacy.direct.long": "Publicar només als usuaris esmentats", + "privacy.direct.long": "Publicar només per als usuaris esmentats", "privacy.direct.short": "Directe", "privacy.private.long": "Publicar només a seguidors", "privacy.private.short": "Només seguidors", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index f7a0fd65ae..e3b3a91f93 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -7,7 +7,7 @@ ca: business_email: 'Correu de negocis:' closed_registrations: Els registres estan actualment tancats en aquesta instància. contact: Contacte - description_headline: "Què es %{domain}?" + description_headline: Què es %{domain}? domain_count_after: altres instàncies domain_count_before: Connectat a features: @@ -34,7 +34,7 @@ ca: follow: Seguir followers: Seguidors following: Seguint - nothing_here: "No hi ha res aquí!" + nothing_here: No hi ha res aquí! people_followed_by: Usuaris a qui %{name} segueix people_who_follow: Usuaris que segueixn a %{name} posts: Toots @@ -48,7 +48,7 @@ ca: name: "%{account_name} created a note." outbox: name: "%{account_name}'s Outbox" - summary: "A collection of activities from user %{account_name}." + summary: A collection of activities from user %{account_name}. admin: accounts: are_you_sure: Estàs segur? @@ -62,6 +62,7 @@ ca: feed_url: URL del feed followers: Seguidors follows: Segueix + ip: IP location: all: Tot local: Local @@ -84,8 +85,10 @@ ca: profile_url: URL del perfil public: Públic push_subscription_expires: La subscripció PuSH expira + reset: Reajustar reset_password: Restablir la contrasenya salmon_url: URL Salmon + search: Cerca show: created_reports: Informes creats per aquest compte report: informe @@ -118,8 +121,8 @@ ca: severity: Severitat show: affected_accounts: - one: Un compte en la base de dades afectat - other: "%{count} comptes en la base de dades afectats" + one: Un compte afectat en la base de dades + other: "%{count} comptes afectats en la base de dades" retroactive: silence: Desfer el silenci a tots els comptes existents d'aquest domini suspend: Desfer la suspensió de tots els comptes d'aquest domini @@ -139,12 +142,16 @@ ca: title: PubSubHubbub topic: Tòpic reports: + are_you_sure: Estàs segur? comment: label: Comentari none: Cap delete: Esborra id: ID mark_as_resolved: Marca com a resolt + nsfw: + 'false': NSFW OFF + 'true': NSFW ON report: 'Informe #%{id}' report_contents: Continguts reported_account: Compte reportat @@ -242,12 +249,12 @@ ca: unlocked_warning_html: Tothom pot seguir-te per veure inmediatament les teves publicacions privades. %{lock_link} per poder revisar i rebutjar seguidors. unlocked_warning_title: El teu compte no està bloquejat generic: - changes_saved_msg: "Canvis guardats amb èxit!" + changes_saved_msg: Canvis guardats amb èxit! powered_by: powered by %{link} save_changes: Guardar canvis validation_errors: - one: "Alguna cosa no esta bé! Si us plau, revisi l'error" - other: "Alguna cosa no esta bé! Si us plau, revisi %{count} errors més a baix" + one: Alguna cosa no esta bé! Si us plau, revisi l'error + other: Alguna cosa no esta bé! Si us plau, revisi %{count} errors més a baix imports: preface: Pots importar algunes dades, com ara totes les persones que estàs seguint o bloquejant, en el teu compte en aquesta instància, desde arxius exportats desde una altra instància. success: Dades rebudes correctament i seran processades en breu @@ -267,8 +274,8 @@ ca: body: 'Un resum del que et vas perdre en %{instance} desde la teva darrera visita el %{since}:' mention: "%{name} t'ha mencionat en:" new_followers_summary: - one: "Visca!. Algú més t´ha començat a seguir" - other: "Genial!. T'han seguit %{count} noves persones" + one: Visca!. Algú més t´ha començat a seguir + other: Genial!. T'han seguit %{count} noves persones subject: one: "1 nova notificació desde la teva darrera visita \U0001F418" other: "%{count} noves notificacions desde la teva darrera visita \U0001F418" -- GitLab From 83435c49ea4f31d80d81658d8faa69ed5350e26f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 20:15:09 -0400 Subject: [PATCH 059/295] Clean up api/subscriptions controller (#3448) --- .../api/subscriptions_controller.rb | 31 +++++++++++++++---- .../api/subscriptions_controller_spec.rb | 27 +++++++++++----- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb index 135a5632e6..dd2f42aab7 100644 --- a/app/controllers/api/subscriptions_controller.rb +++ b/app/controllers/api/subscriptions_controller.rb @@ -5,18 +5,15 @@ class Api::SubscriptionsController < ApiController respond_to :txt def show - if @account.subscription(api_subscription_url(@account.id)).valid?(params['hub.topic']) - @account.update(subscription_expires_at: Time.now.utc + (params['hub.lease_seconds'] || 86_400).to_i.seconds) - render plain: HTMLEntities.new.encode(params['hub.challenge']), status: 200 + if subscription.valid?(params['hub.topic']) + @account.update(subscription_expires_at: future_expires) + render plain: encoded_challenge, status: 200 else head 404 end end def update - body = request.body.read - subscription = @account.subscription(api_subscription_url(@account.id)) - if subscription.verify(body, request.headers['HTTP_X_HUB_SIGNATURE']) ProcessingWorker.perform_async(@account.id, body.force_encoding('UTF-8')) end @@ -26,6 +23,28 @@ class Api::SubscriptionsController < ApiController private + def subscription + @_subscription ||= @account.subscription( + api_subscription_url(@account.id) + ) + end + + def body + @_body ||= request.body.read + end + + def encoded_challenge + HTMLEntities.new.encode(params['hub.challenge']) + end + + def future_expires + Time.now.utc + lease_seconds_or_default + end + + def lease_seconds_or_default + (params['hub.lease_seconds'] || 86_400).to_i.seconds + end + def set_account @account = Account.find(params[:id]) end diff --git a/spec/controllers/api/subscriptions_controller_spec.rb b/spec/controllers/api/subscriptions_controller_spec.rb index 97e36420d6..76f9740ca5 100644 --- a/spec/controllers/api/subscriptions_controller_spec.rb +++ b/spec/controllers/api/subscriptions_controller_spec.rb @@ -6,16 +6,29 @@ RSpec.describe Api::SubscriptionsController, type: :controller do let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', remote_url: 'topic_url', secret: 'abc') } describe 'GET #show' do - before do - get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => "#{86400 * 30}" } - end + context 'with valid subscription' do + before do + get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => "#{86400 * 30}" } + end - it 'returns http success' do - expect(response).to have_http_status(:success) + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'echoes back the challenge' do + expect(response.body).to match '456' + end end - it 'echoes back the challenge' do - expect(response.body).to match '456' + context 'with invalid subscription' do + before do + expect_any_instance_of(Account).to receive_message_chain(:subscription, :valid?).and_return(false) + get :show, params: { :id => account.id } + end + + it 'returns http success' do + expect(response).to have_http_status(:missing) + end end end -- GitLab From 82356233621300b51b3e2a2c093e9c4107e12e81 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 21:11:29 -0400 Subject: [PATCH 060/295] Improve spec coverage and clean up api/v1/media controller (#3467) --- app/controllers/api/v1/media_controller.rb | 14 ++++++++--- .../api/v1/media_controller_spec.rb | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb index aed3578d7e..3d7dcef420 100644 --- a/app/controllers/api/v1/media_controller.rb +++ b/app/controllers/api/v1/media_controller.rb @@ -10,11 +10,11 @@ class Api::V1::MediaController < ApiController respond_to :json def create - @media = MediaAttachment.create!(account: current_user.account, file: media_params[:file]) + @media = current_account.media_attachments.create!(file: media_params[:file]) rescue Paperclip::Errors::NotIdentifiedByImageMagickError - render json: { error: 'File type of uploaded media could not be verified' }, status: 422 + render json: file_type_error, status: 422 rescue Paperclip::Error - render json: { error: 'Error processing thumbnail for uploaded media' }, status: 500 + render json: processing_error, status: 500 end private @@ -22,4 +22,12 @@ class Api::V1::MediaController < ApiController def media_params params.permit(:file) end + + def file_type_error + { error: 'File type of uploaded media could not be verified' } + end + + def processing_error + { error: 'Error processing thumbnail for uploaded media' } + end end diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb index b1d9798eac..00dcac95dc 100644 --- a/spec/controllers/api/v1/media_controller_spec.rb +++ b/spec/controllers/api/v1/media_controller_spec.rb @@ -11,6 +11,30 @@ RSpec.describe Api::V1::MediaController, type: :controller do end describe 'POST #create' do + describe 'with paperclip errors' do + context 'when imagemagick cant identify the file type' do + before do + expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError) + post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') } + end + + it 'returns http 422' do + expect(response).to have_http_status(:unprocessable_entity) + end + end + + context 'when there is a generic error' do + before do + expect_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error) + post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') } + end + + it 'returns http 422' do + expect(response).to have_http_status(:error) + end + end + end + context 'image/jpeg' do before do post :create, params: { file: fixture_file_upload('files/attachment.jpg', 'image/jpeg') } -- GitLab From 7f554306523f0ba531df768f21f6609d186406ea Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 21:11:54 -0400 Subject: [PATCH 061/295] Refactor api/v1/search controller (#3468) --- app/controllers/api/v1/search_controller.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index 6b12924581..1ee2589a01 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -1,9 +1,26 @@ # frozen_string_literal: true class Api::V1::SearchController < ApiController + RESULTS_LIMIT = 5 + respond_to :json def index - @search = OpenStruct.new(SearchService.new.call(params[:q], 5, params[:resolve] == 'true', current_account)) + @search = OpenStruct.new(search_results) + end + + private + + def search_results + SearchService.new.call( + params[:q], + RESULTS_LIMIT, + resolving_search?, + current_account + ) + end + + def resolving_search? + params[:resolve] == 'true' end end -- GitLab From 7c6e02aaf3e3771448ada4197eda66322dff714f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 21:13:31 -0400 Subject: [PATCH 062/295] Refactor api/v1/reports controller (#3469) --- app/controllers/api/v1/reports_controller.rb | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index f83c573cb5..e0f9ed2322 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -8,22 +8,32 @@ class Api::V1::ReportsController < ApiController respond_to :json def index - @reports = Report.where(account: current_account) + @reports = current_account.reports end def create - status_ids = report_params[:status_ids].is_a?(Enumerable) ? report_params[:status_ids] : [report_params[:status_ids]] - - @report = Report.create!(account: current_account, - target_account: Account.find(report_params[:account_id]), - status_ids: Status.find(status_ids).pluck(:id), - comment: report_params[:comment]) - + @report = current_account.reports.create!( + target_account: reported_account, + status_ids: reported_status_ids, + comment: report_params[:comment] + ) render :show end private + def reported_status_ids + Status.find(status_ids).pluck(:id) + end + + def status_ids + Array(report_params[:status_ids]) + end + + def reported_account + Account.find(report_params[:account_id]) + end + def report_params params.permit(:account_id, :comment, status_ids: []) end -- GitLab From 79335e46fd784f21ef5e9c8ae861e6820e422e29 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 May 2017 21:16:28 -0400 Subject: [PATCH 063/295] Refactor api/v1/apps controller (#3471) --- app/controllers/api/v1/apps_controller.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/apps_controller.rb b/app/controllers/api/v1/apps_controller.rb index 2ec7280af0..54f8d40b20 100644 --- a/app/controllers/api/v1/apps_controller.rb +++ b/app/controllers/api/v1/apps_controller.rb @@ -4,11 +4,24 @@ class Api::V1::AppsController < ApiController respond_to :json def create - @app = Doorkeeper::Application.create!(name: app_params[:client_name], redirect_uri: app_params[:redirect_uris], scopes: (app_params[:scopes] || Doorkeeper.configuration.default_scopes), website: app_params[:website]) + @app = Doorkeeper::Application.create!(application_options) end private + def application_options + { + name: app_params[:client_name], + redirect_uri: app_params[:redirect_uris], + scopes: app_scopes_or_default, + website: app_params[:website], + } + end + + def app_scopes_or_default + app_params[:scopes] || Doorkeeper.configuration.default_scopes + end + def app_params params.permit(:client_name, :redirect_uris, :scopes, :website) end -- GitLab From 3652a39de0d40acad1f2b170c74338b4fda01359 Mon Sep 17 00:00:00 2001 From: alpaca-tc Date: Wed, 31 May 2017 22:10:26 +0900 Subject: [PATCH 064/295] Account.find_remote should be raise ActiveRecord::RecordNotFound (#3476) --- app/models/account.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/account.rb b/app/models/account.rb index f5ac892578..cb116dbaf6 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -167,7 +167,7 @@ class Account < ApplicationRecord end def find_remote!(username, domain) - return if username.blank? + raise ActiveRecord::RecordNotFound if username.blank? where('lower(accounts.username) = ?', username.downcase).where(domain.nil? ? { domain: nil } : 'lower(accounts.domain) = ?', domain&.downcase).take! end -- GitLab From 0e12a8dab9ccec83b91722a8b0a065c0919af98a Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Wed, 31 May 2017 06:11:33 -0700 Subject: [PATCH 065/295] Improve scheduling of requestIdleCallback tasks (#3477) --- app/javascript/mastodon/components/status.js | 3 +- .../features/ui/util/schedule_idle_task.js | 29 +++++++++++++++++++ package.json | 1 + yarn.lock | 4 +++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 app/javascript/mastodon/features/ui/util/schedule_idle_task.js diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index d35642ede8..2abe50f0b7 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -14,6 +14,7 @@ import { FormattedMessage } from 'react-intl'; import emojify from '../emoji'; import escapeTextContentForBrowser from 'escape-html'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import scheduleIdleTask from '../features/ui/util/schedule_idle_task'; class Status extends ImmutablePureComponent { @@ -92,7 +93,7 @@ class Status extends ImmutablePureComponent { const isIntersecting = entry.intersectionRatio > 0; this.setState((prevState) => { if (prevState.isIntersecting && !isIntersecting) { - requestIdleCallback(this.hideIfNotIntersecting); + scheduleIdleTask(this.hideIfNotIntersecting); } return { isIntersecting: isIntersecting, diff --git a/app/javascript/mastodon/features/ui/util/schedule_idle_task.js b/app/javascript/mastodon/features/ui/util/schedule_idle_task.js new file mode 100644 index 0000000000..b04d4a8eef --- /dev/null +++ b/app/javascript/mastodon/features/ui/util/schedule_idle_task.js @@ -0,0 +1,29 @@ +// Wrapper to call requestIdleCallback() to schedule low-priority work. +// See https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API +// for a good breakdown of the concepts behind this. + +import Queue from 'tiny-queue'; + +const taskQueue = new Queue(); +let runningRequestIdleCallback = false; + +function runTasks(deadline) { + while (taskQueue.length && deadline.timeRemaining() > 0) { + taskQueue.shift()(); + } + if (taskQueue.length) { + requestIdleCallback(runTasks); + } else { + runningRequestIdleCallback = false; + } +} + +function scheduleIdleTask(task) { + taskQueue.push(task); + if (!runningRequestIdleCallback) { + runningRequestIdleCallback = true; + requestIdleCallback(runTasks); + } +} + +export default scheduleIdleTask; diff --git a/package.json b/package.json index 8bdf6f21b9..92221d8e40 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "stringz": "^0.2.0", "style-loader": "^0.16.1", "throng": "^4.0.0", + "tiny-queue": "^0.2.1", "uuid": "^3.0.1", "uws": "^0.14.5", "webpack": "^2.5.1", diff --git a/yarn.lock b/yarn.lock index 71da80c1a3..d3317f59c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6510,6 +6510,10 @@ tiny-emitter@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.0.2.tgz#8e49470d3f55f89e247210368a6bb9fb51aa1601" +tiny-queue@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" -- GitLab From e49dc6a06eb18af023da82d60e485cd3c382fc96 Mon Sep 17 00:00:00 2001 From: unarist Date: Wed, 31 May 2017 22:30:26 +0900 Subject: [PATCH 066/295] Fix load more on account timelines (regression from #3311) (#3475) This prevents `next` state from being overridden on the loading *new* statuses. --- app/javascript/mastodon/actions/accounts.js | 8 ++++++-- app/javascript/mastodon/reducers/timelines.js | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index 48ab7b6ede..4050324607 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -107,7 +107,9 @@ export function fetchAccountTimeline(id, replace = false) { let params = {}; let skipLoading = false; - if (newestId !== null && !replace) { + replace = replace || newestId === null; + + if (!replace) { params.since_id = newestId; skipLoading = true; } @@ -131,7 +133,9 @@ export function fetchAccountMediaTimeline(id, replace = false) { let params = { only_media: 'true', limit: 12 }; let skipLoading = false; - if (newestId !== null && !replace) { + replace = replace || newestId === null; + + if (!replace) { params.since_id = newestId; skipLoading = true; } diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js index 0087a06ce4..ab756b8546 100644 --- a/app/javascript/mastodon/reducers/timelines.js +++ b/app/javascript/mastodon/reducers/timelines.js @@ -138,7 +138,7 @@ const normalizeAccountTimeline = (state, accountId, statuses, replace, next) => return state.updateIn(['accounts_timelines', accountId], Immutable.Map(), map => map .set('isLoading', false) .set('loaded', true) - .set('next', next) + .update('next', null, v => replace ? next : v) .update('items', Immutable.List(), list => (replace ? ids : ids.concat(list)))); }; @@ -152,7 +152,7 @@ const normalizeAccountMediaTimeline = (state, accountId, statuses, replace, next return state.updateIn(['accounts_media_timelines', accountId], Immutable.Map(), map => map .set('isLoading', false) - .set('next', next) + .update('next', null, v => replace ? next : v) .update('items', Immutable.List(), list => (replace ? ids : ids.concat(list)))); }; -- GitLab From c00ead8a72dd738013b8a132eff7de4959e59670 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Wed, 31 May 2017 08:07:25 -0700 Subject: [PATCH 067/295] Remove react-imageloader (#3423) * Remove react-imageloader * add eslint-disable-line * improve image loading experience * remove unneeded import * use PureComponent * Use componentWillMount instead of constructor --- .../features/ui/components/image_loader.js | 45 +++++++++++++++++++ .../features/ui/components/media_modal.js | 4 +- app/javascript/styles/components.scss | 15 ++++--- package.json | 1 - yarn.lock | 4 -- 5 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 app/javascript/mastodon/features/ui/components/image_loader.js diff --git a/app/javascript/mastodon/features/ui/components/image_loader.js b/app/javascript/mastodon/features/ui/components/image_loader.js new file mode 100644 index 0000000000..af2870517e --- /dev/null +++ b/app/javascript/mastodon/features/ui/components/image_loader.js @@ -0,0 +1,45 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +class ImageLoader extends React.PureComponent { + + static propTypes = { + src: PropTypes.string.isRequired, + } + + state = { + loading: true, + error: false, + } + + componentWillMount() { + this.loadImage(this.props.src); + } + + componentWillReceiveProps(props) { + this.loadImage(props.src); + } + + loadImage(src) { + const image = new Image(); + image.onerror = () => this.setState({loading: false, error: true}); + image.onload = () => this.setState({loading: false, error: false}); + image.src = src; + this.lastSrc = src; + this.setState({loading: true}); + } + + render() { + const { src } = this.props; + const { loading, error } = this.state; + + // TODO: handle image error state + + const imageClass = `image-loader__img ${loading ? 'image-loader__img-loading' : ''}`; + + return ; // eslint-disable-line jsx-a11y/img-has-alt + } + +} + +export default ImageLoader; diff --git a/app/javascript/mastodon/features/ui/components/media_modal.js b/app/javascript/mastodon/features/ui/components/media_modal.js index a8912841b5..effa0aea3b 100644 --- a/app/javascript/mastodon/features/ui/components/media_modal.js +++ b/app/javascript/mastodon/features/ui/components/media_modal.js @@ -3,10 +3,10 @@ import LoadingIndicator from '../../../components/loading_indicator'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import ExtendedVideoPlayer from '../../../components/extended_video_player'; -import ImageLoader from 'react-imageloader'; import { defineMessages, injectIntl } from 'react-intl'; import IconButton from '../../../components/icon_button'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import ImageLoader from './image_loader'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -73,7 +73,7 @@ class MediaModal extends ImmutablePureComponent { } if (attachment.get('type') === 'image') { - content = ; + content = ; } else if (attachment.get('type') === 'gifv') { content = ; } diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index 4afbd12cf1..e396f04cc1 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -1137,13 +1137,13 @@ } } -.transparent-background, -.imageloader { - background: url('../images/void.png'); +.image-loader__img { + transition: opacity 0.3s linear; + opacity: 1; } -.imageloader { - display: block; +.image-loader__img-loading { + opacity: 0.7; } .navigation-bar { @@ -2852,6 +2852,11 @@ button.icon-button.active i.fa-retweet { max-width: 80vw; max-height: 80vh; } + + img { + display: block; + background: url('../images/void.png') repeat; + } } .media-modal__close { diff --git a/package.json b/package.json index 92221d8e40..c686e99e7a 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,6 @@ "react-addons-perf": "^15.4.2", "react-addons-shallow-compare": "^15.5.2", "react-dom": "^15.5.4", - "react-imageloader": "^2.1.0", "react-immutable-proptypes": "^2.1.0", "react-immutable-pure-component": "^0.0.4", "react-intl": "^2.3.0", diff --git a/yarn.lock b/yarn.lock index d3317f59c6..5bef1e0b94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5436,10 +5436,6 @@ react-fuzzy@^0.3.3: classnames "^2.2.3" fuse.js "^2.2.0" -react-imageloader@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/react-imageloader/-/react-imageloader-2.1.0.tgz#a58401970b3282386aeb810c43175165634f6308" - react-immutable-proptypes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz#023d6f39bb15c97c071e9e60d00d136eac5fa0b4" -- GitLab From 41fa53253c09f70f4830e10b86d51d5dfb0b5fa9 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Thu, 1 Jun 2017 00:09:17 +0900 Subject: [PATCH 068/295] Keep ENV['LOCAL_HTTPS'] with ApplicationControllerSpec (fix random fail) (#3479) * Keep ENV['LOCAL_HTTPS'] with ApplicationControllerSpec (fix random fail) * use climate_control --- Gemfile | 1 + Gemfile.lock | 1 + .../controllers/application_controller_spec.rb | 18 ++++++++++-------- spec/features/log_in_spec.rb | 9 ++++++--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 1246658374..cb2a8649a8 100644 --- a/Gemfile +++ b/Gemfile @@ -70,6 +70,7 @@ end group :test do gem 'capybara', '~> 2.14' + gem 'climate_control', '~> 0.2' gem 'faker', '~> 1.7' gem 'microformats2', '~> 3.0' gem 'rails-controller-testing', '~> 1.0' diff --git a/Gemfile.lock b/Gemfile.lock index eeb7a4a8d4..23b99895fc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -487,6 +487,7 @@ DEPENDENCIES capistrano-yarn (~> 2.0) capybara (~> 2.14) cld3 (~> 3.1) + climate_control (~> 0.2) devise (~> 4.2) devise-two-factor (~> 3.0) doorkeeper (~> 4.2) diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 1b209feb50..83ec02401d 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -39,18 +39,20 @@ describe ApplicationController, type: :controller do it "does not force ssl if LOCAL_HTTPS is not 'true'" do routes.draw { get 'success' => 'anonymous#success' } - ENV['LOCAL_HTTPS'] = '' - allow(Rails.env).to receive(:production?).and_return(true) - get 'success' - expect(response).to have_http_status(:success) + ClimateControl.modify LOCAL_HTTPS: '' do + allow(Rails.env).to receive(:production?).and_return(true) + get 'success' + expect(response).to have_http_status(:success) + end end it "forces ssl if LOCAL_HTTPS is 'true'" do routes.draw { get 'success' => 'anonymous#success' } - ENV['LOCAL_HTTPS'] = 'true' - allow(Rails.env).to receive(:production?).and_return(true) - get 'success' - expect(response).to redirect_to('https://test.host/success') + ClimateControl.modify LOCAL_HTTPS: 'true' do + allow(Rails.env).to receive(:production?).and_return(true) + get 'success' + expect(response).to redirect_to('https://test.host/success') + end end describe 'helper_method :current_account' do diff --git a/spec/features/log_in_spec.rb b/spec/features/log_in_spec.rb index f9c222b60e..6dc3cd2f4e 100644 --- a/spec/features/log_in_spec.rb +++ b/spec/features/log_in_spec.rb @@ -1,11 +1,14 @@ require "rails_helper" feature "Log in" do - scenario "A valid email and password user is able to log in" do - email = "test@example.com" - password = "password" + given(:email) { "test@examle.com" } + given(:password) { "password" } + + background do Fabricate(:user, email: email, password: password) + end + scenario "A valid email and password user is able to log in" do visit new_user_session_path fill_in "user_email", with: email fill_in "user_password", with: password -- GitLab From 1a4860a57ad3b66e16aceef4fdf70c8ca11d1400 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Thu, 1 Jun 2017 00:09:28 +0900 Subject: [PATCH 069/295] Hold value of I18n.locale with ApplicationHelperSpec (#3474) --- spec/helpers/application_helper_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 7b875e21f4..ac54f1f703 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -18,6 +18,12 @@ describe ApplicationHelper do end describe 'add_rtl_body_class' do + around do |example| + current_locale = I18n.locale + example.run + I18n.locale = current_locale + end + it 'adds rtl body class if locale is Arabic' do I18n.locale = :ar expect(helper.add_rtl_body_class('other classes')).to eq 'other classes rtl' -- GitLab From bd669e390743f98eb8bc777a8a9d01980b7b44b4 Mon Sep 17 00:00:00 2001 From: caasi Huang Date: Thu, 1 Jun 2017 00:46:57 +0800 Subject: [PATCH 070/295] Update zh-TW.json (#3480) * Update zh-TW.json * Update `search_results.total` --- app/javascript/mastodon/locales/zh-TW.json | 342 ++++++++++----------- 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 6864123aec..59f7bafe1f 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -1,176 +1,176 @@ { - "account.block": "Block @{name}", - "account.block_domain": "Hide everything from {domain}", - "account.disclaimer": "This user is from another instance. This number may be larger.", - "account.edit_profile": "Edit profile", - "account.follow": "Follow", - "account.followers": "Followers", - "account.follows": "Follows", - "account.follows_you": "Follows you", - "account.media": "Media", - "account.mention": "Mention @{name}", - "account.mute": "Mute @{name}", - "account.posts": "Posts", - "account.report": "Report @{name}", - "account.requested": "Awaiting approval", - "account.unblock": "Unblock @{name}", - "account.unblock_domain": "Unhide {domain}", - "account.unfollow": "Unfollow", - "account.unmute": "Unmute @{name}", - "boost_modal.combo": "You can press {combo} to skip this next time", - "column.blocks": "Blocked users", - "column.community": "Local timeline", - "column.favourites": "Favourites", - "column.follow_requests": "Follow requests", - "column.home": "Home", - "column.mutes": "Muted users", - "column.notifications": "Notifications", - "column.public": "Federated timeline", - "column_back_button.label": "Back", - "column_subheading.navigation": "Navigation", - "column_subheading.settings": "Settings", - "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", - "compose_form.lock_disclaimer.lock": "locked", - "compose_form.placeholder": "What is on your mind?", - "compose_form.privacy_disclaimer": "Your post will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is not a public post, and it may be boosted or otherwise made visible to unintended recipients.", - "compose_form.publish": "Toot", - "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive": "Mark media as sensitive", - "compose_form.spoiler": "Hide text behind warning", - "compose_form.spoiler_placeholder": "Content warning", - "confirmation_modal.cancel": "Cancel", - "confirmations.block.confirm": "Block", - "confirmations.block.message": "Are you sure you want to block {name}?", - "confirmations.delete.confirm": "Delete", - "confirmations.delete.message": "Are you sure you want to delete this status?", - "confirmations.domain_block.confirm": "Hide entire domain", - "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", - "confirmations.mute.confirm": "Mute", - "confirmations.mute.message": "Are you sure you want to mute {name}?", - "emoji_button.activity": "Activity", - "emoji_button.flags": "Flags", - "emoji_button.food": "Food & Drink", - "emoji_button.label": "Insert emoji", - "emoji_button.nature": "Nature", - "emoji_button.objects": "Objects", - "emoji_button.people": "People", - "emoji_button.search": "Search...", - "emoji_button.symbols": "Symbols", - "emoji_button.travel": "Travel & Places", - "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", - "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", - "empty_column.home.public_timeline": "the public timeline", - "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", - "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", - "follow_request.authorize": "Authorize", - "follow_request.reject": "Reject", + "account.block": "封鎖 @{name}", + "account.block_domain": "隱藏來自 {domain} 的一切", + "account.disclaimer": "這使用者來自其他副本,實際數字可能更大。", + "account.edit_profile": "編輯用戶資訊", + "account.follow": "關注", + "account.followers": "專注者", + "account.follows": "正在關注", + "account.follows_you": "關注你", + "account.media": "媒體", + "account.mention": "提到 @{name}", + "account.mute": "消音 @{name}", + "account.posts": "貼文", + "account.report": "檢舉 @{name}", + "account.requested": "正在等待許可", + "account.unblock": "取消封鎖 @{name}", + "account.unblock_domain": "不再隱藏 {domain}", + "account.unfollow": "取消關注", + "account.unmute": "不再消音 @{name}", + "boost_modal.combo": "下次你可以按 {combo} 來跳過", + "column.blocks": "封鎖的使用者", + "column.community": "本地時間軸", + "column.favourites": "最愛", + "column.follow_requests": "關注請求", + "column.home": "家", + "column.mutes": "消音的使用者", + "column.notifications": "通知", + "column.public": "聯盟時間軸", + "column_back_button.label": "上一頁", + "column_subheading.navigation": "瀏覽", + "column_subheading.settings": "設定", + "compose_form.lock_disclaimer": "你的帳號沒有{locked}。任何人都可以關注你,看到發給關注者的貼文。", + "compose_form.lock_disclaimer.lock": "上鎖", + "compose_form.placeholder": "在想些什麼?", + "compose_form.privacy_disclaimer": "你的貼文會被傳到 {domains} 上被提到的使用者。你信任 {domainsCount, plural, one {這個伺服器} other {這些伺服器}}嗎?貼文的隱私設定只會在 Mastodon 副本上生效。如果 {domains} {domainsCount, plural, one {不是一個 Mastodon 副本} other {都不是 Mastodon 副本}},就不會被標記為非公開貼文,而且可能會被轉推或是讓不預期的人看見。", + "compose_form.publish": "推", + "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive": "將此媒體標為敏感", + "compose_form.spoiler": "將訊息隱藏在警告訊息之後", + "compose_form.spoiler_placeholder": "內容警告", + "confirmation_modal.cancel": "取消", + "confirmations.block.confirm": "封鎖", + "confirmations.block.message": "你確定要封鎖 {name} ?", + "confirmations.delete.confirm": "刪除", + "confirmations.delete.message": "你確定要刪除這個狀態?", + "confirmations.domain_block.confirm": "隱藏整個網域", + "confirmations.domain_block.message": "你真的真的確定要封鎖整個 {domain} ?多數情況下,比較推薦封鎖或消音幾個特定目標就好。", + "confirmations.mute.confirm": "消音", + "confirmations.mute.message": "你確定要消音 {name} ?", + "emoji_button.activity": "活動", + "emoji_button.flags": "旗幟", + "emoji_button.food": "食物與飲料", + "emoji_button.label": "插入表情符號", + "emoji_button.nature": "自然", + "emoji_button.objects": "物件", + "emoji_button.people": "人", + "emoji_button.search": "搜尋...", + "emoji_button.symbols": "符號", + "emoji_button.travel": "旅遊與地點", + "empty_column.community": "本地時間軸是空的。公開寫點什麼吧!", + "empty_column.hashtag": "這個主題標籤下什麼都沒有。", + "empty_column.home": "你還沒關注任何人。造訪{public}或利用搜尋功能找到其他用戶。", + "empty_column.home.inactivity": "你家的訊息摘要是空的。如果你很久沒活動了,很快它就會重新產生。", + "empty_column.home.public_timeline": "公開時間軸", + "empty_column.notifications": "還沒有任何通知。和別的使用者互動來開始對話。", + "empty_column.public": "這裡什麼都沒有!公開寫些什麼,或是關注其他副本的使用者。", + "follow_request.authorize": "授權", + "follow_request.reject": "拒絕", "getting_started.appsshort": "Apps", "getting_started.faq": "FAQ", - "getting_started.heading": "Getting started", - "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", + "getting_started.heading": "馬上開始", + "getting_started.open_source_notice": "Mastodon 是開源軟體。你可以在 GitHub {github} 上做出貢獻或是回報問題。", "getting_started.support": "{faq} • {userguide} • {apps}", - "getting_started.userguide": "User Guide", - "home.column_settings.advanced": "Advanced", - "home.column_settings.basic": "Basic", - "home.column_settings.filter_regex": "Filter out by regular expressions", - "home.column_settings.show_reblogs": "Show boosts", - "home.column_settings.show_replies": "Show replies", - "home.settings": "Column settings", - "lightbox.close": "Close", - "loading_indicator.label": "Loading...", - "media_gallery.toggle_visible": "Toggle visibility", - "missing_indicator.label": "Not found", - "navigation_bar.blocks": "Blocked users", - "navigation_bar.community_timeline": "Local timeline", - "navigation_bar.edit_profile": "Edit profile", - "navigation_bar.favourites": "Favourites", - "navigation_bar.follow_requests": "Follow requests", - "navigation_bar.info": "Extended information", - "navigation_bar.logout": "Logout", - "navigation_bar.mutes": "Muted users", - "navigation_bar.preferences": "Preferences", - "navigation_bar.public_timeline": "Federated timeline", - "notification.favourite": "{name} favourited your status", - "notification.follow": "{name} followed you", - "notification.mention": "{name} mentioned you", - "notification.reblog": "{name} boosted your status", - "notifications.clear": "Clear notifications", - "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", - "notifications.column_settings.alert": "Desktop notifications", - "notifications.column_settings.favourite": "Favourites:", - "notifications.column_settings.follow": "New followers:", - "notifications.column_settings.mention": "Mentions:", - "notifications.column_settings.reblog": "Boosts:", - "notifications.column_settings.show": "Show in column", - "notifications.column_settings.sound": "Play sound", - "notifications.settings": "Column settings", - "onboarding.done": "Done", - "onboarding.next": "Next", - "onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.", - "onboarding.page_four.home": "The home timeline shows posts from people you follow.", - "onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.", - "onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.", - "onboarding.page_one.handle": "You are on {domain}, so your full handle is {handle}", - "onboarding.page_one.welcome": "Welcome to Mastodon!", - "onboarding.page_six.admin": "Your instance's admin is {admin}.", - "onboarding.page_six.almost_done": "Almost done...", - "onboarding.page_six.appetoot": "Bon Appetoot!", - "onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.", - "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.", - "onboarding.page_six.guidelines": "community guidelines", - "onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!", - "onboarding.page_six.various_app": "mobile apps", - "onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.", - "onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.", - "onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.", - "onboarding.skip": "Skip", - "privacy.change": "Adjust status privacy", - "privacy.direct.long": "Post to mentioned users only", - "privacy.direct.short": "Direct", - "privacy.private.long": "Post to followers only", - "privacy.private.short": "Followers-only", - "privacy.public.long": "Post to public timelines", - "privacy.public.short": "Public", - "privacy.unlisted.long": "Do not post to public timelines", - "privacy.unlisted.short": "Unlisted", - "reply_indicator.cancel": "Cancel", - "report.heading": "New report", - "report.placeholder": "Additional comments", - "report.submit": "Submit", - "report.target": "Reporting", - "search.placeholder": "Search", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", - "status.cannot_reblog": "This post cannot be boosted", - "status.delete": "Delete", - "status.favourite": "Favourite", - "status.load_more": "Load more", - "status.media_hidden": "Media hidden", - "status.mention": "Mention @{name}", - "status.mute_conversation": "Mute conversation", - "status.open": "Expand this status", - "status.reblog": "Boost", - "status.reblogged_by": "{name} boosted", - "status.reply": "Reply", - "status.replyAll": "Reply to thread", - "status.report": "Report @{name}", - "status.sensitive_toggle": "Click to view", - "status.sensitive_warning": "Sensitive content", - "status.show_less": "Show less", - "status.show_more": "Show more", - "status.unmute_conversation": "Unmute conversation", - "tabs_bar.compose": "Compose", - "tabs_bar.federated_timeline": "Federated", - "tabs_bar.home": "Home", - "tabs_bar.local_timeline": "Local", - "tabs_bar.notifications": "Notifications", - "upload_area.title": "Drag & drop to upload", - "upload_button.label": "Add media", - "upload_form.undo": "Undo", - "upload_progress.label": "Uploading...", - "video_player.expand": "Expand video", - "video_player.toggle_sound": "Toggle sound", - "video_player.toggle_visible": "Toggle visibility", - "video_player.video_error": "Video could not be played" + "getting_started.userguide": "使用者指南", + "home.column_settings.advanced": "進階", + "home.column_settings.basic": "基本", + "home.column_settings.filter_regex": "以正規表示式過濾", + "home.column_settings.show_reblogs": "顯示轉推", + "home.column_settings.show_replies": "顯示回應", + "home.settings": "欄位設定", + "lightbox.close": "關閉", + "loading_indicator.label": "讀取中...", + "media_gallery.toggle_visible": "切換可見性", + "missing_indicator.label": "找不到", + "navigation_bar.blocks": "封鎖的使用者", + "navigation_bar.community_timeline": "本地時間軸", + "navigation_bar.edit_profile": "編輯用戶資訊", + "navigation_bar.favourites": "最愛", + "navigation_bar.follow_requests": "關注請求", + "navigation_bar.info": "延伸資訊", + "navigation_bar.logout": "登出", + "navigation_bar.mutes": "消音的使用者", + "navigation_bar.preferences": "偏好設定", + "navigation_bar.public_timeline": "聯盟時間軸", + "notification.favourite": "{name}喜歡你的狀態", + "notification.follow": "{name}關注了你", + "notification.mention": "{name}提到了你", + "notification.reblog": "{name}推了你的狀態", + "notifications.clear": "清除通知", + "notifications.clear_confirmation": "確定要永久清除你的通知嗎?", + "notifications.column_settings.alert": "桌面通知", + "notifications.column_settings.favourite": "最愛:", + "notifications.column_settings.follow": "新的關注者:", + "notifications.column_settings.mention": "提到:", + "notifications.column_settings.reblog": "轉推:", + "notifications.column_settings.show": "顯示在欄位中", + "notifications.column_settings.sound": "播放音效", + "notifications.settings": "欄位設定", + "onboarding.done": "完成", + "onboarding.next": "下一步", + "onboarding.page_five.public_timelines": "本地時間軸顯示 {domain} 上所有人的公開貼文。聯盟時間軸顯示 {domain} 上所有人關注的公開貼文。這就是公開時間軸,發現新朋友的好地方。", + "onboarding.page_four.home": "家時間軸顯示所有你關注的人的貼文。", + "onboarding.page_four.notifications": "通知欄顯示別人和你的互動。", + "onboarding.page_one.federation": "Mastodon 是由獨立的伺服器連結起來,形成的大社群網路。我們把這些伺服器稱為副本。", + "onboarding.page_one.handle": "你在 {domain} 上,所以你的帳號全名是 {handle}", + "onboarding.page_one.welcome": "歡迎來到 Mastodon !", + "onboarding.page_six.admin": "你的副本的管理員是 {admin} 。", + "onboarding.page_six.almost_done": "快好了...", + "onboarding.page_six.appetoot": "推口大開!", + "onboarding.page_six.apps_available": "在 iOS 、 Android 和其他平台上有這些 {apps} 可以用。", + "onboarding.page_six.github": "Mastodon 是自由的開源軟體。你可以在 {github} 上回報臭蟲、請求新功能或是做出貢獻。", + "onboarding.page_six.guidelines": "社群指南", + "onboarding.page_six.read_guidelines": "請閱讀 {domain} 的 {guidelines} !", + "onboarding.page_six.various_app": "行動 apps", + "onboarding.page_three.profile": "編輯你的大頭貼、自傳和顯示名稱。你也可以在這邊找到其他設定。", + "onboarding.page_three.search": "利用搜尋列來找到其他人或是主題標籤,像是 {illustration} 或 {introductions} 。用完整的帳號名稱來找不在這個副本上的使用者。", + "onboarding.page_two.compose": "在編輯欄寫些什麼。可以上傳圖片、改變隱私設定或是用下面的圖示加上內容警告。", + "onboarding.skip": "跳過", + "privacy.change": "調整隱私狀態", + "privacy.direct.long": "只貼給提到的使用者", + "privacy.direct.short": "直接貼", + "privacy.private.long": "只貼給關注者", + "privacy.private.short": "關注貼", + "privacy.public.long": "貼到公開時間軸", + "privacy.public.short": "公開貼", + "privacy.unlisted.long": "不要貼到公開時間軸", + "privacy.unlisted.short": "不列出來", + "reply_indicator.cancel": "取消", + "report.heading": "新的通報", + "report.placeholder": "更多訊息", + "report.submit": "送出", + "report.target": "通報中", + "search.placeholder": "搜尋", + "search_results.total": "{count, number} 項結果", + "status.cannot_reblog": "此貼文無法轉推", + "status.delete": "刪除", + "status.favourite": "喜愛", + "status.load_more": "載入更多", + "status.media_hidden": "媒體已隱藏", + "status.mention": "提到 @{name}", + "status.mute_conversation": "消音對話", + "status.open": "展開這個狀態", + "status.reblog": "轉推", + "status.reblogged_by": "{name} 轉推了", + "status.reply": "回應", + "status.replyAll": "回應這串", + "status.report": "通報 @{name}", + "status.sensitive_toggle": "點來看", + "status.sensitive_warning": "敏感內容", + "status.show_less": "看少點", + "status.show_more": "看更多", + "status.unmute_conversation": "不消音對話", + "tabs_bar.compose": "編輯", + "tabs_bar.federated_timeline": "聯盟", + "tabs_bar.home": "家", + "tabs_bar.local_timeline": "本地", + "tabs_bar.notifications": "通知", + "upload_area.title": "拖放來上傳", + "upload_button.label": "增加媒體", + "upload_form.undo": "復原", + "upload_progress.label": "上傳中...", + "video_player.expand": "展開影片", + "video_player.toggle_sound": "切換音效", + "video_player.toggle_visible": "切換可見性", + "video_player.video_error": "無法播放這影片" } -- GitLab From d6774d2ca39b66ba6a80e707dbd58a6b391ee274 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:27:17 -0400 Subject: [PATCH 071/295] Refactor and spec coverage for api/v1/timelines actions (#3482) --- .../api/v1/timelines/base_controller.rb | 30 ------- .../api/v1/timelines/home_controller.rb | 80 ++++++++++------- .../api/v1/timelines/public_controller.rb | 77 ++++++++++------ .../api/v1/timelines/tag_controller.rb | 90 +++++++++++-------- .../api/v1/timelines/{base => }/show.rabl | 0 spec/routing/api_routing_spec.rb | 20 +++++ spec/routing/api_timelines_spec.rb | 18 ---- 7 files changed, 171 insertions(+), 144 deletions(-) delete mode 100644 app/controllers/api/v1/timelines/base_controller.rb rename app/views/api/v1/timelines/{base => }/show.rabl (100%) create mode 100644 spec/routing/api_routing_spec.rb delete mode 100644 spec/routing/api_timelines_spec.rb diff --git a/app/controllers/api/v1/timelines/base_controller.rb b/app/controllers/api/v1/timelines/base_controller.rb deleted file mode 100644 index 4eb29e74a2..0000000000 --- a/app/controllers/api/v1/timelines/base_controller.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Api::V1::Timelines - class BaseController < ApiController - respond_to :json - after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - - private - - def cache_collection(raw) - super(raw, Status) - end - - def pagination_params(core_params) - params.permit(:local, :limit).merge(core_params) - end - - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def next_path - raise 'Override in child controllers' - end - - def prev_path - raise 'Override in child controllers' - end - end -end diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index 33ff48b398..29e570fa5e 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -1,44 +1,62 @@ # frozen_string_literal: true -module Api::V1::Timelines - class HomeController < BaseController - before_action -> { doorkeeper_authorize! :read }, only: [:show] - before_action :require_user!, only: [:show] +class Api::V1::Timelines::HomeController < ApiController + before_action -> { doorkeeper_authorize! :read }, only: [:show] + before_action :require_user!, only: [:show] + after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - def show - @statuses = load_statuses - end + respond_to :json - private + def show + @statuses = load_statuses + render 'api/v1/timelines/show' + end - def load_statuses - cached_home_statuses.tap do |statuses| - set_maps(statuses) - end - end + private - def cached_home_statuses - cache_collection home_statuses + def load_statuses + cached_home_statuses.tap do |statuses| + set_maps(statuses) end + end - def home_statuses - account_home_feed.get( - limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] - ) - end + def cached_home_statuses + cache_collection home_statuses, Status + end - def account_home_feed - Feed.new(:home, current_account) - end + def home_statuses + account_home_feed.get( + limit_param(DEFAULT_STATUSES_LIMIT), + params[:max_id], + params[:since_id] + ) + end - def next_path - api_v1_timelines_home_url pagination_params(max_id: @statuses.last.id) - end + def account_home_feed + Feed.new(:home, current_account) + end - def prev_path - api_v1_timelines_home_url pagination_params(since_id: @statuses.first.id) - end + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_params(core_params) + params.permit(:local, :limit).merge(core_params) + end + + def next_path + api_v1_timelines_home_url pagination_params(max_id: pagination_max_id) + end + + def prev_path + api_v1_timelines_home_url pagination_params(since_id: pagination_since_id) + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id end end diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index 644c7a6f17..cd3663d5f4 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -1,41 +1,60 @@ # frozen_string_literal: true -module Api::V1::Timelines - class PublicController < BaseController - def show - @statuses = load_statuses - end +class Api::V1::Timelines::PublicController < ApiController + after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - private + respond_to :json - def load_statuses - cached_public_statuses.tap do |statuses| - set_maps(statuses) - end - end + def show + @statuses = load_statuses + render 'api/v1/timelines/show' + end - def cached_public_statuses - cache_collection public_statuses - end + private - def public_statuses - public_timeline_statuses.paginate_by_max_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] - ) + def load_statuses + cached_public_statuses.tap do |statuses| + set_maps(statuses) end + end - def public_timeline_statuses - Status.as_public_timeline(current_account, params[:local]) - end + def cached_public_statuses + cache_collection public_statuses, Status + end - def next_path - api_v1_timelines_public_url pagination_params(max_id: @statuses.last.id) - end + def public_statuses + public_timeline_statuses.paginate_by_max_id( + limit_param(DEFAULT_STATUSES_LIMIT), + params[:max_id], + params[:since_id] + ) + end - def prev_path - api_v1_timelines_public_url pagination_params(since_id: @statuses.first.id) - end + def public_timeline_statuses + Status.as_public_timeline(current_account, params[:local]) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_params(core_params) + params.permit(:local, :limit).merge(core_params) + end + + def next_path + api_v1_timelines_public_url pagination_params(max_id: pagination_max_id) + end + + def prev_path + api_v1_timelines_public_url pagination_params(since_id: pagination_since_id) + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id end end diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb index 818f49d3de..0481f5debe 100644 --- a/app/controllers/api/v1/timelines/tag_controller.rb +++ b/app/controllers/api/v1/timelines/tag_controller.rb @@ -1,51 +1,69 @@ # frozen_string_literal: true -module Api::V1::Timelines - class TagController < BaseController - before_action :load_tag +class Api::V1::Timelines::TagController < ApiController + before_action :load_tag + after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - def show - @statuses = load_statuses - end + respond_to :json - private + def show + @statuses = load_statuses + render 'api/v1/timelines/show' + end - def load_tag - @tag = Tag.find_by(name: params[:id].downcase) - end + private - def load_statuses - cached_tagged_statuses.tap do |statuses| - set_maps(statuses) - end - end + def load_tag + @tag = Tag.find_by(name: params[:id].downcase) + end - def cached_tagged_statuses - cache_collection tagged_statuses + def load_statuses + cached_tagged_statuses.tap do |statuses| + set_maps(statuses) end + end - def tagged_statuses - if @tag.nil? - [] - else - tag_timeline_statuses.paginate_by_max_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] - ) - end - end + def cached_tagged_statuses + cache_collection tagged_statuses, Status + end - def tag_timeline_statuses - Status.as_tag_timeline(@tag, current_account, params[:local]) + def tagged_statuses + if @tag.nil? + [] + else + tag_timeline_statuses.paginate_by_max_id( + limit_param(DEFAULT_STATUSES_LIMIT), + params[:max_id], + params[:since_id] + ) end + end - def next_path - api_v1_timelines_tag_url params[:id], pagination_params(max_id: @statuses.last.id) - end + def tag_timeline_statuses + Status.as_tag_timeline(@tag, current_account, params[:local]) + end - def prev_path - api_v1_timelines_tag_url params[:id], pagination_params(since_id: @statuses.first.id) - end + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_params(core_params) + params.permit(:local, :limit).merge(core_params) + end + + def next_path + api_v1_timelines_tag_url params[:id], pagination_params(max_id: pagination_max_id) + end + + def prev_path + api_v1_timelines_tag_url params[:id], pagination_params(since_id: pagination_since_id) + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id end end diff --git a/app/views/api/v1/timelines/base/show.rabl b/app/views/api/v1/timelines/show.rabl similarity index 100% rename from app/views/api/v1/timelines/base/show.rabl rename to app/views/api/v1/timelines/show.rabl diff --git a/spec/routing/api_routing_spec.rb b/spec/routing/api_routing_spec.rb new file mode 100644 index 0000000000..973b4801d9 --- /dev/null +++ b/spec/routing/api_routing_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +describe 'API routes' do + describe 'Timeline routes' do + it 'routes to home timeline' do + expect(get('/api/v1/timelines/home')). + to route_to('api/v1/timelines/home#show') + end + + it 'routes to public timeline' do + expect(get('/api/v1/timelines/public')). + to route_to('api/v1/timelines/public#show') + end + + it 'routes to tag timeline' do + expect(get('/api/v1/timelines/tag/test')). + to route_to('api/v1/timelines/tag#show', id: 'test') + end + end +end diff --git a/spec/routing/api_timelines_spec.rb b/spec/routing/api_timelines_spec.rb deleted file mode 100644 index 31717209f0..0000000000 --- a/spec/routing/api_timelines_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'rails_helper' - -describe 'API timeline routes' do - it 'routes to home timeline' do - expect(get('/api/v1/timelines/home')). - to route_to('api/v1/timelines/home#show') - end - - it 'routes to public timeline' do - expect(get('/api/v1/timelines/public')). - to route_to('api/v1/timelines/public#show') - end - - it 'routes to tag timeline' do - expect(get('/api/v1/timelines/tag/test')). - to route_to('api/v1/timelines/tag#show', id: 'test') - end -end -- GitLab From bf811e4d4a8626579fc5187f465cdf1e79a32e10 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:27:34 -0400 Subject: [PATCH 072/295] Improve spec coverage and clean up api/v1/mutes controller (#3481) --- app/controllers/api/v1/mutes_controller.rb | 52 ++++++++++++++++--- .../api/v1/mutes_controller_spec.rb | 4 +- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb index 53eb2554b6..b9ac741765 100644 --- a/app/controllers/api/v1/mutes_controller.rb +++ b/app/controllers/api/v1/mutes_controller.rb @@ -3,23 +3,59 @@ class Api::V1::MutesController < ApiController before_action -> { doorkeeper_authorize! :follow } before_action :require_user! + after_action :insert_pagination_headers respond_to :json def index - @accounts = Account.includes(:muted_by) - .references(:muted_by) - .merge(Mute.where(account: current_account) - .paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])) - .to_a + @accounts = load_accounts + end - next_path = api_v1_mutes_url(pagination_params(max_id: @accounts.last.muted_by_ids.last)) if @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) - prev_path = api_v1_mutes_url(pagination_params(since_id: @accounts.first.muted_by_ids.first)) unless @accounts.empty? + private + def load_accounts + default_accounts.merge(paginated_mutes).to_a + end + + def default_accounts + Account.includes(:muted_by).references(:muted_by) + end + + def paginated_mutes + Mute.where(account: current_account).paginate_by_max_id( + limit_param(DEFAULT_ACCOUNTS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def insert_pagination_headers set_pagination_headers(next_path, prev_path) end - private + def next_path + if records_continue? + api_v1_mutes_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @accounts.empty? + api_v1_mutes_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @accounts.last.muted_by_ids.last + end + + def pagination_since_id + @accounts.first.muted_by_ids.first + end + + def records_continue? + @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end def pagination_params(core_params) params.permit(:limit).merge(core_params) diff --git a/spec/controllers/api/v1/mutes_controller_spec.rb b/spec/controllers/api/v1/mutes_controller_spec.rb index be8a5e7dd2..85aad43841 100644 --- a/spec/controllers/api/v1/mutes_controller_spec.rb +++ b/spec/controllers/api/v1/mutes_controller_spec.rb @@ -7,12 +7,14 @@ RSpec.describe Api::V1::MutesController, type: :controller do let(:token) { double acceptable?: true, resource_owner_id: user.id } before do + Fabricate(:mute, account: user.account) allow(controller).to receive(:doorkeeper_token) { token } end describe 'GET #index' do it 'returns http success' do - get :index + get :index, params: { limit: 1 } + expect(response).to have_http_status(:success) end end -- GitLab From 2cc3111a7775066c34eb407cd3b4707acc659488 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:28:45 -0400 Subject: [PATCH 073/295] Expand spec coverage and refactor the `Account.find_` methods (#3485) * Move specs for account finder methods to concern spec * Move account finder methods to concern * Improve spec wording * Use more explicit comparison to ensure correct return value * Add coverage for .find_local! and .find_remote! * Add some methods to the finder * Use arel on matching_username method * Avoid ternary in matching domain method * Simplify finder methods * Use an AccountFinder class to simplify lookup --- app/models/account.rb | 22 +---- app/models/concerns/account_finder_concern.rb | 58 ++++++++++++ spec/models/account_spec.rb | 48 ---------- .../concerns/account_finder_concern_spec.rb | 93 +++++++++++++++++++ 4 files changed, 152 insertions(+), 69 deletions(-) create mode 100644 app/models/concerns/account_finder_concern.rb create mode 100644 spec/models/concerns/account_finder_concern_spec.rb diff --git a/app/models/account.rb b/app/models/account.rb index cb116dbaf6..4561fd0a48 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -42,6 +42,7 @@ class Account < ApplicationRecord MENTION_RE = /(?:^|[^\/[:word:]])@([a-z0-9_]+(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i include AccountAvatar + include AccountFinderConcern include AccountHeader include AccountInteractions include Attachmentable @@ -162,27 +163,6 @@ class Account < ApplicationRecord end class << self - def find_local!(username) - find_remote!(username, nil) - end - - def find_remote!(username, domain) - raise ActiveRecord::RecordNotFound if username.blank? - where('lower(accounts.username) = ?', username.downcase).where(domain.nil? ? { domain: nil } : 'lower(accounts.domain) = ?', domain&.downcase).take! - end - - def find_local(username) - find_local!(username) - rescue ActiveRecord::RecordNotFound - nil - end - - def find_remote(username, domain) - find_remote!(username, domain) - rescue ActiveRecord::RecordNotFound - nil - end - def triadic_closures(account, limit: 5, offset: 0) sql = <<-SQL.squish WITH first_degree AS ( diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account_finder_concern.rb new file mode 100644 index 0000000000..d3ad519b12 --- /dev/null +++ b/app/models/concerns/account_finder_concern.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module AccountFinderConcern + extend ActiveSupport::Concern + + class_methods do + def find_local!(username) + find_local(username) || raise(ActiveRecord::RecordNotFound) + end + + def find_remote!(username, domain) + find_remote(username, domain) || raise(ActiveRecord::RecordNotFound) + end + + def find_local(username) + find_remote(username, nil) + end + + def find_remote(username, domain) + AccountFinder.new(username, domain).account + end + end + + class AccountFinder + attr_reader :username, :domain + + def initialize(username, domain) + @username = username + @domain = domain + end + + def account + scoped_accounts.take + end + + private + + def scoped_accounts + Account.unscoped.tap do |scope| + scope.merge! matching_username + scope.merge! matching_domain + end + end + + def matching_username + raise(ActiveRecord::RecordNotFound) if username.blank? + Account.where(Account.arel_table[:username].lower.eq username.downcase) + end + + def matching_domain + if domain.nil? + Account.where(domain: nil) + else + Account.where(Account.arel_table[:domain].lower.eq domain.downcase) + end + end + end +end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 08098854b1..ebec463e12 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -301,54 +301,6 @@ RSpec.describe Account, type: :model do end end - describe '.find_local' do - before do - Fabricate(:account, username: 'Alice') - end - - it 'returns Alice for alice' do - expect(Account.find_local('alice')).to_not be_nil - end - - it 'returns Alice for Alice' do - expect(Account.find_local('Alice')).to_not be_nil - end - - it 'does not return anything for a_ice' do - expect(Account.find_local('a_ice')).to be_nil - end - - it 'does not return anything for al%' do - expect(Account.find_local('al%')).to be_nil - end - end - - describe '.find_remote' do - before do - Fabricate(:account, username: 'Alice', domain: 'mastodon.social') - end - - it 'returns Alice for alice@mastodon.social' do - expect(Account.find_remote('alice', 'mastodon.social')).to_not be_nil - end - - it 'returns Alice for ALICE@MASTODON.SOCIAL' do - expect(Account.find_remote('ALICE', 'MASTODON.SOCIAL')).to_not be_nil - end - - it 'does not return anything for a_ice@mastodon.social' do - expect(Account.find_remote('a_ice', 'mastodon.social')).to be_nil - end - - it 'does not return anything for alice@m_stodon.social' do - expect(Account.find_remote('alice', 'm_stodon.social')).to be_nil - end - - it 'does not return anything for alice@m%' do - expect(Account.find_remote('alice', 'm%')).to be_nil - end - end - describe '.following_map' do it 'returns an hash' do expect(Account.following_map([], 1)).to be_a Hash diff --git a/spec/models/concerns/account_finder_concern_spec.rb b/spec/models/concerns/account_finder_concern_spec.rb new file mode 100644 index 0000000000..05f0f44f27 --- /dev/null +++ b/spec/models/concerns/account_finder_concern_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe AccountFinderConcern do + describe 'local finders' do + before do + @account = Fabricate(:account, username: 'Alice') + end + + describe '.find_local' do + it 'returns case-insensitive result' do + expect(Account.find_local('alice')).to eq(@account) + end + + it 'returns correctly cased result' do + expect(Account.find_local('Alice')).to eq(@account) + end + + it 'returns nil without a match' do + expect(Account.find_local('a_ice')).to be_nil + end + + it 'returns nil for regex style username value' do + expect(Account.find_local('al%')).to be_nil + end + end + + describe '.find_local!' do + it 'returns matching result' do + expect(Account.find_local!('alice')).to eq(@account) + end + + it 'raises on non-matching result' do + expect { Account.find_local!('missing') }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises with blank username' do + expect { Account.find_local!('') }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises with nil username' do + expect { Account.find_local!(nil) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + describe 'remote finders' do + before do + @account = Fabricate(:account, username: 'Alice', domain: 'mastodon.social') + end + + describe '.find_remote' do + it 'returns exact match result' do + expect(Account.find_remote('alice', 'mastodon.social')).to eq(@account) + end + + it 'returns case-insensitive result' do + expect(Account.find_remote('ALICE', 'MASTODON.SOCIAL')).to eq(@account) + end + + it 'returns nil when username does not match' do + expect(Account.find_remote('a_ice', 'mastodon.social')).to be_nil + end + + it 'returns nil when domain does not match' do + expect(Account.find_remote('alice', 'm_stodon.social')).to be_nil + end + + it 'returns nil for regex style domain value' do + expect(Account.find_remote('alice', 'm%')).to be_nil + end + end + + describe '.find_remote!' do + it 'returns matching result' do + expect(Account.find_remote!('alice', 'mastodon.social')).to eq(@account) + end + + it 'raises on non-matching result' do + expect { Account.find_remote!('missing', 'mastodon.host') }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises with blank username' do + expect { Account.find_remote!('', '') }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises with nil username' do + expect { Account.find_remote!(nil, nil) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end +end -- GitLab From 75cad1d9d6778419a163d2f256d87dbafa9febd4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:30:39 -0400 Subject: [PATCH 074/295] Improve spec coverage and clean up api/v1/favourites controller (#3472) --- .../api/v1/favourites_controller.rb | 60 +++++++++++++++++-- .../api/v1/favourites_controller_spec.rb | 4 +- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index 22b93fe79a..4614a0c724 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -3,22 +3,70 @@ class Api::V1::FavouritesController < ApiController before_action -> { doorkeeper_authorize! :read } before_action :require_user! + after_action :insert_pagination_headers respond_to :json def index - results = Favourite.where(account: current_account).paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id]) - @statuses = cache_collection(Status.where(id: results.map(&:status_id)), Status) + @statuses = load_statuses + end + + private + + def load_statuses + cached_favourites.tap do |statuses| + set_maps(statuses) + end + end - set_maps(@statuses) + def cached_favourites + cache_collection( + Status.where( + id: results.map(&:status_id) + ), + Status + ) + end - next_path = api_v1_favourites_url(pagination_params(max_id: results.last.id)) if results.size == limit_param(DEFAULT_STATUSES_LIMIT) - prev_path = api_v1_favourites_url(pagination_params(since_id: results.first.id)) unless results.empty? + def results + @_results ||= account_favourites.paginate_by_max_id( + limit_param(DEFAULT_STATUSES_LIMIT), + params[:max_id], + params[:since_id] + ) + end + def account_favourites + current_account.favourites + end + + def insert_pagination_headers set_pagination_headers(next_path, prev_path) end - private + def next_path + if records_continue? + api_v1_favourites_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless results.empty? + api_v1_favourites_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + results.last.id + end + + def pagination_since_id + results.first.id + end + + def records_continue? + results.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end def pagination_params(core_params) params.permit(:limit).merge(core_params) diff --git a/spec/controllers/api/v1/favourites_controller_spec.rb b/spec/controllers/api/v1/favourites_controller_spec.rb index a6e9963e52..062e91adcc 100644 --- a/spec/controllers/api/v1/favourites_controller_spec.rb +++ b/spec/controllers/api/v1/favourites_controller_spec.rb @@ -7,12 +7,14 @@ RSpec.describe Api::V1::FavouritesController, type: :controller do let(:token) { double acceptable?: true, resource_owner_id: user.id } before do + Fabricate(:favourite, account: user.account) allow(controller).to receive(:doorkeeper_token) { token } end describe 'GET #index' do it 'returns http success' do - get :index + get :index, params: { limit: 1 } + expect(response).to have_http_status(:success) end end -- GitLab From 9c7505489f9348feade8f8a7b0836cb8f3e92df5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:30:55 -0400 Subject: [PATCH 075/295] Refactor api/v1/notifications controller (#3470) --- .../api/v1/notifications_controller.rb | 67 +++++++++++++++---- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index e79434f1da..1cd4ca40a4 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -3,40 +3,81 @@ class Api::V1::NotificationsController < ApiController before_action -> { doorkeeper_authorize! :read } before_action :require_user! + after_action :insert_pagination_headers, only: :index respond_to :json DEFAULT_NOTIFICATIONS_LIMIT = 15 def index - @notifications = Notification.where(account: current_account).browserable(exclude_types).paginate_by_max_id(limit_param(DEFAULT_NOTIFICATIONS_LIMIT), params[:max_id], params[:since_id]) - @notifications = cache_collection(@notifications, Notification) - statuses = @notifications.select { |n| !n.target_status.nil? }.map(&:target_status) - - set_maps(statuses) - - next_path = api_v1_notifications_url(pagination_params(max_id: @notifications.last.id)) unless @notifications.empty? - prev_path = api_v1_notifications_url(pagination_params(since_id: @notifications.first.id)) unless @notifications.empty? - - set_pagination_headers(next_path, prev_path) + @notifications = load_notifications + set_maps_for_notification_target_statuses end def show - @notification = Notification.where(account: current_account).find(params[:id]) + @notification = current_account.notifications.find(params[:id]) end def clear - Notification.where(account: current_account).delete_all + current_account.notifications.delete_all render_empty end def dismiss - Notification.find_by!(account: current_account, id: params[:id]).destroy! + current_account.notifications.find_by!(id: params[:id]).destroy! render_empty end private + def load_notifications + cache_collection paginated_notifications, Notification + end + + def paginated_notifications + browserable_account_notifications.paginate_by_max_id( + limit_param(DEFAULT_NOTIFICATIONS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def browserable_account_notifications + current_account.notifications.browserable(exclude_types) + end + + def set_maps_for_notification_target_statuses + set_maps target_statuses_from_notifications + end + + def target_statuses_from_notifications + @notifications.select { |notification| !notification.target_status.nil? }.map(&:target_status) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + unless @notifications.empty? + api_v1_notifications_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @notifications.empty? + api_v1_notifications_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @notifications.last.id + end + + def pagination_since_id + @notifications.first.id + end + def exclude_types val = params.permit(exclude_types: [])[:exclude_types] || [] val = [val] unless val.is_a?(Enumerable) -- GitLab From 84dda45df944d973c83417c697b7d871bb84be35 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:31:14 -0400 Subject: [PATCH 076/295] Improve spec coverage and clean up api/v1/domain_blocks controller (#3466) --- .../api/v1/domain_blocks_controller.rb | 50 ++++++++++++++++--- .../api/v1/domain_blocks_controller_spec.rb | 2 +- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb index f223dd16ee..772c046876 100644 --- a/app/controllers/api/v1/domain_blocks_controller.rb +++ b/app/controllers/api/v1/domain_blocks_controller.rb @@ -1,18 +1,16 @@ # frozen_string_literal: true class Api::V1::DomainBlocksController < ApiController + BLOCK_LIMIT = 100 + before_action -> { doorkeeper_authorize! :follow } before_action :require_user! + after_action :insert_pagination_headers, only: :show respond_to :json def show - @blocks = AccountDomainBlock.where(account: current_account).paginate_by_max_id(limit_param(100), params[:max_id], params[:since_id]) - - next_path = api_v1_domain_blocks_url(pagination_params(max_id: @blocks.last.id)) if @blocks.size == limit_param(100) - prev_path = api_v1_domain_blocks_url(pagination_params(since_id: @blocks.first.id)) unless @blocks.empty? - - set_pagination_headers(next_path, prev_path) + @blocks = load_domain_blocks render json: @blocks.map(&:domain) end @@ -28,6 +26,46 @@ class Api::V1::DomainBlocksController < ApiController private + def load_domain_blocks + account_domain_blocks.paginate_by_max_id( + limit_param(BLOCK_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def account_domain_blocks + current_account.domain_blocks + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + if records_continue? + api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @blocks.empty? + api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @blocks.last.id + end + + def pagination_since_id + @blocks.first.id + end + + def records_continue? + @blocks.size == limit_param(BLOCK_LIMIT) + end + def pagination_params(core_params) params.permit(:limit).merge(core_params) end diff --git a/spec/controllers/api/v1/domain_blocks_controller_spec.rb b/spec/controllers/api/v1/domain_blocks_controller_spec.rb index c3331744da..ff5c5f3302 100644 --- a/spec/controllers/api/v1/domain_blocks_controller_spec.rb +++ b/spec/controllers/api/v1/domain_blocks_controller_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Api::V1::DomainBlocksController, type: :controller do describe 'GET #show' do before do - get :show + get :show, params: { limit: 1 } end it 'returns http success' do -- GitLab From 0f155829b7362d2bb81e2b80e96a351dc7dac538 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:32:11 -0400 Subject: [PATCH 077/295] Improve spec coverage and clean up api/v1/follow_requests controller (#3465) --- .../api/v1/follow_requests_controller.rb | 64 +++++++++++++++---- .../api/v1/follow_requests_controller_spec.rb | 2 +- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index fbb2733d82..8a8d40d771 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -3,32 +3,72 @@ class Api::V1::FollowRequestsController < ApiController before_action -> { doorkeeper_authorize! :follow } before_action :require_user! + after_action :insert_pagination_headers, only: :index def index - @accounts = Account.includes(:follow_requests) - .references(:follow_requests) - .merge(FollowRequest.where(target_account: current_account) - .paginate_by_max_id(DEFAULT_ACCOUNTS_LIMIT, params[:max_id], params[:since_id])) - .to_a - - next_path = api_v1_follow_requests_url(pagination_params(max_id: @accounts.last.follow_requests.last.id)) if @accounts.size == DEFAULT_ACCOUNTS_LIMIT - prev_path = api_v1_follow_requests_url(pagination_params(since_id: @accounts.first.follow_requests.first.id)) unless @accounts.empty? - - set_pagination_headers(next_path, prev_path) + @accounts = load_accounts end def authorize - AuthorizeFollowService.new.call(Account.find(params[:id]), current_account) + AuthorizeFollowService.new.call(account, current_account) render_empty end def reject - RejectFollowService.new.call(Account.find(params[:id]), current_account) + RejectFollowService.new.call(account, current_account) render_empty end private + def account + Account.find(params[:id]) + end + + def load_accounts + default_accounts.merge(paginated_follow_requests).to_a + end + + def default_accounts + Account.includes(:follow_requests).references(:follow_requests) + end + + def paginated_follow_requests + FollowRequest.where(target_account: current_account).paginate_by_max_id( + limit_param(DEFAULT_ACCOUNTS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + if records_continue? + api_v1_follow_requests_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @accounts.empty? + api_v1_follow_requests_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @accounts.last.follow_requests.last.id + end + + def pagination_since_id + @accounts.first.follow_requests.first.id + end + + def records_continue? + @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end + def pagination_params(core_params) params.permit(:limit).merge(core_params) end diff --git a/spec/controllers/api/v1/follow_requests_controller_spec.rb b/spec/controllers/api/v1/follow_requests_controller_spec.rb index a90d2d2902..d455a0255d 100644 --- a/spec/controllers/api/v1/follow_requests_controller_spec.rb +++ b/spec/controllers/api/v1/follow_requests_controller_spec.rb @@ -14,7 +14,7 @@ RSpec.describe Api::V1::FollowRequestsController, type: :controller do describe 'GET #index' do before do - get :index + get :index, params: { limit: 1 } end it 'returns http success' do -- GitLab From 5236a6286107f5731c5f57940592a46ebd3c6107 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:34:51 -0400 Subject: [PATCH 078/295] Improve spec coverage and clean up api/v1/blocks controller (#3464) --- app/controllers/api/v1/blocks_controller.rb | 52 ++++++++++++++++--- .../api/v1/blocks_controller_spec.rb | 4 +- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index b2f3ae5125..d15cb439cf 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -3,23 +3,59 @@ class Api::V1::BlocksController < ApiController before_action -> { doorkeeper_authorize! :follow } before_action :require_user! + after_action :insert_pagination_headers respond_to :json def index - @accounts = Account.includes(:blocked_by) - .references(:blocked_by) - .merge(Block.where(account: current_account) - .paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])) - .to_a + @accounts = load_accounts + end - next_path = api_v1_blocks_url(pagination_params(max_id: @accounts.last.blocked_by_ids.last)) if @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) - prev_path = api_v1_blocks_url(pagination_params(since_id: @accounts.first.blocked_by_ids.first)) unless @accounts.empty? + private + def load_accounts + default_accounts.merge(paginated_blocks).to_a + end + + def default_accounts + Account.includes(:blocked_by).references(:blocked_by) + end + + def paginated_blocks + Block.where(account: current_account).paginate_by_max_id( + limit_param(DEFAULT_ACCOUNTS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def insert_pagination_headers set_pagination_headers(next_path, prev_path) end - private + def next_path + if records_continue? + api_v1_blocks_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @accounts.empty? + api_v1_blocks_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @accounts.last.blocked_by_ids.last + end + + def pagination_since_id + @accounts.first.blocked_by_ids.first + end + + def records_continue? + @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end def pagination_params(core_params) params.permit(:limit).merge(core_params) diff --git a/spec/controllers/api/v1/blocks_controller_spec.rb b/spec/controllers/api/v1/blocks_controller_spec.rb index ca20a2d172..4fd968b27c 100644 --- a/spec/controllers/api/v1/blocks_controller_spec.rb +++ b/spec/controllers/api/v1/blocks_controller_spec.rb @@ -7,12 +7,14 @@ RSpec.describe Api::V1::BlocksController, type: :controller do let(:token) { double acceptable?: true, resource_owner_id: user.id } before do + Fabricate(:block, account: user.account) allow(controller).to receive(:doorkeeper_token) { token } end describe 'GET #index' do it 'returns http success' do - get :index + get :index, params: { limit: 1 } + expect(response).to have_http_status(:success) end end -- GitLab From b25e42a77f4b3472bc519e8a394b2cfe0e063e4c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:38:17 -0400 Subject: [PATCH 079/295] Misc tidying and clean ups (#3445) * Remove trailing whitespace in i18n mailers * Use query methods instead of #present? on AR attributes * Delegate Status#account_domain method * Delegate Mention #account_username and #account_acct methods --- app/lib/atom_serializer.rb | 2 +- app/models/mention.rb | 7 +++++++ app/models/status.rb | 4 +++- app/services/post_status_service.rb | 2 +- app/services/process_feed_service.rb | 2 +- app/views/api/v1/statuses/_mention.rabl | 4 ++-- .../user_mailer/confirmation_instructions.ar.text.erb | 2 +- .../user_mailer/confirmation_instructions.fa.text.erb | 4 ++-- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/lib/atom_serializer.rb b/app/lib/atom_serializer.rb index 561bf7b59b..21ee7deba5 100644 --- a/app/lib/atom_serializer.rb +++ b/app/lib/atom_serializer.rb @@ -328,7 +328,7 @@ class AtomSerializer end def conversation_uri(conversation) - return conversation.uri if conversation.uri.present? + return conversation.uri if conversation.uri? TagManager.instance.unique_tag(conversation.created_at, conversation.id, 'Conversation') end diff --git a/app/models/mention.rb b/app/models/mention.rb index a8d243259c..7450b1b852 100644 --- a/app/models/mention.rb +++ b/app/models/mention.rb @@ -17,4 +17,11 @@ class Mention < ApplicationRecord has_one :notification, as: :activity, dependent: :destroy validates :account, uniqueness: { scope: :status } + + delegate( + :username, + :acct, + to: :account, + prefix: true + ) end diff --git a/app/models/status.rb b/app/models/status.rb index a371083d05..e75ac7070f 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -73,6 +73,8 @@ class Status < ApplicationRecord cache_associated :account, :application, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :application, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account + delegate :domain, to: :account, prefix: true + def reply? !in_reply_to_id.nil? || attributes['reply'] end @@ -288,7 +290,7 @@ class Status < ApplicationRecord def filter_from_context?(status, account) should_filter = account&.blocking?(status.account_id) - should_filter ||= account&.domain_blocking?(status.account.domain) + should_filter ||= account&.domain_blocking?(status.account_domain) should_filter ||= account&.muting?(status.account_id) should_filter ||= (status.account.silenced? && !account&.following?(status.account_id)) should_filter ||= !StatusPolicy.new(account, status).show? diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index b665391e3f..2e6fbb5c38 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -34,7 +34,7 @@ class PostStatusService < BaseService process_mentions_service.call(status) process_hashtags_service.call(status) - LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text.present? + LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text? DistributionWorker.perform_async(status.id) Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id) diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb index 87ed68f704..9402baf180 100644 --- a/app/services/process_feed_service.rb +++ b/app/services/process_feed_service.rb @@ -77,7 +77,7 @@ class ProcessFeedService < BaseService Rails.logger.debug "Queuing remote status #{status.id} (#{id}) for distribution" - LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text.present? + LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text? DistributionWorker.perform_async(status.id) status diff --git a/app/views/api/v1/statuses/_mention.rabl b/app/views/api/v1/statuses/_mention.rabl index 498cca2757..8c95fc9bde 100644 --- a/app/views/api/v1/statuses/_mention.rabl +++ b/app/views/api/v1/statuses/_mention.rabl @@ -1,4 +1,4 @@ node(:url) { |mention| TagManager.instance.url_for(mention.account) } -node(:acct) { |mention| mention.account.acct } +node(:acct) { |mention| mention.account_acct } node(:id) { |mention| mention.account_id } -node(:username) { |mention| mention.account.username } +node(:username) { |mention| mention.account_username } diff --git a/app/views/user_mailer/confirmation_instructions.ar.text.erb b/app/views/user_mailer/confirmation_instructions.ar.text.erb index 1b7b445a1a..087c6a9ae4 100644 --- a/app/views/user_mailer/confirmation_instructions.ar.text.erb +++ b/app/views/user_mailer/confirmation_instructions.ar.text.erb @@ -9,4 +9,4 @@ مع أجمل التحيات، -فريق <%= @instance %> +فريق <%= @instance %> diff --git a/app/views/user_mailer/confirmation_instructions.fa.text.erb b/app/views/user_mailer/confirmation_instructions.fa.text.erb index cbabed06d4..904bd5bfe7 100644 --- a/app/views/user_mailer/confirmation_instructions.fa.text.erb +++ b/app/views/user_mailer/confirmation_instructions.fa.text.erb @@ -2,11 +2,11 @@ شما الان در <%= @instance %> حساب باز کردید. -برای تأیید عضویت، لطفاً روی پیوند زیر کلیک کنید: +برای تأیید عضویت، لطفاً روی پیوند زیر کلیک کنید: <%= confirmation_url(@resource, confirmation_token: @token) %> لطفاً همچنین شرایط و مقررات استفادهٔ ما را هم بخوانید <%= terms_url %> با احترام، -گردانندگان سرور <%= @instance %> +گردانندگان سرور <%= @instance %> -- GitLab From a132332b861f997540f30be1b90ade4648834b5b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:38:44 -0400 Subject: [PATCH 080/295] Add Instance class to list admin records (#3443) --- app/controllers/admin/instances_controller.rb | 9 +++++++-- app/models/instance.rb | 12 ++++++++++++ app/views/admin/instances/index.html.haml | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 app/models/instance.rb diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index b8f170ec28..ac93248a85 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -3,13 +3,18 @@ module Admin class InstancesController < BaseController def index - @instances = ordered_instances.page(params[:page]) + @instances = ordered_instances end private + def paginated_instances + Account.remote.by_domain_accounts.page(params[:page]) + end + helper_method :paginated_instances + def ordered_instances - Account.remote.by_domain_accounts + paginated_instances.map { |account| Instance.new(account) } end end end diff --git a/app/models/instance.rb b/app/models/instance.rb new file mode 100644 index 0000000000..6d5c9c2ab6 --- /dev/null +++ b/app/models/instance.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class Instance + include ActiveModel::Model + + attr_accessor :domain, :accounts_count + + def initialize(account) + @domain = account.domain + @accounts_count = account.accounts_count + end +end diff --git a/app/views/admin/instances/index.html.haml b/app/views/admin/instances/index.html.haml index e5955e6bf7..be21d6bf7b 100644 --- a/app/views/admin/instances/index.html.haml +++ b/app/views/admin/instances/index.html.haml @@ -7,6 +7,6 @@ %th= t('admin.instances.domain_name') %th= t('admin.instances.account_count') %tbody - = render partial: 'instance', collection: @instances + = render @instances -= paginate @instances += paginate paginated_instances -- GitLab From de4681b2be0b0efa1dede092445a53d4a593c140 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 14:39:35 -0400 Subject: [PATCH 081/295] Move admin/pubsubhubbub controller to admin/subscriptions (#3442) --- .../admin/pubsubhubbub_controller.rb | 9 --------- .../admin/subscriptions_controller.rb | 19 +++++++++++++++++++ app/views/admin/pubsubhubbub/index.html.haml | 15 --------------- .../_subscription.html.haml | 0 app/views/admin/subscriptions/index.html.haml | 15 +++++++++++++++ config/locales/ca.yml | 2 +- config/locales/de.yml | 2 +- config/locales/en.yml | 2 +- config/locales/fa.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/he.yml | 2 +- config/locales/id.yml | 2 +- config/locales/io.yml | 2 +- config/locales/ja.yml | 2 +- config/locales/no.yml | 2 +- config/locales/oc.yml | 2 +- config/locales/pl.yml | 2 +- config/locales/pt-BR.yml | 2 +- config/locales/pt.yml | 2 +- config/locales/ru.yml | 2 +- config/locales/th.yml | 2 +- config/locales/tr.yml | 2 +- config/locales/uk.yml | 2 +- config/locales/zh-CN.yml | 2 +- config/locales/zh-HK.yml | 2 +- config/locales/zh-TW.yml | 2 +- config/navigation.rb | 2 +- config/routes.rb | 2 +- ...ec.rb => subscriptions_controller_spec.rb} | 2 +- 29 files changed, 58 insertions(+), 48 deletions(-) delete mode 100644 app/controllers/admin/pubsubhubbub_controller.rb create mode 100644 app/controllers/admin/subscriptions_controller.rb delete mode 100644 app/views/admin/pubsubhubbub/index.html.haml rename app/views/admin/{pubsubhubbub => subscriptions}/_subscription.html.haml (100%) create mode 100644 app/views/admin/subscriptions/index.html.haml rename spec/controllers/admin/{pubsubhubbub_controller_spec.rb => subscriptions_controller_spec.rb} (91%) diff --git a/app/controllers/admin/pubsubhubbub_controller.rb b/app/controllers/admin/pubsubhubbub_controller.rb deleted file mode 100644 index 2677a59e46..0000000000 --- a/app/controllers/admin/pubsubhubbub_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Admin - class PubsubhubbubController < BaseController - def index - @subscriptions = Subscription.order(id: :desc).includes(:account).page(params[:page]) - end - end -end diff --git a/app/controllers/admin/subscriptions_controller.rb b/app/controllers/admin/subscriptions_controller.rb new file mode 100644 index 0000000000..624a475a3d --- /dev/null +++ b/app/controllers/admin/subscriptions_controller.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Admin + class SubscriptionsController < BaseController + def index + @subscriptions = ordered_subscriptions.page(requested_page) + end + + private + + def ordered_subscriptions + Subscription.order(id: :desc).includes(:account) + end + + def requested_page + params[:page].to_i + end + end +end diff --git a/app/views/admin/pubsubhubbub/index.html.haml b/app/views/admin/pubsubhubbub/index.html.haml deleted file mode 100644 index 066d9e5c68..0000000000 --- a/app/views/admin/pubsubhubbub/index.html.haml +++ /dev/null @@ -1,15 +0,0 @@ -- content_for :page_title do - = t('admin.pubsubhubbub.title') - -%table.table - %thead - %tr - %th= t('admin.pubsubhubbub.topic') - %th= t('admin.pubsubhubbub.callback_url') - %th= t('admin.pubsubhubbub.confirmed') - %th= t('admin.pubsubhubbub.expires_in') - %th= t('admin.pubsubhubbub.last_delivery') - %tbody - = render partial: 'subscription', collection: @subscriptions - -= paginate @subscriptions diff --git a/app/views/admin/pubsubhubbub/_subscription.html.haml b/app/views/admin/subscriptions/_subscription.html.haml similarity index 100% rename from app/views/admin/pubsubhubbub/_subscription.html.haml rename to app/views/admin/subscriptions/_subscription.html.haml diff --git a/app/views/admin/subscriptions/index.html.haml b/app/views/admin/subscriptions/index.html.haml new file mode 100644 index 0000000000..21b3238a6b --- /dev/null +++ b/app/views/admin/subscriptions/index.html.haml @@ -0,0 +1,15 @@ +- 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 + += paginate @subscriptions diff --git a/config/locales/ca.yml b/config/locales/ca.yml index e3b3a91f93..1917441d70 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -134,7 +134,7 @@ ca: account_count: Comptes coneguts domain_name: Domini title: Instàncies conegudes - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: Confirmat expires_in: Expira en diff --git a/config/locales/de.yml b/config/locales/de.yml index a7d86e2849..0a11e04225 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -119,7 +119,7 @@ de: account_count: Bekannte Konten domain_name: Domain title: Bekannte Instanzen - pubsubhubbub: + subscriptions: callback_url: Callback-URL confirmed: Bestätigt expires_in: Verfällt in diff --git a/config/locales/en.yml b/config/locales/en.yml index c27dfb0e50..2ff2f7eec6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -134,7 +134,7 @@ en: account_count: Known accounts domain_name: Domain title: Known Instances - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: Confirmed expires_in: Expires in diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 458d03db54..de59e4f3fe 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -130,7 +130,7 @@ fa: account_count: حساب‌های شناخته‌شده domain_name: دامین title: سرورهای شناخته‌شده - pubsubhubbub: + subscriptions: callback_url: نشانی Callback confirmed: تأییدشده expires_in: مهلت انقضا diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 4d9af2bc33..8cd8fdd080 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -110,7 +110,7 @@ fr: undo: Annuler title: Blocage de domaines undo: Annuler - pubsubhubbub: + subscriptions: callback_url: URL de rappel confirmed: Confirmé expires_in: Expire dans diff --git a/config/locales/he.yml b/config/locales/he.yml index 88b082b30e..f38981f683 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -134,7 +134,7 @@ he: account_count: חשבונות מוכרים domain_name: שם מתחם title: שרתים מוכרים - pubsubhubbub: + subscriptions: callback_url: קישורית Callback confirmed: מאושר expires_in: פג תוקף ב- diff --git a/config/locales/id.yml b/config/locales/id.yml index f174cdacba..48fe466e55 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -129,7 +129,7 @@ id: account_count: Akun yang diketahui domain_name: Domain title: Server yang diketahui - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: Dikonfirmasi expires_in: Kadaluarsa dalam diff --git a/config/locales/io.yml b/config/locales/io.yml index 240de6422b..42351502b9 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -118,7 +118,7 @@ io: account_count: Known accounts domain_name: Domain title: Known Instances - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: Confirmed expires_in: Expires in diff --git a/config/locales/ja.yml b/config/locales/ja.yml index cc5430c473..e8bf9e61a5 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -134,7 +134,7 @@ ja: account_count: 既知のアカウント数 domain_name: ドメイン名 title: 既知のインスタンス - pubsubhubbub: + subscriptions: callback_url: コールバックURL confirmed: 確認済み expires_in: 期限 diff --git a/config/locales/no.yml b/config/locales/no.yml index 0ed9aea5e3..295293b09b 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -131,7 +131,7 @@ account_count: Kjente kontoer domain_name: Domene title: Kjente instanser - pubsubhubbub: + subscriptions: callback_url: Callback-URL confirmed: Bekreftet expires_in: Utløper om diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 7f6e3daf0f..2a2680a907 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -134,7 +134,7 @@ oc: account_count: Comptes coneguts domain_name: Domeni title: Instàncias conegudas - pubsubhubbub: + subscriptions: callback_url: URL de rapèl confirmed: Confirmat expires_in: S’acaba dins diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 247e6c4ff6..e3b4c64e93 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -134,7 +134,7 @@ pl: account_count: Znane konta domain_name: Domena title: Znane instancje - pubsubhubbub: + subscriptions: callback_url: URL zwrotny confirmed: Potwierdzono expires_in: Wygasa diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 5eab5d6938..1ec10f8d0b 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -130,7 +130,7 @@ pt-BR: account_count: Contas conhecidas domain_name: Domínio title: Instâncias conhecidas - pubsubhubbub: + subscriptions: callback_url: URL de Callback confirmed: Confirmado expires_in: Expira em diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 43659c91e5..f628e59f2b 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -126,7 +126,7 @@ pt: account_count: Contas conhecidas domain_name: Domínio title: Instâncias conhecidas - pubsubhubbub: + subscriptions: callback_url: URL de Callback confirmed: Confirmado expires_in: Expira em diff --git a/config/locales/ru.yml b/config/locales/ru.yml index d26b235ed2..f7a022f114 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -113,7 +113,7 @@ ru: undo: Отменить title: Доменные блокировки undo: Отемнить - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: Подтверждено expires_in: Истекает через diff --git a/config/locales/th.yml b/config/locales/th.yml index dd330cc2b6..ab98adf737 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -131,7 +131,7 @@ th: account_count: Known accounts domain_name: ชื่อโดเมน title: Known Instances - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: ยืนยัน expires_in: หมดอายุภายใน diff --git a/config/locales/tr.yml b/config/locales/tr.yml index b225883c75..ea525e0c05 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -130,7 +130,7 @@ tr: account_count: Bilinen hesaplar domain_name: Domain title: Bilinen Sunucular - pubsubhubbub: + subscriptions: callback_url: Callback linki confirmed: Onaylandı expires_in: Bitiş Tarihi diff --git a/config/locales/uk.yml b/config/locales/uk.yml index a06609ff05..227356f86f 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -113,7 +113,7 @@ uk: undo: Відмінити title: Доменні блокування undo: Відмінити - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: Підтверджено expires_in: Спливає через diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index edfc381db0..2dc6f813f1 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -134,7 +134,7 @@ zh-CN: account_count: 已知帐号 domain_name: 域名 title: 已知实例 - pubsubhubbub: + subscriptions: callback_url: 回调 URL confirmed: 确定 expires_in: 期限 diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index e6223917ea..b886af8de6 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -130,7 +130,7 @@ zh-HK: account_count: 已知帳號 domain_name: 域名 title: 已知服務站 - pubsubhubbub: + subscriptions: callback_url: 回傳 URL confirmed: 確定 expires_in: 期限 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 82b07be34f..cb96f65439 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -92,7 +92,7 @@ zh-TW: title: 新封鎖網域 severity: 嚴重度 title: 網域封鎖 - pubsubhubbub: + subscriptions: callback_url: Callback URL confirmed: 已確認 expires_in: 期限 diff --git a/config/navigation.rb b/config/navigation.rb index 38dee91b24..85ed62118a 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -19,7 +19,7 @@ SimpleNavigation::Configuration.run do |navigation| admin.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports} admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts} admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances} - admin.item :pubsubhubbubs, safe_join([fa_icon('paper-plane-o fw'), t('admin.pubsubhubbub.title')]), admin_pubsubhubbub_index_url + admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks} admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' } admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' } diff --git a/config/routes.rb b/config/routes.rb index 7db3c74b13..b1590f9291 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -74,7 +74,7 @@ Rails.application.routes.draw do resource :authorize_follow, only: [:show, :create] namespace :admin do - resources :pubsubhubbub, only: [:index] + resources :subscriptions, only: [:index] resources :domain_blocks, only: [:index, :new, :create, :show, :destroy] resource :settings, only: [:edit, :update] resources :instances, only: [:index] diff --git a/spec/controllers/admin/pubsubhubbub_controller_spec.rb b/spec/controllers/admin/subscriptions_controller_spec.rb similarity index 91% rename from spec/controllers/admin/pubsubhubbub_controller_spec.rb rename to spec/controllers/admin/subscriptions_controller_spec.rb index c8e8e7a842..eb6f12b16e 100644 --- a/spec/controllers/admin/pubsubhubbub_controller_spec.rb +++ b/spec/controllers/admin/subscriptions_controller_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rails_helper' -RSpec.describe Admin::PubsubhubbubController, type: :controller do +RSpec.describe Admin::SubscriptionsController, type: :controller do render_views describe 'GET #index' do -- GitLab From 5c6352397257d82e75b90cc5e7de1a3922bde7bd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 31 May 2017 15:36:24 -0400 Subject: [PATCH 082/295] Spec coverage and refactor for the api/v1/accounts controllers (#3451) --- .../api/v1/accounts/credentials_controller.rb | 23 ++++ .../accounts/follower_accounts_controller.rb | 68 +++++++++ .../accounts/following_accounts_controller.rb | 68 +++++++++ .../v1/accounts/relationships_controller.rb | 24 ++++ .../api/v1/accounts/search_controller.rb | 29 ++++ .../api/v1/accounts/statuses_controller.rb | 92 +++++++++++++ app/controllers/api/v1/accounts_controller.rb | 94 +------------ .../index.rabl} | 0 .../{statuses.rabl => statuses/index.rabl} | 0 config/routes.rb | 19 ++- .../accounts/credentials_controller_spec.rb | 55 ++++++++ .../follower_accounts_controller_spec.rb | 21 +++ .../following_accounts_controller_spec.rb | 21 +++ .../accounts/relationships_controller_spec.rb | 69 ++++++++++ .../api/v1/accounts/search_controller_spec.rb | 20 +++ .../v1/accounts/statuses_controller_spec.rb | 38 ++++++ .../api/v1/accounts_controller_spec.rb | 129 ------------------ spec/routing/api_routing_spec.rb | 39 ++++++ 18 files changed, 579 insertions(+), 230 deletions(-) create mode 100644 app/controllers/api/v1/accounts/credentials_controller.rb create mode 100644 app/controllers/api/v1/accounts/follower_accounts_controller.rb create mode 100644 app/controllers/api/v1/accounts/following_accounts_controller.rb create mode 100644 app/controllers/api/v1/accounts/relationships_controller.rb create mode 100644 app/controllers/api/v1/accounts/search_controller.rb create mode 100644 app/controllers/api/v1/accounts/statuses_controller.rb rename app/views/api/v1/accounts/{relationships.rabl => relationships/index.rabl} (100%) rename app/views/api/v1/accounts/{statuses.rabl => statuses/index.rabl} (100%) create mode 100644 spec/controllers/api/v1/accounts/credentials_controller_spec.rb create mode 100644 spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb create mode 100644 spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb create mode 100644 spec/controllers/api/v1/accounts/relationships_controller_spec.rb create mode 100644 spec/controllers/api/v1/accounts/search_controller_spec.rb create mode 100644 spec/controllers/api/v1/accounts/statuses_controller_spec.rb diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb new file mode 100644 index 0000000000..8f2ded29e3 --- /dev/null +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class Api::V1::Accounts::CredentialsController < ApiController + before_action -> { doorkeeper_authorize! :write }, only: [:update] + before_action :require_user! + + def show + @account = current_account + render 'api/v1/accounts/show' + end + + def update + current_account.update!(account_params) + @account = current_account + render 'api/v1/accounts/show' + end + + private + + def account_params + params.permit(:display_name, :note, :avatar, :header) + end +end diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb new file mode 100644 index 0000000000..3e9da29e34 --- /dev/null +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +class Api::V1::Accounts::FollowerAccountsController < ApiController + before_action -> { doorkeeper_authorize! :read } + before_action :set_account + after_action :insert_pagination_headers + + respond_to :json + + def index + @accounts = load_accounts + render 'api/v1/accounts/index' + end + + private + + def set_account + @account = Account.find(params[:account_id]) + end + + def load_accounts + default_accounts.merge(paginated_follows).to_a + end + + def default_accounts + Account.includes(:active_relationships).references(:active_relationships) + end + + def paginated_follows + Follow.where(target_account: @account).paginate_by_max_id( + limit_param(DEFAULT_ACCOUNTS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + if records_continue? + api_v1_account_followers_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @accounts.empty? + api_v1_account_followers_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @accounts.last.active_relationships.first.id + end + + def pagination_since_id + @accounts.first.active_relationships.first.id + end + + def records_continue? + @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end + + def pagination_params(core_params) + params.permit(:limit).merge(core_params) + end +end diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb new file mode 100644 index 0000000000..732961aac1 --- /dev/null +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +class Api::V1::Accounts::FollowingAccountsController < ApiController + before_action -> { doorkeeper_authorize! :read } + before_action :set_account + after_action :insert_pagination_headers + + respond_to :json + + def index + @accounts = load_accounts + render 'api/v1/accounts/index' + end + + private + + def set_account + @account = Account.find(params[:account_id]) + end + + def load_accounts + default_accounts.merge(paginated_follows).to_a + end + + def default_accounts + Account.includes(:passive_relationships).references(:passive_relationships) + end + + def paginated_follows + Follow.where(account: @account).paginate_by_max_id( + limit_param(DEFAULT_ACCOUNTS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + if records_continue? + api_v1_account_following_index_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @accounts.empty? + api_v1_account_following_index_url pagination_params(since_id: pagination_since_id) + end + end + + def pagination_max_id + @accounts.last.passive_relationships.first.id + end + + def pagination_since_id + @accounts.first.passive_relationships.first.id + end + + def records_continue? + @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end + + def pagination_params(core_params) + params.permit(:limit).merge(core_params) + end +end diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb new file mode 100644 index 0000000000..d1a4f178b6 --- /dev/null +++ b/app/controllers/api/v1/accounts/relationships_controller.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class Api::V1::Accounts::RelationshipsController < ApiController + before_action -> { doorkeeper_authorize! :read } + before_action :require_user! + + respond_to :json + + def index + @accounts = Account.where(id: account_ids).select('id') + @following = Account.following_map(account_ids, current_user.account_id) + @followed_by = Account.followed_by_map(account_ids, current_user.account_id) + @blocking = Account.blocking_map(account_ids, current_user.account_id) + @muting = Account.muting_map(account_ids, current_user.account_id) + @requested = Account.requested_map(account_ids, current_user.account_id) + @domain_blocking = Account.domain_blocking_map(account_ids, current_user.account_id) + end + + private + + def account_ids + @_account_ids ||= Array(params[:id]).map(&:to_i) + end +end diff --git a/app/controllers/api/v1/accounts/search_controller.rb b/app/controllers/api/v1/accounts/search_controller.rb new file mode 100644 index 0000000000..6d4c6e4cf9 --- /dev/null +++ b/app/controllers/api/v1/accounts/search_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class Api::V1::Accounts::SearchController < ApiController + before_action -> { doorkeeper_authorize! :read } + before_action :require_user! + + respond_to :json + + def show + @accounts = account_search + + render 'api/v1/accounts/index' + end + + private + + def account_search + AccountSearchService.new.call( + params[:q], + limit_param(DEFAULT_ACCOUNTS_LIMIT), + resolving_search?, + current_account + ) + end + + def resolving_search? + params[:resolve] == 'true' + end +end diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb new file mode 100644 index 0000000000..1e0d2a740b --- /dev/null +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +class Api::V1::Accounts::StatusesController < ApiController + before_action -> { doorkeeper_authorize! :read } + before_action :set_account + after_action :insert_pagination_headers + + respond_to :json + + def index + @statuses = load_statuses + end + + private + + def set_account + @account = Account.find(params[:account_id]) + end + + def load_statuses + cached_account_statuses.tap do |statuses| + set_maps(statuses) + end + end + + def cached_account_statuses + cache_collection account_statuses, Status + end + + def account_statuses + default_statuses.tap do |statuses| + statuses.merge!(only_media_scope) if params[:only_media] + statuses.merge!(no_replies_scope) if params[:exclude_replies] + end + end + + def default_statuses + permitted_account_statuses.paginate_by_max_id( + limit_param(DEFAULT_STATUSES_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def permitted_account_statuses + @account.statuses.permitted_for(@account, current_account) + end + + def only_media_scope + Status.where(id: account_media_status_ids) + end + + def account_media_status_ids + @account.media_attachments.attached.reorder(nil).select(:status_id).distinct + end + + def no_replies_scope + Status.without_replies + end + + def pagination_params(core_params) + params.permit(:limit, :only_media, :exclude_replies).merge(core_params) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + if records_continue? + api_v1_account_statuses_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @statuses.empty? + api_v1_account_statuses_url pagination_params(since_id: pagination_since_id) + end + end + + def records_continue? + @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id + end +end diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index bd6fb6a2a8..3b23e996d6 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -1,73 +1,15 @@ # frozen_string_literal: true class Api::V1::AccountsController < ApiController - before_action -> { doorkeeper_authorize! :read }, except: [:follow, :unfollow, :block, :unblock, :mute, :unmute, :update_credentials] + before_action -> { doorkeeper_authorize! :read }, except: [:follow, :unfollow, :block, :unblock, :mute, :unmute] before_action -> { doorkeeper_authorize! :follow }, only: [:follow, :unfollow, :block, :unblock, :mute, :unmute] - before_action -> { doorkeeper_authorize! :write }, only: [:update_credentials] - before_action :require_user!, except: [:show, :following, :followers, :statuses] - before_action :set_account, except: [:verify_credentials, :update_credentials, :suggestions, :search] + before_action :require_user!, except: [:show] + before_action :set_account respond_to :json def show; end - def verify_credentials - @account = current_user.account - render :show - end - - def update_credentials - current_account.update!(account_params) - @account = current_account - render :show - end - - def following - @accounts = Account.includes(:passive_relationships) - .references(:passive_relationships) - .merge(Follow.where(account: @account) - .paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])) - .to_a - - next_path = following_api_v1_account_url(pagination_params(max_id: @accounts.last.passive_relationships.first.id)) if @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) - prev_path = following_api_v1_account_url(pagination_params(since_id: @accounts.first.passive_relationships.first.id)) unless @accounts.empty? - - set_pagination_headers(next_path, prev_path) - - render :index - end - - def followers - @accounts = Account.includes(:active_relationships) - .references(:active_relationships) - .merge(Follow.where(target_account: @account) - .paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), - params[:max_id], - params[:since_id])) - .to_a - - next_path = followers_api_v1_account_url(pagination_params(max_id: @accounts.last.active_relationships.first.id)) if @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) - prev_path = followers_api_v1_account_url(pagination_params(since_id: @accounts.first.active_relationships.first.id)) unless @accounts.empty? - - set_pagination_headers(next_path, prev_path) - - render :index - end - - def statuses - @statuses = @account.statuses.permitted_for(@account, current_account).paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id]) - @statuses = @statuses.where(id: MediaAttachment.where(account: @account).where.not(status_id: nil).reorder('').select('distinct status_id')) if params[:only_media] - @statuses = @statuses.without_replies if params[:exclude_replies] - @statuses = cache_collection(@statuses, Status) - - set_maps(@statuses) - - next_path = statuses_api_v1_account_url(statuses_pagination_params(max_id: @statuses.last.id)) if @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) - prev_path = statuses_api_v1_account_url(statuses_pagination_params(since_id: @statuses.first.id)) unless @statuses.empty? - - set_pagination_headers(next_path, prev_path) - end - def follow FollowService.new.call(current_user.account, @account.acct) set_relationship @@ -111,24 +53,6 @@ class Api::V1::AccountsController < ApiController render :relationship end - def relationships - ids = params[:id].is_a?(Enumerable) ? params[:id].map(&:to_i) : [params[:id].to_i] - - @accounts = Account.where(id: ids).select('id') - @following = Account.following_map(ids, current_user.account_id) - @followed_by = Account.followed_by_map(ids, current_user.account_id) - @blocking = Account.blocking_map(ids, current_user.account_id) - @muting = Account.muting_map(ids, current_user.account_id) - @requested = Account.requested_map(ids, current_user.account_id) - @domain_blocking = Account.domain_blocking_map(ids, current_user.account_id) - end - - def search - @accounts = AccountSearchService.new.call(params[:q], limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:resolve] == 'true', current_account) - - render :index - end - private def set_account @@ -143,16 +67,4 @@ class Api::V1::AccountsController < ApiController @requested = Account.requested_map([@account.id], current_user.account_id) @domain_blocking = Account.domain_blocking_map([@account.id], current_user.account_id) end - - def pagination_params(core_params) - params.permit(:limit).merge(core_params) - end - - def statuses_pagination_params(core_params) - params.permit(:limit, :only_media, :exclude_replies).merge(core_params) - end - - def account_params - params.permit(:display_name, :note, :avatar, :header) - end end diff --git a/app/views/api/v1/accounts/relationships.rabl b/app/views/api/v1/accounts/relationships/index.rabl similarity index 100% rename from app/views/api/v1/accounts/relationships.rabl rename to app/views/api/v1/accounts/relationships/index.rabl diff --git a/app/views/api/v1/accounts/statuses.rabl b/app/views/api/v1/accounts/statuses/index.rabl similarity index 100% rename from app/views/api/v1/accounts/statuses.rabl rename to app/views/api/v1/accounts/statuses/index.rabl diff --git a/config/routes.rb b/config/routes.rb index b1590f9291..5c1c8e594f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -169,19 +169,18 @@ Rails.application.routes.draw do end end + namespace :accounts do + get :verify_credentials, to: 'credentials#show' + patch :update_credentials, to: 'credentials#update' + resource :search, only: :show, controller: :search + resources :relationships, only: :index + end resources :accounts, only: [:show] do - collection do - get :relationships - get :verify_credentials - patch :update_credentials - get :search - end + resources :statuses, only: :index, controller: 'accounts/statuses' + resources :followers, only: :index, controller: 'accounts/follower_accounts' + resources :following, only: :index, controller: 'accounts/following_accounts' member do - get :statuses - get :followers - get :following - post :follow post :unfollow post :block diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb new file mode 100644 index 0000000000..89dbca1119 --- /dev/null +++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb @@ -0,0 +1,55 @@ +require 'rails_helper' + +describe Api::V1::Accounts::CredentialsController do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { double acceptable?: true, resource_owner_id: user.id } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #show' do + it 'returns http success' do + get :show + expect(response).to have_http_status(:success) + end + end + + describe 'PATCH #update' do + describe 'with valid data' do + before do + patch :update, params: { + display_name: "Alice Isn't Dead", + note: "Hi!\n\nToot toot!", + avatar: fixture_file_upload('files/avatar.gif', 'image/gif'), + header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'), + } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'updates account info' do + user.account.reload + + expect(user.account.display_name).to eq("Alice Isn't Dead") + expect(user.account.note).to eq("Hi!\n\nToot toot!") + expect(user.account.avatar).to exist + expect(user.account.header).to exist + end + end + + describe 'with invalid data' do + before do + patch :update, params: { note: 'This is too long. ' * 10 } + end + + it 'returns http unprocessable entity' do + expect(response).to have_http_status(:unprocessable_entity) + end + end + end +end diff --git a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb new file mode 100644 index 0000000000..171852c755 --- /dev/null +++ b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +describe Api::V1::Accounts::FollowerAccountsController do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { double acceptable?: true, resource_owner_id: user.id } + + before do + Fabricate(:follow, target_account: user.account) + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #index' do + it 'returns http success' do + get :index, params: { account_id: user.account.id, limit: 1 } + + expect(response).to have_http_status(:success) + end + end +end diff --git a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb new file mode 100644 index 0000000000..a4cad9163e --- /dev/null +++ b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +describe Api::V1::Accounts::FollowingAccountsController do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { double acceptable?: true, resource_owner_id: user.id } + + before do + Fabricate(:follow, account: user.account) + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #index' do + it 'returns http success' do + get :index, params: { account_id: user.account.id, limit: 1 } + + expect(response).to have_http_status(:success) + end + end +end diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb new file mode 100644 index 0000000000..e281afcb92 --- /dev/null +++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb @@ -0,0 +1,69 @@ +require 'rails_helper' + +describe Api::V1::Accounts::RelationshipsController do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { double acceptable?: true, resource_owner_id: user.id } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #index' do + let(:simon) { Fabricate(:user, email: 'simon@example.com', account: Fabricate(:account, username: 'simon')).account } + let(:lewis) { Fabricate(:user, email: 'lewis@example.com', account: Fabricate(:account, username: 'lewis')).account } + + before do + user.account.follow!(simon) + lewis.follow!(user.account) + end + + context 'provided only one ID' do + before do + get :index, params: { id: simon.id } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'returns JSON with correct data' do + json = body_as_json + + expect(json).to be_a Enumerable + expect(json.first[:following]).to be true + expect(json.first[:followed_by]).to be false + end + end + + context 'provided multiple IDs' do + before do + get :index, params: { id: [simon.id, lewis.id] } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'returns JSON with correct data' do + json = body_as_json + + expect(json).to be_a Enumerable + expect(json.first[:id]).to be simon.id + expect(json.first[:following]).to be true + expect(json.first[:followed_by]).to be false + expect(json.first[:muting]).to be false + expect(json.first[:requested]).to be false + expect(json.first[:domain_blocking]).to be false + + expect(json.second[:id]).to be lewis.id + expect(json.second[:following]).to be false + expect(json.second[:followed_by]).to be true + expect(json.second[:muting]).to be false + expect(json.second[:requested]).to be false + expect(json.second[:domain_blocking]).to be false + end + end + end +end diff --git a/spec/controllers/api/v1/accounts/search_controller_spec.rb b/spec/controllers/api/v1/accounts/search_controller_spec.rb new file mode 100644 index 0000000000..40c82437dd --- /dev/null +++ b/spec/controllers/api/v1/accounts/search_controller_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +RSpec.describe Api::V1::Accounts::SearchController, type: :controller do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { double acceptable?: true, resource_owner_id: user.id } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #show' do + it 'returns http success' do + get :show, params: { q: 'query' } + + expect(response).to have_http_status(:success) + end + end +end diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb new file mode 100644 index 0000000000..55cb5bcc24 --- /dev/null +++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +describe Api::V1::Accounts::StatusesController do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { double acceptable?: true, resource_owner_id: user.id } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + Fabricate(:status, account: user.account) + end + + describe 'GET #index' do + it 'returns http success' do + get :index, params: { account_id: user.account.id, limit: 1 } + + expect(response).to have_http_status(:success) + expect(response.headers['Link'].links.size).to eq(2) + end + end + + describe 'GET #index with only media' do + it 'returns http success' do + get :index, params: { account_id: user.account.id, only_media: true } + + expect(response).to have_http_status(:success) + end + end + + describe 'GET #index with exclude replies' do + it 'returns http success' do + get :index, params: { account_id: user.account.id, exclude_replies: true } + + expect(response).to have_http_status(:success) + end + end +end diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb index dec81aff52..216a9cb3b6 100644 --- a/spec/controllers/api/v1/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts_controller_spec.rb @@ -17,78 +17,6 @@ RSpec.describe Api::V1::AccountsController, type: :controller do end end - describe 'GET #search' do - it 'returns http success' do - get :search, params: { q: 'query' } - - expect(response).to have_http_status(:success) - end - end - - describe 'GET #verify_credentials' do - it 'returns http success' do - get :verify_credentials - expect(response).to have_http_status(:success) - end - end - - describe 'PATCH #update_credentials' do - describe 'with valid data' do - before do - patch :update_credentials, params: { - display_name: "Alice Isn't Dead", - note: "Hi!\n\nToot toot!", - avatar: fixture_file_upload('files/avatar.gif', 'image/gif'), - header: fixture_file_upload('files/attachment.jpg', 'image/jpeg'), - } - end - - it 'returns http success' do - expect(response).to have_http_status(:success) - end - - it 'updates account info' do - user.account.reload - - expect(user.account.display_name).to eq("Alice Isn't Dead") - expect(user.account.note).to eq("Hi!\n\nToot toot!") - expect(user.account.avatar).to exist - expect(user.account.header).to exist - end - end - - describe 'with invalid data' do - before do - patch :update_credentials, params: { note: 'This is too long. ' * 10 } - end - - it 'returns http unprocessable entity' do - expect(response).to have_http_status(:unprocessable_entity) - end - end - end - - describe 'GET #statuses' do - it 'returns http success' do - get :statuses, params: { id: user.account.id } - expect(response).to have_http_status(:success) - end - end - - describe 'GET #followers' do - it 'returns http success' do - get :followers, params: { id: user.account.id } - expect(response).to have_http_status(:success) - end - end - - describe 'GET #following' do - it 'returns http success' do - get :following, params: { id: user.account.id } - expect(response).to have_http_status(:success) - end - end - describe 'POST #follow' do let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } @@ -197,61 +125,4 @@ RSpec.describe Api::V1::AccountsController, type: :controller do expect(user.account.muting?(other_account)).to be false end end - - describe 'GET #relationships' do - let(:simon) { Fabricate(:user, email: 'simon@example.com', account: Fabricate(:account, username: 'simon')).account } - let(:lewis) { Fabricate(:user, email: 'lewis@example.com', account: Fabricate(:account, username: 'lewis')).account } - - before do - user.account.follow!(simon) - lewis.follow!(user.account) - end - - context 'provided only one ID' do - before do - get :relationships, params: { id: simon.id } - end - - it 'returns http success' do - expect(response).to have_http_status(:success) - end - - it 'returns JSON with correct data' do - json = body_as_json - - expect(json).to be_a Enumerable - expect(json.first[:following]).to be true - expect(json.first[:followed_by]).to be false - end - end - - context 'provided multiple IDs' do - before do - get :relationships, params: { id: [simon.id, lewis.id] } - end - - it 'returns http success' do - expect(response).to have_http_status(:success) - end - - it 'returns JSON with correct data' do - json = body_as_json - - expect(json).to be_a Enumerable - expect(json.first[:id]).to be simon.id - expect(json.first[:following]).to be true - expect(json.first[:followed_by]).to be false - expect(json.first[:muting]).to be false - expect(json.first[:requested]).to be false - expect(json.first[:domain_blocking]).to be false - - expect(json.second[:id]).to be lewis.id - expect(json.second[:following]).to be false - expect(json.second[:followed_by]).to be true - expect(json.second[:muting]).to be false - expect(json.second[:requested]).to be false - expect(json.second[:domain_blocking]).to be false - end - end - end end diff --git a/spec/routing/api_routing_spec.rb b/spec/routing/api_routing_spec.rb index 973b4801d9..6dfd074a08 100644 --- a/spec/routing/api_routing_spec.rb +++ b/spec/routing/api_routing_spec.rb @@ -1,6 +1,45 @@ require 'rails_helper' describe 'API routes' do + describe 'Credentials routes' do + it 'routes to verify credentials' do + expect(get('/api/v1/accounts/verify_credentials')). + to route_to('api/v1/accounts/credentials#show') + end + + it 'routes to update credentials' do + expect(patch('/api/v1/accounts/update_credentials')). + to route_to('api/v1/accounts/credentials#update') + end + end + + describe 'Account routes' do + it 'routes to statuses' do + expect(get('/api/v1/accounts/user/statuses')). + to route_to('api/v1/accounts/statuses#index', account_id: 'user') + end + + it 'routes to followers' do + expect(get('/api/v1/accounts/user/followers')). + to route_to('api/v1/accounts/follower_accounts#index', account_id: 'user') + end + + it 'routes to following' do + expect(get('/api/v1/accounts/user/following')). + to route_to('api/v1/accounts/following_accounts#index', account_id: 'user') + end + + it 'routes to search' do + expect(get('/api/v1/accounts/search')). + to route_to('api/v1/accounts/search#show') + end + + it 'routes to relationships' do + expect(get('/api/v1/accounts/relationships')). + to route_to('api/v1/accounts/relationships#index') + end + end + describe 'Timeline routes' do it 'routes to home timeline' do expect(get('/api/v1/timelines/home')). -- GitLab From dbccdcc1b1e295b7f05a7867936e858ea26f0d6b Mon Sep 17 00:00:00 2001 From: unarist Date: Thu, 1 Jun 2017 11:20:10 +0900 Subject: [PATCH 083/295] Focus the submit button on the boost modal (#3494) Focus the submit button when boost modal is opened. --- .../mastodon/features/ui/components/boost_modal.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.js b/app/javascript/mastodon/features/ui/components/boost_modal.js index 183f05fab1..9d99b53361 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.js +++ b/app/javascript/mastodon/features/ui/components/boost_modal.js @@ -27,6 +27,10 @@ class BoostModal extends ImmutablePureComponent { intl: PropTypes.object.isRequired, }; + componentDidMount() { + this.button.focus(); + } + handleReblog = () => { this.props.onReblog(this.props.status); this.props.onClose(); @@ -40,6 +44,10 @@ class BoostModal extends ImmutablePureComponent { } } + setRef = (c) => { + this.button = c; + } + render () { const { status, intl, onClose } = this.props; @@ -67,7 +75,7 @@ class BoostModal extends ImmutablePureComponent {
Shift + }} />
-
); -- GitLab From d1e08bd38c029f0b47dfd2f3ba61ca5bb3e414b8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 1 Jun 2017 08:20:36 -0400 Subject: [PATCH 084/295] Handle nil and blank cases in Account finders (#3500) --- app/models/concerns/account_finder_concern.rb | 10 +++++++--- .../concerns/account_finder_concern_spec.rb | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account_finder_concern.rb index d3ad519b12..561c7ab9f8 100644 --- a/app/models/concerns/account_finder_concern.rb +++ b/app/models/concerns/account_finder_concern.rb @@ -37,21 +37,25 @@ module AccountFinderConcern def scoped_accounts Account.unscoped.tap do |scope| + scope.merge! with_usernames scope.merge! matching_username scope.merge! matching_domain end end + def with_usernames + Account.where.not(username: [nil, '']) + end + def matching_username - raise(ActiveRecord::RecordNotFound) if username.blank? - Account.where(Account.arel_table[:username].lower.eq username.downcase) + Account.where(Account.arel_table[:username].lower.eq username.to_s.downcase) end def matching_domain if domain.nil? Account.where(domain: nil) else - Account.where(Account.arel_table[:domain].lower.eq domain.downcase) + Account.where(Account.arel_table[:domain].lower.eq domain.to_s.downcase) end end end diff --git a/spec/models/concerns/account_finder_concern_spec.rb b/spec/models/concerns/account_finder_concern_spec.rb index 05f0f44f27..25f4fdec4b 100644 --- a/spec/models/concerns/account_finder_concern_spec.rb +++ b/spec/models/concerns/account_finder_concern_spec.rb @@ -24,6 +24,14 @@ describe AccountFinderConcern do it 'returns nil for regex style username value' do expect(Account.find_local('al%')).to be_nil end + + it 'returns nil for nil username value' do + expect(Account.find_local(nil)).to be_nil + end + + it 'returns nil for blank username value' do + expect(Account.find_local('')).to be_nil + end end describe '.find_local!' do @@ -70,6 +78,14 @@ describe AccountFinderConcern do it 'returns nil for regex style domain value' do expect(Account.find_remote('alice', 'm%')).to be_nil end + + it 'returns nil for nil username value' do + expect(Account.find_remote(nil, 'domain')).to be_nil + end + + it 'returns nil for blank username value' do + expect(Account.find_remote('', 'domain')).to be_nil + end end describe '.find_remote!' do -- GitLab From d010e270e613f6299397601289158bd2acedbe8e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 1 Jun 2017 09:29:14 -0400 Subject: [PATCH 085/295] Remove usernames and hashtags from language detection (#3503) * Add failing specs for hashtag and username extraction in language detector * Remove usernames and hashtags from text before language detection * Handle multiple instances of special case, and reduce whitespace --- app/lib/language_detector.rb | 11 +++++++-- spec/lib/language_detector_spec.rb | 38 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/lib/language_detector.rb b/app/lib/language_detector.rb index 1c22a9ccc5..0d087f8d1e 100644 --- a/app/lib/language_detector.rb +++ b/app/lib/language_detector.rb @@ -13,6 +13,10 @@ class LanguageDetector detected_language_code || default_locale.to_sym end + def prepared_text + simplified_text.strip + end + private def detected_language_code @@ -20,18 +24,21 @@ class LanguageDetector end def result - @result ||= @identifier.find_language(text_without_urls) + @result ||= @identifier.find_language(prepared_text) end def detected_language_reliable? result.reliable? end - def text_without_urls + def simplified_text text.dup.tap do |new_text| URI.extract(new_text).each do |url| new_text.gsub!(url, '') end + new_text.gsub!(Account::MENTION_RE, '') + new_text.gsub!(Tag::HASHTAG_RE, '') + new_text.gsub!(/\s+/, ' ') end end diff --git a/spec/lib/language_detector_spec.rb b/spec/lib/language_detector_spec.rb index e543edd496..ace7a326af 100644 --- a/spec/lib/language_detector_spec.rb +++ b/spec/lib/language_detector_spec.rb @@ -1,7 +1,45 @@ # frozen_string_literal: true + require 'rails_helper' describe LanguageDetector do + describe 'prepared_text' do + it 'returns unmodified string without special cases' do + string = 'just a regular string' + result = described_class.new(string).prepared_text + + expect(result).to eq string + end + + it 'collapses spacing in strings' do + string = 'The formatting in this is very odd' + + result = described_class.new(string).prepared_text + expect(result).to eq 'The formatting in this is very odd' + end + + it 'strips usernames from strings before detection' do + string = '@username Yeah, very surreal...! also @friend' + + result = described_class.new(string).prepared_text + expect(result).to eq 'Yeah, very surreal...! also' + end + + it 'strips URLs from strings before detection' do + string = 'Our website is https://example.com and also http://localhost.dev' + + result = described_class.new(string).prepared_text + expect(result).to eq 'Our website is and also' + end + + it 'strips #hashtags from strings before detection' do + string = 'Hey look at all the #animals and #fish' + + result = described_class.new(string).prepared_text + expect(result).to eq 'Hey look at all the and' + end + end + describe 'to_iso_s' do it 'detects english language for basic strings' do strings = [ -- GitLab From cb7ee4698f2a62e15da0db2a5def866615aab57e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 1 Jun 2017 11:24:30 -0400 Subject: [PATCH 086/295] Rubocop changes (#3501) * Update renamed rubocop configuration options * Remove duplicate rubocop configuration, sort options --- .rubocop.yml | 84 ++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 295787e267..7dab38792e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,22 +1,24 @@ -Rails: - Enabled: true - -Style/PerlBackrefs: - AutoCorrect: false +AllCops: + TargetRubyVersion: 2.3 + Exclude: + - 'spec/**/*' + - 'db/**/*' + - 'app/views/**/*' + - 'config/**/*' + - 'bin/*' + - 'Rakefile' + - 'node_modules/**/*' + - 'Vagrantfile' + - 'vendor/**/*' -Style/ClassAndModuleChildren: +Bundler/OrderedGems: Enabled: false -Metrics/BlockNesting: - Max: 2 - -Metrics/LineLength: - AllowURI: true - Enabled: false +Layout/AccessModifierIndentation: + EnforcedStyle: indent -Metrics/MethodLength: - CountComments: false - Max: 10 +Layout/SpaceInsideHashLiteralBraces: + EnforcedStyle: space Metrics/AbcSize: Max: 100 @@ -31,22 +33,33 @@ Metrics/ClassLength: Metrics/CyclomaticComplexity: Max: 15 +Metrics/LineLength: + AllowURI: true + Enabled: false + Metrics/MethodLength: + CountComments: false Max: 55 Metrics/ModuleLength: CountComments: false Max: 200 -Metrics/PerceivedComplexity: - Max: 10 - Metrics/ParameterLists: Max: 4 CountKeywordArgs: true -Style/AccessModifierIndentation: - EnforcedStyle: indent +Metrics/PerceivedComplexity: + Max: 10 + +Rails: + Enabled: true + +Rails/HasAndBelongsToMany: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false Style/CollectionMethods: Enabled: true @@ -62,36 +75,17 @@ Style/DoubleNegation: Style/FrozenStringLiteralComment: Enabled: true -Style/SpaceInsideHashLiteralBraces: - EnforcedStyle: space - -Style/TrailingCommaInLiteral: - EnforcedStyleForMultiline: 'comma' - -Style/RegexpLiteral: +Style/GuardClause: Enabled: false Style/Lambda: Enabled: false -Style/GuardClause: - Enabled: false - -Rails/HasAndBelongsToMany: - Enabled: false +Style/PerlBackrefs: + AutoCorrect: false -Bundler/OrderedGems: +Style/RegexpLiteral: Enabled: false -AllCops: - TargetRubyVersion: 2.3 - Exclude: - - 'spec/**/*' - - 'db/**/*' - - 'app/views/**/*' - - 'config/**/*' - - 'bin/*' - - 'Rakefile' - - 'node_modules/**/*' - - 'Vagrantfile' - - 'vendor/**/*' +Style/TrailingCommaInLiteral: + EnforcedStyleForMultiline: 'comma' -- GitLab From fda5c699c2d1165381da87ffe12ebc92e6529f47 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Fri, 2 Jun 2017 00:25:10 +0900 Subject: [PATCH 087/295] Add ESLint rule (object-curly-spacing) (#3498) --- .eslintrc.yml | 3 +++ app/javascript/mastodon/components/avatar_overlay.js | 2 +- .../compose/components/emoji_picker_dropdown.js | 10 +++++----- .../mastodon/features/getting_started/index.js | 4 ++-- .../mastodon/features/ui/components/image_loader.js | 6 +++--- .../mastodon/features/ui/components/media_modal.js | 4 ++-- .../features/ui/components/onboarding_modal.js | 2 +- .../features/ui/containers/status_list_container.js | 2 +- config/webpack/translationRunner.js | 2 +- 9 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 59218cb24d..8d1bbc43a7 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -54,6 +54,9 @@ rules: comma-dangle: - error - always-multiline + object-curly-spacing: + - error + - always react/jsx-wrap-multilines: error react/jsx-no-bind: error diff --git a/app/javascript/mastodon/components/avatar_overlay.js b/app/javascript/mastodon/components/avatar_overlay.js index a9643499d3..e41d66ab10 100644 --- a/app/javascript/mastodon/components/avatar_overlay.js +++ b/app/javascript/mastodon/components/avatar_overlay.js @@ -9,7 +9,7 @@ class AvatarOverlay extends React.PureComponent { }; render() { - const {staticSrc, overlaySrc} = this.props; + const { staticSrc, overlaySrc } = this.props; const baseStyle = { backgroundImage: `url(${staticSrc})`, diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js index fc921dfb80..ffe5a1bcdf 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js @@ -46,21 +46,21 @@ class EmojiPickerDropdown extends React.PureComponent { } onShowDropdown = () => { - this.setState({active: true}); + this.setState({ active: true }); if (!EmojiPicker) { - this.setState({loading: true}); + this.setState({ loading: true }); import(/* webpackChunkName: "emojione_picker" */ 'emojione-picker').then(TheEmojiPicker => { EmojiPicker = TheEmojiPicker.default; - this.setState({loading: false}); + this.setState({ loading: false }); }).catch(err => { // TODO: show the user an error? - this.setState({loading: false}); + this.setState({ loading: false }); }); } } onHideDropdown = () => { - this.setState({active: false}); + this.setState({ active: false }); } render () { diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index d1123878e2..f9619550cd 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -12,8 +12,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; const messages = defineMessages({ heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' }, - navigation_subheading: { id: 'column_subheading.navigation', defaultMessage: 'Navigation'}, - settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings'}, + navigation_subheading: { id: 'column_subheading.navigation', defaultMessage: 'Navigation' }, + settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' }, community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, diff --git a/app/javascript/mastodon/features/ui/components/image_loader.js b/app/javascript/mastodon/features/ui/components/image_loader.js index af2870517e..2a2cbb9bf1 100644 --- a/app/javascript/mastodon/features/ui/components/image_loader.js +++ b/app/javascript/mastodon/features/ui/components/image_loader.js @@ -22,11 +22,11 @@ class ImageLoader extends React.PureComponent { loadImage(src) { const image = new Image(); - image.onerror = () => this.setState({loading: false, error: true}); - image.onload = () => this.setState({loading: false, error: false}); + image.onerror = () => this.setState({ loading: false, error: true }); + image.onload = () => this.setState({ loading: false, error: false }); image.src = src; this.lastSrc = src; - this.setState({loading: true}); + this.setState({ loading: true }); } render() { diff --git a/app/javascript/mastodon/features/ui/components/media_modal.js b/app/javascript/mastodon/features/ui/components/media_modal.js index effa0aea3b..4f27a0f723 100644 --- a/app/javascript/mastodon/features/ui/components/media_modal.js +++ b/app/javascript/mastodon/features/ui/components/media_modal.js @@ -26,11 +26,11 @@ class MediaModal extends ImmutablePureComponent { }; handleNextClick = () => { - this.setState({ index: (this.getIndex() + 1) % this.props.media.size}); + this.setState({ index: (this.getIndex() + 1) % this.props.media.size }); } handlePrevClick = () => { - this.setState({ index: (this.getIndex() - 1) % this.props.media.size}); + this.setState({ index: (this.getIndex() - 1) % this.props.media.size }); } handleKeyUp = (e) => { diff --git a/app/javascript/mastodon/features/ui/components/onboarding_modal.js b/app/javascript/mastodon/features/ui/components/onboarding_modal.js index cc3c0cdc5c..a06338b25a 100644 --- a/app/javascript/mastodon/features/ui/components/onboarding_modal.js +++ b/app/javascript/mastodon/features/ui/components/onboarding_modal.js @@ -139,7 +139,7 @@ const PageSix = ({ admin, domain }) => {

@{admin.get('acct')} }} />
- }}/> + }}/>

); } diff --git a/app/javascript/mastodon/features/ui/containers/status_list_container.js b/app/javascript/mastodon/features/ui/containers/status_list_container.js index 14222fedd9..cbdd2d12d4 100644 --- a/app/javascript/mastodon/features/ui/containers/status_list_container.js +++ b/app/javascript/mastodon/features/ui/containers/status_list_container.js @@ -56,7 +56,7 @@ const mapDispatchToProps = (dispatch, { type, id }) => ({ onScrollToBottom: debounce(() => { dispatch(scrollTopTimeline(type, false)); dispatch(expandTimeline(type, id)); - }, 300, {leading: true}), + }, 300, { leading: true }), onScrollToTop: debounce(() => { dispatch(scrollTopTimeline(type, true)); diff --git a/config/webpack/translationRunner.js b/config/webpack/translationRunner.js index 8d2fb4893d..a546125494 100644 --- a/config/webpack/translationRunner.js +++ b/config/webpack/translationRunner.js @@ -35,7 +35,7 @@ const validateLanguages = function (languages, validators) { if (invalidLanguages.length > 0) { console.log(`\nError: Specified invalid LANGUAGES:`); - for (let {language, error} of invalidLanguages) { + for (let { language, error } of invalidLanguages) { console.error(`* ${language}: ${error}`); } console.log(`\nUse yarn "manage:translations -- --help" for usage information\n`); -- GitLab From 509b0cfafc0857538d63f4b93b26462f035d458b Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Fri, 2 Jun 2017 00:25:59 +0900 Subject: [PATCH 088/295] Add scenarios for log in (#3497) --- spec/features/log_in_spec.rb | 40 ++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/spec/features/log_in_spec.rb b/spec/features/log_in_spec.rb index 6dc3cd2f4e..ed626d880e 100644 --- a/spec/features/log_in_spec.rb +++ b/spec/features/log_in_spec.rb @@ -1,19 +1,47 @@ require "rails_helper" feature "Log in" do - given(:email) { "test@examle.com" } - given(:password) { "password" } + given(:email) { "test@examle.com" } + given(:password) { "password" } + given(:confirmed_at) { Time.now } background do - Fabricate(:user, email: email, password: password) + Fabricate(:user, email: email, password: password, confirmed_at: confirmed_at) + visit new_user_session_path end + subject { page } + scenario "A valid email and password user is able to log in" do - visit new_user_session_path fill_in "user_email", with: email fill_in "user_password", with: password - click_on "Log in" + click_on I18n.t('auth.login') + + is_expected.to have_css("div.app-holder") + end + + scenario "A invalid email and password user is not able to log in" do + fill_in "user_email", with: "invalid_email" + fill_in "user_password", with: "invalid_password" + click_on I18n.t('auth.login') + + is_expected.to have_css(".flash-message", text: failure_message("invalid")) + end + + context do + given(:confirmed_at) { nil } + + scenario "A unconfirmed user is not able to log in" do + fill_in "user_email", with: email + fill_in "user_password", with: password + click_on I18n.t('auth.login') + + is_expected.to have_css(".flash-message", text: failure_message("unconfirmed")) + end + end - expect(page).to have_css "div.app-holder" + def failure_message(message) + keys = User.authentication_keys.map { |key| User.human_attribute_name(key) } + I18n.t("devise.failure.#{message}", authentication_keys: keys.join("support.array.words_connector")) end end -- GitLab From 39ea5c0e2e9bdf2c6e3bd0797e6fb422e6117aa2 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Fri, 2 Jun 2017 00:27:15 +0900 Subject: [PATCH 089/295] Improve tests for JavaScript (#3496) - Upgrade dependencies - chai (3.5.0 -> 4.0.1) - chai-enzyme (0.6.1 -> 0.7.1) - sinon (2.2.0 -> 2.3.2) - Change extensions from .jsx to .js - Don't assign `React` to `global` - Check code format using ESLint --- package.json | 10 ++-- .../{avatar.test.jsx => avatar.test.js} | 4 +- .../{button.test.jsx => button.test.js} | 2 +- ...lay_name.test.jsx => display_name.test.js} | 8 +-- ...wn_menu.test.jsx => dropdown_menu.test.js} | 12 ++-- .../{column.test.jsx => column.test.js} | 2 +- ...tor.test.jsx => loading_indicator.test.js} | 4 +- spec/javascript/setup.js | 5 +- yarn.lock | 55 +++++++++++-------- 9 files changed, 55 insertions(+), 47 deletions(-) rename spec/javascript/components/{avatar.test.jsx => avatar.test.js} (94%) rename spec/javascript/components/{button.test.jsx => button.test.js} (98%) rename spec/javascript/components/{display_name.test.jsx => display_name.test.js} (88%) rename spec/javascript/components/{dropdown_menu.test.jsx => dropdown_menu.test.js} (96%) rename spec/javascript/components/features/ui/components/{column.test.jsx => column.test.js} (97%) rename spec/javascript/components/{loading_indicator.test.jsx => loading_indicator.test.js} (75%) diff --git a/package.json b/package.json index c686e99e7a..ee65dbea1e 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "start": "rimraf ./tmp/streaming && babel ./streaming/index.js --out-dir ./tmp && node ./tmp/streaming/index.js", "storybook": "NODE_ENV=test start-storybook -p 9001 -c storybook", "test": "npm run test:lint && npm run test:mocha", - "test:lint": "eslint -c .eslintrc.yml --ext=js app/javascript/ config/webpack/ storyboard/ streaming/", - "test:mocha": "NODE_ENV=test mocha --require ./spec/javascript/setup.js --compilers js:babel-register ./spec/javascript/components/*.test.jsx", + "test:lint": "eslint -c .eslintrc.yml --ext=js app/javascript/ config/webpack/ spec/javascript/ storyboard/ streaming/", + "test:mocha": "NODE_ENV=test mocha --require ./spec/javascript/setup.js --compilers js:babel-register ./spec/javascript/components/*.test.js", "postinstall": "npm rebuild node-sass" }, "repository": { @@ -116,8 +116,8 @@ "devDependencies": { "@kadira/storybook": "^2.35.3", "babel-eslint": "^7.2.3", - "chai": "^3.5.0", - "chai-enzyme": "^0.6.1", + "chai": "^4.0.1", + "chai-enzyme": "^0.7.1", "enzyme": "^2.8.2", "eslint": "^3.19.0", "eslint-plugin-jsx-a11y": "^4.0.0", @@ -127,7 +127,7 @@ "mocha": "^3.4.1", "react-intl-translations-manager": "^5.0.0", "react-test-renderer": "^15.5.4", - "sinon": "^2.2.0", + "sinon": "^2.3.2", "webpack-dev-server": "^2.4.5" }, "optionalDependencies": { diff --git a/spec/javascript/components/avatar.test.jsx b/spec/javascript/components/avatar.test.js similarity index 94% rename from spec/javascript/components/avatar.test.jsx rename to spec/javascript/components/avatar.test.js index f701738802..03b71dc9d9 100644 --- a/spec/javascript/components/avatar.test.jsx +++ b/spec/javascript/components/avatar.test.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { render } from 'enzyme'; - -import Avatar from '../../../app/javascript/mastodon/components/avatar' +import React from 'react'; +import Avatar from '../../../app/javascript/mastodon/components/avatar'; describe('', () => { const src = '/path/to/image.jpg'; diff --git a/spec/javascript/components/button.test.jsx b/spec/javascript/components/button.test.js similarity index 98% rename from spec/javascript/components/button.test.jsx rename to spec/javascript/components/button.test.js index e08671c013..9cf8b1eed5 100644 --- a/spec/javascript/components/button.test.jsx +++ b/spec/javascript/components/button.test.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { shallow } from 'enzyme'; import sinon from 'sinon'; - +import React from 'react'; import Button from '../../../app/javascript/mastodon/components/button'; describe('; + + moveButtons = ( +
+ + +
+ ); + } else if (multiColumn) { + pinButton = ; + + backButton = ( + + ); + } + + const collapsedContent = [ + extraContent, + ]; + + if (multiColumn) { + collapsedContent.push(moveButtons); + collapsedContent.push(pinButton); + } + + if (children || multiColumn) { + collapseButton = ; + } + + return ( +
+
+ + {title} + +
+ {backButton} + {collapseButton} +
+
+ +
+
+ {(!collapsed || animating) && collapsedContent} +
+
+
+ ); + } + +} + +export default ColumnHeader; diff --git a/app/javascript/mastodon/features/community_timeline/index.js b/app/javascript/mastodon/features/community_timeline/index.js index a8d58d3fa1..6d25811410 100644 --- a/app/javascript/mastodon/features/community_timeline/index.js +++ b/app/javascript/mastodon/features/community_timeline/index.js @@ -2,7 +2,8 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; +import Column from '../../components/column'; +import ColumnHeader from '../../components/column_header'; import { refreshTimeline, updateTimeline, @@ -10,6 +11,7 @@ import { connectTimeline, disconnectTimeline, } from '../../actions/timelines'; +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import createStream from '../../stream'; @@ -24,28 +26,47 @@ const mapStateToProps = state => ({ accessToken: state.getIn(['meta', 'access_token']), }); -let subscription; - class CommunityTimeline extends React.PureComponent { static propTypes = { dispatch: PropTypes.func.isRequired, + columnId: PropTypes.string, intl: PropTypes.object.isRequired, streamingAPIBaseURL: PropTypes.string.isRequired, accessToken: PropTypes.string.isRequired, hasUnread: PropTypes.bool, + multiColumn: PropTypes.bool, }; + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('COMMUNITY', {})); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + componentDidMount () { const { dispatch, streamingAPIBaseURL, accessToken } = this.props; dispatch(refreshTimeline('community')); - if (typeof subscription !== 'undefined') { + if (typeof this._subscription !== 'undefined') { return; } - subscription = createStream(streamingAPIBaseURL, accessToken, 'public:local', { + this._subscription = createStream(streamingAPIBaseURL, accessToken, 'public:local', { connected () { dispatch(connectTimeline('community')); @@ -74,19 +95,39 @@ class CommunityTimeline extends React.PureComponent { } componentWillUnmount () { - // if (typeof subscription !== 'undefined') { - // subscription.close(); - // subscription = null; - // } + if (typeof this._subscription !== 'undefined') { + this._subscription.close(); + this._subscription = null; + } + } + + setRef = c => { + this.column = c; } render () { - const { intl, hasUnread } = this.props; + const { intl, hasUnread, columnId, multiColumn } = this.props; + const pinned = !!columnId; return ( - - - } /> + + + + } + /> ); } diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js index f64e3b891b..62d991ed10 100644 --- a/app/javascript/mastodon/features/compose/index.js +++ b/app/javascript/mastodon/features/compose/index.js @@ -28,7 +28,7 @@ class Compose extends React.PureComponent { static propTypes = { dispatch: PropTypes.func.isRequired, - withHeader: PropTypes.bool, + multiColumn: PropTypes.bool, showSearch: PropTypes.bool, intl: PropTypes.object.isRequired, }; @@ -42,11 +42,11 @@ class Compose extends React.PureComponent { } render () { - const { withHeader, showSearch, intl } = this.props; + const { multiColumn, showSearch, intl } = this.props; let header = ''; - if (withHeader) { + if (multiColumn) { header = (
diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index f9619550cd..b7ae7743e5 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -11,6 +11,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; const messages = defineMessages({ heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, + home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' }, + notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' }, public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' }, navigation_subheading: { id: 'column_subheading.navigation', defaultMessage: 'Navigation' }, settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' }, @@ -26,6 +28,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ me: state.getIn(['accounts', state.getIn(['meta', 'me'])]), + columns: state.getIn(['settings', 'columns']), }); class GettingStarted extends ImmutablePureComponent { @@ -33,27 +36,51 @@ class GettingStarted extends ImmutablePureComponent { static propTypes = { intl: PropTypes.object.isRequired, me: ImmutablePropTypes.map.isRequired, + columns: ImmutablePropTypes.list, + multiColumn: PropTypes.bool, }; render () { - const { intl, me } = this.props; + const { intl, me, columns, multiColumn } = this.props; - let followRequests = ''; + let navItems = []; + + if (multiColumn) { + if (!columns.find(item => item.get('id') === 'HOME')) { + navItems.push(); + } + + if (!columns.find(item => item.get('id') === 'NOTIFICATIONS')) { + navItems.push(); + } + + if (!columns.find(item => item.get('id') === 'COMMUNITY')) { + navItems.push(); + } + + if (!columns.find(item => item.get('id') === 'PUBLIC')) { + navItems.push(); + } + } + + navItems = navItems.concat([ + , + ]); if (me.get('locked')) { - followRequests = ; + navItems.push(); } + navItems = navItems.concat([ + , + , + ]); + return (
- - - - {followRequests} - - + {navItems} diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js index d997634bab..7f7b3e075b 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/hashtag_timeline/index.js @@ -2,12 +2,14 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; +import Column from '../../components/column'; +import ColumnHeader from '../../components/column_header'; import { refreshTimeline, updateTimeline, deleteFromTimelines, } from '../../actions/timelines'; +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import { FormattedMessage } from 'react-intl'; import createStream from '../../stream'; @@ -22,12 +24,33 @@ class HashtagTimeline extends React.PureComponent { static propTypes = { params: PropTypes.object.isRequired, + columnId: PropTypes.string, dispatch: PropTypes.func.isRequired, streamingAPIBaseURL: PropTypes.string.isRequired, accessToken: PropTypes.string.isRequired, hasUnread: PropTypes.bool, + multiColumn: PropTypes.bool, }; + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('HASHTAG', { id: this.props.params.id })); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + _subscribe (dispatch, id) { const { streamingAPIBaseURL, accessToken } = this.props; @@ -74,13 +97,34 @@ class HashtagTimeline extends React.PureComponent { this._unsubscribe(); } + setRef = c => { + this.column = c; + } + render () { - const { id, hasUnread } = this.props.params; + const { hasUnread, columnId, multiColumn } = this.props; + const { id } = this.props.params; + const pinned = !!columnId; return ( - - - } /> + + + + } + /> ); } diff --git a/app/javascript/mastodon/features/home_timeline/components/column_settings.js b/app/javascript/mastodon/features/home_timeline/components/column_settings.js index 094053aa86..902c7a06cc 100644 --- a/app/javascript/mastodon/features/home_timeline/components/column_settings.js +++ b/app/javascript/mastodon/features/home_timeline/components/column_settings.js @@ -24,25 +24,23 @@ class ColumnSettings extends React.PureComponent { const { settings, onChange, onSave, intl } = this.props; return ( - -
- +
+ -
- } /> -
+
+ } /> +
-
- } /> -
+
+ } /> +
- + -
- -
+
+
- +
); } diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js index 8f03adb120..a0a62eaf63 100644 --- a/app/javascript/mastodon/features/home_timeline/index.js +++ b/app/javascript/mastodon/features/home_timeline/index.js @@ -2,7 +2,9 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; +import Column from '../../components/column'; +import ColumnHeader from '../../components/column_header'; +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ColumnSettingsContainer from './containers/column_settings_container'; import Link from 'react-router/lib/Link'; @@ -19,13 +21,40 @@ const mapStateToProps = state => ({ class HomeTimeline extends React.PureComponent { static propTypes = { + dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, hasUnread: PropTypes.bool, hasFollows: PropTypes.bool, + columnId: PropTypes.string, + multiColumn: PropTypes.bool, }; + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('HOME', {})); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + + setRef = c => { + this.column = c; + } + render () { - const { intl, hasUnread, hasFollows } = this.props; + const { intl, hasUnread, hasFollows, columnId, multiColumn } = this.props; + const pinned = !!columnId; let emptyMessage; @@ -36,12 +65,23 @@ class HomeTimeline extends React.PureComponent { } return ( - - + + + + diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.js b/app/javascript/mastodon/features/notifications/components/column_settings.js index 6c1720b9e6..5150a3902e 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.js +++ b/app/javascript/mastodon/features/notifications/components/column_settings.js @@ -28,41 +28,39 @@ class ColumnSettings extends React.PureComponent { const soundStr = ; return ( - -
- +
+ -
- - - -
+
+ + + +
- + -
- - - -
+
+ + + +
- + -
- - - -
+
+ + + +
- + -
- - - -
+
+ + +
- +
); } diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js index a62dcd50dd..60d8fff95e 100644 --- a/app/javascript/mastodon/features/notifications/index.js +++ b/app/javascript/mastodon/features/notifications/index.js @@ -2,8 +2,10 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import Column from '../ui/components/column'; +import Column from '../../components/column'; +import ColumnHeader from '../../components/column_header'; import { expandNotifications, clearNotifications, scrollTopNotifications } from '../../actions/notifications'; +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import NotificationContainer from './containers/notification_container'; import { ScrollContainer } from 'react-router-scroll'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; @@ -34,12 +36,14 @@ const mapStateToProps = state => ({ class Notifications extends React.PureComponent { static propTypes = { + columnId: PropTypes.string, notifications: ImmutablePropTypes.list.isRequired, dispatch: PropTypes.func.isRequired, shouldUpdateScroll: PropTypes.func, intl: PropTypes.object.isRequired, isLoading: PropTypes.bool, isUnread: PropTypes.bool, + multiColumn: PropTypes.bool, }; static defaultProps = { @@ -81,12 +85,36 @@ class Notifications extends React.PureComponent { })); } + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('NOTIFICATIONS', {})); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + setRef = (c) => { this.node = c; } + setColumnRef = c => { + this.column = c; + } + render () { - const { intl, notifications, shouldUpdateScroll, isLoading, isUnread } = this.props; + const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn } = this.props; + const pinned = !!columnId; let loadMore = ''; let scrollableArea = ''; @@ -124,10 +152,21 @@ class Notifications extends React.PureComponent { this.scrollableArea = scrollableArea; return ( - - - - + + + + + + {scrollableArea} diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js index 228ee8804e..001632004a 100644 --- a/app/javascript/mastodon/features/public_timeline/index.js +++ b/app/javascript/mastodon/features/public_timeline/index.js @@ -2,7 +2,8 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; +import Column from '../../components/column'; +import ColumnHeader from '../../components/column_header'; import { refreshTimeline, updateTimeline, @@ -10,6 +11,7 @@ import { connectTimeline, disconnectTimeline, } from '../../actions/timelines'; +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import createStream from '../../stream'; @@ -24,28 +26,47 @@ const mapStateToProps = state => ({ accessToken: state.getIn(['meta', 'access_token']), }); -let subscription; - class PublicTimeline extends React.PureComponent { static propTypes = { dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, + columnId: PropTypes.string, + multiColumn: PropTypes.bool, streamingAPIBaseURL: PropTypes.string.isRequired, accessToken: PropTypes.string.isRequired, hasUnread: PropTypes.bool, }; + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('PUBLIC', {})); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + componentDidMount () { const { dispatch, streamingAPIBaseURL, accessToken } = this.props; dispatch(refreshTimeline('public')); - if (typeof subscription !== 'undefined') { + if (typeof this._subscription !== 'undefined') { return; } - subscription = createStream(streamingAPIBaseURL, accessToken, 'public', { + this._subscription = createStream(streamingAPIBaseURL, accessToken, 'public', { connected () { dispatch(connectTimeline('public')); @@ -74,19 +95,39 @@ class PublicTimeline extends React.PureComponent { } componentWillUnmount () { - // if (typeof subscription !== 'undefined') { - // subscription.close(); - // subscription = null; - // } + if (typeof this._subscription !== 'undefined') { + this._subscription.close(); + this._subscription = null; + } + } + + setRef = c => { + this.column = c; } render () { - const { intl, hasUnread } = this.props; + const { intl, columnId, hasUnread, multiColumn } = this.props; + const pinned = !!columnId; return ( - - - } /> + + + + } + /> ); } diff --git a/app/javascript/mastodon/features/ui/components/column.js b/app/javascript/mastodon/features/ui/components/column.js index e8973f5955..fb3d35b988 100644 --- a/app/javascript/mastodon/features/ui/components/column.js +++ b/app/javascript/mastodon/features/ui/components/column.js @@ -2,34 +2,7 @@ import React from 'react'; import ColumnHeader from './column_header'; import PropTypes from 'prop-types'; import { debounce } from 'lodash'; - -const easingOutQuint = (x, t, b, c, d) => c*((t=t/d-1)*t*t*t*t + 1) + b; - -const scrollTop = (node) => { - const startTime = Date.now(); - const offset = node.scrollTop; - const targetY = -offset; - const duration = 1000; - let interrupt = false; - - const step = () => { - const elapsed = Date.now() - startTime; - const percentage = elapsed / duration; - - if (percentage > 1 || interrupt) { - return; - } - - node.scrollTop = easingOutQuint(0, elapsed, offset, targetY, duration); - requestAnimationFrame(step); - }; - - step(); - - return () => { - interrupt = true; - }; -}; +import scrollTop from '../../../scroll'; class Column extends React.PureComponent { @@ -43,9 +16,11 @@ class Column extends React.PureComponent { handleHeaderClick = () => { const scrollable = this.node.querySelector('.scrollable'); + if (!scrollable) { return; } + this._interruptScrollAnimation = scrollTop(scrollable); } diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js index ccff417efc..6ed8bc20d6 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.js +++ b/app/javascript/mastodon/features/ui/components/columns_area.js @@ -1,16 +1,51 @@ import React from 'react'; import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import HomeTimeline from '../../home_timeline'; +import Notifications from '../../notifications'; +import PublicTimeline from '../../public_timeline'; +import CommunityTimeline from '../../community_timeline'; +import HashtagTimeline from '../../hashtag_timeline'; +import Compose from '../../compose'; -class ColumnsArea extends React.PureComponent { +const componentMap = { + 'COMPOSE': Compose, + 'HOME': HomeTimeline, + 'NOTIFICATIONS': Notifications, + 'PUBLIC': PublicTimeline, + 'COMMUNITY': CommunityTimeline, + 'HASHTAG': HashtagTimeline, +}; + +class ColumnsArea extends ImmutablePureComponent { static propTypes = { + columns: ImmutablePropTypes.list.isRequired, + singleColumn: PropTypes.bool, children: PropTypes.node, }; render () { + const { columns, children, singleColumn } = this.props; + + if (singleColumn) { + return ( +
+ {children} +
+ ); + } + return (
- {this.props.children} + {columns.map(column => { + const SpecificComponent = componentMap[column.get('id')]; + const params = column.get('params', null) === null ? null : column.get('params').toJS(); + return ; + })} + + {React.Children.map(children, child => React.cloneElement(child, { multiColumn: true }))}
); } diff --git a/app/javascript/mastodon/features/ui/containers/columns_area_container.js b/app/javascript/mastodon/features/ui/containers/columns_area_container.js new file mode 100644 index 0000000000..6420f0784c --- /dev/null +++ b/app/javascript/mastodon/features/ui/containers/columns_area_container.js @@ -0,0 +1,8 @@ +import { connect } from 'react-redux'; +import ColumnsArea from '../components/columns_area'; + +const mapStateToProps = state => ({ + columns: state.getIn(['settings', 'columns']), +}); + +export default connect(mapStateToProps)(ColumnsArea); diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index af124b1ee0..9452e7fcf6 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -1,13 +1,9 @@ import React from 'react'; -import ColumnsArea from './components/columns_area'; import NotificationsContainer from './containers/notifications_container'; import PropTypes from 'prop-types'; import LoadingBarContainer from './containers/loading_bar_container'; -import HomeTimeline from '../home_timeline'; -import Compose from '../compose'; import TabsBar from './components/tabs_bar'; import ModalContainer from './containers/modal_container'; -import Notifications from '../notifications'; import { connect } from 'react-redux'; import { isMobile } from '../../is_mobile'; import { debounce } from 'lodash'; @@ -15,6 +11,7 @@ import { uploadCompose } from '../../actions/compose'; import { refreshTimeline } from '../../actions/timelines'; import { refreshNotifications } from '../../actions/notifications'; import UploadArea from './components/upload_area'; +import ColumnsAreaContainer from './containers/columns_area_container'; const noOp = () => false; @@ -119,31 +116,10 @@ class UI extends React.PureComponent { const { width, draggingOver } = this.state; const { children } = this.props; - let mountedColumns; - - if (isMobile(width)) { - mountedColumns = ( - - {children} - - ); - } else { - mountedColumns = ( - - - - -
{children}
-
- ); - } - return (
- - {mountedColumns} - + {children} diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js index ababd49839..ad70806b17 100644 --- a/app/javascript/mastodon/reducers/settings.js +++ b/app/javascript/mastodon/reducers/settings.js @@ -1,10 +1,18 @@ import { SETTING_CHANGE } from '../actions/settings'; +import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE } from '../actions/columns'; import { STORE_HYDRATE } from '../actions/store'; import Immutable from 'immutable'; +import uuid from '../uuid'; const initialState = Immutable.Map({ onboarded: false, + columns: Immutable.fromJS([ + { id: 'COMPOSE', uuid: uuid(), params: {} }, + { id: 'HOME', uuid: uuid(), params: {} }, + { id: 'NOTIFICATIONS', uuid: uuid(), params: {} }, + ]), + home: Immutable.Map({ shows: Immutable.Map({ reblog: true, @@ -40,12 +48,31 @@ const initialState = Immutable.Map({ }), }); +const moveColumn = (state, uuid, direction) => { + const columns = state.get('columns'); + const index = columns.findIndex(item => item.get('uuid') === uuid); + const newIndex = index + direction; + + let newColumns; + + newColumns = columns.splice(index, 1); + newColumns = newColumns.splice(newIndex, 0, columns.get(index)); + + return state.set('columns', newColumns); +}; + export default function settings(state = initialState, action) { switch(action.type) { case STORE_HYDRATE: return state.mergeDeep(action.state.get('settings')); case SETTING_CHANGE: return state.setIn(action.key, action.value); + case COLUMN_ADD: + return state.update('columns', list => list.push(Immutable.fromJS({ id: action.id, uuid: uuid(), params: action.params }))); + case COLUMN_REMOVE: + return state.update('columns', list => list.filterNot(item => item.get('uuid') === action.uuid)); + case COLUMN_MOVE: + return moveColumn(state, action.uuid, action.direction); default: return state; } diff --git a/app/javascript/mastodon/scroll.js b/app/javascript/mastodon/scroll.js new file mode 100644 index 0000000000..c089d37db8 --- /dev/null +++ b/app/javascript/mastodon/scroll.js @@ -0,0 +1,29 @@ +const easingOutQuint = (x, t, b, c, d) => c * ((t = t / d - 1) * t * t * t * t + 1) + b; + +const scrollTop = (node) => { + const startTime = Date.now(); + const offset = node.scrollTop; + const targetY = -offset; + const duration = 1000; + let interrupt = false; + + const step = () => { + const elapsed = Date.now() - startTime; + const percentage = elapsed / duration; + + if (percentage > 1 || interrupt) { + return; + } + + node.scrollTop = easingOutQuint(0, elapsed, offset, targetY, duration); + requestAnimationFrame(step); + }; + + step(); + + return () => { + interrupt = true; + }; +}; + +export default scrollTop; diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index a617052827..ddd7e4cedd 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -1526,6 +1526,22 @@ } } +.column-header__back-button { + background: lighten($ui-base-color, 4%); + border: 0; + font-family: inherit; + color: $ui-highlight-color; + cursor: pointer; + flex: 0 0 auto; + font-size: 16px; + padding: 15px; + z-index: 3; + + &:hover { + text-decoration: underline; + } +} + .column-back-button__icon { display: inline-block; margin-right: 5px; @@ -2030,6 +2046,89 @@ button.icon-button.active i.fa-retweet { } } +.column-header__buttons { + position: absolute; + right: 0; + top: 0; + display: flex; +} + +.column-header__button { + background: lighten($ui-base-color, 4%); + border: 0; + color: $ui-primary-color; + cursor: pointer; + font-size: 16px; + padding: 15px; + + &:hover { + color: lighten($ui-primary-color, 7%); + } + + &.active { + color: $primary-text-color; + background: lighten($ui-base-color, 8%); + + &:hover { + color: $primary-text-color; + background: lighten($ui-base-color, 8%); + } + } +} + +.column-header__collapsible { + max-height: 70vh; + overflow: hidden; + overflow-y: auto; + color: $ui-primary-color; + transition: max-height 150ms ease-in-out, opacity 300ms linear; + opacity: 1; + + & > div { + background: lighten($ui-base-color, 8%); + padding: 15px; + } + + &.collapsed { + max-height: 0; + opacity: 0.5; + } + + &.animating { + overflow-y: hidden; + } +} + +.column-header__setting-btn { + &:hover { + color: lighten($ui-primary-color, 4%); + text-decoration: underline; + } +} + +.column-header__setting-arrows { + float: right; + + .column-header__setting-btn { + padding: 0 10px; + + &:last-child { + padding-right: 0; + } + } +} + +.text-btn { + display: inline-block; + padding: 0; + font-family: inherit; + font-size: inherit; + color: inherit; + border: 0; + background: transparent; + cursor: pointer; +} + .column-header__icon { display: inline-block; margin-right: 5px; -- GitLab From b97ebaf6202debb8c24d6f726886a594f02a6d3b Mon Sep 17 00:00:00 2001 From: Mingye Wang Date: Sat, 3 Jun 2017 22:25:18 -0400 Subject: [PATCH 112/295] en.json: change about/more link text to "About this instance" (#3538) This change follows #3519, which does the same for the Chinese variants. Or should it be simply "About"? --- app/javascript/mastodon/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 6864123aec..6d94e417d8 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -87,7 +87,7 @@ "navigation_bar.edit_profile": "Edit profile", "navigation_bar.favourites": "Favourites", "navigation_bar.follow_requests": "Follow requests", - "navigation_bar.info": "Extended information", + "navigation_bar.info": "About this instance", "navigation_bar.logout": "Logout", "navigation_bar.mutes": "Muted users", "navigation_bar.preferences": "Preferences", -- GitLab From 1dfd27a028642f4a0f0dcd9b8c3620de23b317f3 Mon Sep 17 00:00:00 2001 From: unarist Date: Sun, 4 Jun 2017 21:51:06 +0900 Subject: [PATCH 113/295] Fix all icons in the column header being hilighted (#3554) --- app/javascript/styles/components.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index ddd7e4cedd..b4e980f1ae 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -2029,7 +2029,7 @@ button.icon-button.active i.fa-retweet { box-shadow: 0 1px 0 rgba($ui-highlight-color, 0.3); } - &.active .fa { + &.active .column-header__icon { color: $ui-highlight-color; text-shadow: 0 0 10px rgba($ui-highlight-color, 0.4); } -- GitLab From 9d2154c4ab9d9d6c73d80962e2d189e20b88acbb Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Sun, 4 Jun 2017 21:51:35 +0900 Subject: [PATCH 114/295] Add Japanese translations (pin) (#3551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Japanese translations (pin) * "ピン留め" is more general --- app/javascript/mastodon/locales/ar.json | 2 ++ app/javascript/mastodon/locales/bg.json | 2 ++ app/javascript/mastodon/locales/ca.json | 2 ++ app/javascript/mastodon/locales/de.json | 2 ++ .../mastodon/locales/defaultMessages.json | 25 +++++++++++++++++++ app/javascript/mastodon/locales/en.json | 2 ++ app/javascript/mastodon/locales/eo.json | 2 ++ app/javascript/mastodon/locales/es.json | 2 ++ app/javascript/mastodon/locales/fa.json | 2 ++ app/javascript/mastodon/locales/fi.json | 2 ++ app/javascript/mastodon/locales/fr.json | 2 ++ app/javascript/mastodon/locales/he.json | 2 ++ app/javascript/mastodon/locales/hr.json | 2 ++ app/javascript/mastodon/locales/hu.json | 2 ++ app/javascript/mastodon/locales/id.json | 2 ++ app/javascript/mastodon/locales/io.json | 2 ++ app/javascript/mastodon/locales/it.json | 2 ++ app/javascript/mastodon/locales/ja.json | 2 ++ app/javascript/mastodon/locales/nl.json | 2 ++ app/javascript/mastodon/locales/no.json | 2 ++ app/javascript/mastodon/locales/oc.json | 2 ++ app/javascript/mastodon/locales/pl.json | 2 ++ app/javascript/mastodon/locales/pt-BR.json | 2 ++ app/javascript/mastodon/locales/pt.json | 2 ++ app/javascript/mastodon/locales/ru.json | 2 ++ app/javascript/mastodon/locales/tr.json | 2 ++ app/javascript/mastodon/locales/uk.json | 2 ++ app/javascript/mastodon/locales/zh-CN.json | 2 ++ app/javascript/mastodon/locales/zh-HK.json | 2 ++ app/javascript/mastodon/locales/zh-TW.json | 2 ++ 30 files changed, 83 insertions(+) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 2a9d00460a..1b0b0a4642 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -27,6 +27,8 @@ "column.notifications": "الإشعارات", "column.public": "الخيط العام الموحد", "column_back_button.label": "العودة", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "التصفح", "column_subheading.settings": "الإعدادات", "compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index a43cd3dabf..11e6cf38a2 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -27,6 +27,8 @@ "column.notifications": "Известия", "column.public": "Публичен канал", "column_back_button.label": "Назад", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index acd2b72163..4b8199d171 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -27,6 +27,8 @@ "column.notifications": "Notificacions", "column.public": "Línia de temps federada", "column_back_button.label": "Enrere", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navegació", "column_subheading.settings": "Configuració", "compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index a82bee22d0..cd0dc54519 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -27,6 +27,8 @@ "column.notifications": "Mitteilungen", "column.public": "Gesamtes bekanntes Netz", "column_back_button.label": "Zurück", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 6b7e632451..37f3c24ddd 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -51,6 +51,23 @@ ], "path": "app/javascript/mastodon/components/column_back_button.json" }, + { + "descriptors": [ + { + "defaultMessage": "Unpin", + "id": "column_header.unpin" + }, + { + "defaultMessage": "Pin", + "id": "column_header.pin" + }, + { + "defaultMessage": "Back", + "id": "column_back_button.label" + } + ], + "path": "app/javascript/mastodon/components/column_header.json" + }, { "descriptors": [ { @@ -657,6 +674,14 @@ "defaultMessage": "Getting started", "id": "getting_started.heading" }, + { + "defaultMessage": "Home", + "id": "tabs_bar.home" + }, + { + "defaultMessage": "Notifications", + "id": "tabs_bar.notifications" + }, { "defaultMessage": "Federated timeline", "id": "navigation_bar.public_timeline" diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 6d94e417d8..eddb68dd73 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -27,6 +27,8 @@ "column.notifications": "Notifications", "column.public": "Federated timeline", "column_back_button.label": "Back", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 3437bd9e99..7d99a62943 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -27,6 +27,8 @@ "column.notifications": "Sciigoj", "column.public": "Fratara tempolinio", "column_back_button.label": "Reveni", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 14b007a3e0..4599ee68d5 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -27,6 +27,8 @@ "column.notifications": "Notificaciones", "column.public": "Historia federada", "column_back_button.label": "Atrás", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 33c1955f31..ea73727b5d 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -27,6 +27,8 @@ "column.notifications": "اعلان‌ها", "column.public": "نوشته‌های همه‌جا", "column_back_button.label": "بازگشت", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "گشت و گذار", "column_subheading.settings": "تنظیمات", "compose_form.lock_disclaimer": "حساب شما {locked} نیست. هر کسی می‌تواند پیگیر شما شود و نوشته‌های ویژهٔ پیگیران شما را ببیند.", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index c544c955cd..1b21d9d339 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -27,6 +27,8 @@ "column.notifications": "Ilmoitukset", "column.public": "Yleinen aikajana", "column_back_button.label": "Takaisin", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index c3e7d0a9a1..bf6e778ecf 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -27,6 +27,8 @@ "column.notifications": "Notifications", "column.public": "Fil public global", "column_back_button.label": "Retour", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Paramètres", "compose_form.lock_disclaimer": "Votre compte n'est pas {locked}. Tout le monde peut vous suivre et voir vos pouets restreints.", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 136abf3b7a..72e78293fd 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -27,6 +27,8 @@ "column.notifications": "התראות", "column.public": "בפרהסיה", "column_back_button.label": "חזרה", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "ניווט", "column_subheading.settings": "אפשרויות", "compose_form.lock_disclaimer": "חשבונך אינו {locked}. כל אחד יוכל לעקוב אחריך כדי לקרוא את הודעותיך המיועדות לעוקבים בלבד.", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 6d4b43c009..437a09e435 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -27,6 +27,8 @@ "column.notifications": "Notifikacije", "column.public": "Federalni timeline", "column_back_button.label": "Natrag", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index ebe2d41717..da75aa4650 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -27,6 +27,8 @@ "column.notifications": "Értesítések", "column.public": "Nyilvános", "column_back_button.label": "Vissza", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 45eea622b3..8626259f47 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -27,6 +27,8 @@ "column.notifications": "Notifikasi", "column.public": "Linimasa gabunggan", "column_back_button.label": "Kembali", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigasi", "column_subheading.settings": "Pengaturan", "compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index f6791d1809..02fb101e20 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -27,6 +27,8 @@ "column.notifications": "Savigi", "column.public": "Federata tempolineo", "column_back_button.label": "Retro", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index c09b705ebb..f2dc145dc0 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -27,6 +27,8 @@ "column.notifications": "Notifiche", "column.public": "Timeline federata", "column_back_button.label": "Indietro", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index bb00eefd18..f75c253960 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -27,6 +27,8 @@ "column.notifications": "通知", "column.public": "連合タイムライン", "column_back_button.label": "戻る", + "column_header.pin": "ピン留めする", + "column_header.unpin": "ピン留めを外す", "column_subheading.navigation": "ナビゲーション", "column_subheading.settings": "設定", "compose_form.lock_disclaimer": "あなたのアカウントは{locked}になっていません。誰でもあなたをフォローすることができ、フォロワー限定の投稿を見ることができます。", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index d70980be60..7b299005be 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -27,6 +27,8 @@ "column.notifications": "Meldingen", "column.public": "Globale tijdlijn", "column_back_button.label": "terug", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigatie", "column_subheading.settings": "Instellingen", "compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en toots zien die je alleen aan volgers hebt gericht.", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 5024171e14..a495e367d5 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -27,6 +27,8 @@ "column.notifications": "Varsler", "column.public": "Felles tidslinje", "column_back_button.label": "Tilbake", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigasjon", "column_subheading.settings": "Innstillinger", "compose_form.lock_disclaimer": "Din konto er ikke {locked}. Hvem som helst kan følge deg og se dine private poster.", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 578b3fa9c3..6e53be9ad6 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -27,6 +27,8 @@ "column.notifications": "Notificacions", "column.public": "Flux public global", "column_back_button.label": "Tornar", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigacion", "column_subheading.settings": "Paramètres", "compose_form.lock_disclaimer": "Vòstre compte es pas {locked}. Tot lo mond pòt vos sègre e veire los estatuts reservats als seguidors.", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index c3fa07d7be..62a5b3a284 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -27,6 +27,8 @@ "column.notifications": "Powiadomienia", "column.public": "Globalna oś czasu", "column_back_button.label": "Wróć", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Nawigacja", "column_subheading.settings": "Ustawienia", "compose_form.lock_disclaimer": "Twoje konto nie jest {locked}. Każdy, kto cię obserwuje, może wyświetlać twoje posty przeznaczone tylko dla obserwujących.", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index c5af75d9c0..fdfccf17b8 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -27,6 +27,8 @@ "column.notifications": "Notificações", "column.public": "Global", "column_back_button.label": "Voltar", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json index c5af75d9c0..fdfccf17b8 100644 --- a/app/javascript/mastodon/locales/pt.json +++ b/app/javascript/mastodon/locales/pt.json @@ -27,6 +27,8 @@ "column.notifications": "Notificações", "column.public": "Global", "column_back_button.label": "Voltar", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigation", "column_subheading.settings": "Settings", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index cd47e0b4fb..950089b521 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -27,6 +27,8 @@ "column.notifications": "Уведомления", "column.public": "Глобальная лента", "column_back_button.label": "Назад", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Навигация", "column_subheading.settings": "Настройки", "compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index ebfa95b845..46f30c9ef1 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -27,6 +27,8 @@ "column.notifications": "Bildirimler", "column.public": "Federe zaman tüneli", "column_back_button.label": "Geri", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigasyon", "column_subheading.settings": "Ayarlar", "compose_form.lock_disclaimer": "Hesabınız {locked} değil. Sadece takipçilerle paylaştığınız gönderileri görebilmek için sizi herhangi bir kullanıcı takip edebilir.", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 6e93db5ada..3fcbf09735 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -27,6 +27,8 @@ "column.notifications": "Сповіщення", "column.public": "Глобальна стрічка", "column_back_button.label": "Назад", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "Навігація", "column_subheading.settings": "Налаштування", "compose_form.lock_disclaimer": "Ваш акаунт не {locked}. Кожен може підписатися на Вас та бачити Ваші приватні пости.", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index c9df724e8c..68648f2dd3 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -27,6 +27,8 @@ "column.notifications": "通知", "column.public": "跨站公共时间轴", "column_back_button.label": "Back", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "导航", "column_subheading.settings": "设置", "compose_form.lock_disclaimer": "你的账户没 {locked}. 任何人可以通过关注你来查看只有关注者可见的嘟文.", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 23611ae97f..a9844a6259 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -27,6 +27,8 @@ "column.notifications": "通知", "column.public": "跨站時間軸", "column_back_button.label": "返回", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "瀏覽", "column_subheading.settings": "設定", "compose_form.lock_disclaimer": "你的用戶狀態為「{locked}」,任何人都能立即關注你,然後看到「只有關注者能看」的文章。", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index c1ca216424..5497becf03 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -27,6 +27,8 @@ "column.notifications": "通知", "column.public": "聯盟時間軸", "column_back_button.label": "上一頁", + "column_header.pin": "Pin", + "column_header.unpin": "Unpin", "column_subheading.navigation": "瀏覽", "column_subheading.settings": "設定", "compose_form.lock_disclaimer": "你的帳號沒有{locked}。任何人都可以關注你,看到發給關注者的貼文。", -- GitLab From f6e2309e70f7df49e30fee2820da8a3fd698be7a Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Sun, 4 Jun 2017 21:52:02 +0900 Subject: [PATCH 115/295] Fix column buttons overflow in Japanese (#3552) --- app/javascript/styles/components.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index b4e980f1ae..7f2b5cfe0c 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -1534,7 +1534,7 @@ cursor: pointer; flex: 0 0 auto; font-size: 16px; - padding: 15px; + padding: 0 15px; z-index: 3; &:hover { @@ -2050,6 +2050,7 @@ button.icon-button.active i.fa-retweet { position: absolute; right: 0; top: 0; + height: 100%; display: flex; } @@ -2059,7 +2060,7 @@ button.icon-button.active i.fa-retweet { color: $ui-primary-color; cursor: pointer; font-size: 16px; - padding: 15px; + padding: 0 15px; &:hover { color: lighten($ui-primary-color, 7%); -- GitLab From e014bf8ed01a5f6ff30d345ce056b667965d64c6 Mon Sep 17 00:00:00 2001 From: Naoki Kosaka Date: Sun, 4 Jun 2017 21:52:26 +0900 Subject: [PATCH 116/295] Fix limit_param in favourites_controller.rb (#3553) --- app/controllers/api/v1/favourites_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index 4614a0c724..a74db92af0 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -65,7 +65,7 @@ class Api::V1::FavouritesController < ApiController end def records_continue? - results.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + results.size == limit_param(DEFAULT_STATUSES_LIMIT) end def pagination_params(core_params) -- GitLab From 19084d3c6cb435ca669ea06daf29c213ebdc149c Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 21:56:10 +0900 Subject: [PATCH 117/295] Remove Targetable (#3548) --- app/models/account.rb | 1 - app/models/concerns/targetable.rb | 7 ------- 2 files changed, 8 deletions(-) delete mode 100644 app/models/concerns/targetable.rb diff --git a/app/models/account.rb b/app/models/account.rb index 4561fd0a48..5b0d2d65c6 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -47,7 +47,6 @@ class Account < ApplicationRecord include AccountInteractions include Attachmentable include Remotable - include Targetable # Local users has_one :user, inverse_of: :account diff --git a/app/models/concerns/targetable.rb b/app/models/concerns/targetable.rb deleted file mode 100644 index 506253bed9..0000000000 --- a/app/models/concerns/targetable.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Targetable - def object_type - :object - end -end -- GitLab From 00e61d6807acad2a09dfceb1b9441848ffbcbbfd Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 21:56:31 +0900 Subject: [PATCH 118/295] Spec action verification of StreamEntryFinder (#3549) --- spec/lib/stream_entry_finder_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/lib/stream_entry_finder_spec.rb b/spec/lib/stream_entry_finder_spec.rb index 88ba72b115..64e03c36af 100644 --- a/spec/lib/stream_entry_finder_spec.rb +++ b/spec/lib/stream_entry_finder_spec.rb @@ -14,6 +14,14 @@ describe StreamEntryFinder do it 'finds the stream entry' do expect(subject.stream_entry).to eq(status.stream_entry) end + + it 'raises an error if action is not :show' do + recognized = Rails.application.routes.recognize_path(url) + expect(recognized).to receive(:[]).with(:action).and_return(:create) + expect(Rails.application.routes).to receive(:recognize_path).with(url).and_return(recognized) + + expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound) + end end context 'with a stream entry url' do -- GitLab From 9475fbae78db2aad6b4d4d5ad29a7e724dc7b4bd Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 21:57:02 +0900 Subject: [PATCH 119/295] Spec Extractor (#3540) --- spec/lib/extractor_spec.rb | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 spec/lib/extractor_spec.rb diff --git a/spec/lib/extractor_spec.rb b/spec/lib/extractor_spec.rb new file mode 100644 index 0000000000..dba4bd0bbc --- /dev/null +++ b/spec/lib/extractor_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Extractor do + describe 'extract_mentions_or_lists_with_indices' do + it 'returns an empty array if the given string does not have at signs' do + text = 'a string without at signs' + extracted = Extractor.extract_mentions_or_lists_with_indices(text) + expect(extracted).to eq [] + end + + it 'does not extract mentions which ends with particular characters' do + text = '@screen_name@' + extracted = Extractor.extract_mentions_or_lists_with_indices(text) + expect(extracted).to eq [] + end + + it 'returns mentions as an array' do + text = '@screen_name' + extracted = Extractor.extract_mentions_or_lists_with_indices(text) + expect(extracted).to eq [ + { screen_name: 'screen_name', indices: [ 0, 12 ] } + ] + end + + it 'yields mentions if a block is given' do + text = '@screen_name' + Extractor.extract_mentions_or_lists_with_indices(text) do |screen_name, start_position, end_position| + expect(screen_name).to eq 'screen_name' + expect(start_position).to eq 0 + expect(end_position).to eq 12 + end + end + end + + describe 'extract_hashtags_with_indices' do + it 'returns an empty array if it does not have #' do + text = 'a string without hash sign' + extracted = Extractor.extract_hashtags_with_indices(text) + expect(extracted).to eq [] + end + + it 'does not exclude normal hash text before ://' do + text = '#hashtag://' + extracted = Extractor.extract_hashtags_with_indices(text) + expect(extracted).to eq [ { hashtag: 'hashtag', indices: [ 0, 8 ] } ] + end + + it 'excludes http://' do + text = '#hashtaghttp://' + extracted = Extractor.extract_hashtags_with_indices(text) + expect(extracted).to eq [ { hashtag: 'hashtag', indices: [ 0, 8 ] } ] + end + + it 'excludes https://' do + text = '#hashtaghttps://' + extracted = Extractor.extract_hashtags_with_indices(text) + expect(extracted).to eq [ { hashtag: 'hashtag', indices: [ 0, 8 ] } ] + end + + it 'yields hashtags if a block is given' do + text = '#hashtag' + Extractor.extract_hashtags_with_indices(text) do |hashtag, start_position, end_position| + expect(hashtag).to eq 'hashtag' + expect(start_position).to eq 0 + expect(end_position).to eq 8 + end + end + end + + describe 'extract_cashtags_with_indices' do + it 'returns []' do + text = '$cashtag' + extracted = Extractor.extract_cashtags_with_indices(text) + expect(extracted).to eq [] + end + end +end -- GitLab From c7af8cbc9081f349461634db0a1d76bc689d8dd5 Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 21:58:57 +0900 Subject: [PATCH 120/295] Remove some arguments of Formatter.instance.format and spec (#3541) * Remove some arguments of Formatter.instance.format * Improve spec for Formatter --- app/lib/formatter.rb | 7 +- spec/lib/formatter_spec.rb | 302 ++++++++++++++++++++++++------------- 2 files changed, 200 insertions(+), 109 deletions(-) diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index 43d23db963..7b89305ac5 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -9,7 +9,7 @@ class Formatter include ActionView::Helpers::TextHelper - def format(status, attribute = :text, paragraphize = true) + def format(status) if status.reblog? prepend_reblog = status.reblog.account.acct status = status.proper @@ -17,9 +17,8 @@ class Formatter prepend_reblog = false end - raw_content = status.public_send(attribute) + raw_content = status.text - return '' if raw_content.blank? return reformat(raw_content) unless status.local? linkable_accounts = status.mentions.map(&:account) @@ -28,7 +27,7 @@ class Formatter html = raw_content html = "RT @#{prepend_reblog} #{html}" if prepend_reblog html = encode_and_link_urls(html, linkable_accounts) - html = simple_format(html, {}, sanitize: false) if paragraphize + html = simple_format(html, {}, sanitize: false) html = html.delete("\n") html.html_safe # rubocop:disable Rails/OutputSafety diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb index ec61eaa43a..cc32f7fd69 100644 --- a/spec/lib/formatter_spec.rb +++ b/spec/lib/formatter_spec.rb @@ -1,193 +1,285 @@ require 'rails_helper' RSpec.describe Formatter do - let(:account) { Fabricate(:account, username: 'alice') } - let(:local_text) { 'Hello world http://google.com' } - let(:local_status) { Fabricate(:status, text: local_text, account: account) } - let(:remote_status) { Fabricate(:status, text: ' Beep boop', uri: 'beepboop', account: account) } - - let(:local_text_with_mention) { "@#{account.username} @#{account.username}@example.com #{local_text}?x=@#{account.username} #hashtag" } - - let(:local_status_with_mention) do - Fabricate( - :status, - text: local_text_with_mention, - account: account, - mentions: [Fabricate(:mention, account: account)] - ) - end + let(:local_account) { Fabricate(:account, domain: nil, username: 'alice') } + let(:remote_account) { Fabricate(:account, domain: 'remote', username: 'bob', url: 'https://remote/') } - describe '#format' do - subject { Formatter.instance.format(local_status) } + shared_examples 'encode and link URLs' do + context 'matches a stand-alone medium URL' do + let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' } - context 'with standalone status' do - it 'returns a string' do - expect(subject).to be_a String + it 'has valid URL' do + is_expected.to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"' end + end - it 'contains plain text' do - expect(subject).to match('Hello world') - end + context 'matches a stand-alone google URL' do + let(:text) { 'http://google.com' } - it 'contains a link' do - expect(subject).to match('google.com/') + it 'has valid URL' do + is_expected.to include 'href="http://google.com/"' end + end + + context 'matches a stand-alone IDN URL' do + let(:text) { 'https://nic.みんな/' } - it 'contains a mention' do - result = Formatter.instance.format(local_status_with_mention) - expect(result).to match "@#{account.username}" - expect(result).to match %r{href=\"http://google.com/\?x=@#{account.username}} - expect(result).not_to match "href=\"https://example.com/@#{account.username}" + it 'has valid URL' do + is_expected.to include 'href="https://nic.xn--q9jyb4c/"' end - it 'contains a hashtag' do - result = Formatter.instance.format(local_status_with_mention) - expect(result).to match('/tags/hashtag" class="mention hashtag" rel="tag">#hashtag') + it 'has display URL' do + is_expected.to include 'nic.みんな/' end end - context 'with cashtag' do - let(:local_text) { 'Hello world $AAPL' } + context 'matches a URL without trailing period' do + let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' } - it 'skip cashtag' do - expect(subject).to match '

Hello world $AAPL

' + it 'has valid URL' do + is_expected.to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"' end end - context 'with reblog' do - let(:local_status) { Fabricate(:status, account: account, reblog: Fabricate(:status, text: 'Hello world', account: account)) } + context 'matches a URL without closing paranthesis' do + let(:text) { '(http://google.com/)' } - it 'contains credit to original author' do - expect(subject).to include("RT @#{account.username} Hello world") + it 'has valid URL' do + is_expected.to include 'href="http://google.com/"' end end - context 'matches a stand-alone medium URL' do - let(:local_text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' } + context 'matches a URL without exclamation point' do + let(:text) { 'http://www.google.com!' } - it 'has valid url' do - expect(subject).to include('href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"') + it 'has valid URL' do + is_expected.to include 'href="http://www.google.com/"' end end - context 'matches a stand-alone google URL' do - let(:local_text) { 'http://google.com' } + context 'matches a URL without single quote' do + let(:text) { "http://www.google.com'" } - it 'has valid url' do - expect(subject).to include('href="http://google.com/"') + it 'has valid URL' do + is_expected.to include 'href="http://www.google.com/"' end end - context 'matches a stand-alone IDN URL' do - let(:local_text) { 'https://nic.みんな/' } + context 'matches a URL without angle brackets' do + let(:text) { 'http://www.google.com>' } - it 'has valid url' do - expect(subject).to include('href="https://nic.xn--q9jyb4c/"') + it 'has valid URL' do + is_expected.to include 'href="http://www.google.com/"' end + end - it 'has display url' do - expect(subject).to include('nic.みんな/') + context 'matches a URL with a query string' do + let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' } + + it 'has valid URL' do + is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"' end end - context 'matches a URL without trailing period' do - let(:local_text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' } + context 'matches a URL with parenthesis in it' do + let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' } - it 'has valid url' do - expect(subject).to include('href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"') + it 'has valid URL' do + is_expected.to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"' end end - xit 'matches a URL without closing paranthesis' do - expect(subject.match('(http://google.com/)')[0]).to eq 'http://google.com' + context 'contains HTML (script tag)' do + let(:text) { '' } + + it 'has escaped HTML' do + is_expected.to include '

<script>alert("Hello")</script>

' + end end - context 'matches a URL without exclamation point' do - let(:local_text) { 'http://www.google.com!' } + context 'contains HTML (XSS attack)' do + let(:text) { %q{} } - it 'has valid url' do - expect(subject).to include('href="http://www.google.com/"') + it 'has escaped HTML' do + is_expected.to include '

<img src="javascript:alert('XSS');">

' end end - context 'matches a URL without single quote' do - let(:local_text) { "http://www.google.com'" } + context 'contains invalid URL' do + let(:text) { 'http://www\.google\.com' } - it 'has valid url' do - expect(subject).to include('href="http://www.google.com/"') + it 'has raw URL' do + is_expected.to eq '

http://www\.google\.com

' end end - context 'matches a URL without angle brackets' do - let(:local_text) { 'http://www.google.com>' } + context 'contains a hashtag' do + let(:text) { '#hashtag' } - it 'has valid url' do - expect(subject).to include('href="http://www.google.com/"') + it 'has a link' do + is_expected.to include '/tags/hashtag" class="mention hashtag" rel="tag">#hashtag' end end + end - context 'matches a URL with a query string' do - let(:local_text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' } + describe '#format' do + subject { Formatter.instance.format(status) } - it 'has valid url' do - expect(subject).to include('href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"') + context 'with local status' do + context 'with reblog' do + let(:reblog) { Fabricate(:status, account: local_account, text: 'Hello world', uri: nil) } + let(:status) { Fabricate(:status, reblog: reblog) } + + it 'returns original status with credit to its author' do + is_expected.to include 'RT @alice Hello world' + end + end + + context 'contains plain text' do + let(:status) { Fabricate(:status, text: 'text', uri: nil) } + + it 'paragraphizes' do + is_expected.to eq '

text

' + end + end + + context 'contains line feeds' do + let(:status) { Fabricate(:status, text: "line\nfeed", uri: nil) } + + it 'removes line feeds' do + is_expected.not_to include "\n" + end + end + + context 'contains linkable mentions' do + let(:status) { Fabricate(:status, mentions: [ Fabricate(:mention, account: local_account) ], text: '@alice') } + + it 'links' do + is_expected.to include '@alice' + end + end + + context 'contains unlinkable mentions' do + let(:status) { Fabricate(:status, text: '@alice', uri: nil) } + + it 'does not link' do + is_expected.to include '@alice' + end + end + + context do + subject do + status = Fabricate(:status, text: text, uri: nil) + Formatter.instance.format(status) + end + + include_examples 'encode and link URLs' end end - context 'matches a URL with parenthesis in it' do - let(:local_text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' } + context 'with remote status' do + let(:status) { Fabricate(:status, text: 'Beep boop', uri: 'beepboop') } - it 'has valid url' do - expect(subject).to include('href="https://en.wikipedia.org/wiki/Diaspora_(software)"') + it 'reformats' do + is_expected.to eq 'Beep boop' end end + end + + describe '#reformat' do + subject { Formatter.instance.reformat(text) } - context 'contains html (script tag)' do - let(:local_text) { '' } + context 'contains plain text' do + let(:text) { 'Beep boop' } - it 'has valid url' do - expect(subject).to match '

<script>alert("Hello")</script>

' + it 'contains plain text' do + is_expected.to include 'Beep boop' end end - context 'contains html (xss attack)' do - let(:local_text) { %q{} } + context 'contains scripts' do + let(:text) { '' } - it 'has valid url' do - expect(subject).to match '

<img src="javascript:alert('XSS');">

' + it 'strips scripts' do + is_expected.to_not include '' end end + end - context 'contains invalid URL' do - let(:local_text) { 'http://www\.google\.com' } + describe '#plaintext' do + subject { Formatter.instance.plaintext(status) } + + context 'with local status' do + let(:status) { Fabricate(:status, text: '

a text by a nerd who uses an HTML tag in text

', uri: nil) } - it 'has valid url' do - expect(subject).to eq '

http://www\.google\.com

' + it 'returns raw text' do + is_expected.to eq '

a text by a nerd who uses an HTML tag in text

' end end - context 'concatenates hashtag and URL' do - let(:local_text) { '#hashtaghttps://www.google.com' } + context 'with remote status' do + let(:status) { Fabricate(:status, text: '', uri: 'beep boop') } - it 'has valid hashtag' do - expect(subject).to match('/tags/hashtag" class="mention hashtag" rel="tag">#hashtag') + it 'returns tag-stripped text' do + is_expected.to eq '' end end end - describe '#reformat' do - subject { Formatter.instance.format(remote_status) } + describe '#simplified_format' do + subject { Formatter.instance.simplified_format(account) } + + context 'with local status' do + let(:account) { Fabricate(:account, domain: nil, note: text) } + + context 'contains linkable mentions for local accounts' do + let(:text) { '@alice' } + + before { local_account } + + it 'links' do + is_expected.to eq '

@alice

' + end + end + + context 'contains linkable mentions for remote accounts' do + let(:text) { '@bob@remote' } + + before { remote_account } + + it 'links' do + is_expected.to eq '

@bob

' + end + end + + context 'contains unlinkable mentions' do + let(:text) { '@alice' } - it 'returns a string' do - expect(subject).to be_a String + it 'returns raw mention texts' do + is_expected.to eq '

@alice

' + end + end + + include_examples 'encode and link URLs' end - it 'contains plain text' do - expect(subject).to match('Beep boop') + context 'with remote status' do + let(:text) { '' } + let(:account) { Fabricate(:account, domain: 'remote', note: text) } + + it 'reformats' do + is_expected.to_not include '' + end end + end + + describe '#sanitize' do + let(:html) { '' } + + subject { Formatter.instance.sanitize(html, Sanitize::Config::MASTODON_STRICT) } - it 'does not contain scripts' do - expect(subject).to_not match('') + it 'sanitizes' do + is_expected.to eq 'alert("Hello")' end end end -- GitLab From e674608d10e3c0381d2e8172580b36eb553b5279 Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 21:59:40 +0900 Subject: [PATCH 121/295] A minor change for ProviderDiscovery and spec (#3543) * Do not default the format in ProviderDiscovery The format should be determined when discovering, as it is in the current implementation, and it is a flaw if it is not determined. * Spec ProviderDiscovery --- app/lib/provider_discovery.rb | 2 +- .../fixtures/requests/oembed_invalid_xml.html | 7 ++ spec/fixtures/requests/oembed_json.html | 7 ++ spec/fixtures/requests/oembed_json_xml.html | 8 ++ .../requests/oembed_undiscoverable.html | 5 + spec/fixtures/requests/oembed_xml.html | 7 ++ spec/lib/provider_discovery_spec.rb | 118 ++++++++++++++++++ 7 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/requests/oembed_invalid_xml.html create mode 100644 spec/fixtures/requests/oembed_json.html create mode 100644 spec/fixtures/requests/oembed_json_xml.html create mode 100644 spec/fixtures/requests/oembed_undiscoverable.html create mode 100644 spec/fixtures/requests/oembed_xml.html create mode 100644 spec/lib/provider_discovery_spec.rb diff --git a/app/lib/provider_discovery.rb b/app/lib/provider_discovery.rb index 3d0712a5ca..6d48cae2f0 100644 --- a/app/lib/provider_discovery.rb +++ b/app/lib/provider_discovery.rb @@ -31,7 +31,7 @@ class ProviderDiscovery < OEmbed::ProviderDiscovery raise OEmbed::NotFound, url end - OEmbed::Provider.new(provider_endpoint, format || OEmbed::Formatter.default) + OEmbed::Provider.new(provider_endpoint, format) end end end diff --git a/spec/fixtures/requests/oembed_invalid_xml.html b/spec/fixtures/requests/oembed_invalid_xml.html new file mode 100644 index 0000000000..405834f129 --- /dev/null +++ b/spec/fixtures/requests/oembed_invalid_xml.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/spec/fixtures/requests/oembed_json.html b/spec/fixtures/requests/oembed_json.html new file mode 100644 index 0000000000..773a4f92a2 --- /dev/null +++ b/spec/fixtures/requests/oembed_json.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/spec/fixtures/requests/oembed_json_xml.html b/spec/fixtures/requests/oembed_json_xml.html new file mode 100644 index 0000000000..b5fc9bed09 --- /dev/null +++ b/spec/fixtures/requests/oembed_json_xml.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/spec/fixtures/requests/oembed_undiscoverable.html b/spec/fixtures/requests/oembed_undiscoverable.html new file mode 100644 index 0000000000..a4acdc47a5 --- /dev/null +++ b/spec/fixtures/requests/oembed_undiscoverable.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/fixtures/requests/oembed_xml.html b/spec/fixtures/requests/oembed_xml.html new file mode 100644 index 0000000000..5d7633e713 --- /dev/null +++ b/spec/fixtures/requests/oembed_xml.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/spec/lib/provider_discovery_spec.rb b/spec/lib/provider_discovery_spec.rb new file mode 100644 index 0000000000..12e2616c9c --- /dev/null +++ b/spec/lib/provider_discovery_spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ProviderDiscovery do + describe 'discover_provider' do + context 'when status code is 200 and MIME type is text/html' do + context 'Both of JSON and XML provider are discoverable' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 200, + headers: { 'Content-Type': 'text/html' }, + body: request_fixture('oembed_json_xml.html') + ) + end + + it 'returns new OEmbed::Provider for JSON provider if :format option is set to :json' do + provider = ProviderDiscovery.discover_provider('https://host/oembed.html', format: :json) + expect(provider.endpoint).to eq 'https://host/provider.json' + expect(provider.format).to eq :json + end + + it 'returns new OEmbed::Provider for XML provider if :format option is set to :xml' do + provider = ProviderDiscovery.discover_provider('https://host/oembed.html', format: :xml) + expect(provider.endpoint).to eq 'https://host/provider.xml' + expect(provider.format).to eq :xml + end + end + + context 'JSON provider is discoverable while XML provider is not' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 200, + headers: { 'Content-Type': 'text/html' }, + body: request_fixture('oembed_json.html') + ) + end + + it 'returns new OEmbed::Provider for JSON provider' do + provider = ProviderDiscovery.discover_provider('https://host/oembed.html') + expect(provider.endpoint).to eq 'https://host/provider.json' + expect(provider.format).to eq :json + end + end + + context 'XML provider is discoverable while JSON provider is not' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 200, + headers: { 'Content-Type': 'text/html' }, + body: request_fixture('oembed_xml.html') + ) + end + + it 'returns new OEmbed::Provider for XML provider' do + provider = ProviderDiscovery.discover_provider('https://host/oembed.html') + expect(provider.endpoint).to eq 'https://host/provider.xml' + expect(provider.format).to eq :xml + end + end + + context 'Invalid XML provider is discoverable while JSON provider is not' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 200, + headers: { 'Content-Type': 'text/html' }, + body: request_fixture('oembed_invalid_xml.html') + ) + end + + it 'raises OEmbed::NotFound' do + expect { ProviderDiscovery.discover_provider('https://host/oembed.html') }.to raise_error OEmbed::NotFound + end + end + + context 'Neither of JSON and XML provider is discoverable' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 200, + headers: { 'Content-Type': 'text/html' }, + body: request_fixture('oembed_undiscoverable.html') + ) + end + + it 'raises OEmbed::NotFound' do + expect { ProviderDiscovery.discover_provider('https://host/oembed.html') }.to raise_error OEmbed::NotFound + end + end + end + + context 'when status code is not 200' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 400, + headers: { 'Content-Type': 'text/html' }, + body: request_fixture('oembed_xml.html') + ) + end + + it 'raises OEmbed::NotFound' do + expect { ProviderDiscovery.discover_provider('https://host/oembed.html') }.to raise_error OEmbed::NotFound + end + end + + context 'when MIME type is not text/html' do + before do + stub_request(:get, 'https://host/oembed.html').to_return( + status: 200, + body: request_fixture('oembed_xml.html') + ) + end + + it 'raises OEmbed::NotFound' do + expect { ProviderDiscovery.discover_provider('https://host/oembed.html') }.to raise_error OEmbed::NotFound + end + end + end +end -- GitLab From 6505a42be0f0633d1dfaedaa5d4bae399c9481e4 Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 21:59:52 +0900 Subject: [PATCH 122/295] Spec HashObject (#3544) --- spec/lib/hash_object_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 spec/lib/hash_object_spec.rb diff --git a/spec/lib/hash_object_spec.rb b/spec/lib/hash_object_spec.rb new file mode 100644 index 0000000000..ce18065209 --- /dev/null +++ b/spec/lib/hash_object_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe HashObject do + it 'has methods corresponding to hash properties' do + expect(HashObject.new(key: 'value').key).to eq 'value' + end +end -- GitLab From 02a0fd5b649ff09433e36a17f7d84e13907eca74 Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 22:00:08 +0900 Subject: [PATCH 123/295] Spec InlineRablScope (#3542) --- spec/lib/inline_rabl_scope_spec.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 spec/lib/inline_rabl_scope_spec.rb diff --git a/spec/lib/inline_rabl_scope_spec.rb b/spec/lib/inline_rabl_scope_spec.rb new file mode 100644 index 0000000000..3fff176e46 --- /dev/null +++ b/spec/lib/inline_rabl_scope_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe InlineRablScope do + describe '#current_account' do + it 'returns the given account' do + account = Fabricate(:account) + expect(InlineRablScope.new(account).current_account).to eq account + end + end + + describe '#current_user' do + it 'returns nil if the given account is nil' do + expect(InlineRablScope.new(nil).current_user).to eq nil + end + + it 'returns user of account if the given account is not nil' do + user = Fabricate(:user) + expect(InlineRablScope.new(user.account).current_user).to eq user + end + end +end -- GitLab From a84664026eef048b7a897f07f9293c44015d792d Mon Sep 17 00:00:00 2001 From: lindwurm Date: Sun, 4 Jun 2017 22:00:15 +0900 Subject: [PATCH 124/295] l10n: ja: Change about/more link text (#3539) ref: #3538 ("Extended information" -> "About this instance") and #3519 Signed-off-by: lindwurm --- app/javascript/mastodon/locales/ja.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index f75c253960..84566c50a8 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -89,7 +89,7 @@ "navigation_bar.edit_profile": "プロフィールを編集", "navigation_bar.favourites": "お気に入り", "navigation_bar.follow_requests": "フォローリクエスト", - "navigation_bar.info": "サーバー情報", + "navigation_bar.info": "このインスタンスについて", "navigation_bar.logout": "ログアウト", "navigation_bar.mutes": "ミュートしたユーザー", "navigation_bar.preferences": "ユーザー設定", -- GitLab From 7c7c18fdea52ce288a87d2455f1efc55f74af003 Mon Sep 17 00:00:00 2001 From: m4sk1n Date: Sun, 4 Jun 2017 15:18:42 +0200 Subject: [PATCH 125/295] i18n: Updated Polish translation (#3555) --- app/javascript/mastodon/locales/pl.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 62a5b3a284..7eee36763b 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -27,8 +27,8 @@ "column.notifications": "Powiadomienia", "column.public": "Globalna oś czasu", "column_back_button.label": "Wróć", - "column_header.pin": "Pin", - "column_header.unpin": "Unpin", + "column_header.pin": "Przypnij", + "column_header.unpin": "Cofnij przypięcie", "column_subheading.navigation": "Nawigacja", "column_subheading.settings": "Ustawienia", "compose_form.lock_disclaimer": "Twoje konto nie jest {locked}. Każdy, kto cię obserwuje, może wyświetlać twoje posty przeznaczone tylko dla obserwujących.", -- GitLab From e07b57852e951efebae7e2380a3691236420072d Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Sun, 4 Jun 2017 23:14:25 +0900 Subject: [PATCH 126/295] Remove some code in TagManager and spec (#3547) * Do not fall back to StreamEntry if object_type is unavailable in TagManager Since 6d6a429af8fe4bd92ed497f401676353fdc603e0, when Status, the only model with stream_entry, and StreamEntry got its own logic in uri_for and url_for, the purpose of the fallbacks to activity_type of StreamEntry became unclear. This commit removes the fallbacks. When adding another model with stream_entry in future, consider to update uri_for and url_for. * Cover TagManager more --- app/lib/tag_manager.rb | 4 - spec/lib/tag_manager_spec.rb | 221 ++++++++++++++++++++++++++++++----- 2 files changed, 193 insertions(+), 32 deletions(-) diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb index 55aed92e3a..f1a2234dc4 100644 --- a/app/lib/tag_manager.rb +++ b/app/lib/tag_manager.rb @@ -93,8 +93,6 @@ class TagManager account_url(target) when :note, :comment, :activity unique_tag(target.created_at, target.id, 'Status') - else - unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type) end end @@ -106,8 +104,6 @@ class TagManager short_account_url(target) when :note, :comment, :activity short_account_status_url(target.account, target) - else - account_stream_entry_url(target.account, target.stream_entry) end end end diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb index cbb427a8c1..1fae6bec45 100644 --- a/spec/lib/tag_manager_spec.rb +++ b/spec/lib/tag_manager_spec.rb @@ -1,23 +1,152 @@ require 'rails_helper' RSpec.describe TagManager do - let(:local_domain) { Rails.configuration.x.local_domain } + describe '#local_domain?' do + # The following comparisons MUST be case-insensitive. + + around do |example| + original_local_domain = Rails.configuration.x.local_domain + Rails.configuration.x.local_domain = 'domain' + + example.run + + Rails.configuration.x.local_domain = original_local_domain + end + + it 'returns true for nil' do + expect(TagManager.instance.local_domain?(nil)).to eq true + end + + it 'returns true if the slash-stripped string equals to local domain' do + expect(TagManager.instance.local_domain?('DoMaIn/')).to eq true + end + + it 'returns false for irrelevant string' do + expect(TagManager.instance.local_domain?('DoMaIn!')).to eq false + end + end + + describe '#web_domain?' do + # The following comparisons MUST be case-insensitive. + + around do |example| + original_web_domain = Rails.configuration.x.web_domain + Rails.configuration.x.web_domain = 'domain' + + example.run + + Rails.configuration.x.web_domain = original_web_domain + end + + it 'returns true for nil' do + expect(TagManager.instance.web_domain?(nil)).to eq true + end + + it 'returns true if the slash-stripped string equals to web domain' do + expect(TagManager.instance.web_domain?('DoMaIn/')).to eq true + end + + it 'returns false for string with irrelevant characters' do + expect(TagManager.instance.web_domain?('DoMaIn!')).to eq false + end + end + + describe '#normalize_domain' do + it 'returns nil if the given parameter is nil' do + expect(TagManager.instance.normalize_domain(nil)).to eq nil + end + + it 'returns normalized domain' do + expect(TagManager.instance.normalize_domain('DoMaIn/')).to eq 'domain' + end + end + + describe '#local_url?' do + around do |example| + original_local_domain = Rails.configuration.x.local_domain + example.run + Rails.configuration.x.local_domain = original_local_domain + end + + it 'returns true if the normalized string with port is local URL' do + Rails.configuration.x.local_domain = 'domain:42' + expect(TagManager.instance.local_url?('https://DoMaIn:42/')).to eq true + end + + it 'returns true if the normalized string without port is local URL' do + Rails.configuration.x.local_domain = 'domain' + expect(TagManager.instance.local_url?('https://DoMaIn/')).to eq true + end + + it 'returns false for string with irrelevant characters' do + Rails.configuration.x.local_domain = 'domain' + expect(TagManager.instance.local_url?('https://domainn/')).to eq false + end + end + + describe '#same_acct?' do + # The following comparisons MUST be case-insensitive. + + it 'returns true if the needle has a correct username and domain for remote user' do + expect(TagManager.instance.same_acct?('username@domain', 'UsErNaMe@DoMaIn')).to eq true + end + + it 'returns false if the needle is missing a domain for remote user' do + expect(TagManager.instance.same_acct?('username@domain', 'UsErNaMe')).to eq false + end + + it 'returns false if the needle has an incorrect domain for remote user' do + expect(TagManager.instance.same_acct?('username@domain', 'UsErNaMe@incorrect')).to eq false + end + + it 'returns false if the needle has an incorrect username for remote user' do + expect(TagManager.instance.same_acct?('username@domain', 'incorrect@DoMaIn')).to eq false + end + + it 'returns true if the needle has a correct username and domain for local user' do + expect(TagManager.instance.same_acct?('username', 'UsErNaMe@Cb6E6126.nGrOk.Io')).to eq true + end + + it 'returns true if the needle is missing a domain for local user' do + expect(TagManager.instance.same_acct?('username', 'UsErNaMe')).to eq true + end + + it 'returns false if the needle has an incorrect username for local user' do + expect(TagManager.instance.same_acct?('username', 'UsErNaM@Cb6E6126.nGrOk.Io')).to eq false + end + + it 'returns false if the needle has an incorrect domain for local user' do + expect(TagManager.instance.same_acct?('username', 'incorrect@Cb6E6126.nGrOk.Io')).to eq false + end + end describe '#unique_tag' do - it 'returns a string' do - expect(TagManager.instance.unique_tag(Time.now, 12, 'Status')).to be_a String + it 'returns a unique tag' do + expect(TagManager.instance.unique_tag(Time.utc(2000), 12, 'Status')).to eq 'tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Status' end end describe '#unique_tag_to_local_id' do it 'returns the ID part' do - expect(TagManager.instance.unique_tag_to_local_id("tag:#{local_domain};objectId=12:objectType=Status", 'Status')).to eql '12' + expect(TagManager.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Status', 'Status')).to eql '12' + end + + it 'returns nil if it is not local id' do + expect(TagManager.instance.unique_tag_to_local_id('tag:remote,2000-01-01:objectId=12:objectType=Status', 'Status')).to eq nil + end + + it 'returns nil if it is not expected type' do + expect(TagManager.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Block', 'Status')).to eq nil + end + + it 'returns nil if it does not have object ID' do + expect(TagManager.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectType=Status', 'Status')).to eq nil end end describe '#local_id?' do it 'returns true for a local ID' do - expect(TagManager.instance.local_id?("tag:#{local_domain};objectId=12:objectType=Status")).to be true + expect(TagManager.instance.local_id?('tag:cb6e6126.ngrok.io;objectId=12:objectType=Status')).to be true end it 'returns false for a foreign ID' do @@ -26,49 +155,85 @@ RSpec.describe TagManager do end describe '#uri_for' do - let(:alice) { Fabricate(:account, username: 'alice') } - let(:bob) { Fabricate(:account, username: 'bob') } - let(:status) { Fabricate(:status, text: 'Hello world', account: alice) } - subject { TagManager.instance.uri_for(target) } - context 'Account' do - let(:target) { alice } + context 'activity object' do + let(:target) { Fabricate(:status, reblog: Fabricate(:status)).stream_entry } + + before { target.update!(created_at: '2000-01-01T00:00:00Z') } + + it 'returns the unique tag for status' do + expect(target.object_type).to eq :activity + is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" + end + end + + context 'comment object' do + let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: true) } + + it 'returns the unique tag for status' do + expect(target.object_type).to eq :comment + is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" + end + end + + context 'note object' do + let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: false, thread: nil) } - it 'returns a string' do - expect(subject).to be_a String + it 'returns the unique tag for status' do + expect(target.object_type).to eq :note + is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" end end - context 'Status' do - let(:target) { status } + context 'person object' do + let(:target) { Fabricate(:account, username: 'alice') } - it 'returns a string' do - expect(subject).to be_a String + it 'returns the URL for account' do + expect(target.object_type).to eq :person + is_expected.to eq 'https://cb6e6126.ngrok.io/users/alice' end end end describe '#url_for' do - let(:alice) { Fabricate(:account, username: 'alice') } - let(:bob) { Fabricate(:account, username: 'bob') } - let(:status) { Fabricate(:status, text: 'Hello world', account: alice) } + let(:alice) { Fabricate(:account, username: 'alice') } subject { TagManager.instance.url_for(target) } - context 'Account' do - let(:target) { alice } + context 'activity object' do + let(:target) { Fabricate(:status, account: alice, reblog: Fabricate(:status)).stream_entry } + + it 'returns the unique tag for status' do + expect(target.object_type).to eq :activity + is_expected.to eq "https://cb6e6126.ngrok.io/@alice/#{target.id}" + end + end + + context 'comment object' do + let(:target) { Fabricate(:status, account: alice, reply: true) } - it 'returns a URL' do - expect(subject).to be_a String + it 'returns the unique tag for status' do + expect(target.object_type).to eq :comment + is_expected.to eq "https://cb6e6126.ngrok.io/@alice/#{target.id}" end end - context 'Status' do - let(:target) { status } + context 'note object' do + let(:target) { Fabricate(:status, account: alice, reply: false, thread: nil) } + + it 'returns the unique tag for status' do + expect(target.object_type).to eq :note + is_expected.to eq "https://cb6e6126.ngrok.io/@alice/#{target.id}" + end + end + + context 'person object' do + let(:target) { alice } - it 'returns a URL' do - expect(subject).to be_a String + it 'returns the URL for account' do + expect(target.object_type).to eq :person + is_expected.to eq 'https://cb6e6126.ngrok.io/@alice' end end end -- GitLab From b0fe58dc699fd1b2de61b54b8e884783f742c664 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Sun, 4 Jun 2017 23:26:07 +0900 Subject: [PATCH 127/295] Upgrade storybook to v3 (#3558) --- package.json | 3 +- storybook/config.js | 3 +- .../stories/autosuggest_textarea.story.js | 3 +- storybook/stories/button.story.js | 3 +- storybook/stories/character_counter.story.js | 3 +- storybook/stories/loading_indicator.story.js | 3 +- storybook/webpack.config.js | 10 +- yarn.lock | 1020 ++++++++--------- 8 files changed, 501 insertions(+), 547 deletions(-) diff --git a/package.json b/package.json index 2c853c22c2..d1d1b8f836 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,8 @@ "websocket.js": "^0.1.7" }, "devDependencies": { - "@kadira/storybook": "^2.35.3", + "@storybook/addon-actions": "^3.0.0", + "@storybook/react": "^3.0.0", "babel-eslint": "^7.2.3", "chai": "^4.0.1", "chai-enzyme": "^0.7.1", diff --git a/storybook/config.js b/storybook/config.js index 9b0f531729..1078059a76 100644 --- a/storybook/config.js +++ b/storybook/config.js @@ -1,6 +1,5 @@ -import { configure, setAddon } from '@kadira/storybook'; +import { configure } from '@storybook/react'; import React from 'react'; -import { storiesOf, action } from '@kadira/storybook'; import { addLocaleData } from 'react-intl'; import en from 'react-intl/locale-data/en'; import '../app/javascript/styles/application.scss'; diff --git a/storybook/stories/autosuggest_textarea.story.js b/storybook/stories/autosuggest_textarea.story.js index 32d0604e4c..65dfe965ca 100644 --- a/storybook/stories/autosuggest_textarea.story.js +++ b/storybook/stories/autosuggest_textarea.story.js @@ -1,6 +1,7 @@ import React from 'react'; import { List } from 'immutable'; -import { action, storiesOf } from '@kadira/storybook'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; import AutosuggestTextarea from 'mastodon/components/autosuggest_textarea'; const props = { diff --git a/storybook/stories/button.story.js b/storybook/stories/button.story.js index 3fd45cb828..628deed0a4 100644 --- a/storybook/stories/button.story.js +++ b/storybook/stories/button.story.js @@ -1,5 +1,6 @@ import React from 'react'; -import { action, storiesOf } from '@kadira/storybook'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; import Button from 'mastodon/components/button'; storiesOf('Button', module) diff --git a/storybook/stories/character_counter.story.js b/storybook/stories/character_counter.story.js index eb6eae7d87..15a401a25c 100644 --- a/storybook/stories/character_counter.story.js +++ b/storybook/stories/character_counter.story.js @@ -1,5 +1,6 @@ import React from 'react'; -import { storiesOf } from '@kadira/storybook'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; import CharacterCounter from 'mastodon/features/compose/components/character_counter'; storiesOf('CharacterCounter', module) diff --git a/storybook/stories/loading_indicator.story.js b/storybook/stories/loading_indicator.story.js index 84d722d698..3e12f61ca8 100644 --- a/storybook/stories/loading_indicator.story.js +++ b/storybook/stories/loading_indicator.story.js @@ -1,6 +1,7 @@ import React from 'react'; import { IntlProvider } from 'react-intl'; -import { storiesOf } from '@kadira/storybook'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; import en from 'mastodon/locales/en.json'; import LoadingIndicator from 'mastodon/components/loading_indicator'; diff --git a/storybook/webpack.config.js b/storybook/webpack.config.js index 8e268077d3..054889b036 100644 --- a/storybook/webpack.config.js +++ b/storybook/webpack.config.js @@ -2,7 +2,7 @@ const path = require('path'); module.exports = { module: { - loaders: [ + rules: [ { test: /\.(jpg|jpeg|png|gif|svg|eot|ttf|woff|woff2)$/i, loader: 'url-loader', @@ -14,10 +14,8 @@ module.exports = { ], }, resolve: { - modulesDirectories: [ - path.resolve(__dirname, '..', 'storybook'), - path.resolve(__dirname, '..', 'app', 'javascript'), - path.resolve(__dirname, '..', 'node_modules'), - ], + alias: { + mastodon: path.resolve(__dirname, '..', 'app', 'javascript', 'mastodon'), + }, }, }; diff --git a/yarn.lock b/yarn.lock index f6ab3861e4..3c7ecb46b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,102 +2,118 @@ # yarn lockfile v1 -"@kadira/react-split-pane@^1.4.0": - version "1.4.7" - resolved "https://registry.yarnpkg.com/@kadira/react-split-pane/-/react-split-pane-1.4.7.tgz#6d753d4a9fe62fe82056e323a6bcef7f026972b5" - -"@kadira/storybook-addon-actions@^1.0.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@kadira/storybook-addon-actions/-/storybook-addon-actions-1.1.3.tgz#e76b2d3215cdf6bba8f153a14a7302d6737fc8ac" +"@storybook/addon-actions@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.0.0.tgz#e141378eeff36cbc61d27ba4330eaadfb6cd5c8b" dependencies: + "@storybook/addons" "^3.0.0" deep-equal "^1.0.1" json-stringify-safe "^5.0.1" - react-inspector "^1.1.0" + prop-types "^15.5.8" + react-inspector "^2.0.0" -"@kadira/storybook-addon-links@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@kadira/storybook-addon-links/-/storybook-addon-links-1.0.1.tgz#566136a8020b60f82f146ef37d93b0c86de969d8" +"@storybook/addon-links@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.0.0.tgz#497ae071b9f36f150a47a5c61d0688d615faec0c" + dependencies: + "@storybook/addons" "^3.0.0" -"@kadira/storybook-addons@^1.5.0": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@kadira/storybook-addons/-/storybook-addons-1.6.1.tgz#e84923d298b38c7c1231ddebc219dfb87b2858a6" +"@storybook/addons@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.0.0.tgz#0a59b73bbea15f927ec439d7bd9e67ef3719a819" -"@kadira/storybook-channel-postmsg@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@kadira/storybook-channel-postmsg/-/storybook-channel-postmsg-2.0.1.tgz#2a9065bf0647c940b8f9a3a7342a3e12e321af72" +"@storybook/channel-postmessage@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.0.0.tgz#b70bd706bb384e40b407603f829e299e1dc23ece" dependencies: - "@kadira/storybook-channel" "^1.1.0" + "@storybook/channels" "^3.0.0" json-stringify-safe "^5.0.1" -"@kadira/storybook-channel@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@kadira/storybook-channel/-/storybook-channel-1.1.0.tgz#806d1cdf2498d11cce09871a6fd27bbb41ed3564" +"@storybook/channels@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.0.0.tgz#603a1ea4779ee3d0b86d854f0ae6f899958ba73d" -"@kadira/storybook-ui@^3.10.1": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@kadira/storybook-ui/-/storybook-ui-3.11.0.tgz#a5ccdcc479aa5e08465c58e7df493e37e4b2a14a" +"@storybook/react-fuzzy@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@storybook/react-fuzzy/-/react-fuzzy-0.4.0.tgz#2961e8a1f6c1afcce97e9e9a14d1dfe9d9061087" dependencies: - "@kadira/react-split-pane" "^1.4.0" - babel-runtime "^6.5.0" + babel-runtime "^6.23.0" + classnames "^2.2.5" + fuse.js "^3.0.1" + prop-types "^15.5.9" + +"@storybook/react@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.0.0.tgz#8e0d7118691bd09c37264000525accaf6546aa5f" + dependencies: + "@storybook/addon-actions" "^3.0.0" + "@storybook/addon-links" "^3.0.0" + "@storybook/addons" "^3.0.0" + "@storybook/channel-postmessage" "^3.0.0" + "@storybook/ui" "^3.0.0" + airbnb-js-shims "^1.1.1" + autoprefixer "^7.1.1" + babel-core "^6.24.1" + babel-loader "^7.0.0" + babel-plugin-react-docgen "^1.4.2" + babel-preset-es2015 "^6.24.1" + babel-preset-es2016 "^6.24.1" + babel-preset-react "^6.24.1" + babel-preset-react-app "^3.0.0" + babel-preset-stage-0 "^6.24.1" + babel-runtime "^6.23.0" + case-sensitive-paths-webpack-plugin "^2.0.0" + chalk "^1.1.3" + commander "^2.9.0" + common-tags "^1.4.0" + configstore "^3.1.0" + css-loader "^0.28.1" + express "^4.15.3" + file-loader "^0.11.1" + find-cache-dir "^1.0.0" + json-loader "^0.5.4" + json-stringify-safe "^5.0.1" + json5 "^0.5.1" + lodash.pick "^4.4.0" + postcss-flexbugs-fixes "^3.0.0" + postcss-loader "^2.0.5" + prop-types "^15.5.10" + qs "^6.4.0" + react-modal "^1.7.7" + redux "^3.6.0" + request "^2.81.0" + serve-favicon "^2.4.3" + shelljs "^0.7.7" + style-loader "^0.17.0" + url-loader "^0.5.8" + util-deprecate "^1.0.2" + uuid "^3.0.1" + webpack "^2.5.1" + webpack-dev-middleware "^1.10.2" + webpack-hot-middleware "^2.18.0" + +"@storybook/ui@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.0.0.tgz#64d83dd7529ebe0ffe7622d90e08bf00cd362508" + dependencies: + "@storybook/react-fuzzy" "^0.4.0" + babel-runtime "^6.23.0" deep-equal "^1.0.1" events "^1.1.1" fuzzysearch "^1.0.3" json-stringify-safe "^5.0.1" - keycode "^2.1.1" - lodash.pick "^4.2.1" + keycode "^2.1.8" + lodash.pick "^4.4.0" lodash.sortby "^4.7.0" mantra-core "^1.7.0" - podda "^1.2.1" - qs "^6.2.0" - react-fuzzy "^0.3.3" - react-inspector "^1.1.0" + podda "^1.2.2" + prop-types "^15.5.8" + qs "^6.4.0" + react-inspector "^2.0.0" react-komposer "^2.0.0" - react-modal "^1.2.1" - redux "^3.5.2" - -"@kadira/storybook@^2.35.3": - version "2.35.3" - resolved "https://registry.yarnpkg.com/@kadira/storybook/-/storybook-2.35.3.tgz#8106195e1733623baf60db6adaa678dc29285d12" - dependencies: - "@kadira/react-split-pane" "^1.4.0" - "@kadira/storybook-addon-actions" "^1.0.2" - "@kadira/storybook-addon-links" "^1.0.0" - "@kadira/storybook-addons" "^1.5.0" - "@kadira/storybook-channel-postmsg" "^2.0.1" - "@kadira/storybook-ui" "^3.10.1" - airbnb-js-shims "^1.0.1" - autoprefixer "^6.3.7" - babel-core "^6.11.4" - babel-loader "^6.2.4" - babel-plugin-react-docgen "^1.4.2" - babel-preset-react-app "^1.0.0" - babel-runtime "^6.9.2" - case-sensitive-paths-webpack-plugin "^1.1.2" - chalk "^1.1.3" - commander "^2.9.0" - common-tags "^1.3.1" - configstore "^2.0.0" - css-loader "^0.26.1" - express "^4.13.3" - file-loader "^0.9.0" - find-cache-dir "^0.1.1" - json-loader "^0.5.4" - json-stringify-safe "^5.0.1" - json5 "^0.5.0" - lodash.pick "^4.2.0" - postcss-loader "1.1.0" - qs "^6.1.0" - react-modal "^1.2.0" - redux "^3.5.2" - request "^2.74.0" - serve-favicon "^2.3.0" - shelljs "^0.7.4" - style-loader "0.13.1" - url-loader "^0.5.7" - uuid "^2.0.3" - webpack "^1.13.1" - webpack-dev-middleware "^1.6.0" - webpack-hot-middleware "^2.13.2" + react-modal "^1.7.6" + react-split-pane "^0.1.63" + redux "^3.6.0" abab@^1.0.3: version "1.0.3" @@ -132,7 +148,7 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -acorn@^3.0.0, acorn@^3.0.4: +acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" @@ -144,7 +160,7 @@ acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" -airbnb-js-shims@^1.0.1: +airbnb-js-shims@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.1.1.tgz#27224f0030f244e6570442ed1020772c1434aec2" dependencies: @@ -349,15 +365,11 @@ async-foreach@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" -async@0.2.x, async@~0.2.6: +async@0.2.x: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" -async@^0.9.0: - version "0.9.2" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" - -async@^1.3.0, async@^1.5.2: +async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -371,7 +383,7 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" -autoprefixer@^6.3.1, autoprefixer@^6.3.7: +autoprefixer@^6.3.1: version "6.7.7" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" dependencies: @@ -382,7 +394,7 @@ autoprefixer@^6.3.1, autoprefixer@^6.3.7: postcss "^5.2.16" postcss-value-parser "^3.2.3" -autoprefixer@^7.1.0: +autoprefixer@^7.1.0, autoprefixer@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.1.tgz#97bc854c7d0b979f8d6489de547a0d17fb307f6d" dependencies: @@ -436,7 +448,7 @@ babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.0" -babel-core@^6.11.4, babel-core@^6.24.1: +babel-core@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" dependencies: @@ -482,6 +494,14 @@ babel-generator@^6.24.1: source-map "^0.5.0" trim-right "^1.0.1" +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" @@ -498,7 +518,7 @@ babel-helper-builder-react-jsx@^6.24.1: babel-types "^6.24.1" esutils "^2.0.0" -babel-helper-call-delegate@^6.24.1, babel-helper-call-delegate@^6.8.0: +babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" dependencies: @@ -524,7 +544,16 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helper-function-name@^6.24.1, babel-helper-function-name@^6.8.0: +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: @@ -534,7 +563,7 @@ babel-helper-function-name@^6.24.1, babel-helper-function-name@^6.8.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helper-get-function-arity@^6.24.1, babel-helper-get-function-arity@^6.8.0: +babel-helper-get-function-arity@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" dependencies: @@ -591,7 +620,7 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-loader@7.x: +babel-loader@7.x, babel-loader@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.0.0.tgz#2e43a66bee1fff4470533d0402c8a4532fafbaf7" dependencies: @@ -599,27 +628,26 @@ babel-loader@7.x: loader-utils "^1.0.2" mkdirp "^0.5.1" -babel-loader@^6.2.4: - version "6.4.1" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" - dependencies: - find-cache-dir "^0.1.1" - loader-utils "^0.2.16" - mkdirp "^0.5.1" - object-assign "^4.0.1" - babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: babel-runtime "^6.22.0" -babel-plugin-check-es2015-constants@^6.22.0, babel-plugin-check-es2015-constants@^6.3.13: +babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: babel-runtime "^6.22.0" +babel-plugin-dynamic-import-node@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.0.2.tgz#adb5bc8f48a89311540395ae9f0cc3ed4b10bb2e" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + babel-plugin-lodash@^3.2.11: version "3.2.11" resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.2.11.tgz#21c8fdec9fe1835efaa737873e3902bdd66d5701" @@ -653,11 +681,27 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" -babel-plugin-syntax-dynamic-import@^6.18.0: +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + +babel-plugin-syntax-dynamic-import@6.18.0, babel-plugin-syntax-dynamic-import@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" @@ -665,10 +709,18 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" -babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.3.13: +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" +babel-plugin-syntax-function-bind@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" + babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" @@ -677,11 +729,19 @@ babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" -babel-plugin-syntax-trailing-function-commas@^6.13.0, babel-plugin-syntax-trailing-function-commas@^6.22.0: +babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" -babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1, babel-plugin-transform-async-to-generator@^6.8.0: +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: @@ -689,15 +749,15 @@ babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async- babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-class-properties@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.16.0.tgz#969bca24d34e401d214f36b8af5c1346859bc904" +babel-plugin-transform-class-constructor-call@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" dependencies: - babel-helper-function-name "^6.8.0" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.9.1" + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" -babel-plugin-transform-class-properties@^6.24.1: +babel-plugin-transform-class-properties@6.24.1, babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" dependencies: @@ -706,19 +766,36 @@ babel-plugin-transform-class-properties@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-arrow-functions@^6.22.0, babel-plugin-transform-es2015-arrow-functions@^6.3.13: +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-do-expressions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb" + dependencies: + babel-plugin-syntax-do-expressions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0, babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1, babel-plugin-transform-es2015-block-scoping@^6.6.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" dependencies: @@ -728,7 +805,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-types "^6.24.1" lodash "^4.2.0" -babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1, babel-plugin-transform-es2015-classes@^6.6.0: +babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: @@ -742,39 +819,33 @@ babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-cla babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1, babel-plugin-transform-es2015-computed-properties@^6.3.13: +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-destructuring@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.16.0.tgz#050fe0866f5d53b36062ee10cdf5bfe64f929627" - dependencies: - babel-runtime "^6.9.0" - -babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0, babel-plugin-transform-es2015-destructuring@^6.6.0: +babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1, babel-plugin-transform-es2015-duplicate-keys@^6.6.0: +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0, babel-plugin-transform-es2015-for-of@^6.6.0: +babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1, babel-plugin-transform-es2015-function-name@^6.3.13: +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: @@ -782,13 +853,13 @@ babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es20 babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-literals@^6.22.0, babel-plugin-transform-es2015-literals@^6.3.13: +babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1, babel-plugin-transform-es2015-modules-amd@^6.8.0: +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: @@ -796,7 +867,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.6.0: +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" dependencies: @@ -805,7 +876,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-template "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: +babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: @@ -813,7 +884,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.12.0, babel-plugin-transform-e babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: +babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: @@ -821,25 +892,14 @@ babel-plugin-transform-es2015-modules-umd@^6.12.0, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1, babel-plugin-transform-es2015-object-super@^6.3.13: +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" -babel-plugin-transform-es2015-parameters@6.17.0: - version "6.17.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.17.0.tgz#e06d30cef897f46adb4734707bbe128a0d427d58" - dependencies: - babel-helper-call-delegate "^6.8.0" - babel-helper-get-function-arity "^6.8.0" - babel-runtime "^6.9.0" - babel-template "^6.16.0" - babel-traverse "^6.16.0" - babel-types "^6.16.0" - -babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1, babel-plugin-transform-es2015-parameters@^6.6.0: +babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: @@ -850,20 +910,20 @@ babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015- babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1, babel-plugin-transform-es2015-shorthand-properties@^6.3.13: +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-spread@^6.22.0, babel-plugin-transform-es2015-spread@^6.3.13: +babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1, babel-plugin-transform-es2015-sticky-regex@^6.3.13: +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: @@ -871,19 +931,19 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es201 babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-template-literals@^6.22.0, babel-plugin-transform-es2015-template-literals@^6.6.0: +babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0, babel-plugin-transform-es2015-typeof-symbol@^6.6.0: +babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1, babel-plugin-transform-es2015-unicode-regex@^6.3.13: +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: @@ -891,7 +951,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es20 babel-runtime "^6.22.0" regexpu-core "^2.0.0" -babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1, babel-plugin-transform-exponentiation-operator@^6.8.0: +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: @@ -899,68 +959,61 @@ babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-e babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-flow-strip-types@^6.22.0, babel-plugin-transform-flow-strip-types@^6.3.13: +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" dependencies: babel-plugin-syntax-flow "^6.18.0" babel-runtime "^6.22.0" -babel-plugin-transform-object-rest-spread@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz#db441d56fffc1999052fdebe2e2f25ebd28e36a9" +babel-plugin-transform-function-bind@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz#c6fb8e96ac296a310b8cf8ea401462407ddf6a97" dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.0.0" + babel-plugin-syntax-function-bind "^6.8.0" + babel-runtime "^6.22.0" -babel-plugin-transform-object-rest-spread@^6.23.0: +babel-plugin-transform-object-rest-spread@6.23.0, babel-plugin-transform-object-rest-spread@^6.22.0, babel-plugin-transform-object-rest-spread@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921" dependencies: babel-plugin-syntax-object-rest-spread "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-react-constant-elements@6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.9.1.tgz#125b86d96cb322e2139b607fd749ad5fbb17f005" +babel-plugin-transform-react-constant-elements@6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.23.0.tgz#2f119bf4d2cdd45eb9baaae574053c604f6147dd" dependencies: - babel-runtime "^6.9.1" + babel-runtime "^6.22.0" -babel-plugin-transform-react-display-name@^6.23.0, babel-plugin-transform-react-display-name@^6.3.13: +babel-plugin-transform-react-display-name@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz#4398910c358441dc4cef18787264d0412ed36b37" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-react-jsx-self@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.11.0.tgz#605c9450c1429f97a930f7e1dfe3f0d9d0dbd0f4" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.9.0" - -babel-plugin-transform-react-jsx-self@^6.11.0, babel-plugin-transform-react-jsx-self@^6.22.0: +babel-plugin-transform-react-jsx-self@6.22.0, babel-plugin-transform-react-jsx-self@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" dependencies: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-react-jsx-source@6.9.0: - version "6.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.9.0.tgz#af684a05c2067a86e0957d4f343295ccf5dccf00" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.9.0" - -babel-plugin-transform-react-jsx-source@^6.22.0, babel-plugin-transform-react-jsx-source@^6.3.13: +babel-plugin-transform-react-jsx-source@6.22.0, babel-plugin-transform-react-jsx-source@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" dependencies: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-react-jsx@^6.24.1, babel-plugin-transform-react-jsx@^6.3.13: +babel-plugin-transform-react-jsx@6.24.1, babel-plugin-transform-react-jsx@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" dependencies: @@ -974,27 +1027,13 @@ babel-plugin-transform-react-remove-prop-types@^0.4.5: dependencies: babel-traverse "^6.24.1" -babel-plugin-transform-regenerator@6.16.1: - version "6.16.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz#a75de6b048a14154aae14b0122756c5bed392f59" - dependencies: - babel-runtime "^6.9.0" - babel-types "^6.16.0" - private "~0.1.5" - -babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1, babel-plugin-transform-regenerator@^6.6.0: +babel-plugin-transform-regenerator@6.24.1, babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" dependencies: regenerator-transform "0.9.11" -babel-plugin-transform-runtime@6.15.0: - version "6.15.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz#3d75b4d949ad81af157570273846fb59aeb0d57c" - dependencies: - babel-runtime "^6.9.0" - -babel-plugin-transform-runtime@^6.23.0: +babel-plugin-transform-runtime@6.23.0, babel-plugin-transform-runtime@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee" dependencies: @@ -1015,38 +1054,39 @@ babel-polyfill@^6.23.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-preset-env@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-0.0.6.tgz#cda63a020069098fad12272a7a447a7c5bafb3c8" - dependencies: - babel-plugin-check-es2015-constants "^6.3.13" - babel-plugin-syntax-trailing-function-commas "^6.13.0" - babel-plugin-transform-async-to-generator "^6.8.0" - babel-plugin-transform-es2015-arrow-functions "^6.3.13" - babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" - babel-plugin-transform-es2015-block-scoping "^6.6.0" - babel-plugin-transform-es2015-classes "^6.6.0" - babel-plugin-transform-es2015-computed-properties "^6.3.13" - babel-plugin-transform-es2015-destructuring "^6.6.0" - babel-plugin-transform-es2015-duplicate-keys "^6.6.0" - babel-plugin-transform-es2015-for-of "^6.6.0" - babel-plugin-transform-es2015-function-name "^6.3.13" - babel-plugin-transform-es2015-literals "^6.3.13" - babel-plugin-transform-es2015-modules-amd "^6.8.0" - babel-plugin-transform-es2015-modules-commonjs "^6.6.0" - babel-plugin-transform-es2015-modules-systemjs "^6.12.0" - babel-plugin-transform-es2015-modules-umd "^6.12.0" - babel-plugin-transform-es2015-object-super "^6.3.13" - babel-plugin-transform-es2015-parameters "^6.6.0" - babel-plugin-transform-es2015-shorthand-properties "^6.3.13" - babel-plugin-transform-es2015-spread "^6.3.13" - babel-plugin-transform-es2015-sticky-regex "^6.3.13" - babel-plugin-transform-es2015-template-literals "^6.6.0" - babel-plugin-transform-es2015-typeof-symbol "^6.6.0" - babel-plugin-transform-es2015-unicode-regex "^6.3.13" - babel-plugin-transform-exponentiation-operator "^6.8.0" - babel-plugin-transform-regenerator "^6.6.0" +babel-preset-env@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" browserslist "^1.4.0" + invariant "^2.2.2" babel-preset-env@^1.4.0: version "1.5.1" @@ -1083,7 +1123,7 @@ babel-preset-env@^1.4.0: invariant "^2.2.2" semver "^5.3.0" -babel-preset-es2015@^6.16.0: +babel-preset-es2015@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" dependencies: @@ -1112,64 +1152,36 @@ babel-preset-es2015@^6.16.0: babel-plugin-transform-es2015-unicode-regex "^6.24.1" babel-plugin-transform-regenerator "^6.24.1" -babel-preset-es2016@^6.16.0: +babel-preset-es2016@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.24.1.tgz#f900bf93e2ebc0d276df9b8ab59724ebfd959f8b" dependencies: babel-plugin-transform-exponentiation-operator "^6.24.1" -babel-preset-es2017@^6.16.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.24.1.tgz#597beadfb9f7f208bcfd8a12e9b2b29b8b2f14d1" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-preset-flow@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" dependencies: babel-plugin-transform-flow-strip-types "^6.22.0" -babel-preset-latest@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-preset-latest/-/babel-preset-latest-6.16.0.tgz#5b87e19e250bb1213f13af4ec9dc7a51d53f388d" - dependencies: - babel-preset-es2015 "^6.16.0" - babel-preset-es2016 "^6.16.0" - babel-preset-es2017 "^6.16.0" - -babel-preset-react-app@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-1.0.0.tgz#e7613500859d96f177ba7a38a3ed0a923ee50da8" - dependencies: - babel-plugin-transform-class-properties "6.16.0" - babel-plugin-transform-es2015-destructuring "6.16.0" - babel-plugin-transform-es2015-parameters "6.17.0" - babel-plugin-transform-object-rest-spread "6.16.0" - babel-plugin-transform-react-constant-elements "6.9.1" - babel-plugin-transform-react-jsx-self "6.11.0" - babel-plugin-transform-react-jsx-source "6.9.0" - babel-plugin-transform-regenerator "6.16.1" - babel-plugin-transform-runtime "6.15.0" - babel-preset-env "0.0.6" - babel-preset-latest "6.16.0" - babel-preset-react "6.16.0" - babel-runtime "6.11.6" - -babel-preset-react@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.16.0.tgz#aa117d60de0928607e343c4828906e4661824316" - dependencies: - babel-plugin-syntax-flow "^6.3.13" - babel-plugin-syntax-jsx "^6.3.13" - babel-plugin-transform-flow-strip-types "^6.3.13" - babel-plugin-transform-react-display-name "^6.3.13" - babel-plugin-transform-react-jsx "^6.3.13" - babel-plugin-transform-react-jsx-self "^6.11.0" - babel-plugin-transform-react-jsx-source "^6.3.13" - -babel-preset-react@^6.24.1: +babel-preset-react-app@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-3.0.0.tgz#f4505092f8bba0f0147c764dc72055fe46ac1416" + dependencies: + babel-plugin-dynamic-import-node "1.0.2" + babel-plugin-syntax-dynamic-import "6.18.0" + babel-plugin-transform-class-properties "6.24.1" + babel-plugin-transform-object-rest-spread "6.23.0" + babel-plugin-transform-react-constant-elements "6.23.0" + babel-plugin-transform-react-jsx "6.24.1" + babel-plugin-transform-react-jsx-self "6.22.0" + babel-plugin-transform-react-jsx-source "6.22.0" + babel-plugin-transform-regenerator "6.24.1" + babel-plugin-transform-runtime "6.23.0" + babel-preset-env "1.4.0" + babel-preset-react "6.24.1" + +babel-preset-react@6.24.1, babel-preset-react@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" dependencies: @@ -1180,6 +1192,41 @@ babel-preset-react@^6.24.1: babel-plugin-transform-react-jsx-source "^6.22.0" babel-preset-flow "^6.23.0" +babel-preset-stage-0@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz#5642d15042f91384d7e5af8bc88b1db95b039e6a" + dependencies: + babel-plugin-transform-do-expressions "^6.22.0" + babel-plugin-transform-function-bind "^6.22.0" + babel-preset-stage-1 "^6.24.1" + +babel-preset-stage-1@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" + dependencies: + babel-plugin-transform-class-constructor-call "^6.24.1" + babel-plugin-transform-export-extensions "^6.22.0" + babel-preset-stage-2 "^6.24.1" + +babel-preset-stage-2@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + babel-register@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" @@ -1192,21 +1239,14 @@ babel-register@^6.24.1: mkdirp "^0.5.1" source-map-support "^0.4.2" -babel-runtime@6.11.6: - version "6.11.6" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.9.5" - -babel-runtime@6.x.x, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.5.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1, babel-runtime@^6.9.2: +babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.5.0, babel-runtime@^6.9.2: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.16.0, babel-template@^6.24.1: +babel-template@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" dependencies: @@ -1216,7 +1256,7 @@ babel-template@^6.16.0, babel-template@^6.24.1: babylon "^6.11.0" lodash "^4.2.0" -babel-traverse@^6.16.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1: +babel-traverse@^6.23.1, babel-traverse@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" dependencies: @@ -1307,6 +1347,10 @@ boom@2.x.x: dependencies: hoek "2.x.x" +bowser@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.0.tgz#169de4018711f994242bff9a8009e77a1f35e003" + brace-expansion@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" @@ -1330,12 +1374,6 @@ browser-stdout@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" -browserify-aes@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-0.4.0.tgz#067149b668df31c4b58533e02d01e806d8608e2c" - dependencies: - inherits "^2.0.1" - browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" @@ -1413,7 +1451,7 @@ buffer-xor@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" -buffer@^4.3.0, buffer@^4.9.0: +buffer@^4.3.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: @@ -1479,9 +1517,9 @@ caniuse-lite@^1.0.30000670: version "1.0.30000671" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000671.tgz#c206c2f1a1feb34de46064407c4356818389bf1e" -case-sensitive-paths-webpack-plugin@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-1.1.4.tgz#8aaedd5699a86cac2b34cf40d9b4145758978472" +case-sensitive-paths-webpack-plugin@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz#3d29ced8c1f124bf6f53846fb3f5894731fdc909" caseless@~0.12.0: version "0.12.0" @@ -1547,7 +1585,7 @@ cheerio@^0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" -chokidar@^1.0.0, chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1: +chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -1688,7 +1726,7 @@ commander@2.9.0, commander@^2.8.1, commander@^2.9.0: dependencies: graceful-readlink ">= 1.0.0" -common-tags@^1.3.1: +common-tags@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" dependencies: @@ -1740,19 +1778,16 @@ concat-stream@^1.4.7, concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" -configstore@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" +configstore@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.0.tgz#45df907073e26dfa1cf4b2d52f5b60545eaa11d1" dependencies: - dot-prop "^3.0.0" + dot-prop "^4.1.0" graceful-fs "^4.1.2" - mkdirp "^0.5.0" - object-assign "^4.0.1" - os-tmpdir "^1.0.0" - osenv "^0.1.0" - uuid "^2.0.1" - write-file-atomic "^1.1.2" - xdg-basedir "^2.0.0" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" connect-history-api-fallback@^1.3.0: version "1.3.0" @@ -1868,15 +1903,6 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" -crypto-browserify@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c" - dependencies: - browserify-aes "0.4.0" - pbkdf2-compat "2.0.1" - ripemd160 "0.2.0" - sha.js "2.2.6" - crypto-browserify@^3.11.0: version "3.11.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522" @@ -1892,6 +1918,10 @@ crypto-browserify@^3.11.0: public-encrypt "^4.0.0" randombytes "^2.0.0" +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + css-color-function@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.0.tgz#72c767baf978f01b8a8a94f42f17ba5d22a776fc" @@ -1905,22 +1935,11 @@ css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" -css-loader@^0.26.1: - version "0.26.4" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.26.4.tgz#b61e9e30db94303e6ffc892f10ecd09ad025a1fd" +css-in-js-utils@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz#9ac7e02f763cf85d94017666565ed68a5b5f3215" dependencies: - babel-code-frame "^6.11.0" - css-selector-tokenizer "^0.7.0" - cssnano ">=2.6.1 <4" - loader-utils "^1.0.2" - lodash.camelcase "^4.3.0" - object-assign "^4.0.1" - postcss "^5.0.6" - postcss-modules-extract-imports "^1.0.0" - postcss-modules-local-by-default "^1.0.1" - postcss-modules-scope "^1.0.0" - postcss-modules-values "^1.1.0" - source-list-map "^0.1.7" + hyphenate-style-name "^1.0.2" css-loader@^0.28.1: version "0.28.2" @@ -2223,9 +2242,9 @@ domutils@1.5.1, domutils@^1.5.1: dom-serializer "0" domelementtype "1" -dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" +dot-prop@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.1.1.tgz#a8493f0b7b5eeec82525b5c7587fa7de7ca859c1" dependencies: is-obj "^1.0.0" @@ -2322,14 +2341,6 @@ enhanced-resolve@^3.0.0: object-assign "^4.0.1" tapable "^0.2.5" -enhanced-resolve@~0.9.0: - version "0.9.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.2.0" - tapable "^0.1.8" - entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" @@ -2622,7 +2633,7 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -express@^4.13.3, express@^4.15.2: +express@^4.13.3, express@^4.15.2, express@^4.15.3: version "4.15.3" resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" dependencies: @@ -2730,12 +2741,6 @@ file-loader@^0.11.1: dependencies: loader-utils "^1.0.2" -file-loader@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42" - dependencies: - loader-utils "~0.2.5" - filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -2774,6 +2779,14 @@ find-cache-dir@^0.1.1: mkdirp "^0.5.1" pkg-dir "^1.0.0" +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -2781,6 +2794,12 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + flat-cache@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" @@ -2921,9 +2940,9 @@ function.prototype.name@^1.0.0: function-bind "^1.1.0" is-callable "^1.1.2" -fuse.js@^2.2.0: - version "2.7.4" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9" +fuse.js@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.0.4.tgz#cd4e2ec63ac324e28f5d17fcc3d01584379d3717" fuzzysearch@^1.0.3: version "1.0.3" @@ -3268,6 +3287,10 @@ https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" +hyphenate-style-name@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" + iconv-lite@0.4.13, iconv-lite@~0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" @@ -3329,6 +3352,13 @@ ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" +inline-style-prefixer@^3.0.2: + version "3.0.5" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.5.tgz#0092881b3a2eadf1bd619dc43726557316f76042" + dependencies: + bowser "^1.6.0" + css-in-js-utils "^1.0.3" + inquirer@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" @@ -3347,10 +3377,6 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -interpret@^0.6.4: - version "0.6.6" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" - interpret@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" @@ -3437,7 +3463,7 @@ is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" -is-dom@^1.0.5: +is-dom@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d" @@ -3748,7 +3774,7 @@ jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4: version "1.4.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" -keycode@^2.1.1: +keycode@^2.1.8: version "2.1.9" resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" @@ -3805,7 +3831,7 @@ loader-runner@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" -loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.7, loader-utils@~0.2.5: +loader-utils@^0.2.16: version "0.2.17" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" dependencies: @@ -3822,6 +3848,13 @@ loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.x: emojis-list "^2.0.0" json5 "^0.5.0" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + lodash-es@^4.2.0, lodash-es@^4.2.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" @@ -3925,7 +3958,7 @@ lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" -lodash.pick@^4.2.0, lodash.pick@^4.2.1, lodash.pick@^4.4.0: +lodash.pick@^4.2.1, lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -3993,6 +4026,12 @@ macaddress@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" +make-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + dependencies: + pify "^2.3.0" + mantra-core@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/mantra-core/-/mantra-core-1.7.0.tgz#a8c83e8cee83ef6a7383131519fe8031ad546386" @@ -4032,10 +4071,6 @@ media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" -memory-fs@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" - memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -4043,13 +4078,6 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" -memory-fs@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - meow@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -4126,7 +4154,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimist@0.0.8, minimist@~0.0.1: +minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -4204,8 +4232,8 @@ negotiator@0.6.1: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-dir@^0.1.10: - version "0.1.16" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.16.tgz#d2ef583aa50b90d93db8cdd26fcea58353957fe4" + version "0.1.17" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" dependencies: minimatch "^3.0.2" @@ -4234,34 +4262,6 @@ node-gyp@^3.3.1: tar "^2.0.0" which "1" -node-libs-browser@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b" - dependencies: - assert "^1.1.1" - browserify-zlib "^0.1.4" - buffer "^4.9.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "3.3.0" - domain-browser "^1.1.1" - events "^1.0.0" - https-browserify "0.0.1" - os-browserify "^0.2.0" - path-browserify "0.0.0" - process "^0.11.0" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.0.5" - stream-browserify "^2.0.1" - stream-http "^2.3.1" - string_decoder "^0.10.25" - timers-browserify "^2.0.2" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" - node-libs-browser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" @@ -4499,13 +4499,6 @@ opn@4.0.2: object-assign "^4.0.1" pinkie-promise "^2.0.0" -optimist@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -4541,7 +4534,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@0, osenv@^0.1.0, osenv@^0.1.4: +osenv@0, osenv@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: @@ -4556,6 +4549,16 @@ output-file-sync@^1.1.0: mkdirp "^0.5.1" object-assign "^4.1.0" +p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + packet-reader@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.3.1.tgz#cd62e60af8d7fea8a705ec4ff990871c46871f27" @@ -4611,6 +4614,10 @@ path-exists@^2.0.0: dependencies: pinkie-promise "^2.0.0" +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -4645,10 +4652,6 @@ pathval@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" -pbkdf2-compat@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" - pbkdf2@^3.0.3: version "3.0.12" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2" @@ -4736,6 +4739,12 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" @@ -4744,7 +4753,7 @@ pn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" -podda@^1.2.1: +podda@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/podda/-/podda-1.2.2.tgz#15b0edbd334ade145813343f5ecf9c10a71cf500" dependencies: @@ -4868,7 +4877,13 @@ postcss-filter-plugins@^2.0.0: postcss "^5.0.4" uniqid "^4.0.0" -postcss-load-config@^1.0.0, postcss-load-config@^1.x: +postcss-flexbugs-fixes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-3.0.0.tgz#7b31cb6c27d0417a35a67914c295f83c403c7ed4" + dependencies: + postcss "^6.0.1" + +postcss-load-config@^1.x: version "1.2.0" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a" dependencies: @@ -4891,15 +4906,6 @@ postcss-load-plugins@^2.3.0: cosmiconfig "^2.1.1" object-assign "^4.1.0" -postcss-loader@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-1.1.0.tgz#4eb0bcbfc710b8b11406f3ea6650aaaa6e51b84f" - dependencies: - loader-utils "^0.2.16" - object-assign "^4.1.0" - postcss "^5.2.5" - postcss-load-config "^1.0.0" - postcss-loader@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.0.5.tgz#c19d3e8b83eb1ac316f5621ef4c0ef5b3d1b8b3a" @@ -5171,7 +5177,7 @@ postcss-zindex@^2.0.1: postcss "^5.0.4" uniqs "^2.0.0" -postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16, postcss@^5.2.17, postcss@^5.2.5, postcss@^5.2.6: +postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16, postcss@^5.2.17, postcss@^5.2.6: version "5.2.17" resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.17.tgz#cf4f597b864d65c8a492b2eabe9d706c879c388b" dependencies: @@ -5271,7 +5277,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7: +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@~15.5.7: version "15.5.10" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" dependencies: @@ -5319,7 +5325,7 @@ q@^1.1.2: version "1.5.0" resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@6.4.0, qs@^6.1.0, qs@^6.2.0, qs@~6.4.0: +qs@6.4.0, qs@^6.4.0, qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -5426,14 +5432,6 @@ react-element-to-jsx-string@^5.0.0: stringify-object "2.4.0" traverse "^0.6.6" -react-fuzzy@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/react-fuzzy/-/react-fuzzy-0.3.3.tgz#9f6775393cd03bbd3c977651771abe16c8b29a81" - dependencies: - babel-runtime "^6.5.0" - classnames "^2.2.3" - fuse.js "^2.2.0" - react-immutable-proptypes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz#023d6f39bb15c97c071e9e60d00d136eac5fa0b4" @@ -5446,12 +5444,12 @@ react-immutable-pure-component@^0.0.4: react "^15.4.2" react-dom "^15.4.2" -react-inspector@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-1.1.2.tgz#192bc54f2be44f9fa0f29f183386f7f6e380f5ec" +react-inspector@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-2.0.0.tgz#c945932f2c2bf2fab7873c6e07d83881404b9313" dependencies: - babel-runtime "^6.9.2" - is-dom "^1.0.5" + babel-runtime "^6.23.0" + is-dom "^1.0.9" react-intl-translations-manager@^5.0.0: version "5.0.0" @@ -5491,7 +5489,7 @@ react-komposer@^2.0.0: react-stubber "^1.0.0" shallowequal "^0.2.2" -react-modal@^1.2.0, react-modal@^1.2.1: +react-modal@^1.7.6, react-modal@^1.7.7: version "1.7.7" resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-1.7.7.tgz#70205f51c58708c487aff681ba3fed7946e391d9" dependencies: @@ -5567,12 +5565,26 @@ react-simple-dropdown@^3.0.0: classnames "^2.1.2" prop-types "^15.5.8" +react-split-pane@^0.1.63: + version "0.1.63" + resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.63.tgz#fadb3960cc659911dd05ffbc88acee4be9f53583" + dependencies: + inline-style-prefixer "^3.0.2" + prop-types "^15.5.8" + react-style-proptype "^3.0.0" + react-stubber@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-stubber/-/react-stubber-1.0.0.tgz#41ee2cac72d4d4fd70a63896da98e13739b84628" dependencies: babel-runtime "^6.5.0" +react-style-proptype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-style-proptype/-/react-style-proptype-3.0.0.tgz#89e0b646f266c656abb0f0dd8202dbd5036c31e6" + dependencies: + prop-types "^15.5.4" + react-test-renderer@^15.5.4: version "15.5.4" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.5.4.tgz#d4ebb23f613d685ea8f5390109c2d20fbf7c83bc" @@ -5721,7 +5733,7 @@ redux-thunk@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" -redux@^3.5.2, redux@^3.6.0: +redux@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d" dependencies: @@ -5738,10 +5750,6 @@ regenerator-runtime@^0.10.0: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" -regenerator-runtime@^0.9.5: - version "0.9.6" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" - regenerator-transform@0.9.11: version "0.9.11" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" @@ -5815,7 +5823,7 @@ request-promise-native@^1.0.3: stealthy-require "^1.1.0" tough-cookie ">=2.3.0" -request@2, request@^2.74.0, request@^2.79.0, request@^2.81.0: +request@2, request@^2.79.0, request@^2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -5906,10 +5914,6 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: dependencies: glob "^7.0.5" -ripemd160@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" - ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" @@ -6012,7 +6016,7 @@ send@0.15.3: range-parser "~1.2.0" statuses "~1.3.1" -serve-favicon@^2.3.0: +serve-favicon@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.3.tgz#5986b17b0502642b641c21f818b1acce32025d23" dependencies: @@ -6063,10 +6067,6 @@ setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" -sha.js@2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" - sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.8" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" @@ -6088,7 +6088,7 @@ shallowequal@0.2.x, shallowequal@^0.2.2: dependencies: lodash.keys "^3.1.2" -shelljs@^0.7.4, shelljs@^0.7.5: +shelljs@^0.7.5, shelljs@^0.7.7: version "0.7.7" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" dependencies: @@ -6175,7 +6175,7 @@ source-map-support@^0.4.2: dependencies: source-map "^0.5.6" -source-map@^0.4.2, source-map@~0.4.1: +source-map@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: @@ -6378,18 +6378,18 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" -style-loader@0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.1.tgz#468280efbc0473023cd3a6cd56e33b5a1d7fc3a9" - dependencies: - loader-utils "^0.2.7" - style-loader@^0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.16.1.tgz#50e325258d4e78421dd9680636b41e8661595d10" dependencies: loader-utils "^1.0.2" +style-loader@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.17.0.tgz#e8254bccdb7af74bd58274e36107b4d5ab4df310" + dependencies: + loader-utils "^1.0.2" + sugarss@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.0.tgz#65e51b3958432fb70d5451a68bb33e32d0cf1ef7" @@ -6443,10 +6443,6 @@ table@^3.7.8: slice-ansi "0.0.4" string-width "^2.0.0" -tapable@^0.1.8, tapable@~0.1.8: - version "0.1.10" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" - tapable@^0.2.5, tapable@~0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d" @@ -6598,15 +6594,6 @@ uglify-js@^2.8.27: optionalDependencies: uglify-to-browserify "~1.0.0" -uglify-js@~2.7.3: - version "2.7.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" - dependencies: - async "~0.2.6" - source-map "~0.5.1" - uglify-to-browserify "~1.0.0" - yargs "~3.10.0" - uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" @@ -6633,11 +6620,17 @@ uniqs@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" -url-loader@^0.5.7: +url-loader@^0.5.8: version "0.5.8" resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.8.tgz#b9183b1801e0f847718673673040bc9dc1c715c5" dependencies: @@ -6675,7 +6668,7 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -util-deprecate@~1.0.1: +util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -6689,7 +6682,7 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@^2.0.1, uuid@^2.0.2, uuid@^2.0.3: +uuid@^2.0.2, uuid@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" @@ -6740,14 +6733,6 @@ warning@^3.0.0: dependencies: loose-envify "^1.0.0" -watchpack@^0.2.1: - version "0.2.9" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" - dependencies: - async "^0.9.0" - chokidar "^1.0.0" - graceful-fs "^4.1.2" - watchpack@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87" @@ -6786,14 +6771,7 @@ webpack-bundle-analyzer@^2.8.2: opener "^1.4.3" ws "^2.3.1" -webpack-core@~0.6.9: - version "0.6.9" - resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" - dependencies: - source-list-map "~0.1.7" - source-map "~0.4.1" - -webpack-dev-middleware@^1.10.2, webpack-dev-middleware@^1.6.0: +webpack-dev-middleware@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.2.tgz#2e252ce1dfb020dbda1ccb37df26f30ab014dbd1" dependencies: @@ -6824,7 +6802,7 @@ webpack-dev-server@^2.4.5: webpack-dev-middleware "^1.10.2" yargs "^6.0.0" -webpack-hot-middleware@^2.13.2: +webpack-hot-middleware@^2.18.0: version "2.18.0" resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.18.0.tgz#a16bb535b83a6ac94a78ac5ebce4f3059e8274d3" dependencies: @@ -6860,26 +6838,6 @@ webpack-sources@^0.2.3: source-list-map "^1.1.1" source-map "~0.5.3" -webpack@^1.13.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.15.0.tgz#4ff31f53db03339e55164a9d468ee0324968fe98" - dependencies: - acorn "^3.0.0" - async "^1.3.0" - clone "^1.0.2" - enhanced-resolve "~0.9.0" - interpret "^0.6.4" - loader-utils "^0.2.11" - memory-fs "~0.3.0" - mkdirp "~0.5.0" - node-libs-browser "^0.7.0" - optimist "~0.6.0" - supports-color "^3.1.0" - tapable "~0.1.8" - uglify-js "~2.7.3" - watchpack "^0.2.1" - webpack-core "~0.6.9" - webpack@^2.5.1: version "2.6.1" resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07" @@ -6967,10 +6925,6 @@ wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -6986,9 +6940,9 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write-file-atomic@^1.1.2: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" +write-file-atomic@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.1.0.tgz#1769f4b551eedce419f0505deae2e26763542d37" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -7007,11 +6961,9 @@ ws@^2.3.1: safe-buffer "~5.0.1" ultron "~1.1.0" -xdg-basedir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" - dependencies: - os-homedir "^1.0.0" +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" xml-name-validator@^2.0.1: version "2.0.1" -- GitLab From 42844df966d7f503321c82a1f04a8a9be0210dbf Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Mon, 5 Jun 2017 00:07:39 +0900 Subject: [PATCH 128/295] Spec ScopedSettings (#3559) --- spec/models/user_spec.rb | 41 +++------- .../examples/lib/settings/scoped_settings.rb | 74 +++++++++++++++++++ .../lib/settings/settings_extended.rb | 15 ++++ 3 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 spec/support/examples/lib/settings/scoped_settings.rb create mode 100644 spec/support/examples/lib/settings/settings_extended.rb diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d7ca91e819..735c78c645 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -41,37 +41,6 @@ RSpec.describe User, type: :model do end end - describe 'settings' do - it 'inherits default settings from default yml' do - expect(Setting.boost_modal).to eq false - expect(Setting.interactions['must_be_follower']).to eq false - - user = User.new - expect(user.settings.boost_modal).to eq false - expect(user.settings.interactions['must_be_follower']).to eq false - end - - it 'can update settings' do - user = Fabricate(:user) - expect(user.settings['interactions']['must_be_follower']).to eq false - user.settings['interactions'] = user.settings['interactions'].merge('must_be_follower' => true) - user.reload - - expect(user.settings['interactions']['must_be_follower']).to eq true - end - - xit 'does not mutate defaults via the cache' do - user = Fabricate(:user) - user.settings['interactions']['must_be_follower'] = true - # TODO - # This mutates the global settings default such that future user - # instances will inherit the incorrect starting values - - other = Fabricate(:user) - expect(other.settings['interactions']['must_be_follower']).to eq false - end - end - describe 'scopes' do describe 'recent' do it 'returns an array of recent users ordered by id' do @@ -285,4 +254,14 @@ RSpec.describe User, type: :model do end end end + + it_behaves_like 'Settings-extended' do + def create! + User.create!(account: Fabricate(:account), email: 'foo@mastodon.space', password: 'abcd1234' ) + end + + def fabricate + Fabricate(:user) + end + end end diff --git a/spec/support/examples/lib/settings/scoped_settings.rb b/spec/support/examples/lib/settings/scoped_settings.rb new file mode 100644 index 0000000000..2457dcfbf2 --- /dev/null +++ b/spec/support/examples/lib/settings/scoped_settings.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +shared_examples 'ScopedSettings' do + describe '[]' do + it 'inherits default settings' do + expect(Setting.boost_modal).to eq false + expect(Setting.interactions['must_be_follower']).to eq false + + settings = create! + + expect(settings['boost_modal']).to eq false + expect(settings['interactions']['must_be_follower']).to eq false + end + end + + describe 'all_as_records' do + # expecting [] and []= works + + it 'returns records merged with default values except hashes' do + expect(Setting.boost_modal).to eq false + expect(Setting.delete_modal).to eq true + + settings = create! + settings['boost_modal'] = true + + records = settings.all_as_records + + expect(records['boost_modal'].value).to eq true + expect(records['delete_modal'].value).to eq true + end + end + + describe 'missing methods' do + # expecting [] and []= works. + + it 'reads settings' do + expect(Setting.boost_modal).to eq false + settings = create! + expect(settings.boost_modal).to eq false + end + + it 'updates settings' do + settings = fabricate + settings.boost_modal = true + expect(settings['boost_modal']).to eq true + end + end + + it 'can update settings with [] and can read with []=' do + settings = fabricate + + settings['boost_modal'] = true + settings['interactions'] = settings['interactions'].merge('must_be_follower' => true) + + Setting.save! + + expect(settings['boost_modal']).to eq true + expect(settings['interactions']['must_be_follower']).to eq true + + Rails.cache.clear + + expect(settings['boost_modal']).to eq true + expect(settings['interactions']['must_be_follower']).to eq true + end + + xit 'does not mutate defaults via the cache' do + fabricate['interactions']['must_be_follower'] = true + # TODO + # This mutates the global settings default such that future + # instances will inherit the incorrect starting values + + expect(fabricate.settings['interactions']['must_be_follower']).to eq false + end +end diff --git a/spec/support/examples/lib/settings/settings_extended.rb b/spec/support/examples/lib/settings/settings_extended.rb new file mode 100644 index 0000000000..5a9d34bb04 --- /dev/null +++ b/spec/support/examples/lib/settings/settings_extended.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +shared_examples 'Settings-extended' do + describe 'settings' do + def fabricate + super.settings + end + + def create! + super.settings + end + + it_behaves_like 'ScopedSettings' + end +end -- GitLab From 943775fd9071d5c9c155aa10f6bad69ec8cc8758 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 00:13:21 +0900 Subject: [PATCH 129/295] Update dependencies of Node.js (#3561) * Update axios to version 0.16.2 * Update css-loader to version 0.28.4 * Update postcss-smart-import to version 0.7.4 * Update react-immutable-pure-component to version 0.0.5 * Update stringz to version 0.2.1 * Update style-loader to version 0.18.1 * Update websocket.js to version 0.1.9 * yarn upgrade --- package.json | 14 ++-- yarn.lock | 199 +++++++++++++++++++++++++-------------------------- 2 files changed, 104 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index d1d1b8f836..a5d3aed041 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "array-includes": "^3.0.3", "autoprefixer": "^7.1.0", - "axios": "^0.16.1", + "axios": "^0.16.2", "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-loader": "7.x", @@ -40,7 +40,7 @@ "babel-preset-react": "^6.24.1", "classnames": "^2.2.5", "compression-webpack-plugin": "^0.4.0", - "css-loader": "^0.28.1", + "css-loader": "^0.28.4", "dotenv": "^4.0.0", "emojione": "^2.2.7", "emojione-picker": "^2.2.1", @@ -69,7 +69,7 @@ "path-complete-extname": "^0.1.0", "pg": "^6.1.5", "postcss-loader": "^2.0.5", - "postcss-smart-import": "^0.7.0", + "postcss-smart-import": "^0.7.4", "precss": "^1.4.0", "prop-types": "^15.5.10", "punycode": "^2.1.0", @@ -79,7 +79,7 @@ "react-addons-shallow-compare": "^15.5.2", "react-dom": "^15.5.4", "react-immutable-proptypes": "^2.1.0", - "react-immutable-pure-component": "^0.0.4", + "react-immutable-pure-component": "^0.0.5", "react-intl": "^2.3.0", "react-motion": "^0.5.0", "react-notification": "^6.7.0", @@ -98,8 +98,8 @@ "reselect": "^3.0.1", "rimraf": "^2.6.1", "sass-loader": "^6.0.5", - "stringz": "^0.2.0", - "style-loader": "^0.16.1", + "stringz": "^0.2.1", + "style-loader": "^0.18.1", "throng": "^4.0.0", "tiny-queue": "^0.2.1", "uuid": "^3.0.1", @@ -108,7 +108,7 @@ "webpack-bundle-analyzer": "^2.8.2", "webpack-manifest-plugin": "^1.1.0", "webpack-merge": "^4.1.0", - "websocket.js": "^0.1.7" + "websocket.js": "^0.1.9" }, "devDependencies": { "@storybook/addon-actions": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index 3c7ecb46b5..203f80a661 100644 --- a/yarn.lock +++ b/yarn.lock @@ -185,8 +185,8 @@ ajv@^4.11.2, ajv@^4.7.0, ajv@^4.9.1: json-stable-stringify "^1.0.1" ajv@^5.0.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.1.3.tgz#423d1c302c61e617081b30ca05f595ec51408e33" + version "5.1.5" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.1.5.tgz#8734931b601f00d4feef7c65738d77d1b65d1f68" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -239,8 +239,8 @@ ap@~0.2.0: resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" aproba@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + version "1.1.2" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" are-we-there-yet@~1.1.2: version "1.1.4" @@ -413,11 +413,12 @@ aws4@^1.2.1: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -axios@^0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.1.tgz#c0b6d26600842384b8f509e57111f0d2df8223ca" +axios@^0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d" dependencies: follow-redirects "^1.2.3" + is-buffer "^1.1.5" babel-cli@^6.24.1: version "6.24.1" @@ -1280,8 +1281,8 @@ babel-types@^6.16.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24 to-fast-properties "^1.0.1" babylon@^6.11.0, babylon@^6.15.0, babylon@^6.17.0: - version "6.17.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.1.tgz#17f14fddf361b695981fe679385e4f1c01ebd86f" + version "6.17.2" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.2.tgz#201d25ef5f892c41bae49488b08db0dd476e9f5c" babylon@~5.8.3: version "5.8.38" @@ -1309,9 +1310,9 @@ base64-js@^1.0.2: version "1.2.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" -batch@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" bcrypt-pbkdf@^1.0.0: version "1.0.1" @@ -1439,10 +1440,6 @@ browserslist@^2.1.2, browserslist@^2.1.3: caniuse-lite "^1.0.30000670" electron-to-chromium "^1.3.11" -buffer-shims@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" - buffer-writer@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-1.0.1.tgz#22a936901e3029afcd7547eb4487ceb697a3bf08" @@ -1510,12 +1507,12 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000671" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000671.tgz#9f071bbc7b96994638ccbaf47829d58a1577a8ed" + version "1.0.30000676" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000676.tgz#82ea578237637c8ff34a28acaade373b624c4ea8" caniuse-lite@^1.0.30000670: - version "1.0.30000671" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000671.tgz#c206c2f1a1feb34de46064407c4356818389bf1e" + version "1.0.30000676" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000676.tgz#1e962123f48073f0c51c4ea0651dd64d25786498" case-sensitive-paths-webpack-plugin@^2.0.0: version "2.1.1" @@ -1941,13 +1938,14 @@ css-in-js-utils@^1.0.3: dependencies: hyphenate-style-name "^1.0.2" -css-loader@^0.28.1: - version "0.28.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.2.tgz#0ff48e1d6013afcdb585d46c1e61a5fcd036404e" +css-loader@^0.28.1, css-loader@^0.28.4: + version "0.28.4" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.4.tgz#6cf3579192ce355e8b38d5f42dd7a1f2ec898d0f" dependencies: babel-code-frame "^6.11.0" css-selector-tokenizer "^0.7.0" cssnano ">=2.6.1 <4" + icss-utils "^2.1.0" loader-utils "^1.0.2" lodash.camelcase "^4.3.0" object-assign "^4.0.1" @@ -2076,7 +2074,7 @@ debug@2.6.7: dependencies: ms "2.0.0" -debug@^2.1.1, debug@^2.2.0, debug@^2.4.5, debug@^2.6.8: +debug@2.6.8, debug@^2.1.1, debug@^2.2.0, debug@^2.4.5, debug@^2.6.8: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: @@ -2279,8 +2277,8 @@ ejs@^2.5.6: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88" electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.11: - version "1.3.11" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.11.tgz#744761df1d67b492b322ce9aa0aba5393260eb61" + version "1.3.13" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.13.tgz#1b3a5eace6e087bb5e257a100b0cbfe81b2891fc" element-class@^0.2.0: version "0.2.2" @@ -2390,8 +2388,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.21" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.21.tgz#19a725f9e51d0300bbc1e8e821109fd9daf55925" + version "0.10.22" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.22.tgz#1876c51f990769c112c781ea3ebe89f84fd39071" dependencies: es6-iterator "2" es6-symbol "~3.1" @@ -3238,14 +3236,6 @@ http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" -http-errors@~1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" - dependencies: - inherits "2.0.3" - setprototypeof "1.0.2" - statuses ">= 1.3.1 < 2" - http-errors@~1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" @@ -3299,6 +3289,12 @@ icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" +icss-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" + dependencies: + postcss "^6.0.1" + ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" @@ -3468,8 +3464,8 @@ is-dom@^1.0.9: resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d" is-dotfile@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" @@ -3563,10 +3559,10 @@ is-plain-obj@^1.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" is-plain-object@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.1.tgz#4d7ca539bc9db9b737b8acb612f2318ef92f294f" + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.3.tgz#c15bf3e4b66b62d72efaf2925848663ecbc619b6" dependencies: - isobject "^1.0.0" + isobject "^3.0.0" is-posix-bracket@^0.1.0: version "0.1.1" @@ -3634,16 +3630,16 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" -isobject@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-1.0.2.tgz#f0f9b8ce92dd540fa0740882e3835a2e022ec78a" - isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" +isobject@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.0.tgz#39565217f3661789e8a0a0c080d5f7e6bc46e1a0" + isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -4057,8 +4053,8 @@ math-expression-evaluator@^1.2.14: resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" mathjs@^3.11.5: - version "3.13.1" - resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-3.13.1.tgz#591ad98c80e87c5d5997eb626137b1efad44ae71" + version "3.13.3" + resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-3.13.3.tgz#39135ea761f57c083da43638248e3f640727e290" dependencies: complex.js "2.0.1" decimal.js "7.1.1" @@ -4238,15 +4234,15 @@ node-dir@^0.1.10: minimatch "^3.0.2" node-fetch@^1.0.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.0.tgz#3ff6c56544f9b7fb00682338bb55ee6f54a8a0ef" + version "1.7.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-gyp@^3.3.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.1.tgz#19561067ff185464aded478212681f47fd578cbc" + version "3.6.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.2.tgz#9bfbe54562286284838e750eac05295853fa1c60" dependencies: fstream "^1.0.0" glob "^7.0.3" @@ -4291,8 +4287,8 @@ node-libs-browser@^2.0.0: vm-browserify "0.0.4" node-pre-gyp@^0.6.29, node-pre-gyp@^0.6.4: - version "0.6.34" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7" + version "0.6.36" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" dependencies: mkdirp "^0.5.1" nopt "^4.0.1" @@ -4682,14 +4678,14 @@ pg-pool@1.*: object-assign "4.1.0" pg-types@1.*: - version "1.11.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.11.0.tgz#aae91a82d952b633bb88d006350a166daaf6ea90" + version "1.12.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.12.0.tgz#8ad3b7b897e3fd463e62de241ad5fc640b4a66f0" dependencies: ap "~0.2.0" postgres-array "~1.0.0" postgres-bytea "~1.0.0" postgres-date "~1.0.0" - postgres-interval "~1.0.0" + postgres-interval "^1.1.0" pg@^6.1.5: version "6.2.3" @@ -5132,9 +5128,9 @@ postcss-simple-vars@^1.0.1: dependencies: postcss "^5.0.13" -postcss-smart-import@^0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/postcss-smart-import/-/postcss-smart-import-0.7.2.tgz#3d37bd5e7501614ba3c809a1b2fe418b26d9c631" +postcss-smart-import@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/postcss-smart-import/-/postcss-smart-import-0.7.4.tgz#50cfb3d9a49b70a61f911451bc24d841f8dbf200" dependencies: babel-runtime "^6.23.0" lodash "^4.17.4" @@ -5206,9 +5202,9 @@ postgres-date@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8" -postgres-interval@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.0.2.tgz#7261438d862b412921c6fdb7617668424b73a6ed" +postgres-interval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.1.0.tgz#1031e7bac34564132862adc9eb6c6d2f3aa75bb4" dependencies: xtend "^4.0.0" @@ -5370,8 +5366,10 @@ randomatic@^1.1.3: kind-of "^3.0.2" randombytes@^2.0.0, randombytes@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" + version "2.0.4" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.4.tgz#9551df208422c8f80eb58e2326dd0b840ff22efd" + dependencies: + safe-buffer "^5.0.1" range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" @@ -5412,7 +5410,7 @@ react-docgen@^2.12.1: node-dir "^0.1.10" recast "^0.11.5" -react-dom@^15.4.2, react-dom@^15.5.4: +react-dom@^15.5.4: version "15.5.4" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.4.tgz#ba0c28786fd52ed7e4f2135fe0288d462aef93da" dependencies: @@ -5436,13 +5434,9 @@ react-immutable-proptypes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz#023d6f39bb15c97c071e9e60d00d136eac5fa0b4" -react-immutable-pure-component@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/react-immutable-pure-component/-/react-immutable-pure-component-0.0.4.tgz#a7c438167e5b82b5231e4ec9246827ebe3257629" - dependencies: - immutable "^3.8.1" - react "^15.4.2" - react-dom "^15.4.2" +react-immutable-pure-component@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/react-immutable-pure-component/-/react-immutable-pure-component-0.0.5.tgz#5ef9bea0ce670c041e6ae5d689b59aea8983384a" react-inspector@^2.0.0: version "2.0.0" @@ -5614,7 +5608,7 @@ react-virtualized@^9.7.4: loose-envify "^1.3.0" prop-types "^15.5.4" -react@>=0.14.0, react@^15.4.2, react@^15.5.4: +react@>=0.14.0, react@^15.5.4: version "15.5.4" resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047" dependencies: @@ -5645,14 +5639,14 @@ read-pkg@^1.0.0: path-type "^1.0.0" readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.2.9: - version "2.2.9" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" + version "2.2.10" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.10.tgz#effe72bb7c884c0dd335e2379d526196d9d011ee" dependencies: - buffer-shims "~1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" process-nextick-args "~1.0.6" + safe-buffer "^5.0.1" string_decoder "~1.0.0" util-deprecate "~1.0.1" @@ -5931,10 +5925,14 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" -safe-buffer@5.0.1, safe-buffer@^5.0.1, safe-buffer@~5.0.1: +safe-buffer@5.0.1, safe-buffer@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" +safe-buffer@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223" + samsam@1.x, samsam@^1.1.3: version "1.2.1" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.2.1.tgz#edd39093a3184370cb859243b2bdf255e7d8ea67" @@ -5962,7 +5960,7 @@ sax@^1.2.1, sax@~1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" -schema-utils@^0.x: +schema-utils@^0.3.0, schema-utils@^0.x: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" dependencies: @@ -6027,15 +6025,15 @@ serve-favicon@^2.4.3: safe-buffer "5.0.1" serve-index@^1.7.2: - version "1.8.0" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.8.0.tgz#7c5d96c13fb131101f93c1c5774f8516a1e78d3b" + version "1.9.0" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.0.tgz#d2b280fc560d616ee81b48bf0fa82abed2485ce7" dependencies: accepts "~1.3.3" - batch "0.5.3" - debug "~2.2.0" + batch "0.6.1" + debug "2.6.8" escape-html "~1.0.3" - http-errors "~1.5.0" - mime-types "~2.1.11" + http-errors "~1.6.1" + mime-types "~2.1.15" parseurl "~1.3.1" serve-static@1.12.3: @@ -6059,10 +6057,6 @@ setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" -setprototypeof@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" - setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" @@ -6348,9 +6342,9 @@ stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -stringz@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/stringz/-/stringz-0.2.0.tgz#f228f85e108b6da2c9001ecc94c835ca4ee58d1b" +stringz@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/stringz/-/stringz-0.2.1.tgz#9f134564e086b4a35f99b6efc1dd88a8d9cb7e4e" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" @@ -6378,18 +6372,19 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" -style-loader@^0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.16.1.tgz#50e325258d4e78421dd9680636b41e8661595d10" - dependencies: - loader-utils "^1.0.2" - style-loader@^0.17.0: version "0.17.0" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.17.0.tgz#e8254bccdb7af74bd58274e36107b4d5ab4df310" dependencies: loader-utils "^1.0.2" +style-loader@^0.18.1: + version "0.18.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.18.1.tgz#6afca8953c842830e5e2dc84796309880a97f7e8" + dependencies: + loader-utils "^1.0.2" + schema-utils "^0.3.0" + sugarss@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.0.tgz#65e51b3958432fb70d5451a68bb33e32d0cf1ef7" @@ -6586,8 +6581,8 @@ ua-parser-js@^0.7.9: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" uglify-js@^2.8.27: - version "2.8.27" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c" + version "2.8.28" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -6874,9 +6869,9 @@ websocket-extensions@>=0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" -websocket.js@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/websocket.js/-/websocket.js-0.1.7.tgz#8d24cefb1a080c259e7e4740c02cab8f142df2b0" +websocket.js@^0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/websocket.js/-/websocket.js-0.1.9.tgz#3a9bbd65fe93835bc756ecada57f0961dbdcc53e" dependencies: backoff "^2.4.1" -- GitLab From defe4f9bc3407cde4d5b1918778b0754ef7f4970 Mon Sep 17 00:00:00 2001 From: "Akihiko Odaki (@fn_aki@pawoo.net)" Date: Mon, 5 Jun 2017 00:13:37 +0900 Subject: [PATCH 130/295] Cover WebfingerResource more (#3560) --- spec/lib/webfinger_resource_spec.rb | 41 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/spec/lib/webfinger_resource_spec.rb b/spec/lib/webfinger_resource_spec.rb index dfd23062f5..3c3d263ef2 100644 --- a/spec/lib/webfinger_resource_spec.rb +++ b/spec/lib/webfinger_resource_spec.rb @@ -2,14 +2,16 @@ require 'rails_helper' describe WebfingerResource do around do |example| - before = Rails.configuration.x.local_domain + before_local = Rails.configuration.x.local_domain + before_web = Rails.configuration.x.web_domain example.run - Rails.configuration.x.local_domain = before + Rails.configuration.x.local_domain = before_local + Rails.configuration.x.webdomain = before_web end describe '#username' do describe 'with a URL value' do - it 'raises with an unrecognized route' do + it 'raises with a route whose controller is not AccountsController' do resource = 'https://example.com/users/alice/other' expect { @@ -17,6 +19,21 @@ describe WebfingerResource do }.to raise_error(ActiveRecord::RecordNotFound) end + it 'raises with a route whose action is not show' do + resource = 'https://example.com/users/alice' + + recognized = Rails.application.routes.recognize_path(resource) + allow(recognized).to receive(:[]).with(:controller).and_return('accounts') + allow(recognized).to receive(:[]).with(:username).and_return('alice') + expect(recognized).to receive(:[]).with(:action).and_return('create') + + expect(Rails.application.routes).to receive(:recognize_path).with(resource).and_return(recognized).at_least(:once) + + expect { + WebfingerResource.new(resource).username + }.to raise_error(ActiveRecord::RecordNotFound) + end + it 'raises with a string that doesnt start with URL' do resource = 'website for http://example.com/users/alice/other' @@ -63,6 +80,14 @@ describe WebfingerResource do result = WebfingerResource.new(resource).username expect(result).to eq 'alice' end + + it 'finds username for a web domain' do + Rails.configuration.x.web_domain = 'example.com' + resource = 'alice@example.com' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end end describe 'with an acct value' do @@ -82,13 +107,21 @@ describe WebfingerResource do }.to raise_error(ActiveRecord::RecordNotFound) end - it 'finds the username for a local account' do + it 'finds the username for a local account if the domain is the local one' do Rails.configuration.x.local_domain = 'example.com' resource = 'acct:alice@example.com' result = WebfingerResource.new(resource).username expect(result).to eq 'alice' end + + it 'finds the username for a local account if the domain is the Web one' do + Rails.configuration.x.web_domain = 'example.com' + resource = 'acct:alice@example.com' + + result = WebfingerResource.new(resource).username + expect(result).to eq 'alice' + end end end end -- GitLab From 3f815b2052f0528bd84fa2c856c69985876561eb Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 08:02:19 +0900 Subject: [PATCH 131/295] Add date to ignore_missing and ignore_unused in config/i18n-tasks.yml (#3572) --- config/i18n-tasks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 20c1342496..f2bb220a6d 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -36,7 +36,7 @@ ignore_missing: - 'activerecord.attributes.*' - 'activerecord.errors.*' - '{devise,pagination,doorkeeper}.*' - - '{datetime,time}.*' + - '{date,datetime,time}.*' - 'simple_form.{yes,no}' - 'simple_form.{placeholders,hints,labels}.*' - 'simple_form.{error_notification,required}.:' @@ -48,7 +48,7 @@ ignore_unused: - 'activerecord.attributes.*' - 'activerecord.errors.*' - '{devise,pagination,doorkeeper}.*' - - '{datetime,time}.*' + - '{date,datetime,time}.*' - 'simple_form.{yes,no}' - 'simple_form.{placeholders,hints,labels}.*' - 'simple_form.{error_notification,required}.:' -- GitLab From f7a30e2fae3199a82e2ad23bb9d761d1fe1be8de Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 5 Jun 2017 01:03:45 +0200 Subject: [PATCH 132/295] Added support for configurable reserved usernames (fix of #1382) (#3566) * Added support for configurable reserved usernames * Added reserved usernames from mastodon issue 1355 * Fix reserved usernames --- app/models/account.rb | 2 +- app/validators/unreserved_validator.rb | 15 +++++++++++++++ config/locales/en.yml | 1 + config/settings.yml | 9 ++++++++- spec/models/account_spec.rb | 6 ++++++ 5 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 app/validators/unreserved_validator.rb diff --git a/app/models/account.rb b/app/models/account.rb index 5b0d2d65c6..918d5b0f1c 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -56,7 +56,7 @@ class Account < ApplicationRecord # Local user validations with_options if: :local? do - validates :username, format: { with: /\A[a-z0-9_]+\z/i }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 } + validates :username, format: { with: /\A[a-z0-9_]+\z/i }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 }, unreserved: true validates :display_name, length: { maximum: 30 } validates :note, length: { maximum: 160 } end diff --git a/app/validators/unreserved_validator.rb b/app/validators/unreserved_validator.rb new file mode 100644 index 0000000000..4e5b9dafc3 --- /dev/null +++ b/app/validators/unreserved_validator.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class UnreservedValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return if value.nil? + record.errors.add(attribute, I18n.t('accounts.reserved_username')) if reserved_username?(value) + end + + private + + def reserved_username?(value) + return false unless Setting.reserved_usernames + Setting.reserved_usernames.include?(value.downcase) + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 2ff2f7eec6..965bfbe477 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -40,6 +40,7 @@ en: posts: Posts remote_follow: Remote follow unfollow: Unfollow + reserved_username: The username is reserved activitypub: activity: announce: diff --git a/config/settings.yml b/config/settings.yml index 4811213cbd..bffb7052ac 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -7,7 +7,7 @@ # For more information, see docs/Running-Mastodon/Administration-guide.md # defaults: &defaults - site_title: 'Mastodon' + site_title: Mastodon site_description: '' site_extended_description: '' site_contact_username: '' @@ -27,6 +27,13 @@ defaults: &defaults interactions: must_be_follower: false must_be_following: false + reserved_usernames: + - admin + - support + - help + - root + - webmaster + - administrator development: <<: *defaults diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index ebec463e12..ab4de9aa12 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -381,6 +381,12 @@ RSpec.describe Account, type: :model do expect(account_2).to model_have_error_on_field(:username) end + it 'is invalid if the username is reserved' do + account = Fabricate.build(:account, username: 'support') + account.valid? + expect(account).to model_have_error_on_field(:username) + end + context 'when is local' do it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do account = Fabricate.build(:account, username: 'the-doctor') -- GitLab From 5be1214c2645c49813a293781c35aa603c80a487 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Sun, 4 Jun 2017 19:10:13 -0400 Subject: [PATCH 133/295] Gem version bumps (#3524) * Update annotate to version 2.7.2 * Update puma to version 3.9.0 * Update aws-sdk to version 2.9.28 * Update bootsnap to version 1.0.0 * Update nio4r to version 2.1.0 * Update nokogumbo to version 1.4.12 * Update oj to version 3.0.11 * Update pkg-config to version 1.2.3 * Update rubocop to version 0.49.1 * Update sidekiq-scheduler to version 2.1.5 --- Gemfile | 2 +- Gemfile.lock | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Gemfile b/Gemfile index d5fbab7485..b014ba03c8 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,7 @@ gem 'paperclip', '~> 5.1' gem 'paperclip-av-transcoder', '~> 0.6' gem 'addressable', '~> 2.5' -gem 'bootsnap', '~> 0.3' +gem 'bootsnap' gem 'cld3', '~> 3.1' gem 'devise', '~> 4.2' gem 'devise-two-factor', '~> 3.0' diff --git a/Gemfile.lock b/Gemfile.lock index ee86bfafd1..a498323060 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -43,22 +43,22 @@ GEM public_suffix (~> 2.0, >= 2.0.2) airbrussh (1.2.0) sshkit (>= 1.6.1, != 1.7.0) - annotate (2.7.1) + annotate (2.7.2) activerecord (>= 3.2, < 6.0) - rake (>= 10.4, < 12.0) + rake (>= 10.4, < 13.0) arel (8.0.0) ast (2.3.0) attr_encrypted (3.0.3) encryptor (~> 3.0.0) av (0.9.0) cocaine (~> 0.5.3) - aws-sdk (2.9.25) - aws-sdk-resources (= 2.9.25) - aws-sdk-core (2.9.25) + aws-sdk (2.9.28) + aws-sdk-resources (= 2.9.28) + aws-sdk-core (2.9.28) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.9.25) - aws-sdk-core (= 2.9.25) + aws-sdk-resources (2.9.28) + aws-sdk-core (= 2.9.28) aws-sigv4 (1.0.0) bcrypt (3.1.11) better_errors (2.1.1) @@ -67,7 +67,7 @@ GEM rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - bootsnap (0.3.0) + bootsnap (1.0.0) msgpack (~> 1.0) brakeman (3.6.2) builder (3.2.3) @@ -186,7 +186,7 @@ GEM httplog (0.99.3) colorize rack - i18n (0.8.1) + i18n (0.8.4) i18n-tasks (0.9.15) activesupport (>= 4.0.2) ast (>= 2.1.0) @@ -243,12 +243,12 @@ GEM net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (4.1.0) - nio4r (2.0.0) + nio4r (2.1.0) nokogiri (1.7.2) mini_portile2 (~> 2.1.0) - nokogumbo (1.4.11) + nokogumbo (1.4.12) nokogiri - oj (3.0.10) + oj (3.0.11) openssl (2.0.3) orm_adapter (0.5.0) ostatus2 (2.0.0) @@ -274,7 +274,7 @@ GEM pg (0.20.0) pghero (1.7.0) activerecord - pkg-config (1.2.0) + pkg-config (1.2.3) powerpack (0.1.1) pry (0.10.4) coderay (~> 1.1.0) @@ -283,7 +283,7 @@ GEM pry-rails (0.3.6) pry (>= 0.10.4) public_suffix (2.0.5) - puma (3.8.2) + puma (3.9.0) pundit (1.1.0) activesupport (>= 3.0.0) rabl (0.13.1) @@ -331,7 +331,7 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (2.2.2) rake - rake (11.3.0) + rake (12.0.0) redis (3.3.3) redis-actionpack (5.0.1) actionpack (>= 4.0, < 6) @@ -377,7 +377,7 @@ GEM rspec-core (~> 3.0, >= 3.0.0) sidekiq (>= 2.4.0) rspec-support (3.6.0) - rubocop (0.49.0) + rubocop (0.49.1) parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) @@ -405,7 +405,7 @@ GEM sidekiq-bulk (0.1.1) activesupport sidekiq - sidekiq-scheduler (2.1.4) + sidekiq-scheduler (2.1.5) redis (~> 3) rufus-scheduler (~> 3.2) sidekiq (>= 3) @@ -481,7 +481,7 @@ DEPENDENCIES aws-sdk (~> 2.9) better_errors (~> 2.1) binding_of_caller (~> 0.7) - bootsnap (~> 0.3) + bootsnap brakeman (~> 3.6) bullet (~> 5.5) bundler-audit (~> 0.5) -- GitLab From 370fa70924228f2baa8e24fd1e8f33eb6cd0bfd6 Mon Sep 17 00:00:00 2001 From: Quent-in Date: Mon, 5 Jun 2017 01:31:10 +0200 Subject: [PATCH 134/295] l10n update for occitan language (#3557) * i18n Update : Add preference setting for delete toot modal Adding a line for "Add preference setting for delete toot modal" * i18n update for pin/unpin Update to add two more translations * i18n update to have the dates in plain occitan * Removed the blank line * %{selft} back in the translation --- app/javascript/mastodon/locales/oc.json | 4 +- config/locales/oc.yml | 57 ++++++++++++++++++++++++- config/locales/simple_form.oc.yml | 1 + 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 6e53be9ad6..f6fc1b5156 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -27,8 +27,8 @@ "column.notifications": "Notificacions", "column.public": "Flux public global", "column_back_button.label": "Tornar", - "column_header.pin": "Pin", - "column_header.unpin": "Unpin", + "column_header.pin": "Penjar", + "column_header.unpin": "Despenjar", "column_subheading.navigation": "Navigacion", "column_subheading.settings": "Paramètres", "compose_form.lock_disclaimer": "Vòstre compte es pas {locked}. Tot lo mond pòt vos sègre e veire los estatuts reservats als seguidors.", diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 2a2680a907..e6fa9aaec6 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -208,6 +208,59 @@ oc: follow: Sègre prompt_html: 'Avètz (%{self}) demandat de sègre :' title: Sègre %{acct} + date: + abbr_day_names: + - dg + - dl + - dm + - dc + - dj + - dv + - ds + abbr_month_names: + - + - gen + - feb + - mar + - mai + - mai + - jun + - jul + - ag + - set + - oct + - nov + - dec + day_names: + - dimenge + - diluns + - dimars + - dimècres + - dijòus + - divendres + - dissabte + formats: + default: "%d/%m/%Y" + long: "Lo %B %d de %Y" + short: "%b %d" + month_names: + - + - de genièr + - de febrièr + - de març + - d’abrial + - de mai + - de junh + - de julhet + - d’agost + - de setembre + - d’octòbre + - de novembre + - de decembre + order: + - :day + - :month + - :year datetime: distance_in_words: about_x_hours: "Fa %{count} oras" @@ -332,11 +385,11 @@ oc: unlisted_long: Tot lo mond pòt veire mai serà pas visible sul flux public stream_entries: click_to_show: Clic per afichar - reblogged: partejat + reblogged: a partejat sensitive_content: Contengut sensible time: formats: - default: "%b %d %Y a %Ho%M" + default: "Lo %d %b de %Y a %Ho%M" two_factor_authentication: code_hint: Picatz lo còdi generat per vòstra aplicacion d’autentificacion per confirmar description_html: S’activatz l’autentificacion two-factor, vos caldrà vòstre mobil per vos connectar perque generarà un geton per vos daissar dintrar. diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml index 720c5a746b..a08b45ea05 100644 --- a/config/locales/simple_form.oc.yml +++ b/config/locales/simple_form.oc.yml @@ -36,6 +36,7 @@ oc: password: Senhal setting_auto_play_gif: Lectura automatica dels GIFS animats setting_boost_modal: Afichar una fenèstra de confirmacion abans de partejar un estatut + setting_delete_modal: Afichar una fenèstra de confirmacion abans de suprimir un estatut setting_default_privacy: Confidencialitat de las publicacions severity: Severitat type: Tip d’impòrt -- GitLab From f54dca06a91c4adb8c916a1af9a699166502efa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kla=C4=8Dan?= Date: Mon, 5 Jun 2017 02:43:02 +0200 Subject: [PATCH 135/295] Add migration versions (#3574) Since Rails 5.1 missing migration version results in following error: ``` StandardError: Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for: ``` This PR fixes all migration files. --- db/migrate/20160220174730_create_accounts.rb | 2 +- db/migrate/20160220211917_create_statuses.rb | 2 +- db/migrate/20160221003140_create_users.rb | 2 +- db/migrate/20160221003621_create_follows.rb | 2 +- db/migrate/20160222122600_create_stream_entries.rb | 2 +- db/migrate/20160222143943_add_profile_fields_to_accounts.rb | 2 +- db/migrate/20160223162837_add_metadata_to_statuses.rb | 2 +- db/migrate/20160223164502_make_uris_nullable_in_statuses.rb | 2 +- db/migrate/20160223165723_add_url_to_statuses.rb | 2 +- db/migrate/20160223165855_add_url_to_accounts.rb | 2 +- db/migrate/20160223171800_create_favourites.rb | 2 +- db/migrate/20160224223247_create_mentions.rb | 2 +- db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb | 2 +- db/migrate/20160305115639_add_devise_to_users.rb | 2 +- db/migrate/20160306172223_create_doorkeeper_tables.rb | 2 +- db/migrate/20160312193225_add_attachment_header_to_accounts.rb | 2 +- db/migrate/20160314164231_add_owner_to_application.rb | 2 +- db/migrate/20160316103650_add_missing_indices.rb | 2 +- db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb | 2 +- db/migrate/20160325130944_add_admin_to_users.rb | 2 +- db/migrate/20161006213403_rails_settings_migration.rb | 2 +- db/migrate/20170112154826_migrate_settings.rb | 2 +- db/migrate/20170330164118_add_attachment_data_to_imports.rb | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/db/migrate/20160220174730_create_accounts.rb b/db/migrate/20160220174730_create_accounts.rb index 65c15f3e8a..daf7c65526 100644 --- a/db/migrate/20160220174730_create_accounts.rb +++ b/db/migrate/20160220174730_create_accounts.rb @@ -1,4 +1,4 @@ -class CreateAccounts < ActiveRecord::Migration +class CreateAccounts < ActiveRecord::Migration[4.2] def change create_table :accounts do |t| t.string :username, null: false, default: '' diff --git a/db/migrate/20160220211917_create_statuses.rb b/db/migrate/20160220211917_create_statuses.rb index 5e62e95be1..b174685687 100644 --- a/db/migrate/20160220211917_create_statuses.rb +++ b/db/migrate/20160220211917_create_statuses.rb @@ -1,4 +1,4 @@ -class CreateStatuses < ActiveRecord::Migration +class CreateStatuses < ActiveRecord::Migration[4.2] def change create_table :statuses do |t| t.string :uri, null: false, default: '' diff --git a/db/migrate/20160221003140_create_users.rb b/db/migrate/20160221003140_create_users.rb index c9750c6238..267466a949 100644 --- a/db/migrate/20160221003140_create_users.rb +++ b/db/migrate/20160221003140_create_users.rb @@ -1,4 +1,4 @@ -class CreateUsers < ActiveRecord::Migration +class CreateUsers < ActiveRecord::Migration[4.2] def change create_table :users do |t| t.string :email, null: false, default: '' diff --git a/db/migrate/20160221003621_create_follows.rb b/db/migrate/20160221003621_create_follows.rb index afec3dee03..17287d09bc 100644 --- a/db/migrate/20160221003621_create_follows.rb +++ b/db/migrate/20160221003621_create_follows.rb @@ -1,4 +1,4 @@ -class CreateFollows < ActiveRecord::Migration +class CreateFollows < ActiveRecord::Migration[4.2] def change create_table :follows do |t| t.integer :account_id, null: false diff --git a/db/migrate/20160222122600_create_stream_entries.rb b/db/migrate/20160222122600_create_stream_entries.rb index 10a6862d9f..00782abc33 100644 --- a/db/migrate/20160222122600_create_stream_entries.rb +++ b/db/migrate/20160222122600_create_stream_entries.rb @@ -1,4 +1,4 @@ -class CreateStreamEntries < ActiveRecord::Migration +class CreateStreamEntries < ActiveRecord::Migration[4.2] def change create_table :stream_entries do |t| t.integer :account_id diff --git a/db/migrate/20160222143943_add_profile_fields_to_accounts.rb b/db/migrate/20160222143943_add_profile_fields_to_accounts.rb index 221142bdd4..cf279a535d 100644 --- a/db/migrate/20160222143943_add_profile_fields_to_accounts.rb +++ b/db/migrate/20160222143943_add_profile_fields_to_accounts.rb @@ -1,4 +1,4 @@ -class AddProfileFieldsToAccounts < ActiveRecord::Migration +class AddProfileFieldsToAccounts < ActiveRecord::Migration[4.2] def change add_column :accounts, :note, :text, null: false, default: '' add_column :accounts, :display_name, :string, null: false, default: '' diff --git a/db/migrate/20160223162837_add_metadata_to_statuses.rb b/db/migrate/20160223162837_add_metadata_to_statuses.rb index 7120e582a4..d11d5f5cdf 100644 --- a/db/migrate/20160223162837_add_metadata_to_statuses.rb +++ b/db/migrate/20160223162837_add_metadata_to_statuses.rb @@ -1,4 +1,4 @@ -class AddMetadataToStatuses < ActiveRecord::Migration +class AddMetadataToStatuses < ActiveRecord::Migration[4.2] def change add_column :statuses, :in_reply_to_id, :integer, null: true add_column :statuses, :reblog_of_id, :integer, null: true diff --git a/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb b/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb index 0fc1c39c3f..24b9b6e190 100644 --- a/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb +++ b/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb @@ -1,4 +1,4 @@ -class MakeUrisNullableInStatuses < ActiveRecord::Migration +class MakeUrisNullableInStatuses < ActiveRecord::Migration[4.2] def change change_column :statuses, :uri, :string, null: true, default: nil end diff --git a/db/migrate/20160223165723_add_url_to_statuses.rb b/db/migrate/20160223165723_add_url_to_statuses.rb index a5aa1613a9..80f4b3289e 100644 --- a/db/migrate/20160223165723_add_url_to_statuses.rb +++ b/db/migrate/20160223165723_add_url_to_statuses.rb @@ -1,4 +1,4 @@ -class AddUrlToStatuses < ActiveRecord::Migration +class AddUrlToStatuses < ActiveRecord::Migration[4.2] def change add_column :statuses, :url, :string, null: true, default: nil end diff --git a/db/migrate/20160223165855_add_url_to_accounts.rb b/db/migrate/20160223165855_add_url_to_accounts.rb index 59dd2b97b9..c81b1c64fc 100644 --- a/db/migrate/20160223165855_add_url_to_accounts.rb +++ b/db/migrate/20160223165855_add_url_to_accounts.rb @@ -1,4 +1,4 @@ -class AddUrlToAccounts < ActiveRecord::Migration +class AddUrlToAccounts < ActiveRecord::Migration[4.2] def change add_column :accounts, :url, :string, null: true, default: nil end diff --git a/db/migrate/20160223171800_create_favourites.rb b/db/migrate/20160223171800_create_favourites.rb index bb35f491fe..64f5cf1197 100644 --- a/db/migrate/20160223171800_create_favourites.rb +++ b/db/migrate/20160223171800_create_favourites.rb @@ -1,4 +1,4 @@ -class CreateFavourites < ActiveRecord::Migration +class CreateFavourites < ActiveRecord::Migration[4.2] def change create_table :favourites do |t| t.integer :account_id, null: false diff --git a/db/migrate/20160224223247_create_mentions.rb b/db/migrate/20160224223247_create_mentions.rb index 095f6b7d26..6dd742d3b1 100644 --- a/db/migrate/20160224223247_create_mentions.rb +++ b/db/migrate/20160224223247_create_mentions.rb @@ -1,4 +1,4 @@ -class CreateMentions < ActiveRecord::Migration +class CreateMentions < ActiveRecord::Migration[4.2] def change create_table :mentions do |t| t.integer :account_id diff --git a/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb b/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb index 99d88e5ecf..c107c4c7fa 100644 --- a/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb +++ b/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb @@ -1,4 +1,4 @@ -class AddAttachmentAvatarToAccounts < ActiveRecord::Migration +class AddAttachmentAvatarToAccounts < ActiveRecord::Migration[4.2] def self.up change_table :accounts do |t| t.attachment :avatar diff --git a/db/migrate/20160305115639_add_devise_to_users.rb b/db/migrate/20160305115639_add_devise_to_users.rb index 236a4b27c3..0e12e60536 100644 --- a/db/migrate/20160305115639_add_devise_to_users.rb +++ b/db/migrate/20160305115639_add_devise_to_users.rb @@ -1,4 +1,4 @@ -class AddDeviseToUsers < ActiveRecord::Migration +class AddDeviseToUsers < ActiveRecord::Migration[4.2] def self.up change_table(:users) do |t| ## Database authenticatable diff --git a/db/migrate/20160306172223_create_doorkeeper_tables.rb b/db/migrate/20160306172223_create_doorkeeper_tables.rb index d89b005c3c..9e173a43f3 100644 --- a/db/migrate/20160306172223_create_doorkeeper_tables.rb +++ b/db/migrate/20160306172223_create_doorkeeper_tables.rb @@ -1,4 +1,4 @@ -class CreateDoorkeeperTables < ActiveRecord::Migration +class CreateDoorkeeperTables < ActiveRecord::Migration[4.2] def change create_table :oauth_applications do |t| t.string :name, null: false diff --git a/db/migrate/20160312193225_add_attachment_header_to_accounts.rb b/db/migrate/20160312193225_add_attachment_header_to_accounts.rb index bdd09c3672..ac9562cbbe 100644 --- a/db/migrate/20160312193225_add_attachment_header_to_accounts.rb +++ b/db/migrate/20160312193225_add_attachment_header_to_accounts.rb @@ -1,4 +1,4 @@ -class AddAttachmentHeaderToAccounts < ActiveRecord::Migration +class AddAttachmentHeaderToAccounts < ActiveRecord::Migration[4.2] def self.up change_table :accounts do |t| t.attachment :header diff --git a/db/migrate/20160314164231_add_owner_to_application.rb b/db/migrate/20160314164231_add_owner_to_application.rb index 7d5e6d07d0..1919f09a17 100644 --- a/db/migrate/20160314164231_add_owner_to_application.rb +++ b/db/migrate/20160314164231_add_owner_to_application.rb @@ -1,4 +1,4 @@ -class AddOwnerToApplication < ActiveRecord::Migration +class AddOwnerToApplication < ActiveRecord::Migration[4.2] def change add_column :oauth_applications, :owner_id, :integer, null: true add_column :oauth_applications, :owner_type, :string, null: true diff --git a/db/migrate/20160316103650_add_missing_indices.rb b/db/migrate/20160316103650_add_missing_indices.rb index 1902418335..8b6bc5771b 100644 --- a/db/migrate/20160316103650_add_missing_indices.rb +++ b/db/migrate/20160316103650_add_missing_indices.rb @@ -1,4 +1,4 @@ -class AddMissingIndices < ActiveRecord::Migration +class AddMissingIndices < ActiveRecord::Migration[4.2] def change add_index :users, :account_id add_index :statuses, :account_id diff --git a/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb b/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb index 9dc4b027f0..f9c213d9b4 100644 --- a/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb +++ b/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb @@ -1,4 +1,4 @@ -class AddAvatarRemoteUrlToAccounts < ActiveRecord::Migration +class AddAvatarRemoteUrlToAccounts < ActiveRecord::Migration[4.2] def change add_column :accounts, :avatar_remote_url, :string, null: true, default: nil end diff --git a/db/migrate/20160325130944_add_admin_to_users.rb b/db/migrate/20160325130944_add_admin_to_users.rb index e386d33dda..b0cd35e008 100644 --- a/db/migrate/20160325130944_add_admin_to_users.rb +++ b/db/migrate/20160325130944_add_admin_to_users.rb @@ -1,4 +1,4 @@ -class AddAdminToUsers < ActiveRecord::Migration +class AddAdminToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :admin, :boolean, default: false end diff --git a/db/migrate/20161006213403_rails_settings_migration.rb b/db/migrate/20161006213403_rails_settings_migration.rb index 3bfd8af8ec..3b2e637fc7 100644 --- a/db/migrate/20161006213403_rails_settings_migration.rb +++ b/db/migrate/20161006213403_rails_settings_migration.rb @@ -1,7 +1,7 @@ MIGRATION_BASE_CLASS = if ActiveRecord::VERSION::MAJOR >= 5 ActiveRecord::Migration[5.0] else - ActiveRecord::Migration + ActiveRecord::Migration[4.2] end class RailsSettingsMigration < MIGRATION_BASE_CLASS diff --git a/db/migrate/20170112154826_migrate_settings.rb b/db/migrate/20170112154826_migrate_settings.rb index f6f6ed5315..0f5afe1d39 100644 --- a/db/migrate/20170112154826_migrate_settings.rb +++ b/db/migrate/20170112154826_migrate_settings.rb @@ -1,4 +1,4 @@ -class MigrateSettings < ActiveRecord::Migration +class MigrateSettings < ActiveRecord::Migration[4.2] def up remove_index :settings, [:target_type, :target_id, :var] rename_column :settings, :target_id, :thing_id diff --git a/db/migrate/20170330164118_add_attachment_data_to_imports.rb b/db/migrate/20170330164118_add_attachment_data_to_imports.rb index 4850b0663d..2deda18861 100644 --- a/db/migrate/20170330164118_add_attachment_data_to_imports.rb +++ b/db/migrate/20170330164118_add_attachment_data_to_imports.rb @@ -1,4 +1,4 @@ -class AddAttachmentDataToImports < ActiveRecord::Migration +class AddAttachmentDataToImports < ActiveRecord::Migration[4.2] def self.up change_table :imports do |t| t.attachment :data -- GitLab From 037f96c5aeaa4b31e03ecc875a76450f2b7e8b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kla=C4=8Dan?= Date: Mon, 5 Jun 2017 03:24:18 +0200 Subject: [PATCH 136/295] Don't follow account if it's already followed (#3575) Closes https://github.com/tootsuite/mastodon/issues/3102 --- app/services/follow_service.rb | 2 ++ spec/services/follow_service_spec.rb | 34 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 23e721fac6..4de75e98d7 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -12,6 +12,8 @@ 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) + if target_account.locked? request_follow(source_account, target_account) else diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb index bda5daee13..32dedb3ad7 100644 --- a/spec/services/follow_service_spec.rb +++ b/spec/services/follow_service_spec.rb @@ -29,6 +29,19 @@ RSpec.describe FollowService do expect(sender.following?(bob)).to be true end end + + describe 'already followed account' do + let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } + + before do + sender.follow!(bob) + subject.call(sender, bob.acct) + end + + it 'keeps a following relation' do + expect(sender.following?(bob)).to be true + end + end end context 'remote account' do @@ -76,5 +89,26 @@ RSpec.describe FollowService do expect(a_request(:post, "http://hub.example.com/")).to have_been_made.once end end + + describe 'already followed account' do + let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account } + + before do + sender.follow!(bob) + subject.call(sender, bob.acct) + end + + it 'keeps a following relation' do + expect(sender.following?(bob)).to be true + end + + it 'does not send a follow salmon slap' do + expect(a_request(:post, "http://salmon.example.com/")).not_to have_been_made + end + + it 'does not subscribe to PuSH' do + expect(a_request(:post, "http://hub.example.com/")).not_to have_been_made + end + end end end -- GitLab From 6adbd114c1957fbd4908d28f612881a0861823f2 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 17:03:01 +0900 Subject: [PATCH 137/295] Skip image length check (regression from #3528) (#3581) --- spec/lib/atom_serializer_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/lib/atom_serializer_spec.rb b/spec/lib/atom_serializer_spec.rb index c998d55edd..d14fc5b40f 100644 --- a/spec/lib/atom_serializer_spec.rb +++ b/spec/lib/atom_serializer_spec.rb @@ -389,7 +389,6 @@ RSpec.describe AtomSerializer do enclosure = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'enclosure' } expect(enclosure[:type]).to eq 'image/jpeg' - expect(enclosure[:length]).to eq '57822' expect(enclosure[:href]).to match /^https:\/\/cb6e6126.ngrok.io\/system\/media_attachments\/files\/.+\/original\/attachment.jpg$/ end -- GitLab From 6a4b2243975451058d42860312f9ec2966b64bc9 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 17:03:36 +0900 Subject: [PATCH 138/295] Fix randomly fail (regression from #3560) (#3580) --- spec/lib/webfinger_resource_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/webfinger_resource_spec.rb b/spec/lib/webfinger_resource_spec.rb index 3c3d263ef2..287537a261 100644 --- a/spec/lib/webfinger_resource_spec.rb +++ b/spec/lib/webfinger_resource_spec.rb @@ -6,7 +6,7 @@ describe WebfingerResource do before_web = Rails.configuration.x.web_domain example.run Rails.configuration.x.local_domain = before_local - Rails.configuration.x.webdomain = before_web + Rails.configuration.x.web_domain = before_web end describe '#username' do -- GitLab From ab914ce6d5a681cf28486c663f01d0c481911c41 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 17:08:07 +0900 Subject: [PATCH 139/295] Add OnboadingModal story (#3578) --- package.json | 2 +- storybook/initial_state.js | 24 +++++++++++++++++++++ storybook/stories/onboarding_modal.story.js | 24 +++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 storybook/initial_state.js create mode 100644 storybook/stories/onboarding_modal.story.js diff --git a/package.json b/package.json index a5d3aed041..da84716054 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build:production": "NODE_ENV=production yarn webpack -- --config config/webpack/production.js", "manage:translations": "node ./config/webpack/translationRunner.js", "start": "rimraf ./tmp/streaming && babel ./streaming/index.js --out-dir ./tmp && node ./tmp/streaming/index.js", - "storybook": "NODE_ENV=test start-storybook -p 9001 -c storybook", + "storybook": "NODE_ENV=test start-storybook -s ./public -p 9001 -c storybook", "test": "npm run test:lint && npm run test:mocha", "test:lint": "eslint -c .eslintrc.yml --ext=js app/javascript/ config/webpack/ spec/javascript/ storyboard/ streaming/", "test:mocha": "NODE_ENV=test mocha --require ./spec/javascript/setup.js --compilers js:babel-register ./spec/javascript/components/*.test.js", diff --git a/storybook/initial_state.js b/storybook/initial_state.js new file mode 100644 index 0000000000..3872586f61 --- /dev/null +++ b/storybook/initial_state.js @@ -0,0 +1,24 @@ +export default { + meta: { + admin: 1, + domain: 'example.com', + me: 2, + }, + accounts: { + 1: { + acct: 'admin', + avatar: '/avatars/original/missing.png', + id: 1, + url: 'https://example.com/@admin', + }, + 2: { + acct: 'user', + avatar: '/avatars/original/missing.png', + id: 1, + url: 'https://example.com/@user', + }, + }, + media_attachments: { + accept_content_types: [], + }, +}; diff --git a/storybook/stories/onboarding_modal.story.js b/storybook/stories/onboarding_modal.story.js new file mode 100644 index 0000000000..91727bdb28 --- /dev/null +++ b/storybook/stories/onboarding_modal.story.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { IntlProvider } from 'react-intl'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import en from 'mastodon/locales/en.json'; +import configureStore from 'mastodon/store/configureStore'; +import { hydrateStore } from 'mastodon/actions/store'; +import OnboadingModal from 'mastodon/features/ui/components/onboarding_modal'; +import initialState from '../initial_state'; + +const store = configureStore(); +store.dispatch(hydrateStore(initialState)); + +storiesOf('OnboadingModal', module) + .add('default state', () => ( + + +
+ +
+
+
+ )); -- GitLab From 4addf051d42393c9f933db2ecf210b151d901192 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 17:08:31 +0900 Subject: [PATCH 140/295] Fix broken embed page (#3577) --- app/views/layouts/embedded.html.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/layouts/embedded.html.haml b/app/views/layouts/embedded.html.haml index c7a3374bc0..5680c1ff92 100644 --- a/app/views/layouts/embedded.html.haml +++ b/app/views/layouts/embedded.html.haml @@ -3,6 +3,8 @@ %head %meta{ charset: 'utf-8' }/ = stylesheet_pack_tag 'application', media: 'all' + = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous' + = javascript_pack_tag "locale_#{I18n.locale}", integrity: true, crossorigin: 'anonymous' = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous' %body.embed = yield -- GitLab From 66ca7157db9c9ea24fd18a624a1a642c9f7a419a Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 5 Jun 2017 17:09:14 +0900 Subject: [PATCH 141/295] Add support key shortcut to Onboarding Modal (#3517) * Add support key shortcut to Onboarding Modal * this.state.pages -> this.pages --- .../ui/components/onboarding_modal.js | 90 +++++++++++++++---- app/javascript/styles/components.scss | 8 ++ 2 files changed, 79 insertions(+), 19 deletions(-) diff --git a/app/javascript/mastodon/features/ui/components/onboarding_modal.js b/app/javascript/mastodon/features/ui/components/onboarding_modal.js index a06338b25a..c121bfb179 100644 --- a/app/javascript/mastodon/features/ui/components/onboarding_modal.js +++ b/app/javascript/mastodon/features/ui/components/onboarding_modal.js @@ -3,6 +3,7 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import classNames from 'classnames'; import Permalink from '../../../components/permalink'; import TransitionMotion from 'react-motion/lib/TransitionMotion'; import spring from 'react-motion/lib/spring'; @@ -59,6 +60,7 @@ const PageTwo = ({ me }) => ( onClearSuggestions={noop} onFetchSuggestions={noop} onSuggestionSelected={noop} + showSearch />
@@ -180,6 +182,25 @@ class OnboardingModal extends React.PureComponent { currentIndex: 0, }; + componentWillMount() { + const { me, admin, domain, intl } = this.props; + this.pages = [ + , + , + , + , + , + ]; + }; + + componentDidMount() { + window.addEventListener('keyup', this.handleKeyUp); + } + + componentWillUnmount() { + window.addEventListener('keyup', this.handleKeyUp); + } + handleSkip = (e) => { e.preventDefault(); this.props.onClose(); @@ -191,27 +212,36 @@ class OnboardingModal extends React.PureComponent { this.setState({ currentIndex: i }); } + handlePrev = () => { + this.setState(({ currentIndex }) => ({ + currentIndex: Math.max(0, currentIndex - 1), + })); + } + handleNext = () => { + const { pages } = this; this.setState(({ currentIndex }) => ({ - currentIndex: currentIndex + 1, + currentIndex: Math.min(currentIndex + 1, pages.length - 1), })); } + handleKeyUp = ({ key }) => { + switch (key) { + case 'ArrowLeft': + this.handlePrev(); + break; + case 'ArrowRight': + this.handleNext(); + break; + } + } + handleClose = () => { this.props.onClose(); } render () { - const { me, admin, domain, intl } = this.props; - - const pages = [ - , - , - , - , - , - ]; - + const { pages } = this; const { currentIndex } = this.state; const hasMore = currentIndex < pages.length - 1; @@ -231,21 +261,29 @@ class OnboardingModal extends React.PureComponent { ); - const styles = pages.map((page, i) => ({ + const styles = pages.map((data, i) => ({ key: `page-${i}`, - style: { opacity: spring(i === currentIndex ? 1 : 0) }, + data, + style: { + opacity: spring(i === currentIndex ? 1 : 0), + }, })); return (
- {interpolatedStyles => + {interpolatedStyles => (
- {pages.map((page, i) => -
{page}
- )} + {interpolatedStyles.map(({ key, data, style }, i) => { + const className = classNames('onboarding-modal__page__wrapper', { + 'onboarding-modal__page__wrapper--active': i === currentIndex, + }); + return ( +
{data}
+ ); + })}
- } + )}
@@ -259,7 +297,21 @@ class OnboardingModal extends React.PureComponent {
- {pages.map((_, i) =>
)} + {pages.map((_, i) => { + const className = classNames('onboarding-modal__dot', { + active: i === currentIndex, + }); + return ( +
+ ); + })}
diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index 7f2b5cfe0c..3301e6e47d 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -3073,6 +3073,14 @@ button.icon-button.active i.fa-retweet { } } +.onboarding-modal__page__wrapper { + pointer-events: none; + + &.onboading-modal__page__wrapper--active { + pointer-events: auto; + } +} + .onboarding-modal__page { cursor: default; line-height: 21px; -- GitLab From 2985d089517a4f83af1cff264d926955f74da2fd Mon Sep 17 00:00:00 2001 From: Daigo 3 Dango Date: Mon, 5 Jun 2017 10:09:29 +0000 Subject: [PATCH 142/295] Redirect to streaming_api_base_url (#3579) * Redirect to streaming_api_base_url When Rails receives a request to streaming API, it most likely means that there is another host which is configured to respond to it. This is to redirect clients to that host if `STREAMING_API_BASE_URL` is set as another host. * Use the new Ruby 1.9 hash syntax --- .../api/v1/streaming_controller.rb | 15 ++++++ config/routes.rb | 1 + .../api/v1/streaming_controller_spec.rb | 46 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 app/controllers/api/v1/streaming_controller.rb create mode 100644 spec/controllers/api/v1/streaming_controller_spec.rb diff --git a/app/controllers/api/v1/streaming_controller.rb b/app/controllers/api/v1/streaming_controller.rb new file mode 100644 index 0000000000..3779514723 --- /dev/null +++ b/app/controllers/api/v1/streaming_controller.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class Api::V1::StreamingController < ApiController + respond_to :json + + def index + if Rails.configuration.x.streaming_api_base_url != request.host + uri = URI.parse(request.url) + uri.host = URI.parse(Rails.configuration.x.streaming_api_base_url).host + redirect_to uri.to_s, status: 301 + else + raise ActiveRecord::RecordNotFound + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 5c1c8e594f..7a2286f92f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -141,6 +141,7 @@ Rails.application.routes.draw do resource :public, only: :show, controller: :public resources :tag, only: :show end + resources :streaming, only: [:index] get '/search', to: 'search#index', as: :search diff --git a/spec/controllers/api/v1/streaming_controller_spec.rb b/spec/controllers/api/v1/streaming_controller_spec.rb new file mode 100644 index 0000000000..daf2807e7f --- /dev/null +++ b/spec/controllers/api/v1/streaming_controller_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::StreamingController do + around(:each) do |example| + before = Rails.configuration.x.streaming_api_base_url + Rails.configuration.x.streaming_api_base_url = Rails.configuration.x.web_domain + example.run + Rails.configuration.x.streaming_api_base_url = before + end + + before(:each) do + request.headers.merge! Host: Rails.configuration.x.web_domain + end + + context 'with streaming api on same host' do + describe 'GET #index' do + it 'raises ActiveRecord::RecordNotFound' do + get :index + expect(response).to have_http_status(404) + end + end + end + + context 'with streaming api on different host' do + before(:each) do + Rails.configuration.x.streaming_api_base_url = 'wss://streaming-' + Rails.configuration.x.web_domain + @streaming_host = URI.parse(Rails.configuration.x.streaming_api_base_url).host + end + + describe 'GET #index' do + it 'redirects to streaming host' do + get :index, params: {access_token: 'deadbeef', stream: 'public'} + expect(response).to have_http_status(301) + request_uri = URI.parse(request.url) + redirect_to_uri = URI.parse(response.location) + [:scheme, :path, :query, :fragment].each do |part| + expect(redirect_to_uri.send(part)).to eq(request_uri.send(part)), "redirect target #{part}" + end + expect(redirect_to_uri.host).to eq(@streaming_host), "redirect target host" + end + end + end + +end -- GitLab From 4c06d1cb241020f2407a6be01b584c508a06ffe9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 5 Jun 2017 13:24:00 +0200 Subject: [PATCH 143/295] Fix #3550 - Add all missing foreign keys (#3562) * Fix #3550 - Add all missing foreign keys * Add missing foreign keys --- ...604144747_add_foreign_keys_for_accounts.rb | 41 +++++++++++++++++++ db/schema.rb | 39 +++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20170604144747_add_foreign_keys_for_accounts.rb diff --git a/db/migrate/20170604144747_add_foreign_keys_for_accounts.rb b/db/migrate/20170604144747_add_foreign_keys_for_accounts.rb new file mode 100644 index 0000000000..76a836ca08 --- /dev/null +++ b/db/migrate/20170604144747_add_foreign_keys_for_accounts.rb @@ -0,0 +1,41 @@ +class AddForeignKeysForAccounts < ActiveRecord::Migration[5.1] + def change + add_foreign_key :statuses, :accounts, on_delete: :cascade + add_foreign_key :statuses, :accounts, column: :in_reply_to_account_id, on_delete: :nullify + add_foreign_key :statuses, :statuses, column: :in_reply_to_id, on_delete: :nullify + add_foreign_key :account_domain_blocks, :accounts, on_delete: :cascade + add_foreign_key :conversation_mutes, :accounts, on_delete: :cascade + add_foreign_key :conversation_mutes, :conversations, on_delete: :cascade + add_foreign_key :favourites, :accounts, on_delete: :cascade + add_foreign_key :favourites, :statuses, on_delete: :cascade + add_foreign_key :blocks, :accounts, on_delete: :cascade + add_foreign_key :blocks, :accounts, column: :target_account_id, on_delete: :cascade + add_foreign_key :follow_requests, :accounts, on_delete: :cascade + add_foreign_key :follow_requests, :accounts, column: :target_account_id, on_delete: :cascade + add_foreign_key :follows, :accounts, on_delete: :cascade + add_foreign_key :follows, :accounts, column: :target_account_id, on_delete: :cascade + add_foreign_key :mutes, :accounts, on_delete: :cascade + add_foreign_key :mutes, :accounts, column: :target_account_id, on_delete: :cascade + add_foreign_key :imports, :accounts, on_delete: :cascade + add_foreign_key :media_attachments, :accounts, on_delete: :nullify + add_foreign_key :media_attachments, :statuses, on_delete: :nullify + add_foreign_key :mentions, :accounts, on_delete: :cascade + add_foreign_key :mentions, :statuses, on_delete: :cascade + add_foreign_key :notifications, :accounts, on_delete: :cascade + add_foreign_key :notifications, :accounts, column: :from_account_id, on_delete: :cascade + add_foreign_key :preview_cards, :statuses, on_delete: :cascade + add_foreign_key :reports, :accounts, on_delete: :cascade + add_foreign_key :reports, :accounts, column: :target_account_id, on_delete: :cascade + add_foreign_key :reports, :accounts, column: :action_taken_by_account_id, on_delete: :nullify + add_foreign_key :statuses_tags, :statuses, on_delete: :cascade + add_foreign_key :statuses_tags, :tags, on_delete: :cascade + add_foreign_key :stream_entries, :accounts, on_delete: :cascade + add_foreign_key :subscriptions, :accounts, on_delete: :cascade + add_foreign_key :users, :accounts, on_delete: :cascade + add_foreign_key :web_settings, :users, on_delete: :cascade + add_foreign_key :oauth_access_grants, :users, column: :resource_owner_id, on_delete: :cascade + add_foreign_key :oauth_access_grants, :oauth_applications, column: :application_id, on_delete: :cascade + add_foreign_key :oauth_access_tokens, :users, column: :resource_owner_id, on_delete: :cascade + add_foreign_key :oauth_access_tokens, :oauth_applications, column: :application_id, on_delete: :cascade + end +end diff --git a/db/schema.rb b/db/schema.rb index c79258cf7c..ca904569e4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170601210557) do +ActiveRecord::Schema.define(version: 20170604144747) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -367,5 +367,42 @@ ActiveRecord::Schema.define(version: 20170601210557) do t.index ["user_id"], name: "index_web_settings_on_user_id", unique: true end + add_foreign_key "account_domain_blocks", "accounts", on_delete: :cascade + add_foreign_key "blocks", "accounts", column: "target_account_id", on_delete: :cascade + add_foreign_key "blocks", "accounts", on_delete: :cascade + add_foreign_key "conversation_mutes", "accounts", on_delete: :cascade + add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade + add_foreign_key "favourites", "accounts", on_delete: :cascade + add_foreign_key "favourites", "statuses", on_delete: :cascade + add_foreign_key "follow_requests", "accounts", column: "target_account_id", on_delete: :cascade + add_foreign_key "follow_requests", "accounts", on_delete: :cascade + add_foreign_key "follows", "accounts", column: "target_account_id", on_delete: :cascade + add_foreign_key "follows", "accounts", on_delete: :cascade + add_foreign_key "imports", "accounts", on_delete: :cascade + add_foreign_key "media_attachments", "accounts", on_delete: :nullify + add_foreign_key "media_attachments", "statuses", on_delete: :nullify + add_foreign_key "mentions", "accounts", on_delete: :cascade + add_foreign_key "mentions", "statuses", on_delete: :cascade + add_foreign_key "mutes", "accounts", column: "target_account_id", on_delete: :cascade + add_foreign_key "mutes", "accounts", on_delete: :cascade + add_foreign_key "notifications", "accounts", column: "from_account_id", on_delete: :cascade + add_foreign_key "notifications", "accounts", on_delete: :cascade + add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id", on_delete: :cascade + add_foreign_key "oauth_access_grants", "users", column: "resource_owner_id", on_delete: :cascade + add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id", on_delete: :cascade + add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id", on_delete: :cascade + add_foreign_key "preview_cards", "statuses", on_delete: :cascade + add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", on_delete: :nullify + add_foreign_key "reports", "accounts", column: "target_account_id", on_delete: :cascade + add_foreign_key "reports", "accounts", on_delete: :cascade + add_foreign_key "statuses", "accounts", column: "in_reply_to_account_id", on_delete: :nullify + add_foreign_key "statuses", "accounts", on_delete: :cascade + add_foreign_key "statuses", "statuses", column: "in_reply_to_id", on_delete: :nullify add_foreign_key "statuses", "statuses", column: "reblog_of_id", on_delete: :cascade + add_foreign_key "statuses_tags", "statuses", on_delete: :cascade + add_foreign_key "statuses_tags", "tags", on_delete: :cascade + add_foreign_key "stream_entries", "accounts", on_delete: :cascade + add_foreign_key "subscriptions", "accounts", on_delete: :cascade + add_foreign_key "users", "accounts", on_delete: :cascade + add_foreign_key "web_settings", "users", on_delete: :cascade end -- GitLab From 1f1d6bf2a07219c9dfd04db5b98e31a0543a7427 Mon Sep 17 00:00:00 2001 From: Naoki Kosaka Date: Mon, 5 Jun 2017 21:13:20 +0900 Subject: [PATCH 144/295] Fix LoadMore in following and followers. (#3585) --- app/javascript/mastodon/features/followers/index.js | 11 +++++++++-- app/javascript/mastodon/features/following/index.js | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js index ed7119cda6..5120a5747e 100644 --- a/app/javascript/mastodon/features/followers/index.js +++ b/app/javascript/mastodon/features/followers/index.js @@ -18,6 +18,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; const mapStateToProps = (state, props) => ({ accountIds: state.getIn(['user_lists', 'followers', Number(props.params.accountId), 'items']), + hasMore: !!state.getIn(['user_lists', 'followers', Number(props.params.accountId), 'next']), }); class Followers extends ImmutablePureComponent { @@ -54,7 +55,9 @@ class Followers extends ImmutablePureComponent { } render () { - const { accountIds } = this.props; + const { accountIds, hasMore } = this.props; + + let loadMore = null; if (!accountIds) { return ( @@ -64,6 +67,10 @@ class Followers extends ImmutablePureComponent { ); } + if (hasMore) { + loadMore = ; + } + return ( @@ -73,7 +80,7 @@ class Followers extends ImmutablePureComponent {
{accountIds.map(id => )} - + {loadMore}
diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js index dd7ab4d46d..e7be0f084b 100644 --- a/app/javascript/mastodon/features/following/index.js +++ b/app/javascript/mastodon/features/following/index.js @@ -18,6 +18,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; const mapStateToProps = (state, props) => ({ accountIds: state.getIn(['user_lists', 'following', Number(props.params.accountId), 'items']), + hasMore: !!state.getIn(['user_lists', 'following', Number(props.params.accountId), 'next']), }); class Following extends ImmutablePureComponent { @@ -54,7 +55,9 @@ class Following extends ImmutablePureComponent { } render () { - const { accountIds } = this.props; + const { accountIds, hasMore } = this.props; + + let loadMore = null; if (!accountIds) { return ( @@ -64,6 +67,10 @@ class Following extends ImmutablePureComponent { ); } + if (hasMore) { + loadMore = ; + } + return ( @@ -73,7 +80,7 @@ class Following extends ImmutablePureComponent {
{accountIds.map(id => )} - + {loadMore}
-- GitLab From c26cea262b7673b0b239dd1da6754e7788aa08d8 Mon Sep 17 00:00:00 2001 From: unarist Date: Mon, 5 Jun 2017 22:20:46 +0900 Subject: [PATCH 145/295] Prevent pinned columns from scroll to top on URL changing (#3586) --- .../mastodon/components/status_list.js | 17 +++++++++++------ .../features/community_timeline/index.js | 1 + .../mastodon/features/hashtag_timeline/index.js | 1 + .../mastodon/features/home_timeline/index.js | 1 + .../mastodon/features/notifications/index.js | 15 ++++++++++++--- .../mastodon/features/public_timeline/index.js | 1 + 6 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/components/status_list.js b/app/javascript/mastodon/components/status_list.js index 9ee3af4d1e..39909d98bd 100644 --- a/app/javascript/mastodon/components/status_list.js +++ b/app/javascript/mastodon/components/status_list.js @@ -15,6 +15,7 @@ class StatusList extends ImmutablePureComponent { onScrollToBottom: PropTypes.func, onScrollToTop: PropTypes.func, onScroll: PropTypes.func, + trackScroll: PropTypes.bool, shouldUpdateScroll: PropTypes.func, isLoading: PropTypes.bool, isUnread: PropTypes.bool, @@ -88,7 +89,7 @@ class StatusList extends ImmutablePureComponent { } render () { - const { statusIds, onScrollToBottom, scrollKey, shouldUpdateScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props; + const { statusIds, onScrollToBottom, scrollKey, trackScroll, shouldUpdateScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props; let loadMore = null; let scrollableArea = null; @@ -126,11 +127,15 @@ class StatusList extends ImmutablePureComponent { ); } - return ( - - {scrollableArea} - - ); + if (trackScroll) { + return ( + + {scrollableArea} + + ); + } else { + return scrollableArea; + } } } diff --git a/app/javascript/mastodon/features/community_timeline/index.js b/app/javascript/mastodon/features/community_timeline/index.js index 6d25811410..1dd8a08ab3 100644 --- a/app/javascript/mastodon/features/community_timeline/index.js +++ b/app/javascript/mastodon/features/community_timeline/index.js @@ -124,6 +124,7 @@ class CommunityTimeline extends React.PureComponent { } diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js index 7f7b3e075b..da43e94033 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/hashtag_timeline/index.js @@ -120,6 +120,7 @@ class HashtagTimeline extends React.PureComponent { /> 0) { loadMore = ; @@ -149,6 +150,16 @@ class Notifications extends React.PureComponent { ); } + if (pinned) { + scrollContainer = scrollableArea; + } else { + scrollContainer = ( + + {scrollableArea} + + ); + } + this.scrollableArea = scrollableArea; return ( @@ -166,9 +177,7 @@ class Notifications extends React.PureComponent { - - {scrollableArea} - + {scrollContainer} ); } diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js index 001632004a..988e5a059c 100644 --- a/app/javascript/mastodon/features/public_timeline/index.js +++ b/app/javascript/mastodon/features/public_timeline/index.js @@ -125,6 +125,7 @@ class PublicTimeline extends React.PureComponent { } /> -- GitLab From 6201f96b8a49d58b5b2d73fac9fa1fa93f5890ed Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 5 Jun 2017 10:07:44 -0400 Subject: [PATCH 146/295] Introduce StatusThreadingConcern (#3490) * Add a StatusFilter class to identify visibility of statuses by accounts * Extract StatusThreadingConcern from Status * Clarify purpose of checking for nil account --- app/lib/status_filter.rb | 56 ++++++++++ .../concerns/status_threading_concern.rb | 89 ++++++++++++++++ app/models/status.rb | 30 +----- spec/lib/status_filter_spec.rb | 65 ++++++++++++ .../concerns/status_threading_concern_spec.rb | 100 ++++++++++++++++++ spec/models/status_spec.rb | 95 ----------------- 6 files changed, 311 insertions(+), 124 deletions(-) create mode 100644 app/lib/status_filter.rb create mode 100644 app/models/concerns/status_threading_concern.rb create mode 100644 spec/lib/status_filter_spec.rb create mode 100644 spec/models/concerns/status_threading_concern_spec.rb diff --git a/app/lib/status_filter.rb b/app/lib/status_filter.rb new file mode 100644 index 0000000000..89d45d442b --- /dev/null +++ b/app/lib/status_filter.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class StatusFilter + attr_reader :status, :account + + def initialize(status, account) + @status = status + @account = account + end + + def filtered? + account_present? && filtered_status? + end + + private + + def account_present? + !account.nil? + end + + def filtered_status? + blocking_account? || blocking_domain? || muting_account? || silenced_account? || blocked_by_policy? + end + + def blocking_account? + account.blocking? status.account_id + end + + def blocking_domain? + account.domain_blocking? status.account_domain + end + + def muting_account? + account.muting? status.account_id + end + + def silenced_account? + status_account_silenced? && !account_following_status_account? + end + + def status_account_silenced? + status.account.silenced? + end + + def account_following_status_account? + account.following? status.account_id + end + + def blocked_by_policy? + !policy_allows_show? + end + + def policy_allows_show? + StatusPolicy.new(account, status).show? + end +end diff --git a/app/models/concerns/status_threading_concern.rb b/app/models/concerns/status_threading_concern.rb new file mode 100644 index 0000000000..65f8e112e6 --- /dev/null +++ b/app/models/concerns/status_threading_concern.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +module StatusThreadingConcern + extend ActiveSupport::Concern + + def ancestors(account = nil) + find_statuses_from_tree_path(ancestor_ids, account) + end + + def descendants(account = nil) + find_statuses_from_tree_path(descendant_ids, account) + end + + private + + def ancestor_ids + Rails.cache.fetch("ancestors:#{id}") do + ancestors_without_self.pluck(:id) + end + end + + def ancestors_without_self + ancestor_statuses - [self] + end + + def ancestor_statuses + Status.find_by_sql([<<-SQL.squish, id: id]) + WITH RECURSIVE search_tree(id, in_reply_to_id, path) + AS ( + SELECT id, in_reply_to_id, ARRAY[id] + FROM statuses + WHERE id = :id + UNION ALL + SELECT statuses.id, statuses.in_reply_to_id, path || statuses.id + FROM search_tree + JOIN statuses ON statuses.id = search_tree.in_reply_to_id + WHERE NOT statuses.id = ANY(path) + ) + SELECT id + FROM search_tree + ORDER BY path DESC + SQL + end + + def descendant_ids + descendants_without_self.pluck(:id) + end + + def descendants_without_self + descendant_statuses - [self] + end + + def descendant_statuses + Status.find_by_sql([<<-SQL.squish, id: id]) + WITH RECURSIVE search_tree(id, path) + AS ( + SELECT id, ARRAY[id] + FROM statuses + WHERE id = :id + UNION ALL + SELECT statuses.id, path || statuses.id + FROM search_tree + JOIN statuses ON statuses.in_reply_to_id = search_tree.id + WHERE NOT statuses.id = ANY(path) + ) + SELECT id + FROM search_tree + ORDER BY path + SQL + end + + def find_statuses_from_tree_path(ids, account) + statuses = statuses_with_accounts(ids).to_a + + # FIXME: n+1 bonanza + statuses.reject! { |status| filter_from_context?(status, account) } + + # Order ancestors/descendants by tree path + statuses.sort_by! { |status| ids.index(status.id) } + end + + def statuses_with_accounts(ids) + Status.where(id: ids).includes(:account) + end + + def filter_from_context?(status, accou