Merge remote-tracking branch 'origin/master' into merge-upstream
Conflicts: app/javascript/styles/mastodon/components.scss app/javascript/styles/mastodon/modal.scsspull/342/head
|
@ -1 +1 @@
|
||||||
2.4.2
|
2.5.0
|
||||||
|
|
|
@ -40,20 +40,20 @@ addons:
|
||||||
- yarn
|
- yarn
|
||||||
|
|
||||||
rvm:
|
rvm:
|
||||||
- 2.3.4
|
|
||||||
- 2.4.2
|
- 2.4.2
|
||||||
|
- 2.5.0
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- redis-server
|
- redis-server
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- gem update --system
|
||||||
- nvm install
|
- nvm install
|
||||||
- bundle install --path=vendor/bundle --without development production --retry=3 --jobs=16
|
- bundle install --path=vendor/bundle --without development production --retry=3 --jobs=16
|
||||||
- yarn install
|
- yarn install
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- bundle exec rake parallel:create parallel:load_schema parallel:prepare
|
- ./bin/rails parallel:create parallel:load_schema parallel:prepare assets:precompile
|
||||||
- bundle exec rails assets:precompile
|
|
||||||
- ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++"
|
- ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -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" \
|
LABEL maintainer="https://github.com/tootsuite/mastodon" \
|
||||||
description="A GNU Social-compatible microblogging server"
|
description="A GNU Social-compatible microblogging server"
|
||||||
|
@ -40,6 +40,7 @@ RUN apk -U upgrade \
|
||||||
protobuf \
|
protobuf \
|
||||||
su-exec \
|
su-exec \
|
||||||
tini \
|
tini \
|
||||||
|
tzdata \
|
||||||
&& update-ca-certificates \
|
&& update-ca-certificates \
|
||||||
&& mkdir -p /tmp/src /opt \
|
&& 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" \
|
&& wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
|
||||||
|
|
4
Gemfile
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
ruby '>= 2.3.0', '< 2.5.0'
|
ruby '>= 2.3.0', '< 2.6.0'
|
||||||
|
|
||||||
gem 'pkg-config', '~> 1.2'
|
gem 'pkg-config', '~> 1.2'
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.5'
|
gem 'charlock_holmes', '~> 0.7.5'
|
||||||
gem 'iso-639'
|
gem 'iso-639'
|
||||||
gem 'cld3', '~> 3.2.0'
|
gem 'cld3', '~> 3.2.0'
|
||||||
gem 'devise', '~> 4.3'
|
gem 'devise', '~> 4.4'
|
||||||
gem 'devise-two-factor', '~> 3.0'
|
gem 'devise-two-factor', '~> 3.0'
|
||||||
gem 'doorkeeper', '~> 4.2'
|
gem 'doorkeeper', '~> 4.2'
|
||||||
gem 'fast_blank', '~> 1.0'
|
gem 'fast_blank', '~> 1.0'
|
||||||
|
|
|
@ -110,7 +110,7 @@ GEM
|
||||||
activesupport
|
activesupport
|
||||||
charlock_holmes (0.7.5)
|
charlock_holmes (0.7.5)
|
||||||
chunky_png (1.3.8)
|
chunky_png (1.3.8)
|
||||||
cld3 (3.2.1)
|
cld3 (3.2.2)
|
||||||
ffi (>= 1.1.0, < 1.10.0)
|
ffi (>= 1.1.0, < 1.10.0)
|
||||||
climate_control (0.2.0)
|
climate_control (0.2.0)
|
||||||
cocaine (0.5.8)
|
cocaine (0.5.8)
|
||||||
|
@ -125,7 +125,7 @@ GEM
|
||||||
css_parser (1.6.0)
|
css_parser (1.6.0)
|
||||||
addressable
|
addressable
|
||||||
debug_inspector (0.0.3)
|
debug_inspector (0.0.3)
|
||||||
devise (4.3.0)
|
devise (4.4.0)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0, < 5.2)
|
railties (>= 4.1.0, < 5.2)
|
||||||
|
@ -569,7 +569,7 @@ DEPENDENCIES
|
||||||
charlock_holmes (~> 0.7.5)
|
charlock_holmes (~> 0.7.5)
|
||||||
cld3 (~> 3.2.0)
|
cld3 (~> 3.2.0)
|
||||||
climate_control (~> 0.2)
|
climate_control (~> 0.2)
|
||||||
devise (~> 4.3)
|
devise (~> 4.4)
|
||||||
devise-two-factor (~> 3.0)
|
devise-two-factor (~> 3.0)
|
||||||
doorkeeper (~> 4.2)
|
doorkeeper (~> 4.2)
|
||||||
dotenv-rails (~> 2.2)
|
dotenv-rails (~> 2.2)
|
||||||
|
@ -651,7 +651,7 @@ DEPENDENCIES
|
||||||
webpush
|
webpush
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.4.2p198
|
ruby 2.5.0p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.16.1
|
1.16.1
|
||||||
|
|
|
@ -32,7 +32,7 @@ module UserTrackingConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def regenerate_feed!
|
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)
|
RegenerationWorker.perform_async(current_user.account_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Before Width: | Height: | Size: 142 KiB |
After Width: | Height: | Size: 11 KiB |
|
@ -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>
|
After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 5.1 KiB |
|
@ -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());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import configureStore from '../store/configureStore';
|
import configureStore from '../store/configureStore';
|
||||||
import { showOnboardingOnce } from '../actions/onboarding';
|
|
||||||
import { BrowserRouter, Route } from 'react-router-dom';
|
import { BrowserRouter, Route } from 'react-router-dom';
|
||||||
import { ScrollContext } from 'react-router-scroll-4';
|
import { ScrollContext } from 'react-router-scroll-4';
|
||||||
import UI from '../features/ui';
|
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';
|
const handlerUrl = window.location.protocol + '//' + window.location.host + '/intent?uri=%s';
|
||||||
window.setTimeout(() => navigator.registerProtocolHandler('web+mastodon', handlerUrl, 'Mastodon'), 5 * 60 * 1000);
|
window.setTimeout(() => navigator.registerProtocolHandler('web+mastodon', handlerUrl, 'Mastodon'), 5 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(showOnboardingOnce());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import VideoModal from './video_modal';
|
||||||
import BoostModal from './boost_modal';
|
import BoostModal from './boost_modal';
|
||||||
import ConfirmationModal from './confirmation_modal';
|
import ConfirmationModal from './confirmation_modal';
|
||||||
import {
|
import {
|
||||||
OnboardingModal,
|
|
||||||
MuteModal,
|
MuteModal,
|
||||||
ReportModal,
|
ReportModal,
|
||||||
EmbedModal,
|
EmbedModal,
|
||||||
|
@ -18,7 +17,6 @@ import {
|
||||||
|
|
||||||
const MODAL_COMPONENTS = {
|
const MODAL_COMPONENTS = {
|
||||||
'MEDIA': () => Promise.resolve({ default: MediaModal }),
|
'MEDIA': () => Promise.resolve({ default: MediaModal }),
|
||||||
'ONBOARDING': OnboardingModal,
|
|
||||||
'VIDEO': () => Promise.resolve({ default: VideoModal }),
|
'VIDEO': () => Promise.resolve({ default: VideoModal }),
|
||||||
'BOOST': () => Promise.resolve({ default: BoostModal }),
|
'BOOST': () => Promise.resolve({ default: BoostModal }),
|
||||||
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
||||||
|
|
|
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -94,10 +94,6 @@ export function Mutes () {
|
||||||
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
|
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnboardingModal () {
|
|
||||||
return import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MuteModal () {
|
export function MuteModal () {
|
||||||
return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
|
return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ const normalizeTimeline = (state, timeline, statuses, next, isPartial) => {
|
||||||
mMap.set('loaded', true);
|
mMap.set('loaded', true);
|
||||||
mMap.set('isLoading', false);
|
mMap.set('isLoading', false);
|
||||||
if (!hadNext) mMap.set('next', next);
|
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);
|
mMap.set('isPartial', isPartial);
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
@import 'mastodon/reset';
|
@import 'mastodon/reset';
|
||||||
@import 'mastodon/basics';
|
@import 'mastodon/basics';
|
||||||
@import 'mastodon/modal';
|
|
||||||
@import 'mastodon/containers';
|
@import 'mastodon/containers';
|
||||||
@import 'mastodon/lists';
|
@import 'mastodon/lists';
|
||||||
@import 'mastodon/footer';
|
@import 'mastodon/footer';
|
||||||
|
@ -15,7 +14,9 @@
|
||||||
@import 'mastodon/forms';
|
@import 'mastodon/forms';
|
||||||
@import 'mastodon/accounts';
|
@import 'mastodon/accounts';
|
||||||
@import 'mastodon/stream_entries';
|
@import 'mastodon/stream_entries';
|
||||||
|
@import 'mastodon/boost';
|
||||||
@import 'mastodon/components';
|
@import 'mastodon/components';
|
||||||
|
@import 'mastodon/modal';
|
||||||
@import 'mastodon/emoji_picker';
|
@import 'mastodon/emoji_picker';
|
||||||
@import 'mastodon/about';
|
@import 'mastodon/about';
|
||||||
@import 'mastodon/tables';
|
@import 'mastodon/tables';
|
||||||
|
|
|
@ -228,6 +228,13 @@ h3 {
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 21px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: lighten($ui-base-color, 34%);
|
||||||
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
td {
|
td {
|
||||||
background: darken($ui-base-color, 8%);
|
background: darken($ui-base-color, 8%);
|
||||||
|
@ -356,6 +363,19 @@ h3 {
|
||||||
font-weight: 500 !important;
|
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 {
|
.button-default {
|
||||||
|
@ -379,6 +399,14 @@ h3 {
|
||||||
padding-right: 16px;
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.padded-bottom {
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin-bottom {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.hero-icon {
|
.hero-icon {
|
||||||
width: 64px;
|
width: 64px;
|
||||||
|
|
||||||
|
@ -463,6 +491,22 @@ h3 {
|
||||||
border-top: 1px solid lighten($ui-base-color, 8%);
|
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) {
|
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) {
|
||||||
body {
|
body {
|
||||||
min-height: 1024px !important;
|
min-height: 1024px !important;
|
||||||
|
|
|
@ -1762,7 +1762,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 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;
|
box-sizing: border-box;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1777,7 +1777,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mastodon {
|
> .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;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2154,10 +2154,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import 'boost';
|
|
||||||
|
|
||||||
.no-reduce-motion button.icon-button i.fa-retweet {
|
.no-reduce-motion button.icon-button i.fa-retweet {
|
||||||
|
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
transition: background-position 0.9s steps(10);
|
transition: background-position 0.9s steps(10);
|
||||||
|
@ -3303,7 +3300,6 @@
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.onboarding-modal,
|
|
||||||
.error-modal,
|
.error-modal,
|
||||||
.embed-modal {
|
.embed-modal {
|
||||||
background: $ui-secondary-color;
|
background: $ui-secondary-color;
|
||||||
|
@ -3314,26 +3310,6 @@
|
||||||
flex-direction: column;
|
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 {
|
.error-modal__body {
|
||||||
height: 80vh;
|
height: 80vh;
|
||||||
width: 80vw;
|
width: 80vw;
|
||||||
|
@ -3367,23 +3343,6 @@
|
||||||
text-align: center;
|
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 {
|
.error-modal__footer {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
background: darken($ui-secondary-color, 8%);
|
background: darken($ui-secondary-color, 8%);
|
||||||
|
@ -3394,7 +3353,6 @@
|
||||||
min-width: 33px;
|
min-width: 33px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.onboarding-modal__nav,
|
|
||||||
.error-modal__nav {
|
.error-modal__nav {
|
||||||
color: darken($ui-secondary-color, 34%);
|
color: darken($ui-secondary-color, 34%);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -3410,11 +3368,6 @@
|
||||||
&:active {
|
&:active {
|
||||||
color: darken($ui-secondary-color, 38%);
|
color: darken($ui-secondary-color, 38%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.onboarding-modal__done,
|
|
||||||
&.onboarding-modal__next {
|
|
||||||
color: $ui-highlight-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3422,6 +3375,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
.onboarding-modal__dots {
|
.onboarding-modal__dots {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -3632,6 +3586,8 @@
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> origin/master
|
||||||
.boost-modal,
|
.boost-modal,
|
||||||
.confirmation-modal,
|
.confirmation-modal,
|
||||||
.report-modal,
|
.report-modal,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.modal-layout {
|
.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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
@ -15,6 +15,6 @@
|
||||||
> * {
|
> * {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
max-height: 235px;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,12 +69,13 @@ class ActivityPub::Activity
|
||||||
def distribute(status)
|
def distribute(status)
|
||||||
crawl_links(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
|
# Only continue if the status is supposed to have
|
||||||
# arrived in real-time
|
# arrived in real-time
|
||||||
return unless @options[:override_timestamps]
|
return unless @options[:override_timestamps]
|
||||||
|
|
||||||
notify_about_reblog(status) if reblog_of_local_account?(status)
|
|
||||||
notify_about_mentions(status)
|
|
||||||
distribute_to_followers(status)
|
distribute_to_followers(status)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -54,4 +54,15 @@ class UserMailer < Devise::Mailer
|
||||||
mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')
|
mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -104,7 +104,7 @@ class Account < ApplicationRecord
|
||||||
has_many :lists, through: :list_accounts
|
has_many :lists, through: :list_accounts
|
||||||
|
|
||||||
# Account migrations
|
# 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 :remote, -> { where.not(domain: nil) }
|
||||||
scope :local, -> { where(domain: nil) }
|
scope :local, -> { where(domain: nil) }
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
class AccountDomainBlock < ApplicationRecord
|
class AccountDomainBlock < ApplicationRecord
|
||||||
include Paginable
|
include Paginable
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
validates :domain, presence: true, uniqueness: { scope: :account_id }
|
validates :domain, presence: true, uniqueness: { scope: :account_id }
|
||||||
|
|
||||||
after_create :remove_blocking_cache
|
after_create :remove_blocking_cache
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
class Admin::ActionLog < ApplicationRecord
|
class Admin::ActionLog < ApplicationRecord
|
||||||
serialize :recorded_changes
|
serialize :recorded_changes
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :target, required: true, polymorphic: true
|
belongs_to :target, polymorphic: true
|
||||||
|
|
||||||
default_scope -> { order('id desc') }
|
default_scope -> { order('id desc') }
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
class Block < ApplicationRecord
|
class Block < ApplicationRecord
|
||||||
include Paginable
|
include Paginable
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :target_account, class_name: 'Account', required: true
|
belongs_to :target_account, class_name: 'Account'
|
||||||
|
|
||||||
validates :account_id, uniqueness: { scope: :target_account_id }
|
validates :account_id, uniqueness: { scope: :target_account_id }
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class ConversationMute < ApplicationRecord
|
class ConversationMute < ApplicationRecord
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :conversation, required: true
|
belongs_to :conversation
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
class Favourite < ApplicationRecord
|
class Favourite < ApplicationRecord
|
||||||
include Paginable
|
include Paginable
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :favourites, required: true
|
belongs_to :account, inverse_of: :favourites
|
||||||
belongs_to :status, inverse_of: :favourites, counter_cache: true, required: true
|
belongs_to :status, inverse_of: :favourites, counter_cache: true
|
||||||
|
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
has_one :notification, as: :activity, dependent: :destroy
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,11 @@
|
||||||
class Follow < ApplicationRecord
|
class Follow < ApplicationRecord
|
||||||
include Paginable
|
include Paginable
|
||||||
|
|
||||||
belongs_to :account, counter_cache: :following_count, required: true
|
belongs_to :account, counter_cache: :following_count
|
||||||
|
|
||||||
belongs_to :target_account,
|
belongs_to :target_account,
|
||||||
class_name: 'Account',
|
class_name: 'Account',
|
||||||
counter_cache: :followers_count,
|
counter_cache: :followers_count
|
||||||
required: true
|
|
||||||
|
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
has_one :notification, as: :activity, dependent: :destroy
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
class FollowRequest < ApplicationRecord
|
class FollowRequest < ApplicationRecord
|
||||||
include Paginable
|
include Paginable
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :target_account, class_name: 'Account', required: true
|
belongs_to :target_account, class_name: 'Account'
|
||||||
|
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
has_one :notification, as: :activity, dependent: :destroy
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Import < ApplicationRecord
|
||||||
|
|
||||||
self.inheritance_column = false
|
self.inheritance_column = false
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
|
|
||||||
enum type: [:following, :blocking, :muting]
|
enum type: [:following, :blocking, :muting]
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class Invite < ApplicationRecord
|
class Invite < ApplicationRecord
|
||||||
belongs_to :user, required: true
|
belongs_to :user
|
||||||
has_many :users, inverse_of: :invite
|
has_many :users, inverse_of: :invite
|
||||||
|
|
||||||
scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) }
|
scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) }
|
||||||
|
|
|
@ -15,7 +15,7 @@ class List < ApplicationRecord
|
||||||
|
|
||||||
PER_ACCOUNT_LIMIT = 50
|
PER_ACCOUNT_LIMIT = 50
|
||||||
|
|
||||||
belongs_to :account
|
belongs_to :account, optional: true
|
||||||
|
|
||||||
has_many :list_accounts, inverse_of: :list, dependent: :destroy
|
has_many :list_accounts, inverse_of: :list, dependent: :destroy
|
||||||
has_many :accounts, through: :list_accounts
|
has_many :accounts, through: :list_accounts
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class ListAccount < ApplicationRecord
|
class ListAccount < ApplicationRecord
|
||||||
belongs_to :list, required: true
|
belongs_to :list
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :follow, required: true
|
belongs_to :follow
|
||||||
|
|
||||||
validates :account_id, uniqueness: { scope: :list_id }
|
validates :account_id, uniqueness: { scope: :list_id }
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,8 @@ class MediaAttachment < ApplicationRecord
|
||||||
},
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :media_attachments
|
belongs_to :account, inverse_of: :media_attachments, optional: true
|
||||||
belongs_to :status, inverse_of: :media_attachments
|
belongs_to :status, inverse_of: :media_attachments, optional: true
|
||||||
|
|
||||||
has_attached_file :file,
|
has_attached_file :file,
|
||||||
styles: ->(f) { file_styles f },
|
styles: ->(f) { file_styles f },
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class Mention < ApplicationRecord
|
class Mention < ApplicationRecord
|
||||||
belongs_to :account, inverse_of: :mentions, required: true
|
belongs_to :account, inverse_of: :mentions
|
||||||
belongs_to :status, required: true
|
belongs_to :status
|
||||||
|
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
has_one :notification, as: :activity, dependent: :destroy
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
class Mute < ApplicationRecord
|
class Mute < ApplicationRecord
|
||||||
include Paginable
|
include Paginable
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :target_account, class_name: 'Account', required: true
|
belongs_to :target_account, class_name: 'Account'
|
||||||
|
|
||||||
validates :account_id, uniqueness: { scope: :target_account_id }
|
validates :account_id, uniqueness: { scope: :target_account_id }
|
||||||
|
|
||||||
|
|
|
@ -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
|
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 :account, optional: true
|
||||||
belongs_to :from_account, class_name: 'Account'
|
belongs_to :from_account, class_name: 'Account', optional: true
|
||||||
belongs_to :activity, polymorphic: true
|
belongs_to :activity, polymorphic: true, optional: true
|
||||||
|
|
||||||
belongs_to :mention, foreign_type: 'Mention', 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'
|
belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', optional: true
|
||||||
belongs_to :follow, foreign_type: 'Follow', foreign_key: 'activity_id'
|
belongs_to :follow, foreign_type: 'Follow', foreign_key: 'activity_id', optional: true
|
||||||
belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id'
|
belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id', optional: true
|
||||||
belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id'
|
belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id', optional: true
|
||||||
|
|
||||||
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
|
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
|
||||||
validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
|
validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
class Report < ApplicationRecord
|
class Report < ApplicationRecord
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
belongs_to :target_account, class_name: '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 :unresolved, -> { where(action_taken: false) }
|
||||||
scope :resolved, -> { where(action_taken: true) }
|
scope :resolved, -> { where(action_taken: true) }
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class SessionActivation < ApplicationRecord
|
class SessionActivation < ApplicationRecord
|
||||||
belongs_to :user, inverse_of: :session_activations, required: true
|
belongs_to :user, inverse_of: :session_activations
|
||||||
belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy
|
belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy, optional: true
|
||||||
belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy
|
belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy, optional: true
|
||||||
|
|
||||||
delegate :token,
|
delegate :token,
|
||||||
to: :access_token,
|
to: :access_token,
|
||||||
|
|
|
@ -34,14 +34,14 @@ class Status < ApplicationRecord
|
||||||
|
|
||||||
enum visibility: [:public, :unlisted, :private, :direct], _suffix: :visibility
|
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 :account, inverse_of: :statuses, counter_cache: true
|
||||||
belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account'
|
belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account', optional: true
|
||||||
belongs_to :conversation
|
belongs_to :conversation, optional: true
|
||||||
|
|
||||||
belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies
|
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
|
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 :favourites, inverse_of: :status, dependent: :destroy
|
||||||
has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy
|
has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class StatusPin < ApplicationRecord
|
class StatusPin < ApplicationRecord
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
belongs_to :status, required: true
|
belongs_to :status
|
||||||
|
|
||||||
validates_with StatusPinValidator
|
validates_with StatusPinValidator
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,7 @@ class Subscription < ApplicationRecord
|
||||||
MIN_EXPIRATION = 1.day.to_i
|
MIN_EXPIRATION = 1.day.to_i
|
||||||
MAX_EXPIRATION = 30.days.to_i
|
MAX_EXPIRATION = 30.days.to_i
|
||||||
|
|
||||||
belongs_to :account, required: true
|
belongs_to :account
|
||||||
|
|
||||||
validates :callback_url, presence: true
|
validates :callback_url, presence: true
|
||||||
validates :callback_url, uniqueness: { scope: :account_id }
|
validates :callback_url, uniqueness: { scope: :account_id }
|
||||||
|
|
|
@ -50,8 +50,8 @@ class User < ApplicationRecord
|
||||||
devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
|
devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
|
||||||
:confirmable
|
:confirmable
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :user, required: true
|
belongs_to :account, inverse_of: :user
|
||||||
belongs_to :invite, counter_cache: :uses
|
belongs_to :invite, counter_cache: :uses, optional: true
|
||||||
accepts_nested_attributes_for :account
|
accepts_nested_attributes_for :account
|
||||||
|
|
||||||
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
|
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
|
||||||
|
@ -223,5 +223,6 @@ class User < ApplicationRecord
|
||||||
def update_statistics!
|
def update_statistics!
|
||||||
BootstrapTimelineWorker.perform_async(account_id)
|
BootstrapTimelineWorker.perform_async(account_id)
|
||||||
ActivityTracker.increment('activity:accounts:local')
|
ActivityTracker.increment('activity:accounts:local')
|
||||||
|
UserMailer.welcome(self).deliver_later
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
---
|
---
|
||||||
|
|
||||||
<%= t('application_mailer.signature', instance: site_hostname) %>
|
<%= t 'about.hosted_on', domain: site_hostname %>
|
||||||
<%= t('application_mailer.settings', link: settings_preferences_url) %>
|
<%= t('application_mailer.settings', link: settings_preferences_url) %>
|
||||||
|
|
|
@ -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'
|
|
@ -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' %>
|
|
@ -3,7 +3,7 @@
|
||||||
class ActivityPub::DeliveryWorker
|
class ActivityPub::DeliveryWorker
|
||||||
include Sidekiq::Worker
|
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
|
HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ require_relative '../lib/mastodon/redis_config'
|
||||||
|
|
||||||
module Mastodon
|
module Mastodon
|
||||||
class Application < Rails::Application
|
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.
|
# Settings in config/environments/* take precedence over those specified here.
|
||||||
# Application configuration should go into files in config/initializers
|
# Application configuration should go into files in config/initializers
|
||||||
# -- all .rb files in that directory are automatically loaded.
|
# -- all .rb files in that directory are automatically loaded.
|
||||||
|
|
|
@ -140,7 +140,6 @@ ar:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name}،"
|
salutation: "%{name}،"
|
||||||
settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}'
|
settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}'
|
||||||
signature: إشعارات ماستدون من %{instance}
|
|
||||||
view: 'View:'
|
view: 'View:'
|
||||||
applications:
|
applications:
|
||||||
created: تم إنشاء التطبيق بنجاح
|
created: تم إنشاء التطبيق بنجاح
|
||||||
|
|
|
@ -26,7 +26,6 @@ bg:
|
||||||
unfollow: Не следвай
|
unfollow: Не следвай
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Промяна на предпочитанията за e-mail: %{link}'
|
settings: 'Промяна на предпочитанията за e-mail: %{link}'
|
||||||
signature: Mastodon известия от %{instance}
|
|
||||||
view: 'Преглед:'
|
view: 'Преглед:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: Предоставеният URL е невалиден
|
invalid_url: Предоставеният URL е невалиден
|
||||||
|
|
|
@ -340,7 +340,6 @@ ca:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Canvia les preferències de correu: %{link}'
|
settings: 'Canvia les preferències de correu: %{link}'
|
||||||
signature: Notificacions de Mastodon des de %{instance}
|
|
||||||
view: 'Vista:'
|
view: 'Vista:'
|
||||||
applications:
|
applications:
|
||||||
created: L'aplicació s'ha creat correctament
|
created: L'aplicació s'ha creat correctament
|
||||||
|
|
|
@ -321,7 +321,6 @@ de:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'E-Mail-Einstellungen ändern: %{link}'
|
settings: 'E-Mail-Einstellungen ändern: %{link}'
|
||||||
signature: Mastodon-Benachrichtigungen von %{instance}
|
|
||||||
view: 'Ansehen:'
|
view: 'Ansehen:'
|
||||||
applications:
|
applications:
|
||||||
created: Anwendung erstellt
|
created: Anwendung erstellt
|
||||||
|
|
|
@ -341,7 +341,6 @@ en:
|
||||||
notification_preferences: Change e-mail preferences
|
notification_preferences: Change e-mail preferences
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Change e-mail preferences: %{link}'
|
settings: 'Change e-mail preferences: %{link}'
|
||||||
signature: Mastodon notifications from %{instance}
|
|
||||||
view: 'View:'
|
view: 'View:'
|
||||||
view_profile: View Profile
|
view_profile: View Profile
|
||||||
view_status: View status
|
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.
|
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
|
setup: Set up
|
||||||
wrong_code: The entered code was invalid! Are server time and device time correct?
|
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:
|
users:
|
||||||
invalid_email: The e-mail address is invalid
|
invalid_email: The e-mail address is invalid
|
||||||
invalid_otp_token: Invalid two-factor code
|
invalid_otp_token: Invalid two-factor code
|
||||||
|
|
|
@ -237,7 +237,6 @@ eo:
|
||||||
subject: Nova raporto por %{instance} (#%{id})
|
subject: Nova raporto por %{instance} (#%{id})
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Ŝanĝi la retpoŝt-mesaĝajn preferojn: %{link}'
|
settings: 'Ŝanĝi la retpoŝt-mesaĝajn preferojn: %{link}'
|
||||||
signature: Sciigoj de Mastodon el %{instance}
|
|
||||||
view: 'Vidi:'
|
view: 'Vidi:'
|
||||||
applications:
|
applications:
|
||||||
created: Aplikaĵo sukcesa kreis
|
created: Aplikaĵo sukcesa kreis
|
||||||
|
|
|
@ -332,7 +332,6 @@ es:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Cambiar preferencias de correo: %{link}'
|
settings: 'Cambiar preferencias de correo: %{link}'
|
||||||
signature: Notificaciones de Mastodon desde %{instance}
|
|
||||||
view: 'Vista:'
|
view: 'Vista:'
|
||||||
applications:
|
applications:
|
||||||
created: Aplicación creada exitosamente
|
created: Aplicación creada exitosamente
|
||||||
|
|
|
@ -334,7 +334,6 @@ fa:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name}،"
|
salutation: "%{name}،"
|
||||||
settings: 'تغییر تنظیمات ایمیل: %{link}'
|
settings: 'تغییر تنظیمات ایمیل: %{link}'
|
||||||
signature: اعلانهای ماستدون از %{instance}
|
|
||||||
view: 'نمایش:'
|
view: 'نمایش:'
|
||||||
applications:
|
applications:
|
||||||
created: برنامه با موفقیت ساخته شد
|
created: برنامه با موفقیت ساخته شد
|
||||||
|
|
|
@ -25,7 +25,6 @@ fi:
|
||||||
unfollow: Lopeta seuraaminen
|
unfollow: Lopeta seuraaminen
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Muokkaa sähköpostiasetuksia: %{link}'
|
settings: 'Muokkaa sähköpostiasetuksia: %{link}'
|
||||||
signature: Mastodon-ilmoituksia palvelimelta %{instance}
|
|
||||||
view: 'Katso:'
|
view: 'Katso:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: Annettu URL on väärä
|
invalid_url: Annettu URL on väärä
|
||||||
|
|
|
@ -334,7 +334,6 @@ fr:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Changer les préférences courriel : %{link}'
|
settings: 'Changer les préférences courriel : %{link}'
|
||||||
signature: Notifications de Mastodon depuis %{instance}
|
|
||||||
view: 'Voir :'
|
view: 'Voir :'
|
||||||
applications:
|
applications:
|
||||||
created: Application créée avec succès
|
created: Application créée avec succès
|
||||||
|
|
|
@ -340,7 +340,6 @@ gl:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Mudar as preferencias de e-mail: %{link}'
|
settings: 'Mudar as preferencias de e-mail: %{link}'
|
||||||
signature: Notificacións Mastodon de %{instance}
|
|
||||||
view: 'Vista:'
|
view: 'Vista:'
|
||||||
applications:
|
applications:
|
||||||
created: Creouse con éxito este aplicativo
|
created: Creouse con éxito este aplicativo
|
||||||
|
|
|
@ -229,7 +229,6 @@ he:
|
||||||
title: ניהול
|
title: ניהול
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'שינוי הגדרות דוא"ל: %{link}'
|
settings: 'שינוי הגדרות דוא"ל: %{link}'
|
||||||
signature: התראות מסטודון מקהילת %{instance}
|
|
||||||
view: 'תצוגה:'
|
view: 'תצוגה:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: כתובת הקישורית אינה חוקית
|
invalid_url: כתובת הקישורית אינה חוקית
|
||||||
|
|
|
@ -26,7 +26,6 @@ hr:
|
||||||
unfollow: Prestani slijediti
|
unfollow: Prestani slijediti
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Promijeni e-mail postavke: %{link}'
|
settings: 'Promijeni e-mail postavke: %{link}'
|
||||||
signature: Mastodon notifikacije sa %{instance}
|
|
||||||
view: 'Vidi:'
|
view: 'Vidi:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: Uneseni link nije valjan
|
invalid_url: Uneseni link nije valjan
|
||||||
|
|
|
@ -12,8 +12,6 @@ hu:
|
||||||
people_who_follow: "%{name} követői"
|
people_who_follow: "%{name} követői"
|
||||||
posts: Bejegyzések
|
posts: Bejegyzések
|
||||||
unfollow: Követés abbahagyása
|
unfollow: Követés abbahagyása
|
||||||
application_mailer:
|
|
||||||
signature: "%{instance} Mastodon értesítései"
|
|
||||||
auth:
|
auth:
|
||||||
change_password: Jelszó változtatása
|
change_password: Jelszó változtatása
|
||||||
didnt_get_confirmation: Nem kaptad meg a megerősítési lépéseket?
|
didnt_get_confirmation: Nem kaptad meg a megerősítési lépéseket?
|
||||||
|
|
|
@ -151,7 +151,6 @@ id:
|
||||||
title: Administrasi
|
title: Administrasi
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Ubah pilihan email: %{link}'
|
settings: 'Ubah pilihan email: %{link}'
|
||||||
signature: Notifikasi Mastodon dari %{instance}
|
|
||||||
view: 'Tampilan:'
|
view: 'Tampilan:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: URL tidak sesuai
|
invalid_url: URL tidak sesuai
|
||||||
|
|
|
@ -149,7 +149,6 @@ io:
|
||||||
title: Administration
|
title: Administration
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Chanjar la retpost-mesajala preferi: %{link}'
|
settings: 'Chanjar la retpost-mesajala preferi: %{link}'
|
||||||
signature: Savigi di Mastodon de %{instance}
|
|
||||||
view: 'Vidar:'
|
view: 'Vidar:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: La URL donita ne esas valida
|
invalid_url: La URL donita ne esas valida
|
||||||
|
|
|
@ -26,7 +26,6 @@ it:
|
||||||
unfollow: Non seguire più
|
unfollow: Non seguire più
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Cambia le impostazioni per le e-mail: %{link}'
|
settings: 'Cambia le impostazioni per le e-mail: %{link}'
|
||||||
signature: Notifiche Mastodon da %{instance}
|
|
||||||
view: 'Guarda:'
|
view: 'Guarda:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: L'URL fornito non è valido
|
invalid_url: L'URL fornito non è valido
|
||||||
|
|
|
@ -341,7 +341,6 @@ ja:
|
||||||
notification_preferences: メール設定の変更
|
notification_preferences: メール設定の変更
|
||||||
salutation: "%{name} さん"
|
salutation: "%{name} さん"
|
||||||
settings: 'メール設定の変更: %{link}'
|
settings: 'メール設定の変更: %{link}'
|
||||||
signature: Mastodon %{instance} インスタンスからの通知
|
|
||||||
view: 'リンク:'
|
view: 'リンク:'
|
||||||
view_profile: プロフィールを表示
|
view_profile: プロフィールを表示
|
||||||
view_status: トゥートを表示
|
view_status: トゥートを表示
|
||||||
|
|
|
@ -340,7 +340,6 @@ ko:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
notification_preferences: 메일 설정 변경
|
notification_preferences: 메일 설정 변경
|
||||||
settings: '메일 설정을 변경: %{link}'
|
settings: '메일 설정을 변경: %{link}'
|
||||||
signature: Mastodon %{instance} 인스턴스로에서 알림
|
|
||||||
view: 'View:'
|
view: 'View:'
|
||||||
view_profile: 프로필 보기
|
view_profile: 프로필 보기
|
||||||
view_status: 게시물 보기
|
view_status: 게시물 보기
|
||||||
|
|
|
@ -340,7 +340,6 @@ nl:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'E-mailvoorkeuren wijzigen: %{link}'
|
settings: 'E-mailvoorkeuren wijzigen: %{link}'
|
||||||
signature: Mastodon-meldingen van %{instance}
|
|
||||||
view: 'Bekijk:'
|
view: 'Bekijk:'
|
||||||
applications:
|
applications:
|
||||||
created: Aanmaken toepassing geslaagd
|
created: Aanmaken toepassing geslaagd
|
||||||
|
|
|
@ -163,7 +163,6 @@
|
||||||
title: Administrasjon
|
title: Administrasjon
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Endre foretrukne e-postinnstillinger: %{link}'
|
settings: 'Endre foretrukne e-postinnstillinger: %{link}'
|
||||||
signature: Mastodon-notiser fra %{instance}
|
|
||||||
view: 'Se:'
|
view: 'Se:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: Den oppgitte URLen er ugyldig
|
invalid_url: Den oppgitte URLen er ugyldig
|
||||||
|
|
|
@ -340,7 +340,6 @@ oc:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Cambiar las preferéncias de corrièl : %{link}'
|
settings: 'Cambiar las preferéncias de corrièl : %{link}'
|
||||||
signature: Notificacion de Mastodon sus %{instance}
|
|
||||||
view: 'Veire :'
|
view: 'Veire :'
|
||||||
applications:
|
applications:
|
||||||
created: Aplicacion ben creada
|
created: Aplicacion ben creada
|
||||||
|
|
|
@ -342,7 +342,6 @@ pl:
|
||||||
notification_preferences: Zmień ustawienia e-maili
|
notification_preferences: Zmień ustawienia e-maili
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Zmień ustawienia powiadamiania: %{link}'
|
settings: 'Zmień ustawienia powiadamiania: %{link}'
|
||||||
signature: Powiadomienie Mastodona z instancji %{instance}
|
|
||||||
view: 'Zobacz:'
|
view: 'Zobacz:'
|
||||||
view_status: Wyświetl wpis
|
view_status: Wyświetl wpis
|
||||||
applications:
|
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.
|
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
|
setup: Skonfiguruj
|
||||||
wrong_code: Wprowadzony kod jest niepoprawny! Czy czas serwera i urządzenia jest poprawny?
|
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:
|
users:
|
||||||
invalid_email: Adres e-mail jest niepoprawny
|
invalid_email: Adres e-mail jest niepoprawny
|
||||||
invalid_otp_token: Kod uwierzytelniający jest niepoprawny
|
invalid_otp_token: Kod uwierzytelniający jest niepoprawny
|
||||||
|
|
|
@ -340,7 +340,6 @@ pt-BR:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Mudar e-mail de preferência: %{link}'
|
settings: 'Mudar e-mail de preferência: %{link}'
|
||||||
signature: Notificações do Mastodon de %{instance}
|
|
||||||
view: 'Visualizar:'
|
view: 'Visualizar:'
|
||||||
applications:
|
applications:
|
||||||
created: Aplicação criada com sucesso
|
created: Aplicação criada com sucesso
|
||||||
|
|
|
@ -328,7 +328,6 @@ pt:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Alterar preferências de email: %{link}'
|
settings: 'Alterar preferências de email: %{link}'
|
||||||
signature: notificações Mastodon do %{instance}
|
|
||||||
view: 'Ver:'
|
view: 'Ver:'
|
||||||
applications:
|
applications:
|
||||||
created: Aplicação criada com sucesso
|
created: Aplicação criada com sucesso
|
||||||
|
|
|
@ -342,7 +342,6 @@ ru:
|
||||||
notification_preferences: Изменить настройки e-mail
|
notification_preferences: Изменить настройки e-mail
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Изменить настройки e-mail: %{link}'
|
settings: 'Изменить настройки e-mail: %{link}'
|
||||||
signature: Уведомления Mastodon от %{instance}
|
|
||||||
view: 'Просмотр:'
|
view: 'Просмотр:'
|
||||||
view_status: Просмотреть статус
|
view_status: Просмотреть статус
|
||||||
applications:
|
applications:
|
||||||
|
|
|
@ -336,7 +336,6 @@ sr-Latn:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Promeni podešavanja e-pošte: %{link}'
|
settings: 'Promeni podešavanja e-pošte: %{link}'
|
||||||
signature: Mastodont obaveštenje sa instance %{instance}
|
|
||||||
view: 'Pogledaj:'
|
view: 'Pogledaj:'
|
||||||
applications:
|
applications:
|
||||||
created: Aplikacija uspešno napravljena
|
created: Aplikacija uspešno napravljena
|
||||||
|
|
|
@ -336,7 +336,6 @@ sr:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Промени подешавања е-поште: %{link}'
|
settings: 'Промени подешавања е-поште: %{link}'
|
||||||
signature: Мастодонт обавештење са инстанце %{instance}
|
|
||||||
view: 'Погледај:'
|
view: 'Погледај:'
|
||||||
applications:
|
applications:
|
||||||
created: Апликација успешно направљена
|
created: Апликација успешно направљена
|
||||||
|
|
|
@ -272,7 +272,6 @@ sv:
|
||||||
application_mailer:
|
application_mailer:
|
||||||
salutation: "%{name},"
|
salutation: "%{name},"
|
||||||
settings: 'Change e-mail preferences: %{link}'
|
settings: 'Change e-mail preferences: %{link}'
|
||||||
signature: Mastodon meddelande från %{instance}
|
|
||||||
view: 'Granska:'
|
view: 'Granska:'
|
||||||
applications:
|
applications:
|
||||||
created: Ansökan är framgångsrikt skapad
|
created: Ansökan är framgångsrikt skapad
|
||||||
|
|
|
@ -153,7 +153,6 @@ th:
|
||||||
title: แอดมิน
|
title: แอดมิน
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'เปลี่ยนอีเมล์ preferences: %{link}'
|
settings: 'เปลี่ยนอีเมล์ preferences: %{link}'
|
||||||
signature: ฟอร์มการแจ้งเตือนแมสโทดอน %{instance}
|
|
||||||
view: 'วิว:'
|
view: 'วิว:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: URL ที่ระบุไม่ถูกตั้ง
|
invalid_url: URL ที่ระบุไม่ถูกตั้ง
|
||||||
|
|
|
@ -152,7 +152,6 @@ tr:
|
||||||
title: Yönetim
|
title: Yönetim
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'E-mail tercihlerini değiştir: %{link}'
|
settings: 'E-mail tercihlerini değiştir: %{link}'
|
||||||
signature: "%{instance} sunucusundan Mastodon bildirimleri"
|
|
||||||
view: 'Görüntüle:'
|
view: 'Görüntüle:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: Verilen URL geçerli değil
|
invalid_url: Verilen URL geçerli değil
|
||||||
|
|
|
@ -143,7 +143,6 @@ uk:
|
||||||
title: Адміністрування
|
title: Адміністрування
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 'Змінити налаштування email: %{link}'
|
settings: 'Змінити налаштування email: %{link}'
|
||||||
signature: Сповіщення Mastodon від %{instance}
|
|
||||||
view: 'Перегляд:'
|
view: 'Перегляд:'
|
||||||
applications:
|
applications:
|
||||||
invalid_url: Введена URL неправильна
|
invalid_url: Введена URL неправильна
|
||||||
|
|
|
@ -339,7 +339,6 @@ zh-CN:
|
||||||
notification_preferences: 更改电子邮件首选项
|
notification_preferences: 更改电子邮件首选项
|
||||||
salutation: "%{name}:"
|
salutation: "%{name}:"
|
||||||
settings: 使用此链接更改你的电子邮件首选项:%{link}
|
settings: 使用此链接更改你的电子邮件首选项:%{link}
|
||||||
signature: 这是一封来自 %{instance} 的 Mastodon 电子邮件通知。
|
|
||||||
view: 点此链接查看详情:
|
view: 点此链接查看详情:
|
||||||
view_profile: 查看个人资料页
|
view_profile: 查看个人资料页
|
||||||
view_status: 查看嘟文
|
view_status: 查看嘟文
|
||||||
|
|
|
@ -152,7 +152,6 @@ zh-HK:
|
||||||
title: 管理
|
title: 管理
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 修改電郵設定︰%{link}
|
settings: 修改電郵設定︰%{link}
|
||||||
signature: 來自 %{instance} 的 Mastodon 通知
|
|
||||||
view: 進入瀏覽︰
|
view: 進入瀏覽︰
|
||||||
applications:
|
applications:
|
||||||
invalid_url: 所提供的網址不正確
|
invalid_url: 所提供的網址不正確
|
||||||
|
|
|
@ -123,7 +123,6 @@ zh-TW:
|
||||||
title: 管理介面
|
title: 管理介面
|
||||||
application_mailer:
|
application_mailer:
|
||||||
settings: 修改信箱設定︰ %{link}
|
settings: 修改信箱設定︰ %{link}
|
||||||
signature: 來自 %{instance} 的 Mastodon 通知
|
|
||||||
view: 進入瀏覽︰
|
view: 進入瀏覽︰
|
||||||
applications:
|
applications:
|
||||||
invalid_url: 網址不正確
|
invalid_url: 網址不正確
|
||||||
|
|
|
@ -341,6 +341,15 @@ namespace :mastodon do
|
||||||
LinkCrawlWorker.push_bulk status_ids
|
LinkCrawlWorker.push_bulk status_ids
|
||||||
end
|
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'
|
desc 'Check every known remote account and delete those that no longer exist in origin'
|
||||||
task purge_removed_accounts: :environment do
|
task purge_removed_accounts: :environment do
|
||||||
prepare_for_options!
|
prepare_for_options!
|
||||||
|
|
|
@ -69,6 +69,12 @@ describe ApplicationController, type: :controller do
|
||||||
expect(RegenerationWorker).to have_received(:perform_async)
|
expect(RegenerationWorker).to have_received(:perform_async)
|
||||||
end
|
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
|
it 'regenerates feed when sign in is older than two weeks' do
|
||||||
get :show
|
get :show
|
||||||
|
|
||||||
|
|
|
@ -29,4 +29,9 @@ class UserMailerPreview < ActionMailer::Preview
|
||||||
def reset_password_instructions
|
def reset_password_instructions
|
||||||
UserMailer.reset_password_instructions(User.first, 'spec')
|
UserMailer.reset_password_instructions(User.first, 'spec')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/welcome
|
||||||
|
def welcome
|
||||||
|
UserMailer.welcome(User.first)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|