From c0006a004d0e58bb3ad356759c17e60f28975b61 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 23 Jan 2020 20:33:20 +0100 Subject: [PATCH] Change followers page to relationships page in admin UI (#12927) Allow browsing and filtering all relationships instead of just followers, unify the codebase with the user-facing relationship manager, add ability to see who the user invited --- app/controllers/admin/followers_controller.rb | 18 --- .../admin/relationships_controller.rb | 25 ++++ app/controllers/relationships_controller.rb | 46 +------- app/models/relationship_filter.rb | 109 ++++++++++++++++++ app/views/admin/accounts/show.html.haml | 2 +- app/views/admin/followers/index.html.haml | 28 ----- app/views/admin/relationships/index.html.haml | 39 +++++++ config/locales/en.yml | 6 +- config/routes.rb | 2 +- 9 files changed, 181 insertions(+), 94 deletions(-) delete mode 100644 app/controllers/admin/followers_controller.rb create mode 100644 app/controllers/admin/relationships_controller.rb delete mode 100644 app/views/admin/followers/index.html.haml create mode 100644 app/views/admin/relationships/index.html.haml diff --git a/app/controllers/admin/followers_controller.rb b/app/controllers/admin/followers_controller.rb deleted file mode 100644 index d826f47c5a..0000000000 --- a/app/controllers/admin/followers_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module Admin - class FollowersController < BaseController - before_action :set_account - - PER_PAGE = 40 - - def index - authorize :account, :index? - @followers = @account.followers.local.recent.page(params[:page]).per(PER_PAGE) - end - - def set_account - @account = Account.find(params[:account_id]) - end - end -end diff --git a/app/controllers/admin/relationships_controller.rb b/app/controllers/admin/relationships_controller.rb new file mode 100644 index 0000000000..07d1213407 --- /dev/null +++ b/app/controllers/admin/relationships_controller.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Admin + class RelationshipsController < BaseController + before_action :set_account + + PER_PAGE = 40 + + def index + authorize :account, :index? + + @accounts = RelationshipFilter.new(@account, filter_params).results.page(params[:page]).per(PER_PAGE) + end + + private + + def set_account + @account = Account.find(params[:account_id]) + end + + def filter_params + params.slice(RelationshipFilter::KEYS).permit(RelationshipFilter::KEYS) + end + end +end diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb index 9d0be4a008..0835758f2d 100644 --- a/app/controllers/relationships_controller.rb +++ b/app/controllers/relationships_controller.rb @@ -19,53 +19,13 @@ class RelationshipsController < ApplicationController rescue ActionController::ParameterMissing # Do nothing ensure - redirect_to relationships_path(current_params) + redirect_to relationships_path(filter_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.eager_load(:account_stat).reorder(nil) - else - current_account.followers.eager_load(:account_stat).reorder(nil) - end - end - - scope.merge!(Follow.recent) if params[:order].blank? || params[:order] == 'recent' - scope.merge!(Account.by_recent_status) if params[:order] == 'active' - scope.merge!(mutual_relationship_scope) if mutual_relationship? - scope.merge!(moved_account_scope) if params[:status] == 'moved' - scope.merge!(primary_account_scope) if params[:status] == 'primary' - scope.merge!(by_domain_scope) if params[:by_domain].present? - scope.merge!(dormant_account_scope) if params[:activity] == 'dormant' - - scope - end - - def mutual_relationship_scope - Account.where(id: current_account.following) - end - - def moved_account_scope - Account.where.not(moved_to_account_id: nil) - end - - def primary_account_scope - Account.where(moved_to_account_id: nil) - end - - def dormant_account_scope - AccountStat.where(last_status_at: nil).or(AccountStat.where(AccountStat.arel_table[:last_status_at].lt(1.month.ago))) - end - - def by_domain_scope - Account.where(domain: params[:by_domain]) + @accounts = RelationshipFilter.new(current_account, filter_params).results.page(params[:page]).per(40) end def form_account_batch_params @@ -84,7 +44,7 @@ class RelationshipsController < ApplicationController params[:relationship] == 'followed_by' end - def current_params + def filter_params params.slice(:page, *RelationshipFilter::KEYS).permit(:page, *RelationshipFilter::KEYS) end diff --git a/app/models/relationship_filter.rb b/app/models/relationship_filter.rb index 51640f494c..fcb3a8dc5b 100644 --- a/app/models/relationship_filter.rb +++ b/app/models/relationship_filter.rb @@ -7,5 +7,114 @@ class RelationshipFilter by_domain activity order + location ).freeze + + attr_reader :params, :account + + def initialize(account, params) + @account = account + @params = params + + set_defaults! + end + + def results + scope = scope_for('relationship', params['relationship']) + + params.each do |key, value| + next if key.to_s == 'page' + + scope.merge!(scope_for(key, value)) if value.present? + end + + scope + end + + private + + def set_defaults! + params['relationship'] = 'following' if params['relationship'].blank? + params['order'] = 'recent' if params['order'].blank? + end + + def scope_for(key, value) + case key.to_s + when 'relationship' + relationship_scope(value) + when 'by_domain' + by_domain_scope(value) + when 'location' + location_scope(value) + when 'status' + status_scope(value) + when 'order' + order_scope(value) + when 'activity' + activity_scope(value) + else + raise "Unknown filter: #{key}" + end + end + + def relationship_scope(value) + case value.to_s + when 'following' + account.following.eager_load(:account_stat).reorder(nil) + when 'followed_by' + account.followers.eager_load(:account_stat).reorder(nil) + when 'mutual' + account.followers.eager_load(:account_stat).reorder(nil).merge(Account.where(id: account.following)) + when 'invited' + Account.joins(user: :invite).merge(Invite.where(user: account.user)).eager_load(:account_stat).reorder(nil) + else + raise "Unknown relationship: #{value}" + end + end + + def by_domain_scope(value) + Account.where(domain: value.to_s) + end + + def location_scope(value) + case value.to_s + when 'local' + Account.local + when 'remote' + Account.remote + else + raise "Unknown location: #{value}" + end + end + + def status_scope(value) + case value.to_s + when 'moved' + Account.where.not(moved_to_account_id: nil) + when 'primary' + Account.where(moved_to_account_id: nil) + else + raise "Unknown status: #{value}" + end + end + + def order_scope(value) + case value.to_s + when 'active' + Account.by_recent_status + when 'recent' + Follow.recent + else + raise "Unknown order: #{value}" + end + end + + def activity_scope(value) + case value.to_s + when 'dormant' + AccountStat.where(last_status_at: nil).or(AccountStat.where(AccountStat.arel_table[:last_status_at].lt(1.month.ago))) + else + raise "Unknown activity: #{value}" + end + end end diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index 1429f56d56..f191d8f25f 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -41,7 +41,7 @@ .dashboard__counters__num= number_to_human_size @account.media_attachments.sum('file_file_size') .dashboard__counters__label= t 'admin.accounts.media_attachments' %div - = link_to admin_account_followers_path(@account.id) do + = link_to admin_account_relationships_path(@account.id, location: 'local') do .dashboard__counters__num= number_with_delimiter @account.local_followers_count .dashboard__counters__label= t 'admin.accounts.followers' %div diff --git a/app/views/admin/followers/index.html.haml b/app/views/admin/followers/index.html.haml deleted file mode 100644 index 25f1f290f4..0000000000 --- a/app/views/admin/followers/index.html.haml +++ /dev/null @@ -1,28 +0,0 @@ -- content_for :page_title do - = t('admin.followers.title', acct: @account.acct) - -.filters - .filter-subset - %strong= t('admin.accounts.location.title') - %ul - %li= link_to t('admin.accounts.location.local'), admin_account_followers_path(@account.id), class: 'selected' - .back-link{ style: 'flex: 1 1 auto; text-align: right' } - = link_to admin_account_path(@account.id) do - = fa_icon 'chevron-left fw' - = t('admin.followers.back_to_account') - -%hr.spacer/ - -.table-wrapper - %table.table - %thead - %tr - %th= t('admin.accounts.username') - %th= t('admin.accounts.role') - %th= t('admin.accounts.most_recent_ip') - %th= t('admin.accounts.most_recent_activity') - %th - %tbody - = render partial: 'admin/accounts/account', collection: @followers - -= paginate @followers diff --git a/app/views/admin/relationships/index.html.haml b/app/views/admin/relationships/index.html.haml new file mode 100644 index 0000000000..3afaff6153 --- /dev/null +++ b/app/views/admin/relationships/index.html.haml @@ -0,0 +1,39 @@ +- content_for :page_title do + = t('admin.relationships.title', acct: @account.acct) + +.filters + .filter-subset + %strong= t 'relationships.relationship' + %ul + %li= filter_link_to t('relationships.following'), relationship: nil + %li= filter_link_to t('relationships.followers'), relationship: 'followed_by' + %li= filter_link_to t('relationships.mutual'), relationship: 'mutual' + %li= filter_link_to t('relationships.invited'), relationship: 'invited' + + .filter-subset + %strong= t('admin.accounts.location.title') + %ul + %li= filter_link_to t('admin.accounts.moderation.all'), location: nil + %li= filter_link_to t('admin.accounts.location.local'), location: 'local' + %li= filter_link_to t('admin.accounts.location.remote'), location: 'remote' + + .back-link{ style: 'flex: 1 1 auto; text-align: right' } + = link_to admin_account_path(@account.id) do + = fa_icon 'chevron-left fw' + = t('admin.statuses.back_to_account') + +%hr.spacer/ + +.table-wrapper + %table.table + %thead + %tr + %th= t('admin.accounts.username') + %th= t('admin.accounts.role') + %th= t('admin.accounts.most_recent_ip') + %th= t('admin.accounts.most_recent_activity') + %th + %tbody + = render partial: 'admin/accounts/account', collection: @accounts + += paginate @accounts diff --git a/config/locales/en.yml b/config/locales/en.yml index d768cef332..8a86f8c7ab 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -344,9 +344,6 @@ en: create: Add domain title: New e-mail blacklist entry title: E-mail blacklist - followers: - back_to_account: Back To Account - title: "%{acct}'s Followers" instances: by_domain: Domain delivery_available: Delivery is available @@ -375,6 +372,8 @@ en: title: Invites pending_accounts: title: Pending accounts (%{count}) + relationships: + title: "%{acct}'s relationships" relays: add_new: Add new relay delete: Delete @@ -935,6 +934,7 @@ en: dormant: Dormant followers: Followers following: Following + invited: Invited last_active: Last active most_recent: Most recent moved: Moved diff --git a/config/routes.rb b/config/routes.rb index ff308699d3..f79af192d8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -223,7 +223,7 @@ Rails.application.routes.draw do resource :reset, only: [:create] resource :action, only: [:new, :create], controller: 'account_actions' resources :statuses, only: [:index, :show, :create, :update, :destroy] - resources :followers, only: [:index] + resources :relationships, only: [:index] resource :confirmation, only: [:create] do collection do