diff --git a/.ruby-version b/.ruby-version
index 8e8299dcc06..437459cd94c 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.4.2
+2.5.0
diff --git a/.travis.yml b/.travis.yml
index 59d495c4339..496315558b2 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 d455116da62..6d8465ddc6f 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 268bf3ad80b..dc72851b367 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 cede4aaf70e..87298fc7790 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 1e313294111..a2510e55fea 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 2b238333092..00000000000
Binary files a/app/javascript/images/elephant-friend-1.png and /dev/null differ
diff --git a/app/javascript/images/elephant_ui_plane.svg b/app/javascript/images/elephant_ui_plane.svg
new file mode 100644
index 00000000000..a2624d170e2
--- /dev/null
+++ b/app/javascript/images/elephant_ui_plane.svg
@@ -0,0 +1 @@
+
\ 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 00000000000..446af14d997
--- /dev/null
+++ b/app/javascript/images/icon_done.svg
@@ -0,0 +1,4 @@
+
\ 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 a1fb642a003..00000000000
Binary files a/app/javascript/images/mastodon-ui.png and /dev/null differ
diff --git a/app/javascript/images/wave-compose-standalone.png b/app/javascript/images/wave-compose-standalone.png
deleted file mode 100644
index 287ee639b34..00000000000
Binary files a/app/javascript/images/wave-compose-standalone.png and /dev/null differ
diff --git a/app/javascript/images/wave-drawer.png b/app/javascript/images/wave-drawer.png
deleted file mode 100644
index ca9f9e1d85d..00000000000
Binary files a/app/javascript/images/wave-drawer.png and /dev/null differ
diff --git a/app/javascript/images/wave-modal.png b/app/javascript/images/wave-modal.png
deleted file mode 100644
index 88818a6d78a..00000000000
Binary files a/app/javascript/images/wave-modal.png and /dev/null differ
diff --git a/app/javascript/mastodon/actions/onboarding.js b/app/javascript/mastodon/actions/onboarding.js
deleted file mode 100644
index a161c50efed..00000000000
--- 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 d1710445b53..8ae3b727af9 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 5839ba40a64..dbfb46ee747 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 54673e223e5..00000000000
--- 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 }) => (
-
-
-
-
-
-
-
@{acct}@{domain} }} />
-
-
-);
-
-PageOne.propTypes = {
- acct: PropTypes.string.isRequired,
- domain: PropTypes.string.isRequired,
-};
-
-const PageTwo = ({ myAccount }) => (
-
-);
-
-PageTwo.propTypes = {
- myAccount: ImmutablePropTypes.map.isRequired,
-};
-
-const PageThree = ({ myAccount }) => (
-
-
-
-
#illustration, introductions: #introductions }} />
-
-
-);
-
-PageThree.propTypes = {
- myAccount: ImmutablePropTypes.map.isRequired,
-};
-
-const PageFour = ({ domain, intl }) => (
-
-);
-
-PageFour.propTypes = {
- domain: PropTypes.string.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-const PageSix = ({ admin, domain }) => {
- let adminSection = '';
-
- if (admin) {
- adminSection = (
-
- @{admin.get('acct')} }} />
-
- }} />
-
- );
- }
-
- return (
-
-
- {adminSection}
-
GitHub }} />
-
}} />
-
-
- );
-};
-
-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 = [
- ,
- ,
- ,
- ,
- ,
- ];
- };
-
- 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 ? (
-
- ) : (
-
- );
-
- return (
-
-
- {pages.map((page, i) => {
- const className = classNames('onboarding-modal__page__wrapper', {
- 'onboarding-modal__page__wrapper--active': i === currentIndex,
- });
- return (
- {page}
- );
- })}
-
-
-
-
-
-
-
-
- {pages.map((_, i) => {
- const className = classNames('onboarding-modal__dot', {
- active: i === currentIndex,
- });
- return (
-
- );
- })}
-
-
-
- {nextOrDoneBtn}
-
-
-
- );
- }
-
-}
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index d6586680b8f..a03c4cefd8e 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 7b7b5470fc0..9a10bcc5938 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 fd6665f65c1..30004017378 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 e6422b2ea5a..b3bcc9209c5 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 d13a18ad7e9..89d4b2ebaea 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,') 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 a17476ccb59..ceb79bbb995 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,') 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 820189d29c9..0f9e4f26303 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 a7efa73c1c7..4104f6cd26d 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 c75ea028eba..6df9668d5a5 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 35810b6c2a2..abcc923b315 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 4e950fbf791..c437c8ee872 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 284abfe4c98..441e6bca308 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 248cdfe6e41..272eb81afd7 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 c38838f2a84..2b1271f31de 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 3fb665afc74..f953b8e3e15 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 ebf6959cef7..bd6c4a0b9ff 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 091fb3044e6..ba88435bfd0 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 6907c1f1d8f..b87a3b72250 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 be85c3b878e..a2ec7e84a27 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 25393259035..da46cf03250 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 368ccef3add..25b7fd0857c 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 14533e6a9e1..f864bf8e151 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 ca984641a5a..da4787179bd 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 97696352888..733f89cf794 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 :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'
- 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 :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 c36f8db0a87..f55fb6d3eef 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 1d4ebca021e..d364f03dfdd 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 cb18b070567..e927fb9ddc5 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 a72c19750eb..d3a98d8bd30 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 7f2eeab91e5..ea11731607c 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 65ecb33cd37..3cf9900bd78 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 cdb284de831..87b0b2929c5 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 00000000000..0823efa1ae6
--- /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 00000000000..5bd0cab2a58
--- /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 ae86e3dd2e8..4763856ac36 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 c1bf3cef2fa..ef97dbc0677 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 82e8e998a08..eadeaef3eae 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 13d0394a386..56a90489573 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 5e30abaf578..1092da38d57 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 39867e37371..7d0cf63495e 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 bc1e98c56ae..7c3cd922b48 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. Keep the recovery codes safe. 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 bridge app. 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 847299ac7ba..bc259957dcc 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 d9084787dc8..7ee2876a903 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 94d4e759486..c498c592c05 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 2da8427b889..f2ee28ba0ed 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 adcb11f1825..09338fdfdfb 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 55f71724966..100e2954ca5 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 4b977ce1b67..1f27dda7a5c 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 581912420de..a3c9aa4368f 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 77551223f37..586503a35a7 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 f3a6649d1cb..6e4d60fd888 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 4114e523121..db821476836 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 ec0209bc196..6ab57d2fcc9 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 8b7b678c6ab..141b5141a63 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 997dc4856be..b254636f3c2 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 600d5225dac..973dc65d1ba 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 57f8547fcbd..3b212932e8e 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 40387de7035..beb5d1f87d2 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 efb955b37cf..949099a712c 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. Trzymaj je w bezpiecznym miejscu. 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 aplikacji mostku. 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 39683bd8850..c2830b75438 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 c0056af4fc7..618373b91e5 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 6e63aaddacc..842fd7d5440 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 964a82d6431..ac80e81ec7a 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 57ccf2008c8..75539682889 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 ebb6d6595da..b6595cb0d98 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 2db3aee8a48..737b3aa9592 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 6aff78fa169..23b4d7a2447 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 995a682a7cc..0ddfa919060 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 14382331bf1..25cfe5a8a87 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 8ff6d1bf8c5..ed73b724421 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 e73dbf9ccf2..bd9f8584023 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 38dbed982a6..486c035de05 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 d08095ef827..1e562022119 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 6ed0090f41c..8d2a9368df4 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