diff options
90 files changed, 376 insertions, 497 deletions
diff --git a/.ruby-version b/.ruby-version index 8e8299dcc..437459cd9 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.2 +2.5.0 diff --git a/.travis.yml b/.travis.yml index 59d495c43..496315558 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,20 +40,20 @@ addons: - yarn rvm: - - 2.3.4 - 2.4.2 + - 2.5.0 services: - redis-server install: + - gem update --system - nvm install - bundle install --path=vendor/bundle --without development production --retry=3 --jobs=16 - yarn install before_script: - - bundle exec rake parallel:create parallel:load_schema parallel:prepare - - bundle exec rails assets:precompile + - ./bin/rails parallel:create parallel:load_schema parallel:prepare assets:precompile - ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++" script: diff --git a/Dockerfile b/Dockerfile index d455116da..6d8465ddc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.4.2-alpine3.6 +FROM ruby:2.5.0-alpine3.7 LABEL maintainer="https://github.com/tootsuite/mastodon" \ description="A GNU Social-compatible microblogging server" @@ -40,6 +40,7 @@ RUN apk -U upgrade \ protobuf \ su-exec \ tini \ + tzdata \ && update-ca-certificates \ && mkdir -p /tmp/src /opt \ && wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \ diff --git a/Gemfile b/Gemfile index 268bf3ad8..dc72851b3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ # frozen_string_literal: true source 'https://rubygems.org' -ruby '>= 2.3.0', '< 2.5.0' +ruby '>= 2.3.0', '< 2.6.0' gem 'pkg-config', '~> 1.2' @@ -29,7 +29,7 @@ gem 'browser' gem 'charlock_holmes', '~> 0.7.5' gem 'iso-639' gem 'cld3', '~> 3.2.0' -gem 'devise', '~> 4.3' +gem 'devise', '~> 4.4' gem 'devise-two-factor', '~> 3.0' gem 'doorkeeper', '~> 4.2' gem 'fast_blank', '~> 1.0' diff --git a/Gemfile.lock b/Gemfile.lock index cede4aaf7..87298fc77 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,7 +110,7 @@ GEM activesupport charlock_holmes (0.7.5) chunky_png (1.3.8) - cld3 (3.2.1) + cld3 (3.2.2) ffi (>= 1.1.0, < 1.10.0) climate_control (0.2.0) cocaine (0.5.8) @@ -125,7 +125,7 @@ GEM css_parser (1.6.0) addressable debug_inspector (0.0.3) - devise (4.3.0) + devise (4.4.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0, < 5.2) @@ -569,7 +569,7 @@ DEPENDENCIES charlock_holmes (~> 0.7.5) cld3 (~> 3.2.0) climate_control (~> 0.2) - devise (~> 4.3) + devise (~> 4.4) devise-two-factor (~> 3.0) doorkeeper (~> 4.2) dotenv-rails (~> 2.2) @@ -651,7 +651,7 @@ DEPENDENCIES webpush RUBY VERSION - ruby 2.4.2p198 + ruby 2.5.0p0 BUNDLED WITH 1.16.1 diff --git a/app/controllers/concerns/user_tracking_concern.rb b/app/controllers/concerns/user_tracking_concern.rb index 1e3132941..a2510e55f 100644 --- a/app/controllers/concerns/user_tracking_concern.rb +++ b/app/controllers/concerns/user_tracking_concern.rb @@ -32,7 +32,7 @@ module UserTrackingConcern end def regenerate_feed! - Redis.current.setnx("account:#{current_user.account_id}:regeneration", true) == 1 && Redis.current.expire("account:#{current_user.account_id}:regeneration", 3_600 * 24) + Redis.current.setnx("account:#{current_user.account_id}:regeneration", true) && Redis.current.expire("account:#{current_user.account_id}:regeneration", 1.day.seconds) RegenerationWorker.perform_async(current_user.account_id) end end diff --git a/app/javascript/images/elephant-friend-1.png b/app/javascript/images/elephant-friend-1.png deleted file mode 100644 index 2b2383330..000000000 --- a/app/javascript/images/elephant-friend-1.png +++ /dev/null Binary files differdiff --git a/app/javascript/images/elephant_ui_plane.svg b/app/javascript/images/elephant_ui_plane.svg new file mode 100644 index 000000000..a2624d170 --- /dev/null +++ b/app/javascript/images/elephant_ui_plane.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 292.85862 204.49997" width="292.85861" height="204.49997"><g transform="translate(-395.89999 -820.4)"><defs><path id="a" d="M395.89999 745.09998H690.5v279.79999H395.89999z"/></defs><clipPath id="b"><use xlink:href="#a" width="100%" height="100%" overflow="visible"/></clipPath><path class="st53" d="M339.3 1028.6c1.5-3.2 14.4-31.3 27.4-58.8-6-9.3-2-17 1.5-23.7 1.9-3.7 3.8-7.1 3.6-10.4-.8-22 8.1-38.3 22.8-41.6 2.8-.6 5.2-.9 7.5-.9 3 0 5.6.5 8.1 1.6 1.4-1.3 2.8-2.6 4.2-3.8-2.8-2.6-4.3-5.5-4.5-8.8-.3-4.5 2.2-9.5 6.8-13.7 5.3-4.8 16.5-12.9 31.7-12.9.9 0 1.7 0 2.6.1-.4-.9-1-2-2.1-2.9-2.1-1.6-1.9-3.2-1.6-4 .7-2.1 3.6-3.2 8.1-3.2 3.9 0 9.7 1.2 14 4.4.3-.7.7-1.3 1.3-1.7.5-.3 1.3-.5 2.2-.5 3.4 0 10.6 2.7 15.5 9.9 3.6 5.3 3.6 10.8.1 16 18.3 4.7 30.1 15.6 39.5 24.4 2.5 2.4 5 4.6 7.3 6.5 10.7 8.9 21.4 13.2 32.7 13.2.9 0 1.8 0 2.7-.1 2-13.5-4.1-25.5-10-35.7-6.2-10.7-6.4-12.1-4.9-13.9l.1-.1c.6-.7 1.3-1 2.1-1.1h.3c1.7 0 4.5 1 13 8.7 9.9 9 16.9 22.2 19.2 36.5 8.9-4.9 15.2-12.5 17.1-20.3 2-8.6.5-16.8-4.2-22.7l-13.1 6.1-7-16.9-15.6 3.2 7.2-19.5h.1l-.2-.5 4.6-11.1 65.7 11.9c3.1.6 3.9 2.7 3.6 4.5l-.2 1-.4-.1c-.3.4-.6.7-1 .9-.7.3-7.5 3.6-21 9.9 2.1 2.9 2.2 6.1.4 9.4-1.1 1.9-2.5 6.2.4 13.3 3.7 8.9 3.5 29.2-8.3 46.2-8.1 11.7-18.3 23-37.6 26.6-3 4.6-6.5 9-10.2 12.6-7.8 7.6-24 15.3-42.3 15.3-5.3 0-10.7-.6-15.9-1.9-7.6 12.9-10.5 26.2-10.6 32.1-.2 11 .9 16.1.9 16.2l.4 1.8-164.9.8.9-2.3z" clip-path="url(#b)"/><path class="st53" d="M339.8 1028.8c.1-.3 13.9-30.1 27.5-59.1-6.1-9.2-2.1-16.8 1.4-23.5 2-3.7 3.8-7.3 3.7-10.6-.8-21.7 8-37.9 22.4-41 2.7-.6 5.1-.9 7.4-.9 3 0 5.7.5 8.2 1.7 1.6-1.6 3.2-3 4.9-4.4-3-2.6-4.6-5.5-4.8-8.8-.3-4.4 2.1-9.2 6.6-13.3 5.3-4.8 16.4-12.8 31.4-12.8 1.1 0 2.2 0 3.3.1-.3-1.1-1-2.7-2.5-3.8-1.8-1.4-1.7-2.8-1.5-3.4.6-1.8 3.4-2.9 7.6-2.9 4.4 0 10.3 1.5 14.3 4.8.1-.9.6-1.7 1.3-2.1.4-.3 1.1-.4 1.9-.4 3.3 0 10.3 2.6 15.1 9.7 3.6 5.3 3.5 10.9-.3 16.1 18.6 4.6 30.5 15.6 40 24.4 2.6 2.4 5 4.6 7.3 6.5 10.8 8.9 21.6 13.3 33.1 13.3 1 0 2.1 0 3.1-.1 2.2-13.9-4-26.1-10-36.4-6.3-10.9-6.2-11.8-5-13.3l.1-.1c.2-.2.7-.9 1.8-.9h.2c1.5 0 4.2 1 12.7 8.6 10 9.1 17 22.5 19.2 36.9 9.3-5 16-12.8 17.9-20.9 2.1-8.9.4-17.4-4.5-23.4l-13 6.1-6.9-16.8-15.1 3.1 6.8-18.4h.6l-.5-1 4.4-10.6 65.3 11.8c3.5.7 3.3 3.2 3.2 3.9l-.1.5h-.2c-.2.4-.6.8-1 1-.7.3-7.9 3.7-21.6 10.2.1.1.2.2.3.4 2 2.7 2.2 5.8.4 8.9-1.1 2-2.6 6.4.4 13.7 3.6 8.8 3.4 28.8-8.2 45.7-8.1 11.7-18.2 22.9-37.5 26.4-3 4.7-6.5 9.1-10.3 12.7-7.8 7.5-23.7 15.1-42 15.1-5.4 0-10.9-.7-16.1-2-7.7 13.1-10.7 26.7-10.9 32.7-.2 11.1.9 16.2.9 16.3l.3 1.2-163.5.8.5-1.7z" clip-path="url(#b)"/><path d="M577.5 843.7l-1-2.1 3.9-9.4 64.5 11.6c2.4.5 2.5 2 2.4 2.8" clip-path="url(#b)" fill="#fff" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path d="M584.2 856.7l6.9 16.6s53.7-25.1 55.5-26c.9-.5 1.5-2.2-1-2.3-2.5-.1-69.6-1.4-69.6-1.4l-5.9 16 14.1-2.9z" clip-path="url(#b)" fill="#fff" stroke="#000" stroke-width="1.70000005" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path d="M585.1 857l58.9-11.2 1.4-.5h.4c.8 0 .7.3.8.6.1.3-.1.6-.4.8L587 861.5l-1.9-4.5z" clip-path="url(#b)" fill="#d1d3d4"/><path class="st57" clip-path="url(#b)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M584.20001 856.70001l61.79999-11.5"/><path class="st58" d="M388.5 927.9c20-40 49.9-56.3 83.4-54.9 33.6 1.4 48.8 21.7 62.4 32.9 13.6 11.2 27.5 15.6 43.4 12.5 15.9-3.1 28.5-14.6 31.2-26.1 2.7-11.5-1-20.7-6.1-25.8-5.1-5.1-1.4-8.1 4.1-6.8 5.4 1.4 8.1 3.4 8.1 3.4s7.8-6.4 9.8-3.7c2 2.7 1.7 5.4.3 7.8-1.4 2.4-2.7 7.1.3 14.6 3.1 7.5 4.1 27.1-8.1 44.8-12.2 17.6-26.5 30.1-62.1 26.5-38.5-3.9-54.6 44.2-54.9 59-.2 11.5.9 16.5.9 16.5l-160.7.8c.2-.1 33.4-72.4 48-101.5z" clip-path="url(#b)" fill="#53606c" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path class="st59" d="M399.4 989.3c-6.1 0-9.9-4.3-10-4.3l-.2-.2-.3.1c-3.1 1-6.1 1.5-9 1.5-6.1 0-11.4-2.2-15.6-6.5 1.4-3 2.9-6.1 4.3-9.1.1.1.1.2.2.3 6.1 8 12.7 9.7 17 9.7 3.2 0 5.6-.9 6.6-1.3.7 1.3 3 4.7 7.5 4.7 1.2 0 2.5-.3 3.9-.8 6.7-2.5 15.7-13.1 18.3-22.1 3.2 5.7-2.8 18.3-13.8 25.3-3 1.7-6 2.7-8.9 2.7zm24.5-78.1c-5.7-11.1-10.8-14.2-12.4-14.9 15.7-15.3 34.7-23 56.6-23 1.3 0 2.5 0 3.8.1 2.1.1 4.2.3 6.4.5 1.5 2.7-.4 5.6-.8 6.3-3 .8-11.2 6.5-18.5 11.6-1.9 1.3-3.7 2.6-5.3 3.7-5.3 3.7-13.6 4.2-18 4.2-1.8 0-2.9-.1-2.9-.1h-.3l-8.6 11.6zm95.3 49c4.2-7.1 12.6-15.2 28.3-15.2 3.5 0 7.2.4 11 1.2 3.4.7 7 1.1 10.6 1.1 15.9 0 29.8-7.9 34.8-12.5 6.5-6 10.5-9.8 12-12.4 1.4-2.4 3.2-2.8 4.7-2 .1.1-.7 1.1-.6 1.1-.9 1.7-1.9 3.3-3 4.8-11.5 16.6-23.9 26.9-50 26.9-3.6 0-7.5-.2-11.6-.6-1.5-.2-3-.2-4.4-.2-9.4 0-18.1 3.2-25.9 9.4l-5.9-1.6z" clip-path="url(#b)" fill="#38434f"/><path class="st58" d="M427.4 920.5c-9.1-24.2-19-27.9-32.4-25-13.4 3-22.4 18-21.6 40 .4 10.2-15.5 20.5-4.3 35s23.5 8 23.5 8 3 7.1 11 4.1 16.7-13.5 18.5-21.6" clip-path="url(#b)" fill="#53606c" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path class="st59" d="M417.2 934.2c-7.3.5-8.6-4.8-7.3-7 1.2-2.1 4.6-3.2 4.6-3.2s-5.3-.2-6.3-4c-1-3.7 4-5.3 4-5.3s-2.9-8.6-13.3-6.1-14.4 11.7-14.2 19c.6 15.3-10.2 22.8 0 29.7 10.1 6.9 23.7-2.8 28.5-11.3 4.8-8.5 4-11.8 4-11.8z" clip-path="url(#b)" fill="#38434f"/><path class="st57" d="M392.6 978.6c6.3-3.9 9.1-7.5 9.1-7.5m15.5-36.9c-7.3.5-8.6-4.8-7.3-7 1.2-2.1 4.6-3.2 4.6-3.2s-5.3-.2-6.3-4c-1-3.7 4-5.3 4-5.3s-2.9-8.6-13.3-6.1-14.6 11.7-14.2 19" clip-path="url(#b)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path d="M417.5 891.4c-9.8-6.9-6.2-16 .3-21.8 6.5-5.8 19-14 35.2-12.2 0 0-.2-3.5-3.1-5.8s-.5-4.5 5.5-4.5 12.9 2.6 15.8 6.9c0 0-1.4-3.2.4-4.4 1.8-1.2 10.2 1 15.6 9s1.1 14.9-5.2 19.9c-6.3 5-36.2 11.6-48.8 10.9" clip-path="url(#b)" fill="#53606c"/><g class="st53" clip-path="url(#b)"><path class="st36" d="M459.5 878.7c-11.1.6-22.1 3.3-32.9 6.1-4.1 1.1-8.2 2.2-12.4 2-.4 0-.8-.1-1.3-.1 1 1.6 2.5 3.2 4.6 4.7l15.6-2.1c11.3.7 37-4.7 46.4-9.4-6.5-1.1-13.3-1.5-20-1.2z" fill="#38434f"/></g><path class="st59" d="M417.5 890.8c-3.5-2.5-5.3-5.5-5.5-8.8-.2-3.2 1.2-6.7 4-9.9-.4 1.6-.2 3.2.5 4.7 1.2 2.5 3.6 4 6.3 4 2.1 0 4.3-.9 6.3-2.6 7.2-6 19.4-10.4 29.1-10.4 1.9 0 3.7.2 5.3.5 7.7 1.6 12.3 3.7 13.8 6.7.8 1.6.8 3.3 0 5.4-10.1 4.3-31.2 8.6-42.1 8.6-.7 0-1.4 0-2.1-.1-1.4-.1-2.8-.1-4-.1-7.5-.1-10.6 1.4-11.6 2z" clip-path="url(#b)" fill="#38434f"/><path class="st57" d="M471.2 854c2.2 3.4 1.1 6.7 1.1 6.7" clip-path="url(#b)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path d="M489.6 967.9c34.6 23.5 68.7 8.7 80.2-2.4 11.4-11.1 20.8-28.5 20-45.9-.8-17.4-8.5-32.9-19.5-42.8-10.7-9.6-12.4-8.7-13.2-7.7-.8 1-1.4 1.1 5 12.2s13.4 24.6 9.5 40.2c-3.9 15.6-15.6 29.9-29.6 34-14 4-21.6-1.4-26.1-3.2 0 0 1 4-3.4 4.3-4.3.3-11.1-2.9-11.1-2.9s2.7 3 .1 5-5.9-.9-5.9-.9 2.5 2.2 1.5 3.3c-1 1.1-2.3.8-4.2-.6 0 0 3.2 3.6 1 5.5s-4.3 1.9-4.3 1.9z" clip-path="url(#b)" fill="#b3becd" stroke="#000" stroke-width="1.60000002" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path d="M528.6 979.9c-13.1 0-25.8-3.9-37.6-11.7.9-.2 2.1-.7 3.3-1.8 1.4-1.3 1-3 .3-4.3.4.1.8.2 1.1.2.7 0 1.3-.3 1.8-.8.3-.3.4-.6.4-1 0-.3-.1-.6-.2-.9.6.2 1.2.4 1.9.4.9 0 1.7-.3 2.4-.8.3-.2.5-.5.7-.8 12.6 6.2 22.6 9.1 31.5 9.1 7.8 0 14.7-2.3 21.1-6.9 16.8-12.3 21.3-21.3 24.6-27.9l.3-.6c2.3-4.5 4.2-6.5 6.4-6.5.9 0 1.7.3 2.7.9-1.4 13.6-8.7 28-19.6 38.6-7.9 7.4-23.4 14.8-41.1 14.8z" clip-path="url(#b)" fill="#92a1b5"/><path class="st57" d="M489.6 967.9c-3.9.1-6.7-.9-6.7-.9" clip-path="url(#b)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path d="M484 908.3c-2.2.9-2.1 3.2.1 6.7 2.1 3.5 4.5 7.9 5.9 10.3 1.4 2.4 2.6 3.5 4 2.8 1.4-.6 1.8-2 .4-4.9-1.4-2.9-5.8-11-7.2-12.7-1.6-1.7-2.4-2.5-3.2-2.2z" clip-path="url(#b)" fill="#38434f" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path class="st57" d="M525.9 907.8c2.5-3.7 4.8-5.2 4.8-5.2m3.8 11.9c1.5-3.1 3.7-5.6 3.7-5.6m11.9 13.3c1-3.9 2.7-5.6 2.7-5.6m10.7 9c.6-4.6.9-6.6.9-6.6" clip-path="url(#b)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><g class="st53" clip-path="url(#b)"><path class="st49" d="M504.9 862.2c.8-.4 1.5-.8 2.2-1.1" fill="none" stroke="#e3e5e5" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M519.8 856.2c13.6-3.5 22.1.5 28.2 3.3 5.3 2.4 11.6 4.7 17.6 5.3" fill="none" stroke="#e3e5e5" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4.5286,13.5857"/><path class="st49" d="M572.4 864.5c.8-.2 1.6-.4 2.4-.7" fill="none" stroke="#e3e5e5" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></g><g class="st53" clip-path="url(#b)"><path d="M491.2 946.7c-4.1 1.1-6.1 1.8-10 3.5-2.1.9-4.6.1-5.6-1.9s0-4.6 2.3-5.6c4.3-1.9 6.6-2.7 11.2-3.9 2.4-.6 4.8.8 5.3 2.9.4 2.2-1 4.4-3.2 5z" fill="#505762"/></g><path class="st57" d="M515.8 952.3c-.2-2.3-1.7-3.3-1.7-3.3" clip-path="url(#b)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><g class="st53" clip-path="url(#b)"><path d="M454.5 887.5c-3.5.7-7.1 1.3-10.6 1.7-3.6.4-7.2.8-10.8.6-.3 0-.5-.2-.5-.5s.2-.5.5-.5c3.5.2 7.1-.1 10.6-.4 3.5-.4 7.1-.9 10.6-1.6.2 0 .4.1.4.3.1.2 0 .4-.2.4z"/></g><g class="st53" clip-path="url(#b)"><path d="M417.2 891.8c-2.2-1.6-4.3-3.6-5.4-6.2l-.4-1-.2-1-.1-.5v-.5c0-.4-.1-.7-.1-1.1 0-1.4.2-2.8.7-4.1.9-2.6 2.6-4.9 4.4-6.9 1.9-2 4-3.6 6.2-5.2s4.6-2.9 7-4.1c2.4-1.2 5-2.2 7.6-2.9 5.2-1.5 10.7-1.9 16.1-1.4l-.6.5c-.2-1.3-.7-2.7-1.4-3.8-.4-.6-.8-1.1-1.4-1.5-.5-.5-1.2-1-1.5-1.9-.1-.2-.1-.5-.1-.7.1-.2.1-.5.2-.7.2-.4.6-.7.9-.9.7-.5 1.4-.7 2.2-.9 1.5-.3 3-.4 4.4-.4 2.9.1 5.9.7 8.6 1.8 2.7 1.1 5.3 2.8 7.1 5.3l-.9.5c-.3-.7-.5-1.3-.5-2.1-.1-.7 0-1.5.4-2.3.3-.3.5-.7 1-.8.2-.1.4-.1.6-.2.2 0 .4-.1.6-.1.7 0 1.4.1 2.1.2 1.4.3 2.6.8 3.9 1.4 1.2.6 2.4 1.3 3.5 2.1 2.2 1.6 4.1 3.6 5.6 5.9.7 1.2 1.4 2.4 1.8 3.7.3.6.4 1.3.5 2 .1.3.1.7.1 1v1c-.1 2.8-1.3 5.5-3 7.6-1.7 2.2-3.6 4-5.9 5.6-2.4 1.4-4.9 2.3-7.4 3.2-2.5.8-5.1 1.5-7.8 1.9 1.2-.5 2.5-.9 3.7-1.4l3.7-1.3c2.5-.9 5-1.8 7.2-3.2 2.1-1.5 4-3.3 5.6-5.4 1.5-2.1 2.6-4.5 2.7-7 .1-2.5-.8-5-2.2-7.1-1.4-2.2-3.2-4.1-5.3-5.6-2.1-1.5-4.4-2.8-6.9-3.4-.6-.1-1.2-.2-1.8-.2-.6 0-1 .1-1.3.5-.5.8-.2 2.3.2 3.4.1.3 0 .5-.3.6-.2.1-.4 0-.6-.2-1.6-2.3-4-3.8-6.6-4.9-2.6-1.1-5.4-1.7-8.2-1.7-1.4 0-2.8.1-4.2.4-.7.2-1.3.4-1.8.7-.5.4-.8.8-.7 1.3.1.5.6.9 1.2 1.4.6.5 1.1 1.1 1.5 1.7.9 1.3 1.4 2.7 1.6 4.3 0 .3-.2.5-.4.5h-.1c-5.3-.5-10.7-.1-15.8 1.4-2.5.7-5 1.7-7.4 2.8-2.4 1.2-4.7 2.5-6.8 4.1-2.2 1.5-4.3 3.2-6.1 5.1-1.8 1.9-3.4 4.1-4.2 6.5-.4 1.2-.6 2.5-.7 3.8 0 .3.1.6.1 1v.5l.1.5.2.9.4.9c1 2.4 2.9 4.3 5 5.8.2.2.3.5.1.7-.2.2-.4.3-.7.1z"/></g><g class="st53" clip-path="url(#b)"><path class="st36" d="M615.1 863.2c2 1.2 2.3 1.8 2.3 1.8" fill="#38434f"/><path d="M615.3 862.9l1.2.9c.2.2.4.3.6.5.2.2.3.4.5.6 0 .1 0 .2-.1.2h-.2l-.5-.5c-.2-.1-.4-.3-.6-.4-.4-.3-.8-.5-1.3-.7-.2-.1-.2-.3-.1-.5s.2-.2.5-.1c-.1 0-.1 0 0 0z"/></g></g></svg> \ No newline at end of file diff --git a/app/javascript/images/icon_done.svg b/app/javascript/images/icon_done.svg new file mode 100644 index 000000000..446af14d9 --- /dev/null +++ b/app/javascript/images/icon_done.svg @@ -0,0 +1,4 @@ +<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> + <path d="M0 0h24v24H0z" fill="none"/> + <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/> +</svg> \ No newline at end of file diff --git a/app/javascript/images/mastodon-ui.png b/app/javascript/images/mastodon-ui.png deleted file mode 100644 index a1fb642a0..000000000 --- a/app/javascript/images/mastodon-ui.png +++ /dev/null Binary files differdiff --git a/app/javascript/images/wave-compose-standalone.png b/app/javascript/images/wave-compose-standalone.png deleted file mode 100644 index 287ee639b..000000000 --- a/app/javascript/images/wave-compose-standalone.png +++ /dev/null Binary files differdiff --git a/app/javascript/images/wave-drawer.png b/app/javascript/images/wave-drawer.png deleted file mode 100644 index ca9f9e1d8..000000000 --- a/app/javascript/images/wave-drawer.png +++ /dev/null Binary files differdiff --git a/app/javascript/images/wave-modal.png b/app/javascript/images/wave-modal.png deleted file mode 100644 index 88818a6d7..000000000 --- a/app/javascript/images/wave-modal.png +++ /dev/null Binary files differdiff --git a/app/javascript/mastodon/actions/onboarding.js b/app/javascript/mastodon/actions/onboarding.js deleted file mode 100644 index a161c50ef..000000000 --- a/app/javascript/mastodon/actions/onboarding.js +++ /dev/null @@ -1,14 +0,0 @@ -import { openModal } from './modal'; -import { changeSetting, saveSettings } from './settings'; - -export function showOnboardingOnce() { - return (dispatch, getState) => { - const alreadySeen = getState().getIn(['settings', 'onboarded']); - - if (!alreadySeen) { - dispatch(openModal('ONBOARDING')); - dispatch(changeSetting(['onboarded'], true)); - dispatch(saveSettings()); - } - }; -}; diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index d1710445b..8ae3b727a 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -2,7 +2,6 @@ import React from 'react'; import { Provider } from 'react-redux'; import PropTypes from 'prop-types'; import configureStore from '../store/configureStore'; -import { showOnboardingOnce } from '../actions/onboarding'; import { BrowserRouter, Route } from 'react-router-dom'; import { ScrollContext } from 'react-router-scroll-4'; import UI from '../features/ui'; @@ -40,8 +39,6 @@ export default class Mastodon extends React.PureComponent { const handlerUrl = window.location.protocol + '//' + window.location.host + '/intent?uri=%s'; window.setTimeout(() => navigator.registerProtocolHandler('web+mastodon', handlerUrl, 'Mastodon'), 5 * 60 * 1000); } - - store.dispatch(showOnboardingOnce()); } componentWillUnmount () { diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js index 5839ba40a..dbfb46ee7 100644 --- a/app/javascript/mastodon/features/ui/components/modal_root.js +++ b/app/javascript/mastodon/features/ui/components/modal_root.js @@ -9,7 +9,6 @@ import VideoModal from './video_modal'; import BoostModal from './boost_modal'; import ConfirmationModal from './confirmation_modal'; import { - OnboardingModal, MuteModal, ReportModal, EmbedModal, @@ -18,7 +17,6 @@ import { const MODAL_COMPONENTS = { 'MEDIA': () => Promise.resolve({ default: MediaModal }), - 'ONBOARDING': OnboardingModal, 'VIDEO': () => Promise.resolve({ default: VideoModal }), 'BOOST': () => Promise.resolve({ default: BoostModal }), 'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }), diff --git a/app/javascript/mastodon/features/ui/components/onboarding_modal.js b/app/javascript/mastodon/features/ui/components/onboarding_modal.js deleted file mode 100644 index 54673e223..000000000 --- a/app/javascript/mastodon/features/ui/components/onboarding_modal.js +++ /dev/null @@ -1,318 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ReactSwipeableViews from 'react-swipeable-views'; -import classNames from 'classnames'; -import Permalink from '../../../components/permalink'; -import ComposeForm from '../../compose/components/compose_form'; -import Search from '../../compose/components/search'; -import NavigationBar from '../../compose/components/navigation_bar'; -import ColumnHeader from './column_header'; -import { List as ImmutableList } from 'immutable'; -import { me } from '../../../initial_state'; - -const noop = () => { }; - -const messages = defineMessages({ - home_title: { id: 'column.home', defaultMessage: 'Home' }, - notifications_title: { id: 'column.notifications', defaultMessage: 'Notifications' }, - local_title: { id: 'column.community', defaultMessage: 'Local timeline' }, - federated_title: { id: 'column.public', defaultMessage: 'Federated timeline' }, -}); - -const PageOne = ({ acct, domain }) => ( - <div className='onboarding-modal__page onboarding-modal__page-one'> - <div style={{ flex: '0 0 auto' }}> - <div className='onboarding-modal__page-one__elephant-friend' /> - </div> - - <div> - <h1><FormattedMessage id='onboarding.page_one.welcome' defaultMessage='Welcome to Mastodon!' /></h1> - <p><FormattedMessage id='onboarding.page_one.federation' defaultMessage='Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.' /></p> - <p><FormattedMessage id='onboarding.page_one.handle' defaultMessage='You are on {domain}, so your full handle is {handle}' values={{ domain, handle: <strong>@{acct}@{domain}</strong> }} /></p> - </div> - </div> -); - -PageOne.propTypes = { - acct: PropTypes.string.isRequired, - domain: PropTypes.string.isRequired, -}; - -const PageTwo = ({ myAccount }) => ( - <div className='onboarding-modal__page onboarding-modal__page-two'> - <div className='figure non-interactive'> - <div className='pseudo-drawer'> - <NavigationBar account={myAccount} /> - </div> - <ComposeForm - text='Awoo! #introductions' - suggestions={ImmutableList()} - mentionedDomains={[]} - spoiler={false} - onChange={noop} - onSubmit={noop} - onPaste={noop} - onPickEmoji={noop} - onChangeSpoilerText={noop} - onClearSuggestions={noop} - onFetchSuggestions={noop} - onSuggestionSelected={noop} - showSearch - /> - </div> - - <p><FormattedMessage id='onboarding.page_two.compose' defaultMessage='Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.' /></p> - </div> -); - -PageTwo.propTypes = { - myAccount: ImmutablePropTypes.map.isRequired, -}; - -const PageThree = ({ myAccount }) => ( - <div className='onboarding-modal__page onboarding-modal__page-three'> - <div className='figure non-interactive'> - <Search - value='' - onChange={noop} - onSubmit={noop} - onClear={noop} - onShow={noop} - /> - - <div className='pseudo-drawer'> - <NavigationBar account={myAccount} /> - </div> - </div> - - <p><FormattedMessage id='onboarding.page_three.search' defaultMessage='Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.' values={{ illustration: <Permalink to='/timelines/tag/illustration' href='/tags/illustration'>#illustration</Permalink>, introductions: <Permalink to='/timelines/tag/introductions' href='/tags/introductions'>#introductions</Permalink> }} /></p> - <p><FormattedMessage id='onboarding.page_three.profile' defaultMessage='Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.' /></p> - </div> -); - -PageThree.propTypes = { - myAccount: ImmutablePropTypes.map.isRequired, -}; - -const PageFour = ({ domain, intl }) => ( - <div className='onboarding-modal__page onboarding-modal__page-four'> - <div className='onboarding-modal__page-four__columns'> - <div className='row'> - <div> - <div className='figure non-interactive'><ColumnHeader icon='home' type={intl.formatMessage(messages.home_title)} /></div> - <p><FormattedMessage id='onboarding.page_four.home' defaultMessage='The home timeline shows posts from people you follow.' /></p> - </div> - - <div> - <div className='figure non-interactive'><ColumnHeader icon='bell' type={intl.formatMessage(messages.notifications_title)} /></div> - <p><FormattedMessage id='onboarding.page_four.notifications' defaultMessage='The notifications column shows when someone interacts with you.' /></p> - </div> - </div> - - <div className='row'> - <div> - <div className='figure non-interactive' style={{ marginBottom: 0 }}><ColumnHeader icon='users' type={intl.formatMessage(messages.local_title)} /></div> - </div> - - <div> - <div className='figure non-interactive' style={{ marginBottom: 0 }}><ColumnHeader icon='globe' type={intl.formatMessage(messages.federated_title)} /></div> - </div> - </div> - - <p><FormattedMessage id='onboarding.page_five.public_timelines' defaultMessage='The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.' values={{ domain }} /></p> - </div> - </div> -); - -PageFour.propTypes = { - domain: PropTypes.string.isRequired, - intl: PropTypes.object.isRequired, -}; - -const PageSix = ({ admin, domain }) => { - let adminSection = ''; - - if (admin) { - adminSection = ( - <p> - <FormattedMessage id='onboarding.page_six.admin' defaultMessage="Your instance's admin is {admin}." values={{ admin: <Permalink href={admin.get('url')} to={`/accounts/${admin.get('id')}`}>@{admin.get('acct')}</Permalink> }} /> - <br /> - <FormattedMessage id='onboarding.page_six.read_guidelines' defaultMessage="Please read {domain}'s {guidelines}!" values={{ domain, guidelines: <a href='/about/more' target='_blank'><FormattedMessage id='onboarding.page_six.guidelines' defaultMessage='community guidelines' /></a> }} /> - </p> - ); - } - - return ( - <div className='onboarding-modal__page onboarding-modal__page-six'> - <h1><FormattedMessage id='onboarding.page_six.almost_done' defaultMessage='Almost done...' /></h1> - {adminSection} - <p><FormattedMessage id='onboarding.page_six.github' defaultMessage='Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.' values={{ github: <a href='https://github.com/tootsuite/mastodon' target='_blank' rel='noopener'>GitHub</a> }} /></p> - <p><FormattedMessage id='onboarding.page_six.apps_available' defaultMessage='There are {apps} available for iOS, Android and other platforms.' values={{ apps: <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' target='_blank' rel='noopener'><FormattedMessage id='onboarding.page_six.various_app' defaultMessage='mobile apps' /></a> }} /></p> - <p><em><FormattedMessage id='onboarding.page_six.appetoot' defaultMessage='Bon Appetoot!' /></em></p> - </div> - ); -}; - -PageSix.propTypes = { - admin: ImmutablePropTypes.map, - domain: PropTypes.string.isRequired, -}; - -const mapStateToProps = state => ({ - myAccount: state.getIn(['accounts', me]), - admin: state.getIn(['accounts', state.getIn(['meta', 'admin'])]), - domain: state.getIn(['meta', 'domain']), -}); - -@connect(mapStateToProps) -@injectIntl -export default class OnboardingModal extends React.PureComponent { - - static propTypes = { - onClose: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - myAccount: ImmutablePropTypes.map.isRequired, - domain: PropTypes.string.isRequired, - admin: ImmutablePropTypes.map, - }; - - state = { - currentIndex: 0, - }; - - componentWillMount() { - const { myAccount, admin, domain, intl } = this.props; - this.pages = [ - <PageOne acct={myAccount.get('acct')} domain={domain} />, - <PageTwo myAccount={myAccount} />, - <PageThree myAccount={myAccount} />, - <PageFour domain={domain} intl={intl} />, - <PageSix admin={admin} domain={domain} />, - ]; - }; - - componentDidMount() { - window.addEventListener('keyup', this.handleKeyUp); - } - - componentWillUnmount() { - window.addEventListener('keyup', this.handleKeyUp); - } - - handleSkip = (e) => { - e.preventDefault(); - this.props.onClose(); - } - - handleDot = (e) => { - const i = Number(e.currentTarget.getAttribute('data-index')); - e.preventDefault(); - this.setState({ currentIndex: i }); - } - - handlePrev = () => { - this.setState(({ currentIndex }) => ({ - currentIndex: Math.max(0, currentIndex - 1), - })); - } - - handleNext = () => { - const { pages } = this; - this.setState(({ currentIndex }) => ({ - currentIndex: Math.min(currentIndex + 1, pages.length - 1), - })); - } - - handleSwipe = (index) => { - this.setState({ currentIndex: index }); - } - - handleKeyUp = ({ key }) => { - switch (key) { - case 'ArrowLeft': - this.handlePrev(); - break; - case 'ArrowRight': - this.handleNext(); - break; - } - } - - handleClose = () => { - this.props.onClose(); - } - - render () { - const { pages } = this; - const { currentIndex } = this.state; - const hasMore = currentIndex < pages.length - 1; - - const nextOrDoneBtn = hasMore ? ( - <button - onClick={this.handleNext} - className='onboarding-modal__nav onboarding-modal__next' - > - <FormattedMessage id='onboarding.next' defaultMessage='Next' /> - </button> - ) : ( - <button - onClick={this.handleClose} - className='onboarding-modal__nav onboarding-modal__done' - > - <FormattedMessage id='onboarding.done' defaultMessage='Done' /> - </button> - ); - - return ( - <div className='modal-root__modal onboarding-modal'> - <ReactSwipeableViews index={currentIndex} onChangeIndex={this.handleSwipe} className='onboarding-modal__pager'> - {pages.map((page, i) => { - const className = classNames('onboarding-modal__page__wrapper', { - 'onboarding-modal__page__wrapper--active': i === currentIndex, - }); - return ( - <div key={i} className={className}>{page}</div> - ); - })} - </ReactSwipeableViews> - - <div className='onboarding-modal__paginator'> - <div> - <button - onClick={this.handleSkip} - className='onboarding-modal__nav onboarding-modal__skip' - > - <FormattedMessage id='onboarding.skip' defaultMessage='Skip' /> - </button> - </div> - - <div className='onboarding-modal__dots'> - {pages.map((_, i) => { - const className = classNames('onboarding-modal__dot', { - active: i === currentIndex, - }); - return ( - <div - key={`dot-${i}`} - role='button' - tabIndex='0' - data-index={i} - onClick={this.handleDot} - className={className} - /> - ); - })} - </div> - - <div> - {nextOrDoneBtn} - </div> - </div> - </div> - ); - } - -} diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index d6586680b..a03c4cefd 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -94,10 +94,6 @@ export function Mutes () { return import(/* webpackChunkName: "features/mutes" */'../../mutes'); } -export function OnboardingModal () { - return import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal'); -} - export function MuteModal () { return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal'); } diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js index 7b7b5470f..9a10bcc59 100644 --- a/app/javascript/mastodon/reducers/timelines.js +++ b/app/javascript/mastodon/reducers/timelines.js @@ -40,7 +40,7 @@ const normalizeTimeline = (state, timeline, statuses, next, isPartial) => { mMap.set('loaded', true); mMap.set('isLoading', false); if (!hadNext) mMap.set('next', next); - mMap.set('items', wasLoaded ? ids.concat(oldIds) : ids); + mMap.set('items', wasLoaded ? ids.concat(oldIds) : oldIds.concat(ids)); mMap.set('isPartial', isPartial); })); }; diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index fd6665f65..300040173 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -6,7 +6,6 @@ @import 'mastodon/reset'; @import 'mastodon/basics'; -@import 'mastodon/modal'; @import 'mastodon/containers'; @import 'mastodon/lists'; @import 'mastodon/footer'; @@ -15,7 +14,9 @@ @import 'mastodon/forms'; @import 'mastodon/accounts'; @import 'mastodon/stream_entries'; +@import 'mastodon/boost'; @import 'mastodon/components'; +@import 'mastodon/modal'; @import 'mastodon/emoji_picker'; @import 'mastodon/about'; @import 'mastodon/tables'; diff --git a/app/javascript/styles/mailer.scss b/app/javascript/styles/mailer.scss index e6422b2ea..b3bcc9209 100644 --- a/app/javascript/styles/mailer.scss +++ b/app/javascript/styles/mailer.scss @@ -228,6 +228,13 @@ h3 { line-height: 25px; } +h5 { + font-size: 16px; + line-height: 21px; + font-weight: 700; + color: lighten($ui-base-color, 34%); +} + .input { td { background: darken($ui-base-color, 8%); @@ -356,6 +363,19 @@ h3 { font-weight: 500 !important; } } + + &.button-small { + td { + border-radius: 4px; + font-size: 14px; + padding: 8px 16px; + + a { + padding: 5px 16px !important; + line-height: 26px !important; + } + } + } } .button-default { @@ -379,6 +399,14 @@ h3 { padding-right: 16px; } +.padded-bottom { + padding-bottom: 32px; +} + +.margin-bottom { + margin-bottom: 20px; +} + .hero-icon { width: 64px; @@ -463,6 +491,22 @@ h3 { border-top: 1px solid lighten($ui-base-color, 8%); } +ul { + padding-left: 15px; + margin-top: 0; + margin-bottom: 0; + padding-top: 16px; + + li { + margin-bottom: 16px; + color: lighten($ui-base-color, 26%); + + span { + color: $ui-primary-color; + } + } +} + @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) { body { min-height: 1024px !important; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index d13a18ad7..89d4b2eba 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1762,7 +1762,7 @@ position: absolute; top: 0; left: 0; - background: lighten($ui-base-color, 13%) url('~images/wave-drawer.png') no-repeat bottom / 100% auto; + background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto; box-sizing: border-box; padding: 0; display: flex; @@ -1777,7 +1777,7 @@ } > .mastodon { - background: url('~images/mastodon-ui.png') no-repeat left bottom / contain; + background: url('~images/elephant_ui_plane.svg') no-repeat left bottom / contain; flex: 1; } } @@ -2154,10 +2154,7 @@ } } -@import 'boost'; - .no-reduce-motion button.icon-button i.fa-retweet { - background-position: 0 0; height: 19px; transition: background-position 0.9s steps(10); @@ -3303,7 +3300,6 @@ z-index: 100; } -.onboarding-modal, .error-modal, .embed-modal { background: $ui-secondary-color; @@ -3314,26 +3310,6 @@ flex-direction: column; } -.onboarding-modal__pager { - height: 80vh; - width: 80vw; - max-width: 520px; - max-height: 420px; - - .react-swipeable-view-container > div { - width: 100%; - height: 100%; - box-sizing: border-box; - padding: 25px; - display: none; - flex-direction: column; - align-items: center; - justify-content: center; - display: flex; - user-select: text; - } -} - .error-modal__body { height: 80vh; width: 80vw; @@ -3367,23 +3343,6 @@ text-align: center; } -@media screen and (max-width: 550px) { - .onboarding-modal { - width: 100%; - height: 100%; - border-radius: 0; - } - - .onboarding-modal__pager { - width: 100%; - height: auto; - max-width: none; - max-height: none; - flex: 1 1 auto; - } -} - -.onboarding-modal__paginator, .error-modal__footer { flex: 0 0 auto; background: darken($ui-secondary-color, 8%); @@ -3394,7 +3353,6 @@ min-width: 33px; } - .onboarding-modal__nav, .error-modal__nav { color: darken($ui-secondary-color, 34%); background-color: transparent; @@ -3410,11 +3368,6 @@ &:active { color: darken($ui-secondary-color, 38%); } - - &.onboarding-modal__done, - &.onboarding-modal__next { - color: $ui-highlight-color; - } } } @@ -3422,6 +3375,7 @@ justify-content: center; } +<<<<<<< HEAD .onboarding-modal__dots { flex: 1 1 auto; display: flex; @@ -3632,6 +3586,8 @@ margin-left: 10px; } +======= +>>>>>>> origin/master .boost-modal, .confirmation-modal, .report-modal, diff --git a/app/javascript/styles/mastodon/modal.scss b/app/javascript/styles/mastodon/modal.scss index a17476ccb..ceb79bbb9 100644 --- a/app/javascript/styles/mastodon/modal.scss +++ b/app/javascript/styles/mastodon/modal.scss @@ -1,5 +1,5 @@ .modal-layout { - background: $ui-base-color url('~images/wave-modal.png') repeat-x bottom fixed; + background: $ui-base-color url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-lighter-color)}"/></svg>') repeat-x bottom fixed; display: flex; flex-direction: column; height: 100vh; @@ -15,6 +15,6 @@ > * { flex: 1; max-height: 235px; - background: url('~images/mastodon-ui.png') no-repeat left bottom / contain; + background: url('~images/elephant_ui_plane.svg') no-repeat left bottom / contain; } } diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 820189d29..0f9e4f263 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -69,12 +69,13 @@ class ActivityPub::Activity def distribute(status) crawl_links(status) + notify_about_reblog(status) if reblog_of_local_account?(status) + notify_about_mentions(status) + # Only continue if the status is supposed to have # arrived in real-time return unless @options[:override_timestamps] - notify_about_reblog(status) if reblog_of_local_account?(status) - notify_about_mentions(status) distribute_to_followers(status) end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index a7efa73c1..4104f6cd2 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -54,4 +54,15 @@ class UserMailer < Devise::Mailer mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject') end end + + def welcome(user) + @resource = user + @instance = Rails.configuration.x.local_domain + + return if @resource.disabled? + + I18n.with_locale(@resource.locale || I18n.default_locale) do + mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject') + end + end end diff --git a/app/models/account.rb b/app/models/account.rb index c75ea028e..6df9668d5 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -104,7 +104,7 @@ class Account < ApplicationRecord has_many :lists, through: :list_accounts # Account migrations - belongs_to :moved_to_account, class_name: 'Account' + belongs_to :moved_to_account, class_name: 'Account', optional: true scope :remote, -> { where.not(domain: nil) } scope :local, -> { where(domain: nil) } diff --git a/app/models/account_domain_block.rb b/app/models/account_domain_block.rb index 35810b6c2..abcc923b3 100644 --- a/app/models/account_domain_block.rb +++ b/app/models/account_domain_block.rb @@ -13,7 +13,7 @@ class AccountDomainBlock < ApplicationRecord include Paginable - belongs_to :account, required: true + belongs_to :account validates :domain, presence: true, uniqueness: { scope: :account_id } after_create :remove_blocking_cache diff --git a/app/models/admin/action_log.rb b/app/models/admin/action_log.rb index 4e950fbf7..c437c8ee8 100644 --- a/app/models/admin/action_log.rb +++ b/app/models/admin/action_log.rb @@ -16,8 +16,8 @@ class Admin::ActionLog < ApplicationRecord serialize :recorded_changes - belongs_to :account, required: true - belongs_to :target, required: true, polymorphic: true + belongs_to :account + belongs_to :target, polymorphic: true default_scope -> { order('id desc') } diff --git a/app/models/block.rb b/app/models/block.rb index 284abfe4c..441e6bca3 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -13,8 +13,8 @@ class Block < ApplicationRecord include Paginable - belongs_to :account, required: true - belongs_to :target_account, class_name: 'Account', required: true + belongs_to :account + belongs_to :target_account, class_name: 'Account' validates :account_id, uniqueness: { scope: :target_account_id } diff --git a/app/models/conversation_mute.rb b/app/models/conversation_mute.rb index 248cdfe6e..272eb81af 100644 --- a/app/models/conversation_mute.rb +++ b/app/models/conversation_mute.rb @@ -9,6 +9,6 @@ # class ConversationMute < ApplicationRecord - belongs_to :account, required: true - belongs_to :conversation, required: true + belongs_to :account + belongs_to :conversation end diff --git a/app/models/favourite.rb b/app/models/favourite.rb index c38838f2a..2b1271f31 100644 --- a/app/models/favourite.rb +++ b/app/models/favourite.rb @@ -13,8 +13,8 @@ class Favourite < ApplicationRecord include Paginable - belongs_to :account, inverse_of: :favourites, required: true - belongs_to :status, inverse_of: :favourites, counter_cache: true, required: true + belongs_to :account, inverse_of: :favourites + belongs_to :status, inverse_of: :favourites, counter_cache: true has_one :notification, as: :activity, dependent: :destroy diff --git a/app/models/follow.rb b/app/models/follow.rb index 3fb665afc..f953b8e3e 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -14,12 +14,11 @@ class Follow < ApplicationRecord include Paginable - belongs_to :account, counter_cache: :following_count, required: true + belongs_to :account, counter_cache: :following_count belongs_to :target_account, class_name: 'Account', - counter_cache: :followers_count, - required: true + counter_cache: :followers_count has_one :notification, as: :activity, dependent: :destroy diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb index ebf6959ce..bd6c4a0b9 100644 --- a/app/models/follow_request.rb +++ b/app/models/follow_request.rb @@ -14,8 +14,8 @@ class FollowRequest < ApplicationRecord include Paginable - belongs_to :account, required: true - belongs_to :target_account, class_name: 'Account', required: true + belongs_to :account + belongs_to :target_account, class_name: 'Account' has_one :notification, as: :activity, dependent: :destroy diff --git a/app/models/import.rb b/app/models/import.rb index 091fb3044..ba88435bf 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -20,7 +20,7 @@ class Import < ApplicationRecord self.inheritance_column = false - belongs_to :account, required: true + belongs_to :account enum type: [:following, :blocking, :muting] diff --git a/app/models/invite.rb b/app/models/invite.rb index 6907c1f1d..b87a3b722 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -14,7 +14,7 @@ # class Invite < ApplicationRecord - belongs_to :user, required: true + belongs_to :user has_many :users, inverse_of: :invite scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) } diff --git a/app/models/list.rb b/app/models/list.rb index be85c3b87..a2ec7e84a 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -15,7 +15,7 @@ class List < ApplicationRecord PER_ACCOUNT_LIMIT = 50 - belongs_to :account + belongs_to :account, optional: true has_many :list_accounts, inverse_of: :list, dependent: :destroy has_many :accounts, through: :list_accounts diff --git a/app/models/list_account.rb b/app/models/list_account.rb index 253932590..da46cf032 100644 --- a/app/models/list_account.rb +++ b/app/models/list_account.rb @@ -10,9 +10,9 @@ # class ListAccount < ApplicationRecord - belongs_to :list, required: true - belongs_to :account, required: true - belongs_to :follow, required: true + belongs_to :list + belongs_to :account + belongs_to :follow validates :account_id, uniqueness: { scope: :list_id } diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 368ccef3a..25b7fd085 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -62,8 +62,8 @@ class MediaAttachment < ApplicationRecord }, }.freeze - belongs_to :account, inverse_of: :media_attachments - belongs_to :status, inverse_of: :media_attachments + belongs_to :account, inverse_of: :media_attachments, optional: true + belongs_to :status, inverse_of: :media_attachments, optional: true has_attached_file :file, styles: ->(f) { file_styles f }, diff --git a/app/models/mention.rb b/app/models/mention.rb index 14533e6a9..f864bf8e1 100644 --- a/app/models/mention.rb +++ b/app/models/mention.rb @@ -11,8 +11,8 @@ # class Mention < ApplicationRecord - belongs_to :account, inverse_of: :mentions, required: true - belongs_to :status, required: true + belongs_to :account, inverse_of: :mentions + belongs_to :status has_one :notification, as: :activity, dependent: :destroy diff --git a/app/models/mute.rb b/app/models/mute.rb index ca984641a..da4787179 100644 --- a/app/models/mute.rb +++ b/app/models/mute.rb @@ -14,8 +14,8 @@ class Mute < ApplicationRecord include Paginable - belongs_to :account, required: true - belongs_to :target_account, class_name: 'Account', required: true + belongs_to :account + belongs_to :target_account, class_name: 'Account' validates :account_id, uniqueness: { scope: :target_account_id } diff --git a/app/models/notification.rb b/app/models/notification.rb index 976963528..733f89cf7 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -26,15 +26,15 @@ class Notification < ApplicationRecord STATUS_INCLUDES = [:account, :application, :stream_entry, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :application, :media_attachments, :tags, mentions: :account]].freeze - belongs_to :account - belongs_to :from_account, class_name: 'Account' - belongs_to :activity, polymorphic: true - - belongs_to :mention, foreign_type: 'Mention', foreign_key: 'activity_id' - belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id' - belongs_to :follow, foreign_type: 'Follow', foreign_key: 'activity_id' - belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id' - belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id' + belongs_to :account, optional: true + belongs_to :from_account, class_name: 'Account', optional: true + belongs_to :activity, polymorphic: true, optional: true + + belongs_to :mention, foreign_type: 'Mention', foreign_key: 'activity_id', optional: true + belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', optional: true + belongs_to :follow, foreign_type: 'Follow', foreign_key: 'activity_id', optional: true + belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id', optional: true + belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id', optional: true validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] } validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values } diff --git a/app/models/report.rb b/app/models/report.rb index c36f8db0a..f55fb6d3e 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -17,7 +17,7 @@ class Report < ApplicationRecord belongs_to :account belongs_to :target_account, class_name: 'Account' - belongs_to :action_taken_by_account, class_name: 'Account' + belongs_to :action_taken_by_account, class_name: 'Account', optional: true scope :unresolved, -> { where(action_taken: false) } scope :resolved, -> { where(action_taken: true) } diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb index 1d4ebca02..d364f03df 100644 --- a/app/models/session_activation.rb +++ b/app/models/session_activation.rb @@ -15,9 +15,9 @@ # class SessionActivation < ApplicationRecord - belongs_to :user, inverse_of: :session_activations, required: true - belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy - belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy + belongs_to :user, inverse_of: :session_activations + belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy, optional: true + belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy, optional: true delegate :token, to: :access_token, diff --git a/app/models/status.rb b/app/models/status.rb index cb18b0705..e927fb9dd 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -34,14 +34,14 @@ class Status < ApplicationRecord enum visibility: [:public, :unlisted, :private, :direct], _suffix: :visibility - belongs_to :application, class_name: 'Doorkeeper::Application' + belongs_to :application, class_name: 'Doorkeeper::Application', optional: true - belongs_to :account, inverse_of: :statuses, counter_cache: true, required: true - belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account' - belongs_to :conversation + belongs_to :account, inverse_of: :statuses, counter_cache: true + belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account', optional: true + belongs_to :conversation, optional: true - belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies - belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, counter_cache: :reblogs_count + belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies, optional: true + belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, counter_cache: :reblogs_count, optional: true has_many :favourites, inverse_of: :status, dependent: :destroy has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy diff --git a/app/models/status_pin.rb b/app/models/status_pin.rb index a72c19750..d3a98d8bd 100644 --- a/app/models/status_pin.rb +++ b/app/models/status_pin.rb @@ -11,8 +11,8 @@ # class StatusPin < ApplicationRecord - belongs_to :account, required: true - belongs_to :status, required: true + belongs_to :account + belongs_to :status validates_with StatusPinValidator end diff --git a/app/models/subscription.rb b/app/models/subscription.rb index 7f2eeab91..ea1173160 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -19,7 +19,7 @@ class Subscription < ApplicationRecord MIN_EXPIRATION = 1.day.to_i MAX_EXPIRATION = 30.days.to_i - belongs_to :account, required: true + belongs_to :account validates :callback_url, presence: true validates :callback_url, uniqueness: { scope: :account_id } diff --git a/app/models/user.rb b/app/models/user.rb index 65ecb33cd..3cf9900bd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -50,8 +50,8 @@ class User < ApplicationRecord devise :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable - belongs_to :account, inverse_of: :user, required: true - belongs_to :invite, counter_cache: :uses + belongs_to :account, inverse_of: :user + belongs_to :invite, counter_cache: :uses, optional: true accepts_nested_attributes_for :account has_many :applications, class_name: 'Doorkeeper::Application', as: :owner @@ -223,5 +223,6 @@ class User < ApplicationRecord def update_statistics! BootstrapTimelineWorker.perform_async(account_id) ActivityTracker.increment('activity:accounts:local') + UserMailer.welcome(self).deliver_later end end diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb index cdb284de8..87b0b2929 100644 --- a/app/views/layouts/mailer.text.erb +++ b/app/views/layouts/mailer.text.erb @@ -1,5 +1,5 @@ <%= yield %> --- -<%= t('application_mailer.signature', instance: site_hostname) %> +<%= t 'about.hosted_on', domain: site_hostname %> <%= t('application_mailer.settings', link: settings_preferences_url) %> diff --git a/app/views/user_mailer/welcome.html.haml b/app/views/user_mailer/welcome.html.haml new file mode 100644 index 000000000..0823efa1a --- /dev/null +++ b/app/views/user_mailer/welcome.html.haml @@ -0,0 +1,146 @@ +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.hero + .email-row + .col-6 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.text-center.padded + %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td + = image_tag full_pack_url('icon_done.svg'), alt: '' + + %h1= t 'user_mailer.welcome.title', name: @resource.account.username + %p.lead= t 'user_mailer.welcome.explanation' + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell + .email-row + .col-3 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.input-cell.text-center.padded-bottom + %h5= t 'user_mailer.welcome.full_handle' + %table.input{ align: 'center', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td= "@#{@resource.account.username}@#{@instance}" + .col-3 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.content-start + %p= t 'user_mailer.welcome.full_handle_hint', instance: @instance + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.content-start.border-top + .email-row + .col-4 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.padded + = t 'user_mailer.welcome.edit_profile_step' + .col-2 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell + %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.button-primary + = link_to settings_profile_url do + %span= t 'user_mailer.welcome.edit_profile_action' + %tr + %td.content-cell + .email-row + .col-4 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.padded + = t 'user_mailer.welcome.review_preferences_step' + .col-2 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell + %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.button-primary + = link_to settings_preferences_url do + %span= t 'user_mailer.welcome.review_preferences_action' + %tr + %td.content-cell.padded-bottom + .email-row + .col-4 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.padded + = t 'user_mailer.welcome.final_step' + .col-2 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell + %table.button.button-small{ align: 'left', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.button-primary + = link_to web_url do + %span= t 'user_mailer.welcome.final_action' + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.border-top + .email-row + .col-6 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.padded + %h5= t 'user_mailer.welcome.tips' + %ul + %li + %span= t 'user_mailer.welcome.tip_mobile_webapp' + %li + %span= t 'user_mailer.welcome.tip_bridge_html', bridge_url: 'https://bridge.joinmastodon.org' + %li + %span= t 'user_mailer.welcome.tip_following' + %li + %span= t 'user_mailer.welcome.tip_local_timeline', instance: @instance + %li + %span= t 'user_mailer.welcome.tip_federated_timeline' diff --git a/app/views/user_mailer/welcome.text.erb b/app/views/user_mailer/welcome.text.erb new file mode 100644 index 000000000..5bd0cab2a --- /dev/null +++ b/app/views/user_mailer/welcome.text.erb @@ -0,0 +1,30 @@ +<%= t 'user_mailer.welcome.title', name: @resource.account.username %> <%= t 'user_mailer.welcome.explanation' %> + +=== + +<%= t 'user_mailer.welcome.full_handle' %> (<%= "@#{@resource.account.username}@#{@instance}" %>) +<%= t 'user_mailer.welcome.full_handle_hint', instance: @instance %> + +--- + +<%= t 'user_mailer.welcome.edit_profile_step' %> + +=> <%= settings_profile_url %> + +<%= t 'user_mailer.welcome.review_preferences_step' %> + +=> <%= settings_preferences_url %> + +<%= t 'user_mailer.welcome.final_step' %> + +=> <%= web_url %> + +--- + +<%= t 'user_mailer.welcome.tips' %> + +* <%= t 'user_mailer.welcome.tip_mobile_webapp' %> +* <%= strip_tags(t('user_mailer.welcome.tip_bridge_html')) %> (https://bridge.joinmastodon.org) +* <%= t 'user_mailer.welcome.tip_following' %> +* <%= t 'user_mailer.welcome.tip_local_timeline', instance: @instance %> +* <%= t 'user_mailer.welcome.tip_federated_timeline' %> diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb index ae86e3dd2..4763856ac 100644 --- a/app/workers/activitypub/delivery_worker.rb +++ b/app/workers/activitypub/delivery_worker.rb @@ -3,7 +3,7 @@ class ActivityPub::DeliveryWorker include Sidekiq::Worker - sidekiq_options queue: 'push', retry: 8, dead: false + sidekiq_options queue: 'push', retry: 16, dead: false HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze diff --git a/config/application.rb b/config/application.rb index c1bf3cef2..ef97dbc06 100644 --- a/config/application.rb +++ b/config/application.rb @@ -19,6 +19,9 @@ require_relative '../lib/mastodon/redis_config' module Mastodon class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.1 + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 82e8e998a..eadeaef3e 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -140,7 +140,6 @@ ar: application_mailer: salutation: "%{name}،" settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}' - signature: إشعارات ماستدون من %{instance} view: 'View:' applications: created: تم إنشاء التطبيق بنجاح diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 13d0394a3..56a904895 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -26,7 +26,6 @@ bg: unfollow: Не следвай application_mailer: settings: 'Промяна на предпочитанията за e-mail: %{link}' - signature: Mastodon известия от %{instance} view: 'Преглед:' applications: invalid_url: Предоставеният URL е невалиден diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 5e30abaf5..1092da38d 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -340,7 +340,6 @@ ca: application_mailer: salutation: "%{name}," settings: 'Canvia les preferències de correu: %{link}' - signature: Notificacions de Mastodon des de %{instance} view: 'Vista:' applications: created: L'aplicació s'ha creat correctament diff --git a/config/locales/de.yml b/config/locales/de.yml index 39867e373..7d0cf6349 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -321,7 +321,6 @@ de: application_mailer: salutation: "%{name}," settings: 'E-Mail-Einstellungen ändern: %{link}' - signature: Mastodon-Benachrichtigungen von %{instance} view: 'Ansehen:' applications: created: Anwendung erstellt diff --git a/config/locales/en.yml b/config/locales/en.yml index bc1e98c56..7c3cd922b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -341,7 +341,6 @@ en: notification_preferences: Change e-mail preferences salutation: "%{name}," settings: 'Change e-mail preferences: %{link}' - signature: Mastodon notifications from %{instance} view: 'View:' view_profile: View Profile view_status: View status @@ -734,6 +733,25 @@ en: recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents. setup: Set up wrong_code: The entered code was invalid! Are server time and device time correct? + user_mailer: + welcome: + edit_profile_action: Setup profile + edit_profile_step: You can customize your profile by uploading an avatar, header, changing your display name and more. If you’d like to review new followers before they’re allowed to follow you, you can lock your account. + explanation: Here are some tips to get you started + final_action: Start posting + final_step: 'Start posting! Even without followers your public messages may be seen by others, for example on the local timeline and in hashtags. You may want to introduce yourself on the #introductions hashtag.' + full_handle: Your full handle + full_handle_hint: This is what you would tell your friends so they can message or follow you from another instance. + review_preferences_action: Change preferences + review_preferences_step: Make sure to set your preferences, such as which emails you'd like to receive, or what privacy level you’d like your posts to default to. If you don’t have motion sickness, you could choose to enable GIF autoplay. + subject: Welcome to Mastodon + tip_bridge_html: If you are coming from Twitter, you can find your friends on Mastodon by using the <a href="%{bridge_url}">bridge app</a>. It only works if they also used the bridge app though! + tip_federated_timeline: The federated timeline is a firehose view of the Mastodon network. But it only includes people your neighbours are subscribed to, so it's not complete. + tip_following: You follow your server's admin(s) by default. To find more interesting people, check the local and federated timelines. + tip_local_timeline: The local timeline is a firehose view of people on %{instance}. These are your immediate neighbours! + tip_mobile_webapp: If your mobile browser offers you to add Mastodon to your homescreen, you can receive push notifications. It acts like a native app in many ways! + tips: Tips + title: Welcome aboard, %{name}! users: invalid_email: The e-mail address is invalid invalid_otp_token: Invalid two-factor code diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 847299ac7..bc259957d 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -237,7 +237,6 @@ eo: subject: Nova raporto por %{instance} (#%{id}) application_mailer: settings: 'Ŝanĝi la retpoŝt-mesaĝajn preferojn: %{link}' - signature: Sciigoj de Mastodon el %{instance} view: 'Vidi:' applications: created: Aplikaĵo sukcesa kreis diff --git a/config/locales/es.yml b/config/locales/es.yml index d9084787d..7ee2876a9 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -332,7 +332,6 @@ es: application_mailer: salutation: "%{name}," settings: 'Cambiar preferencias de correo: %{link}' - signature: Notificaciones de Mastodon desde %{instance} view: 'Vista:' applications: created: Aplicación creada exitosamente diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 94d4e7594..c498c592c 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -334,7 +334,6 @@ fa: application_mailer: salutation: "%{name}،" settings: 'تغییر تنظیمات ایمیل: %{link}' - signature: اعلانهای ماستدون از %{instance} view: 'نمایش:' applications: created: برنامه با موفقیت ساخته شد diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 2da8427b8..f2ee28ba0 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -25,7 +25,6 @@ fi: unfollow: Lopeta seuraaminen application_mailer: settings: 'Muokkaa sähköpostiasetuksia: %{link}' - signature: Mastodon-ilmoituksia palvelimelta %{instance} view: 'Katso:' applications: invalid_url: Annettu URL on väärä diff --git a/config/locales/fr.yml b/config/locales/fr.yml index adcb11f18..09338fdfd 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -334,7 +334,6 @@ fr: application_mailer: salutation: "%{name}," settings: 'Changer les préférences courriel : %{link}' - signature: Notifications de Mastodon depuis %{instance} view: 'Voir :' applications: created: Application créée avec succès diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 55f717249..100e2954c 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -340,7 +340,6 @@ gl: application_mailer: salutation: "%{name}," settings: 'Mudar as preferencias de e-mail: %{link}' - signature: Notificacións Mastodon de %{instance} view: 'Vista:' applications: created: Creouse con éxito este aplicativo diff --git a/config/locales/he.yml b/config/locales/he.yml index 4b977ce1b..1f27dda7a 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -229,7 +229,6 @@ he: title: ניהול application_mailer: settings: 'שינוי הגדרות דוא"ל: %{link}' - signature: התראות מסטודון מקהילת %{instance} view: 'תצוגה:' applications: invalid_url: כתובת הקישורית אינה חוקית diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 581912420..a3c9aa436 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -26,7 +26,6 @@ hr: unfollow: Prestani slijediti application_mailer: settings: 'Promijeni e-mail postavke: %{link}' - signature: Mastodon notifikacije sa %{instance} view: 'Vidi:' applications: invalid_url: Uneseni link nije valjan diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 77551223f..586503a35 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -12,8 +12,6 @@ hu: people_who_follow: "%{name} követői" posts: Bejegyzések unfollow: Követés abbahagyása - application_mailer: - signature: "%{instance} Mastodon értesítései" auth: change_password: Jelszó változtatása didnt_get_confirmation: Nem kaptad meg a megerősítési lépéseket? diff --git a/config/locales/id.yml b/config/locales/id.yml index f3a6649d1..6e4d60fd8 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -151,7 +151,6 @@ id: title: Administrasi application_mailer: settings: 'Ubah pilihan email: %{link}' - signature: Notifikasi Mastodon dari %{instance} view: 'Tampilan:' applications: invalid_url: URL tidak sesuai diff --git a/config/locales/io.yml b/config/locales/io.yml index 4114e5231..db8214768 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -149,7 +149,6 @@ io: title: Administration application_mailer: settings: 'Chanjar la retpost-mesajala preferi: %{link}' - signature: Savigi di Mastodon de %{instance} view: 'Vidar:' applications: invalid_url: La URL donita ne esas valida diff --git a/config/locales/it.yml b/config/locales/it.yml index ec0209bc1..6ab57d2fc 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -26,7 +26,6 @@ it: unfollow: Non seguire più application_mailer: settings: 'Cambia le impostazioni per le e-mail: %{link}' - signature: Notifiche Mastodon da %{instance} view: 'Guarda:' applications: invalid_url: L'URL fornito non è valido diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 8b7b678c6..141b5141a 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -341,7 +341,6 @@ ja: notification_preferences: メール設定の変更 salutation: "%{name} さん" settings: 'メール設定の変更: %{link}' - signature: Mastodon %{instance} インスタンスからの通知 view: 'リンク:' view_profile: プロフィールを表示 view_status: トゥートを表示 diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 997dc4856..b254636f3 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -340,7 +340,6 @@ ko: application_mailer: notification_preferences: 메일 설정 변경 settings: '메일 설정을 변경: %{link}' - signature: Mastodon %{instance} 인스턴스로에서 알림 view: 'View:' view_profile: 프로필 보기 view_status: 게시물 보기 diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 600d5225d..973dc65d1 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -340,7 +340,6 @@ nl: application_mailer: salutation: "%{name}," settings: 'E-mailvoorkeuren wijzigen: %{link}' - signature: Mastodon-meldingen van %{instance} view: 'Bekijk:' applications: created: Aanmaken toepassing geslaagd diff --git a/config/locales/no.yml b/config/locales/no.yml index 57f8547fc..3b212932e 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -163,7 +163,6 @@ title: Administrasjon application_mailer: settings: 'Endre foretrukne e-postinnstillinger: %{link}' - signature: Mastodon-notiser fra %{instance} view: 'Se:' applications: invalid_url: Den oppgitte URLen er ugyldig diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 40387de70..beb5d1f87 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -340,7 +340,6 @@ oc: application_mailer: salutation: "%{name}," settings: 'Cambiar las preferéncias de corrièl : %{link}' - signature: Notificacion de Mastodon sus %{instance} view: 'Veire :' applications: created: Aplicacion ben creada diff --git a/config/locales/pl.yml b/config/locales/pl.yml index efb955b37..949099a71 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -342,7 +342,6 @@ pl: notification_preferences: Zmień ustawienia e-maili salutation: "%{name}," settings: 'Zmień ustawienia powiadamiania: %{link}' - signature: Powiadomienie Mastodona z instancji %{instance} view: 'Zobacz:' view_status: Wyświetl wpis applications: @@ -740,6 +739,25 @@ pl: recovery_instructions_html: Jeżeli kiedykolwiek utracisz dostęp do telefonu, możesz wykorzystać jeden z kodów zapasowych, aby odzyskać dostęp do konta. <strong>Trzymaj je w bezpiecznym miejscu</strong>. Na przykład, wydrukuj je i przechowuj z ważnymi dokumentami. setup: Skonfiguruj wrong_code: Wprowadzony kod jest niepoprawny! Czy czas serwera i urządzenia jest poprawny? + user_mailer: + welcome: + edit_profile_action: Skonfiguruj profil + edit_profile_step: Możesz dostować profil wysyłając awatar, obraz nagłówka, zmieniając wyświetlaną nazwę i wiele więcej. Jeżeli chcesz, możesz zablokować konto, aby kontrolować, kto może Cię śledzić. + explanation: Kilka wskazówek, które pomogą Ci rozpocząć + final_action: Zacznij pisać + final_step: 'Zacznij tworzyć! Nawet jeżeli nikt Cię nie śledzi, Twoje publiczne wiadomości będą widziane przez innych, na przykład na lokalnej osi czasu i w hashtagach. Możesz też utworzyć wpis wprowadzający używając hashtagu #introductions.' + full_handle: Twój pełny adres + full_handle_hint: Ten adres możesz podać znajomym, aby mogli skontaktować się z Tobą lub zacząć śledzić z innej instancji. + review_preferences_action: Zmień ustawienia + review_preferences_step: Upewnij się, że zmieniłeś ustawienia, takie jak maile, które chciałbyś otrzymywać lub domyślne opcje prywatności. Jeżeli nie masz choroby lokomocyjnej, możesz włączyć automatyczne odtwarzanie animacji GIF. + subject: Witaj w Mastodonie + tip_bridge_html: Jeżeli przybywasz z Twittera, możesz znaleźć znajomych na Mastodonie używając <a href="%{bridge_url}">aplikacji mostku</a>. Działa to tylko, jeżeli oni również z niej korzystali! + tip_federated_timeline: Oś czasu federacji przedstawia całą sieć Mastodona. Wyświetla tylko wpisy osób, które śledzą użytkownicy Twojej instancji, więc nie jest kompletna. + tip_following: Domyślnie śledzisz administratora/ów swojej instancji. Aby znaleźć więcej ciekawych ludzi, zajrzyj na lokalną i federalną oś czasu. + tip_local_timeline: Lokalna oś czasu przedstawia osoby z %{instance}. To Twoi najbliżsi sąsiedzi! + tip_mobile_webapp: Jeżeli Twoja przeglądarka pozwala na dodanie Mastodona na ekran główny, będziesz otrzymywać natychmiastowe powiadomienia. Działa to prawie jak natywna aplikacja! + tips: Wskazówki + title: Witaj na pokładzie, %{name}! users: invalid_email: Adres e-mail jest niepoprawny invalid_otp_token: Kod uwierzytelniający jest niepoprawny diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 39683bd88..c2830b754 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -340,7 +340,6 @@ pt-BR: application_mailer: salutation: "%{name}," settings: 'Mudar e-mail de preferência: %{link}' - signature: Notificações do Mastodon de %{instance} view: 'Visualizar:' applications: created: Aplicação criada com sucesso diff --git a/config/locales/pt.yml b/config/locales/pt.yml index c0056af4f..618373b91 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -328,7 +328,6 @@ pt: application_mailer: salutation: "%{name}," settings: 'Alterar preferências de email: %{link}' - signature: notificações Mastodon do %{instance} view: 'Ver:' applications: created: Aplicação criada com sucesso diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 6e63aadda..842fd7d54 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -342,7 +342,6 @@ ru: notification_preferences: Изменить настройки e-mail salutation: "%{name}," settings: 'Изменить настройки e-mail: %{link}' - signature: Уведомления Mastodon от %{instance} view: 'Просмотр:' view_status: Просмотреть статус applications: diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 964a82d64..ac80e81ec 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -336,7 +336,6 @@ sr-Latn: application_mailer: salutation: "%{name}," settings: 'Promeni podešavanja e-pošte: %{link}' - signature: Mastodont obaveštenje sa instance %{instance} view: 'Pogledaj:' applications: created: Aplikacija uspešno napravljena diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 57ccf2008..755396828 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -336,7 +336,6 @@ sr: application_mailer: salutation: "%{name}," settings: 'Промени подешавања е-поште: %{link}' - signature: Мастодонт обавештење са инстанце %{instance} view: 'Погледај:' applications: created: Апликација успешно направљена diff --git a/config/locales/sv.yml b/config/locales/sv.yml index ebb6d6595..b6595cb0d 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -272,7 +272,6 @@ sv: application_mailer: salutation: "%{name}," settings: 'Change e-mail preferences: %{link}' - signature: Mastodon meddelande från %{instance} view: 'Granska:' applications: created: Ansökan är framgångsrikt skapad diff --git a/config/locales/th.yml b/config/locales/th.yml index 2db3aee8a..737b3aa95 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -153,7 +153,6 @@ th: title: แอดมิน application_mailer: settings: 'เปลี่ยนอีเมล์ preferences: %{link}' - signature: ฟอร์มการแจ้งเตือนแมสโทดอน %{instance} view: 'วิว:' applications: invalid_url: URL ที่ระบุไม่ถูกตั้ง diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 6aff78fa1..23b4d7a24 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -152,7 +152,6 @@ tr: title: Yönetim application_mailer: settings: 'E-mail tercihlerini değiştir: %{link}' - signature: "%{instance} sunucusundan Mastodon bildirimleri" view: 'Görüntüle:' applications: invalid_url: Verilen URL geçerli değil diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 995a682a7..0ddfa9190 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -143,7 +143,6 @@ uk: title: Адміністрування application_mailer: settings: 'Змінити налаштування email: %{link}' - signature: Сповіщення Mastodon від %{instance} view: 'Перегляд:' applications: invalid_url: Введена URL неправильна diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 14382331b..25cfe5a8a 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -339,7 +339,6 @@ zh-CN: notification_preferences: 更改电子邮件首选项 salutation: "%{name}:" settings: 使用此链接更改你的电子邮件首选项:%{link} - signature: 这是一封来自 %{instance} 的 Mastodon 电子邮件通知。 view: 点此链接查看详情: view_profile: 查看个人资料页 view_status: 查看嘟文 diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 8ff6d1bf8..ed73b7244 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -152,7 +152,6 @@ zh-HK: title: 管理 application_mailer: settings: 修改電郵設定︰%{link} - signature: 來自 %{instance} 的 Mastodon 通知 view: 進入瀏覽︰ applications: invalid_url: 所提供的網址不正確 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index e73dbf9cc..bd9f85840 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -123,7 +123,6 @@ zh-TW: title: 管理介面 application_mailer: settings: 修改信箱設定︰ %{link} - signature: 來自 %{instance} 的 Mastodon 通知 view: 進入瀏覽︰ applications: invalid_url: 網址不正確 diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index 38dbed982..486c035de 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -341,6 +341,15 @@ namespace :mastodon do LinkCrawlWorker.push_bulk status_ids end + desc 'Remove all home feed regeneration markers' + task remove_regeneration_markers: :environment do + keys = Redis.current.keys('account:*:regeneration') + + Redis.current.pipelined do + keys.each { |key| Redis.current.del(key) } + end + end + desc 'Check every known remote account and delete those that no longer exist in origin' task purge_removed_accounts: :environment do prepare_for_options! diff --git a/spec/controllers/concerns/user_tracking_concern_spec.rb b/spec/controllers/concerns/user_tracking_concern_spec.rb index d08095ef8..1e5620221 100644 --- a/spec/controllers/concerns/user_tracking_concern_spec.rb +++ b/spec/controllers/concerns/user_tracking_concern_spec.rb @@ -69,6 +69,12 @@ describe ApplicationController, type: :controller do expect(RegenerationWorker).to have_received(:perform_async) end + it 'sets the regeneration marker to expire' do + allow(RegenerationWorker).to receive(:perform_async) + get :show + expect(Redis.current.ttl("account:#{user.account_id}:regeneration")).to be >= 0 + end + it 'regenerates feed when sign in is older than two weeks' do get :show diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 6ed0090f4..8d2a9368d 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -29,4 +29,9 @@ class UserMailerPreview < ActionMailer::Preview def reset_password_instructions UserMailer.reset_password_instructions(User.first, 'spec') end + + # Preview this email at http://localhost:3000/rails/mailers/user_mailer/welcome + def welcome + UserMailer.welcome(User.first) + end end |