Separa i canali app e mostra il nodo ingest nelle sessioni admin. Co-authored-by: Cursor <cursoragent@cursor.com>
123 lines
3.5 KiB
Ruby
123 lines
3.5 KiB
Ruby
class AppAnnouncement < ApplicationRecord
|
|
KINDS = %w[info maintenance update].freeze
|
|
SEVERITIES = %w[info warning critical].freeze
|
|
STATUSES = %w[draft published archived].freeze
|
|
CHANNELS = {
|
|
android: :show_on_android,
|
|
ios: :show_on_ios,
|
|
web_public: :show_on_web_public,
|
|
web_private: :show_on_web_private
|
|
}.freeze
|
|
URL_FIELDS = %i[action_url android_action_url ios_action_url].freeze
|
|
|
|
belongs_to :created_by_admin, class_name: "AdminAccount", optional: true
|
|
|
|
validates :kind, :severity, :status, :title, :body, presence: true
|
|
validates :kind, inclusion: { in: KINDS }
|
|
validates :severity, inclusion: { in: SEVERITIES }
|
|
validates :status, inclusion: { in: STATUSES }
|
|
validates :title, :android_title, :ios_title, length: { maximum: 120 }, allow_blank: true
|
|
validates :body, :android_body, :ios_body, length: { maximum: 2000 }, allow_blank: true
|
|
validates :action_label, :android_action_label, :ios_action_label, length: { maximum: 40 }, allow_blank: true
|
|
URL_FIELDS.each do |field|
|
|
validates field, format: { with: /\Ahttps?:\/\/.+/i, allow_blank: true }
|
|
end
|
|
validate :ends_at_after_starts_at
|
|
validate :at_least_one_channel
|
|
|
|
scope :newest, -> { order(created_at: :desc) }
|
|
scope :published, -> { where(status: "published") }
|
|
scope :active_now, lambda {
|
|
now = Time.current
|
|
published
|
|
.where("starts_at IS NULL OR starts_at <= ?", now)
|
|
.where("ends_at IS NULL OR ends_at > ?", now)
|
|
}
|
|
|
|
def self.for_channel(channel)
|
|
column = CHANNELS[channel.to_sym]
|
|
raise ArgumentError, "unknown announcement channel: #{channel}" if column.blank?
|
|
|
|
active_now.where(column => true)
|
|
end
|
|
|
|
def self.for_app
|
|
active_now.where("show_on_android = TRUE OR show_on_ios = TRUE")
|
|
end
|
|
|
|
def self.for_platform(platform)
|
|
case platform.to_s
|
|
when "android" then for_channel(:android)
|
|
when "ios" then for_channel(:ios)
|
|
else for_app
|
|
end
|
|
end
|
|
|
|
def published?
|
|
status == "published"
|
|
end
|
|
|
|
def selected_channels
|
|
CHANNELS.each_with_object([]) do |(key, column), keys|
|
|
keys << key if public_send(column)
|
|
end
|
|
end
|
|
|
|
def as_api_json(platform: nil)
|
|
{
|
|
id: id,
|
|
kind: kind,
|
|
severity: severity,
|
|
title: copy_for(platform, :title),
|
|
body: copy_for(platform, :body),
|
|
dismissible: dismissible,
|
|
action_url: resolved_action_url(platform),
|
|
action_label: copy_for(platform, :action_label).presence,
|
|
starts_at: starts_at&.iso8601,
|
|
ends_at: ends_at&.iso8601
|
|
}
|
|
end
|
|
|
|
def resolved_action_url(platform)
|
|
override = platform_override(platform, :action_url)
|
|
return override if override.present?
|
|
return action_url if action_url.present?
|
|
return nil unless kind == "update"
|
|
|
|
case platform.to_s
|
|
when "android" then MatchLiveTv.play_store_url
|
|
when "ios" then MatchLiveTv.app_store_url
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def copy_for(platform, field)
|
|
override = platform_override(platform, field)
|
|
override.presence || public_send(field)
|
|
end
|
|
|
|
def platform_override(platform, field)
|
|
prefix = case platform.to_s
|
|
when "android" then :android
|
|
when "ios" then :ios
|
|
end
|
|
return if prefix.blank?
|
|
|
|
public_send("#{prefix}_#{field}")
|
|
end
|
|
|
|
def at_least_one_channel
|
|
return if show_on_android? || show_on_ios? || show_on_web_public? || show_on_web_private?
|
|
|
|
errors.add(:base, :no_channel)
|
|
end
|
|
|
|
def ends_at_after_starts_at
|
|
return if starts_at.blank? || ends_at.blank?
|
|
return if ends_at > starts_at
|
|
|
|
errors.add(:ends_at, :invalid)
|
|
end
|
|
end
|