Include admin/API/banner nativi, form contatti e reset copertina standard con layout edit più ampio. Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
2.5 KiB
Ruby
94 lines
2.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 = {
|
|
app: :show_on_app,
|
|
web_public: :show_on_web_public,
|
|
web_private: :show_on_web_private
|
|
}.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, length: { maximum: 120 }
|
|
validates :body, length: { maximum: 2000 }
|
|
validates :action_label, length: { maximum: 40 }, allow_blank: true
|
|
validates :action_url, format: { with: /\Ahttps?:\/\/.+/i, allow_blank: true }
|
|
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
|
|
for_channel(:app)
|
|
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: title,
|
|
body: body,
|
|
dismissible: dismissible,
|
|
action_url: resolved_action_url(platform),
|
|
action_label: action_label.presence,
|
|
starts_at: starts_at&.iso8601,
|
|
ends_at: ends_at&.iso8601
|
|
}
|
|
end
|
|
|
|
def resolved_action_url(platform)
|
|
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 at_least_one_channel
|
|
return if show_on_app? || 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
|