mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-02-02 21:13:02 -05:00
Merge pull request #2958 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 2beab34ca405a0beb3ea9f5ab684779dc2eb6374
This commit is contained in:
commit
65caf6c085
@ -530,7 +530,7 @@ GEM
|
|||||||
opentelemetry-instrumentation-rack (0.26.0)
|
opentelemetry-instrumentation-rack (0.26.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.23.0)
|
opentelemetry-instrumentation-base (~> 0.23.0)
|
||||||
opentelemetry-instrumentation-rails (0.35.0)
|
opentelemetry-instrumentation-rails (0.35.1)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-action_mailer (~> 0.4.0)
|
opentelemetry-instrumentation-action_mailer (~> 0.4.0)
|
||||||
opentelemetry-instrumentation-action_pack (~> 0.11.0)
|
opentelemetry-instrumentation-action_pack (~> 0.11.0)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { useIntl, defineMessages } from 'react-intl';
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
||||||
@ -17,10 +18,12 @@ interface Props<T> {
|
|||||||
|
|
||||||
export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
|
export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
onClick(param);
|
onClick(param);
|
||||||
}, [param, onClick]);
|
}, [setLoading, param, onClick]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@ -28,8 +31,13 @@ export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
aria-label={intl.formatMessage(messages.load_more)}
|
aria-label={intl.formatMessage(messages.load_more)}
|
||||||
|
title={intl.formatMessage(messages.load_more)}
|
||||||
>
|
>
|
||||||
<Icon id='ellipsis-h' icon={MoreHorizIcon} />
|
{loading ? (
|
||||||
|
<LoadingIndicator />
|
||||||
|
) : (
|
||||||
|
<Icon id='ellipsis-h' icon={MoreHorizIcon} />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -73,4 +73,4 @@ const guessLanguage = (text) => {
|
|||||||
|
|
||||||
export const debouncedGuess = debounce((text, setGuess) => {
|
export const debouncedGuess = debounce((text, setGuess) => {
|
||||||
setGuess(guessLanguage(text));
|
setGuess(guessLanguage(text));
|
||||||
}, 500, { leading: true, trailing: true });
|
}, 500, { maxWait: 1500, leading: true, trailing: true });
|
||||||
|
@ -4105,23 +4105,27 @@ a.status-card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.load-more {
|
.load-more {
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
color: $dark-text-color;
|
color: $dark-text-color;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
text-align: center;
|
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
margin: 0;
|
width: 100%;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
|
||||||
clear: both;
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--on-surface-color);
|
background: var(--on-surface-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.load-gap {
|
.load-gap {
|
||||||
@ -4643,6 +4647,7 @@ a.status-card {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load-more .loading-indicator,
|
||||||
.button .loading-indicator {
|
.button .loading-indicator {
|
||||||
position: static;
|
position: static;
|
||||||
transform: none;
|
transform: none;
|
||||||
@ -4654,6 +4659,10 @@ a.status-card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load-more .loading-indicator .circular-progress {
|
||||||
|
color: lighten($ui-base-color, 26%);
|
||||||
|
}
|
||||||
|
|
||||||
.circular-progress {
|
.circular-progress {
|
||||||
color: lighten($ui-base-color, 26%);
|
color: lighten($ui-base-color, 26%);
|
||||||
animation: 1.4s linear 0s infinite normal none running simple-rotate;
|
animation: 1.4s linear 0s infinite normal none running simple-rotate;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { useIntl, defineMessages } from 'react-intl';
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
||||||
@ -17,10 +18,12 @@ interface Props<T> {
|
|||||||
|
|
||||||
export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
|
export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
onClick(param);
|
onClick(param);
|
||||||
}, [param, onClick]);
|
}, [setLoading, param, onClick]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@ -28,8 +31,13 @@ export const LoadGap = <T,>({ disabled, param, onClick }: Props<T>) => {
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
aria-label={intl.formatMessage(messages.load_more)}
|
aria-label={intl.formatMessage(messages.load_more)}
|
||||||
|
title={intl.formatMessage(messages.load_more)}
|
||||||
>
|
>
|
||||||
<Icon id='ellipsis-h' icon={MoreHorizIcon} />
|
{loading ? (
|
||||||
|
<LoadingIndicator />
|
||||||
|
) : (
|
||||||
|
<Icon id='ellipsis-h' icon={MoreHorizIcon} />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -333,7 +333,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
const { onToggleHidden } = this.props;
|
const { onToggleHidden } = this.props;
|
||||||
const status = this._properStatus();
|
const status = this._properStatus();
|
||||||
|
|
||||||
if (status.get('matched_filters')) {
|
if (this.props.status.get('matched_filters')) {
|
||||||
const expandedBecauseOfCW = !status.get('hidden') || status.get('spoiler_text').length === 0;
|
const expandedBecauseOfCW = !status.get('hidden') || status.get('spoiler_text').length === 0;
|
||||||
const expandedBecauseOfFilter = this.state.showDespiteFilter;
|
const expandedBecauseOfFilter = this.state.showDespiteFilter;
|
||||||
|
|
||||||
|
@ -73,4 +73,4 @@ const guessLanguage = (text) => {
|
|||||||
|
|
||||||
export const debouncedGuess = debounce((text, setGuess) => {
|
export const debouncedGuess = debounce((text, setGuess) => {
|
||||||
setGuess(guessLanguage(text));
|
setGuess(guessLanguage(text));
|
||||||
}, 500, { leading: true, trailing: true });
|
}, 500, { maxWait: 1500, leading: true, trailing: true });
|
||||||
|
@ -86,6 +86,9 @@
|
|||||||
"alert.unexpected.message": "Vyskytla sa nečakaná chyba.",
|
"alert.unexpected.message": "Vyskytla sa nečakaná chyba.",
|
||||||
"alert.unexpected.title": "Ups!",
|
"alert.unexpected.title": "Ups!",
|
||||||
"alt_text_badge.title": "Alternatívny popis",
|
"alt_text_badge.title": "Alternatívny popis",
|
||||||
|
"alt_text_modal.add_text_from_image": "Pridaj text z obrázka",
|
||||||
|
"alt_text_modal.cancel": "Zrušiť",
|
||||||
|
"alt_text_modal.done": "Hotovo",
|
||||||
"announcement.announcement": "Oznámenie",
|
"announcement.announcement": "Oznámenie",
|
||||||
"annual_report.summary.archetype.oracle": "Veštec",
|
"annual_report.summary.archetype.oracle": "Veštec",
|
||||||
"annual_report.summary.followers.followers": "sledovatelia",
|
"annual_report.summary.followers.followers": "sledovatelia",
|
||||||
@ -378,6 +381,7 @@
|
|||||||
"ignore_notifications_modal.not_followers_title": "Nevšímať si oznámenia od ľudí, ktorí ťa nenasledujú?",
|
"ignore_notifications_modal.not_followers_title": "Nevšímať si oznámenia od ľudí, ktorí ťa nenasledujú?",
|
||||||
"ignore_notifications_modal.not_following_title": "Nevšímať si oznámenia od ľudí, ktorých nenasleduješ?",
|
"ignore_notifications_modal.not_following_title": "Nevšímať si oznámenia od ľudí, ktorých nenasleduješ?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "Nevšímať si oznámenia o nevyžiadaných súkromných spomínaniach?",
|
"ignore_notifications_modal.private_mentions_title": "Nevšímať si oznámenia o nevyžiadaných súkromných spomínaniach?",
|
||||||
|
"info_button.label": "Pomoc",
|
||||||
"interaction_modal.action.favourite": "Pre pokračovanie si musíš obľúbiť zo svojho účtu.",
|
"interaction_modal.action.favourite": "Pre pokračovanie si musíš obľúbiť zo svojho účtu.",
|
||||||
"interaction_modal.action.follow": "Pre pokračovanie musíš nasledovať zo svojho účtu.",
|
"interaction_modal.action.follow": "Pre pokračovanie musíš nasledovať zo svojho účtu.",
|
||||||
"interaction_modal.action.reply": "Pre pokračovanie musíš odpovedať s tvojho účtu.",
|
"interaction_modal.action.reply": "Pre pokračovanie musíš odpovedať s tvojho účtu.",
|
||||||
|
@ -4028,23 +4028,27 @@ a.status-card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.load-more {
|
.load-more {
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
color: $dark-text-color;
|
color: $dark-text-color;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
text-align: center;
|
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
margin: 0;
|
width: 100%;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
|
||||||
clear: both;
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--on-surface-color);
|
background: var(--on-surface-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.load-gap {
|
.load-gap {
|
||||||
@ -4421,6 +4425,7 @@ a.status-card {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load-more .loading-indicator,
|
||||||
.button .loading-indicator {
|
.button .loading-indicator {
|
||||||
position: static;
|
position: static;
|
||||||
transform: none;
|
transform: none;
|
||||||
@ -4432,6 +4437,10 @@ a.status-card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load-more .loading-indicator .circular-progress {
|
||||||
|
color: lighten($ui-base-color, 26%);
|
||||||
|
}
|
||||||
|
|
||||||
.circular-progress {
|
.circular-progress {
|
||||||
color: lighten($ui-base-color, 26%);
|
color: lighten($ui-base-color, 26%);
|
||||||
animation: 1.4s linear 0s infinite normal none running simple-rotate;
|
animation: 1.4s linear 0s infinite normal none running simple-rotate;
|
||||||
|
@ -81,8 +81,11 @@ class Request
|
|||||||
max_hops: 3,
|
max_hops: 3,
|
||||||
on_redirect: ->(response, request) { re_sign_on_redirect(response, request) },
|
on_redirect: ->(response, request) { re_sign_on_redirect(response, request) },
|
||||||
},
|
},
|
||||||
|
}.merge(options).merge(
|
||||||
socket_class: use_proxy? || @allow_local ? ProxySocket : Socket,
|
socket_class: use_proxy? || @allow_local ? ProxySocket : Socket,
|
||||||
}.merge(options)
|
timeout_class: PerOperationWithDeadline,
|
||||||
|
timeout_options: TIMEOUT
|
||||||
|
)
|
||||||
@options = @options.merge(proxy_url) if use_proxy?
|
@options = @options.merge(proxy_url) if use_proxy?
|
||||||
@headers = {}
|
@headers = {}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
.input-copy
|
.input-copy
|
||||||
.input-copy__wrapper
|
.input-copy__wrapper
|
||||||
= copyable_input value: public_invite_url(invite_code: invite.code)
|
= copyable_input value: public_invite_url(invite_code: invite.code)
|
||||||
%button{ type: :button }= t('generic.copy')
|
%button.button{ type: :button }= t('generic.copy')
|
||||||
|
|
||||||
%td
|
%td
|
||||||
.name-tag
|
.name-tag
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
.input-copy
|
.input-copy
|
||||||
.input-copy__wrapper
|
.input-copy__wrapper
|
||||||
= copyable_input value: public_invite_url(invite_code: invite.code)
|
= copyable_input value: public_invite_url(invite_code: invite.code)
|
||||||
%button{ type: :button }= t('generic.copy')
|
%button.button{ type: :button }= t('generic.copy')
|
||||||
|
|
||||||
- if invite.valid_for_use?
|
- if invite.valid_for_use?
|
||||||
%td
|
%td
|
||||||
|
@ -16,4 +16,5 @@
|
|||||||
= form.hidden_field :type,
|
= form.hidden_field :type,
|
||||||
value: params[:type]
|
value: params[:type]
|
||||||
= form.button t('mail_subscriptions.unsubscribe.action'),
|
= form.button t('mail_subscriptions.unsubscribe.action'),
|
||||||
type: :submit
|
type: :submit,
|
||||||
|
class: 'btn'
|
||||||
|
@ -35,7 +35,8 @@
|
|||||||
= form.hidden_field :scope,
|
= form.hidden_field :scope,
|
||||||
value: @pre_auth.scope
|
value: @pre_auth.scope
|
||||||
= form.button t('doorkeeper.authorizations.buttons.authorize'),
|
= form.button t('doorkeeper.authorizations.buttons.authorize'),
|
||||||
type: :submit
|
type: :submit,
|
||||||
|
class: 'btn'
|
||||||
|
|
||||||
= form_with url: oauth_authorization_path, method: :delete do |form|
|
= form_with url: oauth_authorization_path, method: :delete do |form|
|
||||||
= form.hidden_field :client_id,
|
= form.hidden_field :client_id,
|
||||||
@ -52,4 +53,4 @@
|
|||||||
value: @pre_auth.scope
|
value: @pre_auth.scope
|
||||||
= form.button t('doorkeeper.authorizations.buttons.deny'),
|
= form.button t('doorkeeper.authorizations.buttons.deny'),
|
||||||
type: :submit,
|
type: :submit,
|
||||||
class: 'negative'
|
class: 'btn negative'
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
.input-copy
|
.input-copy
|
||||||
.input-copy__wrapper
|
.input-copy__wrapper
|
||||||
= copyable_input value: params[:code], class: 'oauth-code'
|
= copyable_input value: params[:code], class: 'oauth-code'
|
||||||
%button{ type: :button }= t('generic.copy')
|
%button.button{ type: :button }= t('generic.copy')
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
.input-copy.lead
|
.input-copy.lead
|
||||||
.input-copy__wrapper
|
.input-copy__wrapper
|
||||||
= copyable_input value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: :me)
|
= copyable_input value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: :me)
|
||||||
%button{ type: :button }= t('generic.copy')
|
%button.button{ type: :button }= t('generic.copy')
|
||||||
|
|
||||||
%p.lead= t('verification.extra_instructions_html')
|
%p.lead= t('verification.extra_instructions_html')
|
||||||
|
|
||||||
@ -60,7 +60,7 @@
|
|||||||
.input-copy.lead
|
.input-copy.lead
|
||||||
.input-copy__wrapper
|
.input-copy__wrapper
|
||||||
= copyable_input value: tag.meta(name: 'fediverse:creator', content: "@#{@account.local_username_and_domain}")
|
= copyable_input value: tag.meta(name: 'fediverse:creator', content: "@#{@account.local_username_and_domain}")
|
||||||
%button{ type: :button }= t('generic.copy')
|
%button.button{ type: :button }= t('generic.copy')
|
||||||
|
|
||||||
%p.lead= t('author_attribution.then_instructions')
|
%p.lead= t('author_attribution.then_instructions')
|
||||||
|
|
||||||
|
@ -1209,6 +1209,7 @@ nn:
|
|||||||
too_fast: Skjemaet ble sendt inn for raskt, prøv på nytt.
|
too_fast: Skjemaet ble sendt inn for raskt, prøv på nytt.
|
||||||
use_security_key: Bruk sikkerhetsnøkkel
|
use_security_key: Bruk sikkerhetsnøkkel
|
||||||
user_agreement_html: Eg godtek <a href="%{terms_of_service_path}" target="_blank">bruksvilkåra</a> og <a href="%{privacy_policy_path}" target="_blank">personvernvllkåra</a>
|
user_agreement_html: Eg godtek <a href="%{terms_of_service_path}" target="_blank">bruksvilkåra</a> og <a href="%{privacy_policy_path}" target="_blank">personvernvllkåra</a>
|
||||||
|
user_privacy_agreement_html: Eg har lese og godtar <a href="%{privacy_policy_path}" target="_blank">personvernerklæringa</a>
|
||||||
author_attribution:
|
author_attribution:
|
||||||
example_title: Eksempeltekst
|
example_title: Eksempeltekst
|
||||||
hint_html: Skriv du nyhende eller blogginnlegg utanfor Mastodon? Her kan du kontrollera korleis du blir kreditert når artiklane dine blir delte på Mastodon.
|
hint_html: Skriv du nyhende eller blogginnlegg utanfor Mastodon? Her kan du kontrollera korleis du blir kreditert når artiklane dine blir delte på Mastodon.
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Admin::EmailDomainBlocksController do
|
|
||||||
render_views
|
|
||||||
|
|
||||||
before do
|
|
||||||
sign_in Fabricate(:admin_user), scope: :user
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'GET #index' do
|
|
||||||
around do |example|
|
|
||||||
default_per_page = EmailDomainBlock.default_per_page
|
|
||||||
EmailDomainBlock.paginates_per 2
|
|
||||||
example.run
|
|
||||||
EmailDomainBlock.paginates_per default_per_page
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success' do
|
|
||||||
2.times { Fabricate(:email_domain_block) }
|
|
||||||
Fabricate(:email_domain_block, allow_with_approval: true)
|
|
||||||
get :index, params: { page: 2 }
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'GET #new' do
|
|
||||||
it 'returns http success' do
|
|
||||||
get :new
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST #create' do
|
|
||||||
context 'when resolve button is pressed' do
|
|
||||||
before do
|
|
||||||
resolver = instance_double(Resolv::DNS)
|
|
||||||
|
|
||||||
allow(resolver).to receive(:getresources)
|
|
||||||
.with('example.com', Resolv::DNS::Resource::IN::MX)
|
|
||||||
.and_return([])
|
|
||||||
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([])
|
|
||||||
allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([])
|
|
||||||
allow(resolver).to receive(:timeouts=).and_return(nil)
|
|
||||||
allow(Resolv::DNS).to receive(:open).and_yield(resolver)
|
|
||||||
|
|
||||||
post :create, params: { email_domain_block: { domain: 'example.com' } }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'renders new template' do
|
|
||||||
expect(response).to render_template(:new)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when save button is pressed' do
|
|
||||||
before do
|
|
||||||
post :create, params: { email_domain_block: { domain: 'example.com' }, save: '' }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'blocks the domain and redirects to email domain blocks' do
|
|
||||||
expect(EmailDomainBlock.find_by(domain: 'example.com')).to_not be_nil
|
|
||||||
|
|
||||||
expect(response).to redirect_to(admin_email_domain_blocks_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -28,6 +28,25 @@ module DomainHelpers
|
|||||||
.and_yield(resolver)
|
.and_yield(resolver)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def configure_dns(domain:, results:)
|
||||||
|
resolver = instance_double(Resolv::DNS, :timeouts= => nil)
|
||||||
|
|
||||||
|
allow(resolver).to receive(:getresources)
|
||||||
|
.with(domain, Resolv::DNS::Resource::IN::MX)
|
||||||
|
.and_return(results)
|
||||||
|
allow(resolver)
|
||||||
|
.to receive(:getresources)
|
||||||
|
.with(domain, Resolv::DNS::Resource::IN::A)
|
||||||
|
.and_return(results)
|
||||||
|
allow(resolver)
|
||||||
|
.to receive(:getresources)
|
||||||
|
.with(domain, Resolv::DNS::Resource::IN::AAAA)
|
||||||
|
.and_return(results)
|
||||||
|
allow(Resolv::DNS)
|
||||||
|
.to receive(:open)
|
||||||
|
.and_yield(resolver)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def double_mx(exchange)
|
def double_mx(exchange)
|
||||||
|
@ -7,6 +7,43 @@ RSpec.describe 'Admin::EmailDomainBlocks' do
|
|||||||
|
|
||||||
before { sign_in current_user }
|
before { sign_in current_user }
|
||||||
|
|
||||||
|
describe 'Managing email domain blocks' do
|
||||||
|
before { configure_dns(domain: 'example.com', results: []) }
|
||||||
|
|
||||||
|
let!(:email_domain_block) { Fabricate :email_domain_block }
|
||||||
|
|
||||||
|
it 'views and creates new blocks' do
|
||||||
|
visit admin_email_domain_blocks_path
|
||||||
|
expect(page)
|
||||||
|
.to have_content(I18n.t('admin.email_domain_blocks.title'))
|
||||||
|
.and have_content(email_domain_block.domain)
|
||||||
|
|
||||||
|
click_on I18n.t('admin.email_domain_blocks.add_new')
|
||||||
|
expect(page)
|
||||||
|
.to have_content(I18n.t('admin.email_domain_blocks.new.title'))
|
||||||
|
|
||||||
|
fill_in I18n.t('admin.email_domain_blocks.domain'), with: 'example.com'
|
||||||
|
expect { submit_resolve }
|
||||||
|
.to_not change(EmailDomainBlock, :count)
|
||||||
|
expect(page)
|
||||||
|
.to have_content(I18n.t('admin.email_domain_blocks.new.title'))
|
||||||
|
|
||||||
|
expect { submit_create }
|
||||||
|
.to change(EmailDomainBlock.where(domain: 'example.com'), :count).by(1)
|
||||||
|
expect(page)
|
||||||
|
.to have_content(I18n.t('admin.email_domain_blocks.title'))
|
||||||
|
.and have_content(I18n.t('admin.email_domain_blocks.created_msg'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit_resolve
|
||||||
|
click_on I18n.t('admin.email_domain_blocks.new.resolve')
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit_create
|
||||||
|
click_on I18n.t('admin.email_domain_blocks.new.create')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'Performing batch updates' do
|
describe 'Performing batch updates' do
|
||||||
before do
|
before do
|
||||||
visit admin_email_domain_blocks_path
|
visit admin_email_domain_blocks_path
|
||||||
|
Loading…
x
Reference in New Issue
Block a user