diff --git a/app/controllers/admin/abuse_metrics_controller.rb b/app/controllers/admin/abuse_metrics_controller.rb new file mode 100644 index 000000000..fcfc2a52a --- /dev/null +++ b/app/controllers/admin/abuse_metrics_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Admin + class AbuseMetricsController < BaseController + def index + authorize :dashboard, :index? + end + end +end diff --git a/app/lib/admin/metrics/dimension.rb b/app/lib/admin/metrics/dimension.rb index 81b89d9b3..96c9851f8 100644 --- a/app/lib/admin/metrics/dimension.rb +++ b/app/lib/admin/metrics/dimension.rb @@ -11,6 +11,8 @@ class Admin::Metrics::Dimension tag_languages: Admin::Metrics::Dimension::TagLanguagesDimension, instance_accounts: Admin::Metrics::Dimension::InstanceAccountsDimension, instance_languages: Admin::Metrics::Dimension::InstanceLanguagesDimension, + ips: Admin::Metrics::Dimension::IPsDimension, + email_domains: Admin::Metrics::Dimension::EmailDomainsDimension, }.freeze def self.retrieve(dimension_keys, start_at, end_at, limit, params) diff --git a/app/lib/admin/metrics/dimension/email_domains_dimension.rb b/app/lib/admin/metrics/dimension/email_domains_dimension.rb new file mode 100644 index 000000000..c8e1b97b7 --- /dev/null +++ b/app/lib/admin/metrics/dimension/email_domains_dimension.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class Admin::Metrics::Dimension::EmailDomainsDimension < Admin::Metrics::Dimension::BaseDimension + def key + 'email_domains' + end + + protected + + def perform_query + sql = <<-SQL.squish + SELECT split_part(email, '@', 2) AS domain, count(*) AS value + FROM users + WHERE created_at BETWEEN $1 AND $2 + GROUP BY split_part(email, '@', 2) + ORDER BY count(*) DESC + LIMIT $3 + SQL + + rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, @limit]]) + + rows.map { |row| { key: row['domain'], human_key: row['domain'], value: row['value'].to_s } } + end +end diff --git a/app/lib/admin/metrics/dimension/ips_dimension.rb b/app/lib/admin/metrics/dimension/ips_dimension.rb new file mode 100644 index 000000000..b66626733 --- /dev/null +++ b/app/lib/admin/metrics/dimension/ips_dimension.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class Admin::Metrics::Dimension::IPsDimension < Admin::Metrics::Dimension::BaseDimension + def key + 'ips' + end + + protected + + def perform_query + sql = <<-SQL.squish + SELECT sign_up_ip, count(*) AS value + FROM users + WHERE created_at BETWEEN $1 AND $2 + GROUP BY sign_up_ip + ORDER BY count(*) DESC + LIMIT $3 + SQL + + rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, @limit]]) + + rows.map { |row| { key: row['sign_up_ip'], human_key: row['sign_up_ip'], value: row['value'].to_s } } + end +end diff --git a/app/views/admin/abuse_metrics/index.html.haml b/app/views/admin/abuse_metrics/index.html.haml new file mode 100644 index 000000000..cac089f81 --- /dev/null +++ b/app/views/admin/abuse_metrics/index.html.haml @@ -0,0 +1,16 @@ +- content_for :header_tags do + = javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous' + +.dashboard + .dashboard__item + = react_admin_component :dimension, dimension: 'ips', start_at: 1.hour.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by IP last hour' + .dashboard__item + = react_admin_component :dimension, dimension: 'ips', start_at: 1.day.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by IP last day' + .dashboard__item + = react_admin_component :dimension, dimension: 'ips', start_at: 7.days.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by IP last week' + .dashboard__item + = react_admin_component :dimension, dimension: 'email_domains', start_at: 1.hour.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by e-mail domain last hour' + .dashboard__item + = react_admin_component :dimension, dimension: 'email_domains', start_at: 1.day.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by e-mail domain last day' + .dashboard__item + = react_admin_component :dimension, dimension: 'email_domains', start_at: 7.days.ago, end_at: Time.now.utc, limit: 8, label: 'New accounts by e-mail domain last week' diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 3e5a55617..ef7f0743c 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -25,6 +25,7 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.acronym 'REST' inflect.acronym 'URL' inflect.acronym 'ASCII' + inflect.acronym 'IPs' inflect.singular 'data', 'data' end diff --git a/config/routes.rb b/config/routes.rb index 7dc9f391d..322b3d282 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -189,6 +189,7 @@ Rails.application.routes.draw do namespace :admin do get '/dashboard', to: 'dashboard#index' + get '/abuse_metrics', to: 'abuse_metrics#index' resources :domain_allows, only: [:new, :create, :show, :destroy] resources :domain_blocks, only: [:new, :create, :destroy, :update, :edit]