diff options
author | Thibaut Girka <thib@sitedethib.com> | 2018-12-09 13:28:09 +0100 |
---|---|---|
committer | Thibaut Girka <thib@sitedethib.com> | 2018-12-09 16:08:04 +0100 |
commit | e7f1bfdc2d528f137299ba0c3ab2a30f2f91f53c (patch) | |
tree | 2693ffce4d340a9b77a7ca52c856aaae7af8c913 /app/models | |
parent | e3682c9c1750e5e7e5d2f817e29f6760a18400ca (diff) | |
parent | 81bda7d67c984c9bfcb5bca94e50cec6405b492e (diff) |
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/javascript/packs/public.js - app/models/user.rb - config/settings.yml - db/schema.rb Moved public.js changes to settings.js.
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 40 | ||||
-rw-r--r-- | app/models/account_stat.rb | 12 | ||||
-rw-r--r-- | app/models/account_tag_stat.rb | 24 | ||||
-rw-r--r-- | app/models/concerns/account_associations.rb | 3 | ||||
-rw-r--r-- | app/models/concerns/account_counters.rb | 1 | ||||
-rw-r--r-- | app/models/tag.rb | 31 | ||||
-rw-r--r-- | app/models/user.rb | 6 |
7 files changed, 114 insertions, 3 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index e6b5bd69f..71264bc9f 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -43,11 +43,13 @@ # featured_collection_url :string # fields :jsonb # actor_type :string +# discoverable :boolean # class Account < ApplicationRecord USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i + MIN_FOLLOWERS_DISCOVERY = 10 include AccountAssociations include AccountAvatar @@ -93,6 +95,10 @@ class Account < ApplicationRecord scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) } scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } scope :searchable, -> { where(suspended: false).where(moved_to_account_id: nil) } + scope :discoverable, -> { where(silenced: false).where(discoverable: true).joins(:account_stat).where(AccountStat.arel_table[:followers_count].gteq(MIN_FOLLOWERS_DISCOVERY)) } + scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) } + scope :popular, -> { order('account_stats.followers_count desc') } + scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) } delegate :email, :unconfirmed_email, @@ -178,6 +184,40 @@ class Account < ApplicationRecord @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key) end + def tags_as_strings=(tag_names) + tag_names.map! { |name| name.mb_chars.downcase.to_s } + tag_names.uniq! + + # Existing hashtags + hashtags_map = Tag.where(name: tag_names).each_with_object({}) { |tag, h| h[tag.name] = tag } + + # Initialize not yet existing hashtags + tag_names.each do |name| + next if hashtags_map.key?(name) + hashtags_map[name] = Tag.new(name: name) + end + + # Remove hashtags that are to be deleted + tags.each do |tag| + if hashtags_map.key?(tag.name) + hashtags_map.delete(tag.name) + else + transaction do + tags.delete(tag) + tag.decrement_count!(:accounts_count) + end + end + end + + # Add hashtags that were so far missing + hashtags_map.each_value do |tag| + transaction do + tags << tag + tag.increment_count!(:accounts_count) + end + end + end + def fields (self[:fields] || []).map { |f| Field.new(self, f) } end diff --git a/app/models/account_stat.rb b/app/models/account_stat.rb index d5715268e..9813aa84f 100644 --- a/app/models/account_stat.rb +++ b/app/models/account_stat.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true - # == Schema Information # # Table name: account_stats @@ -11,16 +10,25 @@ # followers_count :bigint(8) default(0), not null # created_at :datetime not null # updated_at :datetime not null +# last_status_at :datetime # class AccountStat < ApplicationRecord belongs_to :account, inverse_of: :account_stat def increment_count!(key) - update(key => public_send(key) + 1) + update(attributes_for_increment(key)) end def decrement_count!(key) update(key => [public_send(key) - 1, 0].max) end + + private + + def attributes_for_increment(key) + attrs = { key => public_send(key) + 1 } + attrs[:last_status_at] = Time.now.utc if key == :statuses_count + attrs + end end diff --git a/app/models/account_tag_stat.rb b/app/models/account_tag_stat.rb new file mode 100644 index 000000000..3c36c155a --- /dev/null +++ b/app/models/account_tag_stat.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: account_tag_stats +# +# id :bigint(8) not null, primary key +# tag_id :bigint(8) not null +# accounts_count :bigint(8) default(0), not null +# hidden :boolean default(FALSE), not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class AccountTagStat < ApplicationRecord + belongs_to :tag, inverse_of: :account_tag_stat + + def increment_count!(key) + update(key => public_send(key) + 1) + end + + def decrement_count!(key) + update(key => [public_send(key) - 1, 0].max) + end +end diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb index 9dba8000d..38e2481c5 100644 --- a/app/models/concerns/account_associations.rb +++ b/app/models/concerns/account_associations.rb @@ -50,5 +50,8 @@ module AccountAssociations # Account migrations belongs_to :moved_to_account, class_name: 'Account', optional: true + + # Hashtags + has_and_belongs_to_many :tags end end diff --git a/app/models/concerns/account_counters.rb b/app/models/concerns/account_counters.rb index fa3ec9a3d..3581df8dd 100644 --- a/app/models/concerns/account_counters.rb +++ b/app/models/concerns/account_counters.rb @@ -16,6 +16,7 @@ module AccountCounters :followers_count=, :increment_count!, :decrement_count!, + :last_status_at, to: :account_stat def account_stat diff --git a/app/models/tag.rb b/app/models/tag.rb index 4f31f796e..99830ae92 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -11,12 +11,36 @@ class Tag < ApplicationRecord has_and_belongs_to_many :statuses + has_and_belongs_to_many :accounts + has_and_belongs_to_many :sample_accounts, -> { searchable.discoverable.popular.limit(3) }, class_name: 'Account' + + has_one :account_tag_stat, dependent: :destroy HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_·][[:word:]_]*' HASHTAG_RE = /(?:^|[^\/\)\w])#(#{HASHTAG_NAME_RE})/i validates :name, presence: true, uniqueness: true, format: { with: /\A#{HASHTAG_NAME_RE}\z/i } + scope :discoverable, -> { joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).where(account_tag_stats: { hidden: false }).order(Arel.sql('account_tag_stats.accounts_count desc')) } + scope :hidden, -> { where(account_tag_stats: { hidden: true }) } + + delegate :accounts_count, + :accounts_count=, + :increment_count!, + :decrement_count!, + :hidden?, + to: :account_tag_stat + + after_save :save_account_tag_stat + + def account_tag_stat + super || build_account_tag_stat + end + + def cached_sample_accounts + Rails.cache.fetch("#{cache_key}/sample_accounts", expires_in: 12.hours) { sample_accounts } + end + def to_param name end @@ -43,4 +67,11 @@ class Tag < ApplicationRecord Tag.where('lower(name) like lower(?)', pattern).order(:name).limit(limit) end end + + private + + def save_account_tag_stat + return unless account_tag_stat&.changed? + account_tag_stat.save + end end diff --git a/app/models/user.rb b/app/models/user.rb index 704523d34..5a21419bf 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -95,7 +95,7 @@ class User < ApplicationRecord delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal, :reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_network, - :expand_spoilers, :default_language, to: :settings, prefix: :setting, allow_nil: false + :expand_spoilers, :default_language, :aggregate_reblogs, to: :settings, prefix: :setting, allow_nil: false attr_reader :invite_code @@ -231,6 +231,10 @@ class User < ApplicationRecord @hides_network ||= settings.hide_network end + def aggregates_reblogs? + @aggregates_reblogs ||= settings.aggregate_reblogs + end + def token_for_app(a) return nil if a.nil? || a.owner != self Doorkeeper::AccessToken |