diff --git a/.codeclimate.yml b/.codeclimate.yml
index 29701a77754..47e3e6ab9db 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -1,21 +1,36 @@
-engines:
+version: "2"
+checks:
+ argument-count:
+ enabled: false
+ complex-logic:
+ enabled: false
+ file-lines:
+ enabled: false
+ method-complexity:
+ enabled: false
+ method-count:
+ enabled: false
+ method-lines:
+ enabled: false
+ nested-control-flow:
+ enabled: false
+ return-statements:
+ enabled: false
+ similar-code:
+ enabled: false
+ identical-code:
+ enabled: false
+plugins:
brakeman:
enabled: true
bundler-audit:
enabled: true
- duplication:
- enabled: false
eslint:
enabled: true
rubocop:
enabled: true
scss-lint:
enabled: true
-ratings:
- paths:
- - "**.rb"
- - "**.js"
- - "**.scss"
-exclude_paths:
+exclude_patterns:
- spec/
- vendor/asset
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 7cec5718067..4b20fe971b5 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at eugen@zeonfederated.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at beatrix.bitrot@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
diff --git a/Gemfile.lock b/Gemfile.lock
index f9c69d53865..37fc77fdf7e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -24,11 +24,11 @@ GEM
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
- active_model_serializers (0.10.6)
+ active_model_serializers (0.10.7)
actionpack (>= 4.1, < 6)
activemodel (>= 4.1, < 6)
case_transform (>= 0.2)
- jsonapi-renderer (>= 0.1.1.beta1, < 0.2)
+ jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
active_record_query_trace (1.5.4)
activejob (5.1.4)
activesupport (= 5.1.4)
@@ -83,15 +83,15 @@ GEM
capistrano-bundler (1.3.0)
capistrano (~> 3.1)
sshkit (~> 1.2)
- capistrano-rails (1.3.0)
+ capistrano-rails (1.3.1)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
- capistrano-rbenv (2.1.2)
+ capistrano-rbenv (2.1.3)
capistrano (~> 3.1)
sshkit (~> 1.3)
capistrano-yarn (2.0.2)
capistrano (~> 3.0)
- capybara (2.15.4)
+ capybara (2.16.1)
addressable
mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
@@ -113,7 +113,7 @@ GEM
connection_pool (2.2.1)
crack (0.4.3)
safe_yaml (~> 1.0.0)
- crass (1.0.2)
+ crass (1.0.3)
debug_inspector (0.0.3)
devise (4.3.0)
bcrypt (~> 3.0)
@@ -121,11 +121,11 @@ GEM
railties (>= 4.1.0, < 5.2)
responders
warden (~> 1.2.3)
- devise-two-factor (3.0.0)
- activesupport
+ devise-two-factor (3.0.2)
+ activesupport (< 5.2)
attr_encrypted (>= 1.3, < 4, != 2)
devise (~> 4.0)
- railties
+ railties (< 5.2)
rotp (~> 2.0)
diff-lcs (1.3)
docile (1.1.5)
@@ -184,7 +184,7 @@ GEM
http (~> 2.2)
nokogiri (~> 1.8)
oj (~> 3.0)
- hamlit (2.8.4)
+ hamlit (2.8.5)
temple (>= 0.8.0)
thor
tilt
@@ -196,7 +196,7 @@ GEM
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashdiff (0.3.7)
- highline (1.7.8)
+ highline (1.7.10)
hiredis (0.6.1)
hkdf (0.3.0)
htmlentities (4.3.4)
@@ -213,9 +213,9 @@ GEM
httplog (0.99.7)
colorize
rack
- i18n (0.9.0)
+ i18n (0.9.1)
concurrent-ruby (~> 1.0)
- i18n-tasks (0.9.18)
+ i18n-tasks (0.9.19)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
easy_translate (>= 0.5.0)
@@ -236,8 +236,8 @@ GEM
json-ld (~> 2.1, >= 2.1.5)
multi_json (~> 1.11)
rdf (~> 2.2)
- jsonapi-renderer (0.1.3)
- jwt (1.5.6)
+ jsonapi-renderer (0.2.0)
+ jwt (2.1.0)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
@@ -267,8 +267,8 @@ GEM
loofah (2.1.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
- mail (2.6.6)
- mime-types (>= 1.16, < 4)
+ mail (2.7.0)
+ mini_mime (>= 0.1.1)
mario-redis-lock (1.2.0)
redis (~> 3, >= 3.0.5)
method_source (0.9.0)
@@ -279,7 +279,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
- mini_mime (0.1.4)
+ mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.10.3)
msgpack (1.1.0)
@@ -305,7 +305,7 @@ GEM
http (~> 2.0)
nokogiri (~> 1.6)
openssl (~> 2.0)
- ox (2.8.1)
+ ox (2.8.2)
paperclip (5.1.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
@@ -316,22 +316,22 @@ GEM
av (~> 0.9.0)
paperclip (>= 2.5.2)
parallel (1.12.0)
- parallel_tests (2.17.0)
+ parallel_tests (2.19.0)
parallel
- parser (2.4.0.0)
- ast (~> 2.2)
+ parser (2.4.0.2)
+ ast (~> 2.3)
pg (0.21.0)
pghero (1.7.0)
activerecord
pkg-config (1.2.8)
powerpack (0.1.1)
- pry (0.11.2)
+ pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-rails (0.3.6)
pry (>= 0.10.4)
- public_suffix (3.0.0)
- puma (3.10.0)
+ public_suffix (3.0.1)
+ puma (3.11.0)
pundit (1.1.0)
activesupport (>= 3.0.0)
rabl (0.13.1)
@@ -344,7 +344,7 @@ GEM
rack
rack-proxy (0.6.2)
rack
- rack-test (0.7.0)
+ rack-test (0.8.2)
rack (>= 1.0, < 3)
rack-timeout (0.4.2)
rails (5.1.4)
@@ -381,8 +381,11 @@ GEM
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
- rake (12.2.1)
- rdf (2.2.11)
+ rake (12.3.0)
+ rb-fsevent (0.10.2)
+ rb-inotify (0.9.10)
+ ffi (>= 0.5.0, < 2)
+ rdf (2.2.12)
hamster (~> 3.0)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.3.2)
@@ -395,8 +398,8 @@ GEM
redis-activesupport (5.0.4)
activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2)
- redis-namespace (1.5.3)
- redis (~> 3.0, >= 3.0.4)
+ redis-namespace (1.6.0)
+ redis (>= 3.0.4)
redis-rack (2.0.3)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
@@ -421,7 +424,7 @@ GEM
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
- rspec-rails (3.7.1)
+ rspec-rails (3.7.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@@ -449,10 +452,14 @@ GEM
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4.1)
- sass (3.4.25)
- scss_lint (0.55.0)
+ sass (3.5.3)
+ sass-listen (~> 4.0.0)
+ sass-listen (4.0.0)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ scss_lint (0.56.0)
rake (>= 0.9, < 13)
- sass (~> 3.4.20)
+ sass (~> 3.5.3)
sidekiq (5.0.5)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
@@ -486,7 +493,7 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
- sshkit (1.14.0)
+ sshkit (1.15.1)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
statsd-ruby (1.2.1)
@@ -514,7 +521,7 @@ GEM
uniform_notifier (1.10.0)
warden (1.2.7)
rack (>= 1.0)
- webmock (3.1.0)
+ webmock (3.1.1)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
@@ -522,12 +529,12 @@ GEM
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
railties (>= 4.2)
- webpush (0.3.2)
+ webpush (0.3.3)
hkdf (~> 0.2)
- jwt
+ jwt (~> 2.0)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
- websocket-extensions (0.1.2)
+ websocket-extensions (0.1.3)
xpath (2.1.0)
nokogiri (~> 1.3)
@@ -638,4 +645,4 @@ RUBY VERSION
ruby 2.4.2p198
BUNDLED WITH
- 1.15.4
+ 1.16.0
diff --git a/app/controllers/admin/account_moderation_notes_controller.rb b/app/controllers/admin/account_moderation_notes_controller.rb
index 7f69a33638e..7d5b9bf52c8 100644
--- a/app/controllers/admin/account_moderation_notes_controller.rb
+++ b/app/controllers/admin/account_moderation_notes_controller.rb
@@ -21,7 +21,7 @@ module Admin
def destroy
authorize @account_moderation_note, :destroy?
- @account_moderation_note.destroy
+ @account_moderation_note.destroy!
redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg')
end
diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb
index 0829bc769f4..e9a512e70cf 100644
--- a/app/controllers/admin/accounts_controller.rb
+++ b/app/controllers/admin/accounts_controller.rb
@@ -32,18 +32,21 @@ module Admin
def memorialize
authorize @account, :memorialize?
@account.memorialize!
+ log_action :memorialize, @account
redirect_to admin_account_path(@account.id)
end
def enable
authorize @account.user, :enable?
@account.user.enable!
+ log_action :enable, @account.user
redirect_to admin_account_path(@account.id)
end
def disable
authorize @account.user, :disable?
@account.user.disable!
+ log_action :disable, @account.user
redirect_to admin_account_path(@account.id)
end
diff --git a/app/controllers/admin/action_logs_controller.rb b/app/controllers/admin/action_logs_controller.rb
new file mode 100644
index 00000000000..e273dfeaef1
--- /dev/null
+++ b/app/controllers/admin/action_logs_controller.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Admin
+ class ActionLogsController < BaseController
+ def index
+ @action_logs = Admin::ActionLog.page(params[:page])
+ end
+ end
+end
diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb
index 72613450900..fc299f74c5f 100644
--- a/app/controllers/admin/base_controller.rb
+++ b/app/controllers/admin/base_controller.rb
@@ -3,6 +3,7 @@
module Admin
class BaseController < ApplicationController
include Authorization
+ include AccountableConcern
layout 'admin'
diff --git a/app/controllers/admin/confirmations_controller.rb b/app/controllers/admin/confirmations_controller.rb
index c10b0ebee89..34dfb458ec8 100644
--- a/app/controllers/admin/confirmations_controller.rb
+++ b/app/controllers/admin/confirmations_controller.rb
@@ -7,6 +7,7 @@ module Admin
def create
authorize @user, :confirm?
@user.confirm!
+ log_action :confirm, @user
redirect_to admin_accounts_path
end
diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb
index 509f7a48f76..3fa2a0b72e1 100644
--- a/app/controllers/admin/custom_emojis_controller.rb
+++ b/app/controllers/admin/custom_emojis_controller.rb
@@ -20,6 +20,7 @@ module Admin
@custom_emoji = CustomEmoji.new(resource_params)
if @custom_emoji.save
+ log_action :create, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.created_msg')
else
render :new
@@ -30,6 +31,7 @@ module Admin
authorize @custom_emoji, :update?
if @custom_emoji.update(resource_params)
+ log_action :update, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg')
else
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.update_failed_msg')
@@ -38,7 +40,8 @@ module Admin
def destroy
authorize @custom_emoji, :destroy?
- @custom_emoji.destroy
+ @custom_emoji.destroy!
+ log_action :destroy, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg')
end
@@ -49,6 +52,7 @@ module Admin
emoji.image = @custom_emoji.image
if emoji.save
+ log_action :create, emoji
flash[:notice] = I18n.t('admin.custom_emojis.copied_msg')
else
flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
@@ -60,12 +64,14 @@ module Admin
def enable
authorize @custom_emoji, :enable?
@custom_emoji.update!(disabled: false)
+ log_action :enable, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg')
end
def disable
authorize @custom_emoji, :disable?
@custom_emoji.update!(disabled: true)
+ log_action :disable, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg')
end
diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb
index e383dc8314d..64de2cbf0cf 100644
--- a/app/controllers/admin/domain_blocks_controller.rb
+++ b/app/controllers/admin/domain_blocks_controller.rb
@@ -21,6 +21,7 @@ module Admin
if @domain_block.save
DomainBlockWorker.perform_async(@domain_block.id)
+ log_action :create, @domain_block
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.created_msg')
else
render :new
@@ -34,6 +35,7 @@ module Admin
def destroy
authorize @domain_block, :destroy?
UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
+ log_action :destroy, @domain_block
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg')
end
diff --git a/app/controllers/admin/email_domain_blocks_controller.rb b/app/controllers/admin/email_domain_blocks_controller.rb
index 01058bf4677..9fe85064e34 100644
--- a/app/controllers/admin/email_domain_blocks_controller.rb
+++ b/app/controllers/admin/email_domain_blocks_controller.rb
@@ -20,6 +20,7 @@ module Admin
@email_domain_block = EmailDomainBlock.new(resource_params)
if @email_domain_block.save
+ log_action :create, @email_domain_block
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
else
render :new
@@ -28,7 +29,8 @@ module Admin
def destroy
authorize @email_domain_block, :destroy?
- @email_domain_block.destroy
+ @email_domain_block.destroy!
+ log_action :destroy, @email_domain_block
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg')
end
diff --git a/app/controllers/admin/invites_controller.rb b/app/controllers/admin/invites_controller.rb
new file mode 100644
index 00000000000..faccaa7c899
--- /dev/null
+++ b/app/controllers/admin/invites_controller.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Admin
+ class InvitesController < BaseController
+ def index
+ authorize :invite, :index?
+
+ @invites = filtered_invites.includes(user: :account).page(params[:page])
+ @invite = Invite.new
+ end
+
+ def create
+ authorize :invite, :create?
+
+ @invite = Invite.new(resource_params)
+ @invite.user = current_user
+
+ if @invite.save
+ redirect_to admin_invites_path
+ else
+ @invites = Invite.page(params[:page])
+ render :index
+ end
+ end
+
+ def destroy
+ @invite = Invite.find(params[:id])
+ authorize @invite, :destroy?
+ @invite.expire!
+ redirect_to admin_invites_path
+ end
+
+ private
+
+ def resource_params
+ params.require(:invite).permit(:max_uses, :expires_in)
+ end
+
+ def filtered_invites
+ InviteFilter.new(filter_params).results
+ end
+
+ def filter_params
+ params.permit(:available, :expired)
+ end
+ end
+end
diff --git a/app/controllers/admin/reported_statuses_controller.rb b/app/controllers/admin/reported_statuses_controller.rb
index 4f66ce708ae..535bd11d487 100644
--- a/app/controllers/admin/reported_statuses_controller.rb
+++ b/app/controllers/admin/reported_statuses_controller.rb
@@ -8,7 +8,7 @@ module Admin
def create
authorize :status, :update?
- @form = Form::StatusBatch.new(form_status_batch_params)
+ @form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_report_path(@report)
@@ -16,13 +16,15 @@ module Admin
def update
authorize @status, :update?
- @status.update(status_params)
+ @status.update!(status_params)
+ log_action :update, @status
redirect_to admin_report_path(@report)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
+ log_action :destroy, @status
render json: @status
end
diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb
index 745757ee82e..75db6b78aa4 100644
--- a/app/controllers/admin/reports_controller.rb
+++ b/app/controllers/admin/reports_controller.rb
@@ -25,12 +25,17 @@ module Admin
def process_report
case params[:outcome].to_s
when 'resolve'
- @report.update(action_taken_by_current_attributes)
+ @report.update!(action_taken_by_current_attributes)
+ log_action :resolve, @report
when 'suspend'
Admin::SuspensionWorker.perform_async(@report.target_account.id)
+ log_action :resolve, @report
+ log_action :suspend, @report.target_account
resolve_all_target_account_reports
when 'silence'
- @report.target_account.update(silenced: true)
+ @report.target_account.update!(silenced: true)
+ log_action :resolve, @report
+ log_action :silence, @report.target_account
resolve_all_target_account_reports
else
raise ActiveRecord::RecordNotFound
diff --git a/app/controllers/admin/resets_controller.rb b/app/controllers/admin/resets_controller.rb
index 00b590bf67b..3e27d01ac27 100644
--- a/app/controllers/admin/resets_controller.rb
+++ b/app/controllers/admin/resets_controller.rb
@@ -7,6 +7,7 @@ module Admin
def create
authorize @user, :reset_password?
@user.send_reset_password_instructions
+ log_action :reset_password, @user
redirect_to admin_accounts_path
end
diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb
index 8f86858279f..af7ec0740d2 100644
--- a/app/controllers/admin/roles_controller.rb
+++ b/app/controllers/admin/roles_controller.rb
@@ -7,12 +7,14 @@ module Admin
def promote
authorize @user, :promote?
@user.promote!
+ log_action :promote, @user
redirect_to admin_account_path(@user.account_id)
end
def demote
authorize @user, :demote?
@user.demote!
+ log_action :demote, @user
redirect_to admin_account_path(@user.account_id)
end
diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb
index e81290228ec..eed5fb6b574 100644
--- a/app/controllers/admin/settings_controller.rb
+++ b/app/controllers/admin/settings_controller.rb
@@ -13,14 +13,17 @@ module Admin
closed_registrations_message
open_deletion
timeline_preview
+ show_staff_badge
bootstrap_timeline_accounts
thumbnail
+ min_invite_role
).freeze
BOOLEAN_SETTINGS = %w(
open_registrations
open_deletion
timeline_preview
+ show_staff_badge
).freeze
UPLOAD_SETTINGS = %w(
diff --git a/app/controllers/admin/silences_controller.rb b/app/controllers/admin/silences_controller.rb
index 01fb292de0c..4c06a9c0cc7 100644
--- a/app/controllers/admin/silences_controller.rb
+++ b/app/controllers/admin/silences_controller.rb
@@ -6,13 +6,15 @@ module Admin
def create
authorize @account, :silence?
- @account.update(silenced: true)
+ @account.update!(silenced: true)
+ log_action :silence, @account
redirect_to admin_accounts_path
end
def destroy
authorize @account, :unsilence?
- @account.update(silenced: false)
+ @account.update!(silenced: false)
+ log_action :unsilence, @account
redirect_to admin_accounts_path
end
diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb
index b54a9b82476..5d4325f5744 100644
--- a/app/controllers/admin/statuses_controller.rb
+++ b/app/controllers/admin/statuses_controller.rb
@@ -26,7 +26,7 @@ module Admin
def create
authorize :status, :update?
- @form = Form::StatusBatch.new(form_status_batch_params)
+ @form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_account_statuses_path(@account.id, current_params)
@@ -34,13 +34,15 @@ module Admin
def update
authorize @status, :update?
- @status.update(status_params)
+ @status.update!(status_params)
+ log_action :update, @status
redirect_to admin_account_statuses_path(@account.id, current_params)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
+ log_action :destroy, @status
render json: @status
end
diff --git a/app/controllers/admin/suspensions_controller.rb b/app/controllers/admin/suspensions_controller.rb
index 778feea5e8e..5f222e12588 100644
--- a/app/controllers/admin/suspensions_controller.rb
+++ b/app/controllers/admin/suspensions_controller.rb
@@ -7,12 +7,14 @@ module Admin
def create
authorize @account, :suspend?
Admin::SuspensionWorker.perform_async(@account.id)
+ log_action :suspend, @account
redirect_to admin_accounts_path
end
def destroy
authorize @account, :unsuspend?
@account.unsuspend!
+ log_action :unsuspend, @account
redirect_to admin_accounts_path
end
diff --git a/app/controllers/admin/two_factor_authentications_controller.rb b/app/controllers/admin/two_factor_authentications_controller.rb
index 5a45d25cd0c..02210720325 100644
--- a/app/controllers/admin/two_factor_authentications_controller.rb
+++ b/app/controllers/admin/two_factor_authentications_controller.rb
@@ -7,6 +7,7 @@ module Admin
def destroy
authorize @user, :disable_2fa?
@user.disable_two_factor!
+ log_action :disable_2fa, @user
redirect_to admin_accounts_path
end
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 85eb2d60e29..b1a2ed57376 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -13,11 +13,9 @@ class Api::V1::AccountsController < Api::BaseController
end
def follow
- reblogs_arg = { reblogs: params[:reblogs] }
-
- FollowService.new.call(current_user.account, @account.acct, reblogs_arg)
+ FollowService.new.call(current_user.account, @account.acct, reblogs: params[:reblogs])
- options = @account.locked? ? {} : { following_map: { @account.id => reblogs_arg }, requested_map: { @account.id => false } }
+ options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: params[:reblogs] } }, requested_map: { @account.id => false } }
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
end
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 42e852c0493..f4247fd95ea 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -17,13 +17,16 @@ class Auth::RegistrationsController < Devise::RegistrationsController
def build_resource(hash = nil)
super(hash)
- resource.locale = I18n.locale
+
+ resource.locale = I18n.locale
+ resource.invite_code = params[:invite_code] if resource.invite_code.blank?
+
resource.build_account if resource.account.nil?
end
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up) do |u|
- u.permit({ account_attributes: [:username] }, :email, :password, :password_confirmation)
+ u.permit({ account_attributes: [:username] }, :email, :password, :password_confirmation, :invite_code)
end
end
@@ -36,7 +39,19 @@ class Auth::RegistrationsController < Devise::RegistrationsController
end
def check_enabled_registrations
- redirect_to root_path if single_user_mode? || !Setting.open_registrations
+ redirect_to root_path if single_user_mode? || !allowed_registrations?
+ end
+
+ def allowed_registrations?
+ Setting.open_registrations || (invite_code.present? && Invite.find_by(code: invite_code)&.valid_for_use?)
+ end
+
+ def invite_code
+ if params[:user]
+ params[:user][:invite_code]
+ else
+ params[:invite_code]
+ end
end
private
diff --git a/app/controllers/concerns/accountable_concern.rb b/app/controllers/concerns/accountable_concern.rb
new file mode 100644
index 00000000000..3cdcffc51c7
--- /dev/null
+++ b/app/controllers/concerns/accountable_concern.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module AccountableConcern
+ extend ActiveSupport::Concern
+
+ def log_action(action, target)
+ Admin::ActionLog.create(account: current_account, action: action, target: target)
+ end
+end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
new file mode 100644
index 00000000000..38d6c8d73e0
--- /dev/null
+++ b/app/controllers/invites_controller.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+class InvitesController < ApplicationController
+ include Authorization
+
+ layout 'admin'
+
+ before_action :authenticate_user!
+
+ def index
+ authorize :invite, :create?
+
+ @invites = Invite.where(user: current_user)
+ @invite = Invite.new(expires_in: 1.day.to_i)
+ end
+
+ def create
+ authorize :invite, :create?
+
+ @invite = Invite.new(resource_params)
+ @invite.user = current_user
+
+ if @invite.save
+ redirect_to invites_path
+ else
+ @invites = Invite.where(user: current_user)
+ render :index
+ end
+ end
+
+ def destroy
+ @invite = Invite.where(user: current_user).find(params[:id])
+ authorize @invite, :destroy?
+ @invite.expire!
+ redirect_to invites_path
+ end
+
+ private
+
+ def resource_params
+ params.require(:invite).permit(:max_uses, :expires_in)
+ end
+end
diff --git a/app/controllers/settings/migrations_controller.rb b/app/controllers/settings/migrations_controller.rb
new file mode 100644
index 00000000000..b18403a7f04
--- /dev/null
+++ b/app/controllers/settings/migrations_controller.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class Settings::MigrationsController < ApplicationController
+ layout 'admin'
+
+ before_action :authenticate_user!
+
+ def show
+ @migration = Form::Migration.new(account: current_account.moved_to_account)
+ end
+
+ def update
+ @migration = Form::Migration.new(resource_params)
+
+ if @migration.valid? && migration_account_changed?
+ current_account.update!(moved_to_account: @migration.account)
+ ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
+ redirect_to settings_migration_path, notice: I18n.t('migrations.updated_msg')
+ else
+ render :show
+ end
+ end
+
+ private
+
+ def resource_params
+ params.require(:migration).permit(:acct)
+ end
+
+ def migration_account_changed?
+ current_account.moved_to_account_id != @migration.account&.id
+ end
+end
diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb
new file mode 100644
index 00000000000..e85243e57e4
--- /dev/null
+++ b/app/helpers/admin/action_logs_helper.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+module Admin::ActionLogsHelper
+ def log_target(log)
+ if log.target
+ linkable_log_target(log.target)
+ else
+ log_target_from_history(log.target_type, log.recorded_changes)
+ end
+ end
+
+ def linkable_log_target(record)
+ case record.class.name
+ when 'Account'
+ link_to record.acct, admin_account_path(record.id)
+ when 'User'
+ link_to record.account.acct, admin_account_path(record.account_id)
+ when 'CustomEmoji'
+ record.shortcode
+ when 'Report'
+ link_to "##{record.id}", admin_report_path(record)
+ when 'DomainBlock', 'EmailDomainBlock'
+ link_to record.domain, "https://#{record.domain}"
+ when 'Status'
+ link_to record.account.acct, TagManager.instance.url_for(record)
+ end
+ end
+
+ def log_target_from_history(type, attributes)
+ case type
+ when 'CustomEmoji'
+ attributes['shortcode']
+ when 'DomainBlock', 'EmailDomainBlock'
+ link_to attributes['domain'], "https://#{attributes['domain']}"
+ when 'Status'
+ tmp_status = Status.new(attributes)
+ link_to tmp_status.account.acct, TagManager.instance.url_for(tmp_status)
+ end
+ end
+
+ def relevant_log_changes(log)
+ if log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)
+ log.recorded_changes.slice('domain')
+ elsif log.target_type == 'CustomEmoji' && log.action == :update
+ log.recorded_changes.slice('domain', 'visible_in_picker')
+ elsif log.target_type == 'User' && [:promote, :demote].include?(log.action)
+ log.recorded_changes.slice('moderator', 'admin')
+ elsif log.target_type == 'DomainBlock'
+ log.recorded_changes.slice('severity', 'reject_media')
+ elsif log.target_type == 'Status' && log.action == :update
+ log.recorded_changes.slice('sensitive')
+ end
+ end
+
+ def log_extra_attributes(hash)
+ safe_join(hash.to_a.map { |key, value| safe_join([content_tag(:span, key, class: 'diff-key'), '=', log_change(value)]) }, ' ')
+ end
+
+ def log_change(val)
+ return content_tag(:span, val, class: 'diff-neutral') unless val.is_a?(Array)
+ safe_join([content_tag(:span, val.first, class: 'diff-old'), content_tag(:span, val.last, class: 'diff-new')], '→')
+ end
+
+ def icon_for_log(log)
+ case log.target_type
+ when 'Account', 'User'
+ 'user'
+ when 'CustomEmoji'
+ 'file'
+ when 'Report'
+ 'flag'
+ when 'DomainBlock'
+ 'lock'
+ when 'EmailDomainBlock'
+ 'envelope'
+ when 'Status'
+ 'pencil'
+ end
+ end
+
+ def class_for_log_icon(log)
+ case log.action
+ when :enable, :unsuspend, :unsilence, :confirm, :promote, :resolve
+ 'positive'
+ when :create
+ opposite_verbs?(log) ? 'negative' : 'positive'
+ when :update, :reset_password, :disable_2fa, :memorialize
+ 'neutral'
+ when :demote, :silence, :disable, :suspend
+ 'negative'
+ when :destroy
+ opposite_verbs?(log) ? 'positive' : 'negative'
+ else
+ ''
+ end
+ end
+
+ private
+
+ def opposite_verbs?(log)
+ %w(DomainBlock EmailDomainBlock).include?(log.target_type)
+ end
+end
diff --git a/app/helpers/admin/filter_helper.rb b/app/helpers/admin/filter_helper.rb
index e0fae9d9a2c..73250cbf56e 100644
--- a/app/helpers/admin/filter_helper.rb
+++ b/app/helpers/admin/filter_helper.rb
@@ -3,8 +3,9 @@
module Admin::FilterHelper
ACCOUNT_FILTERS = %i(local remote by_domain silenced suspended recent username display_name email ip).freeze
REPORT_FILTERS = %i(resolved account_id target_account_id).freeze
+ INVITE_FILTER = %i(available expired).freeze
- FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS
+ FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER
def filter_link_to(text, link_to_params, link_class_params = link_to_params)
new_url = filtered_url_for(link_to_params)
diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/jsonld_helper.rb
index a3441e6f939..6c7c38070ac 100644
--- a/app/helpers/jsonld_helper.rb
+++ b/app/helpers/jsonld_helper.rb
@@ -9,6 +9,24 @@ module JsonLdHelper
value.is_a?(Array) ? value.first : value
end
+ # The url attribute can be a string, an array of strings, or an array of objects.
+ # The objects could include a mimeType. Not-included mimeType means it's text/html.
+ def url_to_href(value, preferred_type = nil)
+ single_value = if value.is_a?(Array) && !value.first.is_a?(String)
+ value.find { |link| preferred_type.nil? || ((link['mimeType'].presence || 'text/html') == preferred_type) }
+ elsif value.is_a?(Array)
+ value.first
+ else
+ value
+ end
+
+ if single_value.nil? || single_value.is_a?(String)
+ single_value
+ else
+ single_value['href']
+ end
+ end
+
def as_array(value)
value.is_a?(Array) ? value : [value]
end
diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 6662285d0ac..b0d9e375769 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -9,6 +9,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { MediaGallery, Video } from 'flavours/glitch/util/async-components';
import { HotKeys } from 'react-hotkeys';
import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container';
+import classNames from 'classnames';
// We use the component (and not the container) since we do not want
// to use the progress bar to show download progress
@@ -21,6 +22,7 @@ export default class Status extends ImmutablePureComponent {
};
static propTypes = {
+ containerId: PropTypes.string,
id: PropTypes.string,
status: ImmutablePropTypes.map,
account: ImmutablePropTypes.map,
@@ -59,6 +61,7 @@ export default class Status extends ImmutablePureComponent {
'muted',
'collapse',
'notification',
+ 'hidden',
]
updateOnStates = [
@@ -187,7 +190,9 @@ export default class Status extends ImmutablePureComponent {
}
handleExpandedToggle = () => {
- this.setExpansion(this.state.isExpanded || !this.props.status.get('spoiler') ? null : true);
+ if (this.props.status.get('spoiler_text')) {
+ this.setExpansion(this.state.isExpanded ? null : true);
+ }
};
handleOpenVideo = startTime => {
@@ -221,11 +226,11 @@ export default class Status extends ImmutablePureComponent {
}
handleHotkeyMoveUp = () => {
- this.props.onMoveUp(this.props.status.get('id'));
+ this.props.onMoveUp(this.props.containerId || this.props.id);
}
handleHotkeyMoveDown = () => {
- this.props.onMoveDown(this.props.status.get('id'));
+ this.props.onMoveDown(this.props.containerId || this.props.id);
}
handleRef = c => {
@@ -370,31 +375,24 @@ export default class Status extends ImmutablePureComponent {
openProfile: this.handleHotkeyOpenProfile,
moveUp: this.handleHotkeyMoveUp,
moveDown: this.handleHotkeyMoveDown,
+ toggleSpoiler: this.handleExpandedToggle,
};
+ const computedClass = classNames('status', `status-${status.get('visibility')}`, {
+ collapsed: isExpanded === false,
+ 'has-background': isExpanded === false && background,
+ 'marked-for-delete': this.state.markedForDelete,
+ muted,
+ }, 'focusable');
+
return (
r |
+ |
m |
+ |
f |
+ |
b |
+ |
enter |
+ |
up |
+ |
down |
+ |
1 -9 |
+ |
n |
+ |
alt +n |
+ |
backspace |
+ |
s |
+ |
esc |
+ |
? |
+
Encara no s'ha configurat la descripció ampliada.
features: - humane_approach_body: Aprenent dels errors d'altres xarxes, Mastodon té com a objectiu fer ètiques eleccions de disseny per combatre el mal ús de les xarxes socials. + humane_approach_body: Aprenent dels errors d'altres xarxes, Mastodon té com a objectiu fer eleccions ètiques de disseny per a combatre el mal ús de les xarxes socials. humane_approach_title: Un enfocament més humà - not_a_product_body: Mastodon no és una xarxa comercial. Sense publicitat, sense mineria de dades, sense jardins amurallats. No hi ha autoritat central. + not_a_product_body: Mastodon no és una xarxa comercial. Sense publicitat, sense mineria de dades, sense jardins emmurallats. No hi ha autoritat central. not_a_product_title: Ets una persona, no un producte real_conversation_body: Amb 500 caràcters a la teva disposició i suport per a continguts granulars i avisos multimèdia, pots expressar-te de la manera que vulguis. real_conversation_title: Construït per a converses reals - within_reach_body: Diverses aplicacions per a iOS, Android i altres plataformes gràcies a un ecosistema API amable amb el desenvolupador, et permet mantenir-te al dia amb els teus amics en qualsevol lloc.. + within_reach_body: Diverses aplicacions per a iOS, Android i altres plataformes gràcies a un ecosistema API amable amb el desenvolupador, et permet mantenir-te al dia amb els amics en qualsevol lloc.. within_reach_title: Sempre a l'abast find_another_instance: Troba altres instàncies generic_description: "%{domain} és un servidor a la xarxa" hosted_on: Mastodon allotjat a %{domain} - learn_more: Aprèn més + learn_more: Més informació other_instances: Altres instàncies source_code: Codi font status_count_after: estats - status_count_before: Que han escrit + status_count_before: que han escrit user_count_after: usuaris registrats user_count_before: Tenim what_is_mastodon: Què és Mastodon? accounts: - follow: Seguir + follow: Segueix followers: Seguidors following: Seguint + media: Mèdia + moved_html: "%{name} s'ha mogut a %{new_profile_link}:" nothing_here: No hi ha res aquí! people_followed_by: Usuaris a qui %{name} segueix - people_who_follow: Usuaris que segueixn a %{name} + people_who_follow: Usuaris que segueixen %{name} posts: Toots - remote_follow: Seguir + posts_with_replies: Toots i respostes + remote_follow: Seguiment remot reserved_username: El nom d'usuari està reservat + roles: + admin: Admin + moderator: Mod unfollow: Deixar de seguir admin: + account_moderation_notes: + account: Moderador + create: Crear + created_at: Data + created_msg: La nota de moderació s'ha creat correctament. + delete: Suprimeix + destroyed_msg: S'ha destruït la nota de moderació. accounts: are_you_sure: Estàs segur? + by_domain: Domini confirm: Confirma confirmed: Confirmat + demote: Degrada + disable: Inhabilita disable_two_factor_authentication: Desactivar 2FA + disabled: Inhabilita display_name: Nom de visualització domain: Domini edit: Editar email: E-mail + enable: Habilitar + enabled: Habilitat feed_url: URL del feed followers: Seguidors + followers_url: URL dels seguidors follows: Segueix + inbox_url: URL de la safata d'entrada ip: IP location: all: Tot local: Local remote: Remot title: Localització + login_status: Estat d'accés media_attachments: Adjunts multimèdia + memorialize: Es converteix en memoriam moderation: all: Tot silenced: Silenciat suspended: Suspès title: Moderació + moderation_notes: Notes de moderació most_recent_activity: Activitat més recent most_recent_ip: IP més recent not_subscribed: No subscrit @@ -76,64 +101,109 @@ ca: alphabetic: Alfabètic most_recent: Més recent title: Ordre + outbox_url: URL de la bústia de sortida perform_full_suspension: Aplicar suspensió completa profile_url: URL del perfil + promote: Promociona + protocol: Protocol public: Públic push_subscription_expires: La subscripció PuSH expira redownload: Refrescar avatar reset: Reajustar reset_password: Restablir la contrasenya resubscribe: Resubscribir + role: Permisos + roles: + admin: Administrador + moderator: Moderador + user: Usuari salmon_url: URL Salmon search: Cerca + shared_inbox_url: URL de la safata d'entrada compartida show: created_reports: Informes creats per aquest compte report: informe targeted_reports: Informes realitzats sobre aquest compte silence: Silenci statuses: Estats - subscribe: Subscribir + subscribe: Subscriu title: Comptes - undo_silenced: Desfer silenci - undo_suspension: Desfer suspensió + undo_silenced: Deixa de silenciar + undo_suspension: Desfés la suspensió unsubscribe: Donar-se de baixa username: Nom d'usuari web: Web + custom_emojis: + copied_msg: S'ha creat correctament la còpia local del emoji + copy: Copia + copy_failed_msg: No s'ha pogut fer una còpia local d'aquest emoji + created_msg: Emoji creat amb èxit! + delete: Suprimeix + destroyed_msg: Emojo s'ha destruït amb èxit! + disable: Inhabilita + disabled_msg: S'ha inhabilitat l'emoji amb èxit + emoji: Emoji + enable: Habilita + enabled_msg: S'ha habilitat amb èxit emoji + image_hint: PNG de fins a 50 KB + listed: Enumerat + new: + title: Afegeix nou emoji personalitzat + overwrite: Sobreescriure + shortcode: Codi curt + shortcode_hint: Com a mínim 2 caràcters, només caràcters alfanumèrics i guions baixos + title: Emojis personatlitzats + unlisted: Sense classificar + update_failed_msg: No s'ha pogut actualitzar aquest emoji + updated_msg: Emoji s'ha actualitzat correctament. + upload: Carrega domain_blocks: - add_new: Afegir nou + add_new: Afegeix created_msg: El bloqueig de domini ara s'està processant destroyed_msg: El bloqueig de domini s'ha desfet domain: Domini new: - create: Crear bloqueig + create: Crea un bloqueig hint: El bloqueig de domini no impedirà la creació de nous comptes en la base de dades, però s´aplicaran mètodes de moderació específics sobre aquests comptes severity: - desc_html: "Silenci farà les publicacions del compte invisibles a tothom que no l'estigui seguint. Suspendre eliminarà tots els continguts, multimèdia i les dades del perfil del compte." + desc_html: "Silenci farà les publicacions del compte invisibles a tothom que no l'estigui seguint. La suspencsió eliminarà tots els continguts, multimèdia i les dades del perfil del compte." noop: Cap silence: Silenci - suspend: Suspendre + suspend: Suspensió title: Nou bloqueig de domini - reject_media: Rebutjar arxius multimèdia - reject_media_hint: Elimina arxius multimèdia emmagatzamats localment i impideix descarregar cap en el futur. Irrellevant per suspensions + reject_media: Rebutja els fitxers multimèdia + reject_media_hint: Elimina els fitxers multimèdia emmagatzamats localment i impideix descarregar-ne cap en el futur. Irrellevant en les suspensions severities: noop: Cap silence: Silenci - suspend: Suspendre + suspend: Suspensió severity: Severitat show: affected_accounts: 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 - title: Desfer el bloqueig de domini de %{domain} - undo: Desfer + silence: Desfés el silenci a tots els comptes existents d'aquest domini + suspend: Desfés la suspensió de tots els comptes d'aquest domini + title: Desfés el bloqueig de domini de %{domain} + undo: Desfés title: Bloquejos de domini undo: Desfer + email_domain_blocks: + add_new: Afegir nou + created_msg: S'ha creat el bloc de domini de correu electrònic + delete: Suprimeix + destroyed_msg: S'ha eliminat correctament el bloc del domini de correu + domain: Domini + new: + create: Crear bloc + title: Nou bloc de domini de correu electrònic + title: Bloc de domini de correu electrònic instances: account_count: Comptes coneguts domain_name: Domini + reset: Restablir + search: Cerca title: Instàncies conegudes reports: action_taken_by: Mesures adoptades per @@ -141,48 +211,57 @@ ca: comment: label: Comentari none: Cap - delete: Esborra + delete: Suprimeix id: ID mark_as_resolved: Marca com a resolt nsfw: - 'false': NSFW OFF - 'true': NSFW ON + 'false': Mostra els fitxers multimèdia adjunts + 'true': Amaga els fitxers multimèdia adjunts report: 'Informe #%{id}' report_contents: Continguts reported_account: Compte reportat reported_by: Reportat per resolved: Resolt - silence_account: Silenciar compte + silence_account: Silencia el compte status: Estat - suspend_account: Suspendre compte + suspend_account: Suspèn el compte target: Objectiu title: Informes unresolved: No resolt - view: Vista + view: Visualització settings: + bootstrap_timeline_accounts: + desc_html: Separa diversos noms d'usuari amb comes. Només funcionaran els comptes locals i desbloquejats. El valor predeterminat quan està buit és tots els administradors locals.. + title: El seguiment per defecte per als nous usuaris contact_information: - email: Introduir una adreça de correu electrònic pùblica - username: Introduir un nom d'usuari + email: Introdueix una adreça de correu electrònic pùblica + username: Introdueix un nom d'usuari registrations: closed_message: - desc_html: Apareix en la primera pàgina quan es tanquen els registres<a>
i <em>
.
title: Descripció del lloc
site_description_extended:
- desc_html: Un bon lloc per al vostre codi de conducta, regles, directrius i altres coses que distingeixen la vostra instància. Podeu utilitzar etiquetes HTML
- title: Descripció estesa del lloc
+ desc_html: Un bon lloc per al codi de conducta, regles, directrius i altres coses que distingeixen la vostra instància. Pots utilitzar etiquetes HTML
+ title: Descripció ampliada del lloc
site_terms:
desc_html: Pots escriure la teva pròpia política de privadesa, els termes del servei o d'altres normes legals. Pots utilitzar etiquetes HTML
title: Termes del servei personalitzats
site_title: Títol del lloc
+ thumbnail:
+ desc_html: S'utilitza per obtenir visualitzacions prèvies a través d'OpenGraph i API. Es recomana 1200x630px
+ title: Miniatura de la Instància
timeline_preview:
desc_html: Mostra la línia de temps pública a la pàgina inicial
title: Vista prèvia de la línia de temps
@@ -190,18 +269,18 @@ ca:
statuses:
back_to_account: Torna a la pàgina del compte
batch:
- delete: Esborra
+ delete: Suprimeix
nsfw_off: NSFW OFF
nsfw_on: NSFW ON
execute: Executa
failed_to_execute: No s'ha pogut executar
media:
- hide: Amaga multimèdia
- show: Mostra multimèdia
- title: Multimèdia
- no_media: Sense multimèdia
+ hide: Amaga el contingut multimèdia
+ show: Mostra el contingut multimèdia
+ title: Contingut multimèdia
+ no_media: Sense contingut multimèdia
title: Estats del compte
- with_media: Amb multimèdia
+ with_media: Amb contingut multimèdia
subscriptions:
callback_url: Callback URL
confirmed: Confirmat
@@ -216,127 +295,137 @@ ca:
subject: Nou informe per a %{instance} (#%{id})
application_mailer:
salutation: "%{name},"
- settings: 'Canviar preferències de correu: %{link}'
- signature: Notificacions de Mastodon desde %{instance}
+ settings: 'Canvia les preferències de correu: %{link}'
+ signature: Notificacions de Mastodon des de %{instance}
view: 'Vista:'
applications:
+ created: L'aplicació s'ha creat correctament
+ destroyed: L'aplicació s'ha suprimit correctament
invalid_url: La URL proporcionada es incorrecte
+ regenerate_token: Regenerar token d'accés
+ token_regenerated: Token d'accés s'ha generat correctament
+ warning: Aneu amb compte amb aquestes dades. No ho compartiu mai amb ningú!
+ your_token: El token d'accés
auth:
- agreement_html: En inscriure't, acceptes les nostres termes del servei i la nostra política de privadesa.
- change_password: Canviar contrasenya
- delete_account: Esborrar el compte
- delete_account_html: Si vols esborrar el teu compte pots fer-ho aquí. S'et demanarà confirmació.
- didnt_get_confirmation: No vas rebre el correu de confirmació?
+ agreement_html: En inscriure't, acceptes els nostres termes del servei i la nostra política de privadesa.
+ change_password: Canvia la contrasenya
+ delete_account: Esborra el compte
+ delete_account_html: Si vols esborrar el teu compte pots fer-ho aquí. Se't demanarà confirmació.
+ didnt_get_confirmation: No ha rebut el correu de confirmació?
forgot_password: Has oblidat la contrasenya?
- invalid_reset_password_token: L'enllaç de restabliment de la contrasenya no és vàlid o caducat. Siusplau torna-ho a provar..
- login: Iniciar sessió
- logout: Tancar sessió
- register: Enregistrarse
- resend_confirmation: Tornar a enviar el correu de confirmació
- reset_password: Restablir contrasenya
- set_new_password: Establir nova contrasenya
+ invalid_reset_password_token: L'enllaç de restabliment de la contrasenya no és vàlid o ha caducat. Torna-ho a provar..
+ login: Inicia sessió
+ logout: Tanca sessió
+ register: Registra't
+ resend_confirmation: Torna a enviar el correu de confirmació
+ reset_password: Restableix la contrasenya
+ set_new_password: Estableix nova contrasenya
authorize_follow:
error: Malauradament, ha ocorregut un error buscant el compte remot
- follow: Seguir
+ follow: Segueix
follow_request: 'Heu enviat una sol·licitud de seguiment a:'
- following: 'Èxit! Ara segueixes:'
+ following: 'Perfecte! Ara segueixes:'
post_follow:
close: O bé, pots tancar aquesta finestra.
return: Torna al perfil de l'usuari
- web: Anar a la web
- title: Seguir %{acct}
+ web: Vés a la web
+ title: Segueix %{acct}
datetime:
distance_in_words:
- about_x_hours: "%{count}h"
- about_x_months: "%{count}m"
- about_x_years: "%{count}y"
- almost_x_years: "%{count}y"
+ about_x_hours: "%{count} h"
+ about_x_months: "%{count} mesos"
+ about_x_years: "%{count} anys"
+ almost_x_years: "%{count}anys"
half_a_minute: Ara mateix
less_than_x_minutes: "%{count}m"
less_than_x_seconds: Ara mateix
- over_x_years: "%{count}y"
- x_days: "%{count}d"
- x_minutes: "%{count}m"
- x_months: "%{count}m"
- x_seconds: "%{count}s"
+ over_x_years: "%{count} anys"
+ x_days: "%{count} dies"
+ x_minutes: "%{count} min"
+ x_months: "%{count} mesos"
+ x_seconds: "%{count} s"
deletes:
- bad_password_msg: Bon intent hackers! Contrasenya incorrecta
- confirm_password: Introdueix la contrasenya actual per verificar la teva identitat
+ bad_password_msg: Bon intent hackers! La contrasenya no és correcta
+ confirm_password: Introdueix la contrasenya actual per a verificar la teva identitat
description_html: Això eliminarà de forma irreversible i permanent el contingut del teu compte i el desactivarà. El teu nom d'usuari romandrà reservat per evitar que algú volgués fer-se passar per tu.
- proceed: Esborrar el compte
+ proceed: Suprimir el compte
success_msg: El teu compte s'ha eliminat correctament
warning_html: Només està garantida l'eliminació d'aquesta particular instància. El contingut que ha estat àmpliament compartit que deixi petjades. Els servidors fora de línia i els que ja no estan subscrits no actualitzaran les seves bases de dades.
warning_title: Disponibilitat de contingut disseminat
errors:
- '403': No tens permís per veure aquesta pàgina.
- '404': La pàgina que estàs buscant no existeix.
- '410': La pàgina que estaves buscant ja no existeix.
+ '403': No tens permís per a veure aquesta pàgina.
+ '404': La pàgina que estàs cercant no existeix.
+ '410': La pàgina que estàs cercant ja no existeix.
'422':
- content: La verificació de seguretat ha fallat. Bloquejes les galetes?
+ content: La verificació de seguretat ha fallat. Bloques les galetes?
title: La verificació de seguretat ha fallat
'429': Estrangulat
- noscript_html: Per utilitzar Mastodon si us plau activa JavaScript.
+ '500':
+ content: We're sorry, but something went wrong on our end.
+ title: This page is not correct
+ noscript_html: Per utilitzar Mastodon si us plau activa JavaScript. També podeu provar una de les aplicacions natives per Mastodon per a la vostra plataforma.
exports:
blocks: Persones que has bloquejat
csv: CSV
follows: Persones que segueixes
- mutes: Persones apagades (muted)
+ mutes: Persones silenciades
storage: Emmagatzematge
followers:
domain: Domini
- explanation_html: Si desitges garantir la privacitat de les teves publicacions, has de ser conscient de qui t'està seguint. Les teves publicacions privades es lliuren a totes les instàncies on es té seguidors strong>. És possible que vulguis revisar-los i eliminar seguidors si no confies en que la teva privacitat sigui respectada pel personal o el programari d'aquests casos
+ explanation_html: Si desitges garantir la privacitat de les teves publicacions, has de ser conscient de qui t'està seguint. Les publicacions privades es lliuren a totes les instàncies on tens seguidors strong>. És possible que vulguis revisar-los i eliminar seguidors si no confies en que la teva privacitat sigui respectada pel personal o el programari d'aquests casos
followers_count: Nombre de seguidors
- lock_link: Bloqueja el teu compte
- purge: Eliminar de seguidors
+ lock_link: Bloca el teu compte
+ purge: Elimina dels seguidors
success:
one: En el procés de bloqueig suau de seguidors d'un domini...
other: En el procés de bloqueig suau de seguidors de %{count} dominis...
- true_privacy_html: Si us plau considera que la autèntica privacitat només es pot aconseguir amb xifrat d'extrem a extrem.
- 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
+ true_privacy_html: Considera que la autèntica privacitat només es pot aconseguir amb xifratge d'extrem a extrem.
+ unlocked_warning_html: Tothom pot seguir-te per a veure inmediatament les teves publicacions privades. %{lock_link} per poder revisar i rebutjar seguidors.
+ unlocked_warning_title: El teu compte no està blocat
generic:
- changes_saved_msg: Canvis guardats amb èxit!
- powered_by: powered by %{link}
- save_changes: Guardar canvis
+ changes_saved_msg: Els canvis s'han desat correctament!
+ powered_by: amb tecnologia %{link}
+ save_changes: Desa els 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 va bé! Si us plau, revisa l'error
+ other: Alguna cosa no va bé! Si us plau, revisa %{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
+ preface: Pots importar algunes dades, com ara totes les persones que estàs seguint o blocant, en el teu compte en aquesta instància, des de fitxers exportats en una altra instància.
+ success: Les dades s'han rebut correctament i es processaran en breu
types:
- blocking: Llista de bloqueajats
+ blocking: Llista de blocats
following: Llista de seguits
muting: Llista d'apagats
upload: Carregar
+ in_memoriam_html: En Memòria.
landing_strip_html: "%{name} és un usuari/a de %{link_to_root_path}. Pots seguir-lo/la o interactuar amb ell/a si tens un compte a qualsevol node del fediverse."
landing_strip_signup_html: Si no en tens, pots registrar-te aquí.
media_attachments:
validations:
images_and_video: No es pot adjuntar un vídeo a una publicació que ja contingui imatges
- too_many: No es poden adjuntar més de 4 arxius
+ too_many: No es poden adjuntar més de 4 fitxers
notification_mailer:
digest:
- body: 'Un resum del que et vas perdre en %{instance} desde la teva darrera visita el %{since}:'
+ body: 'Un resum del que et vas perdre en %{instance} desde la 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
+ other: Genial!. Et segueixen %{count} persones més
subject:
- one: "1 nova notificació desde la teva darrera visita \U0001F418"
- other: "%{count} noves notificacions desde la teva darrera visita \U0001F418"
+ one: "1 notificació nova des de la darrera visita \U0001F418"
+ other: "%{count} notificacions noves des de la darrera visita \U0001F418"
favourite:
- body: 'El teu estat ha estat marcat com a favorit per %{name}:'
+ body: "%{name} ha marcat com a favorit el teu estat:"
subject: "%{name} ha marcat com a favorit el teu estat"
follow:
- body: "¡%{name} t'està seguint!"
+ body: "%{name} t'està seguint!"
subject: "%{name} t'està seguint"
follow_request:
body: "%{name} ha sol·licitat seguir-te"
subject: 'Seguidor pendent: %{name}'
mention:
- body: 'Has estat mencionat per %{name} en:'
- subject: Has estat mencionat per %{name}
+ body: "%{name} t'ha mencionat en:"
+ subject: "%{name} t'ha mencionat"
reblog:
body: "%{name} ha retootejat el teu estat"
subject: "%{name} ha retootejat el teu estat"
@@ -348,31 +437,36 @@ ca:
billion: B
million: M
quadrillion: Q
- thousand: K
+ thousand: m
trillion: T
unit: ''
pagination:
- next: Pròxim
- prev: Anterior
+ next: Següent
+ prev: Enrere
truncate: "…"
+ preferences:
+ languages: Idiomes
+ other: Altre
+ publishing: Publicació
+ web: Web
push_notifications:
favourite:
- title: "%{name} ha afavorit el teu estat"
+ title: "%{name} ha marcat com a preferit el teu estat"
follow:
title: "%{name} ara et segueix"
group:
title: "%{count} notificacions"
mention:
- action_boost: Boost
- action_expand: Mostra més
- action_favourite: Favorit
+ action_boost: Retooteja
+ action_expand: Mostra'n més
+ action_favourite: Preferit
title: "%{name} t'ha mencionat"
reblog:
title: "%{name} t'ha retootejat"
remote_follow:
- acct: Escriu el usuari@domini de la persona que vols seguir
- missing_resource: No s'ha pogut trobar la URL de redirecció necessaria per el compte.
- proceed: Procedir a seguir
+ acct: Escriu l'usuari@domini de la persona que vols seguir
+ missing_resource: No s'ha pogut trobar la URL de redirecció necessaria per al compte.
+ proceed: Comença a seguir
prompt: 'Seguiràs a:'
sessions:
activity: Última activitat
@@ -395,7 +489,7 @@ ca:
weibo: Weibo
current_session: Sessió actual
description: "%{browser} de %{platform}"
- explanation: Aquests són els navegadors web que actualment han iniciat la sessió al teu compte de Mastodon.
+ explanation: Aquests són els navegadors web que actualment han iniciat la sessió amb el teu compte de Mastodon.
ip: IP
platforms:
adobe_air: Adobe Air
@@ -415,53 +509,129 @@ ca:
title: Sessions
settings:
authorized_apps: Aplicacions autoritzades
- back: Tornar al inici
+ back: Torna a l'inici
delete: Eliminació del compte
+ development: Desenvolupament
edit_profile: Editar perfil
export: Exportar informació
followers: Seguidors autoritzats
import: Importar
+ notifications: Notificacions
preferences: Preferències
settings: Configuració
two_factor_authentication: Autenticació de dos factors
+ your_apps: Les teves aplicacions
statuses:
- open_in_web: Obrir en la web
+ open_in_web: Obre en la web
over_character_limit: Límit de caràcters de %{max} superat
+ pin_errors:
+ limit: S'han fixat massa toots
+ ownership: El toot d'algú altre no es pot fixar
+ private: No es pot fixar el toot no públic
+ reblog: No es pot fixar un impuls
show_more: Mostrar més
visibilities:
private: Només seguidors
- private_long: Només mostrar a seguidors
+ private_long: Mostra només als seguidors
public: Públic
public_long: Tothom pot veure-ho
unlisted: No llistat
unlisted_long: Tothom ho pot veure, però no es mostra en la història federada
stream_entries:
click_to_show: Clic per mostrar
- reblogged: retooteado
+ pinned: Toot fixat
+ reblogged: impulsat
sensitive_content: Contingut sensible
terms:
- body_html: "Recopilem informació teva quan et registres en aquesta instància i recopilem dades quan participes en el fòrum llegint, escrivint i avaluant el contingut aquí compartit.
\n\nEn registrar-te en aquesta instància, se't pot demanar que introduexisu el teu nom i l'adreça de correu electrònic. També pots visitar el nostre lloc sense registrar-te. La teva adreça de correu electrònic es verificarà mitjançant un correu electrònic que conté un enllaç únic. Si es visita aquest enllaç, sabem que controles l'adreça de correu electrònic.
\n\nQuan es registra i publica, registrem l'adreça IP de la qual es va originar la publicació. També podrem conservar els registres del servidor que inclouen l'adreça IP de cada sol·licitud al nostre servidor.
\n\nQualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:
\n\nImplementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.
\n\nFarem un esforç de bona fe per a:
\n\nSí. Les cookies són fitxers petits que un lloc o el proveïdor de serveis transfereix al disc dur del vostre ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el vostre navegador i, si teniu un compte registrat, associar-lo al vostre compte registrat.
\n\nUtilitzem cookies per comprendre i desar les vostres preferències per a futures visites i compilar dades agregades sobre el trànsit del lloc i la interacció del lloc, de manera que podrem oferir millors experiències i eines del lloc en el futur. Podem contractar amb proveïdors de serveis de tercers per ajudar-nos a comprendre millor els visitants del nostre lloc. Aquests proveïdors de serveis no estan autoritzats a utilitzar la informació recollida en nom nostre, excepte per ajudar-nos a dur a terme i millorar el nostre negoci.
\n\nNo venem, comercialitzem ni transmetem a tercers la vostra informació d'identificació personal. Això no inclou tercers de confiança que ens ajudin a operar el nostre lloc, a dur a terme el nostre negoci o a fer-ho, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la vostra informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat. No obstant això, la informació de visitant que no sigui personalment identificable es pot proporcionar a altres parts per a la comercialització, la publicitat o altres usos.
\n\nDe tant en tant, segons el nostre criteri, podem incloure o oferir productes o serveis de tercers al nostre lloc. Aquests llocs de tercers tenen polítiques de privadesa separades i independents. Per tant, no tenim responsabilitat ni responsabilitat civil pel contingut i les activitats d'aquests llocs enllaçats. No obstant això, busquem protegir la integritat del nostre lloc i donem la benvinguda a qualsevol comentari sobre aquests llocs.
\n\nEl nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si aquest servidor es troba als EUA, i teniu menys de 13 anys, segons els requisits de COPPA (Children's Online Privacy Protection Act) no feu servir aquest lloc.
\n\nAquesta política de privacitat en línia només s'aplica a la informació recopilada a través del nostre lloc i no a la informació recopilada fora de línia.
\n\nEn utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.
\n\nSi decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.
\n\nAquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.
\n\nOriginalment adaptat a la política de privadesa del Discurs.
\n" + body_html: | +Recopilem informació teva quan et registres en aquesta instància i recopilem dades quan participes en el fòrum llegint, escrivint i avaluant el contingut aquí compartit.
+ +En registrar-te en aquesta instància, se't pot demanar que introduexisu el teu nom i l'adreça de correu electrònic. També pots visitar el nostre lloc sense registrar-te. La teva adreça de correu electrònic es verificarà mitjançant un correu electrònic que conté un enllaç únic. Si es visita aquest enllaç, sabem que controles l'adreça de correu electrònic.
+ +Quan es registra i publica, registrem l'adreça IP de la qual es va originar la publicació. També podrem conservar els registres del servidor que inclouen l'adreça IP de cada sol·licitud al nostre servidor.
+ +Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:
+ +Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.
+ +Farem un esforç de bona fe per a:
+ +Sí. Les cookies són fitxers petits que un lloc o el proveïdor de serveis transfereix al disc dur del vostre ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el vostre navegador i, si teniu un compte registrat, associar-lo al vostre compte registrat.
+ +Utilitzem cookies per comprendre i desar les vostres preferències per a futures visites i compilar dades agregades sobre el trànsit del lloc i la interacció del lloc, de manera que podrem oferir millors experiències i eines del lloc en el futur. Podem contractar amb proveïdors de serveis de tercers per ajudar-nos a comprendre millor els visitants del nostre lloc. Aquests proveïdors de serveis no estan autoritzats a utilitzar la informació recollida en nom nostre, excepte per ajudar-nos a dur a terme i millorar el nostre negoci.
+ +No venem, comercialitzem ni transmetem a tercers la vostra informació d'identificació personal. Això no inclou tercers de confiança que ens ajudin a operar el nostre lloc, a dur a terme el nostre negoci o a fer-ho, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la vostra informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat. No obstant això, la informació de visitant que no sigui personalment identificable es pot proporcionar a altres parts per a la comercialització, la publicitat o altres usos.
+ +De tant en tant, segons el nostre criteri, podem incloure o oferir productes o serveis de tercers al nostre lloc. Aquests llocs de tercers tenen polítiques de privadesa separades i independents. Per tant, no tenim responsabilitat ni responsabilitat civil pel contingut i les activitats d'aquests llocs enllaçats. No obstant això, busquem protegir la integritat del nostre lloc i donem la benvinguda a qualsevol comentari sobre aquests llocs.
+ +El nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si aquest servidor es troba als EUA, i teniu menys de 13 anys, segons els requisits de COPPA (Children's Online Privacy Protection Act) no feu servir aquest lloc.
+ +Aquesta política de privacitat en línia només s'aplica a la informació recopilada a través del nostre lloc i no a la informació recopilada fora de línia.
+ +En utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.
+ +Si decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.
+ +Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.
+ +Originalment adaptat a la política de privadesa del Discurs.
title: "%{instance} Condicions del servei i política de privadesa" time: formats: default: "%b %d, %Y, %H:%M" two_factor_authentication: code_hint: Introdueix el codi generat per l'aplicació autenticadora per a confirmar - description_html: Si habilites la autenticació de dos factors, et caldrà tenir el teu telèfon, que generarà tokens per a que puguis iniciar sessió. - disable: Deshabilitarr - enable: Habilitar + description_html: Si habilites l'autenticació de dos factors, et caldrà tenir el teu telèfon, que generarà tokens per a que puguis iniciar sessió. + disable: Desactiva + enable: Activa enabled: Autenticació de dos factors activada - enabled_success: Autenticació de dos factors activada amb èxit - generate_recovery_codes: Generar codis de recuperació + enabled_success: Autenticació de dos factors activada correctament + generate_recovery_codes: Genera codis de recuperació instructions_html: "Escaneja aquest codi QR desde Google Authenticator o una aplicació similar del teu telèfon. Desde ara, aquesta aplicació generarà tokens que tens que ingresar quan volguis iniciar sessió." - lost_recovery_codes: Els codis de recuperació et permeten recuperar l'accés al teu compte si perds el telèfon. Si has perdut els teus codis de recuperació els pots regenerar aquí. Els codis de recuperació anteriors seran anul·lats. - manual_instructions: 'Si no pots escanejar el codi QR code i necessites introduir-lo manualment, aquí tens el secret en text plà:' + lost_recovery_codes: Els codis de recuperació et permeten recuperar l'accés al teu compte si perds el telèfon. Si has perdut els codis de recuperació els pots tornar a generar aquí. Els codis de recuperació anteriors s'anul·laran. + manual_instructions: 'Si no pots escanejar el codi QR code i necessites introduir-lo manualment, aquí tens el secret en text pla:' recovery_codes: Codis de recuperació de còpia de seguretat recovery_codes_regenerated: Codis de recuperació regenerats amb èxit - recovery_instructions_html: Si alguna vegada perds l'accéss al telèfon pots utilitzar un dels codis de recuperació a continuació per recuperar l'accés al teu compte. Cal mantenir els codis de recuperació en lloc segur, per exemple imprimint-los i guardar-los amb altres documents importants. + recovery_instructions_html: Si mai perds l'accéss al telèfon pots utilitzar un dels codis de recuperació a continuació per a recuperar l'accés al teu compte. Cal mantenir els codis de recuperació en lloc segur, per exemple imprimint-los i guardar-los amb altres documents importants. setup: Establir - wrong_code: El codi introduït es invalid! Es correcta la hora del servidor i del dispositiu? + wrong_code: El codi introduït no és vàlid! És correcta l'hora del servidor i del dispositiu? users: - invalid_email: La direcció de correu es incorrecte - invalid_otp_token: Codi de dos factors incorrecte + invalid_email: L'adreça de correu no és correcta + invalid_otp_token: El codi de dos factors no és correcte signed_in_as: 'Sessió iniciada com a:' diff --git a/config/locales/de.yml b/config/locales/de.yml index 169af50ff12..db96f7de704 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -517,8 +517,6 @@ de: pinned: Angehefteter Beitrag reblogged: teilte sensitive_content: Heikle Inhalte - themes: - default: Mastodon time: formats: default: "%d.%m.%Y %H:%M" diff --git a/config/locales/devise.ca.yml b/config/locales/devise.ca.yml index 4ff51b6e015..fe95c402d61 100644 --- a/config/locales/devise.ca.yml +++ b/config/locales/devise.ca.yml @@ -2,60 +2,60 @@ ca: devise: confirmations: - confirmed: La seva adreça de correu ha estat confirmada amb èxit. - send_instructions: Rebrà un correu electrònic amb instruccions sobre com confirmar la seva adreça de correu en pocs minuts. - send_paranoid_instructions: Si la seva adreça de correu electrònic existeix en la nostre base de dades, rebrà un correu electrònic amb instruccions sobre com confirmar la seva adreça de correu en pocs minuts. + confirmed: L'adreça de correu s'ha confirmat correctament. + send_instructions: En pocs minuts rebràs un correu electrònic amb instruccions sobre com confirmar l'adreça de correu. + send_paranoid_instructions: Si l'adreça de correu electrònic existeix en la nostra base de dades, en pocs minuts rebràs un correu electrònic amb instruccions sobre com confirmar l'adreça de correu. failure: - already_authenticated: Vosté ja està registrat. - inactive: el seu compte encara no està actiu. - invalid: Invàlid %{authentication_keys} o contrassenya. - last_attempt: Té un intent més abans que el seu compte sigui bloquejat. - locked: el seu compte ha estat bloquejat. - not_found_in_database: Invàlit %{authentication_keys} o contrassenya. - timeout: la sessió ha expirat. Si us plau iniciï sessió de nou per a continuar. - unauthenticated: Necessita iniciar sessió o registrar-se abans de continuar. - unconfirmed: Ha de confirmar la seva adreça de correu electrònic abans de continuar. + already_authenticated: Ja estàs registrat. + inactive: el teu compte encara no s'ha activat. + invalid: "%{authentication_keys} o contrasenya no són vàlids." + last_attempt: Tens un intent més, abans que es bloqui el compte. + locked: el compte s'ha blocat. + not_found_in_database: "%{authentication_keys} o contrasenya no vàlids." + timeout: la sessió ha expirat. Incia sessió una altra vegada per a continuar. + unauthenticated: Cal iniciar sessió o registrar-se abans de continuar. + unconfirmed: Has de confirmar l'adreça de correu electrònic abans de continuar. mailer: confirmation_instructions: subject: 'Mastodon: Instruccions de confirmació' password_change: - subject: 'Mastodon: Contrassenya canviada' + subject: 'Mastodon: Contrasenya canviada' reset_password_instructions: subject: 'Mastodon: Instruccions per a reiniciar contrassenya' unlock_instructions: - subject: 'Mastodon: Instruccions per a desbloquejar' + subject: 'Mastodon: Instruccions per a desblocar' omniauth_callbacks: - failure: No podem autentificar-lo desde %{kind} degut a "%{reason}". - success: Autentificat amb èxit desde el compte %{kind} . + failure: No podem autentificar-te desde %{kind} degut a "%{reason}". + success: Autentificat amb èxit des del compte %{kind} . passwords: - no_token: No pot accedir aquesta pàgina sense provenir desde el correu de reinici de contrassenya. Si ve desde el correu de reinici de contrassenya, si us pla asseguri que està emprant la adreça complerta proporcionada. - send_instructions: Rebrà un correu electrònic amb instruccions sobre com reiniciar la seva contrassenya en pocs minuts. - send_paranoid_instructions: Si el seu correu electrònic existeix en la nostre base de dades, rebrà un enllaç de recuperació de contrassenya en la seva adreça de correu en pocs minuts. - updated: La seva contrassenya ha estat canviada amb èxit. Ara ja està registrat. - updated_not_active: La seva contrassenya ha estat canviada amb èxit. + no_token: No pots accedir a aquesta pàgina sense provenir des del correu de restabliment de la contrasenya. Si vens des del correu de restabliment de contrasenya, assegura't que estàs emprant l'adreça completa proporcionada. + send_instructions: Rebràs un correu electrònic amb instruccions sobre com reiniciar la contrasenya en pocs minuts. + send_paranoid_instructions: Si el seu correu electrònic existeix en la nostra base de dades, rebràs un enllaç de restabliment de contrasenya en l'adreça de correu en pocs minuts. + updated: La contrassenya s'ha canviat correctament. Ara ja estàs registrat. + updated_not_active: La contrassenya s'ha canviat correctament. registrations: - destroyed: Adéu! el seu compte ha estat cancel·lat amb èxit. Esperem veure'l aviat de nou. - signed_up: Benvingut! S'ha registrat amb èxit. - signed_up_but_inactive: S´ha registrat amb èxit. No obstant, no podem identificar-lo perque el seu compte no ha estat activat encara. - signed_up_but_locked: S´ha registrat amb èxit. No obstant, no podem identificar-lo perque el seu compte està bloquejat. + destroyed: Adéu! el compte s'ha cancel·lat amb èxit. Desitgem veure't de nou aviat. + signed_up: Benvingut! T'has registrat amb èxit. + signed_up_but_inactive: T´has registrat amb èxit. No obstant, no podem identificar-te perquè el compte encara no s'ha activat. + signed_up_but_locked: T´has registrat amb èxit. No obstant, no podem identificar-te perquè el compte està blocat. signed_up_but_unconfirmed: Un missatge amb un enllaç de confirmació ha estat enviat per correu electrònic. Si us plau segueixi l'enllaç per activar el seu compte. update_needs_confirmation: Ha actualitzat el seu compte amb èxit, però necessitem verificar la nova adreça de correu. Si us plau comprovi el correu i segueixi l'enllaç per confirmar la nova adreça de correu. updated: el seu compte ha estat actualitzat amb èxit. sessions: - already_signed_out: Ha tancat la sessió amb èxit. - signed_in: S'ha registrat amb èxit. - signed_out: Ha tancat la sessió amb èxit. + already_signed_out: Has tancat la sessió amb èxit. + signed_in: T'has registrat amb èxit. + signed_out: Has tancat la sessió amb èxit. unlocks: - send_instructions: Rebrà un correu electrònic amb instruccions sobre com desbloquejar el seu compte en pocs minuts. - send_paranoid_instructions: Si el seu compte existeix, rebrà un correu electrònic amb instruccions sobre com desbloquejarla en pocs minuts. - unlocked: El seu compte ha estat bloquejat amb èxit. Si us plau iniciï sessió per continuar. + send_instructions: Rebràs un correu electrònic amb instruccions sobre com desblocar el compte en pocs minuts. + send_paranoid_instructions: Si el compte existeix, rebràs un correu electrònic amb instruccions sobre com desblocar-lo en pocs minuts. + unlocked: El compte s'ha blocat correctament. Inicia sessió per a continuar. errors: messages: - already_confirmed: ja ha estat confirmat, si us plau intenti iniciar sessió - confirmation_period_expired: necessita ser confirmat dins de %{period}, si us plau demani una nova - expired: ha expirat, si us plau demani una nova - not_found: no trobat - not_locked: no va ser bloquejada + already_confirmed: ja està confirmat. Intenta d'iniciar sessió + confirmation_period_expired: calia fer la confirmació dins de %{period}, torna a sol·licitar-la + expired: ha expirat, demana'n una altra + not_found: no s'ha trobat + not_locked: no està blocada not_saved: - one: '1 error ha prohibit aquest %{resource} de ser guardat:' - other: "%{count} errors va prohibir aquest %{resource} de ser guardat:" + one: '1 error ha impedit desar aquest %{resource}:' + other: "%{count} errors hab impedit desar aquest %{resource}:" diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml index 0e40fcc9021..5560e12b3f1 100644 --- a/config/locales/devise.zh-CN.yml +++ b/config/locales/devise.zh-CN.yml @@ -8,7 +8,7 @@ zh-CN: failure: already_authenticated: 你已经登录。 inactive: 你还没有激活帐户。 - invalid: " %{authentication_keys} 或密码错误。" + invalid: "%{authentication_keys}或密码错误。" last_attempt: 你还有最后一次尝试机会,再次失败你的帐户将被锁定。 locked: 你的帐户已被锁定。 not_found_in_database: "%{authentication_keys}或密码错误。" @@ -53,10 +53,10 @@ zh-CN: unlocked: 你的帐户已成功解锁。登录以继续。 errors: messages: - already_confirmed: 已经确认,请重新登录。 - confirmation_period_expired: 注册帐户后须在 %{period}以内确认。请重新注册。 - expired: 邮件确认已过期,请重新注册。 - not_found: 找不到。 - not_locked: 未锁定。 + already_confirmed: 已经确认成功,请尝试登录 + confirmation_period_expired: 必须在 %{period}以内确认。请重新发起请求 + expired: 已过期。请重新发起请求 + not_found: 找不到 + not_locked: 未被锁定 not_saved: other: 发生 %{count} 个错误,导致%{resource}保存失败: diff --git a/config/locales/doorkeeper.ca.yml b/config/locales/doorkeeper.ca.yml index 38dbbdde97c..c2d2b79b996 100644 --- a/config/locales/doorkeeper.ca.yml +++ b/config/locales/doorkeeper.ca.yml @@ -3,7 +3,7 @@ ca: activerecord: attributes: doorkeeper/application: - name: Nombre + name: Nom redirect_uri: URI per a redirecció errors: models: @@ -11,58 +11,58 @@ ca: attributes: redirect_uri: fragment_present: no pot contenir un fragment. - invalid_uri: ha de ser una URI válid. - relative_uri: ha de ser una URI absoluta. - secured_uri: ha de ser una URI HTTPS/SSL. + invalid_uri: ha de ser un URI válid. + relative_uri: ha de ser un URI absoluta. + secured_uri: ha de ser un URI HTTPS/SSL. doorkeeper: applications: buttons: - authorize: Autoritzar - cancel: Cancel⋅lar - destroy: Destruir - edit: Editar - submit: Enviar + authorize: Autoritza + cancel: Cancel⋅la + destroy: Destrueix + edit: Edita + submit: Envia confirmations: - destroy: Està segur? + destroy: Estàs segur? edit: - title: Editar aplicació + title: Edita l'aplicació form: - error: Uuups! Comprovi el formulari + error: Ep! Comprova el formulari help: - native_redirect_uri: Utilitzi %{native_redirect_uri} per a proves locals - redirect_uri: Utilitzi una línia per URI - scopes: Separi els àmbits amb espais. Deixa-ho en blanc per utilitzar els àmbits per defecte. + native_redirect_uri: Utilitza %{native_redirect_uri} per a proves locals + redirect_uri: Utilitza una línia per URI + scopes: Separa els àmbits amb espais. Deixa-ho en blanc per a utilitzar els àmbits per defecte. index: callback_url: Callback URL name: Nom - new: Nova aplicació + new: Aplicació nova title: Les teves aplicacions new: - title: Nova aplicació + title: Aplicació nova show: actions: Accions - application_id: Id de la aplicació - callback_urls: Callback urls + application_id: Id de l'aplicació + callback_urls: Callback URL scopes: Àmbits secret: Secret title: 'Aplicació: %{name}' authorizations: buttons: - authorize: Autoritzar - deny: Desautoritzar + authorize: Autoritza + deny: Desautoritza error: - title: Ha ocorregut un error + title: S'a produit un error new: able_to: Serà capaç de - prompt: La aplicació %{client_name} sol⋅licita tenir accés al teu compte - title: Es requereix autorizació + prompt: L'aplicació %{client_name} sol⋅licita tenir accés al teu compte + title: Cal autorizació show: - title: Copy this authorization code and paste it to the application. + title: Copia aquest coddi d'autorització i enganxa'l en l'aplicació. authorized_applications: buttons: - revoke: Revocar + revoke: Revoca confirmations: - revoke: Està segur? + revoke: Estàs segur? index: application: Aplicació created_at: Creat el @@ -72,22 +72,22 @@ ca: messages: access_denied: El propietari del recurs o servidor de autorizació ha denegat la petició. credential_flow_not_configured: Les credencials de contrasenya del propietari del recurs han fallat degut a que Doorkeeper.configure.resource_owner_from_credentials està sense configurar. - invalid_client: La autentificación del cliente falló debido o a que es un cliente desconocido o no está incluída la autentificación del cliente o el método de autentificación no está confirmado. - invalid_grant: La concesión de autorización ofrecida es inválida, venció, se revocó, no coincide con la URI de redirección utilizada en la petición de autorización, o fue emitida para otro cliente. - invalid_redirect_uri: La URI de redirección incluida no es válida. - invalid_request: En la petición falta un parámetro necesario o incluye un valor de parámetro no soportado o tiene otro tipo de formato incorrecto. - invalid_resource_owner: Las credenciales del propietario del recurso proporcionado no son válidas, o el propietario del recurso no puede ser encontrado. - invalid_scope: El ámbito pedido es inválido, desconocido o erróneo. + invalid_client: La autentificació del client falló perquè és un client desconegut o no està inclòs l'autentificació del client o el mètode d'autenticació no està confirmat. + invalid_grant: La concessió d'autorizació oferida és invàlida, ha vençut, s'ha revocat, no coincideix amb l'URI de redirecció utilizada en la petició d'autorizació, o fou emesa per a un altre client. + invalid_redirect_uri: L'URI de redirecció inclòs no és vàlid. + invalid_request: En la petició manca un paràmetre necessari o inclou un valor de paràmetre no suportat o te un altre tipus de format incorrecte. + invalid_resource_owner: Les credencials del propietari del recurso proporcionat no son vàlides, o el propietari del recurs no pot ser trobat. + invalid_scope: L'àmbit demanat és invàlid, desconegut o erroni. invalid_token: - expired: El identificador de acceso finalizó. - revoked: El identificador de acceso fue revocado. - unknown: El identificador de acceso es inválido. - resource_owner_authenticator_not_configured: El propietario del recurso falló debido a que Doorkeeper.configure.resource_owner_authenticator está sin configurar. - server_error: El servidor de la autorización entontró una condición inesperada que le impidió cumplir con la solicitud. - temporarily_unavailable: El servidor de la autorización es actualmente incapaz de manejar la petición debido a una sobrecarga temporal o un trabajo de mantenimiento del servidor. - unauthorized_client: El cliente no está autorizado a realizar esta petición utilizando este método. - unsupported_grant_type: El tipo de concesión de autorización no está soportado por el servidor de autorización. - unsupported_response_type: El servidor de autorización no soporta este tipo de respuesta. + expired: L'identificador d'accés ha caducat. + revoked: L'identificador d'accés fou revocat. + unknown: L'identificador d'accés és invàlid. + resource_owner_authenticator_not_configured: El propietari del recurs ha fallat perquè Doorkeeper.configure.resource_owner_authenticator està sense configurar. + server_error: El servidor de l'autorizació ha trobat unca condició inesperada que ha impedit complir la sol·licitud. + temporarily_unavailable: El servidor de l'autorizació és actualment incapaç de gestionar la petició degut a una sobrecàrrega temporal o una tasca de manteniment del servidor. + unauthorized_client: El client no està autoritzat a fer aquesta petició utilitzant aquest mètode. + unsupported_grant_type: El tipus de concessió d'autorització no està suportat pel servidor d'autorizació. + unsupported_response_type: El servidor d'autorizació no suporta aquest tipus de resposta. flash: applications: create: @@ -107,6 +107,6 @@ ca: application: title: OAuth autorització requerida scopes: - follow: seguir, bloquejar, desbloquejar i deixar de seguir comptes + follow: seguir, blocar, desblocar i deixar de seguir comptes read: llegir les dades del teu compte write: publicar en el teu nom diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml index c7e8f368d59..0eb5a0ab60d 100644 --- a/config/locales/doorkeeper.zh-CN.yml +++ b/config/locales/doorkeeper.zh-CN.yml @@ -77,10 +77,10 @@ zh-CN: title: 已授权的应用列表 errors: messages: - access_denied: 用户或服务器拒绝了请求 + access_denied: 资源所有者或服务器拒绝了请求 credential_flow_not_configured: 由于 Doorkeeper.configure.resource_owner_from_credentials 尚未配置,应用验证授权流程失败。 invalid_client: 由于应用信息未知、未提交认证信息或使用了不支持的认证方式,认证失败 - invalid_grant: 授权方式无效,或者登录回调地址无效、过期或已被撤销 + invalid_grant: 授权方式无效、过期或已被撤销、与授权请求中的回调地址不一致,或使用了其他应用的回调地址 invalid_redirect_uri: 无效的登录回调地址 invalid_request: 请求缺少必要的参数,或者参数值、格式不正确 invalid_resource_owner: 资源所有者认证无效,或找不到所有者 diff --git a/config/locales/en.yml b/config/locales/en.yml index cebf704cebf..0ca320e1acb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -39,6 +39,7 @@ en: followers: Followers following: Following media: Media + moved_html: "%{name} has moved to %{new_profile_link}:" nothing_here: There is nothing here! people_followed_by: People whom %{name} follows people_who_follow: People who follow %{name} @@ -132,6 +133,32 @@ en: unsubscribe: Unsubscribe username: Username web: Web + action_logs: + actions: + confirm_user: "%{name} confirmed e-mail address of user %{target}" + create_custom_emoji: "%{name} uploaded new emoji %{target}" + create_domain_block: "%{name} blocked domain %{target}" + create_email_domain_block: "%{name} blacklisted e-mail domain %{target}" + demote_user: "%{name} demoted user %{target}" + destroy_domain_block: "%{name} unblocked domain %{target}" + destroy_email_domain_block: "%{name} whitelisted e-mail domain %{target}" + destroy_status: "%{name} removed status by %{target}" + disable_2fa_user: "%{name} disabled two factor requirement for user %{target}" + disable_custom_emoji: "%{name} disabled emoji %{target}" + disable_user: "%{name} disabled login for user %{target}" + enable_custom_emoji: "%{name} enabled emoji %{target}" + enable_user: "%{name} enabled login for user %{target}" + memorialize_account: "%{name} turned %{target}'s account into a memoriam page" + promote_user: "%{name} promoted user %{target}" + reset_password_user: "%{name} reset password of user %{target}" + resolve_report: "%{name} dismissed report %{target}" + silence_account: "%{name} silenced %{target}'s account" + suspend_account: "%{name} suspended %{target}'s account" + unsilence_account: "%{name} unsilenced %{target}'s account" + unsuspend_account: "%{name} unsuspended %{target}'s account" + update_custom_emoji: "%{name} updated emoji %{target}" + update_status: "%{name} updated status by %{target}" + title: Audit log custom_emojis: copied_msg: Successfully created local copy of the emoji copy: Copy @@ -186,24 +213,31 @@ en: suspend: Unsuspend all existing accounts from this domain title: Undo domain block for %{domain} undo: Undo - title: Domain Blocks + title: Domain blocks undo: Undo email_domain_blocks: add_new: Add new - created_msg: Email domain block successfully created + created_msg: Successfully added e-mail domain to blacklist delete: Delete - destroyed_msg: Email domain block successfully deleted + destroyed_msg: Successfully deleted e-mail domain from blacklist domain: Domain new: - create: Create block - title: New email domain block - title: Email Domain Block + create: Add domain + title: New e-mail blacklist entry + title: E-mail blacklist instances: account_count: Known accounts domain_name: Domain reset: Reset search: Search - title: Known Instances + title: Known instances + invites: + filter: + all: All + available: Available + expired: Expired + title: Filter + title: Invites reports: action_taken_by: Action taken by are_you_sure: Are you sure? @@ -242,9 +276,15 @@ en: deletion: desc_html: Allow anyone to delete their account title: Open account deletion + min_invite_role: + disabled: No one + title: Allow invitations by open: desc_html: Allow anyone to create an account title: Open registration + show_staff_badge: + desc_html: Show a staff badge on a user page + title: Show staff badge site_description: desc_html: Introductory paragraph on the frontpage and in meta tags. You can use HTML tags, in particular<a>
and <em>
.
title: Instance description
@@ -261,7 +301,7 @@ en:
timeline_preview:
desc_html: Display public timeline on landing page
title: Timeline preview
- title: Site Settings
+ title: Site settings
statuses:
back_to_account: Back to account page
batch:
@@ -312,6 +352,8 @@ en:
invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.
login: Log in
logout: Logout
+ migrate_account: Move to a different account
+ migrate_account_html: If you wish to redirect this account to a different one, you can configure it here.
register: Sign up
resend_confirmation: Resend confirmation instructions
reset_password: Reset password
@@ -394,6 +436,26 @@ en:
muting: Muting list
upload: Upload
in_memoriam_html: In Memoriam.
+ invites:
+ delete: Deactivate
+ expired: Expired
+ expires_in:
+ '1800': 30 minutes
+ '21600': 6 hours
+ '3600': 1 hour
+ '43200': 12 hours
+ '86400': 1 day
+ expires_in_prompt: Never
+ generate: Generate
+ max_uses:
+ one: 1 use
+ other: "%{count} uses"
+ max_uses_prompt: No limit
+ prompt: Generate and share links with others to grant access to this instance
+ table:
+ expires_at: Expires
+ uses: Uses
+ title: Invite people
keyword_mutes:
add_keyword: Add keyword
edit: Edit
@@ -408,6 +470,13 @@ en:
validations:
images_and_video: Cannot attach a video to a status that already contains images
too_many: Cannot attach more than 4 files
+ migrations:
+ acct: username@domain of the new account
+ currently_redirecting: 'Your profile is set to redirect to:'
+ proceed: Save
+ updated_msg: Your account migration setting successfully updated!
+ moderation:
+ title: Moderation
notification_mailer:
digest:
body: 'Here is a brief summary of what you missed on %{instance} since your last visit on %{since}:'
@@ -521,6 +590,7 @@ en:
followers: Authorized followers
import: Import
keyword_mutes: Muted keywords
+ migrate: Account migration
notifications: Notifications
preferences: Preferences
settings: Settings
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index 0bf195d1b39..847299ac7ba 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -423,8 +423,6 @@ eo:
sensitive_content: Tikla enhavo
terms:
title: "%{instance} Reguloj de servo kaj Politikaj pri privatecoj"
- themes:
- default: Mastodon
time:
formats:
default: "%b %d, %Y, %H:%M"
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 24a2ddd5117..1e3bd0e8b71 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -587,8 +587,6 @@ fa:
این نوشته اقتباسی است از سیاست رازداری Discourse.
title: شرایط استفاده و سیاست رازداری %{instance} - themes: - default: Mastodon time: formats: default: "%d %b %Y, %H:%M" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 55588d11153..2fd875b2c94 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -587,8 +587,6 @@ fr:Originellement adapté à partir de la politique de confidentialité de Discourse.
title: "%{instance} Conditions d’utilisations et politique de confidentialité" - themes: - default: Mastodon time: formats: default: "%d %b %Y, %H:%M" diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 82b642b5bc1..a008d9cc49d 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -39,6 +39,7 @@ ja: followers: フォロワー following: フォロー中 media: メディア + moved_html: "%{name} さんは引っ越しました %{new_profile_link}:" nothing_here: 何もありません people_followed_by: "%{name} さんがフォロー中のアカウント" people_who_follow: "%{name} さんをフォロー中のアカウント" @@ -48,6 +49,7 @@ ja: reserved_username: このユーザー名は予約されています。 roles: admin: Admin + moderator: Mod unfollow: フォロー解除 admin: account_moderation_notes: @@ -131,6 +133,32 @@ ja: unsubscribe: 購読の解除 username: ユーザー名 web: Web + action_logs: + actions: + confirm_user: "%{name} さんが %{target} さんのメールアドレスを確認済みにしました" + create_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を追加しました" + create_domain_block: "%{name} さんがドメイン %{target} をブロックしました" + create_email_domain_block: "%{name} さんがドメイン %{target} をメールアドレス用ブラックリストに追加しました" + demote_user: "%{name} さんが %{target} さんを降格しました" + destroy_domain_block: "%{name} さんがドメイン %{target} のブロックを外しました" + destroy_email_domain_block: "%{name} さんがドメイン %{target} をメールアドレス用ブラックリストから外しました" + destroy_status: "%{name} さんが %{target} さんの投稿を削除しました" + disable_2fa_user: "%{name} さんが %{target} さんの二段階認証を無効化しました" + disable_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を無効化しました" + disable_user: "%{name} さんが %{target} さんのログインを無効化しました" + enable_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を有効化しました" + enable_user: "%{name} さんが %{target} さんのログインを有効化しました" + memorialize_account: "%{name} さんが %{target} さんを追悼アカウントページに登録しました" + promote_user: "%{name} さんが %{target} さんを昇格しました" + reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました" + resolve_report: "%{name} さんがレポート %{target} を棄却しました" + silence_account: "%{name} さんが %{target} さんをサイレンスにしました" + suspend_account: "%{name} さんが %{target} さんを停止しました" + unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました" + unsuspend_account: "%{name} さんが %{target} さんの停止を解除しました" + update_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を更新しました" + update_status: "%{name} さんが %{target} さんの投稿を更新しました" + title: 操作履歴 custom_emojis: copied_msg: 絵文字のコピーをローカルに作成しました copy: コピー @@ -189,20 +217,27 @@ ja: undo: 元に戻す email_domain_blocks: add_new: 新規追加 - created_msg: 処理を完了しました + created_msg: ブラックリストに追加しました delete: 消去 - destroyed_msg: 消去しました + destroyed_msg: ブラックリストから外しました domain: ドメイン new: - create: ブロックを作成 - title: 新規メールドメインブロック - title: メールドメインブロック + create: ドメインを追加 + title: メールアドレス用ブラックリスト新規追加 + title: メールブラックリスト instances: account_count: 既知のアカウント数 domain_name: ドメイン名 reset: リセット search: 検索 title: 既知のインスタンス + invites: + filter: + all: すべて + available: 使用可能 + expired: 期限切れ + title: フィルター + title: 招待 reports: action_taken_by: レポート処理者 are_you_sure: 本当に実行しますか? @@ -241,9 +276,15 @@ ja: deletion: desc_html: 誰でも自分のアカウントを削除できるようにします title: アカウント削除を受け付ける + min_invite_role: + disabled: 誰も許可しない + title: 招待の作成を許可 open: desc_html: 誰でも自由にアカウントを作成できるようにします title: 新規登録を受け付ける + show_staff_badge: + desc_html: ユーザーページにスタッフのバッジを表示します + title: スタッフバッジを表示する site_description: desc_html: フロントページへの表示と meta タグに使用される紹介文です。HTMLタグ、特に<a>
と <em>
が使えます。
title: インスタンスの説明
@@ -311,6 +352,8 @@ ja:
invalid_reset_password_token: パスワードリセットトークンが正しくないか期限切れです。もう一度リクエストしてください。
login: ログイン
logout: ログアウト
+ migrate_account: 別のアカウントに引っ越す
+ migrate_account_html: 引っ越し先を明記したい場合はこちらで設定できます。
register: 登録する
resend_confirmation: 確認メールを再送する
reset_password: パスワードを再発行
@@ -393,12 +436,39 @@ ja:
muting: ミュートしたアカウントリスト
upload: アップロード
in_memoriam_html: 故人を偲んで
+ invites:
+ delete: 無効化
+ expired: 期限切れ
+ expires_in:
+ '1800': 30 分
+ '21600': 6 時間
+ '3600': 1 時間
+ '43200': 12 時間
+ '86400': 1 日
+ expires_in_prompt: 無期限
+ generate: 作成
+ max_uses:
+ one: 1
+ other: "%{count}"
+ max_uses_prompt: 無制限
+ prompt: リンクを生成・共有してこのインスタンスへの新規登録を受け付けることができます。
+ table:
+ expires_at: 有効期限
+ uses: 使用
+ title: 新規ユーザーの招待
landing_strip_html: "%{name} さんはインスタンス %{link_to_root_path} のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。"
landing_strip_signup_html: もしお持ちでないなら こちら からサインアップできます。
media_attachments:
validations:
images_and_video: 既に画像が追加されているため、動画を追加することはできません。
too_many: 追加できるファイルは4つまでです。
+ migrations:
+ acct: 引っ越し先の ユーザー名@ドメイン
+ currently_redirecting: 'あなたのプロフィールは引っ越し先が設定されています:'
+ proceed: 保存
+ updated_msg: アカウントの引っ越し設定を更新しました
+ moderation:
+ title: モデレーション
notification_mailer:
digest:
body: "%{instance} での最後のログインからの出来事:"
@@ -511,6 +581,7 @@ ja:
export: データのエクスポート
followers: 信頼済みのインスタンス
import: データのインポート
+ migrate: アカウントの引っ越し
notifications: 通知
preferences: ユーザー設定
settings: 設定
@@ -607,8 +678,6 @@ ja:
オリジナルの出典 Discourse privacy policy.
title: "%{instance} 利用規約・プライバシーポリシー" - themes: - default: Mastodon time: formats: default: "%Y年%m月%d日 %H:%M" diff --git a/config/locales/ko.yml b/config/locales/ko.yml index abf5f0ea455..fd635148695 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -518,8 +518,6 @@ ko: sensitive_content: 민감한 컨텐츠 terms: title: "%{instance} 이용약관과 개인정보 취급 방침" - themes: - default: Mastodon time: formats: default: "%Y년 %m월 %d일 %H:%M" diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 501ec013d8f..cda771ce27a 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -587,8 +587,6 @@ nl:Originally adapted from the Discourse privacy policy.
title: "%{instance} Terms of Service and Privacy Policy" - themes: - default: Mastodon time: formats: default: "%d %B %Y om %H:%M" diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 914cc7e9d60..e5d036303db 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -678,8 +678,6 @@ oc:Prima adaptacion de la politica de confidencialitat de Discourse.
title: Condicions d’utilizacion e politica de confidencialitat de %{instance} - themes: - default: Mastodon time: formats: default: Lo %d %b de %Y a %Ho%M diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 49dace354b4..19ee154abd3 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -39,6 +39,7 @@ pl: followers: Śledzących following: Śledzi media: Zawartość multimedialna + moved_html: "%{name} korzysta teraz z konta %{new_profile_link}:" nothing_here: Niczego tu nie ma! people_followed_by: Konta śledzone przez %{name} people_who_follow: Osoby, które śledzą konto %{name} @@ -48,6 +49,7 @@ pl: reserved_username: Ta nazwa użytkownika jest zarezerwowana. roles: admin: Administrator + moderator: Moderator unfollow: Przestań śledzić admin: account_moderation_notes: @@ -131,6 +133,32 @@ pl: unsubscribe: Przestań subskrybować username: Nazwa użytkownika web: Sieć + action_logs: + actions: + confirm_user: "%{name} potwierdził adres e-mail użytkownika %{target}" + create_custom_emoji: "%{name} dodał nowe emoji %{target}" + create_domain_block: "%{name} zablokował domenę %{target}" + create_email_domain_block: "%{name} dodał domenę e-mail %{target} na czarną listę" + demote_user: "%{name} zdegradował użytkownika %{target}" + destroy_domain_block: "%{name} odblokował domenę %{target}" + destroy_email_domain_block: "%{name} usunął domenę e-mail %{target} z czarnej listy" + destroy_status: "%{name} usunął wpis użytkownika %{target}" + disable_2fa_user: "%{name} wyłączył uwierzytelnianie dwustopniowe użytkownikowi %{target}" + disable_custom_emoji: "%{name} wyłączył emoji %{target}" + disable_user: "%{name} zablokował możliwość logowania użytkownikowi %{target}" + enable_custom_emoji: "%{name} włączył emoji %{target}" + enable_user: "%{name} przywrócił możliwość logowania użytkownikowi %{target}" + memorialize_account: "%{name} nadał kontu %{target} status in memoriam" + promote_user: "%{name} podniósł uprawnienia użytkownikowi %{target}" + reset_password_user: "%{name} przywrócił hasło użytkownikowi %{target}" + resolve_report: "%{name} odrzucił zgłoszenie %{target}" + silence_account: "%{name} wyciszył konto %{target}" + suspend_account: "%{name} zawiesił konto %{target}" + unsilence_account: "%{name} cofnął wyciszenie konta %{target}" + unsuspend_account: "%{name} cofnął zawieszenie konta %{target}" + update_custom_emoji: "%{name} zaktualizował emoji %{target}" + update_status: "%{name} zaktualizował wpis użytkownika %{target}" + title: Dziennik działań administracyjnych custom_emojis: copied_msg: Pomyślnie utworzono lokalną kopię emoji copy: Kopiuj @@ -147,6 +175,7 @@ pl: listed: Widoczne new: title: Dodaj nowe niestandardowe emoji + overwrite: Zastąp shortcode: Shortcode shortcode_hint: Co najmniej 2 znaki, tylko znaki alfanumeryczne i podkreślniki title: Niestandardowe emoji @@ -203,6 +232,13 @@ pl: reset: Przywróć search: Szukaj title: Znane instancje + invites: + filter: + all: Wszystkie + available: Dostępne + expired: Wygasłe + title: Filtruj + title: Zaproszenia reports: action_taken_by: Działanie podjęte przez are_you_sure: Czy na pewno? @@ -244,6 +280,9 @@ pl: open: desc_html: Pozwól każdemu na założenie konta title: Otwarta rejestracja + show_staff_badge: + desc_html: Pokazuj odznakę uprawnień na stronie profilu użytkownika + title: Pokazuj odznakę administracji site_description: desc_html: Akapit wprowadzający, widoczny na stronie głównej i znacznikach meta. Możesz korzystać z tagów HTML, w szczególności<a>
i <em>
.
title: Opis instancji
@@ -311,6 +350,8 @@ pl:
invalid_reset_password_token: Token do resetowania hasła jest nieprawidłowy lub utracił ważność. Spróbuj uzyskać nowy.
login: Zaloguj się
logout: Wyloguj się
+ migrate_account: Przenieś konto
+ migrate_account_html: Jeżeli chcesz skonfigurować przekierowanie z obecnego konta na inne, możesz skonfigurować to tutaj.
register: Rejestracja
resend_confirmation: Ponownie prześlij instrukcje weryfikacji
reset_password: Zresetuj hasło
@@ -393,12 +434,48 @@ pl:
muting: Lista wyciszonych
upload: Załaduj
in_memoriam_html: Ku pamięci.
+ invites:
+ delete: Wygaś
+ expired: Wygasły
+ expires_in:
+ '1800': 30 minutach
+ '21600': 6 godzinach
+ '3600': godzinie
+ '43200': 12 godzinach
+ '86400': dobie
+ expires_in_prompt: Nigdy
+ generate: Wygeneruj
+ max_uses:
+ few: "%{count} użycia"
+ many: "%{count} użyć"
+ one: jedno użycie
+ other: "%{count} użyć"
+ max_uses_prompt: Bez ograniczenia
+ prompt: Wygeneruj odnośniki i udostępnij je innym, aby pozwolić na rejestrację na instancji
+ table:
+ expires_at: Wygaśnie po
+ uses: Użycia
+ title: Zaproś użytkowników
+ keyword_mutes:
+ add_keyword: Dodaj słowo kluczowe
+ edit: Edytuj
+ edit_keyword: Edytuj słowo kluczowe
+ keyword: Słowo kluczowe
+ match_whole_word: Uwzględniaj całe słowo
+ remove: Usuń
+ remove_all: Usuń wszystkie
landing_strip_html: "%{name} ma konto na %{link_to_root_path}. Możesz je śledzić i wejść z nim w interakcję jeśli masz konto gdziekolwiek w Fediwersum."
landing_strip_signup_html: Jeśli jeszcze go nie masz, możesz stworzyć konto.
media_attachments:
validations:
images_and_video: Nie możesz załączyć pliku wideo do wpisu, który zawiera już zdjęcia
too_many: Nie możesz załączyć więcej niż 4 plików
+ migrations:
+ acct: nazwa@domena nowego konta
+ currently_redirecting: 'Obecnie Twoje konto przekierowuje do:'
+ proceed: Zapisz
+ moderation:
+ title: Moderacja
notification_mailer:
digest:
body: 'Oto krótkie podsumowanie co Cię ominęło na %{instance} od Twojej ostatniej wizyty (%{since}):'
@@ -515,6 +592,7 @@ pl:
export: Eksportowanie danych
followers: Autoryzowani śledzący
import: Importowanie danych
+ migrate: Migracja konta
notifications: Powiadomienia
preferences: Preferencje
settings: Ustawienia
@@ -611,8 +689,6 @@ pl:
Tekst bazuje na polityce prywatności Discourse.
title: Zasady korzystania i polityka prywatności %{instance} - themes: - default: Mastodon time: formats: default: "%b %d, %Y, %H:%M" diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index f5c61c01caa..de2b9c77866 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -607,8 +607,6 @@ pt-BR:Originalmente adaptado da política de privacidade do Discourse.
title: "%{instance} Termos de Serviço e Política de Privacidade" - themes: - default: Mastodon time: formats: default: "%b %d, %Y, %H:%M" diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 7c9caec14cd..5eb7f256a80 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -521,8 +521,6 @@ ru: sensitive_content: Чувствительный контент terms: title: Условия обслуживания и политика конфиденциальности %{instance} - themes: - default: Mastodon time: formats: default: "%b %d, %Y, %H:%M" diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml index b5b7f26d2b0..f8402af21d1 100644 --- a/config/locales/simple_form.ca.yml +++ b/config/locales/simple_form.ca.yml @@ -4,14 +4,17 @@ ca: hints: defaults: avatar: PNG, GIF o JPG. Màxim 2MB. Serà escalat a 120x120px + digest: S'envia després d'un llarg període d'inactivitat amb un resum de les mencions que has rebut en la teva absència display_name: - one: 1 character left - other: %{count} characters left + one: 1 càracter + other: %{count} càracters header: PNG, GIF o JPG. Màxim 2MB. Serà escalat a 700x335px locked: Requereix que aprovis manualment seguidors i les publicacions seran mostrades només als teus seguidors note: - one: 1 character left - other: %{count} characters left + one: 1 càracter left + other: %{count} càracters + setting_noindex: Afecta el teu perfil públic i les pàgines d'estat + setting_theme: Afecta la manera en què Mastodon es veu quan està connectat des de qualsevol dispositiu. imports: data: Arxiu CSV exportat desde una altra instància de Mastodon sessions: @@ -27,6 +30,7 @@ ca: data: Informació display_name: Mostrar nom email: Direcció de correu electrònic + filtered_languages: Idiomes filtrats header: Img. capçalera locale: Idioma locked: Fer privat aquest compte @@ -37,13 +41,20 @@ ca: setting_auto_play_gif: Auto-reproducció de GIFs animats setting_boost_modal: Mostrar finestra de confirmació abans d'un Retoot setting_default_privacy: Privacitat de publicacions + setting_default_sensitive: Marca sempre els multimèdia com a sensibles setting_delete_modal: Mostrar finestra de confirmació abans d'esborrar un toot + setting_noindex: Desactivació de la indexació del motor de cerca + setting_reduce_motion: Redueix el moviment en animacions + setting_system_font_ui: Utilitzeu el tipus de lletra predeterminat del sistema + setting_theme: Tema del lloc + setting_unfollow_modal: Mostra el diàleg de confirmació abans de deixar de seguir a algú severity: Severitat type: Importar tipus username: Nom d´usuari interactions: must_be_follower: Bloquejar notificacions de persones que no et segueixen must_be_following: Bloquejar notificacions de persones que no segueixes + must_be_following_dm: Bloqueja missatges directes de persones que no segueixes notification_emails: digest: Enviar resum de correus electrònics favourite: Enviar correu electrònic quan algú marqui com a favorit en la teva publicació diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 66ec13634fe..35b45fbc925 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -31,10 +31,12 @@ en: data: Data display_name: Display name email: E-mail address + expires_in: Expire after filtered_languages: Filtered languages header: Header locale: Language locked: Lock account + max_uses: Max number of uses new_password: New password note: Bio otp_attempt: Two-factor code diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 48eaf79b20b..bdeefa7e523 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -26,10 +26,12 @@ ja: data: データ display_name: 表示名 email: メールアドレス + expires_in: 有効期限 filtered_languages: 除外する言語 header: ヘッダー locale: 言語 locked: 非公開アカウントにする + max_uses: 使用できる回数 new_password: 新しいパスワード note: プロフィール otp_attempt: 二段階認証コード diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index 8b539662cae..507e464690e 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -34,10 +34,12 @@ pl: data: Dane display_name: Widoczna nazwa email: Adres e-mail + expires_in: Wygaśnie po filtered_languages: Filtrowane języki header: Nagłówek locale: Język locked: Ustaw konto jako prywatne + max_uses: Maksymalna liczba użyć new_password: Nowe hasło note: Biogram otp_attempt: Kod uwierzytelnienia dwustopniowego diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index f8c9461ad67..23a1f59daf8 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -50,6 +50,7 @@ zh-CN: interactions: must_be_follower: 屏蔽来自未关注你的用户的通知 must_be_following: 屏蔽来自你未关注的用户的通知 + must_be_following_dm: 屏蔽来自你未关注的用户的私信 notification_emails: digest: 发送摘要邮件 favourite: 当有用户收藏了你的嘟文时,发送电子邮件提醒我 diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 260b446665b..ebb6d6595da 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -587,8 +587,6 @@ sv:Ursprungligen anpassad från Discourse integritetspolicy.
title: "%{instance} Användarvillkor och Sekretesspolicy" - themes: - default: Mastodon time: formats: default: "%b %d, %Y, %H:%M" diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index b50c34fd0c5..ec913113f58 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -1,7 +1,7 @@ --- zh-CN: about: - about_hashtag_html: 这里展示的是带有话题标签 #%{hashtag} 的公开嘟文。如果你在象毛世界中拥有一个帐户,就可以加入讨论。 + about_hashtag_html: 这里展示的是带有话题标签 #%{hashtag} 的公开嘟文。如果你想与他们互动,你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。 about_mastodon_html: Mastodon(长毛象)是一个基于开放式网络协议和自由、开源软件建立的社交网络,有着类似于电子邮件的分布式设计。 about_this: 关于本实例 closed_registrations: 这个实例目前没有开放注册。不过,你可以前往其他实例注册一个帐户,同样可以加入到这个网络中哦! @@ -39,15 +39,17 @@ zh-CN: followers: 关注者 following: 正在关注 media: 媒体 + moved_html: "%{name} 已经迁移到 %{new_profile_link}:" nothing_here: 这里神马都没有! - people_followed_by: 正关注 - people_who_follow: 粉丝 + people_followed_by: "%{name} 关注的人" + people_who_follow: 关注 %{name} 的人 posts: 嘟文 posts_with_replies: 嘟文和回复 remote_follow: 跨站关注 reserved_username: 此用户名已保留 roles: admin: 管理员 + moderator: 协管 unfollow: 取消关注 admin: account_moderation_notes: @@ -88,7 +90,7 @@ zh-CN: memorialize: 设置为追悼帐户 moderation: all: 全部 - silenced: 已静音 + silenced: 已隐藏 suspended: 已封禁 title: 帐户状态 moderation_notes: 管理记录 @@ -122,11 +124,11 @@ zh-CN: created_reports: 这个帐户提交的举报 report: 个举报 targeted_reports: 针对这个帐户的举报 - silence: 静音 + silence: 隐藏 statuses: 嘟文 subscribe: 订阅 title: 用户 - undo_silenced: 解除静音 + undo_silenced: 解除隐藏 undo_suspension: 解除封禁 unsubscribe: 取消订阅 username: 用户名 @@ -164,23 +166,23 @@ zh-CN: create: 添加域名屏蔽 hint: 域名屏蔽不会阻止该域名下的帐户进入本站的数据库,但是会对来自这个域名的帐户自动进行预先设置的管理操作。 severity: - desc_html: 选择自动静音会将该域名下帐户发送的嘟文设置为仅关注者可见;选择自动封禁会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;如果你只是想拒绝接收来自该域名的任何媒体文件,请选择无。 + desc_html: 选择自动隐藏会将该域名下帐户发送的嘟文设置为仅关注者可见;选择自动封禁会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;如果你只是想拒绝接收来自该域名的任何媒体文件,请选择无。 noop: 无 - silence: 自动静音 + silence: 自动隐藏 suspend: 自动封禁 title: 添加域名屏蔽 reject_media: 拒绝接收媒体文件 reject_media_hint: 删除本地已缓存的媒体文件,并且不再接收来自该域名的任何媒体文件。此选项不影响封禁 severities: noop: 无 - silence: 自动静音 + silence: 自动隐藏 suspend: 自动封禁 severity: 屏蔽级别 show: affected_accounts: 将会影响到数据库中的 %{count} 个帐户 retroactive: - silence: 对此域名的所有帐户取消静音 - suspend: 对此域名的所有帐户取消封禁 + silence: 对此域名的所有帐户解除隐藏 + suspend: 对此域名的所有帐户解除封禁 title: 撤销对 %{domain} 的域名屏蔽 undo: 撤销 title: 域名屏蔽 @@ -218,7 +220,7 @@ zh-CN: reported_account: 举报用户 reported_by: 举报人 resolved: 已处理 - silence_account: 静音用户 + silence_account: 隐藏用户 status: 状态 suspend_account: 封禁用户 target: 被举报人 @@ -242,6 +244,9 @@ zh-CN: open: desc_html: 允许任何人建立一个帐户 title: 开放注册 + show_staff_badge: + desc_html: 在个人资料页上显示管理员标志 + title: 显示管理员标志 site_description: desc_html: 展示在首页以及 meta 标签中的网站简介。可以使用 HTML 标签,包括<a>
和 <em>
。
title: 本站简介
@@ -361,7 +366,7 @@ zh-CN:
blocks: 屏蔽的用户
csv: CSV
follows: 关注的用户
- mutes: 静音的用户
+ mutes: 隐藏的用户
storage: 媒体文件存储
followers:
domain: 域名
@@ -386,10 +391,10 @@ zh-CN:
types:
blocking: 屏蔽列表
following: 关注列表
- muting: 静音列表
+ muting: 隐藏列表
upload: 上传
in_memoriam_html: 谨此悼念。
- landing_strip_html: "%{name} 是一位来自 %{link_to_root_path} 的用户。如果你想关注这个人或者与这个人互动,你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。"
+ landing_strip_html: "%{name} 是一位来自 %{link_to_root_path} 的用户。如果你想关注他们或者与他们互动,你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。"
landing_strip_signup_html: 还没有这种帐户?你可以在本站注册一个。
media_attachments:
validations:
@@ -601,8 +606,6 @@ zh-CN:
原文出自 Discourse 隐私权政策。
title: "%{instance} 使用条款和隐私权政策" - themes: - default: Mastodon time: formats: default: "%Y年%-m月%d日 %H:%M" diff --git a/config/navigation.rb b/config/navigation.rb index 16c48849b35..3f4c00dfa9d 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -5,7 +5,7 @@ SimpleNavigation::Configuration.run do |navigation| primary.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_url primary.item :settings, safe_join([fa_icon('cog fw'), t('settings.settings')]), settings_profile_url do |settings| - settings.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_url + settings.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_url, highlights_on: %r{/settings/profile|/settings/migration} settings.item :preferences, safe_join([fa_icon('sliders fw'), t('settings.preferences')]), settings_preferences_url settings.item :keyword_mutes, safe_join([fa_icon('volume-off fw'), t('settings.keyword_mutes')]), settings_keyword_mutes_url settings.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_notifications_url @@ -17,21 +17,28 @@ SimpleNavigation::Configuration.run do |navigation| settings.item :follower_domains, safe_join([fa_icon('users fw'), t('settings.followers')]), settings_follower_domains_url end + primary.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: proc { Setting.min_invite_role == 'user' } + primary.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_url do |development| development.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url, highlights_on: %r{/settings/applications} end - primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin| + primary.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin| + admin.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url 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 :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}, if: -> { current_user.admin? } - admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? } 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}, if: -> { current_user.admin? } admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? } - admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? } - admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? } + end + + primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), proc { current_user.admin? ? edit_admin_settings_url : admin_custom_emojis_url }, if: proc { current_user.staff? } do |admin| admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? } admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis} + admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? } + admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? } + admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? } end primary.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_url, link_html: { 'data-method' => 'delete' } diff --git a/config/routes.rb b/config/routes.rb index 7812e4b361e..a41e76c2cc7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,6 +22,10 @@ Rails.application.routes.draw do get 'manifest', to: 'manifests#show', defaults: { format: 'json' } get 'intent', to: 'intents#show' + devise_scope :user do + get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite + end + devise_for :users, path: 'auth', controllers: { sessions: 'auth/sessions', registrations: 'auth/registrations', @@ -99,6 +103,7 @@ Rails.application.routes.draw do end resource :delete, only: [:show, :destroy] + resource :migration, only: [:show, :update] resources :sessions, only: [:destroy] end @@ -106,6 +111,7 @@ Rails.application.routes.draw do resources :media, only: [:show] resources :tags, only: [:show] resources :emojis, only: [:show] + resources :invites, only: [:index, :create, :destroy] get '/media_proxy/:id/(*any)', to: 'media_proxy#show', as: :media_proxy @@ -117,7 +123,9 @@ Rails.application.routes.draw do resources :subscriptions, only: [:index] resources :domain_blocks, only: [:index, :new, :create, :show, :destroy] resources :email_domain_blocks, only: [:index, :new, :create, :destroy] + resources :action_logs, only: [:index] resource :settings, only: [:edit, :update] + resources :invites, only: [:index, :create, :destroy] resources :instances, only: [:index] do collection do diff --git a/config/settings.yml b/config/settings.yml index 48d971d44c3..5aad45da225 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -17,6 +17,8 @@ defaults: &defaults closed_registrations_message: '' open_deletion: true timeline_preview: false + min_invite_role: 'admin' + show_staff_badge: true default_sensitive: false unfollow_modal: false boost_modal: false diff --git a/db/migrate/20171028221157_add_reblogs_to_follows.rb b/db/migrate/20171028221157_add_reblogs_to_follows.rb index eb4640a2010..4b5d5b7ff36 100644 --- a/db/migrate/20171028221157_add_reblogs_to_follows.rb +++ b/db/migrate/20171028221157_add_reblogs_to_follows.rb @@ -3,9 +3,7 @@ require Rails.root.join('lib', 'mastodon', 'migration_helpers') class AddReblogsToFollows < ActiveRecord::Migration[5.1] include Mastodon::MigrationHelpers - safety_assured do - disable_ddl_transaction! - end + disable_ddl_transaction! def up safety_assured do diff --git a/db/migrate/20171118012443_add_moved_to_account_id_to_accounts.rb b/db/migrate/20171118012443_add_moved_to_account_id_to_accounts.rb new file mode 100644 index 00000000000..0c8a894cca2 --- /dev/null +++ b/db/migrate/20171118012443_add_moved_to_account_id_to_accounts.rb @@ -0,0 +1,6 @@ +class AddMovedToAccountIdToAccounts < ActiveRecord::Migration[5.1] + def change + add_column :accounts, :moved_to_account_id, :bigint, null: true, default: nil + add_foreign_key :accounts, :accounts, column: :moved_to_account_id, on_delete: :nullify + end +end diff --git a/db/migrate/20171119172437_create_admin_action_logs.rb b/db/migrate/20171119172437_create_admin_action_logs.rb new file mode 100644 index 00000000000..0c2b6c623d1 --- /dev/null +++ b/db/migrate/20171119172437_create_admin_action_logs.rb @@ -0,0 +1,12 @@ +class CreateAdminActionLogs < ActiveRecord::Migration[5.1] + def change + create_table :admin_action_logs do |t| + t.belongs_to :account, foreign_key: { on_delete: :cascade } + t.string :action, null: false, default: '' + t.references :target, polymorphic: true + t.text :recorded_changes, null: false, default: '' + + t.timestamps + end + end +end diff --git a/db/migrate/20171122120436_add_index_account_and_reblog_of_id_to_statuses.rb b/db/migrate/20171122120436_add_index_account_and_reblog_of_id_to_statuses.rb new file mode 100644 index 00000000000..131e54b72ef --- /dev/null +++ b/db/migrate/20171122120436_add_index_account_and_reblog_of_id_to_statuses.rb @@ -0,0 +1,12 @@ +class AddIndexAccountAndReblogOfIdToStatuses < ActiveRecord::Migration[5.1] + disable_ddl_transaction! + + def up + # This index has been superseded by migration 20171125185353 + # add_index :statuses, [:account_id, :reblog_of_id], algorithm: :concurrently + end + + def down + remove_index :statuses, [:account_id, :reblog_of_id] if index_exists?(:statuses, [:account_id, :reblog_of_id]) + end +end diff --git a/db/migrate/20171125024930_create_invites.rb b/db/migrate/20171125024930_create_invites.rb new file mode 100644 index 00000000000..bcf03bd723e --- /dev/null +++ b/db/migrate/20171125024930_create_invites.rb @@ -0,0 +1,15 @@ +class CreateInvites < ActiveRecord::Migration[5.1] + def change + create_table :invites do |t| + t.belongs_to :user, foreign_key: { on_delete: :cascade } + t.string :code, null: false, default: '' + t.datetime :expires_at, null: true, default: nil + t.integer :max_uses, null: true, default: nil + t.integer :uses, null: false, default: 0 + + t.timestamps + end + + add_index :invites, :code, unique: true + end +end diff --git a/db/migrate/20171125031751_add_invite_id_to_users.rb b/db/migrate/20171125031751_add_invite_id_to_users.rb new file mode 100644 index 00000000000..16829f86659 --- /dev/null +++ b/db/migrate/20171125031751_add_invite_id_to_users.rb @@ -0,0 +1,5 @@ +class AddInviteIdToUsers < ActiveRecord::Migration[5.1] + def change + add_reference :users, :invite, null: true, default: nil, foreign_key: { on_delete: :nullify }, index: false + end +end diff --git a/db/migrate/20171125185353_add_index_reblog_of_id_and_account_to_statuses.rb b/db/migrate/20171125185353_add_index_reblog_of_id_and_account_to_statuses.rb new file mode 100644 index 00000000000..37662eaa5d5 --- /dev/null +++ b/db/migrate/20171125185353_add_index_reblog_of_id_and_account_to_statuses.rb @@ -0,0 +1,7 @@ +class AddIndexReblogOfIdAndAccountToStatuses < ActiveRecord::Migration[5.1] + disable_ddl_transaction! + + def change + add_index :statuses, [:reblog_of_id, :account_id], algorithm: :concurrently + end +end diff --git a/db/migrate/20171125190735_remove_old_reblog_index_on_statuses.rb b/db/migrate/20171125190735_remove_old_reblog_index_on_statuses.rb new file mode 100644 index 00000000000..68146c5ce0c --- /dev/null +++ b/db/migrate/20171125190735_remove_old_reblog_index_on_statuses.rb @@ -0,0 +1,14 @@ +class RemoveOldReblogIndexOnStatuses < ActiveRecord::Migration[5.1] + disable_ddl_transaction! + + def up + # This index may not exists (see migration 20171122120436) + remove_index :statuses, [:account_id, :reblog_of_id] if index_exists?(:statuses, [:account_id, :reblog_of_id]) + + remove_index :statuses, :reblog_of_id + end + + def down + add_index :statuses, :reblog_of_id, algorithm: :concurrently + end +end diff --git a/db/migrate/20171129172043_add_index_on_stream_entries.rb b/db/migrate/20171129172043_add_index_on_stream_entries.rb new file mode 100644 index 00000000000..478530c7fdb --- /dev/null +++ b/db/migrate/20171129172043_add_index_on_stream_entries.rb @@ -0,0 +1,7 @@ +class AddIndexOnStreamEntries < ActiveRecord::Migration[5.1] + def change + commit_db_transaction + add_index :stream_entries, [:account_id, :activity_type, :id], algorithm: :concurrently + remove_index :stream_entries, name: :index_stream_entries_on_account_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 10e35cd7deb..c87c9b393e3 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: 20171116161857) do +ActiveRecord::Schema.define(version: 20171129172043) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -72,6 +72,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do t.string "followers_url", default: "", null: false t.integer "protocol", default: 0, null: false t.boolean "memorial", default: false, null: false + t.bigint "moved_to_account_id" t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower" t.index ["uri"], name: "index_accounts_on_uri" @@ -79,6 +80,18 @@ ActiveRecord::Schema.define(version: 20171116161857) do t.index ["username", "domain"], name: "index_accounts_on_username_and_domain", unique: true end + create_table "admin_action_logs", force: :cascade do |t| + t.bigint "account_id" + t.string "action", default: "", null: false + t.string "target_type" + t.bigint "target_id" + t.text "recorded_changes", default: "", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_admin_action_logs_on_account_id" + t.index ["target_type", "target_id"], name: "index_admin_action_logs_on_target_type_and_target_id" + end + create_table "blocks", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -181,6 +194,18 @@ ActiveRecord::Schema.define(version: 20171116161857) do t.bigint "account_id", null: false end + create_table "invites", force: :cascade do |t| + t.bigint "user_id" + t.string "code", default: "", null: false + t.datetime "expires_at" + t.integer "max_uses" + t.integer "uses", default: 0, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["code"], name: "index_invites_on_code", unique: true + t.index ["user_id"], name: "index_invites_on_user_id" + end + create_table "list_accounts", force: :cascade do |t| t.bigint "list_id", null: false t.bigint "account_id", null: false @@ -397,7 +422,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do t.index ["account_id", "id"], name: "index_statuses_on_account_id_id" t.index ["conversation_id"], name: "index_statuses_on_conversation_id" t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id" - t.index ["reblog_of_id"], name: "index_statuses_on_reblog_of_id" + t.index ["reblog_of_id", "account_id"], name: "index_statuses_on_reblog_of_id_and_account_id" t.index ["uri"], name: "index_statuses_on_uri", unique: true end @@ -415,7 +440,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do t.datetime "updated_at", null: false t.boolean "hidden", default: false, null: false t.bigint "account_id" - t.index ["account_id"], name: "index_stream_entries_on_account_id" + t.index ["account_id", "activity_type", "id"], name: "index_stream_entries_on_account_id_and_activity_type_and_id" t.index ["activity_id", "activity_type"], name: "index_stream_entries_on_activity_id_and_activity_type" end @@ -470,6 +495,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do t.bigint "account_id", null: false t.boolean "disabled", default: false, null: false t.boolean "moderator", default: false, null: false + t.bigint "invite_id" t.index ["account_id"], name: "index_users_on_account_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true @@ -497,6 +523,8 @@ ActiveRecord::Schema.define(version: 20171116161857) do add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade add_foreign_key "account_moderation_notes", "accounts" add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id" + add_foreign_key "accounts", "accounts", column: "moved_to_account_id", on_delete: :nullify + add_foreign_key "admin_action_logs", "accounts", on_delete: :cascade add_foreign_key "blocks", "accounts", column: "target_account_id", name: "fk_9571bfabc1", on_delete: :cascade add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade @@ -509,6 +537,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do add_foreign_key "follows", "accounts", name: "fk_32ed1b5560", on_delete: :cascade add_foreign_key "glitch_keyword_mutes", "accounts", on_delete: :cascade add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade + add_foreign_key "invites", "users", on_delete: :cascade add_foreign_key "list_accounts", "accounts", on_delete: :cascade add_foreign_key "list_accounts", "follows", on_delete: :cascade add_foreign_key "list_accounts", "lists", on_delete: :cascade @@ -542,5 +571,6 @@ ActiveRecord::Schema.define(version: 20171116161857) do add_foreign_key "stream_entries", "accounts", name: "fk_5659b17554", on_delete: :cascade add_foreign_key "subscriptions", "accounts", name: "fk_9847d1cbb5", on_delete: :cascade add_foreign_key "users", "accounts", name: "fk_50500f500d", on_delete: :cascade + add_foreign_key "users", "invites", on_delete: :nullify add_foreign_key "web_settings", "users", name: "fk_11910667b2", on_delete: :cascade end diff --git a/package.json b/package.json index 159181030bb..5ee4e76a9fc 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "axios": "~0.16.2", "babel-core": "^6.25.0", "babel-loader": "^7.1.1", - "babel-plugin-lodash": "^3.2.11", + "babel-plugin-lodash": "^3.3.2", "babel-plugin-preval": "^1.6.1", "babel-plugin-react-intl": "^2.3.1", "babel-plugin-syntax-dynamic-import": "^6.18.0", @@ -55,9 +55,9 @@ "glob": "^7.1.1", "http-link-header": "^0.8.0", "immutable": "^3.8.2", - "intersection-observer": "^0.4.0", + "intersection-observer": "^0.5.0", "intl": "^1.2.5", - "intl-messageformat": "^2.1.0", + "intl-messageformat": "^2.2.0", "intl-relativeformat": "^2.1.0", "is-nan": "^1.2.1", "js-yaml": "^3.9.0", @@ -65,22 +65,22 @@ "mark-loader": "^0.1.6", "marky": "^1.2.0", "mkdirp": "^0.5.1", - "node-sass": "^4.5.2", + "node-sass": "^4.7.2", "npmlog": "^4.1.2", "object-assign": "^4.1.1", "object-fit-images": "^3.2.3", "offline-plugin": "^4.8.3", "path-complete-extname": "^0.1.0", "pg": "^6.4.0", - "postcss-loader": "^2.0.8", + "postcss-loader": "^2.0.9", "postcss-object-fit-images": "^1.1.2", "postcss-smart-import": "^0.7.5", "precss": "^2.0.0", "prop-types": "^15.5.10", "punycode": "^2.1.0", "rails-ujs": "^5.1.2", - "react": "^16.0.0", - "react-dom": "^16.0.0", + "react": "^16.2.0", + "react-dom": "^16.2.0", "react-hotkeys": "^0.10.0", "react-immutable-proptypes": "^2.1.0", "react-immutable-pure-component": "^1.1.1", @@ -93,7 +93,7 @@ "react-router-dom": "^4.1.1", "react-router-scroll-4": "^1.0.0-beta.1", "react-swipeable-views": "^0.12.3", - "react-textarea-autosize": "^5.0.7", + "react-textarea-autosize": "^5.2.1", "react-toggle": "^4.0.1", "redis": "^2.7.1", "redux": "^3.7.1", @@ -104,23 +104,23 @@ "resolve-url-loader": "^2.2.0", "rimraf": "^2.6.1", "sass-loader": "^6.0.6", - "stringz": "^0.2.2", + "stringz": "^0.3.0", "style-loader": "^0.19.0", "substring-trie": "^1.0.2", "throng": "^4.0.0", "tiny-queue": "^0.2.1", "uuid": "^3.1.0", "uws": "^8.14.0", - "webpack": "^3.8.1", - "webpack-bundle-analyzer": "^2.8.3", + "webpack": "^3.9.1", + "webpack-bundle-analyzer": "^2.9.1", "webpack-manifest-plugin": "^1.2.1", - "webpack-merge": "^4.1.0", + "webpack-merge": "^4.1.1", "websocket.js": "^0.1.12" }, "devDependencies": { "babel-eslint": "^7.2.3", - "enzyme": "^3.0.0", - "enzyme-adapter-react-16": "^1.0.2", + "enzyme": "^3.2.0", + "enzyme-adapter-react-16": "^1.1.0", "eslint": "^3.19.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-jsx-a11y": "^4.0.0", @@ -128,8 +128,8 @@ "jest": "^21.2.1", "raf": "^3.4.0", "react-intl-translations-manager": "^5.0.0", - "react-test-renderer": "^16.0.0", - "webpack-dev-server": "^2.9.3", + "react-test-renderer": "^16.2.0", + "webpack-dev-server": "^2.9.5", "yargs": "^8.0.2" }, "optionalDependencies": { diff --git a/spec/fabricators/admin_action_log_fabricator.rb b/spec/fabricators/admin_action_log_fabricator.rb new file mode 100644 index 00000000000..2f44e953d94 --- /dev/null +++ b/spec/fabricators/admin_action_log_fabricator.rb @@ -0,0 +1,5 @@ +Fabricator('Admin::ActionLog') do + account nil + action "MyString" + target nil +end diff --git a/spec/fabricators/invite_fabricator.rb b/spec/fabricators/invite_fabricator.rb new file mode 100644 index 00000000000..62b9b3904a2 --- /dev/null +++ b/spec/fabricators/invite_fabricator.rb @@ -0,0 +1,6 @@ +Fabricator(:invite) do + user + expires_at nil + max_uses nil + uses 0 +end diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb index 38254e31c35..37b93ecf73a 100644 --- a/spec/lib/activitypub/activity/delete_spec.rb +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -1,8 +1,8 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Delete do - let(:sender) { Fabricate(:account, domain: 'example.com') } - let(:status) { Fabricate(:status, account: sender, uri: 'foobar') } + let(:sender) { Fabricate(:account, domain: 'example.com') } + let(:status) { Fabricate(:status, account: sender, uri: 'foobar') } let(:json) do { @@ -30,13 +30,13 @@ RSpec.describe ActivityPub::Activity::Delete do context 'when the status has been reblogged' do describe '#perform' do subject { described_class.new(json, sender) } - let(:reblogger) { Fabricate(:account) } - let(:follower) { Fabricate(:account, username: 'follower', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } + let!(:reblogger) { Fabricate(:account) } + let!(:follower) { Fabricate(:account, username: 'follower', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } + let!(:reblog) { Fabricate(:status, account: reblogger, reblog: status) } before do stub_request(:post, 'http://example.com/inbox').to_return(status: 200) follower.follow!(reblogger) - Fabricate(:status, account: reblogger, reblog: status) subject.perform end @@ -45,8 +45,7 @@ RSpec.describe ActivityPub::Activity::Delete do end it 'sends delete activity to followers of rebloggers' do - # one for Delete original post, and one for Undo reblog (normal delivery) - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.twice + expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end end diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index ba96b6e7e15..f87ef383a3f 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -164,6 +164,22 @@ RSpec.describe FeedManager do expect(FeedManager.instance.filter?(:home, reblog, alice.id)).to be true end + + it 'returns true for a status with a tag that matches a muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: 'jorts') + status = Fabricate(:status, account: bob) + status.tags << Fabricate(:tag, name: 'jorts') + + expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true + end + + it 'returns true for a status with a tag that matches an octothorpe-prefixed muted keyword' do + Fabricate('Glitch::KeywordMute', account: alice, keyword: '#jorts') + status = Fabricate(:status, account: bob) + status.tags << Fabricate(:tag, name: 'jorts') + + expect(FeedManager.instance.filter?(:home, status, alice.id)).to be true + end end context 'for mentions feed' do diff --git a/spec/lib/settings/extend_spec.rb b/spec/lib/settings/extend_spec.rb new file mode 100644 index 00000000000..83ced4230ca --- /dev/null +++ b/spec/lib/settings/extend_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Settings::Extend do + class User + include Settings::Extend + end + + describe '#settings' do + it 'sets @settings as an instance of Settings::ScopedSettings' do + user = Fabricate(:user) + expect(user.settings).to be_kind_of Settings::ScopedSettings + end + end +end diff --git a/spec/models/admin/action_log_spec.rb b/spec/models/admin/action_log_spec.rb new file mode 100644 index 00000000000..59206a36b3f --- /dev/null +++ b/spec/models/admin/action_log_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Admin::ActionLog, type: :model do + +end diff --git a/spec/models/concerns/account_interactions_spec.rb b/spec/models/concerns/account_interactions_spec.rb index 1e238e27c30..95bf9561dcc 100644 --- a/spec/models/concerns/account_interactions_spec.rb +++ b/spec/models/concerns/account_interactions_spec.rb @@ -1,6 +1,561 @@ require 'rails_helper' describe AccountInteractions do + let(:account) { Fabricate(:account, username: 'account') } + let(:account_id) { account.id } + let(:account_ids) { [account_id] } + let(:target_account) { Fabricate(:account, username: 'target') } + let(:target_account_id) { target_account.id } + let(:target_account_ids) { [target_account_id] } + + describe '.following_map' do + subject { Account.following_map(target_account_ids, account_id) } + + context 'account with Follow' do + it 'returns { target_account_id => { reblogs: true } }' do + Fabricate(:follow, account: account, target_account: target_account) + is_expected.to eq(target_account_id => { reblogs: true }) + end + end + + context 'account with Follow but with reblogs disabled' do + it 'returns { target_account_id => { reblogs: false } }' do + Fabricate(:follow, account: account, target_account: target_account, show_reblogs: false) + is_expected.to eq(target_account_id => { reblogs: false }) + end + end + + context 'account without Follow' do + it 'returns {}' do + is_expected.to eq({}) + end + end + end + + describe '.followed_by_map' do + subject { Account.followed_by_map(target_account_ids, account_id) } + + context 'account with Follow' do + it 'returns { target_account_id => true }' do + Fabricate(:follow, account: target_account, target_account: account) + is_expected.to eq(target_account_id => true) + end + end + + context 'account without Follow' do + it 'returns {}' do + is_expected.to eq({}) + end + end + end + + describe '.blocking_map' do + subject { Account.blocking_map(target_account_ids, account_id) } + + context 'account with Block' do + it 'returns { target_account_id => true }' do + Fabricate(:block, account: account, target_account: target_account) + is_expected.to eq(target_account_id => true) + end + end + + context 'account without Block' do + it 'returns {}' do + is_expected.to eq({}) + end + end + end + + describe '.muting_map' do + subject { Account.muting_map(target_account_ids, account_id) } + + context 'account with Mute' do + before do + Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide) + end + + context 'if Mute#hide_notifications?' do + let(:hide) { true } + + it 'returns { target_account_id => { notifications: true } }' do + is_expected.to eq(target_account_id => { notifications: true }) + end + end + + context 'unless Mute#hide_notifications?' do + let(:hide) { false } + + it 'returns { target_account_id => { notifications: false } }' do + is_expected.to eq(target_account_id => { notifications: false }) + end + end + end + + context 'account without Mute' do + it 'returns {}' do + is_expected.to eq({}) + end + end + end + + describe '#follow!' do + it 'creates and returns Follow' do + expect do + expect(account.follow!(target_account)).to be_kind_of Follow + end.to change { account.following.count }.by 1 + end + end + + describe '#block' do + it 'creates and returns Block' do + expect do + expect(account.block!(target_account)).to be_kind_of Block + end.to change { account.block_relationships.count }.by 1 + end + end + + describe '#mute!' do + context 'Mute does not exist yet' do + context 'arg :notifications is nil' do + let(:arg_notifications) { nil } + + it 'creates Mute, and returns nil' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be nil + end.to change { account.mute_relationships.count }.by 1 + end + end + + context 'arg :notifications is false' do + let(:arg_notifications) { false } + + it 'creates Mute, and returns nil' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be nil + end.to change { account.mute_relationships.count }.by 1 + end + end + + context 'arg :notifications is true' do + let(:arg_notifications) { true } + + it 'creates Mute, and returns nil' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be nil + end.to change { account.mute_relationships.count }.by 1 + end + end + end + + context 'Mute already exists' do + before do + account.mute_relationships << mute + end + + let(:mute) do + Fabricate(:mute, + account: account, + target_account: target_account, + hide_notifications: hide_notifications) + end + + context 'mute.hide_notifications is true' do + let(:hide_notifications) { true } + + context 'arg :notifications is nil' do + let(:arg_notifications) { nil } + + it 'returns nil without updating mute.hide_notifications' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be nil + mute = account.mute_relationships.find_by(target_account: target_account) + expect(mute.hide_notifications?).to be true + end + end + end + + context 'arg :notifications is false' do + let(:arg_notifications) { false } + + it 'returns true, and updates mute.hide_notifications false' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be true + mute = account.mute_relationships.find_by(target_account: target_account) + expect(mute.hide_notifications?).to be false + end + end + end + + context 'arg :notifications is true' do + let(:arg_notifications) { true } + + it 'returns nil without updating mute.hide_notifications' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be nil + mute = account.mute_relationships.find_by(target_account: target_account) + expect(mute.hide_notifications?).to be true + end + end + end + end + + context 'mute.hide_notifications is false' do + let(:hide_notifications) { false } + + context 'arg :notifications is nil' do + let(:arg_notifications) { nil } + + it 'returns true, and updates mute.hide_notifications true' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be true + mute = account.mute_relationships.find_by(target_account: target_account) + expect(mute.hide_notifications?).to be true + end + end + end + + context 'arg :notifications is false' do + let(:arg_notifications) { false } + + it 'returns nil without updating mute.hide_notifications' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be nil + mute = account.mute_relationships.find_by(target_account: target_account) + expect(mute.hide_notifications?).to be false + end + end + end + + context 'arg :notifications is true' do + let(:arg_notifications) { true } + + it 'returns true, and updates mute.hide_notifications true' do + expect do + expect(account.mute!(target_account, notifications: arg_notifications)).to be true + mute = account.mute_relationships.find_by(target_account: target_account) + expect(mute.hide_notifications?).to be true + end + end + end + end + end + end + + describe '#mute_conversation!' do + let(:conversation) { Fabricate(:conversation) } + + subject { account.mute_conversation!(conversation) } + + it 'creates and returns ConversationMute' do + expect do + is_expected.to be_kind_of ConversationMute + end.to change { account.conversation_mutes.count }.by 1 + end + end + + describe '#block_domain!' do + let(:domain_block) { Fabricate(:domain_block) } + + subject { account.block_domain!(domain_block) } + + it 'creates and returns AccountDomainBlock' do + expect do + is_expected.to be_kind_of AccountDomainBlock + end.to change { account.domain_blocks.count }.by 1 + end + end + + describe '#unfollow!' do + subject { account.unfollow!(target_account) } + + context 'following target_account' do + it 'returns destroyed Follow' do + account.active_relationships.create(target_account: target_account) + is_expected.to be_kind_of Follow + expect(subject).to be_destroyed + end + end + + context 'not following target_account' do + it 'returns nil' do + is_expected.to be_nil + end + end + end + + describe '#unblock!' do + subject { account.unblock!(target_account) } + + context 'blocking target_account' do + it 'returns destroyed Block' do + account.block_relationships.create(target_account: target_account) + is_expected.to be_kind_of Block + expect(subject).to be_destroyed + end + end + + context 'not blocking target_account' do + it 'returns nil' do + is_expected.to be_nil + end + end + end + + describe '#unmute!' do + subject { account.unmute!(target_account) } + + context 'muting target_account' do + it 'returns destroyed Mute' do + account.mute_relationships.create(target_account: target_account) + is_expected.to be_kind_of Mute + expect(subject).to be_destroyed + end + end + + context 'not muting target_account' do + it 'returns nil' do + is_expected.to be_nil + end + end + end + + describe '#unmute_conversation!' do + let(:conversation) { Fabricate(:conversation) } + + subject { account.unmute_conversation!(conversation) } + + context 'muting the conversation' do + it 'returns destroyed ConversationMute' do + account.conversation_mutes.create(conversation: conversation) + is_expected.to be_kind_of ConversationMute + expect(subject).to be_destroyed + end + end + + context 'not muting the conversation' do + it 'returns nil' do + is_expected.to be nil + end + end + end + + describe '#unblock_domain!' do + let(:domain) { 'example.com' } + + subject { account.unblock_domain!(domain) } + + context 'blocking the domain' do + it 'returns destroyed AccountDomainBlock' do + account_domain_block = Fabricate(:account_domain_block, domain: domain) + account.domain_blocks << account_domain_block + is_expected.to be_kind_of AccountDomainBlock + expect(subject).to be_destroyed + end + end + + context 'unblocking the domain' do + it 'returns nil' do + is_expected.to be_nil + end + end + end + + describe '#following?' do + subject { account.following?(target_account) } + + context 'following target_account' do + it 'returns true' do + account.active_relationships.create(target_account: target_account) + is_expected.to be true + end + end + + context 'not following target_account' do + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#blocking?' do + subject { account.blocking?(target_account) } + + context 'blocking target_account' do + it 'returns true' do + account.block_relationships.create(target_account: target_account) + is_expected.to be true + end + end + + context 'not blocking target_account' do + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#domain_blocking?' do + let(:domain) { 'example.com' } + + subject { account.domain_blocking?(domain) } + + context 'blocking the domain' do + it' returns true' do + account_domain_block = Fabricate(:account_domain_block, domain: domain) + account.domain_blocks << account_domain_block + is_expected.to be true + end + end + + context 'not blocking the domain' do + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#muting?' do + subject { account.muting?(target_account) } + + context 'muting target_account' do + it 'returns true' do + mute = Fabricate(:mute, account: account, target_account: target_account) + account.mute_relationships << mute + is_expected.to be true + end + end + + context 'not muting target_account' do + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#muting_conversation?' do + let(:conversation) { Fabricate(:conversation) } + + subject { account.muting_conversation?(conversation) } + + context 'muting the conversation' do + it 'returns true' do + account.conversation_mutes.create(conversation: conversation) + is_expected.to be true + end + end + + context 'not muting the conversation' do + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#muting_notifications?' do + before do + mute = Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide) + account.mute_relationships << mute + end + + subject { account.muting_notifications?(target_account) } + + context 'muting notifications of target_account' do + let(:hide) { true } + + it 'returns true' do + is_expected.to be true + end + end + + context 'not muting notifications of target_account' do + let(:hide) { false } + + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#requested?' do + subject { account.requested?(target_account) } + + context 'requested by target_account' do + it 'returns true' do + Fabricate(:follow_request, account: account, target_account: target_account) + is_expected.to be true + end + end + + context 'not requested by target_account' do + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#favourited?' do + let(:status) { Fabricate(:status, account: account, favourites: favourites) } + + subject { account.favourited?(status) } + + context 'favorited' do + let(:favourites) { [Fabricate(:favourite, account: account)] } + + it 'returns true' do + is_expected.to be true + end + end + + context 'not favorited' do + let(:favourites) { [] } + + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#reblogged?' do + let(:status) { Fabricate(:status, account: account, reblogs: reblogs) } + + subject { account.reblogged?(status) } + + context 'reblogged' do + let(:reblogs) { [Fabricate(:status, account: account)] } + + it 'returns true' do + is_expected.to be true + end + end + + context 'not reblogged' do + let(:reblogs) { [] } + + it 'returns false' do + is_expected.to be false + end + end + end + + describe '#pinned?' do + let(:status) { Fabricate(:status, account: account) } + + subject { account.pinned?(status) } + + context 'pinned' do + it 'returns true' do + Fabricate(:status_pin, account: account, status: status) + is_expected.to be true + end + end + + context 'not pinned' do + it 'returns false' do + is_expected.to be false + end + end + end + describe 'muting an account' do let(:me) { Fabricate(:account, username: 'Me') } let(:you) { Fabricate(:account, username: 'You') } @@ -72,4 +627,41 @@ describe AccountInteractions do end end end + + describe 'ignoring reblogs from an account' do + before do + @me = Fabricate(:account, username: 'Me') + @you = Fabricate(:account, username: 'You') + end + + context 'with the reblogs option unspecified' do + before do + @me.follow!(@you) + end + + it 'defaults to showing reblogs' do + expect(@me.muting_reblogs?(@you)).to be(false) + end + end + + context 'with the reblogs option set to false' do + before do + @me.follow!(@you, reblogs: false) + end + + it 'does mute reblogs' do + expect(@me.muting_reblogs?(@you)).to be(true) + end + end + + context 'with the reblogs option set to true' do + before do + @me.follow!(@you, reblogs: true) + end + + it 'does not mute reblogs' do + expect(@me.muting_reblogs?(@you)).to be(false) + end + end + end end diff --git a/spec/models/concerns/remotable_spec.rb b/spec/models/concerns/remotable_spec.rb new file mode 100644 index 00000000000..0b2dad23f0d --- /dev/null +++ b/spec/models/concerns/remotable_spec.rb @@ -0,0 +1,205 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Remotable do + class Foo + def initialize + @attrs = {} + end + + def [](arg) + @attrs[arg] + end + + def []=(arg1, arg2) + @attrs[arg1] = arg2 + end + + def hoge=(arg); end + + def hoge_file_name=(arg); end + + def has_attribute?(arg); end + + def self.attachment_definitions + { hoge: nil } + end + end + + context 'Remotable module is included' do + before do + class Foo; include Remotable; end + end + + let(:attribute_name) { "#{hoge}_remote_url".to_sym } + let(:code) { 200 } + let(:file) { 'filename="foo.txt"' } + let(:foo) { Foo.new } + let(:headers) { { 'content-disposition' => file } } + let(:hoge) { :hoge } + let(:url) { 'https://google.com' } + + let(:request) do + stub_request(:get, url) + .to_return(status: code, headers: headers) + end + + it 'defines a method #hoge_remote_url=' do + expect(foo).to respond_to(:hoge_remote_url=) + end + + it 'defines a method #reset_hoge!' do + expect(foo).to respond_to(:reset_hoge!) + end + + describe '#hoge_remote_url' do + before do + request + end + + it 'always returns arg' do + [nil, '', [], {}].each do |arg| + expect(foo.hoge_remote_url = arg).to be arg + end + end + + context 'Addressable::URI::InvalidURIError raised' do + it 'makes no request' do + allow(Addressable::URI).to receive_message_chain(:parse, :normalize) + .with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError) + + foo.hoge_remote_url = url + expect(request).not_to have_been_requested + end + end + + context 'scheme is neither http nor https' do + let(:url) { 'ftp://google.com' } + + it 'makes no request' do + foo.hoge_remote_url = url + expect(request).not_to have_been_requested + end + end + + context 'parsed_url.host is empty' do + it 'makes no request' do + parsed_url = double(scheme: 'https', host: double(empty?: true)) + allow(Addressable::URI).to receive_message_chain(:parse, :normalize) + .with(url).with(no_args).and_return(parsed_url) + + foo.hoge_remote_url = url + expect(request).not_to have_been_requested + end + end + + context 'foo[attribute_name] == url' do + it 'makes no request' do + allow(foo).to receive(:[]).with(attribute_name).and_return(url) + + foo.hoge_remote_url = url + expect(request).not_to have_been_requested + end + end + + context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do + it 'makes a request' do + foo.hoge_remote_url = url + expect(request).to have_been_requested + end + + context 'response.code != 200' do + let(:code) { 500 } + + it 'calls not send' do + expect(foo).not_to receive(:send).with("#{hoge}=", any_args) + expect(foo).not_to receive(:send).with("#{hoge}_file_name=", any_args) + foo.hoge_remote_url = url + end + end + + context 'response.code == 200' do + let(:code) { 200 } + + context 'response contains headers["content-disposition"]' do + let(:file) { 'filename="foo.txt"' } + let(:headers) { { 'content-disposition' => file } } + + it 'calls send' do + string_io = StringIO.new('') + extname = '.txt' + basename = '0123456789abcdef' + + allow(SecureRandom).to receive(:hex).and_return(basename) + allow(StringIO).to receive(:new).with(anything).and_return(string_io) + + expect(foo).to receive(:send).with("#{hoge}=", string_io) + expect(foo).to receive(:send).with("#{hoge}_file_name=", basename + extname) + foo.hoge_remote_url = url + end + end + + context 'if has_attribute?' do + it 'calls foo[attribute_name] = url' do + allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true) + expect(foo).to receive('[]=').with(attribute_name, url) + foo.hoge_remote_url = url + end + end + + context 'unless has_attribute?' do + it 'calls not foo[attribute_name] = url' do + allow(foo).to receive(:has_attribute?) + .with(attribute_name).and_return(false) + expect(foo).not_to receive('[]=').with(attribute_name, url) + foo.hoge_remote_url = url + end + end + end + + context 'an error raised during the request' do + let(:request) { stub_request(:get, url).to_raise(error_class) } + + error_classes = [ + HTTP::TimeoutError, + HTTP::ConnectionError, + OpenSSL::SSL::SSLError, + Paperclip::Errors::NotIdentifiedByImageMagickError, + Addressable::URI::InvalidURIError, + ] + + error_classes.each do |error_class| + let(:error_class) { error_class } + + it 'calls Rails.logger.debug' do + expect(Rails.logger).to receive(:debug).with(/^Error fetching remote #{hoge}: /) + foo.hoge_remote_url = url + end + end + end + end + end + + describe '#reset_hoge!' do + context 'if url.blank?' do + it 'returns nil, without clearing foo[attribute_name] and calling #hoge_remote_url=' do + url = nil + expect(foo).not_to receive(:send).with(:hoge_remote_url=, url) + foo[attribute_name] = url + expect(foo.reset_hoge!).to be_nil + expect(foo[attribute_name]).to be_nil + end + end + + context 'unless url.blank?' do + it 'clears foo[attribute_name] and calls #hoge_remote_url=' do + foo[attribute_name] = url + expect(foo).to receive(:send).with(:hoge_remote_url=, url) + foo.reset_hoge! + expect(foo[attribute_name]).to be '' + end + end + end + end +end diff --git a/spec/models/concerns/streamable_spec.rb b/spec/models/concerns/streamable_spec.rb new file mode 100644 index 00000000000..b5f2d51923e --- /dev/null +++ b/spec/models/concerns/streamable_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Streamable do + class Parent + def title; end + + def target; end + + def thread; end + + def self.has_one(*); end + + def self.after_create; end + end + + class Child < Parent + include Streamable + end + + child = Child.new + + describe '#title' do + it 'calls Parent#title' do + expect_any_instance_of(Parent).to receive(:title) + child.title + end + end + + describe '#content' do + it 'calls #title' do + expect_any_instance_of(Parent).to receive(:title) + child.content + end + end + + describe '#target' do + it 'calls Parent#target' do + expect_any_instance_of(Parent).to receive(:target) + child.target + end + end + + describe '#object_type' do + it 'returns :activity' do + expect(child.object_type).to eq :activity + end + end + + describe '#thread' do + it 'calls Parent#thread' do + expect_any_instance_of(Parent).to receive(:thread) + child.thread + end + end + + describe '#hidden?' do + it 'returns false' do + expect(child.hidden?).to be false + end + end +end diff --git a/spec/models/glitch/keyword_mute_spec.rb b/spec/models/glitch/keyword_mute_spec.rb index 9685c649385..0ffc7b18f23 100644 --- a/spec/models/glitch/keyword_mute_spec.rb +++ b/spec/models/glitch/keyword_mute_spec.rb @@ -4,8 +4,8 @@ RSpec.describe Glitch::KeywordMute, type: :model do let(:alice) { Fabricate(:account, username: 'alice').tap(&:save!) } let(:bob) { Fabricate(:account, username: 'bob').tap(&:save!) } - describe '.matcher_for' do - let(:matcher) { Glitch::KeywordMute.matcher_for(alice) } + describe '.text_matcher_for' do + let(:matcher) { Glitch::KeywordMute.text_matcher_for(alice.id) } describe 'with no mutes' do before do @@ -13,7 +13,7 @@ RSpec.describe Glitch::KeywordMute, type: :model do end it 'does not match' do - expect(matcher =~ 'This is a hot take').to be_falsy + expect(matcher.matches?('This is a hot take')).to be_falsy end end @@ -21,75 +21,136 @@ RSpec.describe Glitch::KeywordMute, type: :model do it 'does not match keywords set by a different account' do Glitch::KeywordMute.create!(account: bob, keyword: 'take') - expect(matcher =~ 'This is a hot take').to be_falsy + expect(matcher.matches?('This is a hot take')).to be_falsy end it 'does not match if no keywords match the status text' do Glitch::KeywordMute.create!(account: alice, keyword: 'cold') - expect(matcher =~ 'This is a hot take').to be_falsy + expect(matcher.matches?('This is a hot take')).to be_falsy end it 'considers word boundaries when matching' do Glitch::KeywordMute.create!(account: alice, keyword: 'bob', whole_word: true) - expect(matcher =~ 'bobcats').to be_falsy + expect(matcher.matches?('bobcats')).to be_falsy end it 'matches substrings if whole_word is false' do Glitch::KeywordMute.create!(account: alice, keyword: 'take', whole_word: false) - expect(matcher =~ 'This is a shiitake mushroom').to be_truthy + expect(matcher.matches?('This is a shiitake mushroom')).to be_truthy end it 'matches keywords at the beginning of the text' do Glitch::KeywordMute.create!(account: alice, keyword: 'take') - expect(matcher =~ 'Take this').to be_truthy + expect(matcher.matches?('Take this')).to be_truthy end it 'matches keywords at the end of the text' do Glitch::KeywordMute.create!(account: alice, keyword: 'take') - expect(matcher =~ 'This is a hot take').to be_truthy + expect(matcher.matches?('This is a hot take')).to be_truthy end it 'matches if at least one keyword case-insensitively matches the text' do Glitch::KeywordMute.create!(account: alice, keyword: 'hot') - expect(matcher =~ 'This is a HOT take').to be_truthy + expect(matcher.matches?('This is a HOT take')).to be_truthy end it 'maintains case-insensitivity when combining keywords into a single matcher' do Glitch::KeywordMute.create!(account: alice, keyword: 'hot') Glitch::KeywordMute.create!(account: alice, keyword: 'cold') - expect(matcher =~ 'This is a HOT take').to be_truthy + expect(matcher.matches?('This is a HOT take')).to be_truthy end it 'matches keywords surrounded by non-alphanumeric ornamentation' do Glitch::KeywordMute.create!(account: alice, keyword: 'hot') - expect(matcher =~ '(hot take)').to be_truthy + expect(matcher.matches?('(hot take)')).to be_truthy end it 'escapes metacharacters in keywords' do Glitch::KeywordMute.create!(account: alice, keyword: '(hot take)') - expect(matcher =~ '(hot take)').to be_truthy + expect(matcher.matches?('(hot take)')).to be_truthy end it 'uses case-folding rules appropriate for more than just English' do Glitch::KeywordMute.create!(account: alice, keyword: 'großeltern') - expect(matcher =~ 'besuch der grosseltern').to be_truthy + expect(matcher.matches?('besuch der grosseltern')).to be_truthy end it 'matches keywords that are composed of multiple words' do Glitch::KeywordMute.create!(account: alice, keyword: 'a shiitake') - expect(matcher =~ 'This is a shiitake').to be_truthy - expect(matcher =~ 'This is shiitake').to_not be_truthy + expect(matcher.matches?('This is a shiitake')).to be_truthy + expect(matcher.matches?('This is shiitake')).to_not be_truthy + end + end + end + + describe '.tag_matcher_for' do + let(:matcher) { Glitch::KeywordMute.tag_matcher_for(alice.id) } + let(:status) { Fabricate(:status) } + + describe 'with no mutes' do + before do + Glitch::KeywordMute.delete_all + end + + it 'does not match' do + status.tags << Fabricate(:tag, name: 'xyzzy') + + expect(matcher.matches?(status.tags)).to be false + end + end + + describe 'with mutes' do + it 'does not match keywords set by a different account' do + status.tags << Fabricate(:tag, name: 'xyzzy') + Glitch::KeywordMute.create!(account: bob, keyword: 'take') + + expect(matcher.matches?(status.tags)).to be false + end + + it 'matches #xyzzy when given the mute "#xyzzy"' do + status.tags << Fabricate(:tag, name: 'xyzzy') + Glitch::KeywordMute.create!(account: alice, keyword: '#xyzzy') + + expect(matcher.matches?(status.tags)).to be true + end + + it 'matches #thingiverse when given the non-whole-word mute "#thing"' do + status.tags << Fabricate(:tag, name: 'thingiverse') + Glitch::KeywordMute.create!(account: alice, keyword: '#thing', whole_word: false) + + expect(matcher.matches?(status.tags)).to be true + end + + it 'matches #hashtag when given the mute "##hashtag""' do + status.tags << Fabricate(:tag, name: 'hashtag') + Glitch::KeywordMute.create!(account: alice, keyword: '##hashtag') + + expect(matcher.matches?(status.tags)).to be true + end + + it 'matches #oatmeal when given the non-whole-word mute "oat"' do + status.tags << Fabricate(:tag, name: 'oatmeal') + Glitch::KeywordMute.create!(account: alice, keyword: 'oat', whole_word: false) + + expect(matcher.matches?(status.tags)).to be true + end + + it 'does not match #oatmeal when given the mute "#oat"' do + status.tags << Fabricate(:tag, name: 'oatmeal') + Glitch::KeywordMute.create!(account: alice, keyword: 'oat') + + expect(matcher.matches?(status.tags)).to be false end end end diff --git a/spec/models/invite_spec.rb b/spec/models/invite_spec.rb new file mode 100644 index 00000000000..0ba1dccb33c --- /dev/null +++ b/spec/models/invite_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe Invite, type: :model do + describe '#valid_for_use?' do + it 'returns true when there are no limitations' do + invite = Invite.new(max_uses: nil, expires_at: nil) + expect(invite.valid_for_use?).to be true + end + + it 'returns true when not expired' do + invite = Invite.new(max_uses: nil, expires_at: 1.hour.from_now) + expect(invite.valid_for_use?).to be true + end + + it 'returns false when expired' do + invite = Invite.new(max_uses: nil, expires_at: 1.hour.ago) + expect(invite.valid_for_use?).to be false + end + + it 'returns true when uses still available' do + invite = Invite.new(max_uses: 250, uses: 249, expires_at: nil) + expect(invite.valid_for_use?).to be true + end + + it 'returns false when maximum uses reached' do + invite = Invite.new(max_uses: 250, uses: 250, expires_at: nil) + expect(invite.valid_for_use?).to be false + end + end +end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 763b1523fd6..8444c8f635e 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -6,23 +6,18 @@ RSpec.describe Notification, type: :model do end describe '#target_status' do - before do - allow(notification).to receive(:type).and_return(type) - allow(notification).to receive(:activity).and_return(activity) - end - - let(:notification) { Fabricate(:notification) } - let(:status) { instance_double('Status') } - let(:favourite) { instance_double('Favourite') } - let(:mention) { instance_double('Mention') } + let(:notification) { Fabricate(:notification, activity_type: type, activity: activity) } + let(:status) { Fabricate(:status) } + let(:reblog) { Fabricate(:status, reblog: status) } + let(:favourite) { Fabricate(:favourite, status: status) } + let(:mention) { Fabricate(:mention, status: status) } context 'type is :reblog' do let(:type) { :reblog } - let(:activity) { status } + let(:activity) { reblog } - it 'calls activity.reblog' do - expect(activity).to receive(:reblog) - notification.target_status + it 'returns status' do + expect(notification.target_status).to eq status end end @@ -30,9 +25,8 @@ RSpec.describe Notification, type: :model do let(:type) { :favourite } let(:activity) { favourite } - it 'calls activity.status' do - expect(activity).to receive(:status) - notification.target_status + it 'returns status' do + expect(notification.target_status).to eq status end end @@ -40,9 +34,8 @@ RSpec.describe Notification, type: :model do let(:type) { :mention } let(:activity) { mention } - it 'calls activity.status' do - expect(activity).to receive(:status) - notification.target_status + it 'returns status' do + expect(notification.target_status).to eq status end end end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 89ad3adcfab..c6701018e52 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -83,8 +83,31 @@ RSpec.describe Status, type: :model do end describe '#title' do - it 'is a shorter version of the content' do - expect(subject.title).to be_a String + # rubocop:disable Style/InterpolationCheck + + let(:account) { subject.account } + + context 'if destroyed?' do + it 'returns "#{account.acct} deleted status"' do + subject.destroy! + expect(subject.title).to eq "#{account.acct} deleted status" + end + end + + context 'unless destroyed?' do + context 'if reblog?' do + it 'returns "#{account.acct} shared a status by #{reblog.account.acct}"' do + reblog = subject.reblog = other + expect(subject.title).to eq "#{account.acct} shared a status by #{reblog.account.acct}" + end + end + + context 'unless reblog?' do + it 'returns "New status by #{account.acct}"' do + subject.reblog = nil + expect(subject.title).to eq "New status by #{account.acct}" + end + end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 77a12c26d06..5ed7ed88b2f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -273,4 +273,47 @@ RSpec.describe User, type: :model do expect(user.token_for_app(app)).to be_nil end end + + describe '#role' do + it 'returns admin for admin' do + user = User.new(admin: true) + expect(user.role).to eq 'admin' + end + + it 'returns moderator for moderator' do + user = User.new(moderator: true) + expect(user.role).to eq 'moderator' + end + + it 'returns user otherwise' do + user = User.new + expect(user.role).to eq 'user' + end + end + + describe '#role?' do + it 'returns false when invalid role requested' do + user = User.new(admin: true) + expect(user.role?('disabled')).to be false + end + + it 'returns true when exact role match' do + user = User.new + mod = User.new(moderator: true) + admin = User.new(admin: true) + + expect(user.role?('user')).to be true + expect(mod.role?('moderator')).to be true + expect(admin.role?('admin')).to be true + end + + it 'returns true when role higher than needed' do + mod = User.new(moderator: true) + admin = User.new(admin: true) + + expect(mod.role?('user')).to be true + expect(admin.role?('user')).to be true + expect(admin.role?('moderator')).to be true + end + end end diff --git a/spec/presenters/account_relationships_presenter_spec.rb b/spec/presenters/account_relationships_presenter_spec.rb new file mode 100644 index 00000000000..f8b048d38af --- /dev/null +++ b/spec/presenters/account_relationships_presenter_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe AccountRelationshipsPresenter do + describe '.initialize' do + before do + allow(Account).to receive(:following_map).with(account_ids, current_account_id).and_return(default_map) + allow(Account).to receive(:followed_by_map).with(account_ids, current_account_id).and_return(default_map) + allow(Account).to receive(:blocking_map).with(account_ids, current_account_id).and_return(default_map) + allow(Account).to receive(:muting_map).with(account_ids, current_account_id).and_return(default_map) + allow(Account).to receive(:requested_map).with(account_ids, current_account_id).and_return(default_map) + allow(Account).to receive(:domain_blocking_map).with(account_ids, current_account_id).and_return(default_map) + end + + let(:presenter) { AccountRelationshipsPresenter.new(account_ids, current_account_id, options) } + let(:current_account_id) { Fabricate(:account).id } + let(:account_ids) { [Fabricate(:account).id] } + let(:default_map) { { 1 => true } } + + context 'options are not set' do + let(:options) { {} } + + it 'sets default maps' do + expect(presenter.following).to eq default_map + expect(presenter.followed_by).to eq default_map + expect(presenter.blocking).to eq default_map + expect(presenter.muting).to eq default_map + expect(presenter.requested).to eq default_map + expect(presenter.domain_blocking).to eq default_map + end + end + + context 'options[:following_map] is set' do + let(:options) { { following_map: { 2 => true } } } + + it 'sets @following merged with default_map and options[:following_map]' do + expect(presenter.following).to eq default_map.merge(options[:following_map]) + end + end + + context 'options[:followed_by_map] is set' do + let(:options) { { followed_by_map: { 3 => true } } } + + it 'sets @followed_by merged with default_map and options[:followed_by_map]' do + expect(presenter.followed_by).to eq default_map.merge(options[:followed_by_map]) + end + end + + context 'options[:blocking_map] is set' do + let(:options) { { blocking_map: { 4 => true } } } + + it 'sets @blocking merged with default_map and options[:blocking_map]' do + expect(presenter.blocking).to eq default_map.merge(options[:blocking_map]) + end + end + + context 'options[:muting_map] is set' do + let(:options) { { muting_map: { 5 => true } } } + + it 'sets @muting merged with default_map and options[:muting_map]' do + expect(presenter.muting).to eq default_map.merge(options[:muting_map]) + end + end + + context 'options[:requested_map] is set' do + let(:options) { { requested_map: { 6 => true } } } + + it 'sets @requested merged with default_map and options[:requested_map]' do + expect(presenter.requested).to eq default_map.merge(options[:requested_map]) + end + end + + context 'options[:domain_blocking_map] is set' do + let(:options) { { domain_blocking_map: { 7 => true } } } + + it 'sets @domain_blocking merged with default_map and options[:domain_blocking_map]' do + expect(presenter.domain_blocking).to eq default_map.merge(options[:domain_blocking_map]) + end + end + end +end diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb index 51f3fe3a18d..ad26abc5b21 100644 --- a/spec/services/activitypub/fetch_remote_status_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' RSpec.describe ActivityPub::FetchRemoteStatusService do + include ActionView::Helpers::TextHelper + let(:sender) { Fabricate(:account) } let(:recipient) { Fabricate(:account) } let(:valid_domain) { Rails.configuration.x.local_domain } @@ -19,6 +21,7 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do describe '#call' do before do + stub_request(:head, 'https://example.com/watch?v=12345').to_return(status: 404, body: '') subject.call(object[:id], prefetched_body: Oj.dump(object)) end @@ -32,5 +35,38 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do expect(status.text).to eq 'Lorem ipsum' end end + + context 'with Video object' do + let(:object) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: "https://#{valid_domain}/@foo/1234", + type: 'Video', + name: 'Nyan Cat 10 hours remix', + attributedTo: ActivityPub::TagManager.instance.uri_for(sender), + url: [ + { + type: 'Link', + mimeType: 'application/x-bittorrent', + href: 'https://example.com/12345.torrent', + }, + + { + type: 'Link', + mimeType: 'text/html', + href: 'https://example.com/watch?v=12345', + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.url).to eq 'https://example.com/watch?v=12345' + expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remix https://example.com/watch?v=12345' + end + end end end diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index a8ebc16b832..bb7601e7643 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -101,6 +101,26 @@ RSpec.describe NotifyService do end end + describe 'reblogs' do + let(:status) { Fabricate(:status, account: Fabricate(:account)) } + let(:activity) { Fabricate(:status, account: sender, reblog: status) } + + it 'shows reblogs by default' do + recipient.follow!(sender) + is_expected.to change(Notification, :count) + end + + it 'shows reblogs when explicitly enabled' do + recipient.follow!(sender, reblogs: true) + is_expected.to change(Notification, :count) + end + + it 'hides reblogs when disabled' do + recipient.follow!(sender, reblogs: false) + is_expected.to_not change(Notification, :count) + end + end + context do let(:asshole) { Fabricate(:account, username: 'asshole') } let(:reply_to) { Fabricate(:status, account: asshole) } diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb index 09f8fa45b8d..19a8678f028 100644 --- a/spec/services/process_mentions_service_spec.rb +++ b/spec/services/process_mentions_service_spec.rb @@ -41,4 +41,25 @@ RSpec.describe ProcessMentionsService do expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once end end + + context 'Temporarily-unreachable ActivityPub user' do + let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) } + + subject { ProcessMentionsService.new } + + before do + stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404) + stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com").to_return(status: 500) + stub_request(:post, remote_user.inbox_url) + subject.call(status) + end + + it 'creates a mention' do + expect(remote_user.mentions.where(status: status).count).to eq 1 + end + + it 'sends activity to the inbox' do + expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once + end + end end diff --git a/streaming/index.js b/streaming/index.js index 42df63031a7..3048802e30d 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -515,7 +515,7 @@ const startWorker = (workerId) => { }); }, 30000); - server.listen(process.env.PORT || 4000, () => { + server.listen(process.env.PORT || 4000, process.env.BIND || '0.0.0.0', () => { log.info(`Worker ${workerId} now listening on ${server.address().address}:${server.address().port}`); }); diff --git a/yarn.lock b/yarn.lock index 0805e8af3ab..cc5ccf720e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,62 @@ # yarn lockfile v1 -"@types/node@^6.0.46": - version "6.0.90" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.90.tgz#0ed74833fa1b73dcdb9409dcb1c97ec0a8b13b02" +"@babel/code-frame@7.0.0-beta.31": + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz#473d021ecc573a2cce1c07d5b509d5215f46ba35" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/helper-function-name@7.0.0-beta.31": + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.31.tgz#afe63ad799209989348b1109b44feb66aa245f57" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.31" + "@babel/template" "7.0.0-beta.31" + "@babel/traverse" "7.0.0-beta.31" + "@babel/types" "7.0.0-beta.31" + +"@babel/helper-get-function-arity@7.0.0-beta.31": + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.31.tgz#1176d79252741218e0aec872ada07efb2b37a493" + dependencies: + "@babel/types" "7.0.0-beta.31" + +"@babel/template@7.0.0-beta.31": + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.31.tgz#577bb29389f6c497c3e7d014617e7d6713f68bda" + dependencies: + "@babel/code-frame" "7.0.0-beta.31" + "@babel/types" "7.0.0-beta.31" + babylon "7.0.0-beta.31" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.31": + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.31.tgz#db399499ad74aefda014f0c10321ab255134b1df" + dependencies: + "@babel/code-frame" "7.0.0-beta.31" + "@babel/helper-function-name" "7.0.0-beta.31" + "@babel/types" "7.0.0-beta.31" + babylon "7.0.0-beta.31" + debug "^3.0.1" + globals "^10.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.31": + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.31.tgz#42c9c86784f674c173fb21882ca9643334029de4" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + +"@types/node@*": + version "8.0.53" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8" abab@^1.0.3: version "1.0.4" @@ -47,7 +100,7 @@ acorn@^4.0.3, acorn@^4.0.4: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0, acorn@^5.1.1: +acorn@^5.0.0, acorn@^5.1.1, acorn@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" @@ -79,8 +132,8 @@ ajv@^4.7.0, ajv@^4.9.1: json-stable-stringify "^1.0.1" ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" + version "5.5.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.1.tgz#b38bb8876d9e86bee994956a04e721e88b248eb2" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -236,8 +289,8 @@ asap@~2.0.3: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" asn1.js@^4.0.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + version "4.9.2" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a" dependencies: bn.js "^4.0.0" inherits "^2.0.1" @@ -277,6 +330,10 @@ async-foreach@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + async@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7" @@ -288,8 +345,8 @@ async@^1.4.0, async@^1.5.2: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.1.2, async@^2.1.4, async@^2.1.5, async@^2.4.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: lodash "^4.14.0" @@ -346,14 +403,6 @@ axios@~0.16.2: follow-redirects "^1.2.3" is-buffer "^1.1.5" -babel-code-frame@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-7.0.0-beta.0.tgz#418a7b5f3f7dc9a4670e61b1158b4c5661bec98d" - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -396,13 +445,13 @@ babel-eslint@^7.2.3: babylon "^6.17.0" babel-eslint@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.0.1.tgz#5d718be7a328625d006022eb293ed3008cbd6346" + version "8.0.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.0.3.tgz#f29ecf02336be438195325cd47c468da81ee4e98" dependencies: - babel-code-frame "7.0.0-beta.0" - babel-traverse "7.0.0-beta.0" - babel-types "7.0.0-beta.0" - babylon "7.0.0-beta.22" + "@babel/code-frame" "7.0.0-beta.31" + "@babel/traverse" "7.0.0-beta.31" + "@babel/types" "7.0.0-beta.31" + babylon "7.0.0-beta.31" babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.0" @@ -459,15 +508,6 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helper-function-name@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-7.0.0-beta.0.tgz#d1b6779b647e5c5c31ebeb05e13b998e4d352d56" - dependencies: - babel-helper-get-function-arity "7.0.0-beta.0" - babel-template "7.0.0-beta.0" - babel-traverse "7.0.0-beta.0" - babel-types "7.0.0-beta.0" - 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" @@ -478,12 +518,6 @@ babel-helper-function-name@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helper-get-function-arity@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-7.0.0-beta.0.tgz#9d1ab7213bb5efe1ef1638a8ea1489969b5a8b6e" - dependencies: - babel-types "7.0.0-beta.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" @@ -498,6 +532,13 @@ babel-helper-hoist-variables@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-module-imports@^7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz#e15764e3af9c8e11810c09f78f498a2bdc71585a" + dependencies: + babel-types "7.0.0-beta.3" + lodash "^4.2.0" + babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" @@ -562,10 +603,6 @@ babel-macros@^1.1.1: dependencies: cosmiconfig "3.1.0" -babel-messages@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-7.0.0-beta.0.tgz#6df01296e49fc8fbd0637394326a167f36da817b" - babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" @@ -590,18 +627,20 @@ babel-plugin-jest-hoist@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" -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" +babel-plugin-lodash@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.2.tgz#da3a5b49ba27447f54463f6c4fa81396ccdd463f" dependencies: + babel-helper-module-imports "^7.0.0-beta.3" + babel-types "^6.26.0" glob "^7.1.1" - lodash "^4.17.2" + lodash "^4.17.4" + require-package-name "^2.0.1" babel-plugin-preval@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/babel-plugin-preval/-/babel-plugin-preval-1.6.1.tgz#c33fd124f9cb9281550cae35ff0ea6065e32261d" + version "1.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-preval/-/babel-plugin-preval-1.6.2.tgz#8f580a1d4579d5fc79f1cfaee6f9fe0996fdeb1f" dependencies: - babel-core "^6.26.0" babel-macros "^1.1.1" babel-register "^6.26.0" babylon "^6.18.0" @@ -1001,15 +1040,6 @@ babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtim core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-7.0.0-beta.0.tgz#85083cf9e4395d5e48bf5154d7a8d6991cafecfb" - dependencies: - babel-traverse "7.0.0-beta.0" - babel-types "7.0.0-beta.0" - babylon "7.0.0-beta.22" - lodash "^4.2.0" - babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" @@ -1020,20 +1050,6 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-te babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-7.0.0-beta.0.tgz#da14be9b762f62a2f060db464eaafdd8cd072a41" - dependencies: - babel-code-frame "7.0.0-beta.0" - babel-helper-function-name "7.0.0-beta.0" - babel-messages "7.0.0-beta.0" - babel-types "7.0.0-beta.0" - babylon "7.0.0-beta.22" - debug "^3.0.1" - globals "^10.0.0" - invariant "^2.2.0" - lodash "^4.2.0" - babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" @@ -1048,9 +1064,9 @@ babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-tr invariant "^2.2.2" lodash "^4.17.4" -babel-types@7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.0.tgz#eb8b6e556470e6dcc4aef982d79ad229469b5169" +babel-types@7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.3.tgz#cd927ca70e0ae8ab05f4aab83778cfb3e6eb20b4" dependencies: esutils "^2.0.2" lodash "^4.2.0" @@ -1065,9 +1081,9 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24 lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@7.0.0-beta.22: - version "7.0.0-beta.22" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.22.tgz#74f0ad82ed7c7c3cfeab74cf684f815104161b65" +babylon@7.0.0-beta.31: + version "7.0.0-beta.31" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.31.tgz#7ec10f81e0e456fd0f855ad60fa30c2ac454283f" babylon@^6.17.0, babylon@^6.18.0: version "6.18.0" @@ -1110,8 +1126,8 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" binary-extensions@^1.0.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" block-stream@*: version "0.0.9" @@ -1242,11 +1258,11 @@ browserify-sign@^4.0.0: inherits "^2.0.1" parse-asn1 "^5.0.0" -browserify-zlib@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" dependencies: - pako "~0.2.0" + pako "~1.0.5" browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: version "1.7.7" @@ -1256,10 +1272,10 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: electron-to-chromium "^1.2.7" browserslist@^2.1.2, browserslist@^2.5.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.6.1.tgz#cc65a05ad6131ebda26f076f2822ba1bc826376b" + version "2.9.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.9.1.tgz#b72d3982ab01b5cd24da62ff6d45573886aff275" dependencies: - caniuse-lite "^1.0.30000755" + caniuse-lite "^1.0.30000770" electron-to-chromium "^1.3.27" bser@^2.0.0: @@ -1351,12 +1367,16 @@ 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.30000755" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000755.tgz#a08c547c39dbe4ad07dcca9763fcbbff0c891de0" + version "1.0.30000777" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000777.tgz#2e19adba63bdd7c501df637a862adead7f4bc054" -caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000755: - version "1.0.30000755" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000755.tgz#9ce5f6e06bd75ec8209abe8853c3beef02248d65" +caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000770: + version "1.0.30000777" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000777.tgz#31c18a4a8cd49782ebb305c8e8a93e6b3b3e4f13" + +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" @@ -1383,7 +1403,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" dependencies: @@ -1418,8 +1438,8 @@ chokidar@^1.6.0, chokidar@^1.7.0: fsevents "^1.0.0" ci-info@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.1.tgz#47b44df118c48d2597b56d342e7e25791060171a" + version "1.1.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -1478,8 +1498,8 @@ clone-deep@^0.3.0: shallow-clone "^0.1.2" clone@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" co@^4.6.0: version "4.6.0" @@ -1496,8 +1516,8 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" color-convert@^1.3.0, color-convert@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: color-name "^1.1.1" @@ -1542,8 +1562,8 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: delayed-stream "~1.0.0" commander@^2.8.1, commander@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" commondir@^1.0.1: version "1.0.1" @@ -1591,8 +1611,8 @@ concat-stream@^1.5.2: typedarray "^0.0.6" connect-history-api-fallback@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.4.0.tgz#3db24f973f4b923b0e82f619ce0df02411ca623d" + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" console-browserify@^1.1.0: version "1.1.0" @@ -1629,8 +1649,8 @@ convert-source-map@^0.3.3: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" convert-source-map@^1.1.1, convert-source-map@^1.4.0, convert-source-map@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" @@ -1743,8 +1763,8 @@ cryptiles@3.x.x: boom "5.x.x" crypto-browserify@^3.11.0: - version "3.11.1" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" dependencies: browserify-cipher "^1.0.0" browserify-sign "^4.0.0" @@ -1756,8 +1776,9 @@ crypto-browserify@^3.11.0: pbkdf2 "^3.0.3" public-encrypt "^4.0.0" randombytes "^2.0.0" + randomfill "^1.0.3" -css-color-function@^1.3.0: +css-color-function@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.3.tgz#8ed24c2c0205073339fafa004bc8c141fccb282e" dependencies: @@ -1933,7 +1954,7 @@ 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.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2040,6 +2061,10 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" @@ -2089,11 +2114,10 @@ doctrine@1.5.0, doctrine@^1.2.2: isarray "^1.0.0" doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + version "2.0.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" dependencies: esutils "^2.0.2" - isarray "^1.0.0" dom-helpers@^3.2.0, dom-helpers@^3.2.1: version "3.2.1" @@ -2215,39 +2239,40 @@ entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" -enzyme-adapter-react-16@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz#8c6f431f17c69e1e9eeb25ca4bd92f31971eb2dd" +enzyme-adapter-react-16@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.0.tgz#86c5db7c10f0be6ec25d54ca41b59f2abb397cf4" dependencies: - enzyme-adapter-utils "^1.0.0" + enzyme-adapter-utils "^1.1.0" lodash "^4.17.4" object.assign "^4.0.4" object.values "^1.0.4" prop-types "^15.5.10" react-test-renderer "^16.0.0-0" -enzyme-adapter-utils@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.0.1.tgz#fcd81223339a55a312f7552641e045c404084009" +enzyme-adapter-utils@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.2.0.tgz#7f4471ee0a70b91169ec8860d2bf0a6b551664b2" dependencies: lodash "^4.17.4" object.assign "^4.0.4" prop-types "^15.5.10" -enzyme@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.1.0.tgz#d8ca84085790fbcec6ed40badd14478faee4c25a" +enzyme@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.2.0.tgz#998bdcda0fc71b8764a0017f7cc692c943f54a7a" dependencies: cheerio "^1.0.0-rc.2" function.prototype.name "^1.0.3" + has "^1.0.1" is-subset "^0.1.1" lodash "^4.17.4" object-is "^1.0.1" object.assign "^4.0.4" object.entries "^1.0.4" object.values "^1.0.4" - raf "^3.3.2" - rst-selector-parser "^2.2.2" + raf "^3.4.0" + rst-selector-parser "^2.2.3" errno@^0.1.3, errno@^0.1.4: version "0.1.4" @@ -2262,8 +2287,8 @@ error-ex@^1.2.0, error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.6.1, es-abstract@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2280,8 +2305,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.35" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.35.tgz#18ee858ce6a3c45c7d79e91c15fcca9ec568494f" + version "0.10.37" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" dependencies: es6-iterator "~2.0.1" es6-symbol "~3.1.1" @@ -2450,10 +2475,10 @@ eslint@^3.19.0: user-home "^2.0.0" espree@^3.4.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" + version "3.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" dependencies: - acorn "^5.1.1" + acorn "^5.2.1" acorn-jsx "^3.0.0" esprima@^2.6.0: @@ -2566,7 +2591,7 @@ expect@^21.2.1: jest-message-util "^21.2.1" jest-regex-util "^21.2.0" -express@^4.13.3, express@^4.15.2, express@^4.16.2: +express@^4.15.2, express@^4.16.2: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: @@ -2620,10 +2645,14 @@ extract-text-webpack-plugin@^3.0.2: schema-utils "^0.3.0" webpack-sources "^1.0.1" -extsprintf@1.3.0, extsprintf@^1.2.0: +extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" @@ -2762,10 +2791,10 @@ flatten@^1.0.2: resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" follow-redirects@^1.2.3: - version "1.2.5" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.5.tgz#ffd3e14cbdd5eaa72f61b6368c1f68516c2a26cc" + version "1.2.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.6.tgz#4dcdc7e4ab3dd6765a97ff89c3b4c258117c79bf" dependencies: - debug "^2.6.9" + debug "^3.1.0" font-awesome@^4.7.0: version "4.7.0" @@ -2842,11 +2871,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@*, fsevents@^1.0.0, fsevents@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" dependencies: nan "^2.3.0" - node-pre-gyp "^0.6.36" + node-pre-gyp "^0.6.39" fstream-ignore@^1.0.5: version "1.0.5" @@ -2941,6 +2970,16 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + 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.2, glob@~7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" @@ -2953,8 +2992,8 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: path-is-absolute "^1.0.0" globals@^10.0.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-10.2.0.tgz#69490789091fcaa7f7d512c668c8eb73894a4ef2" + version "10.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-10.4.0.tgz#5c477388b128a9e4c5c5d01c7a2aca68c68b2da7" globals@^9.14.0, globals@^9.18.0: version "9.18.0" @@ -2990,8 +3029,8 @@ globule@^1.0.0: minimatch "~3.0.2" gonzales-pe@^4.0.3: - version "4.2.2" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.2.tgz#f50a8c17842f13a9007909b7cb32188266e4d74c" + version "4.2.3" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2" dependencies: minimist "1.1.x" @@ -3031,6 +3070,15 @@ har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + har-validator@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" @@ -3235,9 +3283,9 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" iconv-lite@0.4.19, iconv-lite@~0.4.13: version "0.4.19" @@ -3310,8 +3358,8 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" inquirer@^0.12.0: version "0.12.0" @@ -3338,30 +3386,26 @@ internal-ip@1.2.0: meow "^3.3.0" interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" -intersection-observer@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.4.2.tgz#24100ed620baf6a427072996d4d73366e9ec93ef" +intersection-observer@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.5.0.tgz#9fe8bee3953c755b1485c38efd9633d535775ea6" 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" + version "2.1.0" + resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316" -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: +intl-messageformat-parser@1.4.0, intl-messageformat-parser@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075" -intl-messageformat@^2.0.0, intl-messageformat@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.1.0.tgz#1c51da76f02a3f7b360654cdc51bbc4d3fa6c72c" +intl-messageformat@^2.0.0, intl-messageformat@^2.1.0, intl-messageformat@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc" dependencies: - intl-messageformat-parser "1.2.0" + intl-messageformat-parser "1.4.0" intl-relativeformat@^2.0.0, intl-relativeformat@^2.1.0: version "2.1.0" @@ -3483,7 +3527,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-my-json-valid@^2.10.0: +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.16.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" dependencies: @@ -3521,8 +3565,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -3920,8 +3964,8 @@ jest@^21.2.1: jest-cli "^21.2.1" js-base64@^2.1.8, js-base64@^2.1.9: - version "2.3.2" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" + version "2.4.0" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa" js-string-escape@1.0.1: version "1.0.1" @@ -4042,6 +4086,10 @@ keycode@^2.1.7: version "2.1.9" resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" +killable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + kind-of@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" @@ -4253,8 +4301,8 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" loglevel@^1.4.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.5.1.tgz#189078c94ab9053ee215a0acdbf24244ea0f6502" + version "1.6.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.0.tgz#ae0caa561111498c5ba13723d6fb631d24003934" longest@^1.0.1: version "1.0.1" @@ -4313,8 +4361,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.16.5" - resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-3.16.5.tgz#d75a5265435d2824b067b37a478771deebf6aacc" + version "3.17.0" + resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-3.17.0.tgz#9569d278874546175c9d0497d7417eb88fb61503" dependencies: complex.js "2.0.4" decimal.js "7.2.3" @@ -4322,7 +4370,7 @@ mathjs@^3.11.5: javascript-natural-sort "0.7.1" seed-random "2.2.0" tiny-emitter "2.0.0" - typed-function "0.10.5" + typed-function "0.10.6" md5.js@^1.3.4: version "1.3.4" @@ -4401,8 +4449,8 @@ miller-rabin@^4.0.0: brorand "^1.0.1" "mime-db@>= 1.30.0 < 2": - version "1.31.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.31.0.tgz#a49cd8f3ebf3ed1a482b60561d9105ad40ca74cb" + version "1.32.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414" mime-db@~1.30.0: version "1.30.0" @@ -4414,10 +4462,14 @@ mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, dependencies: mime-db "~1.30.0" -mime@1.4.1, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -4430,7 +4482,7 @@ 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@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, 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: @@ -4478,8 +4530,8 @@ multicast-dns-service-types@^1.1.0: resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" multicast-dns@^6.0.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.1.1.tgz#6e7de86a570872ab17058adea7160bbeca814dde" + version "6.2.1" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.1.tgz#c5035defa9219d30640558a49298067352098060" dependencies: dns-packet "^1.0.1" thunky "^0.1.0" @@ -4489,8 +4541,8 @@ 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.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" natural-compare@^1.4.0: version "1.4.0" @@ -4542,28 +4594,28 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" 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" + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" dependencies: assert "^1.1.1" - browserify-zlib "^0.1.4" + browserify-zlib "^0.2.0" buffer "^4.3.0" console-browserify "^1.1.0" constants-browserify "^1.0.0" crypto-browserify "^3.11.0" domain-browser "^1.1.1" events "^1.0.0" - https-browserify "0.0.1" - os-browserify "^0.2.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" path-browserify "0.0.0" - process "^0.11.0" + process "^0.11.10" punycode "^1.2.4" querystring-es3 "^0.2.0" - readable-stream "^2.0.5" + readable-stream "^2.3.3" stream-browserify "^2.0.1" - stream-http "^2.3.1" - string_decoder "^0.10.25" - timers-browserify "^2.0.2" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" tty-browserify "0.0.0" url "^0.11.0" util "^0.10.3" @@ -4578,10 +4630,11 @@ node-notifier@^5.0.2: shellwords "^0.1.0" which "^1.2.12" -node-pre-gyp@^0.6.36, node-pre-gyp@^0.6.4: - version "0.6.38" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" +node-pre-gyp@^0.6.39, node-pre-gyp@^0.6.4: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" dependencies: + detect-libc "^1.0.2" hawk "3.1.3" mkdirp "^0.5.1" nopt "^4.0.1" @@ -4593,9 +4646,9 @@ node-pre-gyp@^0.6.36, node-pre-gyp@^0.6.4: tar "^2.2.1" tar-pack "^3.4.0" -node-sass@^4.5.2: - version "4.5.3" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.3.tgz#d09c9d1179641239d1b97ffc6231fdcec53e1568" +node-sass@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.7.2.tgz#9366778ba1469eb01438a9e8592f4262bcb6794e" dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -4612,9 +4665,10 @@ node-sass@^4.5.2: nan "^2.3.2" node-gyp "^3.3.1" npmlog "^4.0.0" - request "^2.79.0" - sass-graph "^2.1.1" + request "~2.79.0" + sass-graph "^2.2.4" stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" node-zopfli@^2.0.2: version "2.0.2" @@ -4835,9 +4889,9 @@ original@>=0.0.5: dependencies: url-parse "1.0.x" -os-browserify@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" @@ -4894,9 +4948,9 @@ 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" +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" parse-asn1@^5.0.0: version "5.1.0" @@ -4948,10 +5002,10 @@ parse5@^1.5.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" parse5@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510" + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" dependencies: - "@types/node" "^6.0.46" + "@types/node" "*" parseurl@~1.3.2: version "1.3.2" @@ -5037,6 +5091,10 @@ 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-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + pg-pool@1.*: version "1.8.0" resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.8.0.tgz#f7ec73824c37a03f076f51bfdf70e340147c4f37" @@ -5045,9 +5103,10 @@ pg-pool@1.*: object-assign "4.1.0" pg-types@1.*: - version "1.12.1" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.12.1.tgz#d64087e3903b58ffaad279e7595c52208a14c3d2" + version "1.13.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.13.0.tgz#75f490b8a8abf75f1386ef5ec4455ecf6b345c63" dependencies: + pg-int8 "1.0.1" postgres-array "~1.0.0" postgres-bytea "~1.0.0" postgres-date "~1.0.0" @@ -5135,10 +5194,10 @@ postcss-calc@^5.2.0: reduce-css-calc "^1.2.6" postcss-color-function@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-function/-/postcss-color-function-4.0.0.tgz#7e0106f4f6a1ecb1ad5b3a8553ace5e828aae187" + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-function/-/postcss-color-function-4.0.1.tgz#402b3f2cebc3f6947e618fb6be3654fbecef6444" dependencies: - css-color-function "^1.3.0" + css-color-function "~1.3.3" postcss "^6.0.1" postcss-message-helpers "^2.0.0" postcss-value-parser "^3.3.0" @@ -5262,9 +5321,9 @@ postcss-load-plugins@^2.3.0: cosmiconfig "^2.1.1" object-assign "^4.1.0" -postcss-loader@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.0.8.tgz#8c67ddb029407dfafe684a406cfc16bad2ce0814" +postcss-loader@^2.0.9: + version "2.0.9" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.0.9.tgz#001fdf7bfeeb159405ee61d1bb8e59b528dbd309" dependencies: loader-utils "^1.1.0" postcss "^6.0.0" @@ -5349,8 +5408,8 @@ postcss-mixins@^6.0.1: sugarss "^1.0.0" postcss-modules-extract-imports@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb" dependencies: postcss "^6.0.1" @@ -5550,11 +5609,11 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0 source-map "^0.5.6" supports-color "^3.2.3" -postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.13, postcss@^6.0.3, postcss@^6.0.6, postcss@^6.0.9: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.13.tgz#b9ecab4ee00c89db3ec931145bd9590bbf3f125f" +postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.13, postcss@^6.0.14, postcss@^6.0.3, postcss@^6.0.6, postcss@^6.0.9: + version "6.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885" dependencies: - chalk "^2.1.0" + chalk "^2.3.0" source-map "^0.6.1" supports-color "^4.4.0" @@ -5628,7 +5687,7 @@ 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: +process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" @@ -5707,6 +5766,10 @@ qs@6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -5738,7 +5801,7 @@ quote@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/quote/-/quote-0.4.0.tgz#10839217f6c1362b89194044d29b233fd7f32f01" -raf@^3.1.0, raf@^3.3.2, raf@^3.4.0: +raf@^3.1.0, raf@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" dependencies: @@ -5766,12 +5829,19 @@ randomatic@^1.1.3: is-number "^3.0.0" kind-of "^4.0.0" -randombytes@^2.0.0, randombytes@^2.0.1: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" dependencies: safe-buffer "^5.1.0" +randomfill@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + 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" @@ -5794,16 +5864,16 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-dom@^16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.0.0.tgz#9cc3079c3dcd70d4c6e01b84aab2a7e34c303f58" +react-dom@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.0" -react-event-listener@^0.5.0: +react-event-listener@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.5.1.tgz#ba36076e47bc37c5a67ff5ccd4a9ff0f15621040" dependencies: @@ -5920,47 +5990,48 @@ react-router@^4.2.0: prop-types "^15.5.4" warning "^3.0.0" -react-swipeable-views-core@^0.12.8: - version "0.12.8" - resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.12.8.tgz#99460621e5a6da07fb482a25b151905ae7a797a9" +react-swipeable-views-core@^0.12.11: + version "0.12.11" + resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.12.11.tgz#3cf2b4daffbb36f9d69bd19bf5b2d5370b6b2c1b" dependencies: babel-runtime "^6.23.0" warning "^3.0.0" -react-swipeable-views-utils@^0.12.8: - version "0.12.8" - resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.12.8.tgz#9483fc7dd370032f2f93ac44f2a2913d7c52aa41" +react-swipeable-views-utils@^0.12.11: + version "0.12.11" + resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.12.11.tgz#3c9a6a2b8dbdcc331a5d107419578f57b7e101d6" dependencies: babel-runtime "^6.23.0" fbjs "^0.8.4" keycode "^2.1.7" - prop-types "^15.5.4" - react-event-listener "^0.5.0" - react-swipeable-views-core "^0.12.8" + prop-types "^15.6.0" + react-event-listener "^0.5.1" + react-swipeable-views-core "^0.12.11" react-swipeable-views@^0.12.3: - version "0.12.8" - resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.12.8.tgz#8541daab5881067e58281d1e6ff13815ae94ebf5" + version "0.12.12" + resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.12.12.tgz#60cdc8e3682ed082aaf094f7761eaf691ed28a6f" dependencies: babel-runtime "^6.23.0" dom-helpers "^3.2.1" prop-types "^15.5.4" - react-swipeable-views-core "^0.12.8" - react-swipeable-views-utils "^0.12.8" + react-swipeable-views-core "^0.12.11" + react-swipeable-views-utils "^0.12.11" warning "^3.0.0" -react-test-renderer@^16.0.0, react-test-renderer@^16.0.0-0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.0.0.tgz#9fe7b8308f2f71f29fc356d4102086f131c9cb15" +react-test-renderer@^16.0.0-0, react-test-renderer@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211" dependencies: fbjs "^0.8.16" object-assign "^4.1.1" + prop-types "^15.6.0" -react-textarea-autosize@^5.0.7: - version "5.1.0" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-5.1.0.tgz#ffbf8164fce217c79443c1c17dedf730592df224" +react-textarea-autosize@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-5.2.1.tgz#2b78f9067180f41b08ac59f78f1581abadd61e54" dependencies: - prop-types "^15.5.10" + prop-types "^15.6.0" react-toggle@^4.0.1: version "4.0.2" @@ -5979,9 +6050,9 @@ react-transition-group@^2.2.0: prop-types "^15.5.8" warning "^3.0.0" -react@^16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.0.0.tgz#ce7df8f1941b036f02b2cca9dbd0cb1f0e855e2d" +react@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -6024,7 +6095,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.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: +readable-stream@^2.0.1, readable-stream@^2.0.2, 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, readable-stream@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -6237,6 +6308,31 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.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" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + requestidlecallback@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/requestidlecallback/-/requestidlecallback-0.3.0.tgz#6fb74e0733f90df3faa4838f9f6a2a5f9b742ac5" @@ -6257,6 +6353,10 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-package-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" + require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -6264,7 +6364,7 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" -requires-port@1.0.x, requires-port@1.x.x: +requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -6363,7 +6463,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" -rst-selector-parser@^2.2.2: +rst-selector-parser@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91" dependencies: @@ -6384,10 +6484,6 @@ safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" - sane@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/sane/-/sane-2.2.0.tgz#d6d2e2fcab00e3d283c93b912b7c3a20846f1d56" @@ -6402,7 +6498,7 @@ sane@^2.0.0: optionalDependencies: fsevents "^1.1.1" -sass-graph@^2.1.1: +sass-graph@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" dependencies: @@ -6432,8 +6528,8 @@ schema-utils@^0.3.0: ajv "^5.0.0" scroll-behavior@^0.9.1: - version "0.9.4" - resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.4.tgz#73b4a0eae3e59c0b8f3b6fc1ff78f054a513e79c" + version "0.9.5" + resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.5.tgz#41da30b559da004eb48450f6cff6068c7696ff23" dependencies: dom-helpers "^3.2.1" invariant "^2.2.2" @@ -6651,11 +6747,11 @@ source-map@^0.4.2, source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6: +source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@^0.6.1: +source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -6741,7 +6837,7 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" -stream-http@^2.3.1: +stream-http@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" dependencies: @@ -6777,11 +6873,7 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -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.3: +string_decoder@^1.0.0, string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: @@ -6791,9 +6883,9 @@ stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -stringz@^0.2.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/stringz/-/stringz-0.2.3.tgz#87bad6f5462c34bd73f84522c703f019d78f0b2d" +stringz@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/stringz/-/stringz-0.3.0.tgz#58a311a8c791eee1a68f5f188b3db5e66ff49360" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" @@ -6843,10 +6935,10 @@ substring-trie@^1.0.2: resolved "https://registry.yarnpkg.com/substring-trie/-/substring-trie-1.0.2.tgz#7b42592391628b4f2cb17365c6cce4257c7b7af5" sugarss@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.0.tgz#65e51b3958432fb70d5451a68bb33e32d0cf1ef7" + version "1.0.1" + resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.1.tgz#be826d9003e0f247735f92365dc3fd7f1bae9e44" dependencies: - postcss "^6.0.0" + postcss "^6.0.14" supports-color@^2.0.0: version "2.0.0" @@ -6877,8 +6969,8 @@ svgo@^0.7.0: whet.extend "~0.9.9" symbol-observable@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + version "1.1.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" symbol-tree@^3.2.1: version "3.2.2" @@ -6960,7 +7052,7 @@ time-stamp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" -timers-browserify@^2.0.2: +timers-browserify@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.4.tgz#96ca53f4b794a5e7c0e1bd7cc88a372298fa01e6" dependencies: @@ -7008,6 +7100,12 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +"true-case-path@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" + dependencies: + glob "^6.0.4" + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" @@ -7022,6 +7120,10 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -7039,9 +7141,9 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" -typed-function@0.10.5: - version "0.10.5" - resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-0.10.5.tgz#2e0f18abd065219fab694a446a65c6d1981832c0" +typed-function@0.10.6: + version "0.10.6" + resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-0.10.6.tgz#314aa0ea72bd586de5920095559683e20b01688b" typedarray@^0.0.6: version "0.0.6" @@ -7077,8 +7179,8 @@ uid-number@^0.0.6: resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" ultron@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864" + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" underscore@~1.4.4: version "1.4.4" @@ -7118,11 +7220,11 @@ url-parse@1.0.x: requires-port "1.0.x" url-parse@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19" + version "1.2.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" dependencies: querystringify "~1.0.0" - requires-port "1.0.x" + requires-port "~1.0.0" url@^0.11.0: version "0.11.0" @@ -7237,9 +7339,9 @@ webidl-conversions@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" -webpack-bundle-analyzer@^2.8.3: - version "2.9.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.9.0.tgz#b58bc34cc30b27ffdbaf3d00bf27aba6fa29c6e3" +webpack-bundle-analyzer@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.9.1.tgz#c2c8e03e8e5768ed288b39ae9e27a8b8d7b9d476" dependencies: acorn "^5.1.1" chalk "^1.1.3" @@ -7251,21 +7353,21 @@ webpack-bundle-analyzer@^2.8.3: lodash "^4.17.4" mkdirp "^0.5.1" opener "^1.4.3" - ws "^2.3.1" + ws "^3.3.1" webpack-dev-middleware@^1.11.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709" + version "1.12.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" dependencies: memory-fs "~0.4.1" - mime "^1.3.4" + mime "^1.5.0" path-is-absolute "^1.0.0" range-parser "^1.0.3" time-stamp "^2.0.0" -webpack-dev-server@^2.9.3: - version "2.9.3" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.3.tgz#f0554e88d129e87796a6f74a016b991743ca6f81" +webpack-dev-server@^2.9.5: + version "2.9.5" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.5.tgz#79336fba0087a66ae491f4869f6545775b18daa8" dependencies: ansi-html "0.0.7" array-includes "^3.0.3" @@ -7275,12 +7377,13 @@ webpack-dev-server@^2.9.3: connect-history-api-fallback "^1.3.0" debug "^3.1.0" del "^3.0.0" - express "^4.13.3" + express "^4.16.2" html-entities "^1.2.0" http-proxy-middleware "~0.17.4" import-local "^0.1.1" internal-ip "1.2.0" ip "^1.1.5" + killable "^1.0.0" loglevel "^1.4.1" opn "^5.1.0" portfinder "^1.0.9" @@ -7301,22 +7404,22 @@ webpack-manifest-plugin@^1.2.1: fs-extra "^0.30.0" lodash ">=3.5 <5" -webpack-merge@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.0.tgz#6ad72223b3e0b837e531e4597c199f909361511e" +webpack-merge@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.1.tgz#f1197a0a973e69c6fbeeb6d658219aa8c0c13555" dependencies: lodash "^4.17.4" webpack-sources@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf" + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" - source-map "~0.5.3" + source-map "~0.6.1" -webpack@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" +webpack@^3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.9.1.tgz#9a60aa544ed5d4d454c069e3f521aa007e02643c" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -7349,8 +7452,8 @@ websocket-driver@>=0.5.1: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" websocket.js@^0.1.12: version "0.1.12" @@ -7416,8 +7519,8 @@ wordwrap@~1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" worker-farm@^1.3.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.0.tgz#adfdf0cd40581465ed0a1f648f9735722afd5c8d" + version "1.5.2" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" dependencies: errno "^0.1.4" xtend "^4.0.1" @@ -7447,11 +7550,12 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80" +ws@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.2.tgz#96c1d08b3fefda1d5c1e33700d3bfaa9be2d5608" dependencies: - safe-buffer "~5.0.1" + async-limiter "~1.0.0" + safe-buffer "~5.1.0" ultron "~1.1.0" xml-name-validator@^2.0.1: