Merge pull request #973 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
This commit is contained in:
		
						commit
						fad29fd230
					
				@ -80,7 +80,7 @@ Rails/HttpStatus:
 | 
				
			|||||||
Rails/Exit:
 | 
					Rails/Exit:
 | 
				
			||||||
  Exclude:
 | 
					  Exclude:
 | 
				
			||||||
    - 'lib/mastodon/*'
 | 
					    - 'lib/mastodon/*'
 | 
				
			||||||
    - 'lib/cli'
 | 
					    - 'lib/cli.rb'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Style/ClassAndModuleChildren:
 | 
					Style/ClassAndModuleChildren:
 | 
				
			||||||
  Enabled: false
 | 
					  Enabled: false
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Api::V1::Accounts::IdentityProofsController < Api::BaseController
 | 
				
			||||||
 | 
					  before_action :require_user!
 | 
				
			||||||
 | 
					  before_action :set_account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  respond_to :json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def index
 | 
				
			||||||
 | 
					    @proofs = @account.identity_proofs.active
 | 
				
			||||||
 | 
					    render json: @proofs, each_serializer: REST::IdentityProofSerializer
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_account
 | 
				
			||||||
 | 
					    @account = Account.find(params[:account_id])
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -18,7 +18,12 @@ class Settings::IdentityProofsController < Settings::BaseController
 | 
				
			|||||||
      provider_username: params[:provider_username]
 | 
					      provider_username: params[:provider_username]
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render layout: 'auth'
 | 
					    if current_account.username == params[:username]
 | 
				
			||||||
 | 
					      render layout: 'auth'
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      flash[:alert] = I18n.t('identity_proofs.errors.wrong_user', proving: params[:username], current: current_account.username)
 | 
				
			||||||
 | 
					      redirect_to settings_identity_proofs_path
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def create
 | 
					  def create
 | 
				
			||||||
@ -26,6 +31,7 @@ class Settings::IdentityProofsController < Settings::BaseController
 | 
				
			|||||||
    @proof.token = resource_params[:token]
 | 
					    @proof.token = resource_params[:token]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if @proof.save
 | 
					    if @proof.save
 | 
				
			||||||
 | 
					      PostStatusService.new.call(current_user.account, text: post_params[:status_text]) if publish_proof?
 | 
				
			||||||
      redirect_to @proof.on_success_path(params[:user_agent])
 | 
					      redirect_to @proof.on_success_path(params[:user_agent])
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      flash[:alert] = I18n.t('identity_proofs.errors.failed', provider: @proof.provider.capitalize)
 | 
					      flash[:alert] = I18n.t('identity_proofs.errors.failed', provider: @proof.provider.capitalize)
 | 
				
			||||||
@ -36,10 +42,22 @@ class Settings::IdentityProofsController < Settings::BaseController
 | 
				
			|||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def check_required_params
 | 
					  def check_required_params
 | 
				
			||||||
    redirect_to settings_identity_proofs_path unless [:provider, :provider_username, :token].all? { |k| params[k].present? }
 | 
					    redirect_to settings_identity_proofs_path unless [:provider, :provider_username, :username, :token].all? { |k| params[k].present? }
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def resource_params
 | 
					  def resource_params
 | 
				
			||||||
    params.require(:account_identity_proof).permit(:provider, :provider_username, :token)
 | 
					    params.require(:account_identity_proof).permit(:provider, :provider_username, :token)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def publish_proof?
 | 
				
			||||||
 | 
					    ActiveModel::Type::Boolean.new.cast(post_params[:post_status])
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def post_params
 | 
				
			||||||
 | 
					    params.require(:account_identity_proof).permit(:post_status, :status_text)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_body_classes
 | 
				
			||||||
 | 
					    @body_classes = ''
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								app/javascript/mastodon/actions/identity_proofs.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								app/javascript/mastodon/actions/identity_proofs.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import api from '../api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST = 'IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST';
 | 
				
			||||||
 | 
					export const IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS = 'IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS';
 | 
				
			||||||
 | 
					export const IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL    = 'IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fetchAccountIdentityProofs = accountId => (dispatch, getState) => {
 | 
				
			||||||
 | 
					  dispatch(fetchAccountIdentityProofsRequest(accountId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  api(getState).get(`/api/v1/accounts/${accountId}/identity_proofs`)
 | 
				
			||||||
 | 
					    .then(({ data }) => dispatch(fetchAccountIdentityProofsSuccess(accountId, data)))
 | 
				
			||||||
 | 
					    .catch(err => dispatch(fetchAccountIdentityProofsFail(accountId, err)));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fetchAccountIdentityProofsRequest = id => ({
 | 
				
			||||||
 | 
					  type: IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fetchAccountIdentityProofsSuccess = (accountId, identity_proofs) => ({
 | 
				
			||||||
 | 
					  type: IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,
 | 
				
			||||||
 | 
					  accountId,
 | 
				
			||||||
 | 
					  identity_proofs,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fetchAccountIdentityProofsFail = (accountId, err) => ({
 | 
				
			||||||
 | 
					  type: IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
 | 
				
			||||||
 | 
					  accountId,
 | 
				
			||||||
 | 
					  err,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -62,6 +62,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    account: ImmutablePropTypes.map,
 | 
					    account: ImmutablePropTypes.map,
 | 
				
			||||||
 | 
					    identity_props: ImmutablePropTypes.list,
 | 
				
			||||||
    onFollow: PropTypes.func.isRequired,
 | 
					    onFollow: PropTypes.func.isRequired,
 | 
				
			||||||
    onBlock: PropTypes.func.isRequired,
 | 
					    onBlock: PropTypes.func.isRequired,
 | 
				
			||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl: PropTypes.object.isRequired,
 | 
				
			||||||
@ -81,7 +82,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { account, intl, domain } = this.props;
 | 
					    const { account, intl, domain, identity_proofs } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!account) {
 | 
					    if (!account) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
@ -234,8 +235,20 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          <div className='account__header__extra'>
 | 
					          <div className='account__header__extra'>
 | 
				
			||||||
            <div className='account__header__bio'>
 | 
					            <div className='account__header__bio'>
 | 
				
			||||||
              {fields.size > 0 && (
 | 
					              { (fields.size > 0 || identity_proofs.size > 0) && (
 | 
				
			||||||
                <div className='account__header__fields'>
 | 
					                <div className='account__header__fields'>
 | 
				
			||||||
 | 
					                  {identity_proofs.map((proof, i) => (
 | 
				
			||||||
 | 
					                    <dl key={i}>
 | 
				
			||||||
 | 
					                      <dt dangerouslySetInnerHTML={{ __html: proof.get('provider') }} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      <dd className='verified'>
 | 
				
			||||||
 | 
					                        <a href={proof.get('proof_url')} target='_blank' rel='noopener'><span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(proof.get('updated_at'), dateFormatOptions) })}>
 | 
				
			||||||
 | 
					                          <Icon id='check' className='verified__mark' />
 | 
				
			||||||
 | 
					                        </span></a>
 | 
				
			||||||
 | 
					                        <a href={proof.get('profile_url')} target='_blank' rel='noopener'><span dangerouslySetInnerHTML={{ __html: ' '+proof.get('provider_username') }} /></a>
 | 
				
			||||||
 | 
					                      </dd>
 | 
				
			||||||
 | 
					                    </dl>
 | 
				
			||||||
 | 
					                  ))}
 | 
				
			||||||
                  {fields.map((pair, i) => (
 | 
					                  {fields.map((pair, i) => (
 | 
				
			||||||
                    <dl key={i}>
 | 
					                    <dl key={i}>
 | 
				
			||||||
                      <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
 | 
					                      <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ export default class Header extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    account: ImmutablePropTypes.map,
 | 
					    account: ImmutablePropTypes.map,
 | 
				
			||||||
 | 
					    identity_proofs: ImmutablePropTypes.list,
 | 
				
			||||||
    onFollow: PropTypes.func.isRequired,
 | 
					    onFollow: PropTypes.func.isRequired,
 | 
				
			||||||
    onBlock: PropTypes.func.isRequired,
 | 
					    onBlock: PropTypes.func.isRequired,
 | 
				
			||||||
    onMention: PropTypes.func.isRequired,
 | 
					    onMention: PropTypes.func.isRequired,
 | 
				
			||||||
@ -84,7 +85,7 @@ export default class Header extends ImmutablePureComponent {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { account, hideTabs } = this.props;
 | 
					    const { account, hideTabs, identity_proofs } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (account === null) {
 | 
					    if (account === null) {
 | 
				
			||||||
      return <MissingIndicator />;
 | 
					      return <MissingIndicator />;
 | 
				
			||||||
@ -96,6 +97,7 @@ export default class Header extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        <InnerHeader
 | 
					        <InnerHeader
 | 
				
			||||||
          account={account}
 | 
					          account={account}
 | 
				
			||||||
 | 
					          identity_proofs={identity_proofs}
 | 
				
			||||||
          onFollow={this.handleFollow}
 | 
					          onFollow={this.handleFollow}
 | 
				
			||||||
          onBlock={this.handleBlock}
 | 
					          onBlock={this.handleBlock}
 | 
				
			||||||
          onMention={this.handleMention}
 | 
					          onMention={this.handleMention}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@ import { openModal } from '../../../actions/modal';
 | 
				
			|||||||
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
 | 
					import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
 | 
				
			||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
					import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			||||||
import { unfollowModal } from '../../../initial_state';
 | 
					import { unfollowModal } from '../../../initial_state';
 | 
				
			||||||
 | 
					import { List as ImmutableList } from 'immutable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
 | 
					  unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
 | 
				
			||||||
@ -35,6 +36,7 @@ const makeMapStateToProps = () => {
 | 
				
			|||||||
  const mapStateToProps = (state, { accountId }) => ({
 | 
					  const mapStateToProps = (state, { accountId }) => ({
 | 
				
			||||||
    account: getAccount(state, accountId),
 | 
					    account: getAccount(state, accountId),
 | 
				
			||||||
    domain: state.getIn(['meta', 'domain']),
 | 
					    domain: state.getIn(['meta', 'domain']),
 | 
				
			||||||
 | 
					    identity_proofs: state.getIn(['identity_proofs', accountId], ImmutableList()),
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return mapStateToProps;
 | 
					  return mapStateToProps;
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ import ColumnBackButton from '../../components/column_back_button';
 | 
				
			|||||||
import { List as ImmutableList } from 'immutable';
 | 
					import { List as ImmutableList } from 'immutable';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = (state, { params: { accountId }, withReplies = false }) => {
 | 
					const mapStateToProps = (state, { params: { accountId }, withReplies = false }) => {
 | 
				
			||||||
  const path = withReplies ? `${accountId}:with_replies` : accountId;
 | 
					  const path = withReplies ? `${accountId}:with_replies` : accountId;
 | 
				
			||||||
@ -42,6 +43,7 @@ class AccountTimeline extends ImmutablePureComponent {
 | 
				
			|||||||
    const { params: { accountId }, withReplies } = this.props;
 | 
					    const { params: { accountId }, withReplies } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.props.dispatch(fetchAccount(accountId));
 | 
					    this.props.dispatch(fetchAccount(accountId));
 | 
				
			||||||
 | 
					    this.props.dispatch(fetchAccountIdentityProofs(accountId));
 | 
				
			||||||
    if (!withReplies) {
 | 
					    if (!withReplies) {
 | 
				
			||||||
      this.props.dispatch(expandAccountFeaturedTimeline(accountId));
 | 
					      this.props.dispatch(expandAccountFeaturedTimeline(accountId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -51,6 +53,7 @@ class AccountTimeline extends ImmutablePureComponent {
 | 
				
			|||||||
  componentWillReceiveProps (nextProps) {
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
    if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
 | 
					    if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
 | 
				
			||||||
      this.props.dispatch(fetchAccount(nextProps.params.accountId));
 | 
					      this.props.dispatch(fetchAccount(nextProps.params.accountId));
 | 
				
			||||||
 | 
					      this.props.dispatch(fetchAccountIdentityProofs(nextProps.params.accountId));
 | 
				
			||||||
      if (!nextProps.withReplies) {
 | 
					      if (!nextProps.withReplies) {
 | 
				
			||||||
        this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));
 | 
					        this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -83,7 +83,7 @@
 | 
				
			|||||||
  "compose_form.spoiler.unmarked": "Text není skrytý",
 | 
					  "compose_form.spoiler.unmarked": "Text není skrytý",
 | 
				
			||||||
  "compose_form.spoiler_placeholder": "Sem napište vaše varování",
 | 
					  "compose_form.spoiler_placeholder": "Sem napište vaše varování",
 | 
				
			||||||
  "confirmation_modal.cancel": "Zrušit",
 | 
					  "confirmation_modal.cancel": "Zrušit",
 | 
				
			||||||
  "confirmations.block.block_and_report": "Block & Report",
 | 
					  "confirmations.block.block_and_report": "Blokovat a nahlásit",
 | 
				
			||||||
  "confirmations.block.confirm": "Blokovat",
 | 
					  "confirmations.block.confirm": "Blokovat",
 | 
				
			||||||
  "confirmations.block.message": "Jste si jistý/á, že chcete zablokovat uživatele {name}?",
 | 
					  "confirmations.block.message": "Jste si jistý/á, že chcete zablokovat uživatele {name}?",
 | 
				
			||||||
  "confirmations.delete.confirm": "Smazat",
 | 
					  "confirmations.delete.confirm": "Smazat",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								app/javascript/mastodon/reducers/identity_proofs.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/javascript/mastodon/reducers/identity_proofs.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { Map as ImmutableMap, fromJS } from 'immutable';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,
 | 
				
			||||||
 | 
					  IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,
 | 
				
			||||||
 | 
					  IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
 | 
				
			||||||
 | 
					} from '../actions/identity_proofs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initialState = ImmutableMap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function identityProofsReducer(state = initialState, action) {
 | 
				
			||||||
 | 
					  switch(action.type) {
 | 
				
			||||||
 | 
					  case IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST:
 | 
				
			||||||
 | 
					    return state.set('isLoading', true);
 | 
				
			||||||
 | 
					  case IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL:
 | 
				
			||||||
 | 
					    return state.set('isLoading', false);
 | 
				
			||||||
 | 
					  case IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS:
 | 
				
			||||||
 | 
					    return state.update(identity_proofs => identity_proofs.withMutations(map => {
 | 
				
			||||||
 | 
					      map.set('isLoading', false);
 | 
				
			||||||
 | 
					      map.set('loaded', true);
 | 
				
			||||||
 | 
					      map.set(action.accountId, fromJS(action.identity_proofs));
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return state;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -30,6 +30,7 @@ import filters from './filters';
 | 
				
			|||||||
import conversations from './conversations';
 | 
					import conversations from './conversations';
 | 
				
			||||||
import suggestions from './suggestions';
 | 
					import suggestions from './suggestions';
 | 
				
			||||||
import polls from './polls';
 | 
					import polls from './polls';
 | 
				
			||||||
 | 
					import identity_proofs from './identity_proofs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const reducers = {
 | 
					const reducers = {
 | 
				
			||||||
  dropdown_menu,
 | 
					  dropdown_menu,
 | 
				
			||||||
@ -56,6 +57,7 @@ const reducers = {
 | 
				
			|||||||
  notifications,
 | 
					  notifications,
 | 
				
			||||||
  height_cache,
 | 
					  height_cache,
 | 
				
			||||||
  custom_emojis,
 | 
					  custom_emojis,
 | 
				
			||||||
 | 
					  identity_proofs,
 | 
				
			||||||
  lists,
 | 
					  lists,
 | 
				
			||||||
  listEditor,
 | 
					  listEditor,
 | 
				
			||||||
  listAdder,
 | 
					  listAdder,
 | 
				
			||||||
 | 
				
			|||||||
@ -3064,15 +3064,19 @@ a.status-card.compact:hover {
 | 
				
			|||||||
.relationship-tag {
 | 
					.relationship-tag {
 | 
				
			||||||
  color: $primary-text-color;
 | 
					  color: $primary-text-color;
 | 
				
			||||||
  margin-bottom: 4px;
 | 
					  margin-bottom: 4px;
 | 
				
			||||||
  opacity: 0.7;
 | 
					 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  vertical-align: top;
 | 
					  vertical-align: top;
 | 
				
			||||||
  background-color: rgba($base-overlay-background, 0.4);
 | 
					  background-color: $base-overlay-background;
 | 
				
			||||||
  text-transform: uppercase;
 | 
					  text-transform: uppercase;
 | 
				
			||||||
  font-size: 11px;
 | 
					  font-size: 11px;
 | 
				
			||||||
  font-weight: 500;
 | 
					  font-weight: 500;
 | 
				
			||||||
  padding: 4px;
 | 
					  padding: 4px;
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  opacity: 0.7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    opacity: 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.setting-toggle {
 | 
					.setting-toggle {
 | 
				
			||||||
 | 
				
			|||||||
@ -10,12 +10,10 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.logo-container {
 | 
					.logo-container {
 | 
				
			||||||
  margin: 100px auto;
 | 
					  margin: 100px auto 50px;
 | 
				
			||||||
  margin-bottom: 50px;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @media screen and (max-width: 400px) {
 | 
					  @media screen and (max-width: 500px) {
 | 
				
			||||||
    margin: 30px auto;
 | 
					    margin: 40px auto 0;
 | 
				
			||||||
    margin-bottom: 20px;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  h1 {
 | 
					  h1 {
 | 
				
			||||||
 | 
				
			|||||||
@ -854,13 +854,19 @@ code {
 | 
				
			|||||||
    flex: 1;
 | 
					    flex: 1;
 | 
				
			||||||
    flex-direction: column;
 | 
					    flex-direction: column;
 | 
				
			||||||
    flex-shrink: 1;
 | 
					    flex-shrink: 1;
 | 
				
			||||||
 | 
					    max-width: 50%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &-sep {
 | 
					    &-sep {
 | 
				
			||||||
 | 
					      align-self: center;
 | 
				
			||||||
      flex-grow: 0;
 | 
					      flex-grow: 0;
 | 
				
			||||||
      overflow: visible;
 | 
					      overflow: visible;
 | 
				
			||||||
      position: relative;
 | 
					      position: relative;
 | 
				
			||||||
      z-index: 1;
 | 
					      z-index: 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p {
 | 
				
			||||||
 | 
					      word-break: break-word;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .account__avatar {
 | 
					  .account__avatar {
 | 
				
			||||||
@ -882,12 +888,13 @@ code {
 | 
				
			|||||||
      height: 100%;
 | 
					      height: 100%;
 | 
				
			||||||
      left: 50%;
 | 
					      left: 50%;
 | 
				
			||||||
      position: absolute;
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      top: 0;
 | 
				
			||||||
      width: 1px;
 | 
					      width: 1px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &__row {
 | 
					  &__row {
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: flex-start;
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-direction: row;
 | 
					    flex-direction: row;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProofProvider::Keybase
 | 
					class ProofProvider::Keybase
 | 
				
			||||||
  BASE_URL = 'https://keybase.io'
 | 
					  BASE_URL = ENV.fetch('KEYBASE_BASE_URL', 'https://keybase.io')
 | 
				
			||||||
 | 
					  DOMAIN = ENV.fetch('KEYBASE_DOMAIN', Rails.configuration.x.local_domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class Error < StandardError; end
 | 
					  class Error < StandardError; end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ class ProofProvider::Keybase::ConfigSerializer < ActiveModel::Serializer
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def domain
 | 
					  def domain
 | 
				
			||||||
    Rails.configuration.x.local_domain
 | 
					    ProofProvider::Keybase::DOMAIN
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def display_name
 | 
					  def display_name
 | 
				
			||||||
@ -66,6 +66,6 @@ class ProofProvider::Keybase::ConfigSerializer < ActiveModel::Serializer
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def contact
 | 
					  def contact
 | 
				
			||||||
    [Setting.site_contact_email.presence].compact
 | 
					    [Setting.site_contact_email.presence || 'unknown'].compact
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -49,14 +49,10 @@ class ProofProvider::Keybase::Verifier
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def query_params
 | 
					  def query_params
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      domain: domain,
 | 
					      domain: ProofProvider::Keybase::DOMAIN,
 | 
				
			||||||
      kb_username: @provider_username,
 | 
					      kb_username: @provider_username,
 | 
				
			||||||
      username: @local_username,
 | 
					      username: @local_username,
 | 
				
			||||||
      sig_hash: @token,
 | 
					      sig_hash: @token,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					 | 
				
			||||||
  def domain
 | 
					 | 
				
			||||||
    Rails.configuration.x.local_domain
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@ class AccountIdentityProof < ApplicationRecord
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  scope :active, -> { where(verified: true, live: true) }
 | 
					  scope :active, -> { where(verified: true, live: true) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  after_create_commit :queue_worker
 | 
					  after_commit :queue_worker, if: :saved_change_to_token?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delegate :refresh!, :on_success_path, :badge, to: :provider_instance
 | 
					  delegate :refresh!, :on_success_path, :badge, to: :provider_instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								app/serializers/rest/identity_proof_serializer.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/serializers/rest/identity_proof_serializer.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class REST::IdentityProofSerializer < ActiveModel::Serializer
 | 
				
			||||||
 | 
					  attributes :provider, :provider_username, :updated_at, :proof_url, :profile_url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def proof_url
 | 
				
			||||||
 | 
					    object.badge.proof_url
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def profile_url
 | 
				
			||||||
 | 
					    object.badge.profile_url
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def provider
 | 
				
			||||||
 | 
					    object.provider.capitalize
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -27,5 +27,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          %p= t('identity_proofs.i_am_html', username: content_tag(:strong, @proof.provider_username), service: @proof.provider.capitalize)
 | 
					          %p= t('identity_proofs.i_am_html', username: content_tag(:strong, @proof.provider_username), service: @proof.provider.capitalize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .connection-prompt__post
 | 
				
			||||||
 | 
					      = f.input :post_status, label: t('identity_proofs.publicize_checkbox'), as: :boolean, wrapper: :with_label, :input_html => { checked: true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      = f.input :status_text, as: :text, input_html: { value: t('identity_proofs.publicize_toot', username: @proof.provider_username, service: @proof.provider.capitalize, url: @proof.badge.proof_url), rows: 4 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    = f.button :button, t('identity_proofs.authorize'), type: :submit
 | 
					    = f.button :button, t('identity_proofs.authorize'), type: :submit
 | 
				
			||||||
    = link_to t('simple_form.no'), settings_identity_proofs_url, class: 'button negative'
 | 
					    = link_to t('simple_form.no'), settings_identity_proofs_url, class: 'button negative'
 | 
				
			||||||
 | 
				
			|||||||
@ -2,8 +2,9 @@
 | 
				
			|||||||
cs:
 | 
					cs:
 | 
				
			||||||
  activerecord:
 | 
					  activerecord:
 | 
				
			||||||
    attributes:
 | 
					    attributes:
 | 
				
			||||||
      status:
 | 
					      poll:
 | 
				
			||||||
        owned_poll: Anketa
 | 
					        expires_at: Uzávěrka
 | 
				
			||||||
 | 
					        options: Volby
 | 
				
			||||||
    errors:
 | 
					    errors:
 | 
				
			||||||
      models:
 | 
					      models:
 | 
				
			||||||
        account:
 | 
					        account:
 | 
				
			||||||
 | 
				
			|||||||
@ -249,6 +249,7 @@ cs:
 | 
				
			|||||||
      feature_profile_directory: Adresář profilů
 | 
					      feature_profile_directory: Adresář profilů
 | 
				
			||||||
      feature_registrations: Registrace
 | 
					      feature_registrations: Registrace
 | 
				
			||||||
      feature_relay: Federovací most
 | 
					      feature_relay: Federovací most
 | 
				
			||||||
 | 
					      feature_timeline_preview: Náhled časové osy
 | 
				
			||||||
      features: Vlastnosti
 | 
					      features: Vlastnosti
 | 
				
			||||||
      hidden_service: Federace se skrytými službami
 | 
					      hidden_service: Federace se skrytými službami
 | 
				
			||||||
      open_reports: otevřená hlášení
 | 
					      open_reports: otevřená hlášení
 | 
				
			||||||
 | 
				
			|||||||
@ -652,10 +652,13 @@ en:
 | 
				
			|||||||
      keybase:
 | 
					      keybase:
 | 
				
			||||||
        invalid_token: Keybase tokens are hashes of signatures and must be 66 hex characters
 | 
					        invalid_token: Keybase tokens are hashes of signatures and must be 66 hex characters
 | 
				
			||||||
        verification_failed: Keybase does not recognize this token as a signature of Keybase user %{kb_username}. Please retry from Keybase.
 | 
					        verification_failed: Keybase does not recognize this token as a signature of Keybase user %{kb_username}. Please retry from Keybase.
 | 
				
			||||||
 | 
					      wrong_user: Cannot create a proof for %{proving} while logged in as %{current}. Log in as %{proving} and try again.
 | 
				
			||||||
    explanation_html: Here you can cryptographically connect your other identities, such as a Keybase profile. This lets other people send you encrypted messages and trust content you send them.
 | 
					    explanation_html: Here you can cryptographically connect your other identities, such as a Keybase profile. This lets other people send you encrypted messages and trust content you send them.
 | 
				
			||||||
    i_am_html: I am %{username} on %{service}.
 | 
					    i_am_html: I am %{username} on %{service}.
 | 
				
			||||||
    identity: Identity
 | 
					    identity: Identity
 | 
				
			||||||
    inactive: Inactive
 | 
					    inactive: Inactive
 | 
				
			||||||
 | 
					    publicize_checkbox: 'And toot this:'
 | 
				
			||||||
 | 
					    publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}'
 | 
				
			||||||
    status: Verification status
 | 
					    status: Verification status
 | 
				
			||||||
    view_proof: View proof
 | 
					    view_proof: View proof
 | 
				
			||||||
  imports:
 | 
					  imports:
 | 
				
			||||||
 | 
				
			|||||||
@ -366,6 +366,7 @@ Rails.application.routes.draw do
 | 
				
			|||||||
        resources :followers, only: :index, controller: 'accounts/follower_accounts'
 | 
					        resources :followers, only: :index, controller: 'accounts/follower_accounts'
 | 
				
			||||||
        resources :following, only: :index, controller: 'accounts/following_accounts'
 | 
					        resources :following, only: :index, controller: 'accounts/following_accounts'
 | 
				
			||||||
        resources :lists, only: :index, controller: 'accounts/lists'
 | 
					        resources :lists, only: :index, controller: 'accounts/lists'
 | 
				
			||||||
 | 
					        resources :identity_proofs, only: :index, controller: 'accounts/identity_proofs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        member do
 | 
					        member do
 | 
				
			||||||
          post :follow
 | 
					          post :follow
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										73
									
								
								lib/cli.rb
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								lib/cli.rb
									
									
									
									
									
								
							@ -41,6 +41,79 @@ module Mastodon
 | 
				
			|||||||
    desc 'domains SUBCOMMAND ...ARGS', 'Manage account domains'
 | 
					    desc 'domains SUBCOMMAND ...ARGS', 'Manage account domains'
 | 
				
			||||||
    subcommand 'domains', Mastodon::DomainsCLI
 | 
					    subcommand 'domains', Mastodon::DomainsCLI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    option :dry_run, type: :boolean
 | 
				
			||||||
 | 
					    desc 'self-destruct', 'Erase the server from the federation'
 | 
				
			||||||
 | 
					    long_desc <<~LONG_DESC
 | 
				
			||||||
 | 
					      Erase the server from the federation by broadcasting account delete
 | 
				
			||||||
 | 
					      activities to all known other servers. This allows a "clean exit" from
 | 
				
			||||||
 | 
					      running a Mastodon server, as it leaves next to no cache behind on
 | 
				
			||||||
 | 
					      other servers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      This command is always interactive and requires confirmation twice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      No local data is actually deleted, because emptying the
 | 
				
			||||||
 | 
					      database or removing files is much faster through other, external
 | 
				
			||||||
 | 
					      means, such as e.g. deleting the entire VPS. However, because other
 | 
				
			||||||
 | 
					      servers will delete data about local users, but no local data will be
 | 
				
			||||||
 | 
					      updated (such as e.g. followers), there will be a state mismatch
 | 
				
			||||||
 | 
					      that will lead to glitches and issues if you then continue to run and use
 | 
				
			||||||
 | 
					      the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      So either you know exactly what you are doing, or you are starting
 | 
				
			||||||
 | 
					      from a blank slate afterwards by manually clearing out all the local
 | 
				
			||||||
 | 
					      data!
 | 
				
			||||||
 | 
					    LONG_DESC
 | 
				
			||||||
 | 
					    def self_destruct
 | 
				
			||||||
 | 
					      require 'tty-prompt'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      prompt = TTY::Prompt.new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      prompt.warn('This operation WILL NOT be reversible. It can also take a long time.')
 | 
				
			||||||
 | 
					      prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.')
 | 
				
			||||||
 | 
					      prompt.warn('A running Sidekiq process is required. Do not shut it down until queues clear.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      exit(1) if prompt.no?('Are you sure you want to proceed?')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      inboxes   = Account.inboxes
 | 
				
			||||||
 | 
					      processed = 0
 | 
				
			||||||
 | 
					      dry_run   = options[:dry_run] ? ' (DRY RUN)' : ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if inboxes.empty?
 | 
				
			||||||
 | 
					        prompt.ok('It seems like your server has not federated with anything')
 | 
				
			||||||
 | 
					        prompt.ok('You can shut it down and delete it any time')
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      prompt.warn('Do NOT interrupt this process...')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Account.local.without_suspended.find_each do |account|
 | 
				
			||||||
 | 
					        payload = ActiveModelSerializers::SerializableResource.new(
 | 
				
			||||||
 | 
					          account,
 | 
				
			||||||
 | 
					          serializer: ActivityPub::DeleteActorSerializer,
 | 
				
			||||||
 | 
					          adapter: ActivityPub::Adapter
 | 
				
			||||||
 | 
					        ).as_json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unless options[:dry_run]
 | 
				
			||||||
 | 
					          ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
 | 
				
			||||||
 | 
					            [json, account.id, inbox_url]
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          account.update_column(:suspended, true)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        processed += 1
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      prompt.ok("Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run}")
 | 
				
			||||||
 | 
					      prompt.ok('Wait until Sidekiq processes all items, then you can shut everything down and delete the data')
 | 
				
			||||||
 | 
					    rescue TTY::Reader::InputInterrupt
 | 
				
			||||||
 | 
					      exit(1)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    map %w(--version -v) => :version
 | 
					    map %w(--version -v) => :version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    desc 'version', 'Show version'
 | 
					    desc 'version', 'Show version'
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
require 'rails_helper'
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe Settings::IdentityProofsController do
 | 
					describe Settings::IdentityProofsController do
 | 
				
			||||||
 | 
					  include RoutingHelper
 | 
				
			||||||
  render_views
 | 
					  render_views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let(:user) { Fabricate(:user) }
 | 
					  let(:user) { Fabricate(:user) }
 | 
				
			||||||
@ -9,8 +10,15 @@ describe Settings::IdentityProofsController do
 | 
				
			|||||||
  let(:provider) { 'keybase' }
 | 
					  let(:provider) { 'keybase' }
 | 
				
			||||||
  let(:findable_id) { Faker::Number.number(5) }
 | 
					  let(:findable_id) { Faker::Number.number(5) }
 | 
				
			||||||
  let(:unfindable_id) { Faker::Number.number(5) }
 | 
					  let(:unfindable_id) { Faker::Number.number(5) }
 | 
				
			||||||
 | 
					  let(:new_proof_params) do
 | 
				
			||||||
 | 
					    { provider: provider, provider_username: kbname, token: valid_token, username: user.account.username }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  let(:status_text) { "i just proved that i am also #{kbname} on #{provider}." }
 | 
				
			||||||
 | 
					  let(:status_posting_params) do
 | 
				
			||||||
 | 
					    { post_status: '0', status_text: status_text }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
  let(:postable_params) do
 | 
					  let(:postable_params) do
 | 
				
			||||||
    { account_identity_proof: { provider: provider, provider_username: kbname, token: valid_token } }
 | 
					    { account_identity_proof: new_proof_params.merge(status_posting_params) }
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  before do
 | 
					  before do
 | 
				
			||||||
@ -19,10 +27,32 @@ describe Settings::IdentityProofsController do
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe 'new proof creation' do
 | 
					  describe 'new proof creation' do
 | 
				
			||||||
    context 'GET #new with no existing proofs' do
 | 
					    context 'GET #new' do
 | 
				
			||||||
      it 'redirects to :index' do
 | 
					      context 'with all of the correct params' do
 | 
				
			||||||
        get :new
 | 
					        before do
 | 
				
			||||||
        expect(response).to redirect_to settings_identity_proofs_path
 | 
					          allow_any_instance_of(ProofProvider::Keybase::Badge).to receive(:avatar_url) { full_pack_url('media/images/void.png') }
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'renders the template' do
 | 
				
			||||||
 | 
					          get :new, params: new_proof_params
 | 
				
			||||||
 | 
					          expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'without any params' do
 | 
				
			||||||
 | 
					        it 'redirects to :index' do
 | 
				
			||||||
 | 
					          get :new, params: {}
 | 
				
			||||||
 | 
					          expect(response).to redirect_to settings_identity_proofs_path
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'with params to prove a different, not logged-in user' do
 | 
				
			||||||
 | 
					        let(:wrong_user_params) { new_proof_params.merge(username: 'someone_else') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'shows a helpful alert' do
 | 
				
			||||||
 | 
					          get :new, params: wrong_user_params
 | 
				
			||||||
 | 
					          expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.wrong_user', proving: 'someone_else', current: user.account.username)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,6 +74,23 @@ describe Settings::IdentityProofsController do
 | 
				
			|||||||
          post :create, params: postable_params
 | 
					          post :create, params: postable_params
 | 
				
			||||||
          expect(response).to redirect_to root_url
 | 
					          expect(response).to redirect_to root_url
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'does not post a status' do
 | 
				
			||||||
 | 
					          expect(PostStatusService).not_to receive(:new)
 | 
				
			||||||
 | 
					          post :create, params: postable_params
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        context 'and the user has requested to post a status' do
 | 
				
			||||||
 | 
					          let(:postable_params_with_status) do
 | 
				
			||||||
 | 
					            postable_params.tap { |p| p[:account_identity_proof][:post_status] = '1' }
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          it 'posts a status' do
 | 
				
			||||||
 | 
					            expect_any_instance_of(PostStatusService).to receive(:call).with(user.account, text: status_text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            post :create, params: postable_params_with_status
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'when saving fails' do
 | 
					      context 'when saving fails' do
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user