Merge branch 'master' into glitch-soc/merge-upstream
This commit is contained in:
commit
3d73d76e55
|
@ -7,7 +7,6 @@ SHELL ["bash", "-c"]
|
||||||
ENV NODE_VER="8.15.0"
|
ENV NODE_VER="8.15.0"
|
||||||
RUN echo "Etc/UTC" > /etc/localtime && \
|
RUN echo "Etc/UTC" > /etc/localtime && \
|
||||||
apt update && \
|
apt update && \
|
||||||
apt -y dist-upgrade && \
|
|
||||||
apt -y install wget make gcc g++ python && \
|
apt -y install wget make gcc g++ python && \
|
||||||
cd ~ && \
|
cd ~ && \
|
||||||
wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER.tar.gz && \
|
wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER.tar.gz && \
|
||||||
|
@ -80,7 +79,6 @@ ARG GID=991
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
echo "Etc/UTC" > /etc/localtime && \
|
echo "Etc/UTC" > /etc/localtime && \
|
||||||
ln -s /opt/jemalloc/lib/* /usr/lib/ && \
|
ln -s /opt/jemalloc/lib/* /usr/lib/ && \
|
||||||
apt -y dist-upgrade && \
|
|
||||||
apt install -y whois wget && \
|
apt install -y whois wget && \
|
||||||
addgroup --gid $GID mastodon && \
|
addgroup --gid $GID mastodon && \
|
||||||
useradd -m -u $UID -g $GID -d /opt/mastodon mastodon && \
|
useradd -m -u $UID -g $GID -d /opt/mastodon mastodon && \
|
||||||
|
|
|
@ -384,7 +384,7 @@ GEM
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.5)
|
||||||
http (~> 3.0)
|
http (~> 3.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
ox (2.10.0)
|
ox (2.10.1)
|
||||||
paperclip (6.0.0)
|
paperclip (6.0.0)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 4.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
|
|
|
@ -51,6 +51,6 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
||||||
|
|
||||||
def data_params
|
def data_params
|
||||||
return {} if params[:data].blank?
|
return {} if params[:data].blank?
|
||||||
params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention])
|
params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
||||||
favourite: alerts_enabled,
|
favourite: alerts_enabled,
|
||||||
reblog: alerts_enabled,
|
reblog: alerts_enabled,
|
||||||
mention: alerts_enabled,
|
mention: alerts_enabled,
|
||||||
|
poll: alerts_enabled,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +58,6 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def data_params
|
def data_params
|
||||||
@data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention])
|
@data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,24 +16,28 @@ module StreamEntriesHelper
|
||||||
if user_signed_in?
|
if user_signed_in?
|
||||||
if account.id == current_user.account_id
|
if account.id == current_user.account_id
|
||||||
link_to settings_profile_url, class: 'button logo-button' do
|
link_to settings_profile_url, class: 'button logo-button' do
|
||||||
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('settings.edit_profile')])
|
safe_join([svg_logo, t('settings.edit_profile')])
|
||||||
end
|
end
|
||||||
elsif current_account.following?(account) || current_account.requested?(account)
|
elsif current_account.following?(account) || current_account.requested?(account)
|
||||||
link_to account_unfollow_path(account), class: 'button logo-button button--destructive', data: { method: :post } do
|
link_to account_unfollow_path(account), class: 'button logo-button button--destructive', data: { method: :post } do
|
||||||
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.unfollow')])
|
safe_join([svg_logo, t('accounts.unfollow')])
|
||||||
end
|
end
|
||||||
elsif !(account.memorial? || account.moved?)
|
elsif !(account.memorial? || account.moved?)
|
||||||
link_to account_follow_path(account), class: "button logo-button#{account.blocking?(current_account) ? ' disabled' : ''}", data: { method: :post } do
|
link_to account_follow_path(account), class: "button logo-button#{account.blocking?(current_account) ? ' disabled' : ''}", data: { method: :post } do
|
||||||
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.follow')])
|
safe_join([svg_logo, t('accounts.follow')])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elsif !(account.memorial? || account.moved?)
|
elsif !(account.memorial? || account.moved?)
|
||||||
link_to account_remote_follow_path(account), class: 'button logo-button modal-button', target: '_new' do
|
link_to account_remote_follow_path(account), class: 'button logo-button modal-button', target: '_new' do
|
||||||
safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.follow')])
|
safe_join([svg_logo, t('accounts.follow')])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def svg_logo
|
||||||
|
content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo'), 'viewBox' => '0 0 216.4144 232.00976')
|
||||||
|
end
|
||||||
|
|
||||||
def account_badge(account, all: false)
|
def account_badge(account, all: false)
|
||||||
if account.bot?
|
if account.bot?
|
||||||
content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles')
|
content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles')
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.4144 232.00976"><path d="M107.86523 0C78.203984.2425 49.672422 3.4535937 33.044922 11.089844c0 0-32.97656262 14.752031-32.97656262 65.082031 0 11.525-.224375 25.306175.140625 39.919925 1.19750002 49.22 9.02375002 97.72843 54.53124962 109.77343 20.9825 5.55375 38.99711 6.71547 53.505856 5.91797 26.31125-1.45875 41.08203-9.38867 41.08203-9.38867l-.86914-19.08984s-18.80171 5.92758-39.91796 5.20508c-20.921254-.7175-43.006879-2.25516-46.390629-27.94141-.3125-2.25625-.46875-4.66938-.46875-7.20313 0 0 20.536953 5.0204 46.564449 6.21289 15.915.73001 30.8393-.93343 45.99805-2.74218 29.07-3.47125 54.38125-21.3818 57.5625-37.74805 5.0125-25.78125 4.59961-62.916015 4.59961-62.916015 0-50.33-32.97461-65.082031-32.97461-65.082031C166.80539 3.4535938 138.255.2425 108.59375 0h-.72852zM74.296875 39.326172c12.355 0 21.710234 4.749297 27.896485 14.248047l6.01367 10.080078 6.01563-10.080078c6.185-9.49875 15.54023-14.248047 27.89648-14.248047 10.6775 0 19.28156 3.753672 25.85156 11.076172 6.36875 7.3225 9.53907 17.218828 9.53907 29.673828v60.941408h-24.14454V81.869141c0-12.46875-5.24453-18.798829-15.73828-18.798829-11.6025 0-17.41797 7.508516-17.41797 22.353516v32.375002H96.207031V85.423828c0-14.845-5.815468-22.353515-17.417969-22.353516-10.49375 0-15.740234 6.330079-15.740234 18.798829v59.148439H38.904297V80.076172c0-12.455 3.171016-22.351328 9.541015-29.673828 6.568751-7.3225 15.172813-11.076172 25.851563-11.076172z" fill="#fff"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg"><symbol id="mastodon-svg-logo" viewBox="0 0 216.4144 232.00976"><path d="M107.86523 0C78.203984.2425 49.672422 3.4535937 33.044922 11.089844c0 0-32.97656262 14.752031-32.97656262 65.082031 0 11.525-.224375 25.306175.140625 39.919925 1.19750002 49.22 9.02375002 97.72843 54.53124962 109.77343 20.9825 5.55375 38.99711 6.71547 53.505856 5.91797 26.31125-1.45875 41.08203-9.38867 41.08203-9.38867l-.86914-19.08984s-18.80171 5.92758-39.91796 5.20508c-20.921254-.7175-43.006879-2.25516-46.390629-27.94141-.3125-2.25625-.46875-4.66938-.46875-7.20313 0 0 20.536953 5.0204 46.564449 6.21289 15.915.73001 30.8393-.93343 45.99805-2.74218 29.07-3.47125 54.38125-21.3818 57.5625-37.74805 5.0125-25.78125 4.59961-62.916015 4.59961-62.916015 0-50.33-32.97461-65.082031-32.97461-65.082031C166.80539 3.4535938 138.255.2425 108.59375 0h-.72852zM74.296875 39.326172c12.355 0 21.710234 4.749297 27.896485 14.248047l6.01367 10.080078 6.01563-10.080078c6.185-9.49875 15.54023-14.248047 27.89648-14.248047 10.6775 0 19.28156 3.753672 25.85156 11.076172 6.36875 7.3225 9.53907 17.218828 9.53907 29.673828v60.941408h-24.14454V81.869141c0-12.46875-5.24453-18.798829-15.73828-18.798829-11.6025 0-17.41797 7.508516-17.41797 22.353516v32.375002H96.207031V85.423828c0-14.845-5.815468-22.353515-17.417969-22.353516-10.49375 0-15.740234 6.330079-15.740234 18.798829v59.148439H38.904297V80.076172c0-12.455 3.171016-22.351328 9.541015-29.673828 6.568751-7.3225 15.172813-11.076172 25.851563-11.076172z" /></symbol></svg>
|
||||||
|
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -28,7 +28,6 @@ class Poll extends ImmutablePureComponent {
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
visible: PropTypes.bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -70,14 +69,13 @@ class Poll extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
renderOption (option, optionIndex) {
|
renderOption (option, optionIndex) {
|
||||||
const { poll, disabled, visible } = this.props;
|
const { poll, disabled } = this.props;
|
||||||
const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
|
const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
|
||||||
const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
|
const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
|
||||||
const active = !!this.state.selected[`${optionIndex}`];
|
const active = !!this.state.selected[`${optionIndex}`];
|
||||||
const showResults = poll.get('voted') || poll.get('expired');
|
const showResults = poll.get('voted') || poll.get('expired');
|
||||||
|
|
||||||
let titleEmojified = option.get('title_emojified');
|
let titleEmojified = option.get('title_emojified');
|
||||||
|
|
||||||
if (!titleEmojified) {
|
if (!titleEmojified) {
|
||||||
const emojiMap = makeEmojiMap(poll);
|
const emojiMap = makeEmojiMap(poll);
|
||||||
titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap);
|
titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap);
|
||||||
|
@ -106,7 +104,7 @@ class Poll extends ImmutablePureComponent {
|
||||||
{!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}
|
{!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}
|
||||||
{showResults && <span className='poll__number'>{Math.round(percent)}%</span>}
|
{showResults && <span className='poll__number'>{Math.round(percent)}%</span>}
|
||||||
|
|
||||||
{visible ? <span dangerouslySetInnerHTML={{ __html: titleEmojified }} /> : <span>{String.fromCharCode(64 + optionIndex + 1)}</span>}
|
<span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
|
@ -317,7 +317,7 @@ class Status extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.get('poll')) {
|
if (status.get('poll')) {
|
||||||
media = <PollContainer pollId={status.get('poll')} visible={!status.get('hidden')} />;
|
media = <PollContainer pollId={status.get('poll')} />;
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
if (this.props.muted) {
|
if (this.props.muted) {
|
||||||
media = (
|
media = (
|
||||||
|
|
|
@ -7,12 +7,12 @@ import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { me, invitesEnabled, version, profile_directory, repository, source_url } from '../../initial_state';
|
import { me, profile_directory } from '../../initial_state';
|
||||||
import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import NavigationBar from '../compose/components/navigation_bar';
|
import NavigationBar from '../compose/components/navigation_bar';
|
||||||
import Icon from 'mastodon/components/icon';
|
import Icon from 'mastodon/components/icon';
|
||||||
|
import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||||
|
@ -166,27 +166,7 @@ class GettingStarted extends ImmutablePureComponent {
|
||||||
|
|
||||||
{!multiColumn && <div className='flex-spacer' />}
|
{!multiColumn && <div className='flex-spacer' />}
|
||||||
|
|
||||||
<div className='getting-started__footer'>
|
<LinkFooter withHotkeys={multiColumn} />
|
||||||
<ul>
|
|
||||||
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
|
|
||||||
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
|
|
||||||
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
|
|
||||||
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>
|
|
||||||
<li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
|
|
||||||
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
|
|
||||||
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
|
|
||||||
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
|
|
||||||
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
id='getting_started.open_source_notice'
|
|
||||||
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
|
||||||
values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
|
|
@ -108,7 +108,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.get('poll')) {
|
if (status.get('poll')) {
|
||||||
media = <PollContainer pollId={status.get('poll')} visible={!status.get('hidden')} />;
|
media = <PollContainer pollId={status.get('poll')} />;
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||||
const video = status.getIn(['media_attachments', 0]);
|
const video = status.getIn(['media_attachments', 0]);
|
||||||
|
|
|
@ -2,9 +2,7 @@ import React from 'react';
|
||||||
import SearchContainer from 'mastodon/features/compose/containers/search_container';
|
import SearchContainer from 'mastodon/features/compose/containers/search_container';
|
||||||
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
|
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
|
||||||
import NavigationContainer from 'mastodon/features/compose/containers/navigation_container';
|
import NavigationContainer from 'mastodon/features/compose/containers/navigation_container';
|
||||||
import { invitesEnabled, version, repository, source_url } from 'mastodon/initial_state';
|
import LinkFooter from './link_footer';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
const ComposePanel = () => (
|
const ComposePanel = () => (
|
||||||
<div className='compose-panel'>
|
<div className='compose-panel'>
|
||||||
|
@ -14,27 +12,7 @@ const ComposePanel = () => (
|
||||||
|
|
||||||
<div className='flex-spacer' />
|
<div className='flex-spacer' />
|
||||||
|
|
||||||
<div className='getting-started__footer'>
|
<LinkFooter withHotkeys />
|
||||||
<ul>
|
|
||||||
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
|
|
||||||
<li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>
|
|
||||||
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
|
|
||||||
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>
|
|
||||||
<li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
|
|
||||||
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
|
|
||||||
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
|
|
||||||
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
|
|
||||||
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
id='getting_started.open_source_notice'
|
|
||||||
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
|
||||||
values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { invitesEnabled, version, repository, source_url } from 'mastodon/initial_state';
|
||||||
|
|
||||||
|
const LinkFooter = ({ withHotkeys }) => (
|
||||||
|
<div className='getting-started__footer'>
|
||||||
|
<ul>
|
||||||
|
{invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
|
||||||
|
{withHotkeys && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
|
||||||
|
<li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
|
||||||
|
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>
|
||||||
|
<li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
|
||||||
|
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
|
||||||
|
<li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
|
||||||
|
<li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
|
||||||
|
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='getting_started.open_source_notice'
|
||||||
|
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
|
||||||
|
values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
LinkFooter.propTypes = {
|
||||||
|
withHotkeys: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LinkFooter;
|
|
@ -18,7 +18,7 @@ import compareId from '../compare_id';
|
||||||
const initialState = ImmutableMap({
|
const initialState = ImmutableMap({
|
||||||
items: ImmutableList(),
|
items: ImmutableList(),
|
||||||
hasMore: true,
|
hasMore: true,
|
||||||
top: true,
|
top: false,
|
||||||
unread: 0,
|
unread: 0,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -306,7 +306,7 @@
|
||||||
.button.logo-button {
|
.button.logo-button {
|
||||||
color: $white;
|
color: $white;
|
||||||
|
|
||||||
svg path:first-child {
|
svg {
|
||||||
fill: $white;
|
fill: $white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,10 +359,6 @@
|
||||||
|
|
||||||
.logo-button {
|
.logo-button {
|
||||||
background-color: $secondary-text-color;
|
background-color: $secondary-text-color;
|
||||||
|
|
||||||
svg path:last-child {
|
|
||||||
fill: $secondary-text-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,10 +122,7 @@
|
||||||
height: 36px;
|
height: 36px;
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
fill: lighten($ui-base-color, 34%);
|
||||||
path {
|
|
||||||
fill: lighten($ui-base-color, 34%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
|
|
|
@ -89,40 +89,21 @@
|
||||||
height: auto;
|
height: auto;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
fill: $primary-text-color;
|
||||||
path:first-child {
|
|
||||||
fill: $primary-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
path:last-child {
|
|
||||||
fill: $ui-highlight-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background: lighten($ui-highlight-color, 10%);
|
background: lighten($ui-highlight-color, 10%);
|
||||||
|
|
||||||
svg path:last-child {
|
|
||||||
fill: lighten($ui-highlight-color, 10%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled,
|
&:disabled,
|
||||||
&.disabled {
|
&.disabled {
|
||||||
svg path:last-child {
|
|
||||||
fill: $ui-primary-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $ui-primary-color;
|
background: $ui-primary-color;
|
||||||
|
|
||||||
svg path:last-child {
|
|
||||||
fill: $ui-primary-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,10 +112,6 @@
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $error-red;
|
background: $error-red;
|
||||||
|
|
||||||
svg path:last-child {
|
|
||||||
fill: $error-red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,3 +39,6 @@
|
||||||
|
|
||||||
%body{ class: body_classes }
|
%body{ class: body_classes }
|
||||||
= content_for?(:content) ? yield(:content) : yield
|
= content_for?(:content) ? yield(:content) : yield
|
||||||
|
|
||||||
|
%div{ style: 'display: none'}
|
||||||
|
= render file: Rails.root.join('app', 'javascript', 'images', 'logo_transparent.svg')
|
||||||
|
|
|
@ -35,9 +35,7 @@
|
||||||
%li= link_to t('about.api'), 'https://docs.joinmastodon.org/api/guidelines/'
|
%li= link_to t('about.api'), 'https://docs.joinmastodon.org/api/guidelines/'
|
||||||
.column-2
|
.column-2
|
||||||
%h4= link_to t('about.what_is_mastodon'), 'https://joinmastodon.org/'
|
%h4= link_to t('about.what_is_mastodon'), 'https://joinmastodon.org/'
|
||||||
|
= link_to svg_logo, root_url, class: 'brand'
|
||||||
= link_to root_url, class: 'brand' do
|
|
||||||
= render file: Rails.root.join('app', 'javascript', 'images', 'logo_transparent.svg')
|
|
||||||
.column-3
|
.column-3
|
||||||
%h4= site_hostname
|
%h4= site_hostname
|
||||||
%ul
|
%ul
|
||||||
|
|
|
@ -13,6 +13,10 @@ class Rack::Attack
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remote_ip
|
||||||
|
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
|
||||||
|
end
|
||||||
|
|
||||||
def authenticated_user_id
|
def authenticated_user_id
|
||||||
authenticated_token&.resource_owner_id
|
authenticated_token&.resource_owner_id
|
||||||
end
|
end
|
||||||
|
@ -28,6 +32,10 @@ class Rack::Attack
|
||||||
def web_request?
|
def web_request?
|
||||||
!api_request?
|
!api_request?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def paging_request?
|
||||||
|
params['page'].present? || params['min_id'].present? || params['max_id'].present? || params['since_id'].present?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
PROTECTED_PATHS = %w(
|
PROTECTED_PATHS = %w(
|
||||||
|
@ -42,15 +50,15 @@ class Rack::Attack
|
||||||
# (blocklist & throttles are skipped)
|
# (blocklist & throttles are skipped)
|
||||||
Rack::Attack.safelist('allow from localhost') do |req|
|
Rack::Attack.safelist('allow from localhost') do |req|
|
||||||
# Requests are allowed if the return value is truthy
|
# Requests are allowed if the return value is truthy
|
||||||
req.ip == '127.0.0.1' || req.ip == '::1'
|
req.remote_ip == '127.0.0.1' || req.remote_ip == '::1'
|
||||||
end
|
end
|
||||||
|
|
||||||
throttle('throttle_authenticated_api', limit: 300, period: 5.minutes) do |req|
|
throttle('throttle_authenticated_api', limit: 300, period: 5.minutes) do |req|
|
||||||
req.authenticated_user_id if req.api_request?
|
req.authenticated_user_id if req.api_request?
|
||||||
end
|
end
|
||||||
|
|
||||||
throttle('throttle_unauthenticated_api', limit: 7_500, period: 5.minutes) do |req|
|
throttle('throttle_unauthenticated_api', limit: 300, period: 5.minutes) do |req|
|
||||||
req.ip if req.api_request?
|
req.remote_ip if req.api_request? && req.unauthenticated?
|
||||||
end
|
end
|
||||||
|
|
||||||
throttle('throttle_api_media', limit: 30, period: 30.minutes) do |req|
|
throttle('throttle_api_media', limit: 30, period: 30.minutes) do |req|
|
||||||
|
@ -58,11 +66,20 @@ class Rack::Attack
|
||||||
end
|
end
|
||||||
|
|
||||||
throttle('throttle_media_proxy', limit: 30, period: 30.minutes) do |req|
|
throttle('throttle_media_proxy', limit: 30, period: 30.minutes) do |req|
|
||||||
req.ip if req.path.start_with?('/media_proxy')
|
req.remote_ip if req.path.start_with?('/media_proxy')
|
||||||
end
|
end
|
||||||
|
|
||||||
throttle('throttle_api_sign_up', limit: 5, period: 30.minutes) do |req|
|
throttle('throttle_api_sign_up', limit: 5, period: 30.minutes) do |req|
|
||||||
req.ip if req.post? && req.path == '/api/v1/accounts'
|
req.remote_ip if req.post? && req.path == '/api/v1/accounts'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Throttle paging, as it is mainly used for public pages and AP collections
|
||||||
|
throttle('throttle_authenticated_paging', limit: 300, period: 15.minutes) do |req|
|
||||||
|
req.authenticated_user_id if req.paging_request?
|
||||||
|
end
|
||||||
|
|
||||||
|
throttle('throttle_unauthenticated_paging', limit: 300, period: 15.minutes) do |req|
|
||||||
|
req.remote_ip if req.paging_request? && req.unauthenticated?
|
||||||
end
|
end
|
||||||
|
|
||||||
API_DELETE_REBLOG_REGEX = /\A\/api\/v1\/statuses\/[\d]+\/unreblog/.freeze
|
API_DELETE_REBLOG_REGEX = /\A\/api\/v1\/statuses\/[\d]+\/unreblog/.freeze
|
||||||
|
@ -73,7 +90,7 @@ class Rack::Attack
|
||||||
end
|
end
|
||||||
|
|
||||||
throttle('protected_paths', limit: 25, period: 5.minutes) do |req|
|
throttle('protected_paths', limit: 25, period: 5.minutes) do |req|
|
||||||
req.ip if req.post? && req.path =~ PROTECTED_PATHS_REGEX
|
req.remote_ip if req.post? && req.path =~ PROTECTED_PATHS_REGEX
|
||||||
end
|
end
|
||||||
|
|
||||||
self.throttled_response = lambda do |env|
|
self.throttled_response = lambda do |env|
|
||||||
|
|
|
@ -26,6 +26,7 @@ co:
|
||||||
password: Ci volenu almenu 8 caratteri
|
password: Ci volenu almenu 8 caratteri
|
||||||
phrase: Sarà trovu senza primura di e maiuscule o di l'avertimenti
|
phrase: Sarà trovu senza primura di e maiuscule o di l'avertimenti
|
||||||
scopes: L'API à quelle l'applicazione averà accessu. S'è voi selezziunate un parametru d'altu livellu, un c'hè micca bisognu di selezziunà quell'individuali.
|
scopes: L'API à quelle l'applicazione averà accessu. S'è voi selezziunate un parametru d'altu livellu, un c'hè micca bisognu di selezziunà quell'individuali.
|
||||||
|
setting_advanced_layout: L'interfaccia avanzata cunsiste in parechje culonne persunalizabile
|
||||||
setting_aggregate_reblogs: Ùn mustrà micca e nove spartere per i statuti chì sò stati spartuti da pocu (tocca solu e spartere più ricente)
|
setting_aggregate_reblogs: Ùn mustrà micca e nove spartere per i statuti chì sò stati spartuti da pocu (tocca solu e spartere più ricente)
|
||||||
setting_default_language: A lingua di i vostri statuti pò esse induvinata autumaticamente, mà ùn marchja micca sempre bè
|
setting_default_language: A lingua di i vostri statuti pò esse induvinata autumaticamente, mà ùn marchja micca sempre bè
|
||||||
setting_display_media_default: Piattà i media marcati cum'è sensibili
|
setting_display_media_default: Piattà i media marcati cum'è sensibili
|
||||||
|
@ -90,6 +91,7 @@ co:
|
||||||
otp_attempt: Codice d’identificazione à dui fattori
|
otp_attempt: Codice d’identificazione à dui fattori
|
||||||
password: Chjave d’accessu
|
password: Chjave d’accessu
|
||||||
phrase: Parolla-chjave o frasa
|
phrase: Parolla-chjave o frasa
|
||||||
|
setting_advanced_layout: Attivà l'interfaccia web avanzata
|
||||||
setting_aggregate_reblogs: Gruppà e spartere indè e linee
|
setting_aggregate_reblogs: Gruppà e spartere indè e linee
|
||||||
setting_auto_play_gif: Lettura autumatica di i GIF animati
|
setting_auto_play_gif: Lettura autumatica di i GIF animati
|
||||||
setting_boost_modal: Mustrà una cunfirmazione per sparte un statutu
|
setting_boost_modal: Mustrà una cunfirmazione per sparte un statutu
|
||||||
|
|
Loading…
Reference in New Issue