From cf3ec71aa564c7fe47ec79f8dd5f14e3bce0b85c Mon Sep 17 00:00:00 2001 From: multiple creatures Date: Mon, 15 Jul 2019 13:34:05 -0500 Subject: local visibility scope, chat scope+tags, unlisted tags --- app/models/account.rb | 9 +++++++- app/models/chat_account.rb | 17 ++++++++++++++ app/models/concerns/status_threading_concern.rb | 2 +- app/models/featured_tag.rb | 6 ++--- app/models/status.rb | 30 +++++++++++++++---------- app/models/tag.rb | 27 ++++++++++++++++------ 6 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 app/models/chat_account.rb (limited to 'app/models') diff --git a/app/models/account.rb b/app/models/account.rb index 97ebd14d3..7040f138b 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -71,7 +71,8 @@ class Account < ApplicationRecord LOCAL_DOMAINS = ENV.fetch('LOCAL_DOMAINS', '').chomp.split(/\.?\s+/).freeze - enum protocol: [:ostatus, :activitypub] + has_many :chat_accounts, dependent: :destroy, inverse_of: :account + has_many :chat_tags, through: :chat_accounts, source: :tag validates :username, presence: true @@ -545,6 +546,7 @@ class Account < ApplicationRecord before_create :generate_keys before_create :set_domain_from_inbox_url + before_create :set_chat_support before_validation :prepare_contents, if: :local? before_validation :prepare_username, on: :create before_destroy :clean_feed_manager @@ -567,6 +569,11 @@ class Account < ApplicationRecord nil end + def set_chat_support + return unless local? + self.supports_chat = true + end + def generate_keys return unless local? && !Rails.env.test? diff --git a/app/models/chat_account.rb b/app/models/chat_account.rb new file mode 100644 index 000000000..41589a395 --- /dev/null +++ b/app/models/chat_account.rb @@ -0,0 +1,17 @@ +# == Schema Information +# +# Table name: chat_accounts +# +# id :bigint(8) not null, primary key +# account_id :bigint(8) not null +# tag_id :bigint(8) not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class ChatAccount < ApplicationRecord + belongs_to :account, inverse_of: :chat_accounts + belongs_to :tag, inverse_of: :chat_accounts + + validates :account_id, uniqueness: { scope: :tag_id } +end diff --git a/app/models/concerns/status_threading_concern.rb b/app/models/concerns/status_threading_concern.rb index 15eb695cd..1e5c52c46 100644 --- a/app/models/concerns/status_threading_concern.rb +++ b/app/models/concerns/status_threading_concern.rb @@ -12,7 +12,7 @@ module StatusThreadingConcern end def self_replies(limit) - account.statuses.where(in_reply_to_id: id, visibility: [:public, :unlisted]).reorder(id: :asc).limit(limit) + account.statuses.where(in_reply_to_id: id, visibility: [:public, :unlisted, :local]).reorder(id: :asc).limit(limit) end private diff --git a/app/models/featured_tag.rb b/app/models/featured_tag.rb index d06ae26a8..f4015fb07 100644 --- a/app/models/featured_tag.rb +++ b/app/models/featured_tag.rb @@ -31,12 +31,12 @@ class FeaturedTag < ApplicationRecord end def decrement(deleted_status_id) - update(statuses_count: [0, statuses_count - 1].max, last_status_at: account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).where.not(id: deleted_status_id).select(:created_at).first&.created_at) + update(statuses_count: [0, statuses_count - 1].max, last_status_at: account.statuses.where(visibility: %i(public unlisted local)).tagged_with(tag).where.not(id: deleted_status_id).select(:created_at).first&.created_at) end def reset_data - self.statuses_count = account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).count - self.last_status_at = account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).select(:created_at).first&.created_at + self.statuses_count = account.statuses.where(visibility: %i(public unlisted local)).tagged_with(tag).count + self.last_status_at = account.statuses.where(visibility: %i(public unlisted local)).tagged_with(tag).select(:created_at).first&.created_at end private diff --git a/app/models/status.rb b/app/models/status.rb index 30af341cc..8315491f7 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -53,7 +53,7 @@ class Status < ApplicationRecord update_index('statuses#status', :proper) if Chewy.enabled? - enum visibility: [:public, :unlisted, :private, :direct, :limited], _suffix: :visibility + enum visibility: [:public, :unlisted, :private, :direct, :limited, :local, :chat], _suffix: :visibility belongs_to :application, class_name: 'Doorkeeper::Application', optional: true @@ -103,7 +103,8 @@ class Status < ApplicationRecord scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') } scope :reblogs, -> { where('statuses.reblog_of_id IS NOT NULL') } # all reblogs scope :with_public_visibility, -> { where(visibility: :public) } - scope :public_browsable, -> { where(visibility: [:public, :unlisted]) } + scope :public_local_visibility, -> { where(visibility: [:public, :local]) } + scope :public_browsable, -> { where(visibility: [:public, :unlisted, :local, :chat]) } scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) } @@ -240,7 +241,7 @@ class Status < ApplicationRecord end def distributable? - public_visibility? || unlisted_visibility? + public_visibility? || unlisted_visibility? || local_visibility? end def with_media? @@ -261,6 +262,11 @@ class Status < ApplicationRecord @emojis = CustomEmoji.from_text(fields.join(' '), account.domain) end + def chat_tags + return @chat_tags if defined?(@chat_tags) + @chat_tags = tags.only_chat + end + def mark_for_mass_destruction! @marked_for_mass_destruction = true end @@ -313,7 +319,7 @@ class Status < ApplicationRecord pattern = sanitize_sql_like(term) pattern = "#{pattern}" scope = Status.where("tsv @@ plainto_tsquery('english', ?)", pattern) - query = scope.where(visibility: :public) + query = scope.public_local_visibility if account.present? query = query .or(scope.where(account: account)) @@ -333,7 +339,7 @@ class Status < ApplicationRecord end def as_home_timeline(account) - where(account: [account] + account.following).where(visibility: [:public, :unlisted, :private]) + where(account: [account] + account.following, visibility: [:public, :unlisted, :local, :private]) end def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil, cache_ids = false) @@ -390,7 +396,7 @@ class Status < ApplicationRecord def as_tag_timeline(tag, account = nil, local_only = false, priv = false) query = tag_timeline_scope(account, local_only, priv).tagged_with(tag) - apply_timeline_filters(query, account, local_only) + apply_timeline_filters(query, account, local_only, true) end def as_outbox_timeline(account) @@ -438,7 +444,7 @@ class Status < ApplicationRecord end def permitted_for(target_account, account) - visibility = [:public, :unlisted] + visibility = [:public, :unlisted, :local] if account.nil? query = where(visibility: visibility).not_local_only @@ -464,7 +470,7 @@ class Status < ApplicationRecord def timeline_scope(local_only = false) starting_scope = local_only ? Status.network : Status - starting_scope = starting_scope.with_public_visibility + starting_scope = local_only ? starting_scope.public_local_visibility : starting_scope.with_public_visibility if Setting.show_reblogs_in_public_timelines starting_scope else @@ -498,19 +504,19 @@ class Status < ApplicationRecord end end - def apply_timeline_filters(query, account, local_only) + def apply_timeline_filters(query, account = nil, local_only = false, tag_timeline = false) if account.nil? filter_timeline_default(query) else - filter_timeline_for_account(query, account, local_only) + filter_timeline_for_account(query, account, local_only, tag_timeline) end end - def filter_timeline_for_account(query, account, local_only) + def filter_timeline_for_account(query, account, local_only, tag_timeline) query = query.not_excluded_by_account(account) query = query.not_domain_blocked_by_account(account) unless local_only query = query.in_chosen_languages(account) if account.chosen_languages.present? - query = query.reply_not_excluded_by_account(account) + query = query.reply_not_excluded_by_account(account) unless tag_timeline query = query.mention_not_excluded_by_account(account) query.merge(account_silencing_filter(account)) end diff --git a/app/models/tag.rb b/app/models/tag.rb index d3511a54e..858f674c3 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -9,6 +9,8 @@ # updated_at :datetime not null # local :boolean default(FALSE), not null # private :boolean default(FALSE), not null +# unlisted :boolean default(FALSE), not null +# chat :boolean default(FALSE), not null # class Tag < ApplicationRecord @@ -17,6 +19,9 @@ class Tag < ApplicationRecord has_and_belongs_to_many :sample_accounts, -> { searchable.discoverable.popular.limit(3) }, class_name: 'Account' has_many :featured_tags, dependent: :destroy, inverse_of: :tag + has_many :chat_accounts, dependent: :destroy, inverse_of: :tag + has_many :chatters, through: :chat_accounts, source: :account + has_one :account_tag_stat, dependent: :destroy HASHTAG_NAME_RE = '[[:word:]:._\-]*[[:alpha:]:._ยท\-][[:word:]:._\-]*' @@ -28,10 +33,12 @@ class Tag < ApplicationRecord scope :hidden, -> { where(account_tag_stats: { hidden: true }) } scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) } - scope :only_local, -> { where(local: true) } - scope :only_global, -> { where(local: false) } + scope :only_local, -> { where(local: true, unlisted: false) } + scope :only_global, -> { where(local: false, unlisted: false) } scope :only_private, -> { where(private: true) } - scope :only_public, -> { where(private: false) } + scope :only_unlisted, -> { where(unlisted: true) } + scope :only_chat, -> { where(chat: true) } + scope :only_public, -> { where(unlisted: false) } delegate :accounts_count, :accounts_count=, @@ -73,9 +80,11 @@ class Tag < ApplicationRecord class << self def search_for(term, limit = 5, offset = 0) - pattern = sanitize_sql_like(term.strip.gsub(':', '.')) + '%' + term = term.strip.gsub(':', '.') + pattern = sanitize_sql_like(term) + '%' - Tag.where('lower(name) like lower(?)', pattern) + Tag.only_public.where('lower(name) like lower(?)', pattern) + .or(Tag.only_unlisted.where(name: term)) .order(:name) .limit(limit) .offset(offset) @@ -98,7 +107,11 @@ class Tag < ApplicationRecord end def set_scope - self.private = true if name.in?(['self', '_self']) || name.starts_with?('self.', '_self.') - self.local = true if self.private || name.in?(['local', '_local']) || name.starts_with?('local.', '_local.') + self.private = true if name.in?(%w(self .self)) || name.starts_with?('self.', '.self.') + self.unlisted = true if self.private || name.starts_with?('.') + self.chat = true if name.starts_with?('chat.', '.chat') + self.local = true if self.private || + name.in?(%w(local .local chat.local .chat.local)) || + name.starts_with?('local.', '.local', 'chat.local.' '.chat.local') end end -- cgit