diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/relationships_controller.rb | 98 | ||||
-rw-r--r-- | app/controllers/settings/follower_domains_controller.rb | 28 | ||||
-rw-r--r-- | app/helpers/admin/filter_helper.rb | 3 | ||||
-rw-r--r-- | app/javascript/styles/mastodon/tables.scss | 19 | ||||
-rw-r--r-- | app/models/form/account_batch.rb | 60 | ||||
-rw-r--r-- | app/views/relationships/_account.html.haml | 20 | ||||
-rw-r--r-- | app/views/relationships/show.html.haml | 43 | ||||
-rw-r--r-- | app/views/settings/follower_domains/show.html.haml | 34 |
8 files changed, 242 insertions, 63 deletions
diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb new file mode 100644 index 000000000..e6dd65e44 --- /dev/null +++ b/app/controllers/relationships_controller.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +class RelationshipsController < ApplicationController + layout 'admin' + + before_action :authenticate_user! + before_action :set_accounts, only: :show + 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 +end diff --git a/app/controllers/settings/follower_domains_controller.rb b/app/controllers/settings/follower_domains_controller.rb deleted file mode 100644 index ce8ec985d..000000000 --- a/app/controllers/settings/follower_domains_controller.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -class Settings::FollowerDomainsController < Settings::BaseController - layout 'admin' - - before_action :authenticate_user! - - 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 diff --git a/app/helpers/admin/filter_helper.rb b/app/helpers/admin/filter_helper.rb index 8f78bf5f8..09a356296 100644 --- a/app/helpers/admin/filter_helper.rb +++ b/app/helpers/admin/filter_helper.rb @@ -7,8 +7,9 @@ module Admin::FilterHelper CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze TAGS_FILTERS = %i(hidden).freeze INSTANCES_FILTERS = %i(limited by_domain).freeze + FOLLOWERS_FILTERS = %i(relationship status by_domain).freeze - FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS + FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS + FOLLOWERS_FILTERS def filter_link_to(text, link_to_params, link_class_params = link_to_params) new_url = filtered_url_for(link_to_params) diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss index 9e8785679..d3a0ea03d 100644 --- a/app/javascript/styles/mastodon/tables.scss +++ b/app/javascript/styles/mastodon/tables.scss @@ -140,6 +140,15 @@ a.table-action-link { input { margin-top: 8px; } + + &--aligned { + display: flex; + align-items: center; + + input { + margin-top: 0; + } + } } &__actions, @@ -183,6 +192,10 @@ a.table-action-link { &__content { padding-top: 12px; padding-bottom: 16px; + + &--unpadded { + padding: 0; + } } } @@ -197,4 +210,10 @@ a.table-action-link { font-weight: 700; } } + + .nothing-here { + border: 1px solid darken($ui-base-color, 8%); + border-top: 0; + box-shadow: none; + } } diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb new file mode 100644 index 000000000..60eaaf0e2 --- /dev/null +++ b/app/models/form/account_batch.rb @@ -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 diff --git a/app/views/relationships/_account.html.haml b/app/views/relationships/_account.html.haml new file mode 100644 index 000000000..6c22deb51 --- /dev/null +++ b/app/views/relationships/_account.html.haml @@ -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') diff --git a/app/views/relationships/show.html.haml b/app/views/relationships/show.html.haml new file mode 100644 index 000000000..33a43f1a8 --- /dev/null +++ b/app/views/relationships/show.html.haml @@ -0,0 +1,43 @@ +- content_for :page_title do + = t('settings.relationships') + +- content_for :header_tags do + = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous' + +.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 diff --git a/app/views/settings/follower_domains/show.html.haml b/app/views/settings/follower_domains/show.html.haml deleted file mode 100644 index f1687d4d2..000000000 --- a/app/views/settings/follower_domains/show.html.haml +++ /dev/null @@ -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 |