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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user