diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 3bfcbf4a..c525ae74 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -2,6 +2,11 @@ class AccountsController < BaseController before_action :find_account, only: [:follow, :unfollow] before_action :find_admin, only: [:follow, :unfollow] + def index + super + @account_search_query = account_search_query + end + def show; end def follow @@ -15,13 +20,15 @@ def unfollow end def export - accounts = records_filter.public_scope.joins(:user).includes(:user).where.not(users: { confirmed_at: nil }) + accounts = records_filter.build_search - domain = ENV['LOCAL_DOMAIN'] || 'example.com' + local_domain = ENV['LOCAL_DOMAIN'] || 'example.com' csv_data = CSV.generate(headers: true) do |csv| csv << ['Username', 'Display name', 'Email address', 'Time and date account opened'] accounts.find_each do |account| + domain = account.domain.presence || local_domain + csv << [ "@#{account.username}@#{domain}", account.display_name, @@ -44,6 +51,20 @@ def find_admin end def records_filter - @filter = Filter::Account.new(params) + @filter = Filter::Account.new(filter_params) + end + + private + + def filter_params + { + q: account_search_query, + page: params[:page], + role_id_nil: true + } + end + + def account_search_query + params[:q].to_s.presence end end diff --git a/app/models/filter/account.rb b/app/models/filter/account.rb index 927c93bd..080f0ae7 100644 --- a/app/models/filter/account.rb +++ b/app/models/filter/account.rb @@ -1,14 +1,69 @@ class Filter::Account < Filter::Common def initialize(params) - super(params) + @query = params[:q].to_s.strip + @role_id_nil = params[:role_id_nil] + @current_page = params[:page].to_i > 0 ? params[:page].to_i : 1 + @per_page = DEFAULT_ITEMS_LIMIT + @total_pages = (public_scope.count.to_f / @per_page).ceil end def paginated_scope - Account.includes(:user).where.not(user: {confirmed_at: nil}).offset((@current_page - 1) * @per_page).limit(@per_page) + public_scope.offset((@current_page - 1) * @per_page).limit(@per_page) end def build_search - Account.ransack(@q) + public_scope + end + + def get + paginated_scope + end + + private + + def base_scope + scope = Account.joins(:user) + .includes(:user) + .where.not(users: { confirmed_at: nil }) + + scope = scope.where(users: { role_id: nil }) if @role_id_nil + scope + end + + def public_scope + scope = base_scope + + return scope if @query.blank? + + if exact_username_domain_query? + local_domain = ENV['LOCAL_DOMAIN'].presence || Rails.configuration.x.local_domain + + scope.where( + "LOWER(accounts.username) = :username AND LOWER(COALESCE(accounts.domain, :local_domain)) = :domain", + username: exact_username, + local_domain: local_domain.to_s.downcase, + domain: exact_domain + ) + else + search_term = "%#{ActiveRecord::Base.sanitize_sql_like(@query)}%" + + scope.where( + "accounts.username ILIKE :term OR accounts.display_name ILIKE :term OR users.email ILIKE :term", + term: search_term + ) + end + end + + def exact_username_domain_query? + @query.match?(/\A@([^@]+)@([^@]+)\z/) + end + + def exact_username + @query.match(/\A@([^@]+)@([^@]+)\z/)[1].downcase + end + + def exact_domain + @query.match(/\A@([^@]+)@([^@]+)\z/)[2].downcase end end diff --git a/app/models/filter/common.rb b/app/models/filter/common.rb index a37b3a49..c93900fc 100644 --- a/app/models/filter/common.rb +++ b/app/models/filter/common.rb @@ -21,7 +21,9 @@ def paginated_scope end def prev_page - @current_page > 1 ? @current_page - 1 : 1 + return nil if @total_pages <= 1 + + @current_page > 1 ? @current_page - 1 : nil end def next_page @@ -45,6 +47,8 @@ def display_page end def each_page + return [] if @total_pages <= 1 + (display_page..@total_pages).map do |page| ::OpenStruct.new(number: page, current?: page == current_page) end diff --git a/app/views/accounts/index.html.haml b/app/views/accounts/index.html.haml index 327b5efb..e4ba046a 100644 --- a/app/views/accounts/index.html.haml +++ b/app/views/accounts/index.html.haml @@ -6,12 +6,12 @@ .card-header %h3.card-title Registered Users .card-tools.d-flex.justify-content-end.align-items-center - %a{ href: export_accounts_path(format: :csv, q: params[:q]), class: "btn btn-danger", title: "export CSV", style: "display: inline-flex; align-items: center; color: #ffffff !important; margin-right: 8px;" } + %a{ href: export_accounts_path(format: :csv, q: @account_search_query), class: "btn btn-danger", title: "export CSV", style: "display: inline-flex; align-items: center; color: #ffffff !important; margin-right: 8px;" } = image_tag("icons/download.svg", style: "width: 1em; height: 1em; margin-right: 5px;") Export CSV - = search_form_for @search do |f| + = form_tag(accounts_path, method: :get) do .input-group.input-group-sm{style: "width: 150px;"} - = f.search_field :username_cont, class: "form-control float-right", placeholder: "Search" + = text_field_tag :q, params[:q], class: "form-control float-right", placeholder: "Search" .input-group-append %button.btn.btn-default{type: "submit"} %i.fas.fa-search diff --git a/app/views/kaminari/_paginator.html.haml b/app/views/kaminari/_paginator.html.haml index 2e3de513..bd58063e 100644 --- a/app/views/kaminari/_paginator.html.haml +++ b/app/views/kaminari/_paginator.html.haml @@ -1,29 +1,32 @@ - @custom_paginator = custom_paginator -%nav{"aria-label" => "Page navigation example"} - %ul.pagination.pagination-sm.m-0.float-right - - if @custom_paginator.prev_page - %li.page-item - = link_to raw('«'), url_for_page(@custom_paginator.prev_page), class: 'page-link' - - else - %li.page-item.disabled - %span.page-link « +- if @custom_paginator.total_pages > 1 + %nav{"aria-label" => "Page navigation example"} + %ul.pagination.pagination-sm.m-0.float-right + - if @custom_paginator.prev_page + %li.page-item + = link_to raw('«'), url_for_page(@custom_paginator.prev_page), class: 'page-link' + - else + %li.page-item.disabled + %span.page-link « - - if @custom_paginator.current_page >= 5 - %li.page-item.disabled - %span.page-link ... + - if @custom_paginator.current_page >= 5 + %li.page-item.disabled + %span.page-link ... - - @custom_paginator.each_page.take(5).each do |page| - - if page - %li{class: "page-item #{'active' if page.current?}"} - = link_to page.number, url_for_page(page.number), class: 'page-link' + - visible_pages = @custom_paginator.each_page.take(5) + - visible_pages.each do |page| + - if page + %li{class: "page-item #{'active' if page.current?}"} + = link_to page.number, url_for_page(page.number), class: 'page-link' - - if @custom_paginator.total_pages >= @custom_paginator.current_page - %li.page-item.disabled - %span.page-link ... + - last_visible_page = visible_pages.last&.number || 0 + - if @custom_paginator.total_pages > last_visible_page + %li.page-item.disabled + %span.page-link ... - - if @custom_paginator.next_page - %li.page-item - = link_to raw('»'), url_for_page(@custom_paginator.next_page), class: 'page-link' - - else - %li.page-item.disabled - %span.page-link » + - if @custom_paginator.next_page + %li.page-item + = link_to raw('»'), url_for_page(@custom_paginator.next_page), class: 'page-link' + - else + %li.page-item.disabled + %span.page-link »