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
This commit is contained in:
		
							parent
							
								
									f5236fe95a
								
							
						
					
					
						commit
						67172aa4f9
					
				
					 9 changed files with 181 additions and 94 deletions
				
			
		|  | @ -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 | ||||
							
								
								
									
										25
									
								
								app/controllers/admin/relationships_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/controllers/admin/relationships_controller.rb
									
									
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
							
								
								
									
										39
									
								
								app/views/admin/relationships/index.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/views/admin/relationships/index.html.haml
									
									
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue