Merge tag 'v3.4.0' into hometown-dev

This commit is contained in:
Darius Kazemi
2021-05-17 13:48:27 -07:00
897 changed files with 26918 additions and 14941 deletions

View File

@ -1,4 +1,4 @@
class AddUrlToStatuses < ActiveRecord::Migration[4.2]
class AddURLToStatuses < ActiveRecord::Migration[4.2]
def change
add_column :statuses, :url, :string, null: true, default: nil
end

View File

@ -1,4 +1,4 @@
class AddUrlToAccounts < ActiveRecord::Migration[4.2]
class AddURLToAccounts < ActiveRecord::Migration[4.2]
def change
add_column :accounts, :url, :string, null: true, default: nil
end

View File

@ -1,4 +1,4 @@
class AddAvatarRemoteUrlToAccounts < ActiveRecord::Migration[4.2]
class AddAvatarRemoteURLToAccounts < ActiveRecord::Migration[4.2]
def change
add_column :accounts, :avatar_remote_url, :string, null: true, default: nil
end

View File

@ -7,12 +7,12 @@ end
class RailsSettingsMigration < MIGRATION_BASE_CLASS
def self.up
create_table :settings do |t|
t.string :var, :null => false
t.string :var, null: false
t.text :value
t.references :target, :null => false, :polymorphic => true
t.timestamps :null => true
t.references :target, null: false, polymorphic: true, index: { name: 'index_settings_on_target_type_and_target_id' }
t.timestamps null: true
end
add_index :settings, [ :target_type, :target_id, :var ], :unique => true
add_index :settings, [ :target_type, :target_id, :var ], unique: true
end
def self.down

View File

@ -1,4 +1,4 @@
class AddHeaderRemoteUrlToAccounts < ActiveRecord::Migration[5.0]
class AddHeaderRemoteURLToAccounts < ActiveRecord::Migration[5.0]
def change
add_column :accounts, :header_remote_url, :string, null: false, default: ''
end

View File

@ -1,7 +1,7 @@
class StatusIdsToTimestampIds < ActiveRecord::Migration[5.1]
def up
# Prepare the function we will use to generate IDs.
Rake::Task['db:define_timestamp_id'].execute
Mastodon::Snowflake.define_timestamp_id
# Set up the statuses.id column to use our timestamp-based IDs.
ActiveRecord::Base.connection.execute(<<~SQL)
@ -11,7 +11,7 @@ class StatusIdsToTimestampIds < ActiveRecord::Migration[5.1]
SQL
# Make sure we have a sequence to use.
Rake::Task['db:ensure_id_sequences_exist'].execute
Mastodon::Snowflake.ensure_id_sequences_exist
end
def down

View File

@ -3,7 +3,7 @@ class CreateAdminActionLogs < ActiveRecord::Migration[5.1]
create_table :admin_action_logs do |t|
t.belongs_to :account, foreign_key: { on_delete: :cascade }
t.string :action, null: false, default: ''
t.references :target, polymorphic: true
t.references :target, polymorphic: true, index: { name: 'index_admin_action_logs_on_target_type_and_target_id' }
t.text :recorded_changes, null: false, default: ''
t.timestamps

View File

@ -1,6 +1,6 @@
require Rails.root.join('lib', 'mastodon', 'migration_helpers')
class AddEmbedUrlToPreviewCards < ActiveRecord::Migration[5.1]
class AddEmbedURLToPreviewCards < ActiveRecord::Migration[5.1]
include Mastodon::MigrationHelpers
disable_ddl_transaction!

View File

@ -1,4 +1,4 @@
class AddFeaturedCollectionUrlToAccounts < ActiveRecord::Migration[5.1]
class AddFeaturedCollectionURLToAccounts < ActiveRecord::Migration[5.1]
def change
add_column :accounts, :featured_collection_url, :string
end

View File

@ -37,7 +37,7 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
end
end
duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_hash
duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_ary
duplicates.each do |row|
deduplicate_account!(row['ids'].split(','))

View File

@ -17,8 +17,8 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2]
belongs_to :account, optional: true
belongs_to :activity, polymorphic: true, optional: true
belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', optional: true
belongs_to :mention, foreign_type: 'Mention', foreign_key: 'activity_id', optional: true
belongs_to :status, foreign_key: 'activity_id', optional: true
belongs_to :mention, foreign_key: 'activity_id', optional: true
def target_status
mention&.status

View File

@ -2,7 +2,7 @@ class DowncaseCustomEmojiDomains < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_hash
duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_ary
duplicates.each do |row|
CustomEmoji.where(id: row['ids'].split(',')[0...-1]).destroy_all

View File

@ -2,7 +2,7 @@ class AddCaseInsensitiveIndexToTags < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_hash.each do |row|
Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_ary.each do |row|
canonical_tag_id = row['ids'].split(',').first
redundant_tag_ids = row['ids'].split(',')[1..-1]

View File

@ -5,7 +5,7 @@ class ResetUniqueJobsLocks < ActiveRecord::Migration[5.2]
# We do this to clean up unique job digests that were not properly
# disposed of prior to https://github.com/tootsuite/mastodon/pull/13361
SidekiqUniqueJobs::Digests.delete_by_pattern('*', count: SidekiqUniqueJobs::Digests.count)
until SidekiqUniqueJobs::Digests.new.delete_by_pattern('*').nil?; end
end
def down; end

View File

@ -1,4 +1,4 @@
class AddDevicesUrlToAccounts < ActiveRecord::Migration[5.2]
class AddDevicesURLToAccounts < ActiveRecord::Migration[5.2]
def change
add_column :accounts, :devices_url, :string
end

View File

@ -0,0 +1,11 @@
class CreateRules < ActiveRecord::Migration[5.2]
def change
create_table :rules do |t|
t.integer :priority, null: false, default: 0
t.datetime :deleted_at
t.text :text, null: false, default: ''
t.timestamps
end
end
end

View File

@ -0,0 +1,17 @@
class AccountIdsToTimestampIds < ActiveRecord::Migration[5.1]
def up
# Set up the accounts.id column to use our timestamp-based IDs.
safety_assured do
execute("ALTER TABLE accounts ALTER COLUMN id SET DEFAULT timestamp_id('accounts')")
end
# Make sure we have a sequence to use.
Mastodon::Snowflake.ensure_id_sequences_exist
end
def down
execute("LOCK accounts")
execute("SELECT setval('accounts_id_seq', (SELECT MAX(id) FROM accounts))")
execute("ALTER TABLE accounts ALTER COLUMN id SET DEFAULT nextval('accounts_id_seq')")
end
end

View File

@ -0,0 +1,9 @@
class CreateAccountSummaries < ActiveRecord::Migration[5.2]
def change
create_view :account_summaries, materialized: { no_data: true }
# To be able to refresh the view concurrently,
# at least one unique index is required
safety_assured { add_index :account_summaries, :account_id, unique: true }
end
end

View File

@ -0,0 +1,5 @@
class CreateFollowRecommendations < ActiveRecord::Migration[5.2]
def change
create_view :follow_recommendations
end
end

View File

@ -0,0 +1,9 @@
class CreateFollowRecommendationSuppressions < ActiveRecord::Migration[6.1]
def change
create_table :follow_recommendation_suppressions do |t|
t.references :account, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true }
t.timestamps
end
end
end

View File

@ -0,0 +1,10 @@
class CreateCanonicalEmailBlocks < ActiveRecord::Migration[6.1]
def change
create_table :canonical_email_blocks do |t|
t.string :canonical_email_hash, null: false, default: '', index: { unique: true }
t.belongs_to :reference_account, null: false, foreign_key: { on_cascade: :delete, to_table: 'accounts' }
t.timestamps
end
end
end

View File

@ -0,0 +1,13 @@
class AddCaseInsensitiveBtreeIndexToTags < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
safety_assured { execute 'CREATE UNIQUE INDEX CONCURRENTLY index_tags_on_name_lower_btree ON tags (lower(name) text_pattern_ops)' }
remove_index :tags, name: 'index_tags_on_name_lower'
end
def down
safety_assured { execute 'CREATE UNIQUE INDEX CONCURRENTLY index_tags_on_name_lower ON tags (lower(name))' }
remove_index :tags, name: 'index_tags_on_name_lower_btree'
end
end

View File

@ -0,0 +1,13 @@
class AddIndexOnMediaAttachmentsAccountIdStatusId < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_index :media_attachments, [:account_id, :status_id], order: { status_id: :desc }, algorithm: :concurrently
remove_index :media_attachments, :account_id, algorithm: :concurrently
end
def down
add_index :media_attachments, :account_id, algorithm: :concurrently
remove_index :media_attachments, [:account_id, :status_id], order: { status_id: :desc }, algorithm: :concurrently
end
end

View File

@ -0,0 +1,18 @@
class UpdateFollowRecommendationsToVersion2 < ActiveRecord::Migration[6.1]
# We're switching from a normal to a materialized view so we need
# custom `up` and `down` paths.
def up
drop_view :follow_recommendations
create_view :follow_recommendations, version: 2, materialized: { no_data: true }
# To be able to refresh the view concurrently,
# at least one unique index is required
safety_assured { add_index :follow_recommendations, :account_id, unique: true }
end
def down
drop_view :follow_recommendations, materialized: true
create_view :follow_recommendations, version: 1
end
end

View File

@ -0,0 +1,7 @@
class RemoveSubscriptionExpiresAtFromAccounts < ActiveRecord::Migration[5.0]
def change
safety_assured do
remove_column :accounts, :subscription_expires_at, :datetime, null: true, default: nil
end
end
end

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class DropAccountTagStats < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
drop_table :account_tag_stats
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
class RemoveHubURLFromAccounts < ActiveRecord::Migration[5.2]
def change
safety_assured do
remove_column :accounts, :secret, :string, null: false, default: ''
remove_column :accounts, :remote_url, :string, null: false, default: ''
remove_column :accounts, :salmon_url, :string, null: false, default: ''
remove_column :accounts, :hub_url, :string, null: false, default: ''
end
end
end

View File

@ -2,15 +2,15 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_12_18_054746) do
ActiveRecord::Schema.define(version: 2021_05_07_001928) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -115,15 +115,6 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.index ["account_id"], name: "index_account_stats_on_account_id", unique: true
end
create_table "account_tag_stats", force: :cascade do |t|
t.bigint "tag_id", null: false
t.bigint "accounts_count", default: 0, null: false
t.boolean "hidden", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["tag_id"], name: "index_account_tag_stats_on_tag_id", unique: true
end
create_table "account_warning_presets", force: :cascade do |t|
t.text "text", default: "", null: false
t.datetime "created_at", null: false
@ -142,15 +133,11 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.index ["target_account_id"], name: "index_account_warnings_on_target_account_id"
end
create_table "accounts", force: :cascade do |t|
create_table "accounts", id: :bigint, default: -> { "timestamp_id('accounts'::text)" }, force: :cascade do |t|
t.string "username", default: "", null: false
t.string "domain"
t.string "secret", default: "", null: false
t.text "private_key"
t.text "public_key", default: "", null: false
t.string "remote_url", default: "", null: false
t.string "salmon_url", default: "", null: false
t.string "hub_url", default: "", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "note", default: "", null: false
@ -166,7 +153,6 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.integer "header_file_size"
t.datetime "header_updated_at"
t.string "avatar_remote_url"
t.datetime "subscription_expires_at"
t.boolean "locked", default: false, null: false
t.string "header_remote_url", default: "", null: false
t.datetime "last_webfingered_at"
@ -281,6 +267,15 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.index ["status_id"], name: "index_bookmarks_on_status_id"
end
create_table "canonical_email_blocks", force: :cascade do |t|
t.string "canonical_email_hash", default: "", null: false
t.bigint "reference_account_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["canonical_email_hash"], name: "index_canonical_email_blocks_on_canonical_email_hash", unique: true
t.index ["reference_account_id"], name: "index_canonical_email_blocks_on_reference_account_id"
end
create_table "conversation_mutes", force: :cascade do |t|
t.bigint "conversation_id", null: false
t.bigint "account_id", null: false
@ -407,6 +402,13 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.index ["tag_id"], name: "index_featured_tags_on_tag_id"
end
create_table "follow_recommendation_suppressions", force: :cascade do |t|
t.bigint "account_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["account_id"], name: "index_follow_recommendation_suppressions_on_account_id", unique: true
end
create_table "follow_requests", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -527,7 +529,7 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.integer "thumbnail_file_size"
t.datetime "thumbnail_updated_at"
t.string "thumbnail_remote_url"
t.index ["account_id"], name: "index_media_attachments_on_account_id"
t.index ["account_id", "status_id"], name: "index_media_attachments_on_account_id_and_status_id", order: { status_id: :desc }
t.index ["scheduled_status_id"], name: "index_media_attachments_on_scheduled_status_id"
t.index ["shortcode"], name: "index_media_attachments_on_shortcode", unique: true
t.index ["status_id"], name: "index_media_attachments_on_status_id"
@ -724,6 +726,14 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.index ["target_account_id"], name: "index_reports_on_target_account_id"
end
create_table "rules", force: :cascade do |t|
t.integer "priority", default: 0, null: false
t.datetime "deleted_at"
t.text "text", default: "", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "scheduled_statuses", force: :cascade do |t|
t.bigint "account_id"
t.datetime "scheduled_at"
@ -842,7 +852,7 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
t.datetime "last_status_at"
t.float "max_score"
t.datetime "max_score_at"
t.index "lower((name)::text)", name: "index_tags_on_name_lower", unique: true
t.index "lower((name)::text) text_pattern_ops", name: "index_tags_on_name_lower_btree", unique: true
end
create_table "tombstones", force: :cascade do |t|
@ -965,7 +975,6 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
add_foreign_key "account_pins", "accounts", column: "target_account_id", on_delete: :cascade
add_foreign_key "account_pins", "accounts", on_delete: :cascade
add_foreign_key "account_stats", "accounts", on_delete: :cascade
add_foreign_key "account_tag_stats", "tags", on_delete: :cascade
add_foreign_key "account_warnings", "accounts", column: "target_account_id", on_delete: :cascade
add_foreign_key "account_warnings", "accounts", on_delete: :nullify
add_foreign_key "accounts", "accounts", column: "moved_to_account_id", on_delete: :nullify
@ -980,6 +989,7 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade
add_foreign_key "bookmarks", "accounts", on_delete: :cascade
add_foreign_key "bookmarks", "statuses", on_delete: :cascade
add_foreign_key "canonical_email_blocks", "accounts", column: "reference_account_id"
add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade
add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade
add_foreign_key "custom_filters", "accounts", on_delete: :cascade
@ -992,6 +1002,7 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
add_foreign_key "favourites", "statuses", name: "fk_b0e856845e", on_delete: :cascade
add_foreign_key "featured_tags", "accounts", on_delete: :cascade
add_foreign_key "featured_tags", "tags", on_delete: :cascade
add_foreign_key "follow_recommendation_suppressions", "accounts", on_delete: :cascade
add_foreign_key "follow_requests", "accounts", column: "target_account_id", name: "fk_9291ec025d", on_delete: :cascade
add_foreign_key "follow_requests", "accounts", name: "fk_76d644b0e7", on_delete: :cascade
add_foreign_key "follows", "accounts", column: "target_account_id", name: "fk_745ca29eac", on_delete: :cascade
@ -1075,4 +1086,51 @@ ActiveRecord::Schema.define(version: 2020_12_18_054746) do
SQL
add_index "instances", ["domain"], name: "index_instances_on_domain", unique: true
create_view "account_summaries", materialized: true, sql_definition: <<-SQL
SELECT accounts.id AS account_id,
mode() WITHIN GROUP (ORDER BY t0.language) AS language,
mode() WITHIN GROUP (ORDER BY t0.sensitive) AS sensitive
FROM (accounts
CROSS JOIN LATERAL ( SELECT statuses.account_id,
statuses.language,
statuses.sensitive
FROM statuses
WHERE ((statuses.account_id = accounts.id) AND (statuses.deleted_at IS NULL))
ORDER BY statuses.id DESC
LIMIT 20) t0)
WHERE ((accounts.suspended_at IS NULL) AND (accounts.silenced_at IS NULL) AND (accounts.moved_to_account_id IS NULL) AND (accounts.discoverable = true) AND (accounts.locked = false))
GROUP BY accounts.id;
SQL
add_index "account_summaries", ["account_id"], name: "index_account_summaries_on_account_id", unique: true
create_view "follow_recommendations", materialized: true, sql_definition: <<-SQL
SELECT t0.account_id,
sum(t0.rank) AS rank,
array_agg(t0.reason) AS reason
FROM ( SELECT account_summaries.account_id,
((count(follows.id))::numeric / (1.0 + (count(follows.id))::numeric)) AS rank,
'most_followed'::text AS reason
FROM (((follows
JOIN account_summaries ON ((account_summaries.account_id = follows.target_account_id)))
JOIN users ON ((users.account_id = follows.account_id)))
LEFT JOIN follow_recommendation_suppressions ON ((follow_recommendation_suppressions.account_id = follows.target_account_id)))
WHERE ((users.current_sign_in_at >= (now() - 'P30D'::interval)) AND (account_summaries.sensitive = false) AND (follow_recommendation_suppressions.id IS NULL))
GROUP BY account_summaries.account_id
HAVING (count(follows.id) >= 5)
UNION ALL
SELECT account_summaries.account_id,
(sum((status_stats.reblogs_count + status_stats.favourites_count)) / (1.0 + sum((status_stats.reblogs_count + status_stats.favourites_count)))) AS rank,
'most_interactions'::text AS reason
FROM (((status_stats
JOIN statuses ON ((statuses.id = status_stats.status_id)))
JOIN account_summaries ON ((account_summaries.account_id = statuses.account_id)))
LEFT JOIN follow_recommendation_suppressions ON ((follow_recommendation_suppressions.account_id = statuses.account_id)))
WHERE ((statuses.id >= (((date_part('epoch'::text, (now() - 'P30D'::interval)) * (1000)::double precision))::bigint << 16)) AND (account_summaries.sensitive = false) AND (follow_recommendation_suppressions.id IS NULL))
GROUP BY account_summaries.account_id
HAVING (sum((status_stats.reblogs_count + status_stats.favourites_count)) >= (5)::numeric)) t0
GROUP BY t0.account_id
ORDER BY (sum(t0.rank)) DESC;
SQL
add_index "follow_recommendations", ["account_id"], name: "index_follow_recommendations_on_account_id", unique: true
end

View File

@ -0,0 +1,22 @@
SELECT
accounts.id AS account_id,
mode() WITHIN GROUP (ORDER BY language ASC) AS language,
mode() WITHIN GROUP (ORDER BY sensitive ASC) AS sensitive
FROM accounts
CROSS JOIN LATERAL (
SELECT
statuses.account_id,
statuses.language,
statuses.sensitive
FROM statuses
WHERE statuses.account_id = accounts.id
AND statuses.deleted_at IS NULL
ORDER BY statuses.id DESC
LIMIT 20
) t0
WHERE accounts.suspended_at IS NULL
AND accounts.silenced_at IS NULL
AND accounts.moved_to_account_id IS NULL
AND accounts.discoverable = 't'
AND accounts.locked = 'f'
GROUP BY accounts.id

View File

@ -0,0 +1,38 @@
SELECT
account_id,
sum(rank) AS rank,
array_agg(reason) AS reason
FROM (
SELECT
accounts.id AS account_id,
count(follows.id) / (1.0 + count(follows.id)) AS rank,
'most_followed' AS reason
FROM follows
INNER JOIN accounts ON accounts.id = follows.target_account_id
INNER JOIN users ON users.account_id = follows.account_id
WHERE users.current_sign_in_at >= (now() - interval '30 days')
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
AND accounts.silenced_at IS NULL
AND accounts.locked = 'f'
AND accounts.discoverable = 't'
GROUP BY accounts.id
HAVING count(follows.id) >= 5
UNION ALL
SELECT accounts.id AS account_id,
sum(reblogs_count + favourites_count) / (1.0 + sum(reblogs_count + favourites_count)) AS rank,
'most_interactions' AS reason
FROM status_stats
INNER JOIN statuses ON statuses.id = status_stats.status_id
INNER JOIN accounts ON accounts.id = statuses.account_id
WHERE statuses.id >= ((date_part('epoch', now() - interval '30 days') * 1000)::bigint << 16)
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
AND accounts.silenced_at IS NULL
AND accounts.locked = 'f'
AND accounts.discoverable = 't'
GROUP BY accounts.id
HAVING sum(reblogs_count + favourites_count) >= 5
) t0
GROUP BY account_id
ORDER BY rank DESC

View File

@ -0,0 +1,34 @@
SELECT
account_id,
sum(rank) AS rank,
array_agg(reason) AS reason
FROM (
SELECT
account_summaries.account_id AS account_id,
count(follows.id) / (1.0 + count(follows.id)) AS rank,
'most_followed' AS reason
FROM follows
INNER JOIN account_summaries ON account_summaries.account_id = follows.target_account_id
INNER JOIN users ON users.account_id = follows.account_id
LEFT OUTER JOIN follow_recommendation_suppressions ON follow_recommendation_suppressions.account_id = follows.target_account_id
WHERE users.current_sign_in_at >= (now() - interval '30 days')
AND account_summaries.sensitive = 'f'
AND follow_recommendation_suppressions.id IS NULL
GROUP BY account_summaries.account_id
HAVING count(follows.id) >= 5
UNION ALL
SELECT account_summaries.account_id AS account_id,
sum(reblogs_count + favourites_count) / (1.0 + sum(reblogs_count + favourites_count)) AS rank,
'most_interactions' AS reason
FROM status_stats
INNER JOIN statuses ON statuses.id = status_stats.status_id
INNER JOIN account_summaries ON account_summaries.account_id = statuses.account_id
LEFT OUTER JOIN follow_recommendation_suppressions ON follow_recommendation_suppressions.account_id = statuses.account_id
WHERE statuses.id >= ((date_part('epoch', now() - interval '30 days') * 1000)::bigint << 16)
AND account_summaries.sensitive = 'f'
AND follow_recommendation_suppressions.id IS NULL
GROUP BY account_summaries.account_id
HAVING sum(reblogs_count + favourites_count) >= 5
) t0
GROUP BY account_id
ORDER BY rank DESC