Merge branch 'kbtopic_antenna' into kb_migration_development
This commit is contained in:
commit
63b57de234
21 changed files with 655 additions and 1 deletions
76
app/controllers/antennas_controller.rb
Normal file
76
app/controllers/antennas_controller.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AntennasController < ApplicationController
|
||||
layout 'admin'
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_antenna, only: [:edit, :update, :destroy]
|
||||
before_action :set_lists, only: [:new, :edit]
|
||||
before_action :set_body_classes
|
||||
before_action :set_cache_headers
|
||||
|
||||
def index
|
||||
@antennas = current_account.antennas.includes(:antenna_domains).includes(:antenna_tags).includes(:antenna_accounts)
|
||||
end
|
||||
|
||||
def new
|
||||
@antenna = current_account.antennas.build
|
||||
@antenna.antenna_domains.build
|
||||
@antenna.antenna_tags.build
|
||||
@antenna.antenna_accounts.build
|
||||
end
|
||||
|
||||
def create
|
||||
@antenna = current_account.antennas.build(thin_resource_params)
|
||||
|
||||
saved = @antenna.save
|
||||
saved = @antenna.update(resource_params) if saved
|
||||
|
||||
if saved
|
||||
redirect_to antennas_path
|
||||
else
|
||||
render action: :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit; end
|
||||
|
||||
def update
|
||||
if @antenna.update(resource_params)
|
||||
redirect_to antennas_path
|
||||
else
|
||||
render action: :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@antenna.destroy
|
||||
redirect_to antennas_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_antenna
|
||||
@antenna = current_account.antennas.find(params[:id])
|
||||
end
|
||||
|
||||
def set_lists
|
||||
@lists = current_account.owned_lists
|
||||
end
|
||||
|
||||
def resource_params
|
||||
params.require(:antenna).permit(:title, :list, :available, :expires_in, :keywords_raw, :exclude_keywords_raw, :domains_raw, :exclude_domains_raw, :accounts_raw, :exclude_accounts_raw, :tags_raw, :exclude_tags_raw)
|
||||
end
|
||||
|
||||
def thin_resource_params
|
||||
params.require(:antenna).permit(:title, :list)
|
||||
end
|
||||
|
||||
def set_body_classes
|
||||
@body_classes = 'admin'
|
||||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.cache_control.replace(private: true, no_store: true)
|
||||
end
|
||||
end
|
200
app/models/antenna.rb
Normal file
200
app/models/antenna.rb
Normal file
|
@ -0,0 +1,200 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: antennas
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# account_id :bigint(8) not null
|
||||
# list_id :bigint(8) not null
|
||||
# title :string default(""), not null
|
||||
# keywords :jsonb
|
||||
# exclude_keywords :jsonb
|
||||
# any_domains :boolean default(TRUE), not null
|
||||
# any_tags :boolean default(TRUE), not null
|
||||
# any_accounts :boolean default(TRUE), not null
|
||||
# any_keywords :boolean default(TRUE), not null
|
||||
# available :boolean default(TRUE), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# expires_at :datetime
|
||||
#
|
||||
class Antenna < ApplicationRecord
|
||||
include Expireable
|
||||
|
||||
has_many :antenna_domains, inverse_of: :antenna, dependent: :destroy
|
||||
has_many :antenna_tags, inverse_of: :antenna, dependent: :destroy
|
||||
has_many :antenna_accounts, inverse_of: :antenna, dependent: :destroy
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :list
|
||||
|
||||
scope :all_keywords, -> { where(any_keywords: true) }
|
||||
scope :all_domains, -> { where(any_domains: true) }
|
||||
scope :all_accounts, -> { where(any_accounts: true) }
|
||||
scope :all_tags, -> { where(any_tags: true) }
|
||||
scope :availables, -> { where(available: true) }
|
||||
|
||||
def enabled?
|
||||
available && !expires? #&& !(any_keywords && any_domains && any_accounts && any_tags)
|
||||
end
|
||||
|
||||
def expires_in
|
||||
return @expires_in if defined?(@expires_in)
|
||||
return nil if expires_at.nil?
|
||||
|
||||
[30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].find { |expires_in| expires_in.from_now >= expires_at }
|
||||
end
|
||||
|
||||
def expires?
|
||||
expires_at.present? && expires_at < Time.now.utc
|
||||
end
|
||||
|
||||
def context
|
||||
context = []
|
||||
context << 'domain' if !any_domains
|
||||
context << 'tag' if !any_tags
|
||||
context << 'keyword' if !any_keywords
|
||||
context << 'account' if !any_accounts
|
||||
context
|
||||
end
|
||||
|
||||
def list=(list_id)
|
||||
list_id = list_id.to_i if list_id.is_a?(String)
|
||||
if list_id.is_a?(Numeric)
|
||||
self[:list_id] = list_id
|
||||
else
|
||||
self[:list] = list_id
|
||||
end
|
||||
end
|
||||
|
||||
def keywords_raw
|
||||
return '' if !keywords.present?
|
||||
|
||||
keywords.join("\n")
|
||||
end
|
||||
|
||||
def keywords_raw=(raw)
|
||||
keywords = raw.split(/\R/).filter { |r| r.present? }
|
||||
self[:keywords] = keywords
|
||||
self[:any_keywords] = !keywords.any? && !exclude_keywords&.any?
|
||||
end
|
||||
|
||||
def exclude_keywords_raw
|
||||
return '' if !exclude_keywords.present?
|
||||
|
||||
exclude_keywords.join("\n")
|
||||
end
|
||||
|
||||
def exclude_keywords_raw=(raw)
|
||||
exclude_keywords = raw.split(/\R/).filter { |r| r.present? }
|
||||
self[:exclude_keywords] = exclude_keywords
|
||||
self[:any_keywords] = !keywords&.any? && !exclude_keywords.any?
|
||||
end
|
||||
|
||||
def tags_raw
|
||||
antenna_tags.where(exclude: false).map(&:tag).map(&:name).join("\n")
|
||||
end
|
||||
|
||||
def tags_raw=(raw)
|
||||
return if tags_raw == raw
|
||||
|
||||
tag_names = raw.split(/\R/).filter { |r| r.present? }
|
||||
|
||||
antenna_tags.where(exclude: false).destroy_all
|
||||
Tag.find_or_create_by_names(tag_names).each do |tag|
|
||||
antenna_tags.create!(tag: tag, exclude: false)
|
||||
end
|
||||
self[:any_tags] = !tag_names.any?
|
||||
end
|
||||
|
||||
def exclude_tags_raw
|
||||
antenna_tags.where(exclude: true).map(&:tag).map(&:name).join("\n")
|
||||
end
|
||||
|
||||
def exclude_tags_raw=(raw)
|
||||
return if exclude_tags_raw == raw
|
||||
|
||||
tag_names = raw.split(/\R/).filter { |r| r.present? }
|
||||
|
||||
antenna_tags.where(exclude: true).destroy_all
|
||||
Tag.find_or_create_by_names(tag_names).each do |tag|
|
||||
antenna_tags.create!(tag: tag, exclude: true)
|
||||
end
|
||||
end
|
||||
|
||||
def domains_raw
|
||||
antenna_domains.where(exclude: false).map(&:name).join("\n")
|
||||
end
|
||||
|
||||
def domains_raw=(raw)
|
||||
return if domains_raw == raw
|
||||
|
||||
domain_names = raw.split(/\R/).filter { |r| r.present? }
|
||||
|
||||
antenna_domains.where(exclude: false).destroy_all
|
||||
domain_names.each do |domain|
|
||||
antenna_domains.create!(name: domain, exclude: false)
|
||||
end
|
||||
self[:any_domains] = !domain_names.any?
|
||||
end
|
||||
|
||||
def exclude_domains_raw
|
||||
antenna_domains.where(exclude: true).map(&:name).join("\n")
|
||||
end
|
||||
|
||||
def exclude_domains_raw=(raw)
|
||||
return if exclude_domains_raw == raw
|
||||
|
||||
domain_names = raw.split(/\R/).filter { |r| r.present? }
|
||||
|
||||
antenna_domains.where(exclude: true).destroy_all
|
||||
domain_names.each do |domain|
|
||||
antenna_domains.create!(name: domain, exclude: true)
|
||||
end
|
||||
end
|
||||
|
||||
def accounts_raw
|
||||
antenna_accounts.where(exclude: false).map(&:account).map { |account| account.domain ? "@#{account.username}@#{account.domain}" : "@#{account.username}" }.join("\n")
|
||||
end
|
||||
|
||||
def accounts_raw=(raw)
|
||||
return if accounts_raw == raw
|
||||
|
||||
account_names = raw.split(/\R/).filter { |r| r.present? }
|
||||
|
||||
hit = false
|
||||
antenna_accounts.where(exclude: false).destroy_all
|
||||
account_names.each do |name|
|
||||
name = name[1..-1] if name.start_with?('@')
|
||||
username, domain = name.split('@')
|
||||
account = Account.find_by(username: username, domain: domain)
|
||||
if account.present?
|
||||
antenna_accounts.create!(account: account, exclude: false)
|
||||
hit = true
|
||||
end
|
||||
end
|
||||
self[:any_accounts] = !hit
|
||||
end
|
||||
|
||||
def exclude_accounts_raw
|
||||
antenna_accounts.where(exclude: true).map(&:account).map { |account| account.domain ? "@#{account.username}@#{account.domain}" : "@#{account.username}" }.join("\n")
|
||||
end
|
||||
|
||||
def exclude_accounts_raw=(raw)
|
||||
return if exclude_accounts_raw == raw
|
||||
|
||||
account_names = raw.split(/\R/).filter { |r| r.present? }
|
||||
|
||||
hit = false
|
||||
antenna_accounts.where(exclude: true).destroy_all
|
||||
account_names.each do |name|
|
||||
name = name[1..-1] if name.start_with?('@')
|
||||
username, domain = name.split('@')
|
||||
account = Account.find_by(username: username, domain: domain)
|
||||
if account.present?
|
||||
antenna_accounts.create!(account: account, exclude: true)
|
||||
hit = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
17
app/models/antenna_account.rb
Normal file
17
app/models/antenna_account.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: antenna_accounts
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# antenna_id :bigint(8) not null
|
||||
# account_id :bigint(8) not null
|
||||
# exclude :boolean default(FALSE), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
class AntennaAccount < ApplicationRecord
|
||||
|
||||
belongs_to :antenna
|
||||
belongs_to :account
|
||||
|
||||
end
|
16
app/models/antenna_domain.rb
Normal file
16
app/models/antenna_domain.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: antenna_domains
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# antenna_id :bigint(8) not null
|
||||
# name :string
|
||||
# exclude :boolean default(FALSE), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
class AntennaDomain < ApplicationRecord
|
||||
|
||||
belongs_to :antenna
|
||||
|
||||
end
|
17
app/models/antenna_tag.rb
Normal file
17
app/models/antenna_tag.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: antenna_tags
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# antenna_id :bigint(8) not null
|
||||
# tag_id :bigint(8) not null
|
||||
# exclude :boolean default(FALSE), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
class AntennaTag < ApplicationRecord
|
||||
|
||||
belongs_to :antenna
|
||||
belongs_to :tag
|
||||
|
||||
end
|
|
@ -39,6 +39,8 @@ module AccountAssociations
|
|||
|
||||
has_many :report_notes, dependent: :destroy
|
||||
has_many :custom_filters, inverse_of: :account, dependent: :destroy
|
||||
has_many :antennas, inverse_of: :account, dependent: :destroy
|
||||
has_many :antenna_accounts, inverse_of: :account, dependent: :destroy
|
||||
|
||||
# Moderation notes
|
||||
has_many :account_moderation_notes, dependent: :destroy, inverse_of: :account
|
||||
|
|
|
@ -23,6 +23,7 @@ class List < ApplicationRecord
|
|||
|
||||
has_many :list_accounts, inverse_of: :list, dependent: :destroy
|
||||
has_many :accounts, through: :list_accounts
|
||||
has_many :antennas, inverse_of: :list, dependent: :destroy
|
||||
|
||||
validates :title, presence: true
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ class Tag < ApplicationRecord
|
|||
has_many :featured_tags, dependent: :destroy, inverse_of: :tag
|
||||
has_many :followers, through: :passive_relationships, source: :account
|
||||
|
||||
has_one :antenna_tag, dependent: :destroy, inverse_of: :tag
|
||||
|
||||
HASHTAG_SEPARATORS = "_\u00B7\u30FB\u200c"
|
||||
HASHTAG_FIRST_SEQUENCE_CHUNK_ONE = "[[:word:]_][[:word:]#{HASHTAG_SEPARATORS}]*[[:alpha:]#{HASHTAG_SEPARATORS}]"
|
||||
HASHTAG_FIRST_SEQUENCE_CHUNK_TWO = "[[:word:]#{HASHTAG_SEPARATORS}]*[[:word:]_]"
|
||||
|
|
|
@ -49,6 +49,7 @@ class FanOutOnWriteService < BaseService
|
|||
when :public, :unlisted, :public_unlisted, :private
|
||||
deliver_to_all_followers!
|
||||
deliver_to_lists!
|
||||
deliver_to_antennas! if [:public, :public_unlisted].include?(@status.visibility.to_sym)
|
||||
when :limited
|
||||
deliver_to_mentioned_followers!
|
||||
else
|
||||
|
@ -115,6 +116,31 @@ class FanOutOnWriteService < BaseService
|
|||
end
|
||||
end
|
||||
|
||||
def deliver_to_antennas!
|
||||
lists = []
|
||||
antennas = Antenna.availables
|
||||
antennas = antennas.left_joins(:antenna_accounts).where(any_accounts: true).or(Antenna.left_joins(:antenna_accounts) .where(antenna_accounts: { exclude: false, account: @status.account }))
|
||||
antennas = antennas.left_joins(:antenna_domains) .where(any_domains: true) .or(Antenna.left_joins(:antenna_accounts).left_joins(:antenna_domains) .where(antenna_domains: { exclude: false, name: @status.account.domain }))
|
||||
antennas = antennas.left_joins(:antenna_tags) .where(any_tags: true) .or(Antenna.left_joins(:antenna_accounts).left_joins(:antenna_domains).left_joins(:antenna_tags).where(antenna_tags: { exclude: false, tag: @status.tags }))
|
||||
antennas.in_batches do |ans|
|
||||
ans.each do |antenna|
|
||||
next if !antenna.enabled?
|
||||
next if antenna.keywords.any? && !antenna.keywords.any? { |keyword| @status.text.include?(keyword) }
|
||||
next if antenna.exclude_keywords.any? && antenna.exclude_keywords.any? { |keyword| @status.text.include?(keyword) }
|
||||
next if antenna.antenna_accounts.where(exclude: true, account: @status.account).any?
|
||||
next if antenna.antenna_domains.where(exclude: true, name: @status.account.domain).any?
|
||||
next if antenna.antenna_tags.where(exclude: true, tag: @status.tags).any?
|
||||
lists << antenna.list
|
||||
end
|
||||
end
|
||||
|
||||
if lists.any?
|
||||
FeedInsertWorker.push_bulk(lists) do |list|
|
||||
[@status.id, list.id, 'list', { 'update' => update? }]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def deliver_to_mentioned_followers!
|
||||
@status.mentions.joins(:account).merge(@account.followers_for_local_distribution).select(:id, :account_id).reorder(nil).find_in_batches do |mentions|
|
||||
FeedInsertWorker.push_bulk(mentions) do |mention|
|
||||
|
|
65
app/views/antennas/_antenna.html.haml
Normal file
65
app/views/antennas/_antenna.html.haml
Normal file
|
@ -0,0 +1,65 @@
|
|||
.filters-list__item{ class: [antenna.expired? && 'expired'] }
|
||||
= link_to edit_antenna_path(antenna), class: 'filters-list__item__title' do
|
||||
= antenna.title
|
||||
|
||||
- if antenna.expires?
|
||||
.expiration{ title: t('antennas.index.expires_on', date: l(antenna.expires_at)) }
|
||||
- if antenna.expired?
|
||||
= t('invites.expired')
|
||||
- else
|
||||
= t('antennas.index.expires_in', distance: distance_of_time_in_words_to_now(antenna.expires_at))
|
||||
|
||||
.filters-list__item__permissions
|
||||
%ul.permissions-list
|
||||
- unless antenna.antenna_domains.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= fa_icon('sitemap')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.domains', count: antenna.antenna_domains.size)
|
||||
.permissions-list__item__text__type
|
||||
- domains = antenna.antenna_domains.map { |domain| domain.name }
|
||||
- domains = domains.take(5) + ['…'] if domains.size > 5 # TODO
|
||||
= domains.join(', ')
|
||||
- unless antenna.antenna_accounts.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= fa_icon('users')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.accounts', count: antenna.antenna_accounts.size)
|
||||
.permissions-list__item__text__type
|
||||
- accounts = antenna.antenna_accounts.map { |account| account.account.domain ? "@#{account.account.username}@#{account.account.domain}" : "@#{account.account.username}" }
|
||||
- accounts = accounts.take(5) + ['…'] if accounts.size > 5 # TODO
|
||||
= accounts.join(', ')
|
||||
- unless antenna.keywords.nil? || antenna.keywords.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= fa_icon('paragraph')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.keywords', count: antenna.keywords.size)
|
||||
.permissions-list__item__text__type
|
||||
- keywords = antenna.keywords
|
||||
- keywords = keywords.take(5) + ['…'] if keywords.size > 5 # TODO
|
||||
= keywords.join(', ')
|
||||
- unless antenna.antenna_tags.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= fa_icon('hashtag')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.tags', count: antenna.antenna_tags.size)
|
||||
.permissions-list__item__text__type
|
||||
- tags = antenna.antenna_tags.map { |tag| tag.tag.name }
|
||||
- tags = keywords.take(5) + ['…'] if tags.size > 5 # TODO
|
||||
= tags.join(', ')
|
||||
|
||||
.announcements-list__item__action-bar
|
||||
.announcements-list__item__meta
|
||||
= t('antenna.index.contexts', contexts: antenna.context.map { |context| I18n.t("antenna.contexts.#{context}") }.join(', '))
|
||||
|
||||
%div
|
||||
= table_link_to 'pencil', t('antennas.edit.title'), edit_antenna_path(antenna)
|
||||
= table_link_to 'times', t('antennas.index.delete'), antenna_path(antenna), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
45
app/views/antennas/_antenna_fields.html.haml
Normal file
45
app/views/antennas/_antenna_fields.html.haml
Normal file
|
@ -0,0 +1,45 @@
|
|||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :title, as: :string, wrapper: :with_label, hint: false
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: lambda { |i| I18n.t("invites.expires_in.#{i}") }, include_blank: I18n.t('invites.expires_in_prompt')
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :list, collection: lists, wrapper: :with_label, label_method: lambda { |list| list.title }, selected: f.object.list&.id, hint: false
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :available, wrapper: :with_label, hint: false
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
%h4= t('antennas.edit.domains')
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :domains_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :exclude_domains_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
|
||||
%h4= t('antennas.edit.accounts')
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :accounts_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :exclude_accounts_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
|
||||
%h4= t('antennas.edit.tags')
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :tags_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :exclude_tags_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
|
||||
%h4= t('antennas.edit.keywords')
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :keywords_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :exclude_keywords_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }
|
8
app/views/antennas/_keyword_fields.html.haml
Normal file
8
app/views/antennas/_keyword_fields.html.haml
Normal file
|
@ -0,0 +1,8 @@
|
|||
%tr.nested-fields
|
||||
%td= f.input :keyword, as: :string
|
||||
%td
|
||||
.label_input__wrapper= f.input_field :whole_word
|
||||
%td
|
||||
= f.hidden_field :id if f.object&.persisted? # Required so Rails doesn't put the field outside of the <tr/>
|
||||
= link_to_remove_association(f, class: 'table-action-link') do
|
||||
= safe_join([fa_icon('times'), t('antennas.index.delete')])
|
8
app/views/antennas/edit.html.haml
Normal file
8
app/views/antennas/edit.html.haml
Normal file
|
@ -0,0 +1,8 @@
|
|||
- content_for :page_title do
|
||||
= t('antennas.edit.title')
|
||||
|
||||
= simple_form_for @antenna, url: antenna_path(@antenna), method: :put do |f|
|
||||
= render 'antenna_fields', f: f, lists: @lists
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
11
app/views/antennas/index.html.haml
Normal file
11
app/views/antennas/index.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
|||
- content_for :page_title do
|
||||
= t('antennas.index.title')
|
||||
|
||||
- content_for :heading_actions do
|
||||
= link_to t('antennas.new.title'), new_antenna_path, class: 'button'
|
||||
|
||||
- if @antennas.empty?
|
||||
.muted-hint.center-text= t 'antennas.index.empty'
|
||||
- else
|
||||
.applications-list
|
||||
= render partial: 'antenna', collection: @antennas
|
8
app/views/antennas/new.html.haml
Normal file
8
app/views/antennas/new.html.haml
Normal file
|
@ -0,0 +1,8 @@
|
|||
- content_for :page_title do
|
||||
= t('antennas.new.title')
|
||||
|
||||
= simple_form_for @antenna, url: antennas_path do |f|
|
||||
= render 'antenna_fields', f: f, lists: @lists
|
||||
|
||||
.actions
|
||||
= f.button :button, t('antennas.new.save'), type: :submit
|
|
@ -964,6 +964,27 @@ en:
|
|||
empty: You have no aliases.
|
||||
hint_html: If you want to move from another account to this one, here you can create an alias, which is required before you can proceed with moving followers from the old account to this one. This action by itself is <strong>harmless and reversible</strong>. <strong>The account migration is initiated from the old account</strong>.
|
||||
remove: Unlink alias
|
||||
antennas:
|
||||
contexts:
|
||||
account: Accounts
|
||||
domain: Domains
|
||||
keyword: Keywords
|
||||
tag: Tags
|
||||
edit:
|
||||
title: Edit antenna
|
||||
errors:
|
||||
deprecated_api_multiple_keywords: These parameters cannot be changed from this application because they apply to more than one filter keyword. Use a more recent application or the web interface.
|
||||
invalid_context: None or invalid context supplied
|
||||
index:
|
||||
contexts: Antennas in %{contexts}
|
||||
delete: Delete
|
||||
empty: You have no antennas.
|
||||
expires_in: Expires in %{distance}
|
||||
expires_on: Expires on %{date}
|
||||
title: Antennas
|
||||
new:
|
||||
save: Save new antenna
|
||||
title: Add new antenna
|
||||
appearance:
|
||||
advanced_web_interface: Advanced web interface
|
||||
advanced_web_interface_hint: 'If you want to make use of your entire screen width, the advanced web interface allows you to configure many different columns to see as much information at the same time as you want: Home, notifications, federated timeline, any number of lists and hashtags.'
|
||||
|
|
|
@ -946,6 +946,32 @@ ja:
|
|||
empty: エイリアスがありません。
|
||||
hint_html: 他のアカウントからこのアカウントにフォロワーを引き継いで引っ越したい場合、ここでエイリアスを作成しておく必要があります。エイリアス自体は<strong>無害で、取り消す</strong>ことができます。<strong>引っ越しは以前のアカウント側から開始する必要があります</strong>。
|
||||
remove: エイリアスを削除
|
||||
antennas:
|
||||
contexts:
|
||||
account: アカウント
|
||||
domain: ドメイン
|
||||
keyword: キーワード
|
||||
tag: ハッシュタグ
|
||||
edit:
|
||||
title: アンテナを編集
|
||||
index:
|
||||
accounts:
|
||||
other: "%{count}件のアカウント"
|
||||
contexts: "%{contexts}のアンテナ"
|
||||
delete: 削除
|
||||
domains:
|
||||
other: "%{count}件のドメイン"
|
||||
empty: アンテナはありません。
|
||||
expires_in: "%{distance}で期限切れ"
|
||||
expires_on: 有効期限 %{date}
|
||||
keywords:
|
||||
other: "%{count}件のキーワード"
|
||||
tags:
|
||||
other: "%{count}件のタグ"
|
||||
title: アンテナ
|
||||
new:
|
||||
save: 新規アンテナを保存
|
||||
title: 新規アンテナを追加
|
||||
appearance:
|
||||
advanced_web_interface: 上級者向けUI
|
||||
advanced_web_interface_hint: ディスプレイを幅いっぱいまで活用したい場合、上級者向け UI をおすすめします。ホーム、通知、連合タイムライン、更にはリストやハッシュタグなど、様々な異なるカラムから望む限りの情報を一度に受け取れるような設定が可能になります。
|
||||
|
|
|
@ -17,6 +17,7 @@ SimpleNavigation::Configuration.run do |navigation|
|
|||
|
||||
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? }
|
||||
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
|
||||
n.item :antennas, safe_join([fa_icon('wifi fw'), t('antennas.index.title')]), antennas_path
|
||||
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? }
|
||||
|
||||
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s|
|
||||
|
|
|
@ -216,6 +216,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
end
|
||||
resources :antennas, except: [:show]
|
||||
|
||||
resource :relationships, only: [:show, :update]
|
||||
resource :statuses_cleanup, controller: :statuses_cleanup, only: [:show, :update]
|
||||
|
|
40
db/migrate/20230423002728_create_antennas.rb
Normal file
40
db/migrate/20230423002728_create_antennas.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
class CreateAntennas < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :antennas do |t|
|
||||
t.belongs_to :account, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.belongs_to :list, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.string :title, null: false, default: ''
|
||||
t.jsonb :keywords
|
||||
t.jsonb :exclude_keywords
|
||||
t.boolean :any_domains, null: false, default: true, index: true
|
||||
t.boolean :any_tags, null: false, default: true, index: true
|
||||
t.boolean :any_accounts, null: false, default: true, index: true
|
||||
t.boolean :any_keywords, null: false, default: true, index: true
|
||||
t.boolean :available, null: false, default: true, index: true
|
||||
t.datetime :created_at, null: false
|
||||
t.datetime :updated_at, null: false
|
||||
t.datetime :expires_at
|
||||
end
|
||||
create_table :antenna_domains do |t|
|
||||
t.belongs_to :antenna, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.string :name, index: true
|
||||
t.boolean :exclude, null: false, default: false, index: true
|
||||
t.datetime :created_at, null: false
|
||||
t.datetime :updated_at, null: false
|
||||
end
|
||||
create_table :antenna_tags do |t|
|
||||
t.belongs_to :antenna, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.belongs_to :tag, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.boolean :exclude, null: false, default: false, index: true
|
||||
t.datetime :created_at, null: false
|
||||
t.datetime :updated_at, null: false
|
||||
end
|
||||
create_table :antenna_accounts do |t|
|
||||
t.belongs_to :antenna, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.belongs_to :account, null: false, foreign_key: { on_delete: :cascade }
|
||||
t.boolean :exclude, null: false, default: false, index: true
|
||||
t.datetime :created_at, null: false
|
||||
t.datetime :updated_at, null: false
|
||||
end
|
||||
end
|
||||
end
|
65
db/schema.rb
65
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: 2023_04_20_081634) do
|
||||
ActiveRecord::Schema.define(version: 2023_04_23_002728) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -253,6 +253,62 @@ ActiveRecord::Schema.define(version: 2023_04_20_081634) do
|
|||
t.bigint "status_ids", array: true
|
||||
end
|
||||
|
||||
create_table "antenna_accounts", force: :cascade do |t|
|
||||
t.bigint "antenna_id", null: false
|
||||
t.bigint "account_id", null: false
|
||||
t.boolean "exclude", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id"], name: "index_antenna_accounts_on_account_id"
|
||||
t.index ["antenna_id"], name: "index_antenna_accounts_on_antenna_id"
|
||||
t.index ["exclude"], name: "index_antenna_accounts_on_exclude"
|
||||
end
|
||||
|
||||
create_table "antenna_domains", force: :cascade do |t|
|
||||
t.bigint "antenna_id", null: false
|
||||
t.string "name"
|
||||
t.boolean "exclude", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["antenna_id"], name: "index_antenna_domains_on_antenna_id"
|
||||
t.index ["exclude"], name: "index_antenna_domains_on_exclude"
|
||||
t.index ["name"], name: "index_antenna_domains_on_name"
|
||||
end
|
||||
|
||||
create_table "antenna_tags", force: :cascade do |t|
|
||||
t.bigint "antenna_id", null: false
|
||||
t.bigint "tag_id", null: false
|
||||
t.boolean "exclude", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["antenna_id"], name: "index_antenna_tags_on_antenna_id"
|
||||
t.index ["exclude"], name: "index_antenna_tags_on_exclude"
|
||||
t.index ["tag_id"], name: "index_antenna_tags_on_tag_id"
|
||||
end
|
||||
|
||||
create_table "antennas", force: :cascade do |t|
|
||||
t.bigint "account_id", null: false
|
||||
t.bigint "list_id", null: false
|
||||
t.string "title", default: "", null: false
|
||||
t.jsonb "keywords"
|
||||
t.jsonb "exclude_keywords"
|
||||
t.boolean "any_domains", default: true, null: false
|
||||
t.boolean "any_tags", default: true, null: false
|
||||
t.boolean "any_accounts", default: true, null: false
|
||||
t.boolean "any_keywords", default: true, null: false
|
||||
t.boolean "available", default: true, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "expires_at"
|
||||
t.index ["account_id"], name: "index_antennas_on_account_id"
|
||||
t.index ["any_accounts"], name: "index_antennas_on_any_accounts"
|
||||
t.index ["any_domains"], name: "index_antennas_on_any_domains"
|
||||
t.index ["any_keywords"], name: "index_antennas_on_any_keywords"
|
||||
t.index ["any_tags"], name: "index_antennas_on_any_tags"
|
||||
t.index ["available"], name: "index_antennas_on_available"
|
||||
t.index ["list_id"], name: "index_antennas_on_list_id"
|
||||
end
|
||||
|
||||
create_table "appeals", force: :cascade do |t|
|
||||
t.bigint "account_id", null: false
|
||||
t.bigint "account_warning_id", null: false
|
||||
|
@ -1175,6 +1231,13 @@ ActiveRecord::Schema.define(version: 2023_04_20_081634) do
|
|||
add_foreign_key "announcement_reactions", "accounts", on_delete: :cascade
|
||||
add_foreign_key "announcement_reactions", "announcements", on_delete: :cascade
|
||||
add_foreign_key "announcement_reactions", "custom_emojis", on_delete: :cascade
|
||||
add_foreign_key "antenna_accounts", "accounts", on_delete: :cascade
|
||||
add_foreign_key "antenna_accounts", "antennas", on_delete: :cascade
|
||||
add_foreign_key "antenna_domains", "antennas", on_delete: :cascade
|
||||
add_foreign_key "antenna_tags", "antennas", on_delete: :cascade
|
||||
add_foreign_key "antenna_tags", "tags", on_delete: :cascade
|
||||
add_foreign_key "antennas", "accounts", on_delete: :cascade
|
||||
add_foreign_key "antennas", "lists", on_delete: :cascade
|
||||
add_foreign_key "appeals", "account_warnings", on_delete: :cascade
|
||||
add_foreign_key "appeals", "accounts", column: "approved_by_account_id", on_delete: :nullify
|
||||
add_foreign_key "appeals", "accounts", column: "rejected_by_account_id", on_delete: :nullify
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue