mirror of
https://github.com/mastodon/mastodon.git
synced 2025-07-13 15:58:13 +00:00
Compare commits
3 Commits
5327c8b10f
...
6fa52e3517
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6fa52e3517 | ||
![]() |
91a8d29110 | ||
![]() |
54659824f0 |
|
@ -9,6 +9,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
before_action :set_statuses, only: [:index]
|
||||
before_action :set_status, only: [:show, :context]
|
||||
before_action :set_thread, only: [:create]
|
||||
before_action :set_quoted_status, only: [:create]
|
||||
before_action :check_statuses_limit, only: [:index]
|
||||
|
||||
override_rate_limit_headers :create, family: :statuses
|
||||
|
@ -67,6 +68,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
current_user.account,
|
||||
text: status_params[:status],
|
||||
thread: @thread,
|
||||
quoted_status: @quoted_status,
|
||||
media_ids: status_params[:media_ids],
|
||||
sensitive: status_params[:sensitive],
|
||||
spoiler_text: status_params[:spoiler_text],
|
||||
|
@ -138,6 +140,15 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
||||
end
|
||||
|
||||
def set_quoted_status
|
||||
@quoted_status = Status.find(status_params[:quoted_status_id]) if status_params[:quoted_status_id].present?
|
||||
authorize(@quoted_status, :quote?) if @quoted_status.present?
|
||||
# TODO: handle non-local quote posts when we implement sending `QuoteRequest`
|
||||
@quoted_status = nil unless @quoted_status.local?
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
render json: { error: I18n.t('statuses.errors.quoted_status_not_found') }, status: 404
|
||||
end
|
||||
|
||||
def check_statuses_limit
|
||||
raise(Mastodon::ValidationError) if status_ids.size > DEFAULT_STATUSES_LIMIT
|
||||
end
|
||||
|
@ -154,6 +165,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
params.permit(
|
||||
:status,
|
||||
:in_reply_to_id,
|
||||
:quoted_status_id,
|
||||
:sensitive,
|
||||
:spoiler_text,
|
||||
:visibility,
|
||||
|
|
|
@ -19,6 +19,11 @@ class StatusPolicy < ApplicationPolicy
|
|||
end
|
||||
end
|
||||
|
||||
# This is about requesting a quote post, not validating it
|
||||
def quote?
|
||||
owned? || active_mention_exists? || quote_approved_by_policy?
|
||||
end
|
||||
|
||||
def reblog?
|
||||
!requires_mention? && (!private? || owned?) && show? && !blocking_author?
|
||||
end
|
||||
|
@ -39,6 +44,14 @@ class StatusPolicy < ApplicationPolicy
|
|||
|
||||
private
|
||||
|
||||
def quote_approved_by_policy?
|
||||
flattened_policy = record.quote_approval_policy | (record.quote_approval_policy >> 16)
|
||||
return true if flattened_policy & (Status::QUOTE_APPROVAL_POLICY_FLAGS[:unknown] | Status::QUOTE_APPROVAL_POLICY_FLAGS[:public]) != 0
|
||||
|
||||
# TODO: support `:followed`
|
||||
(flattened_policy & Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers] != 0) && following_author?
|
||||
end
|
||||
|
||||
def requires_mention?
|
||||
record.direct_visibility? || record.limited_visibility?
|
||||
end
|
||||
|
@ -61,6 +74,16 @@ class StatusPolicy < ApplicationPolicy
|
|||
end
|
||||
end
|
||||
|
||||
def active_mention_exists?
|
||||
return false if current_account.nil?
|
||||
|
||||
if record.active_mentions.loaded?
|
||||
record.active_mentions.any? { |mention| mention.account_id == current_account.id }
|
||||
else
|
||||
record.active_mentions.exists?(account: current_account)
|
||||
end
|
||||
end
|
||||
|
||||
def author_blocking_domain?
|
||||
return false if current_account.nil? || current_account.domain.nil?
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ class PostStatusService < BaseService
|
|||
# we only support incoming quotes so far
|
||||
|
||||
status.quote = Quote.new(quoted_status: @quoted_status)
|
||||
status.quote.accept! if @status.account == @quoted_status.account || @quoted_status.active_mentions.exists?(mentions: { account_id: status.account_id })
|
||||
status.quote.accept! if StatusPolicy.new(@status.account, @quoted_status).quote? && @quoted_status.local?
|
||||
|
||||
# TODO: the following has yet to be implemented:
|
||||
# - handle approval of local users (requires the interactionPolicy PR)
|
||||
|
|
|
@ -86,6 +86,92 @@ RSpec.describe StatusPolicy, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with the permission of quote?' do
|
||||
permissions :quote? do
|
||||
it 'grants access when direct and account is viewer' do
|
||||
status.visibility = :direct
|
||||
|
||||
expect(subject).to permit(status.account, status)
|
||||
end
|
||||
|
||||
it 'grants access when direct and viewer is mentioned' do
|
||||
status.visibility = :direct
|
||||
status.mentions = [Fabricate(:mention, account: alice)]
|
||||
|
||||
expect(subject).to permit(alice, status)
|
||||
end
|
||||
|
||||
it 'grants access when direct and non-owner viewer is mentioned and mentions are loaded' do
|
||||
status.visibility = :direct
|
||||
status.mentions = [Fabricate(:mention, account: bob)]
|
||||
status.active_mentions.load
|
||||
|
||||
expect(subject).to permit(bob, status)
|
||||
end
|
||||
|
||||
it 'denies access when direct and viewer is not mentioned' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :direct
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'denies access when private and viewer is not mentioned' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :private
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'grants access when private and viewer is mentioned' do
|
||||
status.visibility = :private
|
||||
status.mentions = [Fabricate(:mention, account: bob)]
|
||||
|
||||
expect(subject).to permit(bob, status)
|
||||
end
|
||||
|
||||
it 'denies access when private and non-viewer is mentioned' do
|
||||
viewer = Fabricate(:account)
|
||||
status.visibility = :private
|
||||
status.mentions = [Fabricate(:mention, account: bob)]
|
||||
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'denies access when private and account is following viewer' do
|
||||
follow = Fabricate(:follow)
|
||||
status.visibility = :private
|
||||
status.account = follow.target_account
|
||||
|
||||
expect(subject).to_not permit(follow.account, status)
|
||||
end
|
||||
|
||||
it 'denies access when public but policy does not allow anyone' do
|
||||
viewer = Fabricate(:account)
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'grants access when public and policy allows everyone' do
|
||||
status.quote_approval_policy = Status::QUOTE_APPROVAL_POLICY_FLAGS[:public]
|
||||
viewer = Fabricate(:account)
|
||||
expect(subject).to permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'denies access when public and policy allows followers but viewer is not one' do
|
||||
status.quote_approval_policy = Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers]
|
||||
viewer = Fabricate(:account)
|
||||
expect(subject).to_not permit(viewer, status)
|
||||
end
|
||||
|
||||
it 'grants access when public and policy allows followers and viewer is one' do
|
||||
status.quote_approval_policy = Status::QUOTE_APPROVAL_POLICY_FLAGS[:followers]
|
||||
viewer = Fabricate(:account)
|
||||
viewer.follow!(status.account)
|
||||
expect(subject).to permit(viewer, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the permission of reblog?' do
|
||||
permissions :reblog? do
|
||||
it 'denies access when private' do
|
||||
|
|
Loading…
Reference in New Issue
Block a user