You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.4 KiB
130 lines
3.4 KiB
# frozen_string_literal: true |
|
|
|
# == Schema Information |
|
# |
|
# Table name: announcements |
|
# |
|
# id :bigint(8) not null, primary key |
|
# all_day :boolean default(FALSE), not null |
|
# ends_at :datetime |
|
# notification_sent_at :datetime |
|
# published :boolean default(FALSE), not null |
|
# published_at :datetime |
|
# scheduled_at :datetime |
|
# starts_at :datetime |
|
# status_ids :bigint(8) is an Array |
|
# text :text default(""), not null |
|
# created_at :datetime not null |
|
# updated_at :datetime not null |
|
# |
|
|
|
class Announcement < ApplicationRecord |
|
scope :unpublished, -> { where(published: false) } |
|
scope :published, -> { where(published: true) } |
|
scope :chronological, -> { order(coalesced_chronology_timestamps.asc) } |
|
scope :reverse_chronological, -> { order(coalesced_chronology_timestamps.desc) } |
|
|
|
has_many :announcement_mutes, dependent: :destroy |
|
has_many :announcement_reactions, dependent: :destroy |
|
|
|
validates :text, presence: true |
|
validates :starts_at, presence: true, if: :ends_at? |
|
validates :ends_at, presence: true, if: :starts_at? |
|
|
|
before_validation :set_published, on: :create |
|
|
|
class << self |
|
def coalesced_chronology_timestamps |
|
Arel.sql( |
|
<<~SQL.squish |
|
COALESCE(announcements.starts_at, announcements.scheduled_at, announcements.published_at, announcements.created_at) |
|
SQL |
|
) |
|
end |
|
end |
|
|
|
def to_log_human_identifier |
|
text |
|
end |
|
|
|
def publish! |
|
update!(published: true, published_at: Time.now.utc, scheduled_at: nil) |
|
end |
|
|
|
def unpublish! |
|
update!(published: false, scheduled_at: nil) |
|
end |
|
|
|
def notification_sent? |
|
notification_sent_at.present? |
|
end |
|
|
|
def mentions |
|
@mentions ||= Account.from_text(text) |
|
end |
|
|
|
def statuses |
|
@statuses ||= begin |
|
if status_ids.nil? |
|
[] |
|
else |
|
Status.with_includes.distributable_visibility.where(id: status_ids) |
|
end |
|
end |
|
end |
|
|
|
def tags |
|
@tags ||= Tag.find_or_create_by_names(Extractor.extract_hashtags(text)) |
|
end |
|
|
|
def emojis |
|
@emojis ||= CustomEmoji.from_text(text) |
|
end |
|
|
|
def reactions(account = nil) |
|
grouped_ordered_announcement_reactions.select( |
|
[:name, :custom_emoji_id, 'COUNT(*) as count'].tap do |values| |
|
values << value_for_reaction_me_column(account) |
|
end |
|
).to_a.tap do |records| |
|
ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji).call |
|
end |
|
end |
|
|
|
def scope_for_notification |
|
User.confirmed.joins(:account).merge(Account.without_suspended) |
|
end |
|
|
|
private |
|
|
|
def grouped_ordered_announcement_reactions |
|
announcement_reactions |
|
.group(:announcement_id, :name, :custom_emoji_id) |
|
.order( |
|
Arel.sql('MIN(created_at)').asc |
|
) |
|
end |
|
|
|
def value_for_reaction_me_column(account) |
|
if account.nil? |
|
'FALSE AS me' |
|
else |
|
<<~SQL.squish |
|
EXISTS( |
|
SELECT 1 |
|
FROM announcement_reactions inner_reactions |
|
WHERE inner_reactions.account_id = #{account.id} |
|
AND inner_reactions.announcement_id = announcement_reactions.announcement_id |
|
AND inner_reactions.name = announcement_reactions.name |
|
) AS me |
|
SQL |
|
end |
|
end |
|
|
|
def set_published |
|
return unless scheduled_at.blank? || scheduled_at.past? |
|
|
|
self.published = true |
|
self.published_at = Time.now.utc |
|
end |
|
end
|
|
|