Un account di test su dominio .test faceva 500; ora l'invio fallito viene loggato e l'API resta ok. Co-authored-by: Cursor <cursoragent@cursor.com>
257 lines
6.8 KiB
Ruby
257 lines
6.8 KiB
Ruby
require "net/smtp"
|
||
require "openssl"
|
||
|
||
module MatchLiveTv
|
||
class << self
|
||
def jwt_secret
|
||
ENV.fetch("JWT_SECRET", Rails.application.secret_key_base)
|
||
end
|
||
|
||
def mediamtx_api_url
|
||
ENV.fetch("MEDIAMTX_API_URL", "http://localhost:9997")
|
||
end
|
||
|
||
def mediamtx_rtmp_url
|
||
ENV.fetch("MEDIAMTX_RTMP_URL", "rtmp://localhost:1935")
|
||
end
|
||
|
||
def mediamtx_webhook_secret
|
||
ENV.fetch("MEDIAMTX_WEBHOOK_SECRET", "change_me")
|
||
end
|
||
|
||
def reconnect_timeout_seconds
|
||
ENV.fetch("RECONNECT_TIMEOUT_SECONDS", "300").to_i
|
||
end
|
||
|
||
def hls_public_url
|
||
ENV.fetch("HLS_PUBLIC_URL") { "#{app_public_url.chomp('/')}/hls" }
|
||
end
|
||
|
||
def mediamtx_hls_url
|
||
ENV.fetch("MEDIAMTX_HLS_URL", "http://mediamtx:8888")
|
||
end
|
||
|
||
def app_public_url
|
||
ENV.fetch("APP_PUBLIC_URL", "http://localhost:3000")
|
||
end
|
||
|
||
def stripe_secret_key
|
||
ENV["STRIPE_SECRET_KEY"].presence
|
||
end
|
||
|
||
def stripe_webhook_secret
|
||
ENV["STRIPE_WEBHOOK_SECRET"].presence
|
||
end
|
||
|
||
def stripe_premium_light_yearly_price_id
|
||
ENV["STRIPE_PREMIUM_LIGHT_YEARLY_PRICE_ID"].presence ||
|
||
ENV["STRIPE_PREMIUM_LIGHT_PRICE_ID"].presence ||
|
||
ENV["STRIPE_PREMIUM_PRICE_ID"].presence
|
||
end
|
||
|
||
def stripe_premium_light_monthly_price_id
|
||
ENV["STRIPE_PREMIUM_LIGHT_MONTHLY_PRICE_ID"].presence
|
||
end
|
||
|
||
def stripe_premium_full_yearly_price_id
|
||
ENV["STRIPE_PREMIUM_FULL_YEARLY_PRICE_ID"].presence ||
|
||
ENV["STRIPE_PREMIUM_FULL_PRICE_ID"].presence ||
|
||
ENV["STRIPE_PREMIUM_PRICE_ID"].presence
|
||
end
|
||
|
||
def stripe_premium_full_monthly_price_id
|
||
ENV["STRIPE_PREMIUM_FULL_MONTHLY_PRICE_ID"].presence
|
||
end
|
||
|
||
# Retrocompatibilità
|
||
def stripe_premium_light_price_id
|
||
stripe_premium_light_yearly_price_id.to_s
|
||
end
|
||
|
||
def stripe_premium_full_price_id
|
||
stripe_premium_full_yearly_price_id.to_s
|
||
end
|
||
|
||
def stripe_enabled?
|
||
stripe_secret_key.present?
|
||
end
|
||
|
||
def bank_transfer_iban
|
||
ENV["BANK_TRANSFER_IBAN"].to_s.gsub(/\s+/, "").presence
|
||
end
|
||
|
||
def bank_transfer_account_holder
|
||
ENV["BANK_TRANSFER_ACCOUNT_HOLDER"].to_s.strip.presence
|
||
end
|
||
|
||
def bank_transfer_bank_name
|
||
ENV["BANK_TRANSFER_BANK_NAME"].to_s.strip.presence
|
||
end
|
||
|
||
def bank_transfer_bic
|
||
ENV["BANK_TRANSFER_BIC"].to_s.strip.presence
|
||
end
|
||
|
||
def bank_transfer_proof_email
|
||
ENV["BANK_TRANSFER_PROOF_EMAIL"].presence || support_email
|
||
end
|
||
|
||
def bank_transfer_configured?
|
||
bank_transfer_iban.present? && bank_transfer_account_holder.present?
|
||
end
|
||
|
||
def smtp_configured?
|
||
ENV["SMTP_ADDRESS"].present?
|
||
end
|
||
|
||
# In produzione senza SMTP non blocca il flusso (es. collaudo): la mail si può inviare a mano.
|
||
# Errori SMTP (dominio invalido, EOF Aruba, porta chiusa) non devono far crashare la request.
|
||
def deliver_mail(mail)
|
||
if Rails.env.production? && !smtp_configured?
|
||
Rails.logger.info("[mail] skip (SMTP assente): #{mail.subject}")
|
||
return false
|
||
end
|
||
|
||
mail.deliver_now
|
||
true
|
||
rescue EOFError, Net::SMTPError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError, OpenSSL::SSL::SSLError => e
|
||
Rails.logger.warn("[mail] delivery failed: #{mail.subject} #{e.class}: #{e.message}")
|
||
false
|
||
end
|
||
|
||
def privacy_controller_name
|
||
ENV.fetch("PRIVACY_CONTROLLER_NAME", "Emiliano Frascaro")
|
||
end
|
||
|
||
def privacy_controller_email
|
||
ENV.fetch("PRIVACY_CONTACT_EMAIL", "privacy@matchlivetv.it")
|
||
end
|
||
|
||
# Email di supporto (App Store Support URL e contatti assistenza).
|
||
# Preferisce SUPPORT_CONTACT_EMAIL; default = contatto commerciale già usato nel sito.
|
||
def support_email
|
||
ENV["SUPPORT_CONTACT_EMAIL"].presence || "info@matchlivetv.it"
|
||
end
|
||
|
||
def privacy_controller_address
|
||
ENV.fetch("PRIVACY_CONTROLLER_ADDRESS", "Via Guido De Ruggiero, 89 - 20142 - Milano (MI)")
|
||
end
|
||
|
||
def privacy_controller_vat
|
||
ENV["PRIVACY_CONTROLLER_VAT"].presence
|
||
end
|
||
|
||
def mail_from
|
||
ENV.fetch("MAILER_FROM", "Match Live TV <noreply@matchlivetv.it>")
|
||
end
|
||
|
||
def password_reset_expiry_hours
|
||
ENV.fetch("PASSWORD_RESET_EXPIRY_HOURS", "2").to_i
|
||
end
|
||
|
||
def replay_storage_configured?
|
||
replay_storage_endpoint.present? || replay_storage_local?
|
||
end
|
||
|
||
def replay_storage_endpoint
|
||
ENV["REPLAY_STORAGE_ENDPOINT"].presence
|
||
end
|
||
|
||
def replay_storage_bucket
|
||
ENV.fetch("REPLAY_STORAGE_BUCKET", "matchlivetv-replays")
|
||
end
|
||
|
||
def replay_storage_region
|
||
ENV.fetch("REPLAY_STORAGE_REGION", "garage")
|
||
end
|
||
|
||
def replay_storage_access_key_id
|
||
ENV["REPLAY_STORAGE_ACCESS_KEY_ID"].presence
|
||
end
|
||
|
||
def replay_storage_secret_access_key
|
||
ENV["REPLAY_STORAGE_SECRET_ACCESS_KEY"].presence
|
||
end
|
||
|
||
def replay_storage_force_path_style?
|
||
ENV.fetch("REPLAY_STORAGE_FORCE_PATH_STYLE", "true") == "true"
|
||
end
|
||
|
||
def replay_storage_local?
|
||
replay_storage_endpoint.blank?
|
||
end
|
||
|
||
def recordings_local_path
|
||
ENV.fetch("RECORDINGS_PATH", "/recordings")
|
||
end
|
||
|
||
def replay_presigned_url_ttl_seconds
|
||
ENV.fetch("REPLAY_PRESIGNED_URL_TTL_SECONDS", "7200").to_i
|
||
end
|
||
|
||
def replay_download_url_ttl_seconds
|
||
ENV.fetch("REPLAY_DOWNLOAD_URL_TTL_SECONDS", "900").to_i
|
||
end
|
||
|
||
def replay_media_public_base_url
|
||
ENV.fetch("REPLAY_MEDIA_PUBLIC_BASE_URL") { "#{app_public_url.chomp('/')}/media" }
|
||
end
|
||
|
||
def replay_media_redirect_enabled?
|
||
return false if replay_storage_local?
|
||
|
||
ENV.fetch("REPLAY_MEDIA_REDIRECT", "true") == "true"
|
||
end
|
||
|
||
# Retention copia temporanea post-live YouTube (ore). Clamp 24–72, default 48.
|
||
def youtube_temp_replay_retention_hours
|
||
raw = ENV.fetch("YOUTUBE_TEMP_REPLAY_RETENTION_HOURS", "48").to_i
|
||
raw.clamp(24, 72)
|
||
end
|
||
|
||
def youtube_replay_verify_max_attempts
|
||
ENV.fetch("YOUTUBE_REPLAY_VERIFY_MAX_ATTEMPTS", "12").to_i
|
||
end
|
||
|
||
def youtube_replay_verify_base_interval_secs
|
||
ENV.fetch("YOUTUBE_REPLAY_VERIFY_BASE_INTERVAL_SECS", "300").to_i
|
||
end
|
||
|
||
def youtube_replay_verify_grace_secs
|
||
ENV.fetch("YOUTUBE_REPLAY_VERIFY_GRACE_SECS", "120").to_i
|
||
end
|
||
|
||
def ops_http_rails_url
|
||
ENV.fetch("OPS_HTTP_RAILS_URL", "http://edge/up")
|
||
end
|
||
|
||
def ops_http_public_interval_seconds
|
||
ENV.fetch("OPS_HTTP_PUBLIC_INTERVAL_SECS", "900").to_i
|
||
end
|
||
|
||
def ops_up_latency_warn_ms
|
||
ENV.fetch("OPS_UP_LATENCY_WARN_MS", "2000").to_i
|
||
end
|
||
|
||
def ops_up_latency_crit_ms
|
||
ENV.fetch("OPS_UP_LATENCY_CRIT_MS", "5000").to_i
|
||
end
|
||
|
||
def google_analytics_measurement_id
|
||
ENV["GOOGLE_ANALYTICS_MEASUREMENT_ID"].presence
|
||
end
|
||
|
||
def google_analytics_configured?
|
||
google_analytics_measurement_id.present?
|
||
end
|
||
|
||
def app_store_url
|
||
"https://apps.apple.com/us/app/matchlivetv/id6799510705"
|
||
end
|
||
|
||
def play_store_url
|
||
"https://play.google.com/store/apps/details?id=com.matchlivetv.match_live_tv"
|
||
end
|
||
end
|
||
end
|