From 7cf20680ead006956ee5d6aff7915cf1e06d0a09 Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 14:40:52 +0700 Subject: [PATCH 1/9] fix: 500 error returning for account searching in accounts list page --- app/controllers/accounts_controller.rb | 23 ++++++++++++++++++++++- app/views/accounts/index.html.haml | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 3bfcbf4a..2de67ac4 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 @@ -44,6 +49,22 @@ 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] + } + end + + def account_search_query + q_param = params[:q] + return {} unless q_param.respond_to?(:permit) + + q_param.permit(:username_cont).to_h end end diff --git a/app/views/accounts/index.html.haml b/app/views/accounts/index.html.haml index 327b5efb..9a4560a0 100644 --- a/app/views/accounts/index.html.haml +++ b/app/views/accounts/index.html.haml @@ -6,7 +6,7 @@ .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| From a396f6504147f896e0253f63caa5e5e52dc534e1 Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 15:23:28 +0700 Subject: [PATCH 2/9] fix: add filter layer of searching end-usr only --- app/controllers/accounts_controller.rb | 3 ++- app/models/filter/account.rb | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 2de67ac4..72c5c8c5 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -57,7 +57,8 @@ def records_filter def filter_params { q: account_search_query, - page: params[:page] + page: params[:page], + role_id_nil: true } end diff --git a/app/models/filter/account.rb b/app/models/filter/account.rb index 927c93bd..7f8a1b3f 100644 --- a/app/models/filter/account.rb +++ b/app/models/filter/account.rb @@ -2,13 +2,25 @@ class Filter::Account < Filter::Common def initialize(params) super(params) + @role_id_nil = params[:role_id_nil] 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) + base_scope.ransack(@q) + 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 end From 31e1a2ab5bbb13ec37860f926a321c6fac745208 Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 15:26:59 +0700 Subject: [PATCH 3/9] fix: extra page numbers are generated even though there are no records --- app/models/filter/common.rb | 6 ++- app/views/kaminari/_paginator.html.haml | 51 +++++++++++++------------ 2 files changed, 32 insertions(+), 25 deletions(-) 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/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 » From 1009a0ffb7ebea56fd2fee8b761aef02f6849f0d Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 15:50:41 +0700 Subject: [PATCH 4/9] fix: pagination issue --- app/models/filter/account.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/filter/account.rb b/app/models/filter/account.rb index 7f8a1b3f..467179df 100644 --- a/app/models/filter/account.rb +++ b/app/models/filter/account.rb @@ -6,13 +6,17 @@ def initialize(params) end def paginated_scope - public_scope.offset((@current_page - 1) * @per_page).limit(@per_page) + build_search.result.offset((@current_page - 1) * @per_page).limit(@per_page) end def build_search base_scope.ransack(@q) end + def get + paginated_scope + end + private def base_scope From 969c86bb3bf166587ca20fd98506084baa48a7af Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 16:13:14 +0700 Subject: [PATCH 5/9] fix: wrong calculation of pagination numbers --- app/models/filter/account.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/filter/account.rb b/app/models/filter/account.rb index 467179df..cbcf4b5e 100644 --- a/app/models/filter/account.rb +++ b/app/models/filter/account.rb @@ -1,8 +1,8 @@ class Filter::Account < Filter::Common def initialize(params) - super(params) @role_id_nil = params[:role_id_nil] + super(params) end def paginated_scope From c3c865c5b38014dcd1596ebbcf477a160628cc3a Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 17:23:39 +0700 Subject: [PATCH 6/9] Refine accounts search and pagination --- app/controllers/accounts_controller.rb | 7 ++--- app/models/filter/account.rb | 42 ++++++++++++++++++++++++-- app/views/accounts/index.html.haml | 4 +-- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 72c5c8c5..0928971c 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -20,7 +20,7 @@ def unfollow end def export - accounts = records_filter.public_scope.joins(:user).includes(:user).where.not(users: { confirmed_at: nil }) + accounts = records_filter.public_scope domain = ENV['LOCAL_DOMAIN'] || 'example.com' @@ -63,9 +63,6 @@ def filter_params end def account_search_query - q_param = params[:q] - return {} unless q_param.respond_to?(:permit) - - q_param.permit(:username_cont).to_h + params[:q].to_s.presence end end diff --git a/app/models/filter/account.rb b/app/models/filter/account.rb index cbcf4b5e..0b11c95a 100644 --- a/app/models/filter/account.rb +++ b/app/models/filter/account.rb @@ -1,16 +1,19 @@ class Filter::Account < Filter::Common def initialize(params) + @query = params[:q].to_s.strip @role_id_nil = params[:role_id_nil] - super(params) + @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 - build_search.result.offset((@current_page - 1) * @per_page).limit(@per_page) + public_scope.offset((@current_page - 1) * @per_page).limit(@per_page) end def build_search - base_scope.ransack(@q) + public_scope end def get @@ -27,4 +30,37 @@ def base_scope 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? + scope.where( + "LOWER(accounts.username) = :username AND LOWER(COALESCE(accounts.domain, '')) = :domain", + username: exact_username, + 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/views/accounts/index.html.haml b/app/views/accounts/index.html.haml index 9a4560a0..e4ba046a 100644 --- a/app/views/accounts/index.html.haml +++ b/app/views/accounts/index.html.haml @@ -9,9 +9,9 @@ %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 From 21ac28e410719973dc9fbf15be40b1f09a9b7f98 Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 17:37:55 +0700 Subject: [PATCH 7/9] Fix exact account search for local domain --- app/models/filter/account.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/filter/account.rb b/app/models/filter/account.rb index 0b11c95a..080f0ae7 100644 --- a/app/models/filter/account.rb +++ b/app/models/filter/account.rb @@ -37,9 +37,12 @@ def public_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, '')) = :domain", + "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 From ff27f019f66a78d4955cf5631937f94b6dbe2fd4 Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 17:49:10 +0700 Subject: [PATCH 8/9] Fix accounts CSV export filter call --- app/controllers/accounts_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 0928971c..bb0cf8a4 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -20,7 +20,7 @@ def unfollow end def export - accounts = records_filter.public_scope + accounts = records_filter.build_search domain = ENV['LOCAL_DOMAIN'] || 'example.com' From c2e9b039cf59d73189e74c51eef9dcecb5a3ccce Mon Sep 17 00:00:00 2001 From: Aung Kyaw Phyo Date: Fri, 5 Jun 2026 18:37:28 +0700 Subject: [PATCH 9/9] Use account domain in CSV export handles --- app/controllers/accounts_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index bb0cf8a4..c525ae74 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -22,11 +22,13 @@ def unfollow def export 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,