Merge commit '0ad66175bf59a34b03d9ab2347181548d07089ea' into glitch-soc/merge-upstream
Conflicts: - `app/javascript/mastodon/features/compose/components/compose_form.jsx`: Upstream changed one import, close to a glitch-soc-only import to handle different max character counts. Ported upstream's change.th-new
commit
b0c76eaadd
|
@ -9,6 +9,10 @@ module FormattingHelper
|
|||
TextFormatter.new(text, options).to_s
|
||||
end
|
||||
|
||||
def url_for_preview_card(preview_card)
|
||||
preview_card.url
|
||||
end
|
||||
|
||||
def extract_status_plain_text(status)
|
||||
PlainTextFormatter.new(status.text, status.local?).to_s
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { render, fireEvent, screen } from '@testing-library/react';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import Button from '../button';
|
||||
import { Button } from '../button';
|
||||
|
||||
describe('<Button />', () => {
|
||||
it('renders a button element', () => {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
|||
import { me } from '../initial_state';
|
||||
|
||||
import { Avatar } from './avatar';
|
||||
import Button from './button';
|
||||
import { Button } from './button';
|
||||
import { FollowersCounter } from './counters';
|
||||
import { DisplayName } from './display_name';
|
||||
import { IconButton } from './icon_button';
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class Button extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
text: PropTypes.node,
|
||||
type: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
block: PropTypes.bool,
|
||||
secondary: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
type: 'button',
|
||||
};
|
||||
|
||||
handleClick = (e) => {
|
||||
if (!this.props.disabled && this.props.onClick) {
|
||||
this.props.onClick(e);
|
||||
}
|
||||
};
|
||||
|
||||
setRef = (c) => {
|
||||
this.node = c;
|
||||
};
|
||||
|
||||
focus() {
|
||||
this.node.focus();
|
||||
}
|
||||
|
||||
render () {
|
||||
const className = classNames('button', this.props.className, {
|
||||
'button-secondary': this.props.secondary,
|
||||
'button--block': this.props.block,
|
||||
});
|
||||
|
||||
return (
|
||||
<button
|
||||
className={className}
|
||||
disabled={this.props.disabled}
|
||||
onClick={this.handleClick}
|
||||
ref={this.setRef}
|
||||
title={this.props.title}
|
||||
type={this.props.type}
|
||||
>
|
||||
{this.props.text || this.props.children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface BaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
block?: boolean;
|
||||
secondary?: boolean;
|
||||
text?: JSX.Element;
|
||||
}
|
||||
|
||||
interface PropsWithChildren extends BaseProps {
|
||||
text?: never;
|
||||
}
|
||||
|
||||
interface PropsWithText extends BaseProps {
|
||||
text: JSX.Element;
|
||||
children: never;
|
||||
}
|
||||
|
||||
type Props = PropsWithText | PropsWithChildren;
|
||||
|
||||
export const Button: React.FC<Props> = ({
|
||||
text,
|
||||
type = 'button',
|
||||
onClick,
|
||||
disabled,
|
||||
block,
|
||||
secondary,
|
||||
className,
|
||||
title,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const handleClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
|
||||
(e) => {
|
||||
if (!disabled && onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
},
|
||||
[disabled, onClick],
|
||||
);
|
||||
|
||||
return (
|
||||
<button
|
||||
className={classNames('button', className, {
|
||||
'button-secondary': secondary,
|
||||
'button--block': block,
|
||||
})}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
title={title}
|
||||
type={type}
|
||||
{...props}
|
||||
>
|
||||
{text ?? children}
|
||||
</button>
|
||||
);
|
||||
};
|
|
@ -11,7 +11,7 @@ import { HotKeys } from 'react-hotkeys';
|
|||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||
import { withOptionalRouter, WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
import { withOptionalRouter, WithOptionalRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import Card from '../features/status/components/card';
|
||||
// We use the component (and not the container) since we do not want
|
||||
|
@ -113,7 +113,7 @@ class Status extends ImmutablePureComponent {
|
|||
inUse: PropTypes.bool,
|
||||
available: PropTypes.bool,
|
||||
}),
|
||||
...WithRouterPropTypes,
|
||||
...WithOptionalRouterPropTypes,
|
||||
};
|
||||
|
||||
// Avoid checking props that are functions (and whose equality will always
|
||||
|
|
|
@ -11,7 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { FollowersCounter, FollowingCounter, StatusesCounter } from 'mastodon/components/counters';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
|
|
@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl';
|
|||
import { connect } from 'react-redux';
|
||||
|
||||
import { revealAccount } from 'mastodon/actions/accounts';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
|
||||
const mapDispatchToProps = (dispatch, { accountId }) => ({
|
||||
|
|
|
@ -14,7 +14,7 @@ import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/
|
|||
|
||||
import AutosuggestInput from '../../../components/autosuggest_input';
|
||||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||
import Button from '../../../components/button';
|
||||
import { Button } from '../../../components/button';
|
||||
import { maxChars } from '../../../initial_state';
|
||||
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
|
||||
import LanguageDropdown from '../containers/language_dropdown_container';
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
} from 'mastodon/actions/accounts';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { DisplayName } from 'mastodon/components/display_name';
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import { autoPlayGif, me, unfollowModal } from 'mastodon/initial_state';
|
||||
|
|
|
@ -45,13 +45,10 @@ class Statuses extends PureComponent {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<DismissableBanner id='explore/statuses'>
|
||||
<FormattedMessage id='dismissable_banner.explore_statuses' defaultMessage='These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favorites are ranked higher.' />
|
||||
</DismissableBanner>
|
||||
|
||||
<StatusList
|
||||
trackScroll
|
||||
prepend={<DismissableBanner id='explore/statuses'><FormattedMessage id='dismissable_banner.explore_statuses' defaultMessage='These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favorites are ranked higher.' /></DismissableBanner>}
|
||||
alwaysPrepend
|
||||
timelineId='explore'
|
||||
statusIds={statusIds}
|
||||
scrollKey='explore-statuses'
|
||||
|
@ -62,7 +59,6 @@ class Statuses extends PureComponent {
|
|||
bindToDocument={!multiColumn}
|
||||
withCounters
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { toServerSideType } from 'mastodon/utils/filters';
|
||||
|
||||
const mapStateToProps = (state, { filterId }) => ({
|
||||
|
|
|
@ -4,7 +4,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
|
|
@ -11,7 +11,7 @@ import { throttle, escapeRegExp } from 'lodash';
|
|||
|
||||
import { openModal, closeModal } from 'mastodon/actions/modal';
|
||||
import api from 'mastodon/api';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { registrationsOpen, sso_redirect } from 'mastodon/initial_state';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { defineMessages, injectIntl } from 'react-intl';
|
|||
import { connect } from 'react-redux';
|
||||
|
||||
import { changeListEditorTitle, submitListEditor } from 'mastodon/actions/lists';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
|
||||
const messages = defineMessages({
|
||||
label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' },
|
||||
|
|
|
@ -7,7 +7,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { requestBrowserPermission } from 'mastodon/actions/notifications';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { List as ImmutableList } from 'immutable';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
|
||||
import Option from './components/option';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import { createSelector } from 'reselect';
|
|||
import Toggle from 'react-toggle';
|
||||
|
||||
import { fetchAccount } from 'mastodon/actions/accounts';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
|
|
@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
|
||||
import Option from './components/option';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { OrderedSet } from 'immutable';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import StatusCheckBox from 'mastodon/features/report/containers/status_check_box_container';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
muteAccount,
|
||||
blockAccount,
|
||||
} from 'mastodon/actions/accounts';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
|
||||
const mapStateToProps = () => ({});
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { connect } from 'react-redux';
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
import { followAccount } from 'mastodon/actions/accounts';
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
import Option from 'mastodon/features/report/components/option';
|
||||
import { languages as preloadedLanguages } from 'mastodon/initial_state';
|
||||
|
|
|
@ -8,7 +8,7 @@ import { connect } from 'react-redux';
|
|||
import { blockAccount } from '../../../actions/accounts';
|
||||
import { closeModal } from '../../../actions/modal';
|
||||
import { initReport } from '../../../actions/reports';
|
||||
import Button from '../../../components/button';
|
||||
import { Button } from '../../../components/button';
|
||||
import { makeGetAccount } from '../../../selectors';
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
|
@ -51,10 +51,6 @@ class BlockModal extends PureComponent {
|
|||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.button.focus();
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClose();
|
||||
this.props.onConfirm(this.props.account);
|
||||
|
@ -69,10 +65,6 @@ class BlockModal extends PureComponent {
|
|||
this.props.onClose();
|
||||
};
|
||||
|
||||
setRef = (c) => {
|
||||
this.button = c;
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account } = this.props;
|
||||
|
||||
|
@ -95,7 +87,7 @@ class BlockModal extends PureComponent {
|
|||
<Button onClick={this.handleSecondary} className='confirmation-modal__secondary-button'>
|
||||
<FormattedMessage id='confirmations.block.block_and_report' defaultMessage='Block & Report' />
|
||||
</Button>
|
||||
<Button onClick={this.handleClick} ref={this.setRef}>
|
||||
<Button onClick={this.handleClick} autoFocus>
|
||||
<FormattedMessage id='confirmations.block.confirm' defaultMessage='Block' />
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,7 @@ import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdo
|
|||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import { Avatar } from '../../../components/avatar';
|
||||
import Button from '../../../components/button';
|
||||
import { Button } from '../../../components/button';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
import { RelativeTimestamp } from '../../../components/relative_timestamp';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
|
@ -55,10 +55,6 @@ class BoostModal extends ImmutablePureComponent {
|
|||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.button.focus();
|
||||
}
|
||||
|
||||
handleReblog = () => {
|
||||
this.props.onReblog(this.props.status, this.props.privacy);
|
||||
this.props.onClose();
|
||||
|
@ -76,10 +72,6 @@ class BoostModal extends ImmutablePureComponent {
|
|||
return document.getElementsByClassName('modal-root__container')[0];
|
||||
};
|
||||
|
||||
setRef = (c) => {
|
||||
this.button = c;
|
||||
};
|
||||
|
||||
render () {
|
||||
const { status, privacy, intl } = this.props;
|
||||
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
|
||||
|
@ -133,7 +125,7 @@ class BoostModal extends ImmutablePureComponent {
|
|||
onChange={this.props.onChangeBoostPrivacy}
|
||||
/>
|
||||
)}
|
||||
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
|
||||
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} autoFocus />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -7,7 +7,7 @@ import classNames from 'classnames';
|
|||
import { Helmet } from 'react-helmet';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import Column from 'mastodon/components/column';
|
||||
import { autoPlayGif } from 'mastodon/initial_state';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { PureComponent } from 'react';
|
|||
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import Button from '../../../components/button';
|
||||
import { Button } from '../../../components/button';
|
||||
|
||||
class ConfirmationModal extends PureComponent {
|
||||
|
||||
|
@ -22,10 +22,6 @@ class ConfirmationModal extends PureComponent {
|
|||
closeWhenConfirm: true,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.button.focus();
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
if (this.props.closeWhenConfirm) {
|
||||
this.props.onClose();
|
||||
|
@ -42,10 +38,6 @@ class ConfirmationModal extends PureComponent {
|
|||
this.props.onClose();
|
||||
};
|
||||
|
||||
setRef = (c) => {
|
||||
this.button = c;
|
||||
};
|
||||
|
||||
render () {
|
||||
const { message, confirm, secondary } = this.props;
|
||||
|
||||
|
@ -62,7 +54,7 @@ class ConfirmationModal extends PureComponent {
|
|||
{secondary !== undefined && (
|
||||
<Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' />
|
||||
)}
|
||||
<Button text={confirm} onClick={this.handleClick} ref={this.setRef} />
|
||||
<Button text={confirm} onClick={this.handleClick} autoFocus />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -16,7 +16,7 @@ import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js';
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';
|
||||
|
||||
import Button from 'mastodon/components/button';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { GIFV } from 'mastodon/components/gifv';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
import Audio from 'mastodon/features/audio';
|
||||
|
|
|
@ -10,7 +10,7 @@ import Toggle from 'react-toggle';
|
|||
import { muteAccount } from '../../../actions/accounts';
|
||||
import { closeModal } from '../../../actions/modal';
|
||||
import { toggleHideNotifications, changeMuteDuration } from '../../../actions/mutes';
|
||||
import Button from '../../../components/button';
|
||||
import { Button } from '../../../components/button';
|
||||
|
||||
const messages = defineMessages({
|
||||
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
|
||||
|
@ -63,10 +63,6 @@ class MuteModal extends PureComponent {
|
|||
onChangeMuteDuration: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.button.focus();
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClose();
|
||||
this.props.onConfirm(this.props.account, this.props.notifications, this.props.muteDuration);
|
||||
|
@ -76,10 +72,6 @@ class MuteModal extends PureComponent {
|
|||
this.props.onClose();
|
||||
};
|
||||
|
||||
setRef = (c) => {
|
||||
this.button = c;
|
||||
};
|
||||
|
||||
toggleNotifications = () => {
|
||||
this.props.onToggleNotifications();
|
||||
};
|
||||
|
@ -134,7 +126,7 @@ class MuteModal extends PureComponent {
|
|||
<Button onClick={this.handleCancel} className='mute-modal__cancel-button'>
|
||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||
</Button>
|
||||
<Button onClick={this.handleClick} ref={this.setRef}>
|
||||
<Button onClick={this.handleClick} autoFocus>
|
||||
<FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' />
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -163,13 +163,13 @@
|
|||
"confirmation_modal.cancel": "Annulearje",
|
||||
"confirmations.block.block_and_report": "Blokkearje en rapportearje",
|
||||
"confirmations.block.confirm": "Blokkearje",
|
||||
"confirmations.block.message": "Bisto wis datsto {name} blokkearje wolst?",
|
||||
"confirmations.block.message": "Binne jo wis dat jo {name} blokkearje wolle?",
|
||||
"confirmations.cancel_follow_request.confirm": "Fersyk annulearje",
|
||||
"confirmations.cancel_follow_request.message": "Binne jo wis dat jo jo fersyk om {name} te folgjen annulearje wolle?",
|
||||
"confirmations.delete.confirm": "Fuortsmite",
|
||||
"confirmations.delete.message": "Binne jo wis dat jo dit berjocht fuortsmite wolle?",
|
||||
"confirmations.delete_list.confirm": "Fuortsmite",
|
||||
"confirmations.delete_list.message": "Bisto wis datsto dizze list foar permanint fuortsmite wolst?",
|
||||
"confirmations.delete_list.message": "Binne jo wis dat jo dizze list foar permanint fuortsmite wolle?",
|
||||
"confirmations.discard_edit_media.confirm": "Fuortsmite",
|
||||
"confirmations.discard_edit_media.message": "Jo hawwe net-bewarre wizigingen yn de mediabeskriuwing of foarfertoaning, wolle jo dizze dochs fuortsmite?",
|
||||
"confirmations.domain_block.confirm": "Alles fan dit domein blokkearje",
|
||||
|
@ -177,16 +177,16 @@
|
|||
"confirmations.edit.confirm": "Bewurkje",
|
||||
"confirmations.edit.message": "Troch no te bewurkjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
|
||||
"confirmations.logout.confirm": "Ofmelde",
|
||||
"confirmations.logout.message": "Bisto wis datsto ôfmelde wolst?",
|
||||
"confirmations.logout.message": "Binne jo wis dat jo ôfmelde wolle?",
|
||||
"confirmations.mute.confirm": "Negearje",
|
||||
"confirmations.mute.explanation": "Dit sil berjochten fan harren en berjochten dêr’t se yn fermeld wurde ûnsichtber meitsje, mar se sille berjochten noch hieltyd sjen kinne en jo folgje kinne.",
|
||||
"confirmations.mute.explanation": "Dit sil berjochten fan harren en berjochten dêr’t se yn fermeld wurde ûnsichtber meitsje, mar se sille jo berjochten noch hieltyd sjen kinne en jo folgje kinne.",
|
||||
"confirmations.mute.message": "Binne jo wis dat jo {name} negearje wolle?",
|
||||
"confirmations.redraft.confirm": "Fuortsmite en opnij opstelle",
|
||||
"confirmations.redraft.message": "Binne jo wis dat jo dit berjocht fuortsmite en opnij opstelle wolle? Favoriten en boosts geane dan ferlern en reaksjes op it oarspronklike berjocht reitsje jo kwyt.",
|
||||
"confirmations.reply.confirm": "Reagearje",
|
||||
"confirmations.reply.message": "Troch no te reagearjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
|
||||
"confirmations.unfollow.confirm": "Net mear folgje",
|
||||
"confirmations.unfollow.message": "Bisto wis datsto {name} net mear folgje wolst?",
|
||||
"confirmations.unfollow.message": "Binne jo wis dat jo {name} net mear folgje wolle?",
|
||||
"conversation.delete": "Petear fuortsmite",
|
||||
"conversation.mark_as_read": "As lêzen markearje",
|
||||
"conversation.open": "Petear toane",
|
||||
|
@ -351,7 +351,7 @@
|
|||
"keyboard_shortcuts.local": "to open local timeline",
|
||||
"keyboard_shortcuts.mention": "Skriuwer fermelde",
|
||||
"keyboard_shortcuts.muted": "to open muted users list",
|
||||
"keyboard_shortcuts.my_profile": "Dyn profyl iepenje",
|
||||
"keyboard_shortcuts.my_profile": "Jo profyl iepenje",
|
||||
"keyboard_shortcuts.notifications": "Meldingen toane",
|
||||
"keyboard_shortcuts.open_media": "Media iepenje",
|
||||
"keyboard_shortcuts.pinned": "Fêstsette berjochten toane",
|
||||
|
@ -421,20 +421,20 @@
|
|||
"navigation_bar.public_timeline": "Globale tiidline",
|
||||
"navigation_bar.search": "Sykje",
|
||||
"navigation_bar.security": "Befeiliging",
|
||||
"not_signed_in_indicator.not_signed_in": "Do moatst oanmelde om tagong ta dizze ynformaasje te krijen.",
|
||||
"not_signed_in_indicator.not_signed_in": "Jo moatte oanmelde om tagong ta dizze ynformaasje te krijen.",
|
||||
"notification.admin.report": "{name} hat {target} rapportearre",
|
||||
"notification.admin.sign_up": "{name} hat harren registrearre",
|
||||
"notification.favourite": "{name} hat jo berjocht as favoryt markearre",
|
||||
"notification.follow": "{name} folget dy",
|
||||
"notification.follow_request": "{name} hat dy in folchfersyk stjoerd",
|
||||
"notification.mention": "{name} hat dy fermeld",
|
||||
"notification.own_poll": "Dyn poll is beëinige",
|
||||
"notification.own_poll": "Jo poll is beëinige",
|
||||
"notification.poll": "In enkête dêr’t jo yn stimd hawwe is beëinige",
|
||||
"notification.reblog": "{name} hat jo berjocht boost",
|
||||
"notification.status": "{name} hat in berjocht pleatst",
|
||||
"notification.update": "{name} hat in berjocht bewurke",
|
||||
"notifications.clear": "Meldingen wiskje",
|
||||
"notifications.clear_confirmation": "Bisto wis datsto al dyn meldingen permanint fuortsmite wolst?",
|
||||
"notifications.clear_confirmation": "Binne jo wis dat jo al jo meldingen permanint fuortsmite wolle?",
|
||||
"notifications.column_settings.admin.report": "Nije rapportaazjes:",
|
||||
"notifications.column_settings.admin.sign_up": "Nije registraasjes:",
|
||||
"notifications.column_settings.alert": "Desktopmeldingen",
|
||||
|
|
|
@ -204,7 +204,7 @@
|
|||
"dismissable_banner.explore_links": "이 소식들은 오늘 소셜 웹에서 가장 많이 공유된 내용들입니다. 새 소식을 더 많은 사람들이 공유할수록 높은 순위가 됩니다.",
|
||||
"dismissable_banner.explore_statuses": "이 게시물들은 오늘 소셜 웹에서 호응을 얻고 있는 게시물들입니다. 부스트와 관심을 받는 새로운 글들이 높은 순위가 됩니다.",
|
||||
"dismissable_banner.explore_tags": "이 해시태그들은 이 서버와 분산화된 네트워크의 다른 서버에서 사람들의 인기를 끌고 있는 것들입니다.",
|
||||
"dismissable_banner.public_timeline": "이것들은 {domain}에 있는 사람들이 팔로우한 사람들의 최신 게시물들입니다.",
|
||||
"dismissable_banner.public_timeline": "{domain} 사람들이 팔로우하는 소셜 웹 사람들의 최신 공개 게시물입니다.",
|
||||
"embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.",
|
||||
"embed.preview": "이렇게 표시됩니다:",
|
||||
"emoji_button.activity": "활동",
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
"compose_form.publish": "Legg ut",
|
||||
"compose_form.publish_form": "Legg ut",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.save_changes": "Gøym",
|
||||
"compose_form.save_changes": "Lagre endringar",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Marker mediet som ømtolig} other {Marker media som ømtolige}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Mediet er markert som ømtolig} other {Media er markerte som ømtolige}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Mediet er ikkje markert som ømtolig} other {Media er ikkje markerte som ømtolige}}",
|
||||
|
@ -171,7 +171,7 @@
|
|||
"confirmations.delete_list.confirm": "Slett",
|
||||
"confirmations.delete_list.message": "Er du sikker på at du vil sletta denne lista for alltid?",
|
||||
"confirmations.discard_edit_media.confirm": "Forkast",
|
||||
"confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkaste dei likevel?",
|
||||
"confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkasta dei likevel?",
|
||||
"confirmations.domain_block.confirm": "Skjul alt frå domenet",
|
||||
"confirmations.domain_block.message": "Er du heilt, heilt sikker på at du vil skjula heile {domain}? I dei fleste tilfelle er det godt nok og føretrekt med nokre få målretta blokkeringar eller målbindingar. Du kjem ikkje til å sjå innhald frå domenet i fødererte tidsliner eller i varsla dine. Fylgjarane dine frå domenet vert fjerna.",
|
||||
"confirmations.edit.confirm": "Rediger",
|
||||
|
@ -285,7 +285,7 @@
|
|||
"footer.privacy_policy": "Personvernsreglar",
|
||||
"footer.source_code": "Vis kjeldekode",
|
||||
"footer.status": "Status",
|
||||
"generic.saved": "Gøymt",
|
||||
"generic.saved": "Lagra",
|
||||
"getting_started.heading": "Kom i gang",
|
||||
"hashtag.column_header.tag_mode.all": "og {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "eller {additional}",
|
||||
|
@ -314,7 +314,7 @@
|
|||
"home.pending_critical_update.link": "Sjå oppdateringar",
|
||||
"home.pending_critical_update.title": "Kritisk sikkerheitsoppdatering er tilgjengeleg!",
|
||||
"home.show_announcements": "Vis kunngjeringar",
|
||||
"interaction_modal.description.favourite": "Med ein konto på Mastodon kan du favorittmerkja dette innlegget for å visa forfattaren at du set pris på det, og for å lagra det til seinare.",
|
||||
"interaction_modal.description.favourite": "Med ein konto på Mastodon kan du favorittmerka dette innlegget for å visa forfattaren at du set pris på det, og for å lagra det til seinare.",
|
||||
"interaction_modal.description.follow": "Med ein konto på Mastodon kan du fylgja {name} for å sjå innlegga deira i din heimestraum.",
|
||||
"interaction_modal.description.reblog": "Med ein konto på Mastodon kan du framheva dette innlegget for å dela det med dine eigne fylgjarar.",
|
||||
"interaction_modal.description.reply": "Med ein konto på Mastodon kan du svara på dette innlegget.",
|
||||
|
@ -673,7 +673,7 @@
|
|||
"status.unmute_conversation": "Opphev målbinding av samtalen",
|
||||
"status.unpin": "Løys frå profil",
|
||||
"subscribed_languages.lead": "Kun innlegg på valde språk vil bli dukke opp i heimestraumen din og i listene dine etter denne endringa. For å motta innlegg på alle språk, la vere å velje nokon.",
|
||||
"subscribed_languages.save": "Gøym",
|
||||
"subscribed_languages.save": "Lagre endringar",
|
||||
"subscribed_languages.target": "Endre abonnerte språk for {target}",
|
||||
"tabs_bar.home": "Heim",
|
||||
"tabs_bar.notifications": "Varsel",
|
||||
|
|
|
@ -303,7 +303,7 @@
|
|||
"hashtag.unfollow": "Отпрати хеш ознаку",
|
||||
"hashtags.and_other": "…и {count, plural, one {још #} few {још #}other {још #}}",
|
||||
"home.actions.go_to_explore": "Погледате шта је у тренду",
|
||||
"home.actions.go_to_suggestions": "Пронађeте људе које бисте пратили",
|
||||
"home.actions.go_to_suggestions": "Пронађете људе које бисте пратили",
|
||||
"home.column_settings.basic": "Основна",
|
||||
"home.column_settings.show_reblogs": "Прикажи подржавања",
|
||||
"home.column_settings.show_replies": "Прикажи одговоре",
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
"column.directory": "瀏覽個人檔案",
|
||||
"column.domain_blocks": "已封鎖網域",
|
||||
"column.favourites": "最愛",
|
||||
"column.firehose": "即時河道",
|
||||
"column.firehose": "即時內容",
|
||||
"column.follow_requests": "跟隨請求",
|
||||
"column.home": "首頁",
|
||||
"column.lists": "列表",
|
||||
|
@ -629,7 +629,7 @@
|
|||
"status.edit": "編輯",
|
||||
"status.edited": "編輯於 {date}",
|
||||
"status.edited_x_times": "已編輯 {count, plural, one {{count} 次} other {{count} 次}}",
|
||||
"status.embed": "內嵌",
|
||||
"status.embed": "內嵌嘟文",
|
||||
"status.favourite": "最愛",
|
||||
"status.filter": "過濾此嘟文",
|
||||
"status.filtered": "已過濾",
|
||||
|
|
|
@ -49,6 +49,7 @@ export function withOptionalRouter(Component) {
|
|||
C.displayName = displayName;
|
||||
C.WrappedComponent = Component;
|
||||
C.propTypes = {
|
||||
...Component.propTypes,
|
||||
wrappedComponentRef: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.func,
|
||||
|
|
|
@ -19,7 +19,7 @@ class ActivityPub::LinkedDataSignature
|
|||
return unless type == 'RsaSignature2017'
|
||||
|
||||
creator = ActivityPub::TagManager.instance.uri_to_actor(creator_uri)
|
||||
creator ||= ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false)
|
||||
creator = ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false) if creator&.public_key.blank?
|
||||
|
||||
return if creator.nil?
|
||||
|
||||
|
@ -28,6 +28,8 @@ class ActivityPub::LinkedDataSignature
|
|||
to_be_verified = options_hash + document_hash
|
||||
|
||||
creator if creator.keypair.public_key.verify(OpenSSL::Digest.new('SHA256'), Base64.decode64(signature), to_be_verified)
|
||||
rescue OpenSSL::PKey::RSAError
|
||||
false
|
||||
end
|
||||
|
||||
def sign!(creator, sign_with: nil)
|
||||
|
|
|
@ -55,7 +55,7 @@ class PreviewCard < ApplicationRecord
|
|||
|
||||
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false
|
||||
|
||||
validates :url, presence: true, uniqueness: true
|
||||
validates :url, presence: true, uniqueness: true, url: true
|
||||
validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES
|
||||
validates_attachment_size :image, less_than: LIMIT
|
||||
remotable_attachment :image, LIMIT
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
.batch-table__row__content.pending-account
|
||||
.pending-account__header
|
||||
= link_to preview_card.title, preview_card.url
|
||||
= link_to preview_card.title, url_for_preview_card(preview_card)
|
||||
|
||||
%br/
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"ignored_warnings": [
|
||||
{
|
||||
"warning_type": "Cross-Site Scripting",
|
||||
"warning_code": 4,
|
||||
"fingerprint": "cd5cfd7f40037fbfa753e494d7129df16e358bfc43ef0da3febafbf4ee1ed3ac",
|
||||
"check_name": "LinkToHref",
|
||||
"message": "Potentially unsafe model attribute in `link_to` href",
|
||||
"file": "app/views/admin/trends/links/_preview_card.html.haml",
|
||||
"line": 7,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/link_to_href",
|
||||
"code": "link_to((Unresolved Model).new.title, (Unresolved Model).new.url)",
|
||||
"render_path": [
|
||||
{
|
||||
"type": "template",
|
||||
"name": "admin/trends/links/index",
|
||||
"line": 49,
|
||||
"file": "app/views/admin/trends/links/index.html.haml",
|
||||
"rendered": {
|
||||
"name": "admin/trends/links/_preview_card",
|
||||
"file": "app/views/admin/trends/links/_preview_card.html.haml"
|
||||
}
|
||||
}
|
||||
],
|
||||
"location": {
|
||||
"type": "template",
|
||||
"template": "admin/trends/links/_preview_card"
|
||||
},
|
||||
"user_input": "(Unresolved Model).new.url",
|
||||
"confidence": "Weak",
|
||||
"cwe_id": [
|
||||
79
|
||||
],
|
||||
"note": ""
|
||||
}
|
||||
],
|
||||
"updated": "2023-07-12 11:20:51 -0400",
|
||||
"brakeman_version": "6.0.0"
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
---
|
||||
:skip_checks:
|
||||
- CheckPermitAttributes
|
||||
:url_safe_methods:
|
||||
- url_for_preview_card
|
||||
|
|
|
@ -36,7 +36,7 @@ zh-CN:
|
|||
status:
|
||||
attributes:
|
||||
reblog:
|
||||
taken: 已被转嘟过
|
||||
taken: 已经被转嘟过
|
||||
user:
|
||||
attributes:
|
||||
email:
|
||||
|
|
|
@ -13,7 +13,7 @@ fy:
|
|||
locked: Jo account is blokkearre.
|
||||
not_found_in_database: "%{authentication_keys} of wachtwurd ûnjildich."
|
||||
pending: Jo account moat noch hieltyd beoardiele wurde.
|
||||
timeout: Dyn sesje is ferrûn, meld dy opnij oan.
|
||||
timeout: Jo sesje is ferrûn. Meld jo opnij oan om troch te gean.
|
||||
unauthenticated: Jo moatte oanmelde of registrearje.
|
||||
unconfirmed: Jo moatte earst jo account befêstigje.
|
||||
mailer:
|
||||
|
|
|
@ -9,7 +9,7 @@ zh-CN:
|
|||
already_authenticated: 你已登录。
|
||||
inactive: 你还没有激活账户。
|
||||
invalid: "%{authentication_keys} 无效或密码错误。"
|
||||
last_attempt: 你只有最后一次尝试机会,若未通过,账号将被锁定。
|
||||
last_attempt: 你只有最后一次尝试机会,若未通过,帐号将被锁定。
|
||||
locked: 你的账户已被锁定。
|
||||
not_found_in_database: "%{authentication_keys}或密码错误。"
|
||||
pending: 你的账号仍在审核中。
|
||||
|
@ -85,7 +85,7 @@ zh-CN:
|
|||
send_instructions: 如果你的电子邮件地址存在于我们的数据库中,你将在几分钟后收到一个密码恢复链接。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
|
||||
send_paranoid_instructions: 如果你的电子邮件地址存在于我们的数据库中,你将在几分钟后收到一个密码恢复链接。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
|
||||
updated: 你的密码已成功修改,现在你已登录。
|
||||
updated_not_active: 你的密码已成功修改。
|
||||
updated_not_active: 你的密码已修改成功。
|
||||
registrations:
|
||||
destroyed: 再见!你的账户已成功注销。我们希望很快可以再见到你。
|
||||
signed_up: 欢迎!你已成功注册。
|
||||
|
|
|
@ -43,7 +43,7 @@ fy:
|
|||
new: Nije tapassing
|
||||
scopes: Tastimmingen
|
||||
show: Toane
|
||||
title: Dyn tapassingen
|
||||
title: Jo tapassingen
|
||||
new:
|
||||
title: Nije tapassing
|
||||
show:
|
||||
|
@ -60,7 +60,7 @@ fy:
|
|||
error:
|
||||
title: Der is in flater bard
|
||||
new:
|
||||
prompt_html: "%{client_name} hat tastimming nedich om tagong te krijen ta dyn account. It giet om in tapassing fan in tredde partij.<strong>Asto dit net fertroust, moatsto gjin tastimming jaan.</strong>"
|
||||
prompt_html: "%{client_name} hat tastimming nedich om tagong te krijen ta jo account. It giet om in tapassing fan in tredde partij.<strong>As jo dit net fertrouwe, moatte jo gjin tastimming jaan.</strong>"
|
||||
review_permissions: Tastimmingen beoardiele
|
||||
title: Autorisaasje fereaske
|
||||
show:
|
||||
|
@ -69,15 +69,15 @@ fy:
|
|||
buttons:
|
||||
revoke: Ynlûke
|
||||
confirmations:
|
||||
revoke: Bisto wis?
|
||||
revoke: Binne jo wis?
|
||||
index:
|
||||
authorized_at: Autorisearre op %{date}
|
||||
description_html: Dit binne tapassingen dy’t tagong hawwe ta dyn account fia de API. As der tapassingen tusken steane dy’tsto net werkenst of in tapassing harren misdraacht, kinsto de tagongsrjochten fan de tapassing ynlûke.
|
||||
description_html: Dit binne tapassingen dy’t fia de API tagong hawwe ta jo account. As der tapassingen tusken steane dy’t jo net werkenne of in tapassing harren misdraacht, kinne jo de tagongsrjochten fan de tapassing ynlûke.
|
||||
last_used_at: Lêst brûkt op %{date}
|
||||
never_used: Nea brûkt
|
||||
scopes: Tastimmingen
|
||||
superapp: Yntern
|
||||
title: Dyn autorisearre tapassingen
|
||||
title: Jo autorisearre tapassingen
|
||||
errors:
|
||||
messages:
|
||||
access_denied: De boarne-eigener of autorisaasjeserver hat it fersyk wegere.
|
||||
|
@ -165,22 +165,22 @@ fy:
|
|||
admin:write:reports: moderaasjemaatregelen nimme yn rapportaazjes
|
||||
crypto: ein-ta-ein-fersifering brûke
|
||||
follow: relaasjes tusken accounts bewurkje
|
||||
push: dyn pushmeldingen ûntfange
|
||||
read: alle gegevens fan dyn account lêze
|
||||
push: jo pushmeldingen ûntfange
|
||||
read: alle gegevens fan jo account lêze
|
||||
read:accounts: accountynformaasje besjen
|
||||
read:blocks: dyn blokkearre brûkers besjen
|
||||
read:bookmarks: dyn blêdwizers besjen
|
||||
read:blocks: jo blokkearre brûkers besjen
|
||||
read:bookmarks: jo blêdwizers besjen
|
||||
read:favourites: jo favoriten besjen
|
||||
read:filters: dyn filters besjen
|
||||
read:filters: jo filters besjen
|
||||
read:follows: de accounts dy’tsto folgest besjen
|
||||
read:lists: dyn listen besjen
|
||||
read:mutes: dyn negearre brûkers besjen
|
||||
read:notifications: dyn meldingen besjen
|
||||
read:reports: dyn rapportearre berjochten besjen
|
||||
read:search: út dyn namme sykje
|
||||
read:lists: jo listen besjen
|
||||
read:mutes: jo negearre brûkers besjen
|
||||
read:notifications: jo meldingen besjen
|
||||
read:reports: jo rapportearre berjochten besjen
|
||||
read:search: út jo namme sykje
|
||||
read:statuses: alle berjochten besjen
|
||||
write: alle gegevens fan dyn account bewurkje
|
||||
write:accounts: dyn profyl bewurkje
|
||||
write: alle gegevens fan jo account bewurkje
|
||||
write:accounts: jo profyl bewurkje
|
||||
write:blocks: accounts en domeinen blokkearje
|
||||
write:bookmarks: berjochten oan blêdwizers tafoegje
|
||||
write:conversations: petearen negearre en fuortsmite
|
||||
|
|
|
@ -570,7 +570,7 @@ nn:
|
|||
enabled: Skrudd på
|
||||
inbox_url: Overførings-URL
|
||||
pending: Avventer overgangens godkjenning
|
||||
save_and_enable: Lagr og slå på
|
||||
save_and_enable: Lagre og slå på
|
||||
setup: Sett opp en overgangsforbindelse
|
||||
signatures_not_enabled: Overgangar fungerer ikkje så lenge sikker- eller kvitlistingsmodus er aktivert
|
||||
status: Status
|
||||
|
@ -1280,7 +1280,7 @@ nn:
|
|||
deselect: Vel ingen
|
||||
none: Ingen
|
||||
order_by: Sorter etter
|
||||
save_changes: Lagr endringar
|
||||
save_changes: Lagre endringar
|
||||
select_all_matching_items:
|
||||
one: Vel %{count} element som passar til søket ditt.
|
||||
other: Vel %{count} element som passar til søket ditt.
|
||||
|
|
|
@ -86,7 +86,7 @@ fy:
|
|||
media_cache_retention_period: Mediabestannen dy’t fan oare servers download binne wurde nei it opjûne oantal dagen fuortsmiten en wurde op fersyk opnij download.
|
||||
peers_api_enabled: In list mei domeinnammen, dêr’t dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dy’t statistiken oer federaasje yn algemiene sin sammelet.
|
||||
profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen.
|
||||
require_invite_text: Meitsje it ynfoljen fan "Wêrom wolle jo jo hjir registrearje?" ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte
|
||||
require_invite_text: Meitsje it ynfoljen fan ‘Wêrom wolle jo jo hjir registrearje?’ ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte
|
||||
site_contact_email: Hoe minsken jo berikke kinne foar juridyske fragen of stipe.
|
||||
site_contact_username: Hoe minsken jo op Mastodon berikke kinne.
|
||||
site_extended_description: Alle oanfoljende ynformaasje dy’t nuttich wêze kin foar besikers en jo brûkers. Kin opmakke wurde mei Markdown.
|
||||
|
|
|
@ -40,7 +40,7 @@ zh-CN:
|
|||
current_email: 当前的电子邮箱
|
||||
label: 更改电子邮箱
|
||||
new_email: 新的电子邮箱
|
||||
submit: 更改电子邮件地址
|
||||
submit: 更改电子邮箱
|
||||
title: 更改 %{username} 的电子邮箱
|
||||
change_role:
|
||||
changed_msg: 已成功更改角色!
|
||||
|
@ -68,8 +68,8 @@ zh-CN:
|
|||
enable_sign_in_token_auth: 启用电子邮件令牌认证
|
||||
enabled: 已启用
|
||||
enabled_msg: 成功解冻 %{username} 的账号
|
||||
followers: 关注者
|
||||
follows: 正在关注
|
||||
followers: 粉丝
|
||||
follows: 关注
|
||||
header: 个人资料页横幅图片
|
||||
inbox_url: 收件箱(Inbox)URL
|
||||
invite_request_text: 加入理由
|
||||
|
|
|
@ -34,6 +34,40 @@ RSpec.describe ActivityPub::LinkedDataSignature do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when local account record is missing a public key' do
|
||||
let(:raw_signature) do
|
||||
{
|
||||
'creator' => 'http://example.com/alice',
|
||||
'created' => '2017-09-23T20:21:34Z',
|
||||
}
|
||||
end
|
||||
|
||||
let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) }
|
||||
|
||||
let(:service_stub) { instance_double(ActivityPub::FetchRemoteKeyService) }
|
||||
|
||||
before do
|
||||
# Ensure signature is computed with the old key
|
||||
signature
|
||||
|
||||
# Unset key
|
||||
old_key = sender.public_key
|
||||
sender.update!(private_key: '', public_key: '')
|
||||
|
||||
allow(ActivityPub::FetchRemoteKeyService).to receive(:new).and_return(service_stub)
|
||||
|
||||
allow(service_stub).to receive(:call).with('http://example.com/alice', id: false) do
|
||||
sender.update!(public_key: old_key)
|
||||
sender
|
||||
end
|
||||
end
|
||||
|
||||
it 'fetches key and returns creator' do
|
||||
expect(subject.verify_actor!).to eq sender
|
||||
expect(service_stub).to have_received(:call).with('http://example.com/alice', id: false).once
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signature is missing' do
|
||||
let(:signature) { nil }
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe PreviewCard do
|
||||
describe 'validations' do
|
||||
describe 'urls' do
|
||||
it 'allows http schemes' do
|
||||
record = described_class.new(url: 'http://example.host/path')
|
||||
|
||||
expect(record).to be_valid
|
||||
end
|
||||
|
||||
it 'allows https schemes' do
|
||||
record = described_class.new(url: 'https://example.host/path')
|
||||
|
||||
expect(record).to be_valid
|
||||
end
|
||||
|
||||
it 'does not allow javascript: schemes' do
|
||||
record = described_class.new(url: 'javascript:alert()')
|
||||
|
||||
expect(record).to_not be_valid
|
||||
expect(record).to model_have_error_on_field(:url)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'admin/trends/links/_preview_card.html.haml' do
|
||||
it 'correctly escapes user supplied url values' do
|
||||
form = instance_double(ActionView::Helpers::FormHelper, check_box: nil)
|
||||
trend = PreviewCardTrend.new(allowed: false)
|
||||
preview_card = Fabricate.build(
|
||||
:preview_card,
|
||||
url: 'https://host.example/path?query=<script>',
|
||||
trend: trend,
|
||||
title: 'Fun'
|
||||
)
|
||||
|
||||
render partial: 'admin/trends/links/preview_card', locals: { preview_card: preview_card, f: form }
|
||||
|
||||
expect(rendered).to include('<a href="https://host.example/path?query=<script>">Fun</a>')
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue