Merge branch 'master' into master

This commit is contained in:
pinfort 2017-04-12 00:23:58 +09:00 committed by GitHub
commit 529a2edded
94 changed files with 1294 additions and 583 deletions

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2

View File

@ -35,6 +35,10 @@ SMTP_PORT=587
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=notifications@example.com
#SMTP_AUTH_METHOD=plain
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true
# Optional asset host for multi-server setups
# CDN_HOST=assets.example.com

30
.eslintignore Normal file
View File

@ -0,0 +1,30 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*
!/log/.keep
/tmp
coverage
public/system
public/assets
.env
.env.production
node_modules/
neo4j/
# Ignore Vagrant files
.vagrant/
# Ignore Capistrano customizations
config/deploy/*

View File

@ -1 +1 @@
2.3.1
2.4.1

View File

@ -16,7 +16,7 @@ addons:
postgresql: 9.4
rvm:
- 2.3.1
- 2.4.1
services:
- redis-server

View File

@ -1,4 +1,4 @@
FROM ruby:2.3.1-alpine
FROM ruby:2.4.1-alpine
LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="A GNU Social-compatible microblogging server"

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '2.3.1'
ruby '2.4.1'
gem 'rails', '~> 5.0.2'
gem 'sass-rails', '~> 5.0'
@ -32,6 +32,7 @@ gem 'htmlentities'
gem 'http'
gem 'http_accept_language'
gem 'httplog'
gem 'kaminari'
gem 'link_header'
gem 'nokogiri'
gem 'oj'
@ -52,7 +53,6 @@ gem 'simple_form'
gem 'statsd-instrument'
gem 'twitter-text'
gem 'tzinfo-data'
gem 'will_paginate'
gem 'react-rails'
gem 'browserify-rails'
@ -68,6 +68,7 @@ end
group :test do
gem 'faker'
gem 'rails-controller-testing'
gem 'rspec-sidekiq'
gem 'simplecov', require: false
gem 'webmock'

View File

@ -24,7 +24,7 @@ GEM
erubis (~> 2.7.0)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_record_query_trace (1.5.3)
active_record_query_trace (1.5.4)
activejob (5.0.2)
activesupport (= 5.0.2)
globalid (>= 0.3.6)
@ -39,7 +39,7 @@ GEM
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.5.0)
addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
airbrussh (1.1.2)
sshkit (>= 1.6.1, != 1.7.0)
@ -47,17 +47,17 @@ GEM
ast (2.3.0)
attr_encrypted (3.0.3)
encryptor (~> 3.0.0)
autoprefixer-rails (6.5.0.2)
autoprefixer-rails (6.7.7.1)
execjs
av (0.9.0)
cocaine (~> 0.5.3)
aws-sdk (2.6.28)
aws-sdk-resources (= 2.6.28)
aws-sdk-core (2.6.28)
aws-sdk (2.9.6)
aws-sdk-resources (= 2.9.6)
aws-sdk-core (2.9.6)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
aws-sdk-resources (2.6.28)
aws-sdk-core (= 2.6.28)
aws-sdk-resources (2.9.6)
aws-sdk-core (= 2.9.6)
aws-sigv4 (1.0.0)
babel-source (5.8.35)
babel-transpiler (0.7.0)
@ -78,12 +78,11 @@ GEM
railties (>= 4.0.0, < 5.1)
sprockets (>= 3.6.0)
builder (3.2.3)
bullet (5.3.0)
bullet (5.5.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
capistrano (3.7.2)
capistrano (3.8.0)
airbrussh (>= 1.0.0)
capistrano-harrow
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
@ -92,8 +91,7 @@ GEM
sshkit (~> 1.2)
capistrano-faster-assets (1.0.2)
capistrano (>= 3.1)
capistrano-harrow (0.5.3)
capistrano-rails (1.2.2)
capistrano-rails (1.2.3)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capistrano-rbenv (2.1.0)
@ -119,7 +117,7 @@ GEM
crack (0.4.3)
safe_yaml (~> 1.0.0)
debug_inspector (0.0.2)
devise (4.2.0)
devise (4.2.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.1)
@ -131,16 +129,16 @@ GEM
devise (~> 4.0)
railties
rotp (~> 2.0)
diff-lcs (1.2.5)
diff-lcs (1.3)
docile (1.1.5)
domain_name (0.5.20161129)
domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.2.0)
doorkeeper (4.2.5)
railties (>= 4.2)
dotenv (2.1.1)
dotenv-rails (2.1.1)
dotenv (= 2.1.1)
railties (>= 4.0, < 5.1)
dotenv (2.2.0)
dotenv-rails (2.2.0)
dotenv (= 2.2.0)
railties (>= 3.2, < 5.1)
easy_translate (0.5.0)
json
thread
@ -148,14 +146,14 @@ GEM
encryptor (3.0.0)
erubis (2.7.0)
execjs (2.7.0)
fabrication (2.15.2)
faker (1.6.6)
fabrication (2.16.1)
faker (1.7.3)
i18n (~> 0.5)
fast_blank (1.0.0)
font-awesome-rails (4.6.3.1)
font-awesome-rails (4.7.0.1)
railties (>= 3.2, < 5.1)
fuubar (2.1.1)
rspec (~> 3.0)
fuubar (2.2.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
globalid (0.3.7)
activesupport (>= 4.1.0)
@ -163,20 +161,20 @@ GEM
addressable (~> 2.4)
http (~> 2.0)
nokogiri (~> 1.6)
hamlit (2.7.2)
temple (~> 0.7.6)
hamlit (2.8.1)
temple (>= 0.8.0)
thor
tilt
hamlit-rails (0.1.0)
hamlit-rails (0.2.0)
actionpack (>= 4.0.1)
activesupport (>= 4.0.1)
hamlit (>= 1.2.0)
railties (>= 4.0.1)
hashdiff (0.3.0)
hashdiff (0.3.2)
highline (1.7.8)
hiredis (0.6.1)
htmlentities (4.3.4)
http (2.1.0)
http (2.2.1)
addressable (~> 2.3)
http-cookie (~> 1.0)
http-form_data (~> 1.0.1)
@ -186,10 +184,10 @@ GEM
http-form_data (1.0.1)
http_accept_language (2.1.0)
http_parser.rb (0.6.0)
httplog (0.3.2)
httplog (0.99.2)
colorize
i18n (0.8.1)
i18n-tasks (0.9.6)
i18n-tasks (0.9.13)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
easy_translate (>= 0.5.0)
@ -197,19 +195,31 @@ GEM
highline (>= 1.7.3)
i18n
parser (>= 2.2.3.0)
term-ansicolor (>= 1.3.2)
rainbow (~> 2.2)
terminal-table (>= 1.5.1)
jmespath (1.3.1)
jquery-rails (4.1.1)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
json (2.0.3)
kaminari (1.0.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1)
kaminari-activerecord (= 1.0.1)
kaminari-core (= 1.0.1)
kaminari-actionview (1.0.1)
actionview
kaminari-core (= 1.0.1)
kaminari-activerecord (1.0.1)
activerecord
kaminari-core (= 1.0.1)
kaminari-core (1.0.1)
launchy (2.4.3)
addressable (~> 2.3)
letter_opener (1.4.1)
launchy (~> 2.2)
letter_opener_web (1.3.0)
letter_opener_web (1.3.1)
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
@ -231,11 +241,11 @@ GEM
minitest (5.10.1)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (4.0.1)
net-ssh (4.1.0)
nio4r (2.0.0)
nokogiri (1.7.1)
mini_portile2 (~> 2.1.0)
oj (2.17.3)
oj (2.18.5)
orm_adapter (0.5.0)
ostatus2 (1.0.2)
addressable (~> 2.4)
@ -251,26 +261,26 @@ GEM
paperclip-av-transcoder (0.6.4)
av (~> 0.9.0)
paperclip (>= 2.5.2)
parser (2.3.1.2)
parser (2.4.0.0)
ast (~> 2.2)
pg (0.18.4)
pghero (1.6.2)
pg (0.20.0)
pghero (1.6.4)
activerecord
powerpack (0.1.1)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-rails (0.3.4)
pry (>= 0.9.10)
public_suffix (2.0.4)
puma (3.6.0)
pry-rails (0.3.6)
pry (>= 0.10.4)
public_suffix (2.0.5)
puma (3.8.2)
rabl (0.13.1)
activesupport (>= 2.3.14)
rack (2.0.1)
rack-attack (5.0.1)
rack
rack-cors (0.4.0)
rack-cors (0.4.1)
rack-protection (1.5.3)
rack
rack-test (0.6.3)
@ -288,6 +298,10 @@ GEM
bundler (>= 1.3.0, < 2.0)
railties (= 5.0.2)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.1)
actionpack (~> 5.x)
actionview (~> 5.x)
activesupport (~> 5.x)
rails-dom-testing (2.0.2)
activesupport (>= 4.2.0, < 6.0)
nokogiri (~> 1.6)
@ -306,42 +320,37 @@ GEM
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.1.0)
rainbow (2.2.1)
rake (12.0.0)
react-rails (1.10.0)
react-rails (1.11.0)
babel-transpiler (>= 0.7.0)
coffee-script-source (~> 1.8)
connection_pool
execjs
railties (>= 3.2)
tilt
redis (3.3.2)
redis-actionpack (5.0.0)
actionpack (>= 4.0.0, < 6)
redis-rack (~> 2.0.0.pre)
redis-store (~> 1.2.0.pre)
redis-activesupport (5.0.1)
redis (3.3.3)
redis-actionpack (5.0.1)
actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 1.4.0)
redis-activesupport (5.0.2)
activesupport (>= 3, < 6)
redis-store (~> 1.2.0)
redis-rack (2.0.0)
rack (~> 2.0)
redis-store (~> 1.2.0)
redis-rails (5.0.1)
redis-actionpack (~> 5.0.0)
redis-activesupport (~> 5.0.0)
redis-store (~> 1.2.0)
redis-store (1.2.0)
redis-store (~> 1.3.0)
redis-rack (2.0.1)
rack (>= 2.0, < 3)
redis-store (>= 1.2, < 1.4)
redis-rails (5.0.2)
redis-actionpack (>= 5.0, < 6)
redis-activesupport (>= 5.0, < 6)
redis-store (>= 1.2, < 2)
redis-store (1.3.0)
redis (>= 2.2)
responders (2.3.0)
railties (>= 4.2.0, < 5.1)
rotp (2.1.2)
rqrcode (0.10.1)
chunky_png (~> 1.0)
rspec (3.5.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-core (3.5.2)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
@ -349,7 +358,7 @@ GEM
rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-rails (3.5.1)
rspec-rails (3.5.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@ -357,40 +366,40 @@ GEM
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-support (~> 3.5.0)
rspec-sidekiq (2.2.0)
rspec (~> 3.0, >= 3.0.0)
rspec-sidekiq (3.0.0)
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.5.0)
rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0)
rubocop (0.48.1)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-oembed (0.10.1)
ruby-oembed (0.12.0)
ruby-progressbar (1.8.1)
safe_yaml (1.0.4)
sass (3.4.22)
sass (3.4.23)
sass-rails (5.0.6)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sidekiq (4.2.7)
sidekiq (4.2.10)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
redis (~> 3.2, >= 3.2.1)
sidekiq-unique-jobs (4.0.18)
sidekiq (>= 2.6)
sidekiq-unique-jobs (5.0.0)
sidekiq (>= 4.0)
thor
simple-navigation (4.0.3)
simple-navigation (4.0.5)
activesupport (>= 2.3.2)
simple_form (3.2.1)
simple_form (3.4.0)
actionpack (> 4, < 5.1)
activemodel (> 4, < 5.1)
simplecov (0.12.0)
simplecov (0.14.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
@ -403,43 +412,39 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sshkit (1.11.5)
sshkit (1.13.1)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
statsd-instrument (2.1.2)
temple (0.7.7)
term-ansicolor (1.4.0)
tins (~> 1.0)
terminal-table (1.7.0)
unicode-display_width (~> 1.1)
temple (0.8.0)
terminal-table (1.7.3)
unicode-display_width (~> 1.1.1)
thor (0.19.4)
thread (0.2.2)
thread_safe (0.3.6)
tilt (2.0.6)
tins (1.12.0)
tilt (2.0.7)
twitter-text (1.14.5)
unf (~> 0.1.0)
tzinfo (1.2.2)
tzinfo (1.2.3)
thread_safe (~> 0.1)
tzinfo-data (1.2017.2)
tzinfo (>= 1.0.0)
uglifier (3.0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
unicode-display_width (1.1.0)
unicode-display_width (1.1.3)
uniform_notifier (1.10.0)
warden (1.2.6)
warden (1.2.7)
rack (>= 1.0)
webmock (2.1.0)
webmock (2.3.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
will_paginate (3.1.0)
PLATFORMS
ruby
@ -478,6 +483,7 @@ DEPENDENCIES
httplog
i18n-tasks (~> 0.9.6)
jquery-rails
kaminari
letter_opener
letter_opener_web
link_header
@ -497,6 +503,7 @@ DEPENDENCIES
rack-cors
rack-timeout
rails (~> 5.0.2)
rails-controller-testing
rails-settings-cached
rails_12factor
react-rails
@ -518,10 +525,9 @@ DEPENDENCIES
tzinfo-data
uglifier (>= 1.3.0)
webmock
will_paginate
RUBY VERSION
ruby 2.3.1p112
ruby 2.4.1p111
BUNDLED WITH
1.14.5
1.14.6

View File

@ -67,7 +67,7 @@ Consult the example configuration file, `.env.production.sample` for the full li
[![](https://images.microbadger.com/badges/version/gargron/mastodon.svg)](https://microbadger.com/images/gargron/mastodon "Get your own version badge on microbadger.com") [![](https://images.microbadger.com/badges/image/gargron/mastodon.svg)](https://microbadger.com/images/gargron/mastodon "Get your own image badge on microbadger.com")
The project now includes a `Dockerfile` and a `docker-compose.yml`. You need to turn `.env.production.sample` into `.env.production` with all the variables set before you can:
The project now includes a `Dockerfile` and a `docker-compose.yml` file (which requires at least docker-compose version `1.10.0`). You need to turn `.env.production.sample` into `.env.production` with all the variables set before you can:
docker-compose build

8
Vagrantfile vendored
View File

@ -46,12 +46,12 @@ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
export PATH="$HOME/.rbenv/bin::$PATH"
eval "$(rbenv init -)"
echo "Compiling Ruby 2.3.1: warning, this takes a while!!!"
rbenv install 2.3.1
rbenv global 2.3.1
cd /vagrant
echo "Compiling Ruby $(cat .ruby-version): warning, this takes a while!!!"
rbenv install $(cat .ruby-version)
rbenv global $(cat .ruby-version)
# Configure database
sudo -u postgres createuser -U postgres vagrant -s
sudo -u postgres createdb -U postgres mastodon_development

View File

@ -79,6 +79,18 @@
"SMTP_FROM_ADDRESS": {
"description": "Address to send emails from",
"required": false
},
"SMTP_AUTH_METHOD": {
"description": "Authentication method to use with SMTP server. Default is 'plain'.",
"required": false
},
"SMTP_OPENSSL_VERIFY_MODE": {
"description": "SMTP server certificate verification mode. Defaults is 'peer'.",
"required": false
},
"SMTP_ENABLE_STARTTLS_AUTO": {
"description": "Enable STARTTLS if SMTP server supports it? Default is true.",
"required": false
}
},
"buildpacks": [

View File

@ -61,6 +61,8 @@ export function refreshNotifications() {
params.since_id = ids.first().get('id');
}
params.exclude_types = getState().getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
api(getState).get('/api/v1/notifications', { params }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
@ -105,11 +107,11 @@ export function expandNotifications() {
dispatch(expandNotificationsRequest());
api(getState).get(url, {
params: {
limit: 5
}
}).then(response => {
const params = {};
params.exclude_types = getState().getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
api(getState).get(url, params).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null));

View File

@ -65,7 +65,7 @@ const Account = React.createClass({
<div className='account'>
<div style={{ display: 'flex' }}>
<Permalink key={account.get('id')} className='account__display-name' href={account.get('url')} to={`/accounts/${account.get('id')}`}>
<div style={{ float: 'left', marginLeft: '12px', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={36} /></div>
<div style={{ float: 'left', marginLeft: '12px', marginRight: '10px' }}><Avatar src={account.get('avatar')} staticSrc={status.getIn(['account', 'avatar_static'])} size={36} /></div>
<DisplayName account={account} />
</Permalink>

View File

@ -1,103 +1,18 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
// From: http://stackoverflow.com/a/18320662
const resample = (canvas, width, height, resize_canvas) => {
let width_source = canvas.width;
let height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);
let ratio_w = width_source / width;
let ratio_h = height_source / height;
let ratio_w_half = Math.ceil(ratio_w / 2);
let ratio_h_half = Math.ceil(ratio_h / 2);
let ctx = canvas.getContext("2d");
let img = ctx.getImageData(0, 0, width_source, height_source);
let img2 = ctx.createImageData(width, height);
let data = img.data;
let data2 = img2.data;
for (let j = 0; j < height; j++) {
for (let i = 0; i < width; i++) {
let x2 = (i + j * width) * 4;
let weight = 0;
let weights = 0;
let weights_alpha = 0;
let gx_r = 0;
let gx_g = 0;
let gx_b = 0;
let gx_a = 0;
let center_y = (j + 0.5) * ratio_h;
let yy_start = Math.floor(j * ratio_h);
let yy_stop = Math.ceil((j + 1) * ratio_h);
for (let yy = yy_start; yy < yy_stop; yy++) {
let dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
let center_x = (i + 0.5) * ratio_w;
let w0 = dy * dy; //pre-calc part of w
let xx_start = Math.floor(i * ratio_w);
let xx_stop = Math.ceil((i + 1) * ratio_w);
for (let xx = xx_start; xx < xx_stop; xx++) {
let dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
let w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
// pixel too far
continue;
}
// hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
let pos_x = 4 * (xx + yy * width_source);
// alpha
gx_a += weight * data[pos_x + 3];
weights_alpha += weight;
// colors
if (data[pos_x + 3] < 255)
weight = weight * data[pos_x + 3] / 250;
gx_r += weight * data[pos_x];
gx_g += weight * data[pos_x + 1];
gx_b += weight * data[pos_x + 2];
weights += weight;
}
}
data2[x2] = gx_r / weights;
data2[x2 + 1] = gx_g / weights;
data2[x2 + 2] = gx_b / weights;
data2[x2 + 3] = gx_a / weights_alpha;
}
}
// clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
} else {
ctx.clearRect(0, 0, width_source, height_source);
}
// draw
ctx.putImageData(img2, 0, 0);
};
const Avatar = React.createClass({
propTypes: {
src: React.PropTypes.string.isRequired,
staticSrc: React.PropTypes.string,
size: React.PropTypes.number.isRequired,
style: React.PropTypes.object,
animated: React.PropTypes.bool
animate: React.PropTypes.bool
},
getDefaultProps () {
return {
animated: true
animate: false
};
},
@ -117,38 +32,30 @@ const Avatar = React.createClass({
this.setState({ hovering: false });
},
handleLoad () {
this.canvas.width = this.image.naturalWidth;
this.canvas.height = this.image.naturalHeight;
this.canvas.getContext('2d').drawImage(this.image, 0, 0);
resample(this.canvas, this.props.size * window.devicePixelRatio, this.props.size * window.devicePixelRatio, true);
},
setImageRef (c) {
this.image = c;
},
setCanvasRef (c) {
this.canvas = c;
},
render () {
const { src, size, staticSrc, animate } = this.props;
const { hovering } = this.state;
if (this.props.animated) {
return (
<div style={{ ...this.props.style, width: `${this.props.size}px`, height: `${this.props.size}px` }}>
<img src={this.props.src} width={this.props.size} height={this.props.size} alt='' style={{ borderRadius: '4px' }} />
</div>
);
const style = {
...this.props.style,
width: `${size}px`,
height: `${size}px`,
backgroundSize: `${size}px ${size}px`
};
if (hovering || animate) {
style.backgroundImage = `url(${src})`;
} else {
style.backgroundImage = `url(${staticSrc})`;
}
return (
<div onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} style={{ ...this.props.style, width: `${this.props.size}px`, height: `${this.props.size}px`, position: 'relative' }}>
<img ref={this.setImageRef} onLoad={this.handleLoad} src={this.props.src} width={this.props.size} height={this.props.size} alt='' style={{ position: 'absolute', top: '0', left: '0', opacity: hovering ? '1' : '0', borderRadius: '4px' }} />
<canvas ref={this.setCanvasRef} style={{ borderRadius: '4px', width: this.props.size, height: this.props.size, opacity: hovering ? '0' : '1' }} />
</div>
<div
className='avatar'
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
style={style}
/>
);
}

View File

@ -90,7 +90,7 @@ const Status = React.createClass({
<a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name' style={{ display: 'block', maxWidth: '100%', paddingRight: '25px' }}>
<div className='status__avatar' style={{ position: 'absolute', left: '10px', top: '10px', width: '48px', height: '48px' }}>
<Avatar src={status.getIn(['account', 'avatar'])} size={48} />
<Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} />
</div>
<DisplayName account={status.get('account')} />

View File

@ -36,6 +36,7 @@ const StatusContent = React.createClass({
if (mention) {
link.addEventListener('click', this.onMentionClick.bind(this, mention), false);
link.setAttribute('title', mention.get('acct'));
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
} else if (media) {
@ -91,7 +92,7 @@ const StatusContent = React.createClass({
const { status } = this.props;
const { hidden } = this.state;
const content = { __html: emojify(status.get('content')) };
const content = { __html: emojify(status.get('content')).replace(/\n/g, '') };
const spoilerContent = { __html: emojify(escapeTextContentForBrowser(status.get('spoiler_text', ''))) };
const directionStyle = { direction: 'ltr' };
@ -125,7 +126,7 @@ const StatusContent = React.createClass({
<div style={{ display: hidden ? 'none' : 'block', ...directionStyle }} dangerouslySetInnerHTML={content} />
</div>
);
} else {
} else if (this.props.onClick) {
return (
<div
className='status__content'
@ -135,6 +136,14 @@ const StatusContent = React.createClass({
dangerouslySetInnerHTML={content}
/>
);
} else {
return (
<div
className='status__content'
style={{ ...directionStyle }}
dangerouslySetInnerHTML={content}
/>
);
}
},

View File

@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
const AutosuggestAccount = ({ account }) => (
<div style={{ overflow: 'hidden' }} className='autosuggest-account'>
<div style={{ float: 'left', marginRight: '5px' }}><Avatar src={account.get('avatar')} size={18} /></div>
<div style={{ float: 'left', marginRight: '5px' }}><Avatar src={account.get('avatar')} staticSrc={status.getIn(['account', 'avatar_static'])} size={18} /></div>
<DisplayName account={account} />
</div>
);

View File

@ -83,11 +83,23 @@ const ComposeForm = React.createClass({
this.props.onChangeSpoilerText(e.target.value);
},
componentWillReceiveProps (nextProps) {
// If this is the update where we've finished uploading,
// save the last caret position so we can restore it below!
if (!nextProps.is_uploading && this.props.is_uploading) {
this._restoreCaret = this.autosuggestTextarea.textarea.selectionStart;
}
},
componentDidUpdate (prevProps) {
if (this.props.focusDate !== prevProps.focusDate) {
// If replying to zero or one users, places the cursor at the end of the textbox.
// If replying to more than one user, selects any usernames past the first;
// this provides a convenient shortcut to drop everyone else from the conversation.
// This statement does several things:
// - If we're beginning a reply, and,
// - Replying to zero or one users, places the cursor at the end of the textbox.
// - Replying to more than one user, selects any usernames past the first;
// this provides a convenient shortcut to drop everyone else from the conversation.
// - If we've just finished uploading an image, and have a saved caret position,
// restores the cursor to that position after the text changes!
if (this.props.focusDate !== prevProps.focusDate || (prevProps.is_uploading && !this.props.is_uploading && typeof this._restoreCaret === 'number')) {
let selectionEnd, selectionStart;
if (this.props.preselectDate !== prevProps.preselectDate) {
@ -118,7 +130,7 @@ const ComposeForm = React.createClass({
render () {
const { intl, needsPrivacyWarning, mentionedDomains, onPaste } = this.props;
const disabled = this.props.is_submitting || this.props.is_uploading;
const disabled = this.props.is_submitting;
let publishText = '';
let privacyWarning = '';

View File

@ -17,7 +17,7 @@ const NavigationBar = React.createClass({
render () {
return (
<div className='navigation-bar'>
<Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`} style={{ textDecoration: 'none' }}><Avatar src={this.props.account.get('avatar')} size={40} /></Permalink>
<Permalink href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`} style={{ textDecoration: 'none' }}><Avatar src={this.props.account.get('avatar')} animate size={40} /></Permalink>
<div style={{ flex: '1 1 auto', marginLeft: '8px' }}>
<strong style={{ fontWeight: '500', display: 'block' }}>{this.props.account.get('acct')}</strong>

View File

@ -50,7 +50,7 @@ const ReplyIndicator = React.createClass({
<div style={{ float: 'right', lineHeight: '24px' }}><IconButton title={intl.formatMessage(messages.cancel)} icon='times' onClick={this.handleClick} /></div>
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name' style={{ display: 'block', maxWidth: '100%', paddingRight: '25px', textDecoration: 'none', overflow: 'hidden', lineHeight: '24px' }}>
<div style={{ float: 'left', marginRight: '5px' }}><Avatar size={24} src={status.getIn(['account', 'avatar'])} /></div>
<div style={{ float: 'left', marginRight: '5px' }}><Avatar size={24} src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} /></div>
<DisplayName account={status.get('account')} />
</a>
</div>

View File

@ -33,7 +33,7 @@ const AccountAuthorize = ({ intl, account, onAuthorize, onReject }) => {
<div>
<div style={outerStyle}>
<Permalink href={account.get('url')} to={`/accounts/${account.get('id')}`} className='detailed-status__display-name' style={{ display: 'block', overflow: 'hidden', marginBottom: '15px' }}>
<div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} size={48} /></div>
<div style={{ float: 'left', marginRight: '10px' }}><Avatar src={account.get('avatar')} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} /></div>
<DisplayName account={account} />
</Permalink>

View File

@ -4,16 +4,6 @@ const messages = defineMessages({
clear: { id: 'notifications.clear', defaultMessage: 'Clear notifications' }
});
const iconStyle = {
fontSize: '16px',
padding: '15px',
position: 'absolute',
right: '48px',
top: '0',
cursor: 'pointer',
zIndex: '2'
};
const ClearColumnButton = React.createClass({
propTypes: {
@ -25,7 +15,7 @@ const ClearColumnButton = React.createClass({
const { intl } = this.props;
return (
<div title={intl.formatMessage(messages.clear)} className='column-icon' tabIndex='0' style={iconStyle} onClick={this.props.onClick}>
<div title={intl.formatMessage(messages.clear)} className='column-icon column-icon-clear' tabIndex='0' onClick={this.props.onClick}>
<i className='fa fa-eraser' />
</div>
);

View File

@ -21,7 +21,7 @@ const Notification = React.createClass({
renderFollow (account, link) {
return (
<div className='notification'>
<div className='notification notification-follow'>
<div className='notification__message'>
<div style={{ position: 'absolute', 'left': '-26px'}}>
<i className='fa fa-fw fa-user-plus' />
@ -41,7 +41,7 @@ const Notification = React.createClass({
renderFavourite (notification, link) {
return (
<div className='notification'>
<div className='notification notification-favourite'>
<div className='notification__message'>
<div style={{ position: 'absolute', 'left': '-26px'}}>
<i className='fa fa-fw fa-star' style={{ color: '#ca8f04' }} />
@ -57,7 +57,7 @@ const Notification = React.createClass({
renderReblog (notification, link) {
return (
<div className='notification'>
<div className='notification notification-reblog'>
<div className='notification__message'>
<div style={{ position: 'absolute', 'left': '-26px'}}>
<i className='fa fa-fw fa-retweet' />
@ -76,7 +76,7 @@ const Notification = React.createClass({
const account = notification.get('account');
const displayName = account.get('display_name').length > 0 ? account.get('display_name') : account.get('username');
const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) };
const link = <Permalink className='notification__display-name' style={linkStyle} href={account.get('url')} to={`/accounts/${account.get('id')}`} dangerouslySetInnerHTML={displayNameHTML} />;
const link = <Permalink className='notification__display-name' style={linkStyle} href={account.get('url')} title={account.get('acct')} to={`/accounts/${account.get('id')}`} dangerouslySetInnerHTML={displayNameHTML} />;
switch(notification.get('type')) {
case 'follow':

View File

@ -54,7 +54,7 @@ const DetailedStatus = React.createClass({
return (
<div style={{ padding: '14px 10px' }} className='detailed-status'>
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name' style={{ display: 'block', overflow: 'hidden', marginBottom: '15px' }}>
<div style={{ float: 'left', marginRight: '10px' }}><Avatar src={status.getIn(['account', 'avatar'])} size={48} /></div>
<div style={{ float: 'left', marginRight: '10px' }}><Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} /></div>
<DisplayName account={status.get('account')} />
</a>

View File

@ -72,6 +72,7 @@
position: relative;
z-index: 2;
flex-direction: row;
background: rgba(0,0,0,0.5);
}
.details-counters {
@ -83,7 +84,7 @@
.counter {
width: 80px;
color: $color3;
padding: 0 10px;
padding: 5px 10px 0px;
margin-bottom: 10px;
border-right: 1px solid $color3;
cursor: default;
@ -173,7 +174,7 @@
text-align: center;
overflow: hidden;
a, .current, .next_page, .previous_page, .gap {
a, .current, .page, .gap {
font-size: 14px;
color: $color5;
font-weight: 500;
@ -193,12 +194,12 @@
cursor: default;
}
.previous_page, .next_page {
.prev, .next {
text-transform: uppercase;
color: $color2;
}
.previous_page {
.prev {
float: left;
padding-left: 0;
@ -208,7 +209,7 @@
}
}
.next_page {
.next {
float: right;
padding-right: 0;
@ -226,11 +227,11 @@
@media screen and (max-width: 360px) {
padding: 30px 20px;
a, .current, .next_page, .previous_page, .gap {
a, .current, .next, .prev, .gap {
display: none;
}
.next_page, .previous_page {
.next, .prev {
display: inline-block;
}
}

View File

@ -1,7 +1,7 @@
@import 'variables';
.app-body{
-ms-overflow-style: -ms-autohiding-scrollbar;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.button {
@ -49,6 +49,22 @@
}
}
.column-icon-clear {
font-size: 16px;
padding: 15px;
position: absolute;
right: 48px;
top: 0;
cursor: pointer;
z-index: 2;
}
@media screen and (min-width: 1024px) {
.column-icon-clear {
top: 10px;
}
}
.icon-button {
display: inline-block;
padding: 0;
@ -149,6 +165,14 @@
}
}
.avatar {
border-radius: 4px;
background: transparent no-repeat;
background-position: 50%;
background-clip: padding-box;
position: relative;
}
.lightbox .icon-button {
color: $color1;
}
@ -714,15 +738,7 @@ a.status__content__spoiler-link {
@media screen and (min-width: 360px) {
.columns-area {
margin: 0;
}
.column:first-child, .drawer:first-child {
margin-left: 0;
}
.column:last-child, .drawer:last-child {
margin-right: 0;
padding: 10px;
}
}
@ -730,9 +746,12 @@ a.status__content__spoiler-link {
width: 330px;
position: relative;
box-sizing: border-box;
background: $color1;
display: flex;
flex-direction: column;
> .scrollable {
background: $color1;
}
}
.ui {
@ -764,6 +783,58 @@ a.status__content__spoiler-link {
border-bottom: 2px solid transparent;
}
.column, .drawer {
flex: 1 1 100%;
overflow: hidden;
}
@media screen and (min-width: 360px) {
.tabs-bar {
margin: 10px;
margin-bottom: 0;
}
.search {
margin-bottom: 10px;
}
}
@media screen and (max-width: 1024px) {
.column, .drawer {
width: 100%;
padding: 0;
}
.columns-area {
flex-direction: column;
}
.search__input, .autosuggest-textarea__textarea {
font-size: 16px;
}
}
@media screen and (min-width: 1024px) {
.columns-area {
padding: 0;
}
.column, .drawer {
flex: 0 0 auto;
padding: 10px;
padding-left: 5px;
padding-right: 5px;
&:first-child {
padding-left: 10px;
}
&:last-child {
padding-right: 10px;
}
}
}
@media screen and (min-width: 2560px) {
.columns-area {
justify-content: center;
@ -823,38 +894,6 @@ a.status__content__spoiler-link {
}
}
.column, .drawer {
margin: 10px;
margin-left: 5px;
margin-right: 5px;
flex: 0 0 auto;
overflow: hidden;
}
.column:first-child, .drawer:first-child {
margin-left: 10px;
}
.column:last-child, .drawer:last-child {
margin-right: 10px;
}
@media screen and (max-width: 1024px) {
.column, .drawer {
width: 100%;
margin: 0;
flex: 1 1 100%;
}
.columns-area {
flex-direction: column;
}
.search__input, .autosuggest-textarea__textarea {
font-size: 16px;
}
}
.tabs-bar {
display: flex;
background: lighten($color1, 8%);
@ -895,27 +934,6 @@ a.status__content__spoiler-link {
}
}
@media screen and (min-width: 360px) {
.columns-area {
margin: 10px;
}
.tabs-bar {
margin: 10px;
margin-bottom: 0;
}
.search {
margin-bottom: 10px;
}
}
@media screen and (min-width: 1024px) {
.columns-area {
margin: 0;
}
}
@media screen and (min-width: 600px) {
.tabs-bar__link {
span {
@ -1379,12 +1397,15 @@ button.active i.fa-retweet {
.empty-column-indicator {
color: lighten($color1, 20%);
background: $color1;
text-align: center;
padding: 20px;
padding-top: 100px;
font-size: 15px;
font-weight: 400;
cursor: default;
display: flex;
flex: 1 1 auto;
align-items: center;
a {
color: $color4;
@ -1412,7 +1433,7 @@ button.active i.fa-retweet {
.emoji-dialog {
width: 280px;
height: 220px;
background: $color2;
background: darken($color3, 10%);
box-sizing: border-box;
border-radius: 2px;
overflow: hidden;

View File

@ -35,11 +35,11 @@ class AccountsController < ApplicationController
end
def followers
@followers = @account.followers.order('follows.created_at desc').paginate(page: params[:page], per_page: 12)
@followers = @account.followers.order('follows.created_at desc').page(params[:page]).per(12)
end
def following
@following = @account.following.order('follows.created_at desc').paginate(page: params[:page], per_page: 12)
@following = @account.following.order('follows.created_at desc').page(params[:page]).per(12)
end
private
@ -53,7 +53,7 @@ class AccountsController < ApplicationController
end
def webfinger_account_url
webfinger_url(resource: "acct:#{@account.acct}@#{Rails.configuration.x.local_domain}")
webfinger_url(resource: @account.to_webfinger_s)
end
def check_account_suspension

View File

@ -1,51 +1,50 @@
# frozen_string_literal: true
class Admin::AccountsController < ApplicationController
before_action :require_admin!
before_action :set_account, except: :index
module Admin
class AccountsController < BaseController
before_action :set_account, except: :index
layout 'admin'
def index
@accounts = Account.alphabetic.page(params[:page])
def index
@accounts = Account.alphabetic.paginate(page: params[:page], per_page: 40)
@accounts = @accounts.local if params[:local].present?
@accounts = @accounts.remote if params[:remote].present?
@accounts = @accounts.where(domain: params[:by_domain]) if params[:by_domain].present?
@accounts = @accounts.silenced if params[:silenced].present?
@accounts = @accounts.recent if params[:recent].present?
@accounts = @accounts.suspended if params[:suspended].present?
end
@accounts = @accounts.local if params[:local].present?
@accounts = @accounts.remote if params[:remote].present?
@accounts = @accounts.where(domain: params[:by_domain]) if params[:by_domain].present?
@accounts = @accounts.silenced if params[:silenced].present?
@accounts = @accounts.recent if params[:recent].present?
@accounts = @accounts.suspended if params[:suspended].present?
end
def show; end
def show; end
def suspend
Admin::SuspensionWorker.perform_async(@account.id)
redirect_to admin_accounts_path
end
def suspend
Admin::SuspensionWorker.perform_async(@account.id)
redirect_to admin_accounts_path
end
def unsuspend
@account.update(suspended: false)
redirect_to admin_accounts_path
end
def unsuspend
@account.update(suspended: false)
redirect_to admin_accounts_path
end
def silence
@account.update(silenced: true)
redirect_to admin_accounts_path
end
def silence
@account.update(silenced: true)
redirect_to admin_accounts_path
end
def unsilence
@account.update(silenced: false)
redirect_to admin_accounts_path
end
def unsilence
@account.update(silenced: false)
redirect_to admin_accounts_path
end
private
private
def set_account
@account = Account.find(params[:id])
end
def set_account
@account = Account.find(params[:id])
end
def account_params
params.require(:account).permit(:silenced, :suspended)
def account_params
params.require(:account).permit(:silenced, :suspended)
end
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
module Admin
class BaseController < ApplicationController
before_action :require_admin!
layout 'admin'
end
end

View File

@ -1,32 +1,30 @@
# frozen_string_literal: true
class Admin::DomainBlocksController < ApplicationController
before_action :require_admin!
module Admin
class DomainBlocksController < BaseController
def index
@blocks = DomainBlock.page(params[:page])
end
layout 'admin'
def new
@domain_block = DomainBlock.new
end
def index
@blocks = DomainBlock.paginate(page: params[:page], per_page: 40)
end
def create
@domain_block = DomainBlock.new(resource_params)
def new
@domain_block = DomainBlock.new
end
if @domain_block.save
DomainBlockWorker.perform_async(@domain_block.id)
redirect_to admin_domain_blocks_path, notice: 'Domain block is now being processed'
else
render action: :new
end
end
def create
@domain_block = DomainBlock.new(resource_params)
private
if @domain_block.save
DomainBlockWorker.perform_async(@domain_block.id)
redirect_to admin_domain_blocks_path, notice: 'Domain block is now being processed'
else
render action: :new
def resource_params
params.require(:domain_block).permit(:domain, :severity)
end
end
private
def resource_params
params.require(:domain_block).permit(:domain, :severity)
end
end

View File

@ -1,11 +1,9 @@
# frozen_string_literal: true
class Admin::PubsubhubbubController < ApplicationController
before_action :require_admin!
layout 'admin'
def index
@subscriptions = Subscription.order('id desc').includes(:account).paginate(page: params[:page], per_page: 40)
module Admin
class PubsubhubbubController < BaseController
def index
@subscriptions = Subscription.order('id desc').includes(:account).page(params[:page])
end
end
end

View File

@ -1,45 +1,44 @@
# frozen_string_literal: true
class Admin::ReportsController < ApplicationController
before_action :require_admin!
before_action :set_report, except: [:index]
module Admin
class ReportsController < BaseController
before_action :set_report, except: [:index]
layout 'admin'
def index
@reports = Report.includes(:account, :target_account).order('id desc').page(params[:page])
@reports = params[:action_taken].present? ? @reports.resolved : @reports.unresolved
end
def index
@reports = Report.includes(:account, :target_account).order('id desc').paginate(page: params[:page], per_page: 40)
@reports = params[:action_taken].present? ? @reports.resolved : @reports.unresolved
end
def show
@statuses = Status.where(id: @report.status_ids)
end
def show
@statuses = Status.where(id: @report.status_ids)
end
def resolve
@report.update(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_report_path(@report)
end
def resolve
@report.update(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_report_path(@report)
end
def suspend
Admin::SuspensionWorker.perform_async(@report.target_account.id)
Report.unresolved.where(target_account: @report.target_account).update_all(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_report_path(@report)
end
def suspend
Admin::SuspensionWorker.perform_async(@report.target_account.id)
Report.unresolved.where(target_account: @report.target_account).update_all(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_report_path(@report)
end
def silence
@report.target_account.update(silenced: true)
Report.unresolved.where(target_account: @report.target_account).update_all(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_report_path(@report)
end
def silence
@report.target_account.update(silenced: true)
Report.unresolved.where(target_account: @report.target_account).update_all(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_report_path(@report)
end
def remove
RemovalWorker.perform_async(params[:status_id])
redirect_to admin_report_path(@report)
end
def remove
RemovalWorker.perform_async(params[:status_id])
redirect_to admin_report_path(@report)
end
private
private
def set_report
@report = Report.find(params[:id])
def set_report
@report = Report.find(params[:id])
end
end
end

View File

@ -1,35 +1,33 @@
# frozen_string_literal: true
class Admin::SettingsController < ApplicationController
before_action :require_admin!
layout 'admin'
def index
@settings = Setting.all_as_records
end
def update
@setting = Setting.where(var: params[:id]).first_or_initialize(var: params[:id])
value = settings_params[:value]
# Special cases
value = value == 'true' if @setting.var == 'open_registrations'
if @setting.value != value
@setting.value = value
@setting.save
module Admin
class SettingsController < BaseController
def index
@settings = Setting.all_as_records
end
respond_to do |format|
format.html { redirect_to admin_settings_path }
format.json { respond_with_bip(@setting) }
def update
@setting = Setting.where(var: params[:id]).first_or_initialize(var: params[:id])
value = settings_params[:value]
# Special cases
value = value == 'true' if @setting.var == 'open_registrations'
if @setting.value != value
@setting.value = value
@setting.save
end
respond_to do |format|
format.html { redirect_to admin_settings_path }
format.json { respond_with_bip(@setting) }
end
end
end
private
private
def settings_params
params.require(:setting).permit(:value)
def settings_params
params.require(:setting).permit(:value)
end
end
end

View File

@ -9,7 +9,7 @@ class Api::V1::NotificationsController < ApiController
DEFAULT_NOTIFICATIONS_LIMIT = 15
def index
@notifications = Notification.where(account: current_account).browserable.paginate_by_max_id(limit_param(DEFAULT_NOTIFICATIONS_LIMIT), params[:max_id], params[:since_id])
@notifications = Notification.where(account: current_account).browserable(exclude_types).paginate_by_max_id(limit_param(DEFAULT_NOTIFICATIONS_LIMIT), params[:max_id], params[:since_id])
@notifications = cache_collection(@notifications, Notification)
statuses = @notifications.select { |n| !n.target_status.nil? }.map(&:target_status)
@ -32,7 +32,13 @@ class Api::V1::NotificationsController < ApiController
private
def exclude_types
val = params.permit(exclude_types: [])[:exclude_types] || []
val = [val] unless val.is_a?(Enumerable)
val
end
def pagination_params(core_params)
params.permit(:limit).merge(core_params)
params.permit(:limit, exclude_types: []).merge(core_params)
end
end

View File

@ -25,7 +25,7 @@ class RemoteFollowController < ApplicationController
session[:remote_follow] = @remote_follow.acct
redirect_to Addressable::Template.new(redirect_url_link.template).expand(uri: "#{@account.username}@#{Rails.configuration.x.local_domain}").to_s
redirect_to Addressable::Template.new(redirect_url_link.template).expand(uri: @account.to_webfinger_s).to_s
else
render :new
end

View File

@ -39,7 +39,7 @@ class Settings::ExportsController < ApplicationController
def accounts_list_to_csv(list)
CSV.generate do |csv|
list.each do |account|
csv << [(account.local? ? "#{account.username}@#{Rails.configuration.x.local_domain}" : account.acct)]
csv << [(account.local? ? account.local_username_and_domain : account.acct)]
end
end
end

View File

@ -14,7 +14,7 @@ class XrdController < ApplicationController
def webfinger
@account = Account.find_local!(username_from_resource)
@canonical_account_uri = "acct:#{@account.username}@#{Rails.configuration.x.local_domain}"
@canonical_account_uri = @account.to_webfinger_s
@magic_key = pem_to_magic_key(@account.keypair.public_key)
respond_to do |format|

View File

@ -1,12 +0,0 @@
# frozen_string_literal: true
module AccountsHelper
def pagination_options
{
previous_label: safe_join([fa_icon('chevron-left'), t('pagination.prev')], ' '),
next_label: safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '),
inner_window: 1,
outer_window: 0,
}
end
end

View File

@ -160,7 +160,7 @@ module AtomBuilderHelper
object_type xml, :person
uri xml, TagManager.instance.uri_for(account)
name xml, account.username
email xml, account.local? ? "#{account.acct}@#{Rails.configuration.x.local_domain}" : account.acct
email xml, account.local? ? account.local_username_and_domain : account.acct
summary xml, account.note
link_alternate xml, TagManager.instance.url_for(account)
link_avatar xml, account

View File

@ -20,7 +20,7 @@ class AtomSerializer
append_element(author, 'activity:object-type', TagManager::TYPES[:person])
append_element(author, 'uri', uri)
append_element(author, 'name', account.username)
append_element(author, 'email', account.local? ? "#{account.acct}@#{Rails.configuration.x.local_domain}" : account.acct)
append_element(author, 'email', account.local? ? account.local_username_and_domain : account.acct)
append_element(author, 'summary', account.note)
append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: TagManager.instance.url_for(account))
append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original)))

View File

@ -66,7 +66,7 @@ class FeedManager
timeline_key = key(:home, into_account.id)
oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true)&.first&.last&.to_i || 0
from_account.statuses.select('id').where('id > ?', oldest_home_score).find_in_batches do |statuses|
from_account.statuses.select('id').where('id > ?', oldest_home_score).reorder(nil).find_in_batches do |statuses|
redis.pipelined do
statuses.each do |status|
redis.zrem(timeline_key, status.id)

View File

@ -15,7 +15,6 @@ class Formatter
html = status.text
html = encode(html)
html = simple_format(html, {}, sanitize: false)
html = html.gsub(/\n/, '')
html = link_urls(html)
html = link_mentions(html, status.mentions)
html = link_hashtags(html)

View File

@ -12,12 +12,12 @@ class Account < ApplicationRecord
validates :username, presence: true, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?'
# Avatar upload
has_attached_file :avatar, styles: { original: '120x120#' }, convert_options: { all: '-quality 80 -strip' }
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '-quality 80 -strip' }
validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES
validates_attachment_size :avatar, less_than: 2.megabytes
# Header upload
has_attached_file :header, styles: { original: '700x335#' }, convert_options: { all: '-quality 80 -strip' }
has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '-quality 80 -strip' }
validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES
validates_attachment_size :header, less_than: 2.megabytes
@ -120,6 +120,14 @@ class Account < ApplicationRecord
local? ? username : "#{username}@#{domain}"
end
def local_username_and_domain
"#{username}@#{Rails.configuration.x.local_domain}"
end
def to_webfinger_s
"acct:#{local_username_and_domain}"
end
def subscribed?
!subscription_expires_at.blank?
end
@ -150,6 +158,22 @@ class Account < ApplicationRecord
save!
end
def avatar_original_url
avatar.url(:original)
end
def avatar_static_url
avatar_content_type == 'image/gif' ? avatar.url(:static) : avatar_original_url
end
def header_original_url
header.url(:original)
end
def header_static_url
header_content_type == 'image/gif' ? header.url(:static) : header_original_url
end
def avatar_remote_url=(url)
parsed_url = URI.parse(url)
@ -284,6 +308,18 @@ class Account < ApplicationRecord
def follow_mapping(query, field)
query.pluck(field).inject({}) { |mapping, id| mapping[id] = true; mapping }
end
def avatar_styles(file)
styles = { original: '120x120#' }
styles[:static] = { format: 'png' } if file.content_type == 'image/gif'
styles
end
def header_styles(file)
styles = { original: '700x335#' }
styles[:static] = { format: 'png' } if file.content_type == 'image/gif'
styles
end
end
before_create do

View File

@ -16,10 +16,17 @@ class Notification < ApplicationRecord
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
TYPE_CLASS_MAP = {
mention: 'Mention',
reblog: 'Status',
follow: 'Follow',
follow_request: 'FollowRequest',
favourite: 'Favourite',
}.freeze
STATUS_INCLUDES = [:account, :stream_entry, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :media_attachments, :tags, mentions: :account]].freeze
scope :cache_ids, -> { select(:id, :updated_at, :activity_type, :activity_id) }
scope :browserable, -> { where.not(activity_type: ['FollowRequest']) }
cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account
@ -28,12 +35,7 @@ class Notification < ApplicationRecord
end
def type
case activity_type
when 'Status'
:reblog
else
activity_type.underscore.to_sym
end
@type ||= TYPE_CLASS_MAP.invert[activity_type].to_sym
end
def target_status
@ -50,6 +52,11 @@ class Notification < ApplicationRecord
end
class << self
def browserable(types = [])
types.concat([:follow_request])
where.not(activity_type: activity_types_from_types(types))
end
def reload_stale_associations!(cached_items)
account_ids = cached_items.map(&:from_account_id).uniq
accounts = Account.where(id: account_ids).map { |a| [a.id, a] }.to_h
@ -58,6 +65,12 @@ class Notification < ApplicationRecord
item.from_account = accounts[item.from_account_id]
end
end
private
def activity_types_from_types(types)
types.map { |type| TYPE_CLASS_MAP[type.to_sym] }.compact
end
end
after_initialize :set_from_account

View File

@ -9,4 +9,4 @@
- else
= render partial: 'grid_card', collection: @followers, as: :account, cached: true
= will_paginate @followers, pagination_options
= paginate @followers

View File

@ -9,4 +9,4 @@
- else
= render partial: 'grid_card', collection: @following, as: :account, cached: true
= will_paginate @following, pagination_options
= paginate @following

View File

@ -31,4 +31,4 @@
.pagination
- if @statuses.size == 20
= link_to safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), short_account_url(@account, max_id: @statuses.last.id), class: 'next_page', rel: 'next'
= link_to safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), short_account_url(@account, max_id: @statuses.last.id), class: 'next', rel: 'next'

View File

@ -46,4 +46,4 @@
= table_link_to 'globe', 'Public', TagManager.instance.url_for(account)
= table_link_to 'pencil', 'Edit', admin_account_path(account.id)
= will_paginate @accounts, pagination_options
= paginate @accounts

View File

@ -13,5 +13,5 @@
%samp= block.domain
%td= block.severity
= will_paginate @blocks, pagination_options
= paginate @blocks
= link_to 'Add new', new_admin_domain_block_path, class: 'button'

View File

@ -26,4 +26,4 @@
- else
= l subscription.last_successful_delivery_at
= will_paginate @subscriptions, pagination_options
= paginate @subscriptions

View File

@ -29,4 +29,4 @@
%td= truncate(report.comment, length: 30, separator: ' ')
%td= table_link_to 'circle', 'View', admin_report_path(report)
= will_paginate @reports, pagination_options
= paginate @reports

View File

@ -4,8 +4,9 @@ attributes :id, :username, :acct, :display_name, :locked, :created_at
node(:note) { |account| Formatter.instance.simplified_format(account) }
node(:url) { |account| TagManager.instance.url_for(account) }
node(:avatar) { |account| full_asset_url(account.avatar.url(:original)) }
node(:header) { |account| full_asset_url(account.header.url(:original)) }
node(:followers_count) { |account| defined?(@followers_counts_map) ? (@followers_counts_map[account.id] || 0) : account.followers_count }
node(:following_count) { |account| defined?(@following_counts_map) ? (@following_counts_map[account.id] || 0) : account.following_count }
node(:statuses_count) { |account| defined?(@statuses_counts_map) ? (@statuses_counts_map[account.id] || 0) : account.statuses_count }
node(:avatar) { |account| full_asset_url(account.avatar_original_url) }
node(:avatar_static) { |account| full_asset_url(account.avatar_static_url) }
node(:header) { |account| full_asset_url(account.header_original_url) }
node(:header_static) { |account| full_asset_url(account.header_static_url) }
attributes :followers_count, :following_count, :statuses_count

View File

@ -0,0 +1,9 @@
-# Link to the "Next" page
-# available local variables
-# url: url to the next page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.next
= link_to_unless current_page.last?, safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), url, rel: 'next', remote: remote

View File

@ -0,0 +1,16 @@
-# The container tag
-# available local variables
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-# paginator: the paginator that renders the pagination tags inside
= paginator.render do
%nav.pagination
= prev_page_tag unless current_page.first?
- each_page do |page|
- if page.display_tag?
= page_tag page
- elsif !page.was_truncated?
= gap_tag
= next_page_tag unless current_page.last?

View File

@ -0,0 +1,9 @@
-# Link to the "Previous" page
-# available local variables
-# url: url to the previous page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.prev
= link_to_unless current_page.first?, safe_join([fa_icon('chevron-left'), t('pagination.prev')], ' '), url, rel: 'prev', remote: remote

View File

@ -1,2 +1,5 @@
.landing-strip
= t('landing_strip_html', name: display_name(account), domain: Rails.configuration.x.local_domain, sign_up_path: new_user_registration_path)
= t('landing_strip_html',
name: content_tag(:span, display_name(account), class: :emojify),
domain: Rails.configuration.x.local_domain,
sign_up_path: new_user_registration_path)

View File

@ -13,7 +13,7 @@
= fa_icon('retweet fw')
%span
= link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do
%strong= display_name(status.account)
%strong.emojify= display_name(status.account)
= t('stream_entries.reblogged')
= render partial: centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status', locals: { status: status.proper }

View File

@ -15,4 +15,4 @@
- if @statuses.size == 20
.pagination
= link_to safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), tag_url(@tag, max_id: @statuses.last.id), class: 'next_page', rel: 'next'
= link_to safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), tag_url(@tag, max_id: @statuses.last.id), class: 'next', rel: 'next'

View File

@ -99,7 +99,9 @@ Rails.application.configure do
:user_name => ENV['SMTP_LOGIN'],
:password => ENV['SMTP_PASSWORD'],
:domain => ENV['SMTP_DOMAIN'] || config.x.local_domain,
:authentication => :plain,
:authentication => ENV['SMTP_AUTH_METHOD'] || :plain,
:openssl_verify_mode => ENV['SMTP_OPENSSL_VERIFY_MODE'] || 'peer',
:enable_starttls_auto => ENV['SMTP_ENABLE_STARTTLS_AUTO'] || true,
}
config.action_mailer.delivery_method = :smtp

View File

@ -33,7 +33,7 @@ search:
ignore_unused:
- 'activerecord.attributes.*'
- '{devise,will_paginate,doorkeeper}.*'
- '{devise,pagination,doorkeeper}.*'
- '{datetime,time}.*'
- 'simple_form.{yes,no}'
- 'simple_form.{placeholders,hints,labels}.*'

View File

@ -74,7 +74,8 @@ Devise.setup do |config|
# It will change confirmation, password recovery and other workflows
# to behave the same regardless if the e-mail provided was right or wrong.
# Does not affect registerable.
# config.paranoid = true
# See : https://github.com/plataformatec/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable
config.paranoid = true
# By default Devise will store the user in session. You can skip storage for
# particular strategies by setting this option.

View File

@ -1,3 +1,5 @@
HttpLog.options[:logger] = Rails.logger
HttpLog.options[:color] = { color: :yellow }
HttpLog.options[:compact_log] = true
HttpLog.configure do |config|
config.logger = Rails.logger
config.color = { color: :yellow }
config.compact_log = true
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
Kaminari.configure do |config|
config.default_per_page = 40
config.window = 1
config.left = 3
config.right = 1
end

View File

View File

@ -88,5 +88,3 @@ de:
default: "%d.%m.%Y %H:%M"
users:
invalid_email: Inkorrekte E-mail-Addresse
will_paginate:
page_gap: "&hellip;"

View File

@ -126,6 +126,7 @@ en:
pagination:
next: Next
prev: Prev
truncate: "&hellip;"
remote_follow:
acct: Enter your username@domain you want to follow from
missing_resource: Could not find the required redirect URL for your account
@ -169,5 +170,3 @@ en:
users:
invalid_email: The e-mail address is invalid
invalid_otp_token: Invalid two-factor code
will_paginate:
page_gap: "&hellip;"

View File

@ -160,5 +160,3 @@ eo:
users:
invalid_email: La retpoŝt-adreso ne estas valida
invalid_otp_token: La dufaktora aŭtentigila kodo ne estas valida
will_paginate:
page_gap: "&hellip;"

View File

@ -51,5 +51,3 @@ es:
settings:
edit_profile: Editar perfil
preferences: Preferencias
will_paginate:
page_gap: "&hellip;"

View File

@ -160,5 +160,3 @@ fi:
users:
invalid_email: Virheellinen sähköposti
invalid_otp_token: Virheellinen kaksivaihe tunnistus koodi
will_paginate:
page_gap: "&hellip;"

View File

@ -167,5 +167,3 @@ fr:
users:
invalid_email: L'adresse courriel est invalide
invalid_otp_token: Le code d'authentification à deux facteurs est invalide
will_paginate:
page_gap: "&hellip;"

View File

@ -51,5 +51,3 @@ hu:
settings:
edit_profile: Profil szerkesztése
preferences: Beállítások
will_paginate:
page_gap: "&hellip;"

View File

@ -160,5 +160,3 @@
users:
invalid_email: E-post addressen er ugyldig
invalid_otp_token: Ugyldig two-faktor kode
will_paginate:
page_gap: "&hellip;"

View File

@ -51,5 +51,3 @@ pt:
settings:
edit_profile: Editar perfil
preferences: Preferências
will_paginate:
page_gap: "&hellip;"

View File

@ -161,5 +161,3 @@ ru:
users:
invalid_email: Введенный e-mail неверен
invalid_otp_token: Введен неверный код
will_paginate:
page_gap: "&hellip;"

View File

@ -51,5 +51,3 @@ uk:
settings:
edit_profile: Редагувати профіль
preferences: Налаштування
will_paginate:
page_gap: "&hellip;"

View File

@ -150,5 +150,3 @@ zh-CN:
users:
invalid_email: 无效的邮箱
invalid_otp_token: 无效的两步验证码
will_paginate:
page_gap: "&hellip;"

View File

@ -1,11 +1,20 @@
version: '2'
services:
db:
restart: always
image: postgres:alpine
### Uncomment to enable DB persistance
# volumes:
# - ./postgres:/var/lib/postgresql/data
redis:
restart: always
image: redis:alpine
### Uncomment to enable REDIS persistance
# volumes:
# - ./redis:/data
web:
restart: always
build: .
@ -19,6 +28,7 @@ services:
volumes:
- ./public/assets:/mastodon/public/assets
- ./public/system:/mastodon/public/system
streaming:
restart: always
build: .
@ -29,6 +39,7 @@ services:
depends_on:
- db
- redis
sidekiq:
restart: always
build: .

View File

@ -34,10 +34,19 @@ server {
keepalive_timeout 70;
sendfile on;
client_max_body_size 0;
gzip off;
root /home/mastodon/live/public;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
location / {
@ -49,7 +58,7 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://localhost:3000;
@ -67,6 +76,7 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass http://localhost:4000;
proxy_buffering off;
@ -121,7 +131,7 @@ It is recommended to use rbenv (exclusively from the `mastodon` user) to install
[2]: https://github.com/rbenv/ruby-build#installation
[3]: https://github.com/rbenv/ruby-build/wiki#suggested-build-environment
Then once `rbenv` is ready, run `rbenv install 2.3.1` to install the Ruby version for Mastodon.
Then once `rbenv` is ready, run `rbenv install 2.4.1` to install the Ruby version for Mastodon.
## Git

View File

@ -14,5 +14,6 @@ Some people have started working on apps for the Mastodon API. Here is a list of
|Tooter|Chrome|<https://github.com/ineffyble/tooter>|[@effy@mastodon.social](https://mastodon.social/users/effy)|
|tootstream|CLI|<https://github.com/magicalraccoon/tootstream>|[@Raccoon@mastodon.social](https://mastodon.social/users/Raccoon)|
|HackerNewsBot|CLI|<https://github.com/raymestalez/mastodon-hnbot>|[@rayalez@hackertribe.io](https://hackertribe.io/users/rayalez)|
|Mastodon.tools|Wordpress, web browser, social network|<https://github.com/davidlibeau/mastodon-tools>|[@David@mastodon.xyz](https://mastodon.xyz/users/David)|
If you have a project like this, let me know so I can add it to the list!

View File

@ -76,7 +76,7 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| [mastodon.fun](https://mastodon.fun/)|Mastodon for everyone ! |Yes|Yes|
| [oulipo.social](https://oulipo.social/)|An Oulipo Mastodon in which that fifth symbol in Latin script is taboo|Yes|No|
| [indigo.zone](https://indigo.zone)|Open Registrations, General Purpose|Yes|No|
| [mastodon.cloud](https://mastodon.cloud)|An open Mastodon instance with people from all around the world|Yes|Yes|
| [mst3k.interlinked.me](https://mst3k.interlinked.me)|Open registrations, general purpose|Yes|Yes|
We are no longer maintaining this list as instances are popping up too quickly for using GitHub to be a tenable system for tracking them. Please standby while we work on another solution

View File

@ -362,15 +362,15 @@ Returns an empty object.
#### Reblogging/unreblogging a status:
POST /api/vi/statuses/:id/reblog
POST /api/vi/statuses/:id/unreblog
POST /api/v1/statuses/:id/reblog
POST /api/v1/statuses/:id/unreblog
Returns the target [Status](#status).
#### Favouriting/unfavouriting a status:
POST /api/vi/statuses/:id/favourite
POST /api/vi/statuses/:id/unfavourite
POST /api/v1/statuses/:id/favourite
POST /api/v1/statuses/:id/unfavourite
Returns the target [Status](#status).

View File

@ -13,10 +13,13 @@ namespace :mastodon do
desc 'Manually confirms a user with associated user email address stored in USER_EMAIL environment variable.'
task confirm_email: :environment do
email = ENV.fetch('USER_EMAIL')
user = User.where(email: email)
user.update(confirmed_at: Time.now.utc)
puts "User #{email} confirmed."
user = User.where(email: email).first
if user
user.update(confirmed_at: Time.now.utc)
puts "User #{email} confirmed."
else
abort "User #{email} not found."
end
end
namespace :media do
@ -89,5 +92,17 @@ namespace :mastodon do
Rails.logger.debug 'Done!'
end
desc 'Generate static versions of GIF avatars/headers'
task add_static_avatars: :environment do
Rails.logger.debug 'Generating static avatars/headers for GIF ones...'
Account.unscoped.where(avatar_content_type: 'image/gif').or(Account.unscoped.where(header_content_type: 'image/gif')).find_each do |account|
account.avatar.reprocess!
account.header.reprocess!
end
Rails.logger.debug 'Done!'
end
end
end

View File

@ -72,5 +72,10 @@
"webpack": "^2.2.1",
"websocket.js": "^0.1.7",
"ws": "^2.1.0"
},
"devDependencies": {
"babel-eslint": "^7.2.1",
"eslint": "^3.19.0",
"eslint-plugin-react": "^6.10.3"
}
}

View File

@ -71,6 +71,18 @@
"description": "Address to send emails from",
"required": false
},
"SMTP_AUTH_METHOD": {
"description": "Authentication method to use with SMTP server. Default is 'plain'.",
"required": false
},
"SMTP_OPENSSL_VERIFY_MODE": {
"description": "SMTP server certificate verification mode. Defaults is 'peer'.",
"required": false
},
"SMTP_ENABLE_STARTTLS_AUTO": {
"description": "Enable STARTTLS if SMTP server supports it? Default is true.",
"required": false
},
"BUILDPACK_URL": {
"description": "Internal scalingo configuration",
"required": true,

View File

@ -0,0 +1,14 @@
require 'rails_helper'
RSpec.describe Admin::ReportsController, type: :controller do
describe 'GET #index' do
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
it 'returns http success' do
get :index
expect(response).to have_http_status(:success)
end
end
end

View File

@ -0,0 +1,14 @@
require 'rails_helper'
RSpec.describe Admin::SettingsController, type: :controller do
describe 'GET #index' do
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
it 'returns http success' do
get :index
expect(response).to have_http_status(:success)
end
end
end

View File

@ -5,15 +5,71 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { double acceptable?: true, resource_owner_id: user.id }
let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index
expect(response).to have_http_status(:success)
before do
status = PostStatusService.new.call(user.account, 'Test')
@reblog = ReblogService.new.call(other.account, status)
@mention = PostStatusService.new.call(other.account, 'Hello @alice')
@favourite = FavouriteService.new.call(other.account, status)
@follow = FollowService.new.call(other.account, 'alice')
end
describe 'with no options' do
before do
get :index
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'includes reblog' do
expect(assigns(:notifications).map(&:activity_id)).to include(@reblog.id)
end
it 'includes mention' do
expect(assigns(:notifications).map(&:activity_id)).to include(@mention.mentions.first.id)
end
it 'includes favourite' do
expect(assigns(:notifications).map(&:activity_id)).to include(@favourite.id)
end
it 'includes follow' do
expect(assigns(:notifications).map(&:activity_id)).to include(@follow.id)
end
end
describe 'with excluded mentions' do
before do
get :index, params: { exclude_types: ['mention'] }
end
it 'returns http success' do
expect(response).to have_http_status(:success)
end
it 'includes reblog' do
expect(assigns(:notifications).map(&:activity_id)).to include(@reblog.id)
end
it 'excludes mention' do
expect(assigns(:notifications).map(&:activity_id)).to_not include(@mention.mentions.first.id)
end
it 'includes favourite' do
expect(assigns(:notifications).map(&:activity_id)).to include(@favourite.id)
end
it 'includes follow' do
expect(assigns(:notifications).map(&:activity_id)).to include(@follow.id)
end
end
end
end

View File

@ -14,7 +14,7 @@ RSpec.describe XrdController, type: :controller do
let(:alice) { Fabricate(:account, username: 'alice') }
it 'returns http success when account can be found' do
get :webfinger, params: { resource: "acct:#{alice.username}@#{Rails.configuration.x.local_domain}" }
get :webfinger, params: { resource: alice.to_webfinger_s }
expect(response).to have_http_status(:success)
end

BIN
spec/fixtures/files/avatar.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -1,5 +0,0 @@
require 'rails_helper'
RSpec.describe AccountsHelper, type: :helper do
end

View File

@ -6,16 +6,10 @@ import Avatar from '../../../app/assets/javascripts/components/components/avatar
describe('<Avatar />', () => {
const src = '/path/to/image.jpg';
const size = 100;
const wrapper = render(<Avatar src={src} size={size} />);
const wrapper = render(<Avatar src={src} animate size={size} />);
it('renders an img element with the given src', () => {
expect(wrapper.find('img')).to.have.attr('src', `${src}`);
});
it('renders an img element of the given size', () => {
['width', 'height'].map((attr) => {
expect(wrapper.find('img')).to.have.attr(attr, `${size}`);
});
it('renders a div element with the given src as background', () => {
expect(wrapper.find('div')).to.have.style('background-image', `url(${src})`);
});
it('renders a div element of the given size', () => {

View File

@ -54,6 +54,30 @@ RSpec.describe Account, type: :model do
end
end
describe 'Local domain user methods' do
around do |example|
before = Rails.configuration.x.local_domain
example.run
Rails.configuration.x.local_domain = before
end
describe '#to_webfinger_s' do
it 'returns a webfinger string for the account' do
Rails.configuration.x.local_domain = 'example.com'
expect(subject.to_webfinger_s).to eq 'acct:alice@example.com'
end
end
describe '#local_username_and_domain' do
it 'returns the username and local domain for the account' do
Rails.configuration.x.local_domain = 'example.com'
expect(subject.local_username_and_domain).to eq 'alice@example.com'
end
end
end
describe '#acct' do
it 'returns username for local users' do
expect(subject.acct).to eql 'alice'
@ -397,4 +421,24 @@ RSpec.describe Account, type: :model do
end
end
end
describe 'static avatars' do
describe 'when GIF' do
it 'creates a png static style' do
subject.avatar = attachment_fixture('avatar.gif')
subject.save
expect(subject.avatar_static_url).to_not eq subject.avatar_original_url
end
end
describe 'when non-GIF' do
it 'does not create extra static style' do
subject.avatar = attachment_fixture('attachment.jpg')
subject.save
expect(subject.avatar_static_url).to eq subject.avatar_original_url
end
end
end
end

View File

@ -87,21 +87,24 @@ const setRequestId = (req, res, next) => {
const accountFromToken = (token, req, next) => {
pgPool.connect((err, client, done) => {
if (err) {
return next(err)
next(err)
return
}
client.query('SELECT oauth_access_tokens.resource_owner_id, users.account_id FROM oauth_access_tokens INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id WHERE oauth_access_tokens.token = $1 LIMIT 1', [token], (err, result) => {
done()
if (err) {
return next(err)
next(err)
return
}
if (result.rows.length === 0) {
err = new Error('Invalid access token')
err.statusCode = 401
return next(err)
next(err)
return
}
req.accountId = result.rows[0].account_id
@ -113,7 +116,8 @@ const accountFromToken = (token, req, next) => {
const authenticationMiddleware = (req, res, next) => {
if (req.method === 'OPTIONS') {
return next()
next()
return
}
const authorization = req.get('Authorization')
@ -122,7 +126,8 @@ const authenticationMiddleware = (req, res, next) => {
const err = new Error('Missing access token')
err.statusCode = 401
return next(err)
next(err)
return
}
const token = authorization.replace(/^Bearer /, '')

486
yarn.lock
View File

@ -140,6 +140,12 @@ acorn-globals@^3.1.0:
dependencies:
acorn "^4.0.4"
acorn-jsx@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
dependencies:
acorn "^3.0.4"
acorn@^1.0.3:
version "1.2.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014"
@ -148,7 +154,7 @@ acorn@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7"
acorn@^3.0.0:
acorn@^3.0.0, acorn@^3.0.4:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
@ -156,6 +162,10 @@ acorn@^4.0.3, acorn@^4.0.4:
version "4.0.11"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
acorn@^5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
airbnb-js-shims@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.0.1.tgz#7d5a7d772c8c6fdeb624ea3cef62506091b180b5"
@ -169,7 +179,7 @@ airbnb-js-shims@^1.0.1:
string.prototype.padend "^3.0.0"
string.prototype.padstart "^3.0.0"
ajv-keywords@^1.1.1:
ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@ -196,6 +206,10 @@ amdefine@>=0.0.4:
version "1.0.0"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.0.tgz#fd17474700cb5cc9c2b709f0be9d23ce3c198c33"
ansi-escapes@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
ansi-html@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
@ -284,10 +298,27 @@ array-reduce@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
dependencies:
array-uniq "^1.0.1"
array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
array.prototype.find@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90"
dependencies:
define-properties "^1.1.2"
es-abstract "^1.7.0"
arrify@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@ -424,7 +455,7 @@ babel-code-frame@^6.11.0:
esutils "^2.0.2"
js-tokens "^2.0.0"
babel-code-frame@^6.22.0:
babel-code-frame@^6.16.0, babel-code-frame@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
dependencies:
@ -480,6 +511,15 @@ babel-core@^6.11.4:
slash "^1.0.0"
source-map "^0.5.0"
babel-eslint@^7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.1.tgz#079422eb73ba811e3ca0865ce87af29327f8c52f"
dependencies:
babel-code-frame "^6.22.0"
babel-traverse "^6.23.1"
babel-types "^6.23.0"
babylon "^6.16.1"
babel-generator@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.22.0.tgz#d642bf4961911a8adc7c692b0c9297f325cda805"
@ -1302,6 +1342,10 @@ babylon@^6.15.0:
version "6.15.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e"
babylon@^6.16.1:
version "6.16.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
babylon@~5.8.3:
version "5.8.38"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd"
@ -1586,6 +1630,16 @@ cached-path-relative@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7"
caller-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
dependencies:
callsites "^0.2.0"
callsites@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@ -1639,7 +1693,7 @@ chai@^3.5.0:
deep-eql "^0.1.3"
type-detect "^1.0.0"
chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
@ -1695,6 +1749,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1:
dependencies:
inherits "^2.0.1"
circular-json@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
clap@^1.0.9:
version "1.1.1"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.1.tgz#a8a93e0bfb7581ac199c4f001a5525a724ce696d"
@ -1705,6 +1763,16 @@ classnames@^2.1.2, classnames@^2.2.3, classnames@~2.2:
version "2.2.5"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
cli-cursor@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
dependencies:
restore-cursor "^1.0.1"
cli-width@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@ -1824,7 +1892,7 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
concat-stream@^1.4.7, concat-stream@~1.5.0, concat-stream@~1.5.1:
concat-stream@^1.4.7, concat-stream@^1.5.2, concat-stream@~1.5.0, concat-stream@~1.5.1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
dependencies:
@ -2085,6 +2153,12 @@ currently-unhandled@^0.4.1:
dependencies:
array-find-index "^1.0.1"
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
dependencies:
es5-ext "^0.10.9"
d@^0.1.1, d@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309"
@ -2140,6 +2214,18 @@ defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
del@^2.0.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
dependencies:
globby "^5.0.0"
is-path-cwd "^1.0.0"
is-path-in-cwd "^1.0.0"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
rimraf "^2.2.8"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@ -2197,6 +2283,13 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
doctrine@^1.2.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
dependencies:
esutils "^2.0.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"
@ -2377,6 +2470,15 @@ es-abstract@^1.3.2, es-abstract@^1.4.3, es-abstract@^1.5.0, es-abstract@^1.5.1:
is-callable "^1.1.3"
is-regex "^1.0.3"
es-abstract@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c"
dependencies:
es-to-primitive "^1.1.1"
function-bind "^1.1.0"
is-callable "^1.1.3"
is-regex "^1.0.3"
es-to-primitive@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d"
@ -2385,6 +2487,13 @@ es-to-primitive@^1.1.1:
is-date-object "^1.0.1"
is-symbol "^1.0.1"
es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
version "0.10.15"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6"
dependencies:
es6-iterator "2"
es6-symbol "~3.1"
es5-ext@^0.10.7, es5-ext@~0.10.11, es5-ext@~0.10.2:
version "0.10.12"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047"
@ -2404,10 +2513,39 @@ es6-iterator@2:
es5-ext "^0.10.7"
es6-symbol "3"
es6-iterator@^2.0.1, es6-iterator@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512"
dependencies:
d "1"
es5-ext "^0.10.14"
es6-symbol "^3.1"
es6-map@^0.1.3:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
dependencies:
d "1"
es5-ext "~0.10.14"
es6-iterator "~2.0.1"
es6-set "~0.1.5"
es6-symbol "~3.1.1"
event-emitter "~0.3.5"
es6-promise@^3.2.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
es6-set@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
dependencies:
d "1"
es5-ext "~0.10.14"
es6-iterator "~2.0.1"
es6-symbol "3.1.1"
event-emitter "~0.3.5"
es6-shim@^0.35.1:
version "0.35.1"
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.1.tgz#a23524009005b031ab4a352ac196dfdfd1144ab7"
@ -2419,6 +2557,22 @@ es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1:
d "~0.1.1"
es5-ext "~0.10.11"
es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
dependencies:
d "1"
es5-ext "~0.10.14"
es6-weak-map@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
dependencies:
d "1"
es5-ext "^0.10.14"
es6-iterator "^2.0.1"
es6-symbol "^3.1.1"
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -2438,6 +2592,72 @@ escodegen@^1.6.1:
optionalDependencies:
source-map "~0.2.0"
escope@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
dependencies:
es6-map "^0.1.3"
es6-weak-map "^2.0.1"
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-plugin-react@^6.10.3:
version "6.10.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78"
dependencies:
array.prototype.find "^2.0.1"
doctrine "^1.2.2"
has "^1.0.1"
jsx-ast-utils "^1.3.4"
object.assign "^4.0.4"
eslint@^3.19.0:
version "3.19.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc"
dependencies:
babel-code-frame "^6.16.0"
chalk "^1.1.3"
concat-stream "^1.5.2"
debug "^2.1.1"
doctrine "^2.0.0"
escope "^3.6.0"
espree "^3.4.0"
esquery "^1.0.0"
estraverse "^4.2.0"
esutils "^2.0.2"
file-entry-cache "^2.0.0"
glob "^7.0.3"
globals "^9.14.0"
ignore "^3.2.0"
imurmurhash "^0.1.4"
inquirer "^0.12.0"
is-my-json-valid "^2.10.0"
is-resolvable "^1.0.0"
js-yaml "^3.5.1"
json-stable-stringify "^1.0.0"
levn "^0.3.0"
lodash "^4.0.0"
mkdirp "^0.5.0"
natural-compare "^1.4.0"
optionator "^0.8.2"
path-is-inside "^1.0.1"
pluralize "^1.2.1"
progress "^1.1.8"
require-uncached "^1.0.2"
shelljs "^0.7.5"
strip-bom "^3.0.0"
strip-json-comments "~2.0.1"
table "^3.7.8"
text-table "~0.2.0"
user-home "^2.0.0"
espree@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.1.tgz#28a83ab4aaed71ed8fe0f5efe61b76a05c13c4d2"
dependencies:
acorn "^5.0.1"
acorn-jsx "^3.0.0"
esprima@^2.6.0, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
@ -2446,10 +2666,31 @@ esprima@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
esquery@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa"
dependencies:
estraverse "^4.0.0"
esrecurse@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220"
dependencies:
estraverse "~4.1.0"
object-assign "^4.0.1"
estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
estraverse@~4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2"
esutils@^2.0.0, esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@ -2458,6 +2699,13 @@ etag@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8"
event-emitter@~0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
dependencies:
d "1"
es5-ext "~0.10.14"
events@^1.0.0, events@^1.1.1, events@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
@ -2478,6 +2726,10 @@ exenv@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.0.tgz#3835f127abf075bfe082d0aed4484057c78e3c89"
exit-hook@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
@ -2559,6 +2811,20 @@ fbjs@^0.8.1, fbjs@^0.8.4:
promise "^7.1.1"
ua-parser-js "^0.7.9"
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
dependencies:
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
file-entry-cache@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
dependencies:
flat-cache "^1.2.1"
object-assign "^4.0.1"
file-loader@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42"
@ -2604,6 +2870,15 @@ find-up@^1.0.0:
path-exists "^2.0.0"
pinkie-promise "^2.0.0"
flat-cache@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
dependencies:
circular-json "^0.3.1"
del "^2.0.2"
graceful-fs "^4.1.2"
write "^0.2.1"
flatten@1.0.2, flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
@ -2815,10 +3090,21 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^9.0.0:
globals@^9.0.0, globals@^9.14.0:
version "9.14.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034"
globby@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
dependencies:
array-union "^1.0.1"
arrify "^1.0.0"
glob "^7.0.3"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
globule@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
@ -2986,6 +3272,10 @@ ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
ignore@^3.2.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd"
immutable@^3.7.6, immutable@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2"
@ -3037,6 +3327,24 @@ inline-source-map@~0.6.0:
dependencies:
source-map "~0.5.3"
inquirer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
dependencies:
ansi-escapes "^1.1.0"
ansi-regex "^2.0.0"
chalk "^1.0.0"
cli-cursor "^1.0.1"
cli-width "^2.0.0"
figures "^1.3.5"
lodash "^4.3.0"
readline2 "^1.0.1"
run-async "^0.1.0"
rx-lite "^3.1.2"
string-width "^1.0.1"
strip-ansi "^3.0.0"
through "^2.3.6"
insert-module-globals@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3"
@ -3162,13 +3470,17 @@ is-fullwidth-code-point@^1.0.0:
dependencies:
number-is-nan "^1.0.0"
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
dependencies:
is-extglob "^1.0.0"
is-my-json-valid@^2.12.4:
is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4:
version "2.15.0"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b"
dependencies:
@ -3187,6 +3499,22 @@ is-obj@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
is-path-in-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
dependencies:
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"
dependencies:
path-is-inside "^1.0.1"
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@ -3217,6 +3545,12 @@ is-regexp@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
is-resolvable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
dependencies:
tryit "^1.0.1"
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@ -3298,7 +3632,7 @@ js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
js-yaml@^3.4.3, js-yaml@~3.6.1:
js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@~3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30"
dependencies:
@ -3349,7 +3683,7 @@ json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
json-stable-stringify@^1.0.1:
json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
dependencies:
@ -3397,6 +3731,12 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.3.6"
jsx-ast-utils@^1.3.4:
version "1.4.0"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.0.tgz#5afe38868f56bc8cc7aeaef0100ba8c75bd12591"
dependencies:
object-assign "^4.1.0"
keycode@^2.1.1:
version "2.1.7"
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.7.tgz#7b9255919f6cff562b09a064d222dca70b020f5c"
@ -3435,7 +3775,7 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
levn@~0.3.0:
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
dependencies:
@ -3634,7 +3974,7 @@ lodash.tail@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
lodash@4.x.x, lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.1:
lodash@4.x.x, lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.3.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@ -3865,10 +4205,18 @@ ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
mute-stream@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
nan@^2.3.0, nan@^2.3.2, nan@~2.5.0:
version "2.5.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2"
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@ -4156,6 +4504,10 @@ once@~1.3.0, once@~1.3.3:
dependencies:
wrappy "1"
onetime@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
optimist@~0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
@ -4163,7 +4515,7 @@ optimist@~0.6.0:
minimist "~0.0.1"
wordwrap "~0.0.2"
optionator@^0.8.1:
optionator@^0.8.1, optionator@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
dependencies:
@ -4284,6 +4636,10 @@ path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
path-is-inside@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
path-platform@~0.11.15:
version "0.11.15"
resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2"
@ -4373,6 +4729,10 @@ pkg-dir@^1.0.0:
dependencies:
find-up "^1.0.0"
pluralize@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
podda@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/podda/-/podda-1.2.2.tgz#15b0edbd334ade145813343f5ecf9c10a71cf500"
@ -4718,6 +5078,10 @@ process@^0.11.0, process@~0.11.0:
version "0.11.9"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1"
progress@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
promise@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
@ -5140,6 +5504,14 @@ readdirp@^2.0.0:
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
readline2@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
dependencies:
code-point-at "^1.0.0"
is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5"
recast@^0.11.5:
version "0.11.22"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.22.tgz#dedeb18fb001a2bbc6ac34475fda53dfe3d47dfa"
@ -5341,6 +5713,13 @@ 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-uncached@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
dependencies:
caller-path "^0.1.0"
resolve-from "^1.0.0"
requires-port@1.0.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
@ -5349,17 +5728,28 @@ reselect@^2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-2.5.4.tgz#b7d23fdf00b83fa7ad0279546f8dbbbd765c7047"
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
resolve@1.1.7, resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
dependencies:
exit-hook "^1.0.0"
onetime "^1.0.0"
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
dependencies:
align-text "^0.1.1"
rimraf@2, rimraf@~2.5.0, rimraf@~2.5.1:
rimraf@2, rimraf@^2.2.8, rimraf@~2.5.0, rimraf@~2.5.1:
version "2.5.4"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
dependencies:
@ -5373,6 +5763,16 @@ ripemd160@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e"
run-async@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
dependencies:
once "^1.3.0"
rx-lite@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
samsam@1.1.2, samsam@~1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567"
@ -5523,6 +5923,14 @@ shelljs@^0.7.4:
interpret "^1.0.0"
rechoir "^0.6.2"
shelljs@^0.7.5:
version "0.7.7"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1"
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
signal-exit@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.1.tgz#5a4c884992b63a7acd9badb7894c3ee9cfccad81"
@ -5548,6 +5956,10 @@ slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
slide@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
@ -5692,6 +6104,13 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
string-width@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e"
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^3.0.0"
string.prototype.padend@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
@ -5735,6 +6154,10 @@ strip-bom@^2.0.0:
dependencies:
is-utf8 "^0.2.0"
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
@ -5745,6 +6168,10 @@ strip-json-comments@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
style-loader@0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.1.tgz#468280efbc0473023cd3a6cd56e33b5a1d7fc3a9"
@ -5809,6 +6236,17 @@ syntax-error@^1.1.1:
dependencies:
acorn "^2.7.0"
table@^3.7.8:
version "3.8.3"
resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
dependencies:
ajv "^4.7.0"
ajv-keywords "^1.0.0"
chalk "^1.1.1"
lodash "^4.0.0"
slice-ansi "0.0.4"
string-width "^2.0.0"
tapable@^0.1.8, tapable@~0.1.8:
version "0.1.10"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
@ -5856,6 +6294,10 @@ tar@^2.0.0, tar@~2.2.0, tar@~2.2.1:
fstream "^1.0.2"
inherits "2"
text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
through2@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.1.tgz#384e75314d49f32de12eebb8136b8eb6b5d59da9"
@ -5863,7 +6305,7 @@ through2@^2.0.0:
readable-stream "~2.0.0"
xtend "~4.0.0"
through@2, "through@>=2.2.7 <3":
through@2, "through@>=2.2.7 <3", through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -5909,6 +6351,10 @@ trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
tryit@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
tty-browserify@0.0.0, tty-browserify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@ -6022,6 +6468,12 @@ user-home@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
user-home@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
dependencies:
os-homedir "^1.0.0"
utf-8-validate@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-3.0.1.tgz#5d2b8656b4ddcfded47217b647a98941b63cf213"
@ -6280,6 +6732,12 @@ write-file-atomic@^1.1.2:
imurmurhash "^0.1.4"
slide "^1.1.5"
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
dependencies:
mkdirp "^0.5.1"
ws@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-2.1.0.tgz#b24eaed9609f8632dd51e3f7698619a90fddcc92"