diff --git a/.env.production.sample b/.env.production.sample
index 3e054db844..e022a84059 100644
--- a/.env.production.sample
+++ b/.env.production.sample
@@ -101,11 +101,19 @@ SMTP_FROM_ADDRESS=notifications@example.com
# Swift (optional)
# SWIFT_ENABLED=true
# SWIFT_USERNAME=
+# For Keystone V3, the value for SWIFT_TENANT should be the project name
# SWIFT_TENANT=
# SWIFT_PASSWORD=
+# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
+# issues with token rate-limiting during high load.
# SWIFT_AUTH_URL=
# SWIFT_CONTAINER=
# SWIFT_OBJECT_URL=
+# SWIFT_REGION=
+# Defaults to 'default'
+# SWIFT_DOMAIN_NAME=
+# Defaults to 60 seconds. Set to 0 to disable
+# SWIFT_CACHE_TTL=
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
# S3_CLOUDFRONT_HOST=
diff --git a/.ruby-version b/.ruby-version
index 005119baaa..8e8299dcc0 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.4.1
+2.4.2
diff --git a/.travis.yml b/.travis.yml
index d5b51fcb0c..52ff15c012 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,18 +26,16 @@ addons:
postgresql: 9.4
apt:
sources:
- - ubuntu-toolchain-r-test
- trusty-media
packages:
- ffmpeg
- - g++-6
- libprotobuf-dev
- protobuf-compiler
- libicu-dev
rvm:
- 2.3.4
- - 2.4.1
+ - 2.4.2
services:
- redis-server
diff --git a/Aptfile b/Aptfile
index 48dff1a770..5dac836079 100644
--- a/Aptfile
+++ b/Aptfile
@@ -1,4 +1,5 @@
ffmpeg
+libicu[0-9][0-9]
libicu-dev
libidn11
libidn11-dev
diff --git a/Dockerfile b/Dockerfile
index 15138065b6..3ad2ad7efe 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:2.4.1-alpine3.6
+FROM ruby:2.4.2-alpine3.6
LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="A GNU Social-compatible microblogging server"
diff --git a/Gemfile b/Gemfile
index 637bf53eeb..4f4861913e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,8 +5,8 @@ ruby '>= 2.3.0', '< 2.5.0'
gem 'pkg-config', '~> 1.2'
-gem 'puma', '~> 3.8'
-gem 'rails', '~> 5.1.0'
+gem 'puma', '~> 3.10'
+gem 'rails', '~> 5.1.4'
gem 'uglifier', '~> 3.2'
gem 'hamlit-rails', '~> 0.2'
@@ -25,7 +25,7 @@ gem 'bootsnap'
gem 'browser'
gem 'charlock_holmes', '~> 0.7.5'
gem 'iso-639'
-gem 'cld3', '~> 3.1'
+gem 'cld3', '~> 3.2.0'
gem 'devise', '~> 4.2'
gem 'devise-two-factor', '~> 3.0'
gem 'doorkeeper', '~> 4.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index ddb97dd940..97db3aa9ac 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,25 +1,25 @@
GEM
remote: https://rubygems.org/
specs:
- actioncable (5.1.3)
- actionpack (= 5.1.3)
+ actioncable (5.1.4)
+ actionpack (= 5.1.4)
nio4r (~> 2.0)
websocket-driver (~> 0.6.1)
- actionmailer (5.1.3)
- actionpack (= 5.1.3)
- actionview (= 5.1.3)
- activejob (= 5.1.3)
+ actionmailer (5.1.4)
+ actionpack (= 5.1.4)
+ actionview (= 5.1.4)
+ activejob (= 5.1.4)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (5.1.3)
- actionview (= 5.1.3)
- activesupport (= 5.1.3)
+ actionpack (5.1.4)
+ actionview (= 5.1.4)
+ activesupport (= 5.1.4)
rack (~> 2.0)
- rack-test (~> 0.6.3)
+ rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (5.1.3)
- activesupport (= 5.1.3)
+ actionview (5.1.4)
+ activesupport (= 5.1.4)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
@@ -30,16 +30,16 @@ GEM
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.2)
active_record_query_trace (1.5.4)
- activejob (5.1.3)
- activesupport (= 5.1.3)
+ activejob (5.1.4)
+ activesupport (= 5.1.4)
globalid (>= 0.3.6)
- activemodel (5.1.3)
- activesupport (= 5.1.3)
- activerecord (5.1.3)
- activemodel (= 5.1.3)
- activesupport (= 5.1.3)
+ activemodel (5.1.4)
+ activesupport (= 5.1.4)
+ activerecord (5.1.4)
+ activemodel (= 5.1.4)
+ activesupport (= 5.1.4)
arel (~> 8.0)
- activesupport (5.1.3)
+ activesupport (5.1.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
@@ -57,33 +57,33 @@ GEM
encryptor (~> 3.0.0)
av (0.9.0)
cocaine (~> 0.5.3)
- aws-sdk (2.10.21)
- aws-sdk-resources (= 2.10.21)
- aws-sdk-core (2.10.21)
+ aws-sdk (2.10.46)
+ aws-sdk-resources (= 2.10.46)
+ aws-sdk-core (2.10.46)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
- aws-sdk-resources (2.10.21)
- aws-sdk-core (= 2.10.21)
- aws-sigv4 (1.0.1)
+ aws-sdk-resources (2.10.46)
+ aws-sdk-core (= 2.10.46)
+ aws-sigv4 (1.0.2)
bcrypt (3.1.11)
- better_errors (2.1.1)
+ better_errors (2.3.0)
coderay (>= 1.0.0)
- erubis (>= 2.6.6)
+ erubi (>= 1.0.0)
rack (>= 0.9.0)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
- bootsnap (1.1.2)
+ bootsnap (1.1.3)
msgpack (~> 1.0)
brakeman (3.7.2)
- browser (2.4.0)
+ browser (2.5.1)
builder (3.2.3)
- bullet (5.5.1)
+ bullet (5.6.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
bundler-audit (0.6.0)
bundler (~> 1.2)
thor (~> 0.18)
- capistrano (3.8.2)
+ capistrano (3.9.1)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
@@ -99,9 +99,9 @@ GEM
sshkit (~> 1.3)
capistrano-yarn (2.0.2)
capistrano (~> 3.0)
- capybara (2.14.4)
+ capybara (2.15.1)
addressable
- mime-types (>= 1.16)
+ mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
@@ -110,12 +110,12 @@ GEM
activesupport
charlock_holmes (0.7.5)
chunky_png (1.3.8)
- cld3 (3.1.3)
+ cld3 (3.2.0)
ffi (>= 1.1.0, < 1.10.0)
climate_control (0.2.0)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
- coderay (1.1.1)
+ coderay (1.1.2)
colorize (0.8.1)
concurrent-ruby (1.0.5)
connection_pool (2.2.1)
@@ -151,13 +151,12 @@ GEM
thread_safe
encryptor (3.0.0)
erubi (1.6.1)
- erubis (2.7.0)
et-orbi (1.0.5)
tzinfo
- excon (0.58.0)
+ excon (0.59.0)
execjs (2.7.0)
- fabrication (2.16.2)
- faker (1.7.3)
+ fabrication (2.16.3)
+ faker (1.8.4)
i18n (~> 0.5)
fast_blank (1.0.0)
ffi (1.9.18)
@@ -194,7 +193,7 @@ GEM
railties (>= 4.0.1)
hamster (3.0.0)
concurrent-ruby (~> 1.0)
- hashdiff (0.3.5)
+ hashdiff (0.3.6)
highline (1.7.8)
hiredis (0.6.1)
hkdf (0.3.0)
@@ -213,11 +212,11 @@ GEM
colorize
rack
i18n (0.8.6)
- i18n-tasks (0.9.16)
+ i18n-tasks (0.9.18)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
easy_translate (>= 0.5.0)
- erubis
+ erubi
highline (>= 1.7.3)
i18n
parser (>= 2.2.3.0)
@@ -231,7 +230,7 @@ GEM
json-ld (2.1.5)
multi_json (~> 1.12)
rdf (~> 2.2)
- json-ld-preloaded (2.2.1)
+ json-ld-preloaded (2.2.2)
json-ld (~> 2.1, >= 2.1.5)
multi_json (~> 1.11)
rdf (~> 2.2)
@@ -258,10 +257,11 @@ GEM
letter_opener (~> 1.0)
railties (>= 3.2)
link_header (0.0.8)
- lograge (0.5.1)
+ lograge (0.6.0)
actionpack (>= 4, < 5.2)
activesupport (>= 4, < 5.2)
railties (>= 4, < 5.2)
+ request_store (~> 1.0)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.6)
@@ -276,27 +276,28 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
+ mini_mime (0.1.4)
mini_portile2 (2.2.0)
minitest (5.10.3)
msgpack (1.1.0)
- multi_json (1.12.1)
+ multi_json (1.12.2)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
- net-ssh (4.1.0)
+ net-ssh (4.2.0)
nio4r (2.1.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
nokogumbo (1.4.13)
nokogiri
- oj (3.3.4)
- openssl (2.0.4)
+ oj (3.3.5)
+ openssl (2.0.5)
orm_adapter (0.5.0)
ostatus2 (2.0.1)
addressable (~> 2.4)
http (~> 2.0)
nokogiri (~> 1.6)
openssl (~> 2.0)
- ox (2.5.0)
+ ox (2.6.0)
paperclip (5.1.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
@@ -306,15 +307,15 @@ GEM
paperclip-av-transcoder (0.6.4)
av (~> 0.9.0)
paperclip (>= 2.5.2)
- parallel (1.11.2)
- parallel_tests (2.14.2)
+ parallel (1.12.0)
+ parallel_tests (2.15.0)
parallel
parser (2.4.0.0)
ast (~> 2.2)
pg (0.21.0)
pghero (1.7.0)
activerecord
- pkg-config (1.2.4)
+ pkg-config (1.2.7)
powerpack (0.1.1)
pry (0.10.4)
coderay (~> 1.1.0)
@@ -323,7 +324,7 @@ GEM
pry-rails (0.3.6)
pry (>= 0.10.4)
public_suffix (3.0.0)
- puma (3.9.1)
+ puma (3.10.0)
pundit (1.1.0)
activesupport (>= 3.0.0)
rabl (0.13.1)
@@ -334,20 +335,20 @@ GEM
rack-cors (0.4.1)
rack-protection (2.0.0)
rack
- rack-test (0.6.3)
- rack (>= 1.0)
+ rack-test (0.7.0)
+ rack (>= 1.0, < 3)
rack-timeout (0.4.2)
- rails (5.1.3)
- actioncable (= 5.1.3)
- actionmailer (= 5.1.3)
- actionpack (= 5.1.3)
- actionview (= 5.1.3)
- activejob (= 5.1.3)
- activemodel (= 5.1.3)
- activerecord (= 5.1.3)
- activesupport (= 5.1.3)
+ rails (5.1.4)
+ actioncable (= 5.1.4)
+ actionmailer (= 5.1.4)
+ actionpack (= 5.1.4)
+ actionview (= 5.1.4)
+ activejob (= 5.1.4)
+ activemodel (= 5.1.4)
+ activerecord (= 5.1.4)
+ activesupport (= 5.1.4)
bundler (>= 1.3.0)
- railties (= 5.1.3)
+ railties (= 5.1.4)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
@@ -363,16 +364,16 @@ GEM
railties (~> 5.0)
rails-settings-cached (0.6.6)
rails (>= 4.2.0)
- railties (5.1.3)
- actionpack (= 5.1.3)
- activesupport (= 5.1.3)
+ railties (5.1.4)
+ actionpack (= 5.1.4)
+ activesupport (= 5.1.4)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
- rake (12.0.0)
- rdf (2.2.8)
+ rake (12.1.0)
+ rdf (2.2.9)
hamster (~> 3.0)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.3.2)
@@ -396,6 +397,7 @@ GEM
redis-store (>= 1.2, < 2)
redis-store (1.3.0)
redis (>= 2.2)
+ request_store (1.3.2)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
@@ -410,7 +412,7 @@ GEM
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
- rspec-rails (3.6.0)
+ rspec-rails (3.6.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@@ -422,15 +424,15 @@ GEM
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.6.0)
- rubocop (0.49.1)
+ rubocop (0.50.0)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
- rainbow (>= 1.99.1, < 3.0)
+ rainbow (>= 2.2.2, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-oembed (0.12.0)
- ruby-progressbar (1.8.1)
+ ruby-progressbar (1.8.3)
rufus-scheduler (3.4.2)
et-orbi (~> 1.0)
safe_yaml (1.0.4)
@@ -438,7 +440,7 @@ GEM
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4.1)
- sass (3.4.24)
+ sass (3.4.25)
scss_lint (0.54.0)
rake (>= 0.9, < 13)
sass (~> 3.4.20)
@@ -450,12 +452,12 @@ GEM
sidekiq-bulk (0.1.1)
activesupport
sidekiq
- sidekiq-scheduler (2.1.8)
+ sidekiq-scheduler (2.1.9)
redis (~> 3)
rufus-scheduler (~> 3.2)
sidekiq (>= 3)
tilt (>= 1.4.0)
- sidekiq-unique-jobs (5.0.9)
+ sidekiq-unique-jobs (5.0.10)
sidekiq (>= 4.0, <= 6.0)
thor (~> 0)
simple-navigation (4.0.5)
@@ -463,20 +465,20 @@ GEM
simple_form (3.5.0)
actionpack (> 4, < 5.2)
activemodel (> 4, < 5.2)
- simplecov (0.14.1)
+ simplecov (0.15.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
- simplecov-html (0.10.1)
+ simplecov-html (0.10.2)
slop (3.6.0)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.2.0)
+ sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
- sshkit (1.13.1)
+ sshkit (1.14.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
statsd-instrument (2.1.4)
@@ -541,7 +543,7 @@ DEPENDENCIES
capistrano-yarn (~> 2.0)
capybara (~> 2.14)
charlock_holmes (~> 0.7.5)
- cld3 (~> 3.1)
+ cld3 (~> 3.2.0)
climate_control (~> 0.2)
devise (~> 4.2)
devise-two-factor (~> 3.0)
@@ -582,13 +584,13 @@ DEPENDENCIES
pghero (~> 1.7)
pkg-config (~> 1.2)
pry-rails (~> 0.3)
- puma (~> 3.8)
+ puma (~> 3.10)
pundit (~> 1.1)
rabl (~> 0.13)
rack-attack (~> 5.0)
rack-cors (~> 0.4)
rack-timeout (~> 0.4)
- rails (~> 5.1.0)
+ rails (~> 5.1.4)
rails-controller-testing (~> 1.0)
rails-i18n (~> 5.0)
rails-settings-cached (~> 0.6)
@@ -620,7 +622,7 @@ DEPENDENCIES
webpush
RUBY VERSION
- ruby 2.4.1p111
+ ruby 2.4.2p198
BUNDLED WITH
1.15.4
diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb
new file mode 100644
index 0000000000..572ad1ac2e
--- /dev/null
+++ b/app/controllers/admin/custom_emojis_controller.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Admin
+ class CustomEmojisController < BaseController
+ def index
+ @custom_emojis = CustomEmoji.where(domain: nil)
+ end
+
+ def new
+ @custom_emoji = CustomEmoji.new
+ end
+
+ def create
+ @custom_emoji = CustomEmoji.new(resource_params)
+
+ if @custom_emoji.save
+ redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.created_msg')
+ else
+ render :new
+ end
+ end
+
+ def destroy
+ CustomEmoji.find(params[:id]).destroy
+ redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg')
+ end
+
+ private
+
+ def resource_params
+ params.require(:custom_emoji).permit(:shortcode, :image)
+ end
+ end
+end
diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb
index 3296e08db8..22f02e5d08 100644
--- a/app/controllers/admin/instances_controller.rb
+++ b/app/controllers/admin/instances_controller.rb
@@ -14,8 +14,12 @@ module Admin
private
+ def filtered_instances
+ InstanceFilter.new(filter_params).results
+ end
+
def paginated_instances
- Account.remote.by_domain_accounts.page(params[:page])
+ filtered_instances.page(params[:page])
end
helper_method :paginated_instances
@@ -27,5 +31,11 @@ module Admin
def subscribeable_accounts
Account.with_followers.remote.where(domain: params[:by_domain])
end
+
+ def filter_params
+ params.permit(
+ :domain_name
+ )
+ end
end
end
diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb
index c5e6fe4e50..a2f86b8a9e 100644
--- a/app/controllers/admin/settings_controller.rb
+++ b/app/controllers/admin/settings_controller.rb
@@ -14,6 +14,7 @@ module Admin
open_deletion
timeline_preview
bootstrap_timeline_accounts
+ thumbnail
).freeze
BOOLEAN_SETTINGS = %w(
@@ -22,14 +23,23 @@ module Admin
timeline_preview
).freeze
+ UPLOAD_SETTINGS = %w(
+ thumbnail
+ ).freeze
+
def edit
@admin_settings = Form::AdminSettings.new
end
def update
settings_params.each do |key, value|
- setting = Setting.where(var: key).first_or_initialize(var: key)
- setting.update(value: value_for_update(key, value))
+ if UPLOAD_SETTINGS.include?(key)
+ upload = SiteUpload.where(var: key).first_or_initialize(var: key)
+ upload.update(file: value)
+ else
+ setting = Setting.where(var: key).first_or_initialize(var: key)
+ setting.update(value: value_for_update(key, value))
+ end
end
flash[:notice] = I18n.t('generic.changes_saved_msg')
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index fbfb5473ee..ad7f09f348 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -12,7 +12,30 @@ class HomeController < ApplicationController
private
def authenticate_user!
- redirect_to(single_user_mode? ? account_path(Account.first) : about_path) unless user_signed_in?
+ return if user_signed_in?
+
+ matches = request.path.match(/\A\/web\/(statuses|accounts)\/([\d]+)\z/)
+
+ if matches
+ case matches[1]
+ when 'statuses'
+ status = Status.find_by(id: matches[2])
+
+ if status && (status.public_visibility? || status.unlisted_visibility?)
+ redirect_to(ActivityPub::TagManager.instance.url_for(status))
+ return
+ end
+ when 'accounts'
+ account = Account.find_by(id: matches[2])
+
+ if account
+ redirect_to(ActivityPub::TagManager.instance.url_for(account))
+ return
+ end
+ end
+ end
+
+ redirect_to(default_redirect_path)
end
def set_initial_state_json
@@ -29,4 +52,14 @@ class HomeController < ApplicationController
admin: Account.find_local(Setting.site_contact_username),
}
end
+
+ def default_redirect_path
+ if request.path.start_with?('/web')
+ new_user_session_path
+ elsif single_user_mode?
+ short_account_path(Account.first)
+ else
+ about_path
+ end
+ end
end
diff --git a/app/controllers/media_proxy_controller.rb b/app/controllers/media_proxy_controller.rb
new file mode 100644
index 0000000000..155670837e
--- /dev/null
+++ b/app/controllers/media_proxy_controller.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+class MediaProxyController < ApplicationController
+ include RoutingHelper
+
+ def show
+ RedisLock.acquire(lock_options) do |lock|
+ if lock.acquired?
+ @media_attachment = MediaAttachment.remote.find(params[:id])
+ redownload! if @media_attachment.needs_redownload? && !reject_media?
+ end
+ end
+
+ redirect_to full_asset_url(@media_attachment.file.url(version))
+ end
+
+ private
+
+ def redownload!
+ @media_attachment.file_remote_url = @media_attachment.remote_url
+ @media_attachment.created_at = Time.now.utc
+ @media_attachment.save!
+ end
+
+ def version
+ if request.path.ends_with?('/small')
+ :small
+ else
+ :original
+ end
+ end
+
+ def lock_options
+ { redis: Redis.current, key: "media_download:#{params[:id]}" }
+ end
+
+ def reject_media?
+ DomainBlock.find_by(domain: @media_attachment.account.domain)&.reject_media?
+ end
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 61d4442c12..6d625e7db9 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -42,4 +42,8 @@ module ApplicationHelper
content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end
+
+ def opengraph(property, content)
+ tag(:meta, content: content, property: property)
+ end
end
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index 369a456809..14776b3540 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -41,7 +41,7 @@ module SettingsHelper
end
def filterable_languages
- I18n.available_locales.map { |locale| locale.to_s.split('-').first.to_sym }.uniq
+ LanguageDetector.instance.language_names.select(&HUMAN_LOCALES.method(:key?))
end
def hash_to_object(hash)
diff --git a/app/javascript/images/logo.svg b/app/javascript/images/logo.svg
index 4b72b3ac8b..034a9c2217 100644
--- a/app/javascript/images/logo.svg
+++ b/app/javascript/images/logo.svg
@@ -1 +1 @@
-
+
diff --git a/app/javascript/images/logo_alt.svg b/app/javascript/images/logo_alt.svg
index e88ca74185..102d4c787e 100644
--- a/app/javascript/images/logo_alt.svg
+++ b/app/javascript/images/logo_alt.svg
@@ -1 +1 @@
-
+
diff --git a/app/javascript/images/logo_full.svg b/app/javascript/images/logo_full.svg
index 8b1328e8c8..c33883342d 100644
--- a/app/javascript/images/logo_full.svg
+++ b/app/javascript/images/logo_full.svg
@@ -1 +1 @@
-
+
diff --git a/app/javascript/images/mastodon_small.jpg b/app/javascript/images/mastodon_small.jpg
deleted file mode 100644
index 9c88ce3f7b..0000000000
Binary files a/app/javascript/images/mastodon_small.jpg and /dev/null differ
diff --git a/app/javascript/images/preview.jpg b/app/javascript/images/preview.jpg
new file mode 100644
index 0000000000..ec28567484
Binary files /dev/null and b/app/javascript/images/preview.jpg differ
diff --git a/app/javascript/mastodon/actions/height_cache.js b/app/javascript/mastodon/actions/height_cache.js
new file mode 100644
index 0000000000..4c752993fe
--- /dev/null
+++ b/app/javascript/mastodon/actions/height_cache.js
@@ -0,0 +1,17 @@
+export const HEIGHT_CACHE_SET = 'HEIGHT_CACHE_SET';
+export const HEIGHT_CACHE_CLEAR = 'HEIGHT_CACHE_CLEAR';
+
+export function setHeight (key, id, height) {
+ return {
+ type: HEIGHT_CACHE_SET,
+ key,
+ id,
+ height,
+ };
+};
+
+export function clearHeight () {
+ return {
+ type: HEIGHT_CACHE_CLEAR,
+ };
+};
diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js
index 0b5e72c171..2204e0b14a 100644
--- a/app/javascript/mastodon/actions/statuses.js
+++ b/app/javascript/mastodon/actions/statuses.js
@@ -23,9 +23,6 @@ export const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST';
export const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS';
export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL';
-export const STATUS_SET_HEIGHT = 'STATUS_SET_HEIGHT';
-export const STATUSES_CLEAR_HEIGHT = 'STATUSES_CLEAR_HEIGHT';
-
export function fetchStatusRequest(id, skipLoading) {
return {
type: STATUS_FETCH_REQUEST,
@@ -218,17 +215,3 @@ export function unmuteStatusFail(id, error) {
error,
};
};
-
-export function setStatusHeight (id, height) {
- return {
- type: STATUS_SET_HEIGHT,
- id,
- height,
- };
-};
-
-export function clearStatusesHeight () {
- return {
- type: STATUSES_CLEAR_HEIGHT,
- };
-};
diff --git a/app/javascript/mastodon/components/intersection_observer_article.js b/app/javascript/mastodon/components/intersection_observer_article.js
index 3477678188..bb83a4da09 100644
--- a/app/javascript/mastodon/components/intersection_observer_article.js
+++ b/app/javascript/mastodon/components/intersection_observer_article.js
@@ -7,10 +7,13 @@ import getRectFromEntry from '../features/ui/util/get_rect_from_entry';
export default class IntersectionObserverArticle extends ImmutablePureComponent {
static propTypes = {
- intersectionObserverWrapper: PropTypes.object,
+ intersectionObserverWrapper: PropTypes.object.isRequired,
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
index: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
listLength: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ saveHeightKey: PropTypes.string,
+ cachedHeight: PropTypes.number,
+ onHeightChange: PropTypes.func,
children: PropTypes.node,
};
@@ -34,13 +37,10 @@ export default class IntersectionObserverArticle extends ImmutablePureComponent
}
componentDidMount () {
- if (!this.props.intersectionObserverWrapper) {
- // TODO: enable IntersectionObserver optimization for notification statuses.
- // These are managed in notifications/index.js rather than status_list.js
- return;
- }
- this.props.intersectionObserverWrapper.observe(
- this.props.id,
+ const { intersectionObserverWrapper, id } = this.props;
+
+ intersectionObserverWrapper.observe(
+ id,
this.node,
this.handleIntersection
);
@@ -49,20 +49,21 @@ export default class IntersectionObserverArticle extends ImmutablePureComponent
}
componentWillUnmount () {
- if (this.props.intersectionObserverWrapper) {
- this.props.intersectionObserverWrapper.unobserve(this.props.id, this.node);
- }
+ const { intersectionObserverWrapper, id } = this.props;
+ intersectionObserverWrapper.unobserve(id, this.node);
this.componentMounted = false;
}
handleIntersection = (entry) => {
+ const { onHeightChange, saveHeightKey, id } = this.props;
+
if (this.node && this.node.children.length !== 0) {
// save the height of the fully-rendered element
this.height = getRectFromEntry(entry).height;
- if (this.props.onHeightChange) {
- this.props.onHeightChange(this.props.status, this.height);
+ if (onHeightChange && saveHeightKey) {
+ onHeightChange(saveHeightKey, id, this.height);
}
}
@@ -94,16 +95,16 @@ export default class IntersectionObserverArticle extends ImmutablePureComponent
}
render () {
- const { children, id, index, listLength } = this.props;
+ const { children, id, index, listLength, cachedHeight } = this.props;
const { isIntersecting, isHidden } = this.state;
- if (!isIntersecting && isHidden) {
+ if (!isIntersecting && (isHidden || cachedHeight)) {
return (
diff --git a/app/javascript/mastodon/components/load_more.js b/app/javascript/mastodon/components/load_more.js
index e2fe1fed7e..c4c8c94a2a 100644
--- a/app/javascript/mastodon/components/load_more.js
+++ b/app/javascript/mastodon/components/load_more.js
@@ -17,7 +17,7 @@ export default class LoadMore extends React.PureComponent {
const { visible } = this.props;
return (
-
' }
+
+ it 'does not touch the shortcodes' do
+ is_expected.to match(/:coolcat::coolcat:<\/p>/)
+ end
+ end
+
+ context 'with emoji at the end' do
+ let(:text) { '
Beep boop
:coolcat:
' }
+
+ it 'converts shortcode to image tag' do
+ is_expected.to match(/
Hello :coolcat:' }
+
+ it 'returns records used via shortcodes in text' do
+ is_expected.to include(emojo)
+ end
+ end
+ end
+end
diff --git a/spec/models/site_upload_spec.rb b/spec/models/site_upload_spec.rb
new file mode 100644
index 0000000000..8745d54b8f
--- /dev/null
+++ b/spec/models/site_upload_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe SiteUpload, type: :model do
+
+end
diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb
index 484effd5e1..12efcae617 100644
--- a/spec/models/status_spec.rb
+++ b/spec/models/status_spec.rb
@@ -173,19 +173,6 @@ RSpec.describe Status, type: :model do
end
end
- describe '.local_only' do
- it 'returns only statuses from local accounts' do
- local_account = Fabricate(:account, domain: nil)
- remote_account = Fabricate(:account, domain: 'test.com')
- local_status = Fabricate(:status, account: local_account)
- remote_status = Fabricate(:status, account: remote_account)
-
- results = described_class.local_only
- expect(results).to include(local_status)
- expect(results).not_to include(remote_status)
- end
- end
-
describe '.as_home_timeline' do
let(:account) { Fabricate(:account) }
let(:followed) { Fabricate(:account) }
@@ -529,6 +516,14 @@ RSpec.describe Status, type: :model do
end
end
+ describe 'validation' do
+ it 'disallow empty uri for remote status' do
+ alice.update(domain: 'example.com')
+ status = Fabricate.build(:status, uri: '', account: alice)
+ expect(status).to model_have_error_on_field(:uri)
+ end
+ end
+
describe 'after_create' do
it 'saves ActivityPub uri as uri for local status' do
status = Status.create(account: alice, text: 'foo')
diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb
index b0aa740ac9..ba61d22c34 100644
--- a/spec/services/fetch_link_card_service_spec.rb
+++ b/spec/services/fetch_link_card_service_spec.rb
@@ -12,6 +12,8 @@ RSpec.describe FetchLinkCardService do
stub_request(:get, 'http://example.com/sjis_with_wrong_charset').to_return(request_fixture('sjis_with_wrong_charset.txt'))
stub_request(:head, 'http://example.com/koi8-r').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt'))
+ stub_request(:head, 'http://example.com/日本語').to_return(status: 200, headers: { 'Content-Type' => 'text/html' })
+ stub_request(:get, 'http://example.com/日本語').to_return(request_fixture('sjis.txt'))
stub_request(:head, 'https://github.com/qbi/WannaCry').to_return(status: 404)
subject.call(status)
@@ -52,6 +54,15 @@ RSpec.describe FetchLinkCardService do
expect(status.preview_cards.first.title).to eq("Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.")
end
end
+
+ context do
+ let(:status) { Fabricate(:status, text: 'テストhttp://example.com/日本語') }
+
+ it 'works with Japanese path string' do
+ expect(a_request(:get, 'http://example.com/日本語')).to have_been_made.at_least_once
+ expect(status.preview_cards.first.title).to eq("SJISのページ")
+ end
+ end
end
context 'in a remote status' do
diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb
index 4182c4e1fa..91902ff69d 100644
--- a/spec/services/post_status_service_spec.rb
+++ b/spec/services/post_status_service_spec.rb
@@ -65,15 +65,12 @@ RSpec.describe PostStatusService do
end
it 'creates a status with a language set' do
- detector = double(to_iso_s: :en)
- allow(LanguageDetector).to receive(:new).and_return(detector)
-
account = Fabricate(:account)
- text = 'test status text'
+ text = 'This is an English text.'
- subject.call(account, text)
+ status = subject.call(account, text)
- expect(LanguageDetector).to have_received(:new).with(text, account)
+ expect(status.language).to eq 'en'
end
it 'processes mentions' do
diff --git a/spec/services/resolve_remote_account_service_spec.rb b/spec/services/resolve_remote_account_service_spec.rb
index d0eab2310b..d0bb6a1373 100644
--- a/spec/services/resolve_remote_account_service_spec.rb
+++ b/spec/services/resolve_remote_account_service_spec.rb
@@ -72,6 +72,39 @@ RSpec.describe ResolveRemoteAccountService do
end
context 'with an ActivityPub account' do
+ before do
+ stub_request(:get, "https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com").to_return(request_fixture('activitypub-webfinger.txt'))
+ stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor.txt'))
+ stub_request(:get, "https://ap.example.com/users/foo.atom").to_return(request_fixture('activitypub-feed.txt'))
+ stub_request(:get, %r{https://ap.example.com/users/foo/\w+}).to_return(status: 404)
+ end
+
+ it 'fallback to OStatus if actor json could not be fetched' do
+ stub_request(:get, "https://ap.example.com/users/foo").to_return(status: 404)
+
+ account = subject.call('foo@ap.example.com')
+
+ expect(account.ostatus?).to eq true
+ expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
+ end
+
+ it 'fallback to OStatus if actor json did not have inbox_url' do
+ stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor-noinbox.txt'))
+
+ account = subject.call('foo@ap.example.com')
+
+ expect(account.ostatus?).to eq true
+ expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
+ end
+
+ it 'returns new remote account' do
+ account = subject.call('foo@ap.example.com')
+
+ expect(account.activitypub?).to eq true
+ expect(account.domain).to eq 'ap.example.com'
+ expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox'
+ end
+
pending
end
diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb
index 95a8a63234..b2f2658de8 100644
--- a/spec/views/about/show.html.haml_spec.rb
+++ b/spec/views/about/show.html.haml_spec.rb
@@ -17,6 +17,7 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do
version_number: '1.0',
source_url: 'https://github.com/tootsuite/mastodon',
open_registrations: false,
+ thumbnail: nil,
closed_registrations_message: 'yes',
commit_hash: commit_hash)
diff --git a/spec/views/stream_entries/show.html.haml_spec.rb b/spec/views/stream_entries/show.html.haml_spec.rb
index 6cc3b117aa..59ea409907 100644
--- a/spec/views/stream_entries/show.html.haml_spec.rb
+++ b/spec/views/stream_entries/show.html.haml_spec.rb
@@ -80,9 +80,9 @@ describe 'stream_entries/show.html.haml', without_verify_partial_doubles: true d
header_tags = view.content_for(:header_tags)
- expect(header_tags).to match(%r{})
- expect(header_tags).to match(%r{})
- expect(header_tags).to match(%r{})
- expect(header_tags).to match(%r{})
+ expect(header_tags).to match(%r{})
+ expect(header_tags).to match(%r{})
+ expect(header_tags).to match(%r{})
+ expect(header_tags).to match(%r{})
end
end