commit
65cbcce997
76 changed files with 2122 additions and 1497 deletions
@ -0,0 +1,41 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
class MailSubscriptionsController < ApplicationController |
||||
layout 'auth' |
||||
|
||||
skip_before_action :require_functional! |
||||
|
||||
before_action :set_body_classes |
||||
before_action :set_user |
||||
before_action :set_type |
||||
|
||||
def show; end |
||||
|
||||
def create |
||||
@user.settings[email_type_from_param] = false |
||||
@user.save! |
||||
end |
||||
|
||||
private |
||||
|
||||
def set_user |
||||
@user = GlobalID::Locator.locate_signed(params[:token], for: 'unsubscribe') |
||||
end |
||||
|
||||
def set_body_classes |
||||
@body_classes = 'lighter' |
||||
end |
||||
|
||||
def set_type |
||||
@type = email_type_from_param |
||||
end |
||||
|
||||
def email_type_from_param |
||||
case params[:type] |
||||
when 'follow', 'reblog', 'favourite', 'mention', 'follow_request' |
||||
"notification_emails.#{params[:type]}" |
||||
else |
||||
raise ArgumentError |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,27 @@ |
||||
interface Props { |
||||
size: number; |
||||
strokeWidth: number; |
||||
} |
||||
|
||||
export const CircularProgress: React.FC<Props> = ({ size, strokeWidth }) => { |
||||
const viewBox = `0 0 ${size} ${size}`; |
||||
const radius = (size - strokeWidth) / 2; |
||||
|
||||
return ( |
||||
<svg |
||||
width={size} |
||||
height={size} |
||||
viewBox={viewBox} |
||||
className='circular-progress' |
||||
role='progressbar' |
||||
> |
||||
<circle |
||||
fill='none' |
||||
cx={size / 2} |
||||
cy={size / 2} |
||||
r={radius} |
||||
strokeWidth={`${strokeWidth}px`} |
||||
/> |
||||
</svg> |
||||
); |
||||
}; |
@ -1,23 +0,0 @@ |
||||
import PropTypes from 'prop-types'; |
||||
import { PureComponent } from 'react'; |
||||
|
||||
import { FormattedMessage } from 'react-intl'; |
||||
|
||||
export default class LoadPending extends PureComponent { |
||||
|
||||
static propTypes = { |
||||
onClick: PropTypes.func, |
||||
count: PropTypes.number, |
||||
}; |
||||
|
||||
render() { |
||||
const { count } = this.props; |
||||
|
||||
return ( |
||||
<button className='load-more load-gap' onClick={this.props.onClick}> |
||||
<FormattedMessage id='load_pending' defaultMessage='{count, plural, one {# new item} other {# new items}}' values={{ count }} /> |
||||
</button> |
||||
); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,18 @@ |
||||
import { FormattedMessage } from 'react-intl'; |
||||
|
||||
interface Props { |
||||
onClick: (event: React.MouseEvent) => void; |
||||
count: number; |
||||
} |
||||
|
||||
export const LoadPending: React.FC<Props> = ({ onClick, count }) => { |
||||
return ( |
||||
<button className='load-more load-gap' onClick={onClick}> |
||||
<FormattedMessage |
||||
id='load_pending' |
||||
defaultMessage='{count, plural, one {# new item} other {# new items}}' |
||||
values={{ count }} |
||||
/> |
||||
</button> |
||||
); |
||||
}; |
@ -1,31 +0,0 @@ |
||||
import PropTypes from 'prop-types'; |
||||
|
||||
export const CircularProgress = ({ size, strokeWidth }) => { |
||||
const viewBox = `0 0 ${size} ${size}`; |
||||
const radius = (size - strokeWidth) / 2; |
||||
|
||||
return ( |
||||
<svg width={size} height={size} viewBox={viewBox} className='circular-progress' role='progressbar'> |
||||
<circle |
||||
fill='none' |
||||
cx={size / 2} |
||||
cy={size / 2} |
||||
r={radius} |
||||
strokeWidth={`${strokeWidth}px`} |
||||
/> |
||||
</svg> |
||||
); |
||||
}; |
||||
|
||||
CircularProgress.propTypes = { |
||||
size: PropTypes.number.isRequired, |
||||
strokeWidth: PropTypes.number.isRequired, |
||||
}; |
||||
|
||||
const LoadingIndicator = () => ( |
||||
<div className='loading-indicator'> |
||||
<CircularProgress size={50} strokeWidth={6} /> |
||||
</div> |
||||
); |
||||
|
||||
export default LoadingIndicator; |
@ -0,0 +1,7 @@ |
||||
import { CircularProgress } from './circular_progress'; |
||||
|
||||
export const LoadingIndicator: React.FC = () => ( |
||||
<div className='loading-indicator'> |
||||
<CircularProgress size={50} strokeWidth={6} /> |
||||
</div> |
||||
); |
@ -0,0 +1,51 @@ |
||||
import type { BaseEmoji, EmojiData, NimbleEmojiIndex } from 'emoji-mart'; |
||||
import type { Category, Data, Emoji } from 'emoji-mart/dist-es/utils/data'; |
||||
|
||||
/* |
||||
* The 'search' property, although not defined in the [`Emoji`]{@link node_modules/@types/emoji-mart/dist-es/utils/data.d.ts#Emoji} type, |
||||
* is used in the application. |
||||
* This could be due to an oversight by the library maintainer. |
||||
* The `search` property is defined and used [here]{@link node_modules/emoji-mart/dist/utils/data.js#uncompress}. |
||||
*/ |
||||
export type Search = string; |
||||
/* |
||||
* The 'skins' property does not exist in the application data. |
||||
* This could be a potential area of refactoring or error handling. |
||||
* The non-existence of 'skins' property is evident at [this location]{@link app/javascript/mastodon/features/emoji/emoji_compressed.js:121}. |
||||
*/ |
||||
export type Skins = null; |
||||
|
||||
export type FilenameData = string[] | string[][]; |
||||
export type ShortCodesToEmojiDataKey = |
||||
| EmojiData['id'] |
||||
| BaseEmoji['native'] |
||||
| keyof NimbleEmojiIndex['emojis']; |
||||
|
||||
export type SearchData = [ |
||||
BaseEmoji['native'], |
||||
Emoji['short_names'], |
||||
Search, |
||||
Emoji['unified'] |
||||
]; |
||||
|
||||
export interface ShortCodesToEmojiData { |
||||
[key: ShortCodesToEmojiDataKey]: [FilenameData, SearchData]; |
||||
} |
||||
export type EmojisWithoutShortCodes = FilenameData[]; |
||||
|
||||
export type EmojiCompressed = [ |
||||
ShortCodesToEmojiData, |
||||
Skins, |
||||
Category[], |
||||
Data['aliases'], |
||||
EmojisWithoutShortCodes |
||||
]; |
||||
|
||||
/* |
||||
* `emoji_compressed.js` uses `babel-plugin-preval`, which makes it difficult to convert to TypeScript. |
||||
* As a temporary solution, we are allowing a default export here to apply the TypeScript type `EmojiCompressed` to the JS file export. |
||||
* - {@link app/javascript/mastodon/features/emoji/emoji_compressed.js} |
||||
*/ |
||||
declare const emojiCompressed: EmojiCompressed; |
||||
|
||||
export default emojiCompressed; // eslint-disable-line import/no-default-export
|
@ -1,43 +0,0 @@ |
||||
// The output of this module is designed to mimic emoji-mart's
|
||||
// "data" object, such that we can use it for a light version of emoji-mart's
|
||||
// emojiIndex.search functionality.
|
||||
import emojiCompressed from './emoji_compressed'; |
||||
import { unicodeToUnifiedName } from './unicode_to_unified_name'; |
||||
|
||||
const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed; |
||||
|
||||
const emojis = {}; |
||||
|
||||
// decompress
|
||||
Object.keys(shortCodesToEmojiData).forEach((shortCode) => { |
||||
let [ |
||||
filenameData, // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
searchData, |
||||
] = shortCodesToEmojiData[shortCode]; |
||||
let [ |
||||
native, |
||||
short_names, |
||||
search, |
||||
unified, |
||||
] = searchData; |
||||
|
||||
if (!unified) { |
||||
// unified name can be derived from unicodeToUnifiedName
|
||||
unified = unicodeToUnifiedName(native); |
||||
} |
||||
|
||||
short_names = [shortCode].concat(short_names); |
||||
emojis[shortCode] = { |
||||
native, |
||||
search, |
||||
short_names, |
||||
unified, |
||||
}; |
||||
}); |
||||
|
||||
export { |
||||
emojis, |
||||
skins, |
||||
categories, |
||||
short_names, |
||||
}; |
@ -0,0 +1,52 @@ |
||||
// The output of this module is designed to mimic emoji-mart's
|
||||
// "data" object, such that we can use it for a light version of emoji-mart's
|
||||
// emojiIndex.search functionality.
|
||||
import type { BaseEmoji } from 'emoji-mart'; |
||||
import type { Emoji } from 'emoji-mart/dist-es/utils/data'; |
||||
|
||||
import type { Search, ShortCodesToEmojiData } from './emoji_compressed'; |
||||
import emojiCompressed from './emoji_compressed'; |
||||
import { unicodeToUnifiedName } from './unicode_to_unified_name'; |
||||
|
||||
type Emojis = { |
||||
[key in keyof ShortCodesToEmojiData]: { |
||||
native: BaseEmoji['native']; |
||||
search: Search; |
||||
short_names: Emoji['short_names']; |
||||
unified: Emoji['unified']; |
||||
}; |
||||
}; |
||||
|
||||
const [ |
||||
shortCodesToEmojiData, |
||||
skins, |
||||
categories, |
||||
short_names, |
||||
_emojisWithoutShortCodes, |
||||
] = emojiCompressed; |
||||
|
||||
const emojis: Emojis = {}; |
||||
|
||||
// decompress
|
||||
Object.keys(shortCodesToEmojiData).forEach((shortCode) => { |
||||
const [_filenameData, searchData] = shortCodesToEmojiData[shortCode]; |
||||
const native = searchData[0]; |
||||
let short_names = searchData[1]; |
||||
const search = searchData[2]; |
||||
let unified = searchData[3]; |
||||
|
||||
if (!unified) { |
||||
// unified name can be derived from unicodeToUnifiedName
|
||||
unified = unicodeToUnifiedName(native); |
||||
} |
||||
|
||||
if (short_names) short_names = [shortCode].concat(short_names); |
||||
emojis[shortCode] = { |
||||
native, |
||||
search, |
||||
short_names, |
||||
unified, |
||||
}; |
||||
}); |
||||
|
||||
export { emojis, skins, categories, short_names }; |
@ -0,0 +1,9 @@ |
||||
- content_for :page_title do |
||||
= t('mail_subscriptions.unsubscribe.title') |
||||
|
||||
.simple_form |
||||
%h1.title= t('mail_subscriptions.unsubscribe.complete') |
||||
%p.lead |
||||
= t('mail_subscriptions.unsubscribe.success_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email)) |
||||
%p.lead |
||||
= t('mail_subscriptions.unsubscribe.resubscribe_html', settings_path: settings_preferences_notifications_path) |
@ -0,0 +1,12 @@ |
||||
- content_for :page_title do |
||||
= t('mail_subscriptions.unsubscribe.title') |
||||
|
||||
.simple_form |
||||
%h1.title= t('mail_subscriptions.unsubscribe.title') |
||||
%p.lead |
||||
= t('mail_subscriptions.unsubscribe.confirmation_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email), settings_path: settings_preferences_notifications_path) |
||||
|
||||
= form_tag unsubscribe_path, method: :post do |
||||
= hidden_field_tag :token, params[:token] |
||||
= hidden_field_tag :type, params[:type] |
||||
= button_tag t('mail_subscriptions.unsubscribe.action'), type: :submit |
@ -1,358 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe Api::V1::Admin::CanonicalEmailBlocksController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'admin:read:canonical_email_blocks admin:write:canonical_email_blocks' } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
context 'with wrong scope' do |
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
get :index |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there is no canonical email block' do |
||||
it 'returns an empty list' do |
||||
get :index |
||||
|
||||
body = body_as_json |
||||
|
||||
expect(body).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are canonical email blocks' do |
||||
let!(:canonical_email_blocks) { Fabricate.times(5, :canonical_email_block) } |
||||
let(:expected_email_hashes) { canonical_email_blocks.pluck(:canonical_email_hash) } |
||||
|
||||
it 'returns the correct canonical email hashes' do |
||||
get :index |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json.pluck(:canonical_email_hash)).to match_array(expected_email_hashes) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of canonical email blocks' do |
||||
get :index, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
|
||||
context 'with since_id param' do |
||||
let(:params) { { since_id: canonical_email_blocks[1].id } } |
||||
|
||||
it 'returns only the canonical email blocks after since_id' do |
||||
get :index, params: params |
||||
|
||||
canonical_email_blocks_ids = canonical_email_blocks.pluck(:id).map(&:to_s) |
||||
json = body_as_json |
||||
|
||||
expect(json.pluck(:id)).to match_array(canonical_email_blocks_ids[2..]) |
||||
end |
||||
end |
||||
|
||||
context 'with max_id param' do |
||||
let(:params) { { max_id: canonical_email_blocks[3].id } } |
||||
|
||||
it 'returns only the canonical email blocks before max_id' do |
||||
get :index, params: params |
||||
|
||||
canonical_email_blocks_ids = canonical_email_blocks.pluck(:id).map(&:to_s) |
||||
json = body_as_json |
||||
|
||||
expect(json.pluck(:id)).to match_array(canonical_email_blocks_ids[..2]) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
let!(:canonical_email_block) { Fabricate(:canonical_email_block) } |
||||
let(:params) { { id: canonical_email_block.id } } |
||||
|
||||
context 'with wrong scope' do |
||||
before do |
||||
get :show, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
get :show, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
context 'when canonical email block exists' do |
||||
it 'returns http success' do |
||||
get :show, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns canonical email block data correctly' do |
||||
get :show, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:id]).to eq(canonical_email_block.id.to_s) |
||||
expect(json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
end |
||||
|
||||
context 'when canonical block does not exist' do |
||||
it 'returns http not found' do |
||||
get :show, params: { id: 0 } |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST #test' do |
||||
context 'with wrong scope' do |
||||
before do |
||||
post :test |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
post :test, params: { email: 'whatever@email.com' } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
context 'when required email is not provided' do |
||||
it 'returns http bad request' do |
||||
post :test |
||||
|
||||
expect(response).to have_http_status(400) |
||||
end |
||||
end |
||||
|
||||
context 'when required email is provided' do |
||||
let(:params) { { email: 'example@email.com' } } |
||||
|
||||
context 'when there is a matching canonical email block' do |
||||
let!(:canonical_email_block) { CanonicalEmailBlock.create(params) } |
||||
|
||||
it 'returns http success' do |
||||
post :test, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns expected canonical email hash' do |
||||
post :test, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
end |
||||
|
||||
context 'when there is no matching canonical email block' do |
||||
it 'returns http success' do |
||||
post :test, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns an empty list' do |
||||
post :test, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json).to be_empty |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST #create' do |
||||
let(:params) { { email: 'example@email.com' } } |
||||
let(:canonical_email_block) { CanonicalEmailBlock.new(email: params[:email]) } |
||||
|
||||
context 'with wrong scope' do |
||||
before do |
||||
post :create, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
post :create, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns canonical_email_hash correctly' do |
||||
post :create, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
|
||||
context 'when required email param is not provided' do |
||||
it 'returns http unprocessable entity' do |
||||
post :create |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when canonical_email_hash param is provided instead of email' do |
||||
let(:params) { { canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } } |
||||
|
||||
it 'returns http success' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns correct canonical_email_hash' do |
||||
post :create, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:canonical_email_hash]).to eq(params[:canonical_email_hash]) |
||||
end |
||||
end |
||||
|
||||
context 'when both email and canonical_email_hash params are provided' do |
||||
let(:params) { { email: 'example@email.com', canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } } |
||||
|
||||
it 'returns http success' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'ignores canonical_email_hash param' do |
||||
post :create, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
end |
||||
|
||||
context 'when canonical email was already blocked' do |
||||
before do |
||||
canonical_email_block.save |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE #destroy' do |
||||
let!(:canonical_email_block) { Fabricate(:canonical_email_block) } |
||||
let(:params) { { id: canonical_email_block.id } } |
||||
|
||||
context 'with wrong scope' do |
||||
before do |
||||
delete :destroy, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
delete :destroy, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
delete :destroy, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when canonical email block is not found' do |
||||
it 'returns http not found' do |
||||
delete :destroy, params: { id: 0 } |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,140 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::Admin::DomainAllowsController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
let!(:domain_allow) { Fabricate(:domain_allow) } |
||||
|
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the expected domain allows' do |
||||
json = body_as_json |
||||
expect(json.length).to eq 1 |
||||
expect(json[0][:id].to_i).to eq domain_allow.id |
||||
end |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
let!(:domain_allow) { Fabricate(:domain_allow) } |
||||
|
||||
before do |
||||
get :show, params: { id: domain_allow.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns expected domain name' do |
||||
json = body_as_json |
||||
expect(json[:domain]).to eq domain_allow.domain |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE #destroy' do |
||||
let!(:domain_allow) { Fabricate(:domain_allow) } |
||||
|
||||
before do |
||||
delete :destroy, params: { id: domain_allow.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'deletes the block' do |
||||
expect(DomainAllow.find_by(id: domain_allow.id)).to be_nil |
||||
end |
||||
end |
||||
|
||||
describe 'POST #create' do |
||||
let!(:domain_allow) { Fabricate(:domain_allow, domain: 'example.com') } |
||||
|
||||
context 'with a valid domain' do |
||||
before do |
||||
post :create, params: { domain: 'foo.bar.com' } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns expected domain name' do |
||||
json = body_as_json |
||||
expect(json[:domain]).to eq 'foo.bar.com' |
||||
end |
||||
|
||||
it 'creates a domain block' do |
||||
expect(DomainAllow.find_by(domain: 'foo.bar.com')).to_not be_nil |
||||
end |
||||
end |
||||
|
||||
context 'with invalid domain name' do |
||||
before do |
||||
post :create, params: { domain: 'foo bar' } |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when domain name is not specified' do |
||||
it 'returns http unprocessable entity' do |
||||
post :create |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,180 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::Admin::DomainBlocksController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
let!(:block) { Fabricate(:domain_block) } |
||||
|
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the expected domain blocks' do |
||||
json = body_as_json |
||||
expect(json.length).to eq 1 |
||||
expect(json[0][:id].to_i).to eq block.id |
||||
end |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
let!(:block) { Fabricate(:domain_block) } |
||||
|
||||
before do |
||||
get :show, params: { id: block.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns expected domain name' do |
||||
json = body_as_json |
||||
expect(json[:domain]).to eq block.domain |
||||
end |
||||
end |
||||
|
||||
describe 'PUT #update' do |
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.com') } |
||||
let(:subject) do |
||||
post :update, params: { id: domain_block.id, domain: 'example.com', severity: new_severity } |
||||
end |
||||
let(:domain_block) { Fabricate(:domain_block, domain: 'example.com', severity: original_severity) } |
||||
|
||||
before do |
||||
BlockDomainService.new.call(domain_block) |
||||
end |
||||
|
||||
context 'when downgrading a domain suspension to silence' do |
||||
let(:original_severity) { 'suspend' } |
||||
let(:new_severity) { 'silence' } |
||||
|
||||
it 'changes the block severity' do |
||||
expect { subject }.to change { domain_block.reload.severity }.from('suspend').to('silence') |
||||
end |
||||
|
||||
it 'undoes individual suspensions' do |
||||
expect { subject }.to change { remote_account.reload.suspended? }.from(true).to(false) |
||||
end |
||||
|
||||
it 'performs individual silences' do |
||||
expect { subject }.to change { remote_account.reload.silenced? }.from(false).to(true) |
||||
end |
||||
end |
||||
|
||||
context 'when upgrading a domain silence to suspend' do |
||||
let(:original_severity) { 'silence' } |
||||
let(:new_severity) { 'suspend' } |
||||
|
||||
it 'changes the block severity' do |
||||
expect { subject }.to change { domain_block.reload.severity }.from('silence').to('suspend') |
||||
end |
||||
|
||||
it 'undoes individual silences' do |
||||
expect { subject }.to change { remote_account.reload.silenced? }.from(true).to(false) |
||||
end |
||||
|
||||
it 'performs individual suspends' do |
||||
expect { subject }.to change { remote_account.reload.suspended? }.from(false).to(true) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE #destroy' do |
||||
let!(:block) { Fabricate(:domain_block) } |
||||
|
||||
before do |
||||
delete :destroy, params: { id: block.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'deletes the block' do |
||||
expect(DomainBlock.find_by(id: block.id)).to be_nil |
||||
end |
||||
end |
||||
|
||||
describe 'POST #create' do |
||||
let(:existing_block_domain) { 'example.com' } |
||||
let!(:block) { Fabricate(:domain_block, domain: existing_block_domain, severity: :suspend) } |
||||
|
||||
before do |
||||
post :create, params: { domain: 'foo.bar.com', severity: :silence } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns expected domain name' do |
||||
json = body_as_json |
||||
expect(json[:domain]).to eq 'foo.bar.com' |
||||
end |
||||
|
||||
it 'creates a domain block' do |
||||
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to_not be_nil |
||||
end |
||||
|
||||
context 'when a stricter domain block already exists' do |
||||
let(:existing_block_domain) { 'bar.com' } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
expect(response).to have_http_status(422) |
||||
end |
||||
|
||||
it 'renders existing domain block in error' do |
||||
json = body_as_json |
||||
expect(json[:existing_domain_block][:domain]).to eq existing_block_domain |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,309 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe Api::V1::Admin::IpBlocksController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'admin:read:ip_blocks admin:write:ip_blocks' } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
context 'with wrong scope' do |
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
get :index |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there is no ip block' do |
||||
it 'returns an empty body' do |
||||
get :index |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are ip blocks' do |
||||
let!(:ip_blocks) do |
||||
[ |
||||
IpBlock.create(ip: '192.0.2.0/24', severity: :no_access), |
||||
IpBlock.create(ip: '172.16.0.1', severity: :sign_up_requires_approval, comment: 'Spam'), |
||||
IpBlock.create(ip: '2001:0db8::/32', severity: :sign_up_block, expires_in: 10.days), |
||||
] |
||||
end |
||||
let(:expected_response) do |
||||
ip_blocks.map do |ip_block| |
||||
{ |
||||
id: ip_block.id.to_s, |
||||
ip: ip_block.ip, |
||||
severity: ip_block.severity.to_s, |
||||
comment: ip_block.comment, |
||||
created_at: ip_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
expires_at: ip_block.expires_at&.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
} |
||||
end |
||||
end |
||||
|
||||
it 'returns the correct blocked ips' do |
||||
get :index |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of ip blocks' do |
||||
get :index, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
let!(:ip_block) { IpBlock.create(ip: '192.0.2.0/24', severity: :no_access) } |
||||
let(:params) { { id: ip_block.id } } |
||||
|
||||
context 'with wrong scope' do |
||||
before do |
||||
get :show, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
get :show, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
get :show, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct ip block' do |
||||
get :show, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:ip]).to eq("#{ip_block.ip}/#{ip_block.ip.prefix}") |
||||
expect(json[:severity]).to eq(ip_block.severity.to_s) |
||||
end |
||||
|
||||
context 'when ip block does not exist' do |
||||
it 'returns http not found' do |
||||
get :show, params: { id: 0 } |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST #create' do |
||||
let(:params) { { ip: '151.0.32.55', severity: 'no_access', comment: 'Spam' } } |
||||
|
||||
context 'with wrong scope' do |
||||
before do |
||||
post :create, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read:ip_blocks' |
||||
end |
||||
|
||||
context 'with wrong role' do |
||||
before do |
||||
post :create, params: params |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
end |
||||
|
||||
it 'returns http success' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct ip block' do |
||||
post :create, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:ip]).to eq("#{params[:ip]}/32") |
||||
expect(json[:severity]).to eq(params[:severity]) |
||||
expect(json[:comment]).to eq(params[:comment]) |
||||
end |
||||
|
||||
context 'when ip is not provided' do |
||||
let(:params) { { ip: '', severity: 'no_access' } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when severity is not provided' do |
||||
let(:params) { { ip: '173.65.23.1', severity: '' } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when provided ip is already blocked' do |
||||
before do |
||||
IpBlock.create(params) |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when provided ip address is invalid' do |
||||
let(:params) { { ip: '520.13.54.120', severity: 'no_access' } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
post :create, params: params |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'PUT #update' do |
||||
context 'when ip block exists' do |
||||
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) } |
||||
let(:params) { { id: ip_block.id, severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } } |
||||
|
||||
it 'returns http success' do |
||||
put :update, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct ip block' do |
||||
put :update, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json).to match(hash_including({ |
||||
ip: "#{ip_block.ip}/#{ip_block.ip.prefix}", |
||||
severity: 'sign_up_requires_approval', |
||||
comment: 'Decreasing severity', |
||||
})) |
||||
end |
||||
|
||||
it 'updates the severity correctly' do |
||||
expect { put :update, params: params }.to change { ip_block.reload.severity }.from('no_access').to('sign_up_requires_approval') |
||||
end |
||||
|
||||
it 'updates the comment correctly' do |
||||
expect { put :update, params: params }.to change { ip_block.reload.comment }.from('Spam').to('Decreasing severity') |
||||
end |
||||
end |
||||
|
||||
context 'when ip block does not exist' do |
||||
it 'returns http not found' do |
||||
put :update, params: { id: 0 } |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE #destroy' do |
||||
context 'when ip block exists' do |
||||
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') } |
||||
let(:params) { { id: ip_block.id } } |
||||
|
||||
it 'returns http success' do |
||||
delete :destroy, params: params |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns an empty body' do |
||||
delete :destroy, params: params |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json).to be_empty |
||||
end |
||||
|
||||
it 'deletes the ip block' do |
||||
delete :destroy, params: params |
||||
|
||||
expect(IpBlock.find_by(id: ip_block.id)).to be_nil |
||||
end |
||||
end |
||||
|
||||
context 'when ip block does not exist' do |
||||
it 'returns http not found' do |
||||
delete :destroy, params: { id: 0 } |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,111 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe Api::V1::Admin::ReportsController do |
||||
render_views |
||||
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:report) { Fabricate(:report) } |
||||
|
||||
before do |
||||
allow(controller).to receive(:doorkeeper_token) { token } |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET #index' do |
||||
before do |
||||
get :index |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'GET #show' do |
||||
before do |
||||
get :show, params: { id: report.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #resolve' do |
||||
before do |
||||
post :resolve, params: { id: report.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #reopen' do |
||||
before do |
||||
post :reopen, params: { id: report.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #assign_to_self' do |
||||
before do |
||||
post :assign_to_self, params: { id: report.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #unassign' do |
||||
before do |
||||
post :unassign, params: { id: report.id } |
||||
end |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
expect(response).to have_http_status(200) |
||||
end |
||||
end |
||||
end |
@ -1,5 +1,5 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
Fabricator(:domain_allow) do |
||||
domain 'MyString' |
||||
domain { sequence(:domain) { |i| "example#{i}.com" } } |
||||
end |
||||
|
@ -0,0 +1,8 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
Fabricator(:status_stat) do |
||||
status |
||||
replies_count '123' |
||||
reblogs_count '456' |
||||
favourites_count '789' |
||||
end |
@ -0,0 +1,53 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe 'GET /api/v1/accounts/{account_id}' do |
||||
it 'returns account entity as 200 OK' do |
||||
account = Fabricate(:account) |
||||
|
||||
get "/api/v1/accounts/#{account.id}" |
||||
|
||||
aggregate_failures do |
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json[:id]).to eq(account.id.to_s) |
||||
end |
||||
end |
||||
|
||||
it 'returns 404 if account not found' do |
||||
get '/api/v1/accounts/1' |
||||
|
||||
aggregate_failures do |
||||
expect(response).to have_http_status(404) |
||||
expect(body_as_json[:error]).to eq('Record not found') |
||||
end |
||||
end |
||||
|
||||
context 'when with token' do |
||||
it 'returns account entity as 200 OK if token is valid' do |
||||
account = Fabricate(:account) |
||||
user = Fabricate(:user, account: account) |
||||
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts').token |
||||
|
||||
get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" } |
||||
|
||||
aggregate_failures do |
||||
expect(response).to have_http_status(200) |
||||
expect(body_as_json[:id]).to eq(account.id.to_s) |
||||
end |
||||
end |
||||
|
||||
it 'returns 403 if scope of token is invalid' do |
||||
account = Fabricate(:account) |
||||
user = Fabricate(:user, account: account) |
||||
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses').token |
||||
|
||||
get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" } |
||||
|
||||
aggregate_failures do |
||||
expect(response).to have_http_status(403) |
||||
expect(body_as_json[:error]).to eq('This action is outside the authorized scopes') |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,305 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Canonical Email Blocks' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'admin:read:canonical_email_blocks admin:write:canonical_email_blocks' } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/canonical_email_blocks' do |
||||
subject do |
||||
get '/api/v1/admin/canonical_email_blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { {} } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there is no canonical email block' do |
||||
it 'returns an empty list' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are canonical email blocks' do |
||||
let!(:canonical_email_blocks) { Fabricate.times(5, :canonical_email_block) } |
||||
let(:expected_email_hashes) { canonical_email_blocks.pluck(:canonical_email_hash) } |
||||
|
||||
it 'returns the correct canonical email hashes' do |
||||
subject |
||||
|
||||
expect(body_as_json.pluck(:canonical_email_hash)).to match_array(expected_email_hashes) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of canonical email blocks' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
|
||||
context 'with since_id param' do |
||||
let(:params) { { since_id: canonical_email_blocks[1].id } } |
||||
|
||||
it 'returns only the canonical email blocks after since_id' do |
||||
subject |
||||
|
||||
canonical_email_blocks_ids = canonical_email_blocks.pluck(:id).map(&:to_s) |
||||
|
||||
expect(body_as_json.pluck(:id)).to match_array(canonical_email_blocks_ids[2..]) |
||||
end |
||||
end |
||||
|
||||
context 'with max_id param' do |
||||
let(:params) { { max_id: canonical_email_blocks[3].id } } |
||||
|
||||
it 'returns only the canonical email blocks before max_id' do |
||||
subject |
||||
|
||||
canonical_email_blocks_ids = canonical_email_blocks.pluck(:id).map(&:to_s) |
||||
|
||||
expect(body_as_json.pluck(:id)).to match_array(canonical_email_blocks_ids[..2]) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/canonical_email_blocks/:id' do |
||||
subject do |
||||
get "/api/v1/admin/canonical_email_blocks/#{canonical_email_block.id}", headers: headers |
||||
end |
||||
|
||||
let!(:canonical_email_block) { Fabricate(:canonical_email_block) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
context 'when the requested canonical email block exists' do |
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the requested canonical email block data correctly' do |
||||
subject |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:id]).to eq(canonical_email_block.id.to_s) |
||||
expect(json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
end |
||||
|
||||
context 'when the requested canonical block does not exist' do |
||||
it 'returns http not found' do |
||||
get '/api/v1/admin/canonical_email_blocks/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/canonical_email_blocks/test' do |
||||
subject do |
||||
post '/api/v1/admin/canonical_email_blocks/test', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { { email: 'email@example.com' } } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
context 'when the required email param is not provided' do |
||||
let(:params) { {} } |
||||
|
||||
it 'returns http bad request' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(400) |
||||
end |
||||
end |
||||
|
||||
context 'when the required email param is provided' do |
||||
context 'when there is a matching canonical email block' do |
||||
let!(:canonical_email_block) { CanonicalEmailBlock.create(params) } |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the expected canonical email hash' do |
||||
subject |
||||
|
||||
expect(body_as_json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
end |
||||
|
||||
context 'when there is no matching canonical email block' do |
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns an empty list' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/canonical_email_blocks' do |
||||
subject do |
||||
post '/api/v1/admin/canonical_email_blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { { email: 'example@email.com' } } |
||||
let(:canonical_email_block) { CanonicalEmailBlock.new(email: params[:email]) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the canonical_email_hash correctly' do |
||||
subject |
||||
|
||||
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
|
||||
context 'when the required email param is not provided' do |
||||
let(:params) { {} } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when the canonical_email_hash param is provided instead of email' do |
||||
let(:params) { { canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } } |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct canonical_email_hash' do |
||||
subject |
||||
|
||||
expect(body_as_json[:canonical_email_hash]).to eq(params[:canonical_email_hash]) |
||||
end |
||||
end |
||||
|
||||
context 'when both email and canonical_email_hash params are provided' do |
||||
let(:params) { { email: 'example@email.com', canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } } |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'ignores the canonical_email_hash param' do |
||||
subject |
||||
|
||||
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) |
||||
end |
||||
end |
||||
|
||||
context 'when the given canonical email was already blocked' do |
||||
before do |
||||
canonical_email_block.save |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE /api/v1/admin/canonical_email_blocks/:id' do |
||||
subject do |
||||
delete "/api/v1/admin/canonical_email_blocks/#{canonical_email_block.id}", headers: headers |
||||
end |
||||
|
||||
let!(:canonical_email_block) { Fabricate(:canonical_email_block) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses' |
||||
|
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'deletes the canonical email block' do |
||||
subject |
||||
|
||||
expect(CanonicalEmailBlock.find_by(id: canonical_email_block.id)).to be_nil |
||||
end |
||||
|
||||
context 'when the canonical email block is not found' do |
||||
it 'returns http not found' do |
||||
delete '/api/v1/admin/canonical_email_blocks/0', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,214 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Domain Allows' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read admin:write' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/domain_allows' do |
||||
subject do |
||||
get '/api/v1/admin/domain_allows', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { {} } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there is no allowed domains' do |
||||
it 'returns an empty body' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are allowed domains' do |
||||
let!(:domain_allows) { Fabricate.times(5, :domain_allow) } |
||||
let(:expected_response) do |
||||
domain_allows.map do |domain_allow| |
||||
{ |
||||
id: domain_allow.id.to_s, |
||||
domain: domain_allow.domain, |
||||
created_at: domain_allow.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
} |
||||
end |
||||
end |
||||
|
||||
it 'returns the correct allowed domains' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of allowed domains' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/domain_allows/:id' do |
||||
subject do |
||||
get "/api/v1/admin/domain_allows/#{domain_allow.id}", headers: headers |
||||
end |
||||
|
||||
let!(:domain_allow) { Fabricate(:domain_allow) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the expected allowed domain name' do |
||||
subject |
||||
|
||||
expect(body_as_json[:domain]).to eq domain_allow.domain |
||||
end |
||||
|
||||
context 'when the requested allowed domain does not exist' do |
||||
it 'returns http not found' do |
||||
get '/api/v1/admin/domain_allows/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/domain_allows' do |
||||
subject do |
||||
post '/api/v1/admin/domain_allows', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { { domain: 'foo.bar.com' } } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
context 'with a valid domain name' do |
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the expected domain name' do |
||||
subject |
||||
|
||||
expect(body_as_json[:domain]).to eq 'foo.bar.com' |
||||
end |
||||
|
||||
it 'creates a domain allow' do |
||||
subject |
||||
|
||||
expect(DomainAllow.find_by(domain: 'foo.bar.com')).to be_present |
||||
end |
||||
end |
||||
|
||||
context 'with invalid domain name' do |
||||
let(:params) { 'foo bar' } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when domain name is not specified' do |
||||
let(:params) { {} } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when the domain is already allowed' do |
||||
before do |
||||
DomainAllow.create(params) |
||||
end |
||||
|
||||
it 'returns the existing allowed domain name' do |
||||
subject |
||||
|
||||
expect(body_as_json[:domain]).to eq(params[:domain]) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE /api/v1/admin/domain_allows/:id' do |
||||
subject do |
||||
delete "/api/v1/admin/domain_allows/#{domain_allow.id}", headers: headers |
||||
end |
||||
|
||||
let!(:domain_allow) { Fabricate(:domain_allow) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'deletes the allowed domain' do |
||||
subject |
||||
|
||||
expect(DomainAllow.find_by(id: domain_allow.id)).to be_nil |
||||
end |
||||
|
||||
context 'when the allowed domain does not exist' do |
||||
it 'returns http not found' do |
||||
delete '/api/v1/admin/domain_allows/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,284 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Domain Blocks' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read:domain_blocks admin:write:domain_blocks' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/domain_blocks' do |
||||
subject do |
||||
get '/api/v1/admin/domain_blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { {} } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there are no domain blocks' do |
||||
it 'returns an empty list' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are domain blocks' do |
||||
let!(:domain_blocks) do |
||||
[ |
||||
Fabricate(:domain_block, severity: :silence, reject_media: true), |
||||
Fabricate(:domain_block, severity: :suspend, obfuscate: true), |
||||
Fabricate(:domain_block, severity: :noop, reject_reports: true), |
||||
Fabricate(:domain_block, public_comment: 'Spam'), |
||||
Fabricate(:domain_block, private_comment: 'Spam'), |
||||
] |
||||
end |
||||
let(:expected_responde) do |
||||
domain_blocks.map do |domain_block| |
||||
{ |
||||
id: domain_block.id.to_s, |
||||
domain: domain_block.domain, |
||||
created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
severity: domain_block.severity.to_s, |
||||
reject_media: domain_block.reject_media, |
||||
reject_reports: domain_block.reject_reports, |
||||
private_comment: domain_block.private_comment, |
||||
public_comment: domain_block.public_comment, |
||||
obfuscate: domain_block.obfuscate, |
||||
} |
||||
end |
||||
end |
||||
|
||||
it 'returns the expected domain blocks' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_responde) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of domain blocks' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/domain_blocks/:id' do |
||||
subject do |
||||
get "/api/v1/admin/domain_blocks/#{domain_block.id}", headers: headers |
||||
end |
||||
|
||||
let!(:domain_block) { Fabricate(:domain_block) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the expected domain block content' do |
||||
subject |
||||
|
||||
expect(body_as_json).to eq( |
||||
{ |
||||
id: domain_block.id.to_s, |
||||
domain: domain_block.domain, |
||||
created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
severity: domain_block.severity.to_s, |
||||
reject_media: domain_block.reject_media, |
||||
reject_reports: domain_block.reject_reports, |
||||
private_comment: domain_block.private_comment, |
||||
public_comment: domain_block.public_comment, |
||||
obfuscate: domain_block.obfuscate, |
||||
} |
||||
) |
||||
end |
||||
|
||||
context 'when the requested domain block does not exist' do |
||||
it 'returns http not found' do |
||||
get '/api/v1/admin/domain_blocks/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/domain_blocks' do |
||||
subject do |
||||
post '/api/v1/admin/domain_blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { { domain: 'foo.bar.com', severity: :silence } } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns expected domain name and severity' do |
||||
subject |
||||
|
||||
body = body_as_json |
||||
|
||||
expect(body).to match a_hash_including( |
||||
{ |
||||
domain: 'foo.bar.com', |
||||
severity: 'silence', |
||||
} |
||||
) |
||||
end |
||||
|
||||
it 'creates a domain block' do |
||||
subject |
||||
|
||||
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present |
||||
end |
||||
|
||||
context 'when a stricter domain block already exists' do |
||||
before do |
||||
Fabricate(:domain_block, domain: 'bar.com', severity: :suspend) |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
|
||||
it 'returns existing domain block in error' do |
||||
subject |
||||
|
||||
expect(body_as_json[:existing_domain_block][:domain]).to eq('bar.com') |
||||
end |
||||
end |
||||
|
||||
context 'when given domain name is invalid' do |
||||
let(:params) { { domain: 'foo bar', severity: :silence } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'PUT /api/v1/admin/domain_blocks/:id' do |
||||
subject do |
||||
put "/api/v1/admin/domain_blocks/#{domain_block.id}", headers: headers, params: params |
||||
end |
||||
|
||||
let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com', severity: :silence) } |
||||
let(:params) { { domain: 'example.com', severity: 'suspend' } } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the updated domain block' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match a_hash_including( |
||||
{ |
||||
id: domain_block.id.to_s, |
||||
domain: domain_block.domain, |
||||
severity: 'suspend', |
||||
} |
||||
) |
||||
end |
||||
|
||||
it 'updates the block severity' do |
||||
expect { subject }.to change { domain_block.reload.severity }.from('silence').to('suspend') |
||||
end |
||||
|
||||
context 'when domain block does not exist' do |
||||
it 'returns http not found' do |
||||
put '/api/v1/admin/domain_blocks/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE /api/v1/admin/domain_blocks/:id' do |
||||
subject do |
||||
delete "/api/v1/admin/domain_blocks/#{domain_block.id}", headers: headers |
||||
end |
||||
|
||||
let!(:domain_block) { Fabricate(:domain_block) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'deletes the domain block' do |
||||
subject |
||||
|
||||
expect(DomainBlock.find_by(id: domain_block.id)).to be_nil |
||||
end |
||||
|
||||
context 'when domain block does not exist' do |
||||
it 'returns http not found' do |
||||
delete '/api/v1/admin/domain_blocks/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,275 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'IP Blocks' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:scopes) { 'admin:read:ip_blocks admin:write:ip_blocks' } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/ip_blocks' do |
||||
subject do |
||||
get '/api/v1/admin/ip_blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { {} } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there is no ip block' do |
||||
it 'returns an empty body' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are ip blocks' do |
||||
let!(:ip_blocks) do |
||||
[ |
||||
IpBlock.create(ip: '192.0.2.0/24', severity: :no_access), |
||||
IpBlock.create(ip: '172.16.0.1', severity: :sign_up_requires_approval, comment: 'Spam'), |
||||
IpBlock.create(ip: '2001:0db8::/32', severity: :sign_up_block, expires_in: 10.days), |
||||
] |
||||
end |
||||
let(:expected_response) do |
||||
ip_blocks.map do |ip_block| |
||||
{ |
||||
id: ip_block.id.to_s, |
||||
ip: ip_block.ip, |
||||
severity: ip_block.severity.to_s, |
||||
comment: ip_block.comment, |
||||
created_at: ip_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
expires_at: ip_block.expires_at&.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), |
||||
} |
||||
end |
||||
end |
||||
|
||||
it 'returns the correct blocked ips' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 2 } } |
||||
|
||||
it 'returns only the requested number of ip blocks' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(params[:limit]) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/ip_blocks/:id' do |
||||
subject do |
||||
get "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers |
||||
end |
||||
|
||||
let!(:ip_block) { IpBlock.create(ip: '192.0.2.0/24', severity: :no_access) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct ip block' do |
||||
subject |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:ip]).to eq("#{ip_block.ip}/#{ip_block.ip.prefix}") |
||||
expect(json[:severity]).to eq(ip_block.severity.to_s) |
||||
end |
||||
|
||||
context 'when ip block does not exist' do |
||||
it 'returns http not found' do |
||||
get '/api/v1/admin/ip_blocks/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'POST /api/v1/admin/ip_blocks' do |
||||
subject do |
||||
post '/api/v1/admin/ip_blocks', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { { ip: '151.0.32.55', severity: 'no_access', comment: 'Spam' } } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read:ip_blocks' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
it_behaves_like 'forbidden for wrong role', 'Moderator' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct ip block' do |
||||
subject |
||||
|
||||
json = body_as_json |
||||
|
||||
expect(json[:ip]).to eq("#{params[:ip]}/32") |
||||
expect(json[:severity]).to eq(params[:severity]) |
||||
expect(json[:comment]).to eq(params[:comment]) |
||||
end |
||||
|
||||
context 'when the required ip param is not provided' do |
||||
let(:params) { { ip: '', severity: 'no_access' } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when the required severity param is not provided' do |
||||
let(:params) { { ip: '173.65.23.1', severity: '' } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when the given ip address is already blocked' do |
||||
before do |
||||
IpBlock.create(params) |
||||
end |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
|
||||
context 'when the given ip address is invalid' do |
||||
let(:params) { { ip: '520.13.54.120', severity: 'no_access' } } |
||||
|
||||
it 'returns http unprocessable entity' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(422) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'PUT /api/v1/admin/ip_blocks/:id' do |
||||
subject do |
||||
put "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers, params: params |
||||
end |
||||
|
||||
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) } |
||||
let(:params) { { severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } } |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the correct ip block' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match(hash_including({ |
||||
ip: "#{ip_block.ip}/#{ip_block.ip.prefix}", |
||||
severity: 'sign_up_requires_approval', |
||||
comment: 'Decreasing severity', |
||||
})) |
||||
end |
||||
|
||||
it 'updates the severity correctly' do |
||||
expect { subject }.to change { ip_block.reload.severity }.from('no_access').to('sign_up_requires_approval') |
||||
end |
||||
|
||||
it 'updates the comment correctly' do |
||||
expect { subject }.to change { ip_block.reload.comment }.from('Spam').to('Decreasing severity') |
||||
end |
||||
|
||||
context 'when ip block does not exist' do |
||||
it 'returns http not found' do |
||||
put '/api/v1/admin/ip_blocks/-1', headers: headers, params: params |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'DELETE /api/v1/admin/ip_blocks/:id' do |
||||
subject do |
||||
delete "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers |
||||
end |
||||
|
||||
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') } |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns an empty body' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
|
||||
it 'deletes the ip block' do |
||||
subject |
||||
|
||||
expect(IpBlock.find_by(id: ip_block.id)).to be_nil |
||||
end |
||||
|
||||
context 'when ip block does not exist' do |
||||
it 'returns http not found' do |
||||
delete '/api/v1/admin/ip_blocks/-1', headers: headers |
||||
|
||||
expect(response).to have_http_status(404) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,292 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
RSpec.describe 'Reports' do |
||||
let(:role) { UserRole.find_by(name: 'Admin') } |
||||
let(:user) { Fabricate(:user, role: role) } |
||||
let(:scopes) { 'admin:read:reports admin:write:reports' } |
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } |
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } |
||||
|
||||
shared_examples 'forbidden for wrong scope' do |wrong_scope| |
||||
let(:scopes) { wrong_scope } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role| |
||||
let(:role) { UserRole.find_by(name: wrong_role) } |
||||
|
||||
it 'returns http forbidden' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(403) |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/reports' do |
||||
subject do |
||||
get '/api/v1/admin/reports', headers: headers, params: params |
||||
end |
||||
|
||||
let(:params) { {} } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
context 'when there are no reports' do |
||||
it 'returns an empty list' do |
||||
subject |
||||
|
||||
expect(body_as_json).to be_empty |
||||
end |
||||
end |
||||
|
||||
context 'when there are reports' do |
||||
let!(:reporter) { Fabricate(:account) } |
||||
let!(:spammer) { Fabricate(:account) } |
||||
let(:expected_response) do |
||||
scope.map do |report| |
||||
hash_including({ |
||||
id: report.id.to_s, |
||||
action_taken: report.action_taken?, |
||||
category: report.category, |
||||
comment: report.comment, |
||||
account: hash_including(id: report.account.id.to_s), |
||||
target_account: hash_including(id: report.target_account.id.to_s), |
||||
statuses: report.statuses, |
||||
rules: report.rules, |
||||
forwarded: report.forwarded, |
||||
}) |
||||
end |
||||
end |
||||
let(:scope) { Report.unresolved } |
||||
|
||||
before do |
||||
Fabricate(:report) |
||||
Fabricate(:report, target_account: spammer) |
||||
Fabricate(:report, account: reporter, target_account: spammer) |
||||
Fabricate(:report, action_taken_at: 4.days.ago, account: reporter) |
||||
Fabricate(:report, action_taken_at: 20.days.ago) |
||||
end |
||||
|
||||
it 'returns all unresolved reports' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
|
||||
context 'with resolved param' do |
||||
let(:params) { { resolved: true } } |
||||
let(:scope) { Report.resolved } |
||||
|
||||
it 'returns only the resolved reports' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
end |
||||
|
||||
context 'with account_id param' do |
||||
let(:params) { { account_id: reporter.id } } |
||||
let(:scope) { Report.unresolved.where(account: reporter) } |
||||
|
||||
it 'returns all unresolved reports filed by the specified account' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
end |
||||
|
||||
context 'with target_account_id param' do |
||||
let(:params) { { target_account_id: spammer.id } } |
||||
let(:scope) { Report.unresolved.where(target_account: spammer) } |
||||
|
||||
it 'returns all unresolved reports targeting the specified account' do |
||||
subject |
||||
|
||||
expect(body_as_json).to match_array(expected_response) |
||||
end |
||||
end |
||||
|
||||
context 'with limit param' do |
||||
let(:params) { { limit: 1 } } |
||||
|
||||
it 'returns only the requested number of reports' do |
||||
subject |
||||
|
||||
expect(body_as_json.size).to eq(1) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe 'GET /api/v1/admin/reports/:id' do |
||||
subject do |
||||
get "/api/v1/admin/reports/#{report.id}", headers: headers |
||||
end |
||||
|
||||
let(:report) { Fabricate(:report) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'returns the requested report content' do |
||||
subject |
||||
|
||||
expect(body_as_json).to include( |
||||
{ |
||||
id: report.id.to_s, |
||||
action_taken: report.action_taken?, |
||||
category: report.category, |
||||
comment: report.comment, |
||||
account: a_hash_including(id: report.account.id.to_s), |
||||
target_account: a_hash_including(id: report.target_account.id.to_s), |
||||
statuses: report.statuses, |
||||
rules: report.rules, |
||||
forwarded: report.forwarded, |
||||
} |
||||
) |
||||
end |
||||
end |
||||
|
||||
describe 'PUT /api/v1/admin/reports/:id' do |
||||
subject do |
||||
put "/api/v1/admin/reports/#{report.id}", headers: headers, params: params |
||||
end |
||||
|
||||
let!(:report) { Fabricate(:report, category: :other) } |
||||
let(:params) { { category: 'spam' } } |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'updates the report category' do |
||||
expect { subject }.to change { report.reload.category }.from('other').to('spam') |
||||
end |
||||
|
||||
it 'returns the updated report content' do |
||||
subject |
||||
|
||||
report.reload |
||||
|
||||
expect(body_as_json).to include( |
||||
{ |
||||
id: report.id.to_s, |
||||
action_taken: report.action_taken?, |
||||
category: report.category, |
||||
comment: report.comment, |
||||
account: a_hash_including(id: report.account.id.to_s), |
||||
target_account: a_hash_including(id: report.target_account.id.to_s), |
||||
statuses: report.statuses, |
||||
rules: report.rules, |
||||
forwarded: report.forwarded, |
||||
} |
||||
) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #resolve' do |
||||
subject do |
||||
post "/api/v1/admin/reports/#{report.id}/resolve", headers: headers |
||||
end |
||||
|
||||
let(:report) { Fabricate(:report, action_taken_at: nil) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'marks report as resolved' do |
||||
expect { subject }.to change { report.reload.unresolved? }.from(true).to(false) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #reopen' do |
||||
subject do |
||||
post "/api/v1/admin/reports/#{report.id}/reopen", headers: headers |
||||
end |
||||
|
||||
let(:report) { Fabricate(:report, action_taken_at: 10.days.ago) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'marks report as unresolved' do |
||||
expect { subject }.to change { report.reload.unresolved? }.from(false).to(true) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #assign_to_self' do |
||||
subject do |
||||
post "/api/v1/admin/reports/#{report.id}/assign_to_self", headers: headers |
||||
end |
||||
|
||||
let(:report) { Fabricate(:report) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'assigns report to the requesting user' do |
||||
expect { subject }.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id) |
||||
end |
||||
end |
||||
|
||||
describe 'POST #unassign' do |
||||
subject do |
||||
post "/api/v1/admin/reports/#{report.id}/unassign", headers: headers |
||||
end |
||||
|
||||
let(:report) { Fabricate(:report, assigned_account_id: user.account.id) } |
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses' |
||||
it_behaves_like 'forbidden for wrong role', '' |
||||
|
||||
it 'returns http success' do |
||||
subject |
||||
|
||||
expect(response).to have_http_status(200) |
||||
end |
||||
|
||||
it 'unassigns report from assignee' do |
||||
expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil) |
||||
end |
||||
end |
||||
end |
@ -1,74 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
shared_examples 'ScopedSettings' do |
||||
describe '[]' do |
||||
it 'inherits default settings' do |
||||
expect(Setting.boost_modal).to be false |
||||
expect(Setting.interactions['must_be_follower']).to be false |
||||
|
||||
settings = create! |
||||
|
||||
expect(settings['boost_modal']).to be false |
||||
expect(settings['interactions']['must_be_follower']).to be false |
||||
end |
||||
end |
||||
|
||||
describe 'all_as_records' do |
||||
# expecting [] and []= works |
||||
|
||||
it 'returns records merged with default values except hashes' do |
||||
expect(Setting.boost_modal).to be false |
||||
expect(Setting.delete_modal).to be true |
||||
|
||||
settings = create! |
||||
settings['boost_modal'] = true |
||||
|
||||
records = settings.all_as_records |
||||
|
||||
expect(records['boost_modal'].value).to be true |
||||
expect(records['delete_modal'].value).to be true |
||||
end |
||||
end |
||||
|
||||
describe 'missing methods' do |
||||
# expecting [] and []= works. |
||||
|
||||
it 'reads settings' do |
||||
expect(Setting.boost_modal).to be false |
||||
settings = create! |
||||
expect(settings.boost_modal).to be false |
||||
end |
||||
|
||||
it 'updates settings' do |
||||
settings = fabricate |
||||
settings.boost_modal = true |
||||
expect(settings['boost_modal']).to be true |
||||
end |
||||
end |
||||
|
||||
it 'can update settings with [] and can read with []=' do |
||||
settings = fabricate |
||||
|
||||
settings['boost_modal'] = true |
||||
settings['interactions'] = settings['interactions'].merge('must_be_follower' => true) |
||||
|
||||
Setting.save! |
||||
|
||||
expect(settings['boost_modal']).to be true |
||||
expect(settings['interactions']['must_be_follower']).to be true |
||||
|
||||
Rails.cache.clear |
||||
|
||||
expect(settings['boost_modal']).to be true |
||||
expect(settings['interactions']['must_be_follower']).to be true |
||||
end |
||||
|
||||
xit 'does not mutate defaults via the cache' do |
||||
fabricate['interactions']['must_be_follower'] = true |
||||
# TODO |
||||
# This mutates the global settings default such that future |
||||
# instances will inherit the incorrect starting values |
||||
|
||||
expect(fabricate.settings['interactions']['must_be_follower']).to be false |
||||
end |
||||
end |
@ -1,15 +0,0 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
shared_examples 'Settings-extended' do |
||||
describe 'settings' do |
||||
def fabricate |
||||
super.settings |
||||
end |
||||
|
||||
def create! |
||||
super.settings |
||||
end |
||||
|
||||
it_behaves_like 'ScopedSettings' |
||||
end |
||||
end |
Loading…
Reference in new issue