commit
6af2300454
@ -0,0 +1,12 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::PreferencesController < Api::BaseController
|
||||||
|
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
||||||
|
before_action :require_user!
|
||||||
|
|
||||||
|
respond_to :json
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: current_account, serializer: REST::PreferencesSerializer
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,103 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RelationshipsController < ApplicationController
|
||||||
|
layout 'admin'
|
||||||
|
|
||||||
|
before_action :authenticate_user!
|
||||||
|
before_action :set_accounts, only: :show
|
||||||
|
before_action :set_pack
|
||||||
|
before_action :set_body_classes
|
||||||
|
|
||||||
|
helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship?
|
||||||
|
|
||||||
|
def show
|
||||||
|
@form = Form::AccountBatch.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
|
@form.save
|
||||||
|
rescue ActionController::ParameterMissing
|
||||||
|
# Do nothing
|
||||||
|
ensure
|
||||||
|
redirect_to relationships_path(current_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_accounts
|
||||||
|
@accounts = relationships_scope.page(params[:page]).per(40)
|
||||||
|
end
|
||||||
|
|
||||||
|
def relationships_scope
|
||||||
|
scope = begin
|
||||||
|
if following_relationship?
|
||||||
|
current_account.following.includes(:account_stat)
|
||||||
|
else
|
||||||
|
current_account.followers.includes(:account_stat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scope.merge!(Follow.recent)
|
||||||
|
scope.merge!(mutual_relationship_scope) if mutual_relationship?
|
||||||
|
scope.merge!(abandoned_account_scope) if params[:status] == 'abandoned'
|
||||||
|
scope.merge!(active_account_scope) if params[:status] == 'active'
|
||||||
|
scope.merge!(by_domain_scope) if params[:by_domain].present?
|
||||||
|
|
||||||
|
scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def mutual_relationship_scope
|
||||||
|
Account.where(id: current_account.following)
|
||||||
|
end
|
||||||
|
|
||||||
|
def abandoned_account_scope
|
||||||
|
Account.where.not(moved_to_account_id: nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def active_account_scope
|
||||||
|
Account.where(moved_to_account_id: nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def by_domain_scope
|
||||||
|
Account.where(domain: params[:by_domain])
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_account_batch_params
|
||||||
|
params.require(:form_account_batch).permit(:action, account_ids: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def following_relationship?
|
||||||
|
params[:relationship].blank? || params[:relationship] == 'following'
|
||||||
|
end
|
||||||
|
|
||||||
|
def mutual_relationship?
|
||||||
|
params[:relationship] == 'mutual'
|
||||||
|
end
|
||||||
|
|
||||||
|
def followed_by_relationship?
|
||||||
|
params[:relationship] == 'followed_by'
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_params
|
||||||
|
params.slice(:page, :status, :relationship, :by_domain).permit(:page, :status, :relationship, :by_domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_from_button
|
||||||
|
if params[:unfollow]
|
||||||
|
'unfollow'
|
||||||
|
elsif params[:remove_from_followers]
|
||||||
|
'remove_from_followers'
|
||||||
|
elsif params[:block_domains]
|
||||||
|
'block_domains'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_body_classes
|
||||||
|
@body_classes = 'admin'
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_pack
|
||||||
|
use_pack 'admin'
|
||||||
|
end
|
||||||
|
end
|
@ -1,24 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class Settings::FollowerDomainsController < Settings::BaseController
|
|
||||||
def show
|
|
||||||
@account = current_account
|
|
||||||
@domains = current_account.followers.reorder(Arel.sql('MIN(follows.id) DESC')).group('accounts.domain').select('accounts.domain, count(accounts.id) as accounts_from_domain').page(params[:page]).per(10)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update
|
|
||||||
domains = bulk_params[:select] || []
|
|
||||||
|
|
||||||
AfterAccountDomainBlockWorker.push_bulk(domains) do |domain|
|
|
||||||
[current_account.id, domain]
|
|
||||||
end
|
|
||||||
|
|
||||||
redirect_to settings_follower_domains_path, notice: I18n.t('followers.success', count: domains.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def bulk_params
|
|
||||||
params.permit(select: [])
|
|
||||||
end
|
|
||||||
end
|
|
@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import illustration from '../../images/elephant_ui_disappointed.svg';
|
||||||
|
|
||||||
|
export default class ErrorBoundary extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
hasError: false,
|
||||||
|
stackTrace: undefined,
|
||||||
|
componentStack: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(error, info) {
|
||||||
|
this.setState({
|
||||||
|
hasError: true,
|
||||||
|
stackTrace: error.stack,
|
||||||
|
componentStack: info && info.componentStack,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { hasError } = this.state;
|
||||||
|
|
||||||
|
if (!hasError) {
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<img src={illustration} alt='' />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Form::AccountBatch
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_accessor :account_ids, :action, :current_account
|
||||||
|
|
||||||
|
def save
|
||||||
|
case action
|
||||||
|
when 'unfollow'
|
||||||
|
unfollow!
|
||||||
|
when 'remove_from_followers'
|
||||||
|
remove_from_followers!
|
||||||
|
when 'block_domains'
|
||||||
|
block_domains!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def unfollow!
|
||||||
|
accounts.find_each do |target_account|
|
||||||
|
UnfollowService.new.call(current_account, target_account)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_from_followers!
|
||||||
|
current_account.passive_relationships.where(account_id: account_ids).find_each do |follow|
|
||||||
|
reject_follow!(follow)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def block_domains!
|
||||||
|
AfterAccountDomainBlockWorker.push_bulk(account_domains) do |domain|
|
||||||
|
[current_account.id, domain]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_domains
|
||||||
|
accounts.pluck(Arel.sql('distinct domain')).compact
|
||||||
|
end
|
||||||
|
|
||||||
|
def accounts
|
||||||
|
Account.where(id: account_ids)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reject_follow!(follow)
|
||||||
|
follow.destroy
|
||||||
|
|
||||||
|
return unless follow.account.activitypub?
|
||||||
|
|
||||||
|
json = ActiveModelSerializers::SerializableResource.new(
|
||||||
|
follow,
|
||||||
|
serializer: ActivityPub::RejectFollowSerializer,
|
||||||
|
adapter: ActivityPub::Adapter
|
||||||
|
).to_json
|
||||||
|
|
||||||
|
ActivityPub::DeliveryWorker.perform_async(json, current_account.id, follow.account.inbox_url)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,30 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class REST::PreferencesSerializer < ActiveModel::Serializer
|
||||||
|
attribute :posting_default_privacy, key: 'posting:default:visibility'
|
||||||
|
attribute :posting_default_sensitive, key: 'posting:default:sensitive'
|
||||||
|
attribute :posting_default_language, key: 'posting:default:language'
|
||||||
|
|
||||||
|
attribute :reading_default_sensitive_media, key: 'reading:expand:media'
|
||||||
|
attribute :reading_default_sensitive_text, key: 'reading:expand:spoilers'
|
||||||
|
|
||||||
|
def posting_default_privacy
|
||||||
|
object.user.setting_default_privacy
|
||||||
|
end
|
||||||
|
|
||||||
|
def posting_default_sensitive
|
||||||
|
object.user.setting_default_sensitive
|
||||||
|
end
|
||||||
|
|
||||||
|
def posting_default_language
|
||||||
|
object.user.setting_default_language.presence
|
||||||
|
end
|
||||||
|
|
||||||
|
def reading_default_sensitive_media
|
||||||
|
object.user.setting_display_media
|
||||||
|
end
|
||||||
|
|
||||||
|
def reading_default_sensitive_text
|
||||||
|
object.user.setting_expand_spoilers
|
||||||
|
end
|
||||||
|
end
|
@ -1,6 +1,6 @@
|
|||||||
.hero-widget
|
.hero-widget
|
||||||
.hero-widget__img
|
.hero-widget__img
|
||||||
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('preview.jpg'), alt: @instance_presenter.site_title
|
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title
|
||||||
|
|
||||||
.hero-widget__text
|
.hero-widget__text
|
||||||
%p= @instance_presenter.site_short_description.html_safe.presence || @instance_presenter.site_description.html_safe.presence || t('about.generic_description', domain: site_hostname)
|
%p= @instance_presenter.site_short_description.html_safe.presence || @instance_presenter.site_description.html_safe.presence || t('about.generic_description', domain: site_hostname)
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
.batch-table__row
|
||||||
|
%label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox
|
||||||
|
= f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id
|
||||||
|
.batch-table__row__content.batch-table__row__content--unpadded
|
||||||
|
%table.accounts-table
|
||||||
|
%tbody
|
||||||
|
%tr
|
||||||
|
%td= account_link_to account
|
||||||
|
%td.accounts-table__count.optional
|
||||||
|
= number_to_human account.statuses_count, strip_insignificant_zeros: true
|
||||||
|
%small= t('accounts.posts', count: account.statuses_count).downcase
|
||||||
|
%td.accounts-table__count.optional
|
||||||
|
= number_to_human account.followers_count, strip_insignificant_zeros: true
|
||||||
|
%small= t('accounts.followers', count: account.followers_count).downcase
|
||||||
|
%td.accounts-table__count
|
||||||
|
- if account.last_status_at.present?
|
||||||
|
%time.time-ago{ datetime: account.last_status_at.iso8601, title: l(account.last_status_at) }= l account.last_status_at
|
||||||
|
- else
|
||||||
|
\-
|
||||||
|
%small= t('accounts.last_active')
|
@ -0,0 +1,40 @@
|
|||||||
|
- content_for :page_title do
|
||||||
|
= t('settings.relationships')
|
||||||
|
|
||||||
|
.filters
|
||||||
|
.filter-subset
|
||||||
|
%strong= t 'relationships.relationship'
|
||||||
|
%ul
|
||||||
|
%li= filter_link_to t('accounts.following', count: current_account.following_count), relationship: nil
|
||||||
|
%li= filter_link_to t('accounts.followers', count: current_account.followers_count), relationship: 'followed_by'
|
||||||
|
%li= filter_link_to t('relationships.mutual'), relationship: 'mutual'
|
||||||
|
|
||||||
|
.filter-subset
|
||||||
|
%strong= t 'relationships.status'
|
||||||
|
%ul
|
||||||
|
%li= filter_link_to t('generic.all'), status: nil
|
||||||
|
%li= filter_link_to t('relationships.active'), status: 'active'
|
||||||
|
%li= filter_link_to t('relationships.abandoned'), status: 'abandoned'
|
||||||
|
|
||||||
|
= form_for(@form, url: relationships_path, method: :patch) do |f|
|
||||||
|
= hidden_field_tag :page, params[:page] || 1
|
||||||
|
= hidden_field_tag :relationship, params[:relationship]
|
||||||
|
= hidden_field_tag :status, params[:status]
|
||||||
|
|
||||||
|
.batch-table
|
||||||
|
.batch-table__toolbar
|
||||||
|
%label.batch-table__toolbar__select.batch-checkbox-all
|
||||||
|
= check_box_tag :batch_checkbox_all, nil, false
|
||||||
|
.batch-table__toolbar__actions
|
||||||
|
= f.button safe_join([fa_icon('user-times'), t('relationships.remove_selected_follows')]), name: :unfollow, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } unless followed_by_relationship?
|
||||||
|
|
||||||
|
= f.button safe_join([fa_icon('trash'), t('relationships.remove_selected_followers')]), name: :remove_from_followers, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } unless following_relationship?
|
||||||
|
|
||||||
|
= f.button safe_join([fa_icon('trash'), t('relationships.remove_selected_domains')]), name: :block_domains, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } if followed_by_relationship?
|
||||||
|
.batch-table__body
|
||||||
|
- if @accounts.empty?
|
||||||
|
= nothing_here 'nothing-here--under-tabs'
|
||||||
|
- else
|
||||||
|
= render partial: 'account', collection: @accounts, locals: { f: f }
|
||||||
|
|
||||||
|
= paginate @accounts
|
@ -1,34 +0,0 @@
|
|||||||
- content_for :page_title do
|
|
||||||
= t('settings.followers')
|
|
||||||
|
|
||||||
= form_tag settings_follower_domains_path, method: :patch, class: 'table-form' do
|
|
||||||
- unless @account.locked?
|
|
||||||
.warning
|
|
||||||
%strong
|
|
||||||
= fa_icon('warning')
|
|
||||||
= t('followers.unlocked_warning_title')
|
|
||||||
= t('followers.unlocked_warning_html', lock_link: link_to(t('followers.lock_link'), settings_profile_url))
|
|
||||||
|
|
||||||
%p= t('followers.explanation_html')
|
|
||||||
%p= t('followers.true_privacy_html')
|
|
||||||
|
|
||||||
.table-wrapper
|
|
||||||
%table.table
|
|
||||||
%thead
|
|
||||||
%tr
|
|
||||||
%th
|
|
||||||
%th= t('followers.domain')
|
|
||||||
%th= t('followers.followers_count')
|
|
||||||
%tbody
|
|
||||||
- @domains.each do |domain|
|
|
||||||
%tr
|
|
||||||
%td
|
|
||||||
= check_box_tag 'select[]', domain.domain, false, disabled: !@account.locked? unless domain.domain.nil?
|
|
||||||
%td
|
|
||||||
%samp= domain.domain.presence || Rails.configuration.x.local_domain
|
|
||||||
%td= number_with_delimiter domain.accounts_from_domain
|
|
||||||
|
|
||||||
.action-pagination
|
|
||||||
.actions
|
|
||||||
= button_tag t('followers.purge'), type: :submit, class: 'button', disabled: !@account.locked?
|
|
||||||
= paginate @domains
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue