about summary refs log tree commit diff
path: root/app/lib/admin
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2022-03-09 08:52:32 +0100
committerGitHub <noreply@github.com>2022-03-09 08:52:32 +0100
commitbd53dd521064b12261b82105624cf5f8b9ca9d69 (patch)
treedde9c499734f74303776705810e76dad668e7d7c /app/lib/admin
parent318d34d528d8d4f9165bf9c1f873da68aadb90a2 (diff)
Change design of federation pages in admin UI (#17704)
* Change design of federation pages in admin UI

* Fix query performance in instance media attachments measure

* Fix reblogs being included in instance languages dimension
Diffstat (limited to 'app/lib/admin')
-rw-r--r--app/lib/admin/metrics/dimension.rb2
-rw-r--r--app/lib/admin/metrics/dimension/instance_accounts_dimension.rb35
-rw-r--r--app/lib/admin/metrics/dimension/instance_languages_dimension.rb37
-rw-r--r--app/lib/admin/metrics/measure.rb6
-rw-r--r--app/lib/admin/metrics/measure/base_measure.rb8
-rw-r--r--app/lib/admin/metrics/measure/instance_accounts_measure.rb58
-rw-r--r--app/lib/admin/metrics/measure/instance_followers_measure.rb59
-rw-r--r--app/lib/admin/metrics/measure/instance_follows_measure.rb59
-rw-r--r--app/lib/admin/metrics/measure/instance_media_attachments_measure.rb69
-rw-r--r--app/lib/admin/metrics/measure/instance_reports_measure.rb59
-rw-r--r--app/lib/admin/metrics/measure/instance_statuses_measure.rb60
11 files changed, 452 insertions, 0 deletions
diff --git a/app/lib/admin/metrics/dimension.rb b/app/lib/admin/metrics/dimension.rb
index d8392ddfc..81b89d9b3 100644
--- a/app/lib/admin/metrics/dimension.rb
+++ b/app/lib/admin/metrics/dimension.rb
@@ -9,6 +9,8 @@ class Admin::Metrics::Dimension
     software_versions: Admin::Metrics::Dimension::SoftwareVersionsDimension,
     tag_servers: Admin::Metrics::Dimension::TagServersDimension,
     tag_languages: Admin::Metrics::Dimension::TagLanguagesDimension,
+    instance_accounts: Admin::Metrics::Dimension::InstanceAccountsDimension,
+    instance_languages: Admin::Metrics::Dimension::InstanceLanguagesDimension,
   }.freeze
 
   def self.retrieve(dimension_keys, start_at, end_at, limit, params)
diff --git a/app/lib/admin/metrics/dimension/instance_accounts_dimension.rb b/app/lib/admin/metrics/dimension/instance_accounts_dimension.rb
new file mode 100644
index 000000000..4eac8e611
--- /dev/null
+++ b/app/lib/admin/metrics/dimension/instance_accounts_dimension.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Dimension::InstanceAccountsDimension < Admin::Metrics::Dimension::BaseDimension
+  include LanguagesHelper
+
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_accounts'
+  end
+
+  protected
+
+  def perform_query
+    sql = <<-SQL.squish
+      SELECT accounts.username, count(follows.*) AS value
+      FROM accounts
+      LEFT JOIN follows ON follows.target_account_id = accounts.id
+      WHERE accounts.domain = $1
+      GROUP BY accounts.id, follows.target_account_id
+      ORDER BY value DESC
+      LIMIT $2
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, params[:domain]], [nil, @limit]])
+
+    rows.map { |row| { key: row['username'], human_key: row['username'], value: row['value'].to_s } }
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/dimension/instance_languages_dimension.rb b/app/lib/admin/metrics/dimension/instance_languages_dimension.rb
new file mode 100644
index 000000000..1ede1a56e
--- /dev/null
+++ b/app/lib/admin/metrics/dimension/instance_languages_dimension.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Dimension::InstanceLanguagesDimension < Admin::Metrics::Dimension::BaseDimension
+  include LanguagesHelper
+
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_languages'
+  end
+
+  protected
+
+  def perform_query
+    sql = <<-SQL.squish
+      SELECT COALESCE(statuses.language, 'und') AS language, count(*) AS value
+      FROM statuses
+      INNER JOIN accounts ON accounts.id = statuses.account_id
+      WHERE accounts.domain = $1
+        AND statuses.id BETWEEN $2 AND $3
+        AND statuses.reblog_of_id IS NULL
+      GROUP BY COALESCE(statuses.language, 'und')
+      ORDER BY count(*) DESC
+      LIMIT $4
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, params[:domain]], [nil, Mastodon::Snowflake.id_at(@start_at, with_random: false)], [nil, Mastodon::Snowflake.id_at(@end_at, with_random: false)], [nil, @limit]])
+
+    rows.map { |row| { key: row['language'], human_key: standard_locale_name(row['language']), value: row['value'].to_s } }
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/measure.rb b/app/lib/admin/metrics/measure.rb
index a839498a1..0b510eb25 100644
--- a/app/lib/admin/metrics/measure.rb
+++ b/app/lib/admin/metrics/measure.rb
@@ -10,6 +10,12 @@ class Admin::Metrics::Measure
     tag_accounts: Admin::Metrics::Measure::TagAccountsMeasure,
     tag_uses: Admin::Metrics::Measure::TagUsesMeasure,
     tag_servers: Admin::Metrics::Measure::TagServersMeasure,
+    instance_accounts: Admin::Metrics::Measure::InstanceAccountsMeasure,
+    instance_media_attachments: Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure,
+    instance_reports: Admin::Metrics::Measure::InstanceReportsMeasure,
+    instance_statuses: Admin::Metrics::Measure::InstanceStatusesMeasure,
+    instance_follows: Admin::Metrics::Measure::InstanceFollowsMeasure,
+    instance_followers: Admin::Metrics::Measure::InstanceFollowersMeasure,
   }.freeze
 
   def self.retrieve(measure_keys, start_at, end_at, params)
diff --git a/app/lib/admin/metrics/measure/base_measure.rb b/app/lib/admin/metrics/measure/base_measure.rb
index ed1df9c7d..e33a6c494 100644
--- a/app/lib/admin/metrics/measure/base_measure.rb
+++ b/app/lib/admin/metrics/measure/base_measure.rb
@@ -26,6 +26,14 @@ class Admin::Metrics::Measure::BaseMeasure
     raise NotImplementedError
   end
 
+  def unit
+    nil
+  end
+
+  def total_in_time_range?
+    true
+  end
+
   def total
     load[:total]
   end
diff --git a/app/lib/admin/metrics/measure/instance_accounts_measure.rb b/app/lib/admin/metrics/measure/instance_accounts_measure.rb
new file mode 100644
index 000000000..4c61a064a
--- /dev/null
+++ b/app/lib/admin/metrics/measure/instance_accounts_measure.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Measure::InstanceAccountsMeasure < Admin::Metrics::Measure::BaseMeasure
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_accounts'
+  end
+
+  def total_in_time_range?
+    false
+  end
+
+  protected
+
+  def perform_total_query
+    Account.where(domain: params[:domain]).count
+  end
+
+  def perform_previous_total_query
+    nil
+  end
+
+  def perform_data_query
+    sql = <<-SQL.squish
+      SELECT axis.*, (
+        WITH new_accounts AS (
+          SELECT accounts.id
+          FROM accounts
+          WHERE date_trunc('day', accounts.created_at)::date = axis.period
+            AND accounts.domain = $3::text
+        )
+        SELECT count(*) FROM new_accounts
+      ) AS value
+      FROM (
+        SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period
+      ) AS axis
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]])
+
+    rows.map { |row| { date: row['period'], value: row['value'].to_s } }
+  end
+
+  def time_period
+    (@start_at.to_date..@end_at.to_date)
+  end
+
+  def previous_time_period
+    ((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/measure/instance_followers_measure.rb b/app/lib/admin/metrics/measure/instance_followers_measure.rb
new file mode 100644
index 000000000..caa60013b
--- /dev/null
+++ b/app/lib/admin/metrics/measure/instance_followers_measure.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Measure::InstanceFollowersMeasure < Admin::Metrics::Measure::BaseMeasure
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_followers'
+  end
+
+  def total_in_time_range?
+    false
+  end
+
+  protected
+
+  def perform_total_query
+    Follow.joins(:account).merge(Account.where(domain: params[:domain])).count
+  end
+
+  def perform_previous_total_query
+    nil
+  end
+
+  def perform_data_query
+    sql = <<-SQL.squish
+      SELECT axis.*, (
+        WITH new_followers AS (
+          SELECT follows.id
+          FROM follows
+          INNER JOIN accounts ON follows.account_id = accounts.id
+          WHERE date_trunc('day', follows.created_at)::date = axis.period
+            AND accounts.domain = $3::text
+        )
+        SELECT count(*) FROM new_followers
+      ) AS value
+      FROM (
+        SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period
+      ) AS axis
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]])
+
+    rows.map { |row| { date: row['period'], value: row['value'].to_s } }
+  end
+
+  def time_period
+    (@start_at.to_date..@end_at.to_date)
+  end
+
+  def previous_time_period
+    ((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/measure/instance_follows_measure.rb b/app/lib/admin/metrics/measure/instance_follows_measure.rb
new file mode 100644
index 000000000..b026c7e6d
--- /dev/null
+++ b/app/lib/admin/metrics/measure/instance_follows_measure.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Measure::InstanceFollowsMeasure < Admin::Metrics::Measure::BaseMeasure
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_follows'
+  end
+
+  def total_in_time_range?
+    false
+  end
+
+  protected
+
+  def perform_total_query
+    Follow.joins(:target_account).merge(Account.where(domain: params[:domain])).count
+  end
+
+  def perform_previous_total_query
+    nil
+  end
+
+  def perform_data_query
+    sql = <<-SQL.squish
+      SELECT axis.*, (
+        WITH new_follows AS (
+          SELECT follows.id
+          FROM follows
+          INNER JOIN accounts ON follows.target_account_id = accounts.id
+          WHERE date_trunc('day', follows.created_at)::date = axis.period
+            AND accounts.domain = $3::text
+        )
+        SELECT count(*) FROM new_follows
+      ) AS value
+      FROM (
+        SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period
+      ) AS axis
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]])
+
+    rows.map { |row| { date: row['period'], value: row['value'].to_s } }
+  end
+
+  def time_period
+    (@start_at.to_date..@end_at.to_date)
+  end
+
+  def previous_time_period
+    ((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb
new file mode 100644
index 000000000..2e2154c92
--- /dev/null
+++ b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure < Admin::Metrics::Measure::BaseMeasure
+  include ActionView::Helpers::NumberHelper
+
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_media_attachments'
+  end
+
+  def unit
+    'bytes'
+  end
+
+  def value_to_human_value(value)
+    number_to_human_size(value)
+  end
+
+  def total_in_time_range?
+    false
+  end
+
+  protected
+
+  def perform_total_query
+    MediaAttachment.joins(:account).merge(Account.where(domain: params[:domain])).sum('COALESCE(file_file_size, 0) + COALESCE(thumbnail_file_size, 0)')
+  end
+
+  def perform_previous_total_query
+    nil
+  end
+
+  def perform_data_query
+    sql = <<-SQL.squish
+      SELECT axis.*, (
+        WITH new_media_attachments AS (
+          SELECT COALESCE(media_attachments.file_file_size, 0) + COALESCE(media_attachments.thumbnail_file_size, 0) AS size
+          FROM media_attachments
+          INNER JOIN accounts ON accounts.id = media_attachments.account_id
+          WHERE date_trunc('day', media_attachments.created_at)::date = axis.period
+            AND accounts.domain = $3::text
+        )
+        SELECT SUM(size) FROM new_media_attachments
+      ) AS value
+      FROM (
+        SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period
+      ) AS axis
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]])
+
+    rows.map { |row| { date: row['period'], value: row['value'].to_s } }
+  end
+
+  def time_period
+    (@start_at.to_date..@end_at.to_date)
+  end
+
+  def previous_time_period
+    ((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/measure/instance_reports_measure.rb b/app/lib/admin/metrics/measure/instance_reports_measure.rb
new file mode 100644
index 000000000..6b3f35067
--- /dev/null
+++ b/app/lib/admin/metrics/measure/instance_reports_measure.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Measure::InstanceReportsMeasure < Admin::Metrics::Measure::BaseMeasure
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_reports'
+  end
+
+  def total_in_time_range?
+    false
+  end
+
+  protected
+
+  def perform_total_query
+    Report.where(target_account: Account.where(domain: params[:domain])).count
+  end
+
+  def perform_previous_total_query
+    nil
+  end
+
+  def perform_data_query
+    sql = <<-SQL.squish
+      SELECT axis.*, (
+        WITH new_reports AS (
+          SELECT reports.id
+          FROM reports
+          INNER JOIN accounts ON accounts.id = reports.target_account_id
+          WHERE date_trunc('day', reports.created_at)::date = axis.period
+            AND accounts.domain = $3::text
+        )
+        SELECT count(*) FROM new_reports
+      ) AS value
+      FROM (
+        SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period
+      ) AS axis
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, params[:domain]]])
+
+    rows.map { |row| { date: row['period'], value: row['value'].to_s } }
+  end
+
+  def time_period
+    (@start_at.to_date..@end_at.to_date)
+  end
+
+  def previous_time_period
+    ((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end
diff --git a/app/lib/admin/metrics/measure/instance_statuses_measure.rb b/app/lib/admin/metrics/measure/instance_statuses_measure.rb
new file mode 100644
index 000000000..86b10da6c
--- /dev/null
+++ b/app/lib/admin/metrics/measure/instance_statuses_measure.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+class Admin::Metrics::Measure::InstanceStatusesMeasure < Admin::Metrics::Measure::BaseMeasure
+  def self.with_params?
+    true
+  end
+
+  def key
+    'instance_statuses'
+  end
+
+  def total_in_time_range?
+    false
+  end
+
+  protected
+
+  def perform_total_query
+    Status.joins(:account).merge(Account.where(domain: params[:domain])).count
+  end
+
+  def perform_previous_total_query
+    nil
+  end
+
+  def perform_data_query
+    sql = <<-SQL.squish
+      SELECT axis.*, (
+        WITH new_statuses AS (
+          SELECT statuses.id
+          FROM statuses
+          INNER JOIN accounts ON accounts.id = statuses.account_id
+          WHERE statuses.id BETWEEN $3 AND $4
+            AND accounts.domain = $5::text
+            AND date_trunc('day', statuses.created_at)::date = axis.period
+        )
+        SELECT count(*) FROM new_statuses
+      ) AS value
+      FROM (
+        SELECT generate_series(date_trunc('day', $1::timestamp)::date, date_trunc('day', $2::timestamp)::date, interval '1 day') AS period
+      ) AS axis
+    SQL
+
+    rows = ActiveRecord::Base.connection.select_all(sql, nil, [[nil, @start_at], [nil, @end_at], [nil, Mastodon::Snowflake.id_at(@start_at, with_random: false)], [nil, Mastodon::Snowflake.id_at(@end_at, with_random: false)], [nil, params[:domain]]])
+
+    rows.map { |row| { date: row['period'], value: row['value'].to_s } }
+  end
+
+  def time_period
+    (@start_at.to_date..@end_at.to_date)
+  end
+
+  def previous_time_period
+    ((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
+  end
+
+  def params
+    @params.permit(:domain)
+  end
+end