commit
ed6c60a0c2
@ -0,0 +1,69 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class StatusesController < BaseController
|
||||||
|
include Authorization
|
||||||
|
|
||||||
|
helper_method :current_params
|
||||||
|
|
||||||
|
before_action :set_account
|
||||||
|
before_action :set_status, only: [:update, :destroy]
|
||||||
|
|
||||||
|
PAR_PAGE = 20
|
||||||
|
|
||||||
|
def index
|
||||||
|
@statuses = @account.statuses
|
||||||
|
if params[:media]
|
||||||
|
account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
|
||||||
|
@statuses.merge!(Status.where(id: account_media_status_ids))
|
||||||
|
end
|
||||||
|
@statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PAR_PAGE)
|
||||||
|
|
||||||
|
@form = Form::StatusBatch.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@form = Form::StatusBatch.new(form_status_batch_params)
|
||||||
|
flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save
|
||||||
|
|
||||||
|
redirect_to admin_account_statuses_path(@account.id, current_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@status.update(status_params)
|
||||||
|
redirect_to admin_account_statuses_path(@account.id, current_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize @status, :destroy?
|
||||||
|
RemovalWorker.perform_async(@status.id)
|
||||||
|
render json: @status
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def status_params
|
||||||
|
params.require(:status).permit(:sensitive)
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_status_batch_params
|
||||||
|
params.require(:form_status_batch).permit(:action, status_ids: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_status
|
||||||
|
@status = @account.statuses.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = Account.find(params[:account_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_params
|
||||||
|
page = (params[:page] || 1).to_i
|
||||||
|
{
|
||||||
|
media: params[:media],
|
||||||
|
page: page > 1 && page,
|
||||||
|
}.select { |_, value| value.present? }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1 +1,10 @@
|
|||||||
import './web_push_notifications';
|
import './web_push_notifications';
|
||||||
|
|
||||||
|
// Cause a new version of a registered Service Worker to replace an existing one
|
||||||
|
// that is already installed, and replace the currently active worker on open pages.
|
||||||
|
self.addEventListener('install', function(event) {
|
||||||
|
event.waitUntil(self.skipWaiting());
|
||||||
|
});
|
||||||
|
self.addEventListener('activate', function(event) {
|
||||||
|
event.waitUntil(self.clients.claim());
|
||||||
|
});
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import { delegate } from 'rails-ujs';
|
||||||
|
|
||||||
|
function handleDeleteStatus(event) {
|
||||||
|
const [data] = event.detail;
|
||||||
|
const element = document.querySelector(`[data-id="${data.id}"]`);
|
||||||
|
if (element) {
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[].forEach.call(document.querySelectorAll('.trash-button'), (content) => {
|
||||||
|
content.addEventListener('ajax:success', handleDeleteStatus);
|
||||||
|
});
|
||||||
|
|
||||||
|
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
||||||
|
|
||||||
|
delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
|
||||||
|
[].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
|
||||||
|
content.checked = target.checked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate(document, batchCheckboxClassName, 'change', () => {
|
||||||
|
const checkAllElement = document.querySelector('#batch_checkbox_all');
|
||||||
|
if (checkAllElement) {
|
||||||
|
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate(document, '.media-spoiler-show-button', 'click', () => {
|
||||||
|
[].forEach.call(document.querySelectorAll('.activity-stream .media-spoiler-wrapper'), (content) => {
|
||||||
|
content.classList.add('media-spoiler-wrapper__visible');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate(document, '.media-spoiler-hide-button', 'click', () => {
|
||||||
|
[].forEach.call(document.querySelectorAll('.activity-stream .media-spoiler-wrapper'), (content) => {
|
||||||
|
content.classList.remove('media-spoiler-wrapper__visible');
|
||||||
|
});
|
||||||
|
});
|
@ -1,6 +1,7 @@
|
|||||||
import main from '../mastodon/main';
|
|
||||||
import loadPolyfills from '../mastodon/load_polyfills';
|
import loadPolyfills from '../mastodon/load_polyfills';
|
||||||
|
|
||||||
loadPolyfills().then(main).catch(e => {
|
loadPolyfills().then(() => {
|
||||||
|
require('../mastodon/main').default();
|
||||||
|
}).catch(e => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::Base
|
||||||
|
def initialize(xml, account = nil)
|
||||||
|
@xml = xml
|
||||||
|
@account = account
|
||||||
|
end
|
||||||
|
|
||||||
|
def status?
|
||||||
|
[:activity, :note, :comment].include?(type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verb
|
||||||
|
raw = @xml.at_xpath('./activity:verb', activity: TagManager::AS_XMLNS).content
|
||||||
|
TagManager::VERBS.key(raw)
|
||||||
|
rescue
|
||||||
|
:post
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
raw = @xml.at_xpath('./activity:object-type', activity: TagManager::AS_XMLNS).content
|
||||||
|
TagManager::TYPES.key(raw)
|
||||||
|
rescue
|
||||||
|
:activity
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
@xml.at_xpath('./xmlns:id', xmlns: TagManager::XMLNS).content
|
||||||
|
end
|
||||||
|
|
||||||
|
def url
|
||||||
|
link = @xml.at_xpath('./xmlns:link[@rel="alternate"]', xmlns: TagManager::XMLNS)
|
||||||
|
link.nil? ? nil : link['href']
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_status(uri)
|
||||||
|
if TagManager.instance.local_id?(uri)
|
||||||
|
local_id = TagManager.instance.unique_tag_to_local_id(uri, 'Status')
|
||||||
|
return Status.find_by(id: local_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
Status.find_by(uri: uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
def redis
|
||||||
|
Redis.current
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,149 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::Creation < Ostatus::Activity::Base
|
||||||
|
def perform
|
||||||
|
if redis.exists("delete_upon_arrival:#{@account.id}:#{id}")
|
||||||
|
Rails.logger.debug "Delete for status #{id} was queued, ignoring"
|
||||||
|
return [nil, false]
|
||||||
|
end
|
||||||
|
|
||||||
|
return [nil, false] if @account.suspended?
|
||||||
|
|
||||||
|
Rails.logger.debug "Creating remote status #{id}"
|
||||||
|
|
||||||
|
# Return early if status already exists in db
|
||||||
|
status = find_status(id)
|
||||||
|
|
||||||
|
return [status, false] unless status.nil?
|
||||||
|
|
||||||
|
status = Status.create!(
|
||||||
|
uri: id,
|
||||||
|
url: url,
|
||||||
|
account: @account,
|
||||||
|
reblog: reblog,
|
||||||
|
text: content,
|
||||||
|
spoiler_text: content_warning,
|
||||||
|
created_at: published,
|
||||||
|
reply: thread?,
|
||||||
|
language: content_language,
|
||||||
|
visibility: visibility_scope,
|
||||||
|
conversation: find_or_create_conversation,
|
||||||
|
thread: thread? ? find_status(thread.first) : nil
|
||||||
|
)
|
||||||
|
|
||||||
|
save_mentions(status)
|
||||||
|
save_hashtags(status)
|
||||||
|
save_media(status)
|
||||||
|
|
||||||
|
if thread? && status.thread.nil?
|
||||||
|
Rails.logger.debug "Trying to attach #{status.id} (#{id}) to #{thread.first}"
|
||||||
|
ThreadResolveWorker.perform_async(status.id, thread.second)
|
||||||
|
end
|
||||||
|
|
||||||
|
Rails.logger.debug "Queuing remote status #{status.id} (#{id}) for distribution"
|
||||||
|
|
||||||
|
LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
|
||||||
|
DistributionWorker.perform_async(status.id)
|
||||||
|
|
||||||
|
[status, true]
|
||||||
|
end
|
||||||
|
|
||||||
|
def content
|
||||||
|
@xml.at_xpath('./xmlns:content', xmlns: TagManager::XMLNS).content
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_language
|
||||||
|
@xml.at_xpath('./xmlns:content', xmlns: TagManager::XMLNS)['xml:lang']&.presence || 'en'
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_warning
|
||||||
|
@xml.at_xpath('./xmlns:summary', xmlns: TagManager::XMLNS)&.content || ''
|
||||||
|
end
|
||||||
|
|
||||||
|
def visibility_scope
|
||||||
|
@xml.at_xpath('./mastodon:scope', mastodon: TagManager::MTDN_XMLNS)&.content&.to_sym || :public
|
||||||
|
end
|
||||||
|
|
||||||
|
def published
|
||||||
|
@xml.at_xpath('./xmlns:published', xmlns: TagManager::XMLNS).content
|
||||||
|
end
|
||||||
|
|
||||||
|
def thread?
|
||||||
|
!@xml.at_xpath('./thr:in-reply-to', thr: TagManager::THR_XMLNS).nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def thread
|
||||||
|
thr = @xml.at_xpath('./thr:in-reply-to', thr: TagManager::THR_XMLNS)
|
||||||
|
[thr['ref'], thr['href']]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_or_create_conversation
|
||||||
|
uri = @xml.at_xpath('./ostatus:conversation', ostatus: TagManager::OS_XMLNS)&.attribute('ref')&.content
|
||||||
|
return if uri.nil?
|
||||||
|
|
||||||
|
if TagManager.instance.local_id?(uri)
|
||||||
|
local_id = TagManager.instance.unique_tag_to_local_id(uri, 'Conversation')
|
||||||
|
return Conversation.find_by(id: local_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
Conversation.find_by(uri: uri) || Conversation.create!(uri: uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_mentions(parent)
|
||||||
|
processed_account_ids = []
|
||||||
|
|
||||||
|
@xml.xpath('./xmlns:link[@rel="mentioned"]', xmlns: TagManager::XMLNS).each do |link|
|
||||||
|
next if [TagManager::TYPES[:group], TagManager::TYPES[:collection]].include? link['ostatus:object-type']
|
||||||
|
|
||||||
|
mentioned_account = account_from_href(link['href'])
|
||||||
|
|
||||||
|
next if mentioned_account.nil? || processed_account_ids.include?(mentioned_account.id)
|
||||||
|
|
||||||
|
mentioned_account.mentions.where(status: parent).first_or_create(status: parent)
|
||||||
|
|
||||||
|
# So we can skip duplicate mentions
|
||||||
|
processed_account_ids << mentioned_account.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_hashtags(parent)
|
||||||
|
tags = @xml.xpath('./xmlns:category', xmlns: TagManager::XMLNS).map { |category| category['term'] }.select(&:present?)
|
||||||
|
ProcessHashtagsService.new.call(parent, tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_media(parent)
|
||||||
|
do_not_download = DomainBlock.find_by(domain: parent.account.domain)&.reject_media?
|
||||||
|
|
||||||
|
@xml.xpath('./xmlns:link[@rel="enclosure"]', xmlns: TagManager::XMLNS).each do |link|
|
||||||
|
next unless link['href']
|
||||||
|
|
||||||
|
media = MediaAttachment.where(status: parent, remote_url: link['href']).first_or_initialize(account: parent.account, status: parent, remote_url: link['href'])
|
||||||
|
parsed_url = Addressable::URI.parse(link['href']).normalize
|
||||||
|
|
||||||
|
next if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.empty?
|
||||||
|
|
||||||
|
media.save
|
||||||
|
|
||||||
|
next if do_not_download
|
||||||
|
|
||||||
|
begin
|
||||||
|
media.file_remote_url = link['href']
|
||||||
|
media.save!
|
||||||
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_from_href(href)
|
||||||
|
url = Addressable::URI.parse(href).normalize
|
||||||
|
|
||||||
|
if TagManager.instance.web_domain?(url.host)
|
||||||
|
Account.find_local(url.path.gsub('/users/', ''))
|
||||||
|
else
|
||||||
|
Account.where(uri: href).or(Account.where(url: href)).first || FetchRemoteAccountService.new.call(href)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::Deletion < Ostatus::Activity::Base
|
||||||
|
def perform
|
||||||
|
Rails.logger.debug "Deleting remote status #{id}"
|
||||||
|
status = Status.find_by(uri: id, account: @account)
|
||||||
|
|
||||||
|
if status.nil?
|
||||||
|
redis.setex("delete_upon_arrival:#{@account.id}:#{id}", 6 * 3_600, id)
|
||||||
|
else
|
||||||
|
RemoveStatusService.new.call(status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::General < Ostatus::Activity::Base
|
||||||
|
def specialize
|
||||||
|
special_class&.new(@xml, @account)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def special_class
|
||||||
|
case verb
|
||||||
|
when :post
|
||||||
|
Ostatus::Activity::Post
|
||||||
|
when :share
|
||||||
|
Ostatus::Activity::Share
|
||||||
|
when :delete
|
||||||
|
Ostatus::Activity::Deletion
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::Post < Ostatus::Activity::Creation
|
||||||
|
def perform
|
||||||
|
status, just_created = super
|
||||||
|
|
||||||
|
if just_created
|
||||||
|
status.mentions.includes(:account).each do |mention|
|
||||||
|
mentioned_account = mention.account
|
||||||
|
next unless mentioned_account.local?
|
||||||
|
NotifyService.new.call(mentioned_account, mention)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
status
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def reblog
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::Remote < Ostatus::Activity::Base
|
||||||
|
def perform
|
||||||
|
find_status(id) || FetchRemoteStatusService.new.call(url)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Ostatus::Activity::Share < Ostatus::Activity::Creation
|
||||||
|
def perform
|
||||||
|
return if reblog.nil?
|
||||||
|
|
||||||
|
status, just_created = super
|
||||||
|
NotifyService.new.call(reblog.account, status) if reblog.account.local? && just_created
|
||||||
|
status
|
||||||
|
end
|
||||||
|
|
||||||
|
def object
|
||||||
|
@xml.at_xpath('.//activity:object', activity: TagManager::AS_XMLNS)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def reblog
|
||||||
|
return @reblog if defined? @reblog
|
||||||
|
|
||||||
|
original_status = Ostatus::Activity::Remote.new(object).perform
|
||||||
|
return if original_status.nil?
|
||||||
|
|
||||||
|
@reblog = original_status.reblog? ? original_status.reblog : original_status
|
||||||
|
end
|
||||||
|
end
|
@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AtomSerializer
|
class Ostatus::AtomSerializer
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
include ActionView::Helpers::SanitizeHelper
|
include ActionView::Helpers::SanitizeHelper
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Form::StatusBatch
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_accessor :status_ids, :action
|
||||||
|
|
||||||
|
ACTION_TYPE = %w(nsfw_on nsfw_off delete).freeze
|
||||||
|
|
||||||
|
def save
|
||||||
|
case action
|
||||||
|
when 'nsfw_on', 'nsfw_off'
|
||||||
|
change_sensitive(action == 'nsfw_on')
|
||||||
|
when 'delete'
|
||||||
|
delete_statuses
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def change_sensitive(sensitive)
|
||||||
|
media_attached_status_ids = MediaAttachment.where(status_id: status_ids).pluck(:status_id)
|
||||||
|
ApplicationRecord.transaction do
|
||||||
|
Status.where(id: media_attached_status_ids).find_each do |status|
|
||||||
|
status.update!(sensitive: sensitive)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
true
|
||||||
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_statuses
|
||||||
|
Status.where(id: status_ids).find_each do |status|
|
||||||
|
RemovalWorker.perform_async(status.id)
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,47 @@
|
|||||||
|
- content_for :header_tags do
|
||||||
|
= javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'
|
||||||
|
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('admin.statuses.title')
|
||||||
|
|
||||||
|
.back-link
|
||||||
|
= link_to admin_account_path(@account.id) do
|
||||||
|
%i.fa.fa-chevron-left.fa-fw
|
||||||
|
= t('admin.statuses.back_to_account')
|
||||||
|
|
||||||
|
.filters
|
||||||
|
.filter-subset
|
||||||
|
%strong= t('admin.statuses.media.title')
|
||||||
|
%ul
|
||||||
|
%li= link_to t('admin.statuses.no_media'), admin_account_statuses_path(@account.id, current_params.merge(media: nil)), class: !params[:media] && 'selected'
|
||||||
|
%li= link_to t('admin.statuses.with_media'), admin_account_statuses_path(@account.id, current_params.merge(media: true)), class: params[:media] && 'selected'
|
||||||
|
|
||||||
|
- if @statuses.empty?
|
||||||
|
.accounts-grid
|
||||||
|
= render 'accounts/nothing_here'
|
||||||
|
- else
|
||||||
|
= form_for(@form, url: admin_account_statuses_path(@account.id)) do |f|
|
||||||
|
= hidden_field_tag :page, params[:page]
|
||||||
|
= hidden_field_tag :media, params[:media]
|
||||||
|
.batch-form-box
|
||||||
|
.batch-checkbox-all
|
||||||
|
= check_box_tag :batch_checkbox_all, nil, false
|
||||||
|
= f.select :action, Form::StatusBatch::ACTION_TYPE.map{|action| [t("admin.statuses.batch.#{action}"), action]}
|
||||||
|
= f.submit t('admin.statuses.execute'), data: { confirm: t('admin.reports.are_you_sure') }, class: 'button'
|
||||||
|
.media-spoiler-toggle-buttons
|
||||||
|
.media-spoiler-show-button.button= t('admin.statuses.media.show')
|
||||||
|
.media-spoiler-hide-button.button= t('admin.statuses.media.hide')
|
||||||
|
- @statuses.each do |status|
|
||||||
|
.account-status{ data: { id: status.id } }
|
||||||
|
.batch-checkbox
|
||||||
|
= f.check_box :status_ids, { multiple: true, include_hidden: false }, status.id
|
||||||
|
.activity-stream.activity-stream-headless
|
||||||
|
.entry= render 'stream_entries/simple_status', status: status
|
||||||
|
.account-status__actions
|
||||||
|
- unless status.media_attachments.empty?
|
||||||
|
= link_to admin_account_status_path(@account.id, status, current_params.merge(status: { sensitive: !status.sensitive })), method: :patch, class: 'icon-button nsfw-button', title: t("admin.reports.nsfw.#{!status.sensitive}") do
|
||||||
|
= fa_icon status.sensitive? ? 'eye' : 'eye-slash'
|
||||||
|
= link_to admin_account_status_path(@account.id, status), method: :delete, class: 'icon-button trash-button', title: t('admin.reports.delete'), data: { confirm: t('admin.reports.are_you_sure') }, remote: true do
|
||||||
|
= fa_icon 'trash'
|
||||||
|
|
||||||
|
= paginate @statuses
|
@ -0,0 +1,107 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Admin::StatusesController do
|
||||||
|
render_views
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user, admin: true) }
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
let!(:status) { Fabricate(:status, account: account) }
|
||||||
|
let(:media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }
|
||||||
|
let!(:media_attachment) { Fabricate(:media_attachment, account: account, status: media_attached_status) }
|
||||||
|
let(:sensitive) { true }
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in user, scope: :user
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET #index' do
|
||||||
|
it 'returns http success with no media' do
|
||||||
|
get :index, params: { account_id: account.id }
|
||||||
|
|
||||||
|
statuses = assigns(:statuses).to_a
|
||||||
|
expect(statuses.size).to eq 2
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http success with media' do
|
||||||
|
get :index, params: { account_id: account.id , media: true }
|
||||||
|
|
||||||
|
statuses = assigns(:statuses).to_a
|
||||||
|
expect(statuses.size).to eq 1
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST #create' do
|
||||||
|
subject do
|
||||||
|
-> { post :create, params: { account_id: account.id, form_status_batch: { action: action, status_ids: status_ids } } }
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:action) { 'nsfw_on' }
|
||||||
|
let(:status_ids) { [media_attached_status.id] }
|
||||||
|
|
||||||
|
context 'updates sensitive column to true' do
|
||||||
|
it 'updates sensitive column' do
|
||||||
|
is_expected.to change {
|
||||||
|
media_attached_status.reload.sensitive
|
||||||
|
}.from(false).to(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'updates sensitive column to false' do
|
||||||
|
let(:action) { 'nsfw_off' }
|
||||||
|
let(:sensitive) { false }
|
||||||
|
|
||||||
|
it 'updates sensitive column' do
|
||||||
|
is_expected.to change {
|
||||||
|
media_attached_status.reload.sensitive
|
||||||
|
}.from(true).to(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to account statuses page' do
|
||||||
|
subject.call
|
||||||
|
expect(response).to redirect_to(admin_account_statuses_path(account.id))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'PATCH #update' do
|
||||||
|
subject do
|
||||||
|
-> { patch :update, params: { account_id: account.id, id: media_attached_status, status: { sensitive: sensitive } } }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'updates sensitive column to true' do
|
||||||
|
it 'updates sensitive column' do
|
||||||
|
is_expected.to change {
|
||||||
|
media_attached_status.reload.sensitive
|
||||||
|
}.from(false).to(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'updates sensitive column to false' do
|
||||||
|
let(:sensitive) { false }
|
||||||
|
|
||||||
|
it 'updates sensitive column' do
|
||||||
|
is_expected.to change {
|
||||||
|
media_attached_status.reload.sensitive
|
||||||
|
}.from(true).to(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to account statuses page' do
|
||||||
|
subject.call
|
||||||
|
expect(response).to redirect_to(admin_account_statuses_path(account.id))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE #destroy' do
|
||||||
|
it 'removes a status' do
|
||||||
|
allow(RemovalWorker).to receive(:perform_async)
|
||||||
|
|
||||||
|
delete :destroy, params: { account_id: account.id, id: status }
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(RemovalWorker).
|
||||||
|
to have_received(:perform_async).with(status.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Form::StatusBatch do
|
||||||
|
let(:form) { Form::StatusBatch.new(action: action, status_ids: status_ids) }
|
||||||
|
let(:status) { Fabricate(:status) }
|
||||||
|
|
||||||
|
describe 'with nsfw action' do
|
||||||
|
let(:status_ids) { [status.id, nonsensitive_status.id, sensitive_status.id] }
|
||||||
|
let(:nonsensitive_status) { Fabricate(:status, sensitive: false) }
|
||||||
|
let(:sensitive_status) { Fabricate(:status, sensitive: true) }
|
||||||
|
let!(:shown_media_attachment) { Fabricate(:media_attachment, status: nonsensitive_status) }
|
||||||
|
let!(:hidden_media_attachment) { Fabricate(:media_attachment, status: sensitive_status) }
|
||||||
|
|
||||||
|
context 'nsfw_on' do
|
||||||
|
let(:action) { 'nsfw_on' }
|
||||||
|
|
||||||
|
it { expect(form.save).to be true }
|
||||||
|
it { expect { form.save }.to change { nonsensitive_status.reload.sensitive }.from(false).to(true) }
|
||||||
|
it { expect { form.save }.not_to change { sensitive_status.reload.sensitive } }
|
||||||
|
it { expect { form.save }.not_to change { status.reload.sensitive } }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'nsfw_off' do
|
||||||
|
let(:action) { 'nsfw_off' }
|
||||||
|
|
||||||
|
it { expect(form.save).to be true }
|
||||||
|
it { expect { form.save }.to change { sensitive_status.reload.sensitive }.from(true).to(false) }
|
||||||
|
it { expect { form.save }.not_to change { nonsensitive_status.reload.sensitive } }
|
||||||
|
it { expect { form.save }.not_to change { status.reload.sensitive } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with delete action' do
|
||||||
|
let(:status_ids) { [status.id] }
|
||||||
|
let(:action) { 'delete' }
|
||||||
|
let!(:another_status) { Fabricate(:status) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(RemovalWorker).to receive(:perform_async)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'call RemovalWorker' do
|
||||||
|
form.save
|
||||||
|
expect(RemovalWorker).to have_received(:perform_async).with(status.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'do not call RemovalWorker' do
|
||||||
|
form.save
|
||||||
|
expect(RemovalWorker).not_to have_received(:perform_async).with(another_status.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in new issue