mirror of
https://github.com/mastodon/mastodon.git
synced 2025-07-14 00:08:14 +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_statuses, only: [:index]
|
||||||
before_action :set_status, only: [:show, :context]
|
before_action :set_status, only: [:show, :context]
|
||||||
before_action :set_thread, only: [:create]
|
before_action :set_thread, only: [:create]
|
||||||
|
before_action :set_quoted_status, only: [:create]
|
||||||
before_action :check_statuses_limit, only: [:index]
|
before_action :check_statuses_limit, only: [:index]
|
||||||
|
|
||||||
override_rate_limit_headers :create, family: :statuses
|
override_rate_limit_headers :create, family: :statuses
|
||||||
|
@ -67,6 +68,7 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
current_user.account,
|
current_user.account,
|
||||||
text: status_params[:status],
|
text: status_params[:status],
|
||||||
thread: @thread,
|
thread: @thread,
|
||||||
|
quoted_status: @quoted_status,
|
||||||
media_ids: status_params[:media_ids],
|
media_ids: status_params[:media_ids],
|
||||||
sensitive: status_params[:sensitive],
|
sensitive: status_params[:sensitive],
|
||||||
spoiler_text: status_params[:spoiler_text],
|
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
|
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
||||||
end
|
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
|
def check_statuses_limit
|
||||||
raise(Mastodon::ValidationError) if status_ids.size > DEFAULT_STATUSES_LIMIT
|
raise(Mastodon::ValidationError) if status_ids.size > DEFAULT_STATUSES_LIMIT
|
||||||
end
|
end
|
||||||
|
@ -154,6 +165,7 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
params.permit(
|
params.permit(
|
||||||
:status,
|
:status,
|
||||||
:in_reply_to_id,
|
:in_reply_to_id,
|
||||||
|
:quoted_status_id,
|
||||||
:sensitive,
|
:sensitive,
|
||||||
:spoiler_text,
|
:spoiler_text,
|
||||||
:visibility,
|
:visibility,
|
||||||
|
|
|
@ -19,6 +19,11 @@ class StatusPolicy < ApplicationPolicy
|
||||||
end
|
end
|
||||||
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?
|
def reblog?
|
||||||
!requires_mention? && (!private? || owned?) && show? && !blocking_author?
|
!requires_mention? && (!private? || owned?) && show? && !blocking_author?
|
||||||
end
|
end
|
||||||
|
@ -39,6 +44,14 @@ class StatusPolicy < ApplicationPolicy
|
||||||
|
|
||||||
private
|
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?
|
def requires_mention?
|
||||||
record.direct_visibility? || record.limited_visibility?
|
record.direct_visibility? || record.limited_visibility?
|
||||||
end
|
end
|
||||||
|
@ -61,6 +74,16 @@ class StatusPolicy < ApplicationPolicy
|
||||||
end
|
end
|
||||||
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?
|
def author_blocking_domain?
|
||||||
return false if current_account.nil? || current_account.domain.nil?
|
return false if current_account.nil? || current_account.domain.nil?
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ class PostStatusService < BaseService
|
||||||
# we only support incoming quotes so far
|
# we only support incoming quotes so far
|
||||||
|
|
||||||
status.quote = Quote.new(quoted_status: @quoted_status)
|
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:
|
# TODO: the following has yet to be implemented:
|
||||||
# - handle approval of local users (requires the interactionPolicy PR)
|
# - handle approval of local users (requires the interactionPolicy PR)
|
||||||
|
|
|
@ -86,6 +86,92 @@ RSpec.describe StatusPolicy, type: :model do
|
||||||
end
|
end
|
||||||
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
|
context 'with the permission of reblog?' do
|
||||||
permissions :reblog? do
|
permissions :reblog? do
|
||||||
it 'denies access when private' do
|
it 'denies access when private' do
|
||||||
|
|
Loading…
Reference in New Issue
Block a user