Skip to content

Commit

Permalink
Implement text blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
akihikodaki committed Feb 18, 2018
1 parent cba2897 commit fc66e86
Show file tree
Hide file tree
Showing 30 changed files with 590 additions and 7 deletions.
67 changes: 67 additions & 0 deletions app/controllers/admin/text_blocks_controller.rb
@@ -0,0 +1,67 @@
# frozen_string_literal: true

module Admin
class TextBlocksController < BaseController
before_action :set_new_text_block, only: [:index, :create]
before_action :find_and_set_text_block, only: [:show, :update, :destroy]
before_action :authorize_text_block

def index
page = params[:page]
@text_block = TextBlock.new if page.nil?
@text_blocks = TextBlock.recent.page(page)
end

def show; end

def create
if @text_block.save
log_action :create, @text_block
redirect_to({ action: :index }, notice: I18n.t('admin.text_blocks.created'))
else
@text_blocks = TextBlock.page(0)
flash.now[:alert] = @text_block.errors.full_messages.first
render :index
end
end

def update
if @text_block.update text_block_params
log_action :update, @text_block
redirect_to({ action: :index }, notice: I18n.t('admin.text_blocks.updated'))
else
flash.now[:alert] = @text_block.errors.full_messages.first
render :show
end
end

def destroy
if @text_block.destroy
log_action :destroy, @text_block
flash[:notice] = I18n.t('admin.text_blocks.destroyed')
else
flash[:alert] = @text_block.errors.full_messages.first
end

redirect_to action: :index
end

private

def authorize_text_block
authorize @text_block
end

def set_new_text_block
@text_block = TextBlock.new(text_block_params)
end

def find_and_set_text_block
@text_block = TextBlock.find(params.require(:id))
end

def text_block_params
params[:text_block]&.permit(:text, :severity)
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/api/v1/timelines/public_controller.rb
Expand Up @@ -13,7 +13,7 @@ def show
private

def load_statuses
cached_public_statuses
cached_public_statuses.reject { |status| TextBlock.silence? status }
end

def cached_public_statuses
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/timelines/tag_controller.rb
Expand Up @@ -18,7 +18,7 @@ def load_tag
end

def load_statuses
cached_tagged_statuses
cached_tagged_statuses.reject { |status| TextBlock.silence? status }
end

def cached_tagged_statuses
Expand Down
3 changes: 3 additions & 0 deletions app/models/account.rb
Expand Up @@ -72,6 +72,9 @@ class Account < ApplicationRecord
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
validates :note, length: { maximum: 160 }, if: -> { local? && will_save_change_to_note? }

validates :display_name, text_blocks: true
validates :note, text_blocks: true

# Timelines
has_many :stream_entries, inverse_of: :account, dependent: :destroy
has_many :statuses, inverse_of: :account, dependent: :destroy
Expand Down
2 changes: 2 additions & 0 deletions app/models/media_attachment.rb
Expand Up @@ -61,6 +61,8 @@ class MediaAttachment < ApplicationRecord
validates :account, presence: true
validates :description, length: { maximum: 420 }, if: :local?

validates :description, text_blocks: true

scope :attached, -> { where.not(status_id: nil) }
scope :unattached, -> { where(status_id: nil) }
scope :local, -> { where(remote_url: '') }
Expand Down
3 changes: 3 additions & 0 deletions app/models/status.rb
Expand Up @@ -61,6 +61,9 @@ class Status < ApplicationRecord
validates_with StatusLengthValidator
validates :reblog, uniqueness: { scope: :account }, if: :reblog?

validates :text, text_blocks: true
validates :spoiler_text, text_blocks: true

default_scope { recent }

scope :recent, -> { reorder(id: :desc) }
Expand Down
47 changes: 47 additions & 0 deletions app/models/text_block.rb
@@ -0,0 +1,47 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: text_blocks
#
# id :integer not null, primary key
# text :string not null
# severity :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#

class TextBlock < ApplicationRecord
after_commit :uncache

enum severity: [:silence, :reject]

scope :recent, -> { reorder(id: :desc) }

def self.silence?(object)
(object.is_a?(Status) && (silence?(object.account) || object.media_attachments.any? { |attachment| silence? attachment })) ||
[:description, :display_name, :name, :note, :spoiler_text, :text].any? do |key|
object.respond_to?(key) && silenced_texts.any? do |text|
object.public_send(key)&.include? text
end
end
end

def self.rejected_texts
Rails.cache.fetch :rejected_texts do
where(severity: :reject).pluck(:text)
end
end

def self.silenced_texts
Rails.cache.fetch :silenced_texts do
where(severity: :silence).pluck(:text)
end
end

private

def uncache
Rails.cache.delete :rejected_texts
Rails.cache.delete :silenced_texts
end
end
23 changes: 23 additions & 0 deletions app/policies/text_block_policy.rb
@@ -0,0 +1,23 @@
# frozen_string_literal: true

class TextBlockPolicy < ApplicationPolicy
def index?
true
end

def show?
true
end

def create?
admin?
end

def update?
admin?
end

def destroy?
admin?
end
end
2 changes: 1 addition & 1 deletion app/services/account_search_service.rb
Expand Up @@ -9,7 +9,7 @@ def call(query, limit, account = nil, options = {})
@options = options
@account = account

search_service_results
search_service_results.reject { |result| TextBlock.silence? result }
end

private
Expand Down
2 changes: 1 addition & 1 deletion app/services/fan_out_on_write_service.rb
Expand Up @@ -17,7 +17,7 @@ def call(status)
deliver_to_lists(status)
end

return if status.account.silenced? || !status.public_visibility? || status.reblog?
return if status.account.silenced? || !status.public_visibility? || status.reblog? || TextBlock.silence?(status)

render_anonymous_payload(status)
deliver_to_hashtags(status)
Expand Down
6 changes: 4 additions & 2 deletions app/services/search_service.rb
Expand Up @@ -31,11 +31,13 @@ def perform_statuses_search!
.query(multi_match: { type: 'most_fields', query: query, operator: 'and', fields: %w(text text.stemmed) })
.limit(limit).objects

statuses.reject { |status| StatusFilter.new(status, account).filtered? }
statuses.reject do |status|
StatusFilter.new(status, account).filtered? || TextBlock.silence?(tag)
end
end

def perform_hashtags_search!
Tag.search_for(query.gsub(/\A#/, ''), limit)
Tag.search_for(query.gsub(/\A#/, ''), limit).reject { |tag| TextBlock.silence? tag }
end

def default_results
Expand Down
10 changes: 10 additions & 0 deletions app/validators/text_blocks_validator.rb
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class TextBlocksValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.nil?

rejected = TextBlock.rejected_texts.find { |text| value.include? text }
record.errors.add attribute, I18n.t('rejected_text', text: rejected) if rejected.present?
end
end
11 changes: 11 additions & 0 deletions app/views/admin/text_blocks/_text_block.html.haml
@@ -0,0 +1,11 @@
= simple_form_for text_block, url: text_block.persisted? ? admin_text_block_path(text_block) : admin_text_blocks_path do |f|
= render 'shared/error_messages', object: text_block

= f.input :text, placeholder: t('admin.text_blocks.text'), disabled: text_block.persisted?, readonly: text_block.persisted?, required: true

= f.input :severity, collection: TextBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: ->(type) { t(".severities.#{type}") }

%p.hint= t('admin.text_blocks.severity.desc_html')

.actions
= f.button :button, text_block.persisted? ? t('admin.text_blocks.save') : t('admin.text_blocks.create')
27 changes: 27 additions & 0 deletions app/views/admin/text_blocks/index.html.haml
@@ -0,0 +1,27 @@
- content_for :page_title do
= t('admin.text_blocks.title')

.table-wrapper
%table.table
%thead
%tr
%th= t('admin.text_blocks.text')
%th= t('admin.text_blocks.severity.title')
%th
%th
%tbody
- @text_blocks.each do |text_block|
%tr
%td= link_to text_block.text, admin_text_block_path(text_block)
%td= t("admin.text_blocks.severities.#{text_block.severity}")
%td
= table_link_to 'trash', t('admin.text_blocks.destroy'), admin_text_block_path(text_block), method: :delete

= paginate @text_blocks

- if @text_block.present?
%hr

%h3= t('admin.text_blocks.new')

= render @text_block
11 changes: 11 additions & 0 deletions app/views/admin/text_blocks/show.haml
@@ -0,0 +1,11 @@
- content_for :page_title do
= t('.title')

= render @text_block

%hr

%h3= t('admin.text_blocks.deletion')

.simple_form
= link_to t('admin.text_blocks.destroy'), admin_text_block_path(@text_block), class: 'block-button', method: :delete
20 changes: 20 additions & 0 deletions config/locales/en.yml
Expand Up @@ -335,6 +335,25 @@ en:
last_delivery: Last delivery
title: WebSub
topic: Topic
text_blocks:
create: Block text
created: Text successfully blocked
deletion: Unblock text
destroy: Unblock
destroyed: Text successfully unblocked
new: New text block
save: Save
severities:
reject: Reject
silence: Silence
severity:
desc_html: "<strong>Silence</strong> will make the objects including the text invisible on public timeline and search window. <strong>Reject</strong> will reject all of the objects including the text."
title: Severity
show:
title: Text block details
text: Text
title: Text blocks
updated: Text block entry successfully updated
title: Administration
admin_mailer:
new_report:
Expand Down Expand Up @@ -558,6 +577,7 @@ en:
title: "%{name} mentioned you"
reblog:
title: "%{name} boosted your status"
rejected_text: 'Prohibited text: %{text}'
remote_follow:
acct: Enter your username@domain you want to follow from
missing_resource: Could not find the required redirect URL for your account
Expand Down
19 changes: 19 additions & 0 deletions config/locales/ja.yml
Expand Up @@ -332,6 +332,25 @@ ja:
last_delivery: 最終配送
title: WebSub
topic: トピック
text_blocks:
create: 文字列をブロックする
created: 文字列のブロックに成功しました
deletion: 文字列ブロックの解除
destroy: ブロックを解除
destroyed: 文字列ブロックの解除に成功しました
new: 新しい文字列ブロック
save: 保存
severities:
reject: 拒否
silence: サイレンス
severity:
desc_html: "<strong>サイレンス</strong>は文字列を含むオブジェクトを公開タイムラインと検索画面で非表示にします。<strong>拒否</strong>は文字列を含む全てのオブジェクトを拒否します。"
title: 深刻度
show:
title: 文字列ブロックの詳細
text: 文字列
title: 文字列ブロック
updated: 文字列ブロックの更新に成功しました
title: 管理
admin_mailer:
new_report:
Expand Down
1 change: 1 addition & 0 deletions config/navigation.rb
Expand Up @@ -30,6 +30,7 @@
admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}, if: -> { current_user.admin? }
admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks}, if: -> { current_user.admin? }
admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? }
admin.item :text_blocks, safe_join([fa_icon('language fw'), t('admin.text_blocks.title')]), admin_text_blocks_url, highlights_on: %r{/admin/text_blocks}, if: -> { current_user.admin? }
end

primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), proc { current_user.admin? ? edit_admin_settings_url : admin_custom_emojis_url }, if: proc { current_user.staff? } do |admin|
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Expand Up @@ -121,6 +121,7 @@
resources :subscriptions, only: [:index]
resources :domain_blocks, only: [:index, :new, :create, :show, :destroy]
resources :email_domain_blocks, only: [:index, :new, :create, :destroy]
resources :text_blocks, only: [:index, :show, :create, :update, :destroy]
resources :action_logs, only: [:index]
resource :settings, only: [:edit, :update]
resources :invites, only: [:index, :create, :destroy]
Expand Down
9 changes: 9 additions & 0 deletions db/migrate/20180210000000_create_text_blocks.rb
@@ -0,0 +1,9 @@
class CreateTextBlocks < ActiveRecord::Migration[5.1]
def change
create_table :text_blocks do |t|
t.string :text, index: { unique: true }, null: false
t.integer :severity, null: false
t.timestamps
end
end
end
10 changes: 9 additions & 1 deletion db/schema.rb
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20180206000000) do
ActiveRecord::Schema.define(version: 20180210000000) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -464,6 +464,14 @@
t.index ["name"], name: "index_tags_on_name", unique: true
end

create_table "text_blocks", id: :serial, force: :cascade do |t|
t.string "text", null: false
t.integer "severity", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["text"], name: "index_text_blocks_on_text", unique: true
end

create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.datetime "created_at", null: false
Expand Down

0 comments on commit fc66e86

Please sign in to comment.