Expose whether a version is soft or hard-blocked in the blocked page (#13285)

* Expose whether a version is soft or hard-blocked in the blocked page
This commit is contained in:
Mathieu Pillard 2024-10-29 12:51:50 +01:00 коммит произвёл GitHub
Родитель 12e5d2ee1a
Коммит 65d99c8084
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 132 добавлений и 125 удалений

Просмотреть файл

@ -83,52 +83,26 @@ export class BlockBase extends React.Component<InternalProps> {
);
}
renderDateAndURL(): React.Node | Array<React.Node | string> {
renderURL(): React.Node | Array<React.Node | string> {
const { block, i18n } = this.props;
if (!block) {
return <LoadingText />;
}
const content: Array<React.Node | string> = [
i18n.sprintf(i18n.gettext('Blocked on %(date)s.'), {
date: i18n.moment(block.created).format('ll'),
}),
];
if (block.url) {
content.push(
' ',
return (
<a key={block.url.url} href={block.url.outgoing} title={block.url.url}>
{i18n.gettext('View block request')}
</a>,
'.',
</a>
);
}
return content;
}
renderVersions(): React.Node | string {
const { block, i18n } = this.props;
if (!block) {
return <LoadingText />;
}
if (block.is_all_versions) {
return i18n.gettext('Versions blocked: all versions.');
}
const versions = block.versions.join(', ');
return i18n.sprintf(i18n.gettext('Versions blocked: %(versions)s.'), {
versions,
});
return null;
}
render(): React.Node {
const { block, errorHandler, i18n } = this.props;
const { block, errorHandler, i18n, match } = this.props;
if (errorHandler.hasError()) {
log.warn(`Captured API Error: ${errorHandler.capturedError.messages}`);
@ -140,15 +114,40 @@ export class BlockBase extends React.Component<InternalProps> {
return <ServerErrorPage />;
}
const title =
block && block.name
? i18n.sprintf(
i18n.gettext(`%(addonName)s has been blocked for your protection.`),
{
addonName: block.name,
},
)
: i18n.gettext(`This add-on has been blocked for your protection.`);
const isSoftBlocked =
block?.soft_blocked.length &&
(block?.soft_blocked.includes(match.params.versionId) ||
!block?.blocked.length);
let title;
if (isSoftBlocked) {
title =
block && block.name
? i18n.sprintf(
i18n.gettext(
`%(addonName)s is restricted for violating Mozilla policies.`,
),
{
addonName: block.name,
},
)
: i18n.gettext(
`This add-on is restricted for violating Mozilla policies.`,
);
} else {
title =
block && block.name
? i18n.sprintf(
i18n.gettext(
`%(addonName)s is blocked for violating Mozilla policies.`,
),
{
addonName: block.name,
},
)
: i18n.gettext(
`This add-on is blocked for violating Mozilla policies.`,
);
}
return (
<Page>
@ -159,13 +158,13 @@ export class BlockBase extends React.Component<InternalProps> {
</Helmet>
<Card className="Block-content" header={title}>
<h2>{i18n.gettext('Why was it blocked?')}</h2>
<h2>{i18n.gettext('Why did this happen?')}</h2>
<p
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={sanitizeHTML(
i18n.sprintf(
i18n.gettext(`This add-on violates %(startLink)sMozilla's
Add-on Policies%(endLink)s.`),
i18n.gettext(`This extension, theme, or plugin violates
%(startLink)sMozilla's Add-on Policies%(endLink)s.`),
{
startLink: `<a href="${POLICIES_URL}">`,
endLink: '</a>',
@ -178,8 +177,16 @@ export class BlockBase extends React.Component<InternalProps> {
<h2>{i18n.gettext('What does this mean?')}</h2>
<p>
{i18n.gettext(`The problematic add-on or plugin will be
automatically disabled and no longer usable.`)}
{isSoftBlocked
? i18n.gettext(`Until the violation is resolved, this add-on
won't be available for download from addons.mozilla.org.
If its already installed, it will be disabled and users
will be informed about the violation. They may choose to
enable the add-on again at their own risk.`)
: i18n.gettext(`Until the violation is resolved, this add-on
won't be available for download from addons.mozilla.org.
It will be automatically disabled and no longer usable in
Firefox.`)}
</p>
<p
// eslint-disable-next-line react/no-danger
@ -189,9 +196,10 @@ export class BlockBase extends React.Component<InternalProps> {
or other third-party software that seriously compromises
Firefox security, stability, or performance and meets
%(criteriaStartLink)scertain criteria%(criteriaEndLink)s,
the software may be blocked from general use. For more
information, please read %(supportStartLink)sthis support
article%(supportEndLink)s.`),
the software may be blocked or restricted from general
use. For more information, please read
%(supportStartLink)sthis support article%(supportEndLink)s.
`),
{
criteriaStartLink: `<a href="${CRITERIA_URL}">`,
criteriaEndLink: '</a>',
@ -202,11 +210,7 @@ export class BlockBase extends React.Component<InternalProps> {
['a'],
)}
/>
<p className="Block-metadata">
{this.renderVersions()}
<br />
{this.renderDateAndURL()}
</p>
<p className="Block-metadata">{this.renderURL()}</p>
</Card>
</div>
</Page>

Просмотреть файл

@ -14,7 +14,8 @@ export type ExternalBlockType = {|
created: string,
guid: string,
id: number,
versions: [string],
soft_blocked: [string],
blocked: [string],
is_all_versions?: boolean,
modified: string,
reason: string | null,

Просмотреть файл

@ -15,7 +15,6 @@ import {
createFakeBlockResult,
createLocalizedString,
dispatchClientMetadata,
fakeI18n,
getElement,
renderPage as defaultRender,
screen,
@ -129,16 +128,14 @@ describe(__filename, () => {
expect(
within(screen.getByClassName('Block-reason')).getAllByRole('alert'),
).toHaveLength(1);
// 1. versions blocked
// 2. date and URL
expect(
within(screen.getByClassName('Block-metadata')).getAllByRole('alert'),
).toHaveLength(2);
).toHaveLength(1);
});
it('renders a generic header/title when the block has no add-on name', async () => {
const block = _createFakeBlockResult({ addonName: null });
const title = 'This add-on has been blocked for your protection.';
const title = 'This add-on is blocked for violating Mozilla policies.';
store.dispatch(loadBlock({ block }));
render();
@ -155,7 +152,7 @@ describe(__filename, () => {
const block = _createFakeBlockResult({
addonName: createLocalizedString(name),
});
const title = `${name} has been blocked for your protection.`;
const title = `${name} is blocked for violating Mozilla policies.`;
store.dispatch(loadBlock({ block }));
render();
@ -168,6 +165,24 @@ describe(__filename, () => {
expect(screen.getByText(title)).toBeInTheDocument();
});
it('renders a generic soft-block header/title when the block has no add-on name', async () => {
const block = _createFakeBlockResult({
addonName: null,
soft_blocked: ['42.0'],
blocked: [],
});
const title = 'This add-on is restricted for violating Mozilla policies.';
store.dispatch(loadBlock({ block }));
render();
await waitFor(() =>
expect(getElement('title')).toHaveTextContent(
`${title} – Add-ons for Firefox (${lang})`,
),
);
expect(screen.getByText(title)).toBeInTheDocument();
});
it('renders a paragraph with the reason when the block has one', () => {
const reason = 'this is a reason for a block';
const block = _createFakeBlockResult({ reason });
@ -186,69 +201,6 @@ describe(__filename, () => {
expect(screen.queryByClassName('Block-reason')).not.toBeInTheDocument();
});
it('renders "all versions" when "is_all_versions" is true', () => {
const block = _createFakeBlockResult({
is_all_versions: true,
});
const i18n = fakeI18n();
store.dispatch(loadBlock({ block }));
render();
// The version info and the block date are inside the same tag, separated
// by a </br>.
expect(
screen.getByTextAcrossTags(
`Versions blocked: all versions.Blocked on ${i18n
.moment(block.created)
.format('ll')}.`,
),
).toBeInTheDocument();
});
it('renders the versions if "is_all_versions" is false', () => {
const v1 = '12';
const v2 = '34';
const block = _createFakeBlockResult({
versions: [v1, v2],
is_all_versions: false,
});
const i18n = fakeI18n();
store.dispatch(loadBlock({ block }));
render();
// The version info and the block date are inside the same tag, separated
// by a </br>.
expect(
screen.getByTextAcrossTags(
`Versions blocked: ${v1}, ${v2}.Blocked on ${i18n
.moment(block.created)
.format('ll')}.`,
),
).toBeInTheDocument();
});
it('renders the versions if "is_all_versions" is missing', () => {
const v1 = '12';
const v2 = '34';
const block = _createFakeBlockResult({
versions: [v1, v2],
is_all_versions: undefined,
});
const i18n = fakeI18n();
store.dispatch(loadBlock({ block }));
render();
// The version info and the block date are inside the same tag, separated
// by a </br>.
expect(
screen.getByTextAcrossTags(
`Versions blocked: ${v1}, ${v2}.Blocked on ${i18n
.moment(block.created)
.format('ll')}.`,
),
).toBeInTheDocument();
});
it('renders the reason with HTML tags removed', () => {
const reason = 'this is a <a>reason for a block</a>';
const block = _createFakeBlockResult({ reason });
@ -307,7 +259,56 @@ describe(__filename, () => {
});
expect(
screen.getByText(`${name} has been blocked for your protection.`),
screen.getByText(`${name} is blocked for violating Mozilla policies.`),
).toBeInTheDocument();
expect(
screen.getByText(
/It will be automatically disabled and no longer usable in Firefox./,
),
).toBeInTheDocument();
});
it('renders a soft-block page when the block has only soft-blocks', () => {
const name = 'some-addon-name';
const block = _createFakeBlockResult({
addonName: createLocalizedString(name),
soft_blocked: ['42.0'],
blocked: [],
});
store.dispatch(loadBlock({ block }));
render();
expect(
screen.getByText(`${name} is restricted for violating Mozilla policies.`),
).toBeInTheDocument();
expect(
screen.getByText(
/They may choose to enable the add-on again at their own risk./,
),
).toBeInTheDocument();
});
it('renders a soft-block page when a soft-blocked versionId is present in the URL', () => {
const name = 'some-addon-name';
const block = _createFakeBlockResult({
addonName: createLocalizedString(name),
soft_blocked: ['42.0'],
});
store.dispatch(loadBlock({ block }));
defaultRender({
initialEntries: [`${getLocation()}42.0/`],
store,
});
expect(
screen.getByText(`${name} is restricted for violating Mozilla policies.`),
).toBeInTheDocument();
expect(
screen.getByText(
/They may choose to enable the add-on again at their own risk./,
),
).toBeInTheDocument();
});

Просмотреть файл

@ -1312,7 +1312,8 @@ export const createFakeBlockResult = ({
created: '2020-01-22T10:09:01Z',
modified: '2020-01-22T10:09:01Z',
guid,
versions: ['0.1', '4.56'],
blocked: ['0.1', '4.56'],
soft_blocked: [],
is_all_versions: false,
addon_name: addonName,
reason,