Implement UI for Admin Search of Hashtags (#30880)
This commit is contained in:
		@@ -2,7 +2,15 @@
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class TagsController < BaseController
 | 
			
		||||
    before_action :set_tag
 | 
			
		||||
    before_action :set_tag, except: [:index]
 | 
			
		||||
 | 
			
		||||
    PER_PAGE = 20
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :tag, :index?
 | 
			
		||||
 | 
			
		||||
      @tags = filtered_tags.page(params[:page]).per(PER_PAGE)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def show
 | 
			
		||||
      authorize @tag, :show?
 | 
			
		||||
@@ -31,5 +39,13 @@ module Admin
 | 
			
		||||
    def tag_params
 | 
			
		||||
      params.require(:tag).permit(:name, :display_name, :trendable, :usable, :listable)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def filtered_tags
 | 
			
		||||
      TagFilter.new(filter_params.with_defaults(order: 'newest')).results
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def filter_params
 | 
			
		||||
      params.slice(:page, *TagFilter::KEYS).permit(:page, *TagFilter::KEYS)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								app/helpers/admin/tags_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/helpers/admin/tags_helper.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Admin::TagsHelper
 | 
			
		||||
  def admin_tags_moderation_options
 | 
			
		||||
    [
 | 
			
		||||
      [t('admin.tags.moderation.reviewed'), 'reviewed'],
 | 
			
		||||
      [t('admin.tags.moderation.review_requested'), 'review_requested'],
 | 
			
		||||
      [t('admin.tags.moderation.unreviewed'), 'unreviewed'],
 | 
			
		||||
      [t('admin.tags.moderation.trendable'), 'trendable'],
 | 
			
		||||
      [t('admin.tags.moderation.not_trendable'), 'not_trendable'],
 | 
			
		||||
      [t('admin.tags.moderation.usable'), 'usable'],
 | 
			
		||||
      [t('admin.tags.moderation.not_usable'), 'not_usable'],
 | 
			
		||||
    ]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -350,6 +350,10 @@
 | 
			
		||||
      color: $primary-text-color;
 | 
			
		||||
      font-weight: 700;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .warning-hint {
 | 
			
		||||
      font-weight: normal !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &__body {
 | 
			
		||||
 
 | 
			
		||||
@@ -286,6 +286,10 @@ a.table-action-link {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &--padded {
 | 
			
		||||
        padding: 12px 16px 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &--with-image {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										74
									
								
								app/models/admin/tag_filter.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								app/models/admin/tag_filter.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::TagFilter
 | 
			
		||||
  KEYS = %i(
 | 
			
		||||
    status
 | 
			
		||||
    name
 | 
			
		||||
    order
 | 
			
		||||
  ).freeze
 | 
			
		||||
 | 
			
		||||
  attr_reader :params
 | 
			
		||||
 | 
			
		||||
  def initialize(params)
 | 
			
		||||
    @params = params.to_h.symbolize_keys
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def results
 | 
			
		||||
    scope = Tag.reorder(nil)
 | 
			
		||||
 | 
			
		||||
    params.each do |key, value|
 | 
			
		||||
      next if key == :page
 | 
			
		||||
 | 
			
		||||
      scope.merge!(scope_for(key, value)) if value.present?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    scope
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def scope_for(key, value)
 | 
			
		||||
    case key
 | 
			
		||||
    when :status
 | 
			
		||||
      status_scope(value)
 | 
			
		||||
    when :name
 | 
			
		||||
      Tag.search_for(value.to_s.strip, params[:limit], params[:offset], exclude_unlistable: false)
 | 
			
		||||
    when :order
 | 
			
		||||
      order_scope(value)
 | 
			
		||||
    else
 | 
			
		||||
      raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def status_scope(value)
 | 
			
		||||
    case value.to_s
 | 
			
		||||
    when 'reviewed'
 | 
			
		||||
      Tag.reviewed
 | 
			
		||||
    when 'review_requested'
 | 
			
		||||
      Tag.pending_review
 | 
			
		||||
    when 'unreviewed'
 | 
			
		||||
      Tag.unreviewed
 | 
			
		||||
    when 'trendable'
 | 
			
		||||
      Tag.trendable
 | 
			
		||||
    when 'not_trendable'
 | 
			
		||||
      Tag.not_trendable
 | 
			
		||||
    when 'usable'
 | 
			
		||||
      Tag.usable
 | 
			
		||||
    when 'not_usable'
 | 
			
		||||
      Tag.not_usable
 | 
			
		||||
    else
 | 
			
		||||
      raise Mastodon::InvalidParameterError, "Unknown status: #{value}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def order_scope(value)
 | 
			
		||||
    case value.to_s
 | 
			
		||||
    when 'newest'
 | 
			
		||||
      Tag.order(created_at: :desc)
 | 
			
		||||
    when 'oldest'
 | 
			
		||||
      Tag.order(created_at: :asc)
 | 
			
		||||
    else
 | 
			
		||||
      raise Mastodon::InvalidParameterError, "Unknown order: #{value}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -52,6 +52,7 @@ class Tag < ApplicationRecord
 | 
			
		||||
  scope :unreviewed, -> { where(reviewed_at: nil) }
 | 
			
		||||
  scope :pending_review, -> { unreviewed.where.not(requested_review_at: nil) }
 | 
			
		||||
  scope :usable, -> { where(usable: [true, nil]) }
 | 
			
		||||
  scope :not_usable, -> { where(usable: false) }
 | 
			
		||||
  scope :listable, -> { where(listable: [true, nil]) }
 | 
			
		||||
  scope :trendable, -> { Setting.trendable_by_default ? where(trendable: [true, nil]) : where(trendable: true) }
 | 
			
		||||
  scope :not_trendable, -> { where(trendable: false) }
 | 
			
		||||
@@ -74,6 +75,10 @@ class Tag < ApplicationRecord
 | 
			
		||||
    attributes['display_name'] || name
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def formatted_name
 | 
			
		||||
    "##{display_name}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def usable
 | 
			
		||||
    boolean_with_default('usable', true)
 | 
			
		||||
  end
 | 
			
		||||
@@ -132,8 +137,10 @@ class Tag < ApplicationRecord
 | 
			
		||||
 | 
			
		||||
    def search_for(term, limit = 5, offset = 0, options = {})
 | 
			
		||||
      stripped_term = term.strip
 | 
			
		||||
      options.reverse_merge!({ exclude_unlistable: true, exclude_unreviewed: false })
 | 
			
		||||
 | 
			
		||||
      query = Tag.listable.matches_name(stripped_term)
 | 
			
		||||
      query = Tag.matches_name(stripped_term)
 | 
			
		||||
      query = query.merge(Tag.listable) if options[:exclude_unlistable]
 | 
			
		||||
      query = query.merge(matching_name(stripped_term).or(where.not(reviewed_at: nil))) if options[:exclude_unreviewed]
 | 
			
		||||
 | 
			
		||||
      query.order(Arel.sql('length(name) ASC, name ASC'))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								app/views/admin/tags/_tag.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/views/admin/tags/_tag.html.haml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
.batch-table__row{ class: [!tag.requires_review? && !tag.usable? && 'batch-table__row--muted'] }
 | 
			
		||||
  .batch-table__row__content.batch-table__row__content--padded.pending-account
 | 
			
		||||
    .pending-account__header
 | 
			
		||||
      %strong
 | 
			
		||||
        = link_to tag.formatted_name, admin_tag_path(tag.id)
 | 
			
		||||
 | 
			
		||||
      %br/
 | 
			
		||||
 | 
			
		||||
      - if tag.usable?
 | 
			
		||||
        = t('admin.tags.moderation.usable')
 | 
			
		||||
      - else
 | 
			
		||||
        = t('admin.tags.moderation.not_usable')
 | 
			
		||||
 | 
			
		||||
      ·
 | 
			
		||||
      - if tag.trendable?
 | 
			
		||||
        = t('admin.tags.moderation.trendable')
 | 
			
		||||
      - else
 | 
			
		||||
        = t('admin.tags.moderation.not_trendable')
 | 
			
		||||
 | 
			
		||||
      - if tag.requested_review? || tag.requires_review?
 | 
			
		||||
        ·
 | 
			
		||||
        - if tag.requested_review?
 | 
			
		||||
          %span.negative-hint
 | 
			
		||||
            = t('admin.tags.moderation.review_requested')
 | 
			
		||||
        - else
 | 
			
		||||
          %span.warning-hint
 | 
			
		||||
            = t('admin.tags.moderation.pending_review')
 | 
			
		||||
							
								
								
									
										39
									
								
								app/views/admin/tags/index.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/views/admin/tags/index.html.haml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
- content_for :page_title do
 | 
			
		||||
  = t('admin.tags.title')
 | 
			
		||||
 | 
			
		||||
= form_with url: admin_tags_url, method: :get, class: :simple_form do |form|
 | 
			
		||||
  .filters
 | 
			
		||||
    .filter-subset.filter-subset--with-select
 | 
			
		||||
      %strong= t('admin.tags.moderation.title')
 | 
			
		||||
      .input.select.optional
 | 
			
		||||
        = form.select :status,
 | 
			
		||||
                      options_for_select(admin_tags_moderation_options, params[:status]),
 | 
			
		||||
                      prompt: t('generic.all')
 | 
			
		||||
 | 
			
		||||
    .filter-subset.filter-subset--with-select
 | 
			
		||||
      %strong= t 'generic.order_by'
 | 
			
		||||
      .input.select
 | 
			
		||||
        = form.select :order,
 | 
			
		||||
                      options_for_select([[t('admin.tags.newest'), 'newest'], [t('admin.tags.oldest'), 'oldest']], params[:order])
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    .input.string.optional
 | 
			
		||||
      = form.text_field :name,
 | 
			
		||||
                        value: params[:name],
 | 
			
		||||
                        class: 'string optional',
 | 
			
		||||
                        placeholder: t('admin.tags.name')
 | 
			
		||||
 | 
			
		||||
  .actions
 | 
			
		||||
    %button.button= t('admin.tags.search')
 | 
			
		||||
    = link_to t('admin.tags.reset'), admin_tags_path, class: 'button negative'
 | 
			
		||||
 | 
			
		||||
%hr.spacer/
 | 
			
		||||
 | 
			
		||||
.batch-table
 | 
			
		||||
  .batch-table__body
 | 
			
		||||
    - if @tags.empty?
 | 
			
		||||
      = nothing_here 'nothing-here--under-tabs'
 | 
			
		||||
    - else
 | 
			
		||||
      = render partial: 'tag', collection: @tags
 | 
			
		||||
 | 
			
		||||
= paginate @tags
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
- content_for :page_title do
 | 
			
		||||
  = "##{@tag.display_name}"
 | 
			
		||||
  = @tag.formatted_name
 | 
			
		||||
 | 
			
		||||
- if current_user.can?(:view_dashboard)
 | 
			
		||||
  - content_for :heading_actions do
 | 
			
		||||
- content_for :heading_actions do
 | 
			
		||||
  - if current_user.can?(:view_dashboard)
 | 
			
		||||
    = l(@time_period.first)
 | 
			
		||||
    = ' - '
 | 
			
		||||
    = l(@time_period.last)
 | 
			
		||||
 | 
			
		||||
- if current_user.can?(:view_dashboard)
 | 
			
		||||
  .dashboard
 | 
			
		||||
    .dashboard__item
 | 
			
		||||
      = react_admin_component :counter,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,7 @@
 | 
			
		||||
 | 
			
		||||
  .batch-table__row__content.pending-account
 | 
			
		||||
    .pending-account__header
 | 
			
		||||
      = link_to admin_tag_path(tag.id) do
 | 
			
		||||
        = material_symbol 'tag'
 | 
			
		||||
        = tag.display_name
 | 
			
		||||
      = link_to tag.formatted_name, admin_tag_path(tag.id)
 | 
			
		||||
 | 
			
		||||
      %br/
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -885,7 +885,23 @@ en:
 | 
			
		||||
        action: Check here for more information
 | 
			
		||||
        message_html: "<strong>Your object storage is misconfigured. The privacy of your users is at risk.</strong>"
 | 
			
		||||
    tags:
 | 
			
		||||
      moderation:
 | 
			
		||||
        not_trendable: Not trendable
 | 
			
		||||
        not_usable: Not usable
 | 
			
		||||
        pending_review: Pending review
 | 
			
		||||
        review_requested: Review requested
 | 
			
		||||
        reviewed: Reviewed
 | 
			
		||||
        title: Status
 | 
			
		||||
        trendable: Trendable
 | 
			
		||||
        unreviewed: Unreviewed
 | 
			
		||||
        usable: Usable
 | 
			
		||||
      name: Name
 | 
			
		||||
      newest: Newest
 | 
			
		||||
      oldest: Oldest
 | 
			
		||||
      reset: Reset
 | 
			
		||||
      review: Review status
 | 
			
		||||
      search: Search
 | 
			
		||||
      title: Hashtags
 | 
			
		||||
      updated_msg: Hashtag settings updated successfully
 | 
			
		||||
    title: Administration
 | 
			
		||||
    trends:
 | 
			
		||||
 
 | 
			
		||||
@@ -314,7 +314,7 @@ en:
 | 
			
		||||
        listable: Allow this hashtag to appear in searches and suggestions
 | 
			
		||||
        name: Hashtag
 | 
			
		||||
        trendable: Allow this hashtag to appear under trends
 | 
			
		||||
        usable: Allow posts to use this hashtag
 | 
			
		||||
        usable: Allow posts to use this hashtag locally
 | 
			
		||||
      user:
 | 
			
		||||
        role: Role
 | 
			
		||||
        time_zone: Time zone
 | 
			
		||||
 
 | 
			
		||||
@@ -40,13 +40,14 @@ SimpleNavigation::Configuration.run do |navigation|
 | 
			
		||||
 | 
			
		||||
    n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s|
 | 
			
		||||
      s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses}
 | 
			
		||||
      s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/tags|/admin/trends/tags}
 | 
			
		||||
      s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/trends/tags}
 | 
			
		||||
      s.item :links, safe_join([fa_icon('newspaper-o fw'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links}
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s|
 | 
			
		||||
      s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports|admin/report_notes}, if: -> { current_user.can?(:manage_reports) }
 | 
			
		||||
      s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) }
 | 
			
		||||
      s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.tags.title')]), admin_tags_path, highlights_on: %r{/admin/tags}, if: -> { current_user.can?(:manage_taxonomies) }
 | 
			
		||||
      s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
 | 
			
		||||
      s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) }
 | 
			
		||||
      s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) }
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ namespace :admin do
 | 
			
		||||
  resources :roles, except: [:show]
 | 
			
		||||
  resources :account_moderation_notes, only: [:create, :destroy]
 | 
			
		||||
  resource :follow_recommendations, only: [:show, :update]
 | 
			
		||||
  resources :tags, only: [:show, :update]
 | 
			
		||||
  resources :tags, only: [:index, :show, :update]
 | 
			
		||||
 | 
			
		||||
  namespace :trends do
 | 
			
		||||
    resources :links, only: [:index] do
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,43 @@ RSpec.describe Admin::TagsController do
 | 
			
		||||
    sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'GET #index' do
 | 
			
		||||
    before do
 | 
			
		||||
      Fabricate(:tag)
 | 
			
		||||
 | 
			
		||||
      tag_filter = instance_double(Admin::TagFilter, results: Tag.all)
 | 
			
		||||
      allow(Admin::TagFilter).to receive(:new).and_return(tag_filter)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:params) { { order: 'newest' } }
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      get :index
 | 
			
		||||
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
      expect(response).to render_template(:index)
 | 
			
		||||
 | 
			
		||||
      expect(Admin::TagFilter)
 | 
			
		||||
        .to have_received(:new)
 | 
			
		||||
        .with(hash_including(params))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    describe 'with filters' do
 | 
			
		||||
      let(:params) { { order: 'newest', name: 'test' } }
 | 
			
		||||
 | 
			
		||||
      it 'returns http success' do
 | 
			
		||||
        get :index, params: { name: 'test' }
 | 
			
		||||
 | 
			
		||||
        expect(response).to have_http_status(200)
 | 
			
		||||
        expect(response).to render_template(:index)
 | 
			
		||||
 | 
			
		||||
        expect(Admin::TagFilter)
 | 
			
		||||
          .to have_received(:new)
 | 
			
		||||
          .with(hash_including(params))
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'GET #show' do
 | 
			
		||||
    let!(:tag) { Fabricate(:tag) }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								spec/models/admin/tag_filter_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								spec/models/admin/tag_filter_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
describe Admin::TagFilter do
 | 
			
		||||
  describe 'with invalid params' do
 | 
			
		||||
    it 'raises with key error' do
 | 
			
		||||
      filter = described_class.new(wrong: true)
 | 
			
		||||
 | 
			
		||||
      expect { filter.results }.to raise_error(/wrong/)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'raises with status scope error' do
 | 
			
		||||
      filter = described_class.new(status: 'unknown')
 | 
			
		||||
 | 
			
		||||
      expect { filter.results }.to raise_error(/Unknown status: unknown/)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'raises with order value error' do
 | 
			
		||||
      filter = described_class.new(order: 'unknown')
 | 
			
		||||
 | 
			
		||||
      expect { filter.results }.to raise_error(/Unknown order: unknown/)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '#results' do
 | 
			
		||||
    let(:listable_tag) { Fabricate(:tag, name: 'test1', listable: true) }
 | 
			
		||||
    let(:not_listable_tag) { Fabricate(:tag, name: 'test2', listable: false) }
 | 
			
		||||
 | 
			
		||||
    it 'returns tags filtered by name' do
 | 
			
		||||
      filter = described_class.new(name: 'test')
 | 
			
		||||
 | 
			
		||||
      expect(filter.results).to eq([listable_tag, not_listable_tag])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -112,6 +112,18 @@ RSpec.describe Tag do
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '#formatted_name' do
 | 
			
		||||
    it 'returns name with a proceeding hash symbol' do
 | 
			
		||||
      tag = Fabricate(:tag, name: 'foo')
 | 
			
		||||
      expect(tag.formatted_name).to eq '#foo'
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'returns display_name with a proceeding hash symbol, if display name present' do
 | 
			
		||||
      tag = Fabricate(:tag, name: 'foobar', display_name: 'FooBar')
 | 
			
		||||
      expect(tag.formatted_name).to eq '#FooBar'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '.recently_used' do
 | 
			
		||||
    let(:account) { Fabricate(:account) }
 | 
			
		||||
    let(:other_person_status) { Fabricate(:status) }
 | 
			
		||||
@@ -240,5 +252,23 @@ RSpec.describe Tag do
 | 
			
		||||
 | 
			
		||||
      expect(results).to eq [tag, similar_tag]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'finds only listable tags' do
 | 
			
		||||
      tag = Fabricate(:tag, name: 'match')
 | 
			
		||||
      _miss_tag = Fabricate(:tag, name: 'matchunlisted', listable: false)
 | 
			
		||||
 | 
			
		||||
      results = described_class.search_for('match')
 | 
			
		||||
 | 
			
		||||
      expect(results).to eq [tag]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'finds non-listable tags as well via option' do
 | 
			
		||||
      tag = Fabricate(:tag, name: 'match')
 | 
			
		||||
      unlisted_tag = Fabricate(:tag, name: 'matchunlisted', listable: false)
 | 
			
		||||
 | 
			
		||||
      results = described_class.search_for('match', 5, 0, exclude_unlistable: false)
 | 
			
		||||
 | 
			
		||||
      expect(results).to eq [tag, unlisted_tag]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user