Merge commit '25c66fa640' into kb_migration

This commit is contained in:
KMY 2023-06-13 18:34:49 +09:00
commit 1f64358afb
107 changed files with 2159 additions and 1540 deletions

View file

@ -394,7 +394,7 @@ RSpec/MessageSpies:
- 'spec/validators/status_length_validator_spec.rb'
RSpec/MultipleExpectations:
Max: 19
Max: 8
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
@ -1242,11 +1242,6 @@ Style/GlobalStdStream:
- 'config/environments/development.rb'
- 'config/environments/production.rb'
# Configuration parameters: AllowedVariables.
Style/GlobalVars:
Exclude:
- 'config/initializers/statsd.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals.
Style/GuardClause:
@ -1380,7 +1375,6 @@ Style/RedundantConstantBase:
Exclude:
- 'config/environments/production.rb'
- 'config/initializers/sidekiq.rb'
- 'config/initializers/statsd.rb'
- 'config/locales/sr-Latn.rb'
- 'config/locales/sr.rb'

View file

@ -887,4 +887,4 @@ RUBY VERSION
ruby 3.2.2p53
BUNDLED WITH
2.4.10
2.4.13

View file

@ -14,15 +14,5 @@ module Admin
@pending_tags_count = Tag.pending_review.count
@pending_appeals_count = Appeal.pending.count
end
private
def redis_info
@redis_info ||= if redis.is_a?(Redis::Namespace)
redis.redis.info
else
redis.info
end
end
end
end

View file

@ -90,7 +90,7 @@ class Api::V1::AccountsController < Api::BaseController
end
def account_params
params.permit(:username, :email, :password, :agreement, :locale, :reason)
params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone)
end
def check_enabled_registrations

View file

@ -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

View file

@ -19,6 +19,6 @@ class Settings::Preferences::BaseController < Settings::BaseController
end
def user_params
params.require(:user).permit(:locale, chosen_languages: [], settings_attributes: UserSettings.keys)
params.require(:user).permit(:locale, :time_zone, chosen_languages: [], settings_attributes: UserSettings.keys)
end
end

View file

@ -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>
);
}
}

View file

@ -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>
);
};

View file

@ -16,7 +16,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';
import { LoadMore } from './load_more';
import LoadPending from './load_pending';
import { LoadPending } from './load_pending';
import LoadingIndicator from './loading_indicator';
const MOUSE_IDLE_DELAY = 300;

View file

@ -377,7 +377,7 @@ class Header extends ImmutablePureComponent {
let badge;
if (account.get('bot')) {
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>);
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Automated' /></div>);
} else if (account.get('group')) {
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
} else {

View file

@ -15,7 +15,7 @@
"about.rules": "Server rules",
"account.account_note_header": "Note",
"account.add_or_remove_from_list": "Add or Remove from lists",
"account.badges.bot": "Bot",
"account.badges.bot": "Automated",
"account.badges.group": "Group",
"account.block": "Block @{name}",
"account.block_domain": "Block domain {domain}",

View file

@ -8,61 +8,71 @@ class NotificationMailer < ApplicationMailer
def mention(recipient, notification)
@me = recipient
@user = recipient.user
@type = 'mention'
@status = notification.target_status
return unless @me.user.functional? && @status.present?
return unless @user.functional? && @status.present?
locale_for_account(@me) do
thread_by_conversation(@status.conversation)
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
end
end
def follow(recipient, notification)
@me = recipient
@user = recipient.user
@type = 'follow'
@account = notification.from_account
return unless @me.user.functional?
return unless @user.functional?
locale_for_account(@me) do
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
end
end
def favourite(recipient, notification)
@me = recipient
@user = recipient.user
@type = 'favourite'
@account = notification.from_account
@status = notification.target_status
return unless @me.user.functional? && @status.present?
return unless @user.functional? && @status.present?
locale_for_account(@me) do
thread_by_conversation(@status.conversation)
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
end
end
def reblog(recipient, notification)
@me = recipient
@user = recipient.user
@type = 'reblog'
@account = notification.from_account
@status = notification.target_status
return unless @me.user.functional? && @status.present?
return unless @user.functional? && @status.present?
locale_for_account(@me) do
thread_by_conversation(@status.conversation)
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
end
end
def follow_request(recipient, notification)
@me = recipient
@user = recipient.user
@type = 'follow_request'
@account = notification.from_account
return unless @me.user.functional?
return unless @user.functional?
locale_for_account(@me) do
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
end
end

View file

@ -145,6 +145,7 @@ class Account < ApplicationRecord
:locale,
:shows_application?,
:prefers_noindex?,
:time_zone,
to: :user,
prefix: true,
allow_nil: true

View file

@ -40,6 +40,7 @@
# sign_up_ip :inet
# role_id :bigint(8)
# settings :text
# time_zone :string
#
class User < ApplicationRecord
@ -101,6 +102,7 @@ class User < ApplicationRecord
validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? }
validates_with EmailMxValidator, if: :validate_email_dns?
validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
validates :time_zone, inclusion: { in: ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name } }, allow_blank: true
# Honeypot/anti-spam fields
attr_accessor :registration_form_time, :website, :confirm_password

View file

@ -35,7 +35,7 @@ class AppSignUpService < BaseService
end
def user_params
@params.slice(:email, :password, :agreement, :locale)
@params.slice(:email, :password, :agreement, :locale, :time_zone)
end
def account_params

View file

@ -44,7 +44,11 @@
%tbody
%td.column-cell
%p= t 'about.hosted_on', domain: site_hostname
%p= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url
%p
= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url
- if defined?(@type)
·
= link_to t('application_mailer.unsubscribe'), unsubscribe_url(token: @user.to_sgid(for: 'unsubscribe').to_s, type: @type)
%td.column-cell.text-right
= link_to root_url do
= image_tag full_pack_url('media/images/mailer/logo.png'), alt: 'Mastodon', height: 24

View file

@ -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)

View file

@ -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

View file

@ -42,4 +42,4 @@
= link_to a.remote_url, a.remote_url
%p.status-footer
= link_to l(status.created_at), web_url("@#{status.account.pretty_acct}/#{status.id}")
= link_to l(status.created_at.in_time_zone(time_zone)), web_url("@#{status.account.pretty_acct}/#{status.id}")

View file

@ -22,7 +22,7 @@
%h1= t 'notification_mailer.favourite.title'
%p.lead= t('notification_mailer.favourite.body', name: @account.pretty_acct)
= render 'status', status: @status
= render 'status', status: @status, time_zone: @me.user_time_zone
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -22,7 +22,7 @@
%h1= t 'notification_mailer.mention.title'
%p.lead= t('notification_mailer.mention.body', name: @status.account.pretty_acct)
= render 'status', status: @status
= render 'status', status: @status, time_zone: @me.user_time_zone
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -22,7 +22,7 @@
%h1= t 'notification_mailer.reblog.title'
%p.lead= t('notification_mailer.reblog.body', name: @account.pretty_acct)
= render 'status', status: @status
= render 'status', status: @status, time_zone: @me.user_time_zone
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -9,8 +9,11 @@
.fields-group.fields-row__column.fields-row__column-6
= f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| native_locale_name(locale) }, selected: I18n.locale, hint: false
.fields-group.fields-row__column.fields-row__column-6
= f.simple_fields_for :settings, current_user.settings do |ff|
= ff.input :theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, include_blank: false, hint: false
= f.input :time_zone, wrapper: :with_label, collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] }, hint: false
.fields-group
= f.simple_fields_for :settings, current_user.settings do |ff|
= ff.input :theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_theme'), include_blank: false, hint: false
- unless I18n.locale == :en
.flash-message.translation-prompt

View file

@ -36,7 +36,7 @@
%tbody
%tr
%td.column-cell.text-center
%p= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at)
%p= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone))
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -2,6 +2,6 @@
===
<%= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) %>
<%= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone)) %>
=> <%= root_url %>

View file

@ -36,7 +36,7 @@
%tbody
%tr
%td.column-cell.text-center
%p= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at)
%p= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone))
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -2,6 +2,6 @@
===
<%= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) %>
<%= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone)) %>
=> <%= root_url %>

View file

@ -47,7 +47,7 @@
%strong= "#{t('sessions.browser')}:"
%span{ title: @user_agent }= t 'sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s), platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
%br/
= l(@timestamp)
= l(@timestamp.in_time_zone(@resource.time_zone))
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -8,7 +8,7 @@
<%= t('sessions.ip') %>: <%= @remote_ip %>
<%= t('sessions.browser') %>: <%= t('sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: "#{@detection.id}"), platform: t("sessions.platforms.#{@detection.platform.id}", default: "#{@detection.platform.id}")) %>
<%= l(@timestamp) %>
<%= l(@timestamp.in_time_zone(@resource.time_zone)) %>
<%= t 'user_mailer.suspicious_sign_in.further_actions_html', action: t('user_mailer.suspicious_sign_in.change_password') %>

View file

@ -58,7 +58,7 @@
- unless @statuses.empty?
- @statuses.each_with_index do |status, i|
= render 'notification_mailer/status', status: status, i: i + 1, highlighted: true
= render 'notification_mailer/status', status: status, i: i + 1, highlighted: true, time_zone: @resource.time_zone
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody

View file

@ -66,6 +66,7 @@ ignore_unused:
- 'notification_mailer.*'
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
- 'mail_subscriptions.unsubscribe.emails.*'
ignore_inconsistent_interpolations:
- '*.one'

View file

@ -1072,6 +1072,7 @@ en:
notification_preferences: Change e-mail preferences
salutation: "%{name},"
settings: 'Change e-mail preferences: %{link}'
unsubscribe: Unsubscribe
view: 'View:'
view_profile: View profile
view_status: View post
@ -1437,6 +1438,21 @@ en:
failed_sign_in_html: Failed sign-in attempt with %{method} from %{ip} (%{browser})
successful_sign_in_html: Successful sign-in with %{method} from %{ip} (%{browser})
title: Authentication history
mail_subscriptions:
unsubscribe:
action: Yes, unsubscribe
complete: Unsubscribed
confirmation_html: Are you sure you want to unsubscribe from receiving %{type} for Mastodon on %{domain} to your e-mail at %{email}? You can always re-subscribe from your <a href="%{settings_path}">e-mail notification settings</a>.
emails:
notification_emails:
favourite: favorite notification e-mails
follow: follow notification e-mails
follow_request: follow request e-mails
mention: mention notification e-mails
reblog: boost notification e-mails
resubscribe_html: If you've unsubscribed by mistake, you can re-subscribe from your <a href="%{settings_path}">e-mail notification settings</a>.
success_html: You'll no longer receive %{type} for Mastodon on %{domain} to your e-mail at %{email}.
title: Unsubscribe
media_attachments:
validations:
images_and_video: Cannot attach a video to a post that already contains images

View file

@ -173,7 +173,7 @@ en:
defaults:
autofollow: Invite to follow your account
avatar: Avatar
bot: This is a bot account
bot: This is an automated account
chosen_languages: Filter languages
confirm_new_password: Confirm new password
confirm_password: Confirm password
@ -322,6 +322,7 @@ en:
usable: Allow posts to use this hashtag
user:
role: Role
time_zone: Time zone
user_role:
color: Badge color
highlighted: Display role as badge on user profiles

View file

@ -69,6 +69,8 @@ Rails.application.routes.draw do
devise_scope :user do
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
resource :unsubscribe, only: [:show, :create], controller: :mail_subscriptions
namespace :auth do
resource :setup, only: [:show, :update], controller: :setup
resource :challenge, only: [:create], controller: :challenges

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddTimeZoneToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :time_zone, :string
end
end

View file

@ -12,7 +12,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2023_06_05_085710) do
ActiveRecord::Schema.define(version: 2023_06_05_085711) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -1211,6 +1211,7 @@ ActiveRecord::Schema.define(version: 2023_06_05_085710) do
t.boolean "skip_sign_in_token"
t.bigint "role_id"
t.text "settings"
t.string "time_zone"
t.index ["account_id"], name: "index_users_on_account_id"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id", where: "(created_by_application_id IS NOT NULL)"

View file

@ -23,23 +23,12 @@ module Mastodon::CLI
def recount(type)
case type
when 'accounts'
processed, = parallelize_with_progress(Account.local.includes(:account_stat)) do |account|
account_stat = account.account_stat
account_stat.following_count = account.active_relationships.count
account_stat.followers_count = account.passive_relationships.count
account_stat.statuses_count = account.statuses.where.not(visibility: :direct).count
account_stat.save if account_stat.changed?
processed, = parallelize_with_progress(accounts_with_stats) do |account|
recount_account_stats(account)
end
when 'statuses'
processed, = parallelize_with_progress(Status.includes(:status_stat)) do |status|
status_stat = status.status_stat
status_stat.replies_count = status.replies.where.not(visibility: :direct).count
status_stat.reblogs_count = status.reblogs.count
status_stat.favourites_count = status.favourites.count
status_stat.emoji_reactions = status.generate_emoji_reactions_grouped_by_name
status_stat.save if status_stat.changed?
processed, = parallelize_with_progress(statuses_with_stats) do |status|
recount_status_stats(status)
end
else
say("Unknown type: #{type}", :red)
@ -49,5 +38,36 @@ module Mastodon::CLI
say
say("OK, recounted #{processed} records", :green)
end
private
def accounts_with_stats
Account.local.includes(:account_stat)
end
def statuses_with_stats
Status.includes(:status_stat)
end
def recount_account_stats(account)
account.account_stat.tap do |account_stat|
account_stat.following_count = account.active_relationships.count
account_stat.followers_count = account.passive_relationships.count
account_stat.statuses_count = account.statuses.where.not(visibility: :direct).count
account_stat.save if account_stat.changed?
end
end
def recount_status_stats(status)
status.status_stat.tap do |status_stat|
status_stat.replies_count = status.replies.where.not(visibility: :direct).count
status_stat.reblogs_count = status.reblogs.count
status_stat.favourites_count = status.favourites.count
status_stat.emoji_reactions = status.generate_emoji_reactions_grouped_by_name
status_stat.save if status_stat.changed?
end
end
end
end

View file

@ -19,7 +19,7 @@ module Mastodon::CLI
LONG_DESC
def build(username = nil)
if options[:all] || username.nil?
processed, = parallelize_with_progress(Account.joins(:user).merge(User.active)) do |account|
processed, = parallelize_with_progress(active_user_accounts) do |account|
PrecomputeFeedService.new.call(account) unless dry_run?
end
@ -47,5 +47,11 @@ module Mastodon::CLI
redis.del(keys)
say('OK', :green)
end
private
def active_user_accounts
Account.joins(:user).merge(User.active)
end
end
end

View file

@ -48,25 +48,32 @@ describe Api::V1::Accounts::RelationshipsController do
expect(response).to have_http_status(200)
end
it 'returns JSON with correct data' do
json = body_as_json
context 'when there is returned JSON data' do
let(:json) { body_as_json }
expect(json).to be_a Enumerable
expect(json.first[:id]).to eq simon.id.to_s
expect(json.first[:following]).to be true
expect(json.first[:showing_reblogs]).to be true
expect(json.first[:followed_by]).to be false
expect(json.first[:muting]).to be false
expect(json.first[:requested]).to be false
expect(json.first[:domain_blocking]).to be false
it 'returns an enumerable json' do
expect(json).to be_a Enumerable
end
expect(json.second[:id]).to eq lewis.id.to_s
expect(json.second[:following]).to be false
expect(json.second[:showing_reblogs]).to be false
expect(json.second[:followed_by]).to be true
expect(json.second[:muting]).to be false
expect(json.second[:requested]).to be false
expect(json.second[:domain_blocking]).to be false
it 'returns a correct first element' do
expect(json.first[:id]).to eq simon.id.to_s
expect(json.first[:following]).to be true
expect(json.first[:showing_reblogs]).to be true
expect(json.first[:followed_by]).to be false
expect(json.first[:muting]).to be false
expect(json.first[:requested]).to be false
expect(json.first[:domain_blocking]).to be false
end
it 'returns a correct second element' do
expect(json.second[:id]).to eq lewis.id.to_s
expect(json.second[:following]).to be false
expect(json.second[:showing_reblogs]).to be false
expect(json.second[:followed_by]).to be true
expect(json.second[:muting]).to be false
expect(json.second[:requested]).to be false
expect(json.second[:domain_blocking]).to be false
end
end
it 'returns JSON with correct data on cached requests too' do

View file

@ -55,20 +55,6 @@ RSpec.describe Api::V1::AccountsController do
end
end
describe 'GET #show' do
let(:scopes) { 'read:accounts' }
before do
get :show, params: { id: user.account.id }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
end
describe 'POST #follow' do
let(:scopes) { 'write:follows' }
let(:other_account) { Fabricate(:account, username: 'bob', locked: locked) }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -56,18 +56,11 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
end
describe 'when creation succeeds' do
let!(:otp_backup_codes) { user.generate_otp_backup_codes! }
it 'renders page with success' do
otp_backup_codes = user.generate_otp_backup_codes!
expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|
expect(value).to eq user
otp_backup_codes
end
expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options|
expect(value).to eq user
expect(code).to eq '123456'
expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' })
true
end
prepare_user_otp_generation
prepare_user_otp_consumption
expect do
post :create,
@ -80,6 +73,22 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
expect(response).to have_http_status(200)
expect(response).to render_template('settings/two_factor_authentication/recovery_codes/index')
end
def prepare_user_otp_generation
expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|
expect(value).to eq user
otp_backup_codes
end
end
def prepare_user_otp_consumption
expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options|
expect(value).to eq user
expect(code).to eq '123456'
expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' })
true
end
end
end
describe 'when creation fails' do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:account_domain_block) do
account
account { Fabricate.build(:account) }
domain 'example.com'
end

View file

@ -2,6 +2,6 @@
Fabricator(:account_moderation_note) do
content 'MyText'
account
target_account { Fabricate(:account) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account) }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:account_note) do
account
target_account { Fabricate(:account) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account) }
comment 'User note text'
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:account_stat) do
account
account { Fabricate.build(:account) }
statuses_count '123'
following_count '456'
followers_count '789'

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true
Fabricator(:account_statuses_cleanup_policy) do
account
account { Fabricate.build(:account) }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:account_warning) do
account
account { Fabricate.build(:account) }
target_account(fabricator: :account)
text { Faker::Lorem.paragraph }
action 'suspend'

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator('Admin::ActionLog') do
account
account { Fabricate.build(:account) }
action 'MyString'
target nil
end

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true
Fabricator(:backup) do
user
user { Fabricate.build(:user) }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:block) do
account
target_account { Fabricate(:account) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account) }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:bookmark) do
account
status
account { Fabricate.build(:account) }
status { Fabricate.build(:status) }
end

View file

@ -8,5 +8,5 @@ Fabricator(:bulk_import) do
imported_items 1
finished_at '2022-11-18 14:55:07'
overwrite false
account
account { Fabricate.build(:account) }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:bulk_import_row) do
bulk_import
bulk_import { Fabricate.build(:bulk_import) }
data ''
end

View file

@ -2,5 +2,5 @@
Fabricator(:canonical_email_block) do
email { sequence(:email) { |i| "#{i}#{Faker::Internet.email}" } }
reference_account { Fabricate(:account) }
reference_account { Fabricate.build(:account) }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:custom_filter) do
account
account { Fabricate.build(:account) }
expires_at nil
phrase 'discourse'
context %w(home notifications)

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:custom_filter_keyword) do
custom_filter
custom_filter { Fabricate.build(:custom_filter) }
keyword 'discourse'
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:custom_filter_status) do
custom_filter
status
custom_filter { Fabricate.build(:custom_filter) }
status { Fabricate.build(:status) }
end

View file

@ -1,8 +1,8 @@
# frozen_string_literal: true
Fabricator(:device) do
access_token
account
access_token { Fabricate.build(:access_token) }
account { Fabricate.build(:account) }
device_id { Faker::Number.number(digits: 5) }
name { Faker::App.name }
fingerprint_key { Base64.strict_encode64(Ed25519::SigningKey.generate.verify_key.to_bytes) }

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true
Fabricator(:domain_allow) do
domain 'MyString'
domain { sequence(:domain) { |i| "example#{i}.com" } }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:encrypted_message) do
device
from_account { Fabricate(:account) }
device { Fabricate.build(:device) }
from_account { Fabricate.build(:account) }
from_device_id { Faker::Number.number(digits: 5) }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:favourite) do
account
status
account { Fabricate.build(:account) }
status { Fabricate.build(:status) }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:featured_tag) do
account
tag
account { Fabricate.build(:account) }
tag { Fabricate.build(:tag) }
name { sequence(:name) { |i| "Tag#{i}" } }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:follow) do
account
target_account { Fabricate(:account) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account) }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:follow_request) do
account
target_account { Fabricate(:account, locked: true) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account, locked: true) }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:identity) do
user
user { Fabricate.build(:user) }
provider 'MyString'
uid 'MyString'
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:invite) do
user
user { Fabricate.build(:user) }
expires_at nil
max_uses nil
uses 0

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:list) do
account
account { Fabricate.build(:account) }
title 'MyString'
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:login_activity) do
user
user { Fabricate.build(:user) }
authentication_method 'password'
success true
failure_reason nil

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:marker) do
user
user { Fabricate.build(:user) }
timeline 'home'
last_read_id 0
lock_version 0

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:media_attachment) do
account
account { Fabricate.build(:account) }
file do |attrs|
case attrs[:type]

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:mention) do
account
status
account { Fabricate.build(:account) }
status { Fabricate.build(:status) }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:mute) do
account
target_account { Fabricate(:account) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account) }
end

View file

@ -2,5 +2,5 @@
Fabricator(:notification) do
activity fabricator: :status
account
account { Fabricate.build(:account) }
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:one_time_key) do
device
device { Fabricate.build(:device) }
key_id { Faker::Alphanumeric.alphanumeric(number: 10) }
key { Base64.strict_encode64(Ed25519::SigningKey.generate.verify_key.to_bytes) }

View file

@ -1,8 +1,8 @@
# frozen_string_literal: true
Fabricator(:poll) do
account
status
account { Fabricate.build(:account) }
status { Fabricate.build(:status) }
expires_at { 7.days.from_now }
options %w(Foo Bar)
multiple false

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:poll_vote) do
account
account { Fabricate.build(:account) }
poll
choice 0
end

View file

@ -1,8 +1,8 @@
# frozen_string_literal: true
Fabricator(:report) do
account
target_account { Fabricate(:account) }
account { Fabricate.build(:account) }
target_account { Fabricate.build(:account) }
comment 'You nasty'
action_taken_at nil
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:report_note) do
report
account { Fabricate(:account) }
report { Fabricate.build(:report) }
account { Fabricate.build(:account) }
content 'Test Content'
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:scheduled_status) do
account
account { Fabricate.build(:account) }
scheduled_at { 20.hours.from_now }
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:session_activation) do
user
user { Fabricate.build(:user) }
session_id 'MyString'
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
Fabricator(:status) do
account
account { Fabricate.build(:account) }
text 'Lorem ipsum dolor sit amet'
after_build do |status|

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:status_pin) do
account
status { |attrs| Fabricate(:status, account: attrs[:account], visibility: :public) }
account { Fabricate.build(:account) }
status { |attrs| Fabricate.build(:status, account: attrs[:account], visibility: :public) }
end

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
Fabricator(:status_stat) do
status
replies_count '123'
reblogs_count '456'
favourites_count '789'
end

View file

@ -2,5 +2,5 @@
Fabricator(:tag_follow) do
tag
account
account { Fabricate.build(:account) }
end

View file

@ -4,9 +4,68 @@ require 'rails_helper'
require 'mastodon/cli/cache'
describe Mastodon::CLI::Cache do
let(:cli) { described_class.new }
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
describe '#clear' do
before { allow(Rails.cache).to receive(:clear) }
it 'clears the Rails cache' do
expect { cli.invoke(:clear) }.to output(
a_string_including('OK')
).to_stdout
expect(Rails.cache).to have_received(:clear)
end
end
describe '#recount' do
context 'with the `accounts` argument' do
let(:arguments) { ['accounts'] }
let(:account_stat) { Fabricate(:account_stat) }
before do
account_stat.update(statuses_count: 123)
end
it 're-calculates account records in the cache' do
expect { cli.invoke(:recount, arguments) }.to output(
a_string_including('OK')
).to_stdout
expect(account_stat.reload.statuses_count).to be_zero
end
end
context 'with the `statuses` argument' do
let(:arguments) { ['statuses'] }
let(:status_stat) { Fabricate(:status_stat) }
before do
status_stat.update(replies_count: 123)
end
it 're-calculates account records in the cache' do
expect { cli.invoke(:recount, arguments) }.to output(
a_string_including('OK')
).to_stdout
expect(status_stat.reload.replies_count).to be_zero
end
end
context 'with an unknown type' do
let(:arguments) { ['other-type'] }
it 'Exits with an error message' do
expect { cli.invoke(:recount, arguments) }.to output(
a_string_including('Unknown')
).to_stdout.and raise_error(SystemExit)
end
end
end
end

View file

@ -4,9 +4,65 @@ require 'rails_helper'
require 'mastodon/cli/feeds'
describe Mastodon::CLI::Feeds do
let(:cli) { described_class.new }
describe '.exit_on_failure?' do
it 'returns true' do
expect(described_class.exit_on_failure?).to be true
end
end
describe '#build' do
before { Fabricate(:account) }
context 'with --all option' do
let(:options) { { all: true } }
it 'regenerates feeds for all accounts' do
expect { cli.invoke(:build, [], options) }.to output(
a_string_including('Regenerated feeds')
).to_stdout
end
end
context 'with a username' do
before { Fabricate(:account, username: 'alice') }
let(:arguments) { ['alice'] }
it 'regenerates feeds for the account' do
expect { cli.invoke(:build, arguments) }.to output(
a_string_including('OK')
).to_stdout
end
end
context 'with invalid username' do
let(:arguments) { ['invalid-username'] }
it 'displays an error and exits' do
expect { cli.invoke(:build, arguments) }.to output(
a_string_including('No such account')
).to_stdout.and raise_error(SystemExit)
end
end
end
describe '#clear' do
before do
allow(redis).to receive(:del).with(key_namespace)
end
it 'clears the redis `feed:*` namespace' do
expect { cli.invoke(:clear) }.to output(
a_string_including('OK')
).to_stdout
expect(redis).to have_received(:del).with(key_namespace).once
end
def key_namespace
redis.keys('feed:*')
end
end
end

View file

@ -245,17 +245,44 @@ RSpec.describe Form::Import do
expect(account.bulk_imports.first.rows.pluck(:data)).to match_array(expected_rows)
end
it 'creates a BulkImport with expected attributes' do
bulk_import = account.bulk_imports.first
expect(bulk_import).to_not be_nil
expect(bulk_import.type.to_sym).to eq subject.type.to_sym
expect(bulk_import.original_filename).to eq subject.data.original_filename
expect(bulk_import.likely_mismatched?).to eq subject.likely_mismatched?
expect(bulk_import.overwrite?).to eq !!subject.overwrite # rubocop:disable Style/DoubleNegation
expect(bulk_import.processed_items).to eq 0
expect(bulk_import.imported_items).to eq 0
expect(bulk_import.total_items).to eq bulk_import.rows.count
expect(bulk_import.unconfirmed?).to be true
context 'with a BulkImport' do
let(:bulk_import) { account.bulk_imports.first }
it 'creates a non-nil bulk import' do
expect(bulk_import).to_not be_nil
end
it 'matches the subjects type' do
expect(bulk_import.type.to_sym).to eq subject.type.to_sym
end
it 'matches the subjects original filename' do
expect(bulk_import.original_filename).to eq subject.data.original_filename
end
it 'matches the subjects likely_mismatched? value' do
expect(bulk_import.likely_mismatched?).to eq subject.likely_mismatched?
end
it 'matches the subject overwrite value' do
expect(bulk_import.overwrite?).to eq !!subject.overwrite # rubocop:disable Style/DoubleNegation
end
it 'has zero processed items' do
expect(bulk_import.processed_items).to eq 0
end
it 'has zero imported items' do
expect(bulk_import.imported_items).to eq 0
end
it 'has a correct total_items value' do
expect(bulk_import.total_items).to eq bulk_import.rows.count
end
it 'defaults to unconfirmed true' do
expect(bulk_import.unconfirmed?).to be true
end
end
end

View file

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe MediaAttachment do
RSpec.describe MediaAttachment, paperclip_processing: true do
describe 'local?' do
subject { media_attachment.local? }

View file

@ -99,73 +99,87 @@ RSpec.describe Notification do
]
end
it 'preloads target status' do
# mention
expect(subject[0].type).to eq :mention
expect(subject[0].association(:mention)).to be_loaded
expect(subject[0].mention.association(:status)).to be_loaded
context 'with a preloaded target status' do
it 'preloads mention' do
expect(subject[0].type).to eq :mention
expect(subject[0].association(:mention)).to be_loaded
expect(subject[0].mention.association(:status)).to be_loaded
end
# status
expect(subject[1].type).to eq :status
expect(subject[1].association(:status)).to be_loaded
it 'preloads status' do
expect(subject[1].type).to eq :status
expect(subject[1].association(:status)).to be_loaded
end
# reblog
expect(subject[2].type).to eq :reblog
expect(subject[2].association(:status)).to be_loaded
expect(subject[2].status.association(:reblog)).to be_loaded
it 'preloads reblog' do
expect(subject[2].type).to eq :reblog
expect(subject[2].association(:status)).to be_loaded
expect(subject[2].status.association(:reblog)).to be_loaded
end
# follow: nothing
expect(subject[3].type).to eq :follow
expect(subject[3].target_status).to be_nil
it 'preloads follow as nil' do
expect(subject[3].type).to eq :follow
expect(subject[3].target_status).to be_nil
end
# follow_request: nothing
expect(subject[4].type).to eq :follow_request
expect(subject[4].target_status).to be_nil
it 'preloads follow_request as nill' do
expect(subject[4].type).to eq :follow_request
expect(subject[4].target_status).to be_nil
end
# favourite
expect(subject[5].type).to eq :favourite
expect(subject[5].association(:favourite)).to be_loaded
expect(subject[5].favourite.association(:status)).to be_loaded
it 'preloads favourite' do
expect(subject[5].type).to eq :favourite
expect(subject[5].association(:favourite)).to be_loaded
expect(subject[5].favourite.association(:status)).to be_loaded
end
# poll
expect(subject[6].type).to eq :poll
expect(subject[6].association(:poll)).to be_loaded
expect(subject[6].poll.association(:status)).to be_loaded
it 'preloads poll' do
expect(subject[6].type).to eq :poll
expect(subject[6].association(:poll)).to be_loaded
expect(subject[6].poll.association(:status)).to be_loaded
end
end
it 'replaces to cached status' do
# mention
expect(subject[0].type).to eq :mention
expect(subject[0].target_status.association(:account)).to be_loaded
expect(subject[0].target_status).to eq mention.status
context 'with a cached status' do
it 'replaces mention' do
expect(subject[0].type).to eq :mention
expect(subject[0].target_status.association(:account)).to be_loaded
expect(subject[0].target_status).to eq mention.status
end
# status
expect(subject[1].type).to eq :status
expect(subject[1].target_status.association(:account)).to be_loaded
expect(subject[1].target_status).to eq status
it 'replaces status' do
expect(subject[1].type).to eq :status
expect(subject[1].target_status.association(:account)).to be_loaded
expect(subject[1].target_status).to eq status
end
# reblog
expect(subject[2].type).to eq :reblog
expect(subject[2].target_status.association(:account)).to be_loaded
expect(subject[2].target_status).to eq reblog.reblog
it 'replaces reblog' do
expect(subject[2].type).to eq :reblog
expect(subject[2].target_status.association(:account)).to be_loaded
expect(subject[2].target_status).to eq reblog.reblog
end
# follow: nothing
expect(subject[3].type).to eq :follow
expect(subject[3].target_status).to be_nil
it 'replaces follow' do
expect(subject[3].type).to eq :follow
expect(subject[3].target_status).to be_nil
end
# follow_request: nothing
expect(subject[4].type).to eq :follow_request
expect(subject[4].target_status).to be_nil
it 'replaces follow_request' do
expect(subject[4].type).to eq :follow_request
expect(subject[4].target_status).to be_nil
end
# favourite
expect(subject[5].type).to eq :favourite
expect(subject[5].target_status.association(:account)).to be_loaded
expect(subject[5].target_status).to eq favourite.status
it 'replaces favourite' do
expect(subject[5].type).to eq :favourite
expect(subject[5].target_status.association(:account)).to be_loaded
expect(subject[5].target_status).to eq favourite.status
end
# poll
expect(subject[6].type).to eq :poll
expect(subject[6].target_status.association(:account)).to be_loaded
expect(subject[6].target_status).to eq poll.status
it 'replaces poll' do
expect(subject[6].type).to eq :poll
expect(subject[6].target_status.association(:account)).to be_loaded
expect(subject[6].target_status).to eq poll.status
end
end
end
end

View file

@ -79,6 +79,7 @@ RSpec.configure do |config|
config.before :each, type: :cli do
stub_stdout
stub_reset_connection_pools
end
config.before :each, type: :feature do
@ -94,6 +95,12 @@ RSpec.configure do |config|
stub_jsonld_contexts!
end
config.before(:each) do |example|
unless example.metadata[:paperclip_processing]
allow_any_instance_of(Paperclip::Attachment).to receive(:post_process).and_return(true) # rubocop:disable RSpec/AnyInstance
end
end
config.after :each do
Rails.cache.clear
redis.del(redis.keys)
@ -115,9 +122,20 @@ def attachment_fixture(name)
end
def stub_stdout
# TODO: Is there a bettery way to:
# - Avoid CLI command output being printed out
# - Allow rspec to assert things against STDOUT
# - Avoid disabling stdout for other desirable output (deprecation warnings, for example)
allow($stdout).to receive(:write)
end
def stub_reset_connection_pools
# TODO: Is there a better way to correctly run specs without stubbing this?
# (Avoids reset_connection_pools! in test env)
allow(ActiveRecord::Base).to receive(:establish_connection)
allow(RedisConfiguration).to receive(:establish_pool)
end
def stub_jsonld_contexts!
stub_request(:get, 'https://www.w3.org/ns/activitystreams').to_return(request_fixture('json-ld.activitystreams.txt'))
stub_request(:get, 'https://w3id.org/identity/v1').to_return(request_fixture('json-ld.identity.txt'))

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -2,23 +2,20 @@
require 'rails_helper'
describe Api::V1::Admin::EmailDomainBlocksController do
render_views
RSpec.describe 'Email Domain 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(:account) { Fabricate(:account) }
let(:scopes) { 'admin:read:email_domain_blocks admin:write:email_domain_blocks' }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
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
@ -27,65 +24,54 @@ describe Api::V1::Admin::EmailDomainBlocksController do
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 #index' do
context 'with wrong scope' do
before do
get :index
end
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
describe 'GET /api/v1/admin/email_domain_blocks' do
subject do
get '/api/v1/admin/email_domain_blocks', headers: headers, params: params
end
context 'with wrong role' do
before do
get :index
end
let(:params) { {} }
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
end
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
get :index
subject
expect(response).to have_http_status(200)
end
context 'when there is no email domain block' do
it 'returns an empty list' do
get :index
subject
json = body_as_json
expect(json).to be_empty
expect(body_as_json).to be_empty
end
end
context 'when there are email domain blocks' do
let!(:email_domain_blocks) { Fabricate.times(5, :email_domain_block) }
let!(:email_domain_blocks) { Fabricate.times(5, :email_domain_block) }
let(:blocked_email_domains) { email_domain_blocks.pluck(:domain) }
it 'return the correct blocked email domains' do
get :index
subject
json = body_as_json
expect(json.pluck(:domain)).to match_array(blocked_email_domains)
expect(body_as_json.pluck(:domain)).to match_array(blocked_email_domains)
end
context 'with limit param' do
let(:params) { { limit: 2 } }
it 'returns only the requested number of email domain blocks' do
get :index, params: params
subject
json = body_as_json
expect(json.size).to eq(params[:limit])
expect(body_as_json.size).to eq(params[:limit])
end
end
@ -93,12 +79,11 @@ describe Api::V1::Admin::EmailDomainBlocksController do
let(:params) { { since_id: email_domain_blocks[1].id } }
it 'returns only the email domain blocks after since_id' do
get :index, params: params
subject
email_domain_blocks_ids = email_domain_blocks.pluck(:id).map(&:to_s)
json = body_as_json
expect(json.pluck(:id)).to match_array(email_domain_blocks_ids[2..])
expect(body_as_json.pluck(:id)).to match_array(email_domain_blocks_ids[2..])
end
end
@ -106,102 +91,78 @@ describe Api::V1::Admin::EmailDomainBlocksController do
let(:params) { { max_id: email_domain_blocks[3].id } }
it 'returns only the email domain blocks before max_id' do
get :index, params: params
subject
email_domain_blocks_ids = email_domain_blocks.pluck(:id).map(&:to_s)
json = body_as_json
expect(json.pluck(:id)).to match_array(email_domain_blocks_ids[..2])
expect(body_as_json.pluck(:id)).to match_array(email_domain_blocks_ids[..2])
end
end
end
end
describe 'GET #show' do
describe 'GET /api/v1/admin/email_domain_blocks/:id' do
subject do
get "/api/v1/admin/email_domain_blocks/#{email_domain_block.id}", headers: headers
end
let!(:email_domain_block) { Fabricate(:email_domain_block) }
let(:params) { { id: email_domain_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
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 email domain block exists' do
it 'returns http success' do
get :show, params: params
subject
expect(response).to have_http_status(200)
end
it 'returns the correct blocked domain' do
get :show, params: params
subject
json = body_as_json
expect(json[:domain]).to eq(email_domain_block.domain)
expect(body_as_json[:domain]).to eq(email_domain_block.domain)
end
end
context 'when email domain block does not exist' do
it 'returns http not found' do
get :show, params: { id: 0 }
get '/api/v1/admin/email_domain_blocks/-1', headers: headers
expect(response).to have_http_status(404)
end
end
end
describe 'POST #create' do
describe 'POST /api/v1/admin/email_domain_blocks' do
subject do
post '/api/v1/admin/email_domain_blocks', headers: headers, params: params
end
let(:params) { { domain: 'example.com' } }
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_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
post :create, params: params
subject
expect(response).to have_http_status(200)
end
it 'returns the correct blocked email domain' do
post :create, params: params
subject
json = body_as_json
expect(json[:domain]).to eq(params[:domain])
expect(body_as_json[:domain]).to eq(params[:domain])
end
context 'when domain param is not provided' do
let(:params) { { domain: '' } }
it 'returns http unprocessable entity' do
post :create, params: params
subject
expect(response).to have_http_status(422)
end
@ -211,7 +172,7 @@ describe Api::V1::Admin::EmailDomainBlocksController do
let(:params) { { domain: 'do\uD800.com' } }
it 'returns http unprocessable entity' do
post :create, params: params
subject
expect(response).to have_http_status(422)
end
@ -223,59 +184,45 @@ describe Api::V1::Admin::EmailDomainBlocksController do
end
it 'returns http unprocessable entity' do
post :create, params: params
subject
expect(response).to have_http_status(422)
end
end
end
describe 'DELETE #destroy' do
describe 'DELETE /api/v1/admin/email_domain_blocks' do
subject do
delete "/api/v1/admin/email_domain_blocks/#{email_domain_block.id}", headers: headers
end
let!(:email_domain_block) { Fabricate(:email_domain_block) }
let(:params) { { id: email_domain_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_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
delete :destroy, params: params
subject
expect(response).to have_http_status(200)
end
it 'returns an empty body' do
delete :destroy, params: params
subject
json = body_as_json
expect(json).to be_empty
expect(body_as_json).to be_empty
end
it 'deletes email domain block' do
delete :destroy, params: params
subject
email_domain_block = EmailDomainBlock.find_by(id: params[:id])
expect(email_domain_block).to be_nil
expect(EmailDomainBlock.find_by(id: email_domain_block.id)).to be_nil
end
context 'when email domain block does not exist' do
it 'returns http not found' do
delete :destroy, params: { id: 0 }
delete '/api/v1/admin/email_domain_blocks/-1', headers: headers
expect(response).to have_http_status(404)
end

Some files were not shown because too many files have changed in this diff Show more