From 7a737c79cc06e931afef2eaebd971ea0324e0741 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 7 Aug 2019 16:13:34 +0200 Subject: Add number of pending accounts and pending hashtags to admin dashboard (#11514) --- config/locales/en.yml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'config/locales') diff --git a/config/locales/en.yml b/config/locales/en.yml index 20baf634e..7b24df016 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -260,6 +260,8 @@ en: features: Features hidden_service: Federation with hidden services open_reports: open reports + pending_tags: hashtags waiting for review + pending_users: users waiting for review recent_users: Recent users search: Full-text search single_user_mode: Single user mode -- cgit From 94c54997cf6dc3bef2af67a070a61cc10595339c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 7 Aug 2019 17:08:30 +0200 Subject: Fix trending tags returning less items than requested sometimes (#11513) Add better sorting defaults to the hashtags admin UI Add "not reviewed" filter to hashtags admin UI --- app/controllers/admin/tags_controller.rb | 7 ++++--- app/models/tag.rb | 3 ++- app/models/trending_tags.rb | 9 +++++---- app/views/admin/tags/index.html.haml | 1 + config/locales/en.yml | 1 + 5 files changed, 13 insertions(+), 8 deletions(-) (limited to 'config/locales') diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb index ed271aedc..794bb114a 100644 --- a/app/controllers/admin/tags_controller.rb +++ b/app/controllers/admin/tags_controller.rb @@ -36,9 +36,10 @@ module Admin def filtered_tags scope = Tag scope = scope.discoverable if filter_params[:context] == 'directory' - scope = scope.reviewed if filter_params[:review] == 'reviewed' - scope = scope.pending_review if filter_params[:review] == 'pending_review' - scope.reorder(score: :desc) + scope = scope.unreviewed if filter_params[:review] == 'unreviewed' + scope = scope.reviewed.order(reviewed_at: :desc) if filter_params[:review] == 'reviewed' + scope = scope.pending_review.order(requested_review_at: :desc) if filter_params[:review] == 'pending_review' + scope.order(score: :desc) end def filter_params diff --git a/app/models/tag.rb b/app/models/tag.rb index e2fe91da1..1364d1dba 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -30,7 +30,8 @@ class Tag < ApplicationRecord validate :validate_name_change, if: -> { !new_record? && name_changed? } scope :reviewed, -> { where.not(reviewed_at: nil) } - scope :pending_review, -> { where(reviewed_at: nil).where.not(requested_review_at: nil) } + scope :unreviewed, -> { where(reviewed_at: nil) } + scope :pending_review, -> { unreviewed.where.not(requested_review_at: nil) } scope :usable, -> { where(usable: [true, nil]) } scope :discoverable, -> { where(listable: [true, nil]).joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) } scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) } diff --git a/app/models/trending_tags.rb b/app/models/trending_tags.rb index 0a7e2feac..594ae9520 100644 --- a/app/models/trending_tags.rb +++ b/app/models/trending_tags.rb @@ -5,6 +5,7 @@ class TrendingTags EXPIRE_HISTORY_AFTER = 7.days.seconds EXPIRE_TRENDS_AFTER = 1.day.seconds THRESHOLD = 5 + LIMIT = 10 class << self include Redisable @@ -18,18 +19,18 @@ class TrendingTags end def get(limit, filtered: true) - tag_ids = redis.zrevrange("#{KEY}:#{Time.now.utc.beginning_of_day.to_i}", 0, limit - 1).map(&:to_i) + tag_ids = redis.zrevrange("#{KEY}:#{Time.now.utc.beginning_of_day.to_i}", 0, LIMIT - 1).map(&:to_i) tags = Tag.where(id: tag_ids) tags = tags.where(trendable: true) if filtered tags = tags.each_with_object({}) { |tag, h| h[tag.id] = tag } - tag_ids.map { |tag_id| tags[tag_id] }.compact + tag_ids.map { |tag_id| tags[tag_id] }.compact.take(limit) end def trending?(tag) rank = redis.zrevrank("#{KEY}:#{Time.now.utc.beginning_of_day.to_i}", tag.id) - rank.present? && rank <= 10 + rank.present? && rank <= LIMIT end private @@ -59,7 +60,7 @@ class TrendingTags old_rank = redis.zrevrank(key, tag.id) redis.zadd(key, score, tag.id) - request_review!(tag) if (old_rank.nil? || old_rank > 10) && redis.zrevrank(key, tag.id) <= 10 && !tag.trendable? && tag.requires_review? && !tag.requested_review? + request_review!(tag) if (old_rank.nil? || old_rank > LIMIT) && redis.zrevrank(key, tag.id) <= LIMIT && !tag.trendable? && tag.requires_review? && !tag.requested_review? end redis.expire(key, EXPIRE_TRENDS_AFTER) diff --git a/app/views/admin/tags/index.html.haml b/app/views/admin/tags/index.html.haml index 5e4ee21f5..d994955ef 100644 --- a/app/views/admin/tags/index.html.haml +++ b/app/views/admin/tags/index.html.haml @@ -12,6 +12,7 @@ %strong= t('admin.tags.review') %ul %li= filter_link_to t('generic.all'), review: nil + %li= filter_link_to t('admin.tags.unreviewed'), review: 'unreviewed' %li= filter_link_to t('admin.tags.reviewed'), review: 'reviewed' %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), review: 'pending_review' diff --git a/config/locales/en.yml b/config/locales/en.yml index 7b24df016..17ff24726 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -498,6 +498,7 @@ en: title: Hashtags trending_right_now: Trending right now unique_uses_today: "%{count} posting today" + unreviewed: Not reviewed updated_msg: Hashtag settings updated successfully title: Administration warning_presets: -- cgit From bced70469a6c4aecdb3c71055f329a0f579eb14c Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 7 Aug 2019 20:20:23 +0200 Subject: Add domain block notes (#11515) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add database columns for adding notes to domain blocks/restrctions * Add admin UI to set private and public comments when blocking a domain * Add text for private and public comments on domain blocks * Show domain block comments in admin UI * Add comments to the domain block undo page * Make UnblockDomainService more robust regarding upgraded domain blocks * Allow editing domain blocks * Rename button from “undo domain block” to “view domain block” in account admin UI * Change test to unsilence silenced users from upgraded blocks --- app/controllers/admin/domain_blocks_controller.rb | 28 ++++++++++++++++++-- app/controllers/admin/instances_controller.rb | 2 ++ app/models/domain_block.rb | 16 +++++++----- app/services/block_domain_service.rb | 11 +++++++- app/services/unblock_domain_service.rb | 19 ++------------ app/views/admin/accounts/show.html.haml | 2 +- app/views/admin/domain_blocks/edit.html.haml | 30 ++++++++++++++++++++++ app/views/admin/domain_blocks/new.html.haml | 6 +++++ app/views/admin/domain_blocks/show.html.haml | 12 +++++++++ app/views/admin/instances/show.html.haml | 13 ++++++++++ app/workers/domain_block_worker.rb | 4 +-- config/locales/en.yml | 8 ++++++ config/routes.rb | 6 ++++- ...20190807135426_add_comments_to_domain_blocks.rb | 7 +++++ db/schema.rb | 4 ++- spec/services/unblock_domain_service_spec.rb | 2 +- spec/workers/domain_block_worker_spec.rb | 2 +- 17 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 app/views/admin/domain_blocks/edit.html.haml create mode 100644 db/migrate/20190807135426_add_comments_to_domain_blocks.rb (limited to 'config/locales') diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb index 7129656da..74a36b79c 100644 --- a/app/controllers/admin/domain_blocks_controller.rb +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -2,13 +2,17 @@ module Admin class DomainBlocksController < BaseController - before_action :set_domain_block, only: [:show, :destroy] + before_action :set_domain_block, only: [:show, :destroy, :edit, :update] def new authorize :domain_block, :create? @domain_block = DomainBlock.new(domain: params[:_domain]) end + def edit + authorize :domain_block, :create? + end + def create authorize :domain_block, :create? @@ -35,6 +39,22 @@ module Admin end end + def update + authorize :domain_block, :create? + + @domain_block.update(update_params) + + severity_changed = @domain_block.severity_changed? + + if @domain_block.save + DomainBlockWorker.perform_async(@domain_block.id, severity_changed) + log_action :create, @domain_block + redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg') + else + render :edit + end + end + def show authorize @domain_block, :show? end @@ -52,8 +72,12 @@ module Admin @domain_block = DomainBlock.find(params[:id]) end + def update_params + params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment) + end + def resource_params - params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports) + params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment) end end end diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index d4f201807..b47b18f8e 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -21,6 +21,8 @@ module Admin @blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count @available = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url) @media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size) + @private_comment = @domain_block&.private_comment + @public_comment = @domain_block&.public_comment end private diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index 25d3b87ef..3f5b9f23e 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -3,13 +3,15 @@ # # Table name: domain_blocks # -# id :bigint(8) not null, primary key -# domain :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# severity :integer default("silence") -# reject_media :boolean default(FALSE), not null -# reject_reports :boolean default(FALSE), not null +# id :bigint(8) not null, primary key +# domain :string default(""), not null +# created_at :datetime not null +# updated_at :datetime not null +# severity :integer default("silence") +# reject_media :boolean default(FALSE), not null +# reject_reports :boolean default(FALSE), not null +# private_comment :text +# public_comment :text # class DomainBlock < ApplicationRecord diff --git a/app/services/block_domain_service.rb b/app/services/block_domain_service.rb index c5e5e5761..0ec6be503 100644 --- a/app/services/block_domain_service.rb +++ b/app/services/block_domain_service.rb @@ -3,13 +3,22 @@ class BlockDomainService < BaseService attr_reader :domain_block - def call(domain_block) + def call(domain_block, update = false) @domain_block = domain_block process_domain_block! + process_retroactive_updates! if update end private + def process_retroactive_updates! + # If the domain block severity has been changed, undo the appropriate limitations + scope = Account.by_domain_and_subdomains(domain_block.domain) + + scope.where(silenced_at: domain_block.created_at).in_batches.update_all(silenced_at: nil) unless domain_block.silence? + scope.where(suspended_at: domain_block.created_at).in_batches.update_all(suspended_at: nil) unless domain_block.suspend? + end + def process_domain_block! clear_media! if domain_block.reject_media? diff --git a/app/services/unblock_domain_service.rb b/app/services/unblock_domain_service.rb index fc262a50a..d502d9e49 100644 --- a/app/services/unblock_domain_service.rb +++ b/app/services/unblock_domain_service.rb @@ -10,24 +10,9 @@ class UnblockDomainService < BaseService end def process_retroactive_updates - blocked_accounts.in_batches.update_all(update_options) unless domain_block.noop? - end - - def blocked_accounts scope = Account.by_domain_and_subdomains(domain_block.domain) - if domain_block.silence? - scope.where(silenced_at: @domain_block.created_at) - else - scope.where(suspended_at: @domain_block.created_at) - end - end - - def update_options - { domain_block_impact => nil } - end - - def domain_block_impact - domain_block.silence? ? :silenced_at : :suspended_at + scope.where(silenced_at: domain_block.created_at).in_batches.update_all(silenced_at: nil) unless domain_block.noop? + scope.where(suspended_at: domain_block.created_at).in_batches.update_all(suspended_at: nil) if domain_block.suspend? end end diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index 7494c9fa2..59babd3b0 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -174,7 +174,7 @@ - unless @account.local? - if DomainBlock.where(domain: @account.domain).exists? - = link_to t('admin.domain_blocks.undo'), admin_instance_path(@account.domain), class: 'button' + = link_to t('admin.domain_blocks.view'), admin_instance_path(@account.domain), class: 'button' - else = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive' diff --git a/app/views/admin/domain_blocks/edit.html.haml b/app/views/admin/domain_blocks/edit.html.haml new file mode 100644 index 000000000..29e47ef3b --- /dev/null +++ b/app/views/admin/domain_blocks/edit.html.haml @@ -0,0 +1,30 @@ +- content_for :header_tags do + = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous' + +- content_for :page_title do + = t('admin.domain_blocks.edit') + += simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :put do |f| + = render 'shared/error_messages', object: @domain_block + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :domain, wrapper: :with_label, label: t('admin.domain_blocks.domain'), hint: t('admin.domain_blocks.new.hint'), required: true, readonly: true, disabled: true + + .fields-row__column.fields-row__column-6.fields-group + = f.input :severity, collection: DomainBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| t("admin.domain_blocks.new.severity.#{type}") }, hint: t('admin.domain_blocks.new.severity.desc_html') + + .fields-group + = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint') + + .fields-group + = f.input :reject_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint') + + .field-group + = f.input :private_comment, wrapper: :with_label, label: I18n.t('admin.domain_blocks.private_comment'), hint: t('admin.domain_blocks.private_comment_hint'), rows: 6 + + .field-group + = f.input :public_comment, wrapper: :with_label, label: I18n.t('admin.domain_blocks.public_comment'), hint: t('admin.domain_blocks.public_comment_hint'), rows: 6 + + .actions + = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/domain_blocks/new.html.haml b/app/views/admin/domain_blocks/new.html.haml index 055d2fbd7..ed1581936 100644 --- a/app/views/admin/domain_blocks/new.html.haml +++ b/app/views/admin/domain_blocks/new.html.haml @@ -20,5 +20,11 @@ .fields-group = f.input :reject_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint') + .field-group + = f.input :private_comment, wrapper: :with_label, label: I18n.t('admin.domain_blocks.private_comment'), hint: t('admin.domain_blocks.private_comment_hint'), rows: 6 + + .field-group + = f.input :public_comment, wrapper: :with_label, label: I18n.t('admin.domain_blocks.public_comment'), hint: t('admin.domain_blocks.public_comment_hint'), rows: 6 + .actions = f.button :button, t('.create'), type: :submit diff --git a/app/views/admin/domain_blocks/show.html.haml b/app/views/admin/domain_blocks/show.html.haml index dca4dbac7..e64aaa629 100644 --- a/app/views/admin/domain_blocks/show.html.haml +++ b/app/views/admin/domain_blocks/show.html.haml @@ -1,6 +1,18 @@ - content_for :page_title do = t('admin.domain_blocks.show.title', domain: @domain_block.domain) +- if @domain_block.private_comment.present? + .speech-bubble + .speech-bubble__bubble + = simple_format(h(@domain_block.private_comment)) + .speech-bubble__owner= t 'admin.instances.private_comment' + +- if @domain_block.public_comment.present? + .speech-bubble + .speech-bubble__bubble + = simple_format(h(@domain_block.public_comment)) + .speech-bubble__owner= t 'admin.instances.public_comment' + = simple_form_for @domain_block, url: admin_domain_block_path(@domain_block), method: :delete do |f| - unless (@domain_block.noop?) diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml index fbb49ba02..294c9495d 100644 --- a/app/views/admin/instances/show.html.haml +++ b/app/views/admin/instances/show.html.haml @@ -31,6 +31,18 @@ = fa_icon 'times' .dashboard__counters__label= t 'admin.instances.delivery_available' +- if @private_comment.present? + .speech-bubble + .speech-bubble__bubble + = simple_format(h(@private_comment)) + .speech-bubble__owner= t 'admin.instances.private_comment' + +- if @public_comment.present? + .speech-bubble + .speech-bubble__bubble + = simple_format(h(@public_comment)) + .speech-bubble__owner= t 'admin.instances.public_comment' + %hr.spacer/ %div{ style: 'overflow: hidden' } @@ -41,6 +53,7 @@ - if @domain_allow = link_to t('admin.domain_allows.undo'), admin_domain_allow_path(@domain_allow), class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure'), method: :delete } - elsif @domain_block + = link_to t('admin.domain_blocks.edit'), edit_admin_domain_block_path(@domain_block), class: 'button' = link_to t('admin.domain_blocks.undo'), admin_domain_block_path(@domain_block), class: 'button' - else = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button' diff --git a/app/workers/domain_block_worker.rb b/app/workers/domain_block_worker.rb index 884477829..35518d6b5 100644 --- a/app/workers/domain_block_worker.rb +++ b/app/workers/domain_block_worker.rb @@ -3,8 +3,8 @@ class DomainBlockWorker include Sidekiq::Worker - def perform(domain_block_id) - BlockDomainService.new.call(DomainBlock.find(domain_block_id)) + def perform(domain_block_id, update = false) + BlockDomainService.new.call(DomainBlock.find(domain_block_id), update) rescue ActiveRecord::RecordNotFound true end diff --git a/config/locales/en.yml b/config/locales/en.yml index 17ff24726..b677a6651 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -284,6 +284,7 @@ en: created_msg: Domain block is now being processed destroyed_msg: Domain block has been undone domain: Domain + edit: Edit domain block existing_domain_block_html: You have already imposed stricter limits on %{name}, you need to unblock it first. new: create: Create block @@ -294,6 +295,10 @@ en: silence: Silence suspend: Suspend title: New domain block + private_comment: Private comment + private_comment_hint: Comment about this domain limitation for internal use by the moderators. + public_comment: Public comment + public_comment_hint: Comment about this domain limitation for the general public, if advertising the list of domain limitations is enabled. reject_media: Reject media files reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions reject_reports: Reject reports @@ -313,6 +318,7 @@ en: title: Undo domain block for %{domain} undo: Undo undo: Undo domain block + view: View domain block email_domain_blocks: add_new: Add new created_msg: Successfully added e-mail domain to blacklist @@ -336,6 +342,8 @@ en: all: All limited: Limited title: Moderation + private_comment: Private comment + public_comment: Public comment title: Federation total_blocked_by_us: Blocked by us total_followed_by_them: Followed by them diff --git a/config/routes.rb b/config/routes.rb index 60f7d2e05..9c33b8190 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -155,7 +155,11 @@ Rails.application.routes.draw do get '/dashboard', to: 'dashboard#index' resources :domain_allows, only: [:new, :create, :show, :destroy] - resources :domain_blocks, only: [:new, :create, :show, :destroy] + resources :domain_blocks, only: [:new, :create, :show, :destroy, :update] do + member do + get :edit + end + end resources :email_domain_blocks, only: [:index, :new, :create, :destroy] resources :action_logs, only: [:index] resources :warning_presets, except: [:new] diff --git a/db/migrate/20190807135426_add_comments_to_domain_blocks.rb b/db/migrate/20190807135426_add_comments_to_domain_blocks.rb new file mode 100644 index 000000000..b660a71ad --- /dev/null +++ b/db/migrate/20190807135426_add_comments_to_domain_blocks.rb @@ -0,0 +1,7 @@ +class AddCommentsToDomainBlocks < ActiveRecord::Migration[5.2] + def change + add_column :domain_blocks, :private_comment, :text + add_column :domain_blocks, :public_comment, :text + end +end + diff --git a/db/schema.rb b/db/schema.rb index d1b6825b4..f8fc6a821 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_08_05_123746) do +ActiveRecord::Schema.define(version: 2019_08_07_135426) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -259,6 +259,8 @@ ActiveRecord::Schema.define(version: 2019_08_05_123746) do t.integer "severity", default: 0 t.boolean "reject_media", default: false, null: false t.boolean "reject_reports", default: false, null: false + t.text "private_comment" + t.text "public_comment" t.index ["domain"], name: "index_domain_blocks_on_domain", unique: true end diff --git a/spec/services/unblock_domain_service_spec.rb b/spec/services/unblock_domain_service_spec.rb index 619aefb5c..27dbc92ad 100644 --- a/spec/services/unblock_domain_service_spec.rb +++ b/spec/services/unblock_domain_service_spec.rb @@ -31,7 +31,7 @@ describe UnblockDomainService, type: :service do subject.call(@domain_block) expect_deleted_domain_block expect(@suspended.reload.suspended?).to be false - expect(@silenced.reload.silenced?).to be true + expect(@silenced.reload.silenced?).to be false expect(@independently_suspended.reload.suspended?).to be true expect(@independently_silenced.reload.silenced?).to be true end diff --git a/spec/workers/domain_block_worker_spec.rb b/spec/workers/domain_block_worker_spec.rb index c4138501f..48b3e38c4 100644 --- a/spec/workers/domain_block_worker_spec.rb +++ b/spec/workers/domain_block_worker_spec.rb @@ -14,7 +14,7 @@ describe DomainBlockWorker do result = subject.perform(domain_block.id) expect(result).to be_nil - expect(service).to have_received(:call).with(domain_block) + expect(service).to have_received(:call).with(domain_block, false) end it 'calls domain block service for relevant domain block' do -- cgit From 3a6b6c63f22e31c9b113428d6c69be451a3bcc17 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 7 Aug 2019 20:20:39 +0200 Subject: Add breakdown of usage by source to admin UI for hashtags (#11517) Allows determining where the majority of posts in a hashtag come from on a given day at a glance. --- app/controllers/admin/tags_controller.rb | 25 +++++++++++++++++++++++++ app/views/admin/tags/show.html.haml | 29 +++++++++++++++++++++++++++++ config/locales/en.yml | 3 +++ 3 files changed, 57 insertions(+) (limited to 'config/locales') diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb index 794bb114a..d62361eaa 100644 --- a/app/controllers/admin/tags_controller.rb +++ b/app/controllers/admin/tags_controller.rb @@ -4,6 +4,8 @@ module Admin class TagsController < BaseController before_action :set_tags, only: :index before_action :set_tag, except: :index + before_action :set_usage_by_domain, except: :index + before_action :set_counters, except: :index def index authorize :tag, :index? @@ -33,6 +35,21 @@ module Admin @tag = Tag.find(params[:id]) end + def set_usage_by_domain + @usage_by_domain = @tag.statuses + .where(visibility: :public) + .where(Status.arel_table[:id].gteq(Mastodon::Snowflake.id_at(Time.now.utc.beginning_of_day))) + .joins(:account) + .group('accounts.domain') + .reorder('statuses_count desc') + .pluck('accounts.domain, count(*) AS statuses_count') + end + + def set_counters + @accounts_today = @tag.history.first[:accounts] + @accounts_week = Redis.current.pfcount(*current_week_days.map { |day| "activity:tags:#{@tag.id}:#{day}:accounts" }) + end + def filtered_tags scope = Tag scope = scope.discoverable if filter_params[:context] == 'directory' @@ -49,5 +66,13 @@ module Admin def tag_params params.require(:tag).permit(:name, :trendable, :usable, :listable) end + + def current_week_days + now = Time.now.utc.beginning_of_day.to_date + + (Date.commercial(now.cwyear, now.cweek)..now).map do |date| + date.to_time.utc.beginning_of_day.to_i + end + end end end diff --git a/app/views/admin/tags/show.html.haml b/app/views/admin/tags/show.html.haml index 5f3a8e4d9..6a1e03065 100644 --- a/app/views/admin/tags/show.html.haml +++ b/app/views/admin/tags/show.html.haml @@ -1,6 +1,22 @@ - content_for :page_title do = "##{@tag.name}" +.dashboard__counters + %div + = link_to web_url("timelines/tag/#{@tag.name}") do + .dashboard__counters__num= number_with_delimiter @accounts_today + .dashboard__counters__label= t 'admin.tags.accounts_today' + %div + %div + .dashboard__counters__num= number_with_delimiter @accounts_week + .dashboard__counters__label= t 'admin.tags.accounts_week' + %div + = link_to explore_hashtag_path(@tag) do + .dashboard__counters__num= number_with_delimiter @tag.accounts_count + .dashboard__counters__label= t 'admin.tags.directory' + +%hr.spacer/ + = simple_form_for @tag, url: admin_tag_path(@tag.id) do |f| = render 'shared/error_messages', object: @tag @@ -14,3 +30,16 @@ .actions = f.button :button, t('generic.save_changes'), type: :submit + +%hr.spacer/ + +%h3= t 'admin.tags.breakdown' + +.table-wrapper + %table.table + %tbody + - @usage_by_domain.each do |(domain, count)| + %tr + %th= domain || site_hostname + %td= "#{number_with_delimiter((count.to_f / @tag.history[0][:uses].to_f) * 100)}%" + %td= number_with_delimiter count diff --git a/config/locales/en.yml b/config/locales/en.yml index b677a6651..7fd0536ae 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -498,6 +498,9 @@ en: title: Account statuses with_media: With media tags: + accounts_today: Unique uses today + accounts_week: Unique uses this week + breakdown: Breakdown of today's usage by source context: Context directory: In directory in_directory: "%{count} in directory" -- cgit