| <%= s.match.team.name %> vs <%= s.match.opponent_name %> |
<%= s.status %> |
+ <%= render "admin/sessions/ingest_cell", session: s %> |
<%= s.disconnection_count %> |
<% admin_session_watch_links(s).each do |link| %>
diff --git a/backend/app/views/admin/sessions/show.html.erb b/backend/app/views/admin/sessions/show.html.erb
index 0a2fd69..a9fd548 100644
--- a/backend/app/views/admin/sessions/show.html.erb
+++ b/backend/app/views/admin/sessions/show.html.erb
@@ -16,6 +16,16 @@
<% if @session.youtube_broadcast_id %>
<%= t("admin.sessions.show.youtube_studio") %>: <%= t("admin.sessions.show.broadcast") %>
<% end %>
+
+ <%= t("admin.sessions.show.ingest_node") %>
+ <% if @session.stream_node %>
+ <%= @session.stream_node.slug %>
+ <%= admin_session_ingest_role_label(@session.stream_node) %>
+ (<%= @session.stream_node.provider %>)
+ <% else %>
+ <%= t("admin.sessions.ingest.none") %>
+ <% end %>
+
<%= t("admin.sessions.show.rtmp_ingest") %> <%= @session.rtmp_ingest_url %>
<%= t("admin.sessions.show.events_title") %>
diff --git a/backend/app/views/layouts/admin.html.erb b/backend/app/views/layouts/admin.html.erb
index 587dad6..7e47050 100644
--- a/backend/app/views/layouts/admin.html.erb
+++ b/backend/app/views/layouts/admin.html.erb
@@ -4,7 +4,7 @@
<%= t("admin.layout.title") %>
-
+
<% if content_for?(:replay_archive_styles) %>
<% end %>
diff --git a/backend/config/locales/admin.de.yml b/backend/config/locales/admin.de.yml
index 4454b35..ed5dab1 100644
--- a/backend/config/locales/admin.de.yml
+++ b/backend/config/locales/admin.de.yml
@@ -110,6 +110,7 @@ de:
table:
match: Spiel
status: Status
+ ingest: Ingest
start: Start
link: Link
none: Derzeit keine aktive Sitzung.
@@ -253,6 +254,7 @@ de:
table:
match: Spiel
status: Status
+ ingest: Ingest
disconnects: Verbindungsabbrüche
link: Link
detail: Details
@@ -265,6 +267,7 @@ de:
match_label: "Spiel: %{team} gegen %{opponent}"
youtube_studio: YouTube Studio
broadcast: Übertragung
+ ingest_node: "Ingest-Knoten:"
rtmp_ingest: "RTMP-Ingest:"
events_title: Ereignisse
table:
@@ -281,6 +284,13 @@ de:
active_exists: Es existiert bereits ein aktiver Regie-Link (die URL kann nicht abgerufen werden). Erzeuge einen neuen, wenn du ihn erneut teilen musst.
none_active: Kein aktiver Regie-Link. Erzeuge einen Link zum Teilen mit der Person, die den Spielstand verwaltet.
generate_button: Regie-Link erzeugen
+ ingest:
+ none: "—"
+ role:
+ home: Home-lab
+ lab: Lab
+ cloud: Hetzner
+
billing:
index:
title: Zu berechnende Zahlungen
@@ -398,7 +408,8 @@ de:
published: Veröffentlicht
archived: Archiviert
channels:
- app: Apps (Android und iOS)
+ android: Android-App
+ ios: iOS-App
web_public: Öffentliche Website
web_private: Login-Bereich
window:
@@ -410,15 +421,18 @@ de:
severity: Schwere
status: Status
channels: Wo anzeigen
- channels_hint: Eine oder mehrere Ziele wählen. Der Login-Bereich ist nach der Anmeldung sichtbar (Verein, Teams, Konto).
+ channels_hint: Eine oder mehrere Ziele wählen. Android und iOS sind unabhängig. Der Login-Bereich ist nach der Anmeldung sichtbar (Verein, Teams, Konto).
title: Titel
body: Text
starts_at: Sichtbar ab
ends_at: Sichtbar bis
window_hint: Leer lassen, um sofort und solange veröffentlicht anzuzeigen.
action_url: Link (optional)
- action_url_hint: Bei Updates öffnet eine leere URL den Store. Sonst eine https-URL.
+ action_url_hint: Bei Updates öffnet eine leere URL den Store der Plattform. Unten können Titel, Text und Link für Android und iOS unterschiedlich sein.
action_label: Button-Text
+ android_override: Nur Android (optional)
+ ios_override: Nur iOS (optional)
+ platform_override_hint: Leer lassen, um gemeinsame Texte und Links zu nutzen. Nur ausfüllen, wenn diese Plattform etwas anderes sehen soll.
dismissible: Nutzer können den Hinweis schließen
dismissible_hint: Haken entfernen für Wartungshinweise, die sichtbar bleiben sollen.
submit_create: Hinweis speichern
diff --git a/backend/config/locales/admin.en.yml b/backend/config/locales/admin.en.yml
index e445089..1d790ac 100644
--- a/backend/config/locales/admin.en.yml
+++ b/backend/config/locales/admin.en.yml
@@ -110,6 +110,7 @@ en:
table:
match: Match
status: Status
+ ingest: Ingest
start: Start
link: Link
none: No active session right now.
@@ -253,6 +254,7 @@ en:
table:
match: Match
status: Status
+ ingest: Ingest
disconnects: Disconnects
link: Link
detail: Details
@@ -265,6 +267,7 @@ en:
match_label: "Match: %{team} vs %{opponent}"
youtube_studio: YouTube Studio
broadcast: Broadcast
+ ingest_node: "Ingest node:"
rtmp_ingest: "RTMP ingest:"
events_title: Events
table:
@@ -281,6 +284,13 @@ en:
active_exists: An active control link already exists (the URL cannot be retrieved). Generate a new one if you need to share it again.
none_active: No active control link. Generate a link to share with whoever manages the score.
generate_button: Generate control link
+ ingest:
+ none: "—"
+ role:
+ home: Home-lab
+ lab: Lab
+ cloud: Hetzner
+
billing:
index:
title: Payments to invoice
@@ -398,7 +408,8 @@ en:
published: Published
archived: Archived
channels:
- app: Apps (Android and iOS)
+ android: Android app
+ ios: iOS app
web_public: Public website
web_private: Logged-in area
window:
@@ -410,15 +421,18 @@ en:
severity: Severity
status: Status
channels: Where to show it
- channels_hint: Select one or more destinations. The logged-in area is visible after sign-in (club, teams, account).
+ channels_hint: Select one or more destinations. Android and iOS are independent. The logged-in area is visible after sign-in (club, teams, account).
title: Title
body: Body
starts_at: Visible from
ends_at: Visible until
window_hint: Leave empty to show immediately while published.
action_url: Link (optional)
- action_url_hint: For updates, an empty URL opens the store. Otherwise use an https URL.
+ action_url_hint: For updates, an empty URL opens that platform's store. Below you can set a different title, body and link for Android and iOS.
action_label: Button label
+ android_override: Android only (optional)
+ ios_override: iOS only (optional)
+ platform_override_hint: Leave empty to use the shared title, body and link. Fill in only if this platform should see different copy or a different URL.
dismissible: Users can dismiss the notice
dismissible_hint: Uncheck for maintenance notices that should stay visible.
submit_create: Save notice
diff --git a/backend/config/locales/admin.es.yml b/backend/config/locales/admin.es.yml
index a1be8f0..963c9a1 100644
--- a/backend/config/locales/admin.es.yml
+++ b/backend/config/locales/admin.es.yml
@@ -110,6 +110,7 @@ es:
table:
match: Partido
status: Estado
+ ingest: Ingest
start: Inicio
link: Enlace
none: No hay ninguna sesión activa en este momento.
@@ -253,6 +254,7 @@ es:
table:
match: Partido
status: Estado
+ ingest: Ingest
disconnects: Desconexiones
link: Enlace
detail: Detalle
@@ -265,6 +267,7 @@ es:
match_label: "Partido: %{team} vs %{opponent}"
youtube_studio: YouTube Studio
broadcast: Emisión
+ ingest_node: "Nodo ingest:"
rtmp_ingest: "Ingesta RTMP:"
events_title: Eventos
table:
@@ -281,6 +284,13 @@ es:
active_exists: Ya existe un enlace de regie activo (la URL no se puede recuperar). Genera uno nuevo si necesitas compartirlo de nuevo.
none_active: No hay ningún enlace de regie activo. Genera un enlace para compartir con quien gestione el marcador.
generate_button: Generar enlace de regie
+ ingest:
+ none: "—"
+ role:
+ home: Home-lab
+ lab: Lab
+ cloud: Hetzner
+
billing:
index:
title: Pagos por facturar
@@ -398,7 +408,8 @@ es:
published: Publicado
archived: Archivado
channels:
- app: Apps (Android e iOS)
+ android: App Android
+ ios: App iOS
web_public: Sitio público
web_private: Área privada
window:
@@ -410,15 +421,18 @@ es:
severity: Gravedad
status: Estado
channels: Dónde mostrarlo
- channels_hint: Elige uno o más destinos. El área privada se ve tras iniciar sesión (club, equipos, cuenta).
+ channels_hint: Elige uno o más destinos. Android e iOS son independientes. El área privada se ve tras iniciar sesión (club, equipos, cuenta).
title: Título
body: Texto
starts_at: Visible desde
ends_at: Visible hasta
window_hint: Déjalo vacío para mostrarlo de inmediato mientras esté publicado.
action_url: Enlace (opcional)
- action_url_hint: En actualizaciones, una URL vacía abre la tienda. Si no, usa una URL https.
+ action_url_hint: En actualizaciones, una URL vacía abre la tienda de esa plataforma. Abajo puedes poner título, texto y enlace distintos para Android e iOS.
action_label: Texto del botón
+ android_override: Solo Android (opcional)
+ ios_override: Solo iOS (opcional)
+ platform_override_hint: Déjalo vacío para usar el título, texto y enlace comunes. Rellena solo si esta plataforma debe ver un mensaje o un enlace distinto.
dismissible: El usuario puede cerrar el aviso
dismissible_hint: Quita la marca para avisos de mantenimiento que deben permanecer visibles.
submit_create: Guardar aviso
diff --git a/backend/config/locales/admin.fr.yml b/backend/config/locales/admin.fr.yml
index 48730d7..26c41dd 100644
--- a/backend/config/locales/admin.fr.yml
+++ b/backend/config/locales/admin.fr.yml
@@ -110,6 +110,7 @@ fr:
table:
match: Match
status: Statut
+ ingest: Ingest
start: Début
link: Lien
none: Aucune session active pour le moment.
@@ -253,6 +254,7 @@ fr:
table:
match: Match
status: Statut
+ ingest: Ingest
disconnects: Déconnexions
link: Lien
detail: Détail
@@ -265,6 +267,7 @@ fr:
match_label: "Match : %{team} contre %{opponent}"
youtube_studio: YouTube Studio
broadcast: Diffusion
+ ingest_node: "Nœud ingest :"
rtmp_ingest: "Ingestion RTMP :"
events_title: Événements
table:
@@ -281,6 +284,13 @@ fr:
active_exists: Un lien de régie actif existe déjà (l'URL n'est pas récupérable). Générez-en un nouveau si vous devez le repartager.
none_active: Aucun lien de régie actif. Générez un lien à partager avec la personne qui gère le score.
generate_button: Générer le lien de régie
+ ingest:
+ none: "—"
+ role:
+ home: Home-lab
+ lab: Lab
+ cloud: Hetzner
+
billing:
index:
title: Paiements à facturer
@@ -398,7 +408,8 @@ fr:
published: Publié
archived: Archivé
channels:
- app: Apps (Android et iOS)
+ android: App Android
+ ios: App iOS
web_public: Site public
web_private: Espace connecté
window:
@@ -410,15 +421,18 @@ fr:
severity: Gravité
status: Statut
channels: Où l'afficher
- channels_hint: Choisissez une ou plusieurs destinations. L'espace connecté est visible après connexion (club, équipes, compte).
+ channels_hint: Choisissez une ou plusieurs destinations. Android et iOS sont indépendants. L'espace connecté est visible après connexion (club, équipes, compte).
title: Titre
body: Texte
starts_at: Visible à partir de
ends_at: Visible jusqu'à
window_hint: Laissez vide pour afficher immédiatement tant que l'alerte est publiée.
action_url: Lien (facultatif)
- action_url_hint: Pour une mise à jour, une URL vide ouvre le store. Sinon une URL https.
+ action_url_hint: Pour une mise à jour, une URL vide ouvre le store de la plateforme. Ci-dessous vous pouvez définir titre, texte et lien différents pour Android et iOS.
action_label: Libellé du bouton
+ android_override: Android uniquement (facultatif)
+ ios_override: iOS uniquement (facultatif)
+ platform_override_hint: Laissez vide pour utiliser le titre, le texte et le lien communs. Remplissez seulement si cette plateforme doit voir un message ou un lien différent.
dismissible: L'utilisateur peut fermer l'alerte
dismissible_hint: Décochez pour une maintenance qui doit rester visible.
submit_create: Enregistrer l'alerte
diff --git a/backend/config/locales/admin.it.yml b/backend/config/locales/admin.it.yml
index 77e9ce2..30d96cb 100644
--- a/backend/config/locales/admin.it.yml
+++ b/backend/config/locales/admin.it.yml
@@ -114,6 +114,7 @@ it:
table:
match: Partita
status: Stato
+ ingest: Ingest
start: Inizio
link: Link
none: Nessuna sessione attiva in questo momento.
@@ -274,6 +275,7 @@ it:
table:
match: Match
status: Stato
+ ingest: Ingest
disconnects: Disconnessioni
link: Link
detail: Dettaglio
@@ -286,6 +288,7 @@ it:
match_label: "Match: %{team} vs %{opponent}"
youtube_studio: YouTube Studio
broadcast: Broadcast
+ ingest_node: "Nodo ingest:"
rtmp_ingest: "RTMP ingest:"
events_title: Eventi
table:
@@ -302,6 +305,13 @@ it:
active_exists: Esiste già un link regia attivo (l’URL non è recuperabile). Generane uno nuovo se serve condividerlo di nuovo.
none_active: Nessun link regia attivo. Genera un link da condividere con chi gestisce il punteggio.
generate_button: Genera link regia
+ ingest:
+ none: "—"
+ role:
+ home: Home-lab
+ lab: Lab
+ cloud: Hetzner
+
billing:
index:
title: Pagamenti da fatturare
@@ -436,7 +446,8 @@ it:
published: Pubblicato
archived: Archiviato
channels:
- app: App (Android e iOS)
+ android: App Android
+ ios: App iOS
web_public: Sito pubblico
web_private: Area riservata
window:
@@ -448,15 +459,18 @@ it:
severity: Gravità
status: Stato
channels: Dove mostrarlo
- channels_hint: Puoi selezionare una o più destinazioni. L'area riservata è visibile dopo il login (società, squadre, account).
+ channels_hint: Puoi selezionare una o più destinazioni. Android e iOS sono indipendenti. L'area riservata è visibile dopo il login (società, squadre, account).
title: Titolo
body: Testo
starts_at: Inizio visibilità
ends_at: Fine visibilità
window_hint: Lascia vuoto per mostrare subito e finché resta pubblicato.
action_url: Link (facoltativo)
- action_url_hint: Per gli aggiornamenti, se vuoto l'app apre lo store. Altrimenti un URL https.
+ action_url_hint: Per gli aggiornamenti, se vuoto l'app apre lo store della piattaforma. Sotto puoi impostare titolo, testo e link diversi per Android e iOS.
action_label: Etichetta del pulsante
+ android_override: Solo Android (facoltativo)
+ ios_override: Solo iOS (facoltativo)
+ platform_override_hint: Lascia vuoto per usare titolo, testo e link comuni. Compila solo se questa piattaforma deve vedere un messaggio o un link diverso.
dismissible: L'utente può chiudere l'avviso
dismissible_hint: Togli la spunta per avvisi di manutenzione che devono restare visibili.
submit_create: Salva avviso
diff --git a/backend/db/migrate/20260820180000_split_announcement_app_platforms.rb b/backend/db/migrate/20260820180000_split_announcement_app_platforms.rb
new file mode 100644
index 0000000..9a6a36e
--- /dev/null
+++ b/backend/db/migrate/20260820180000_split_announcement_app_platforms.rb
@@ -0,0 +1,26 @@
+class SplitAnnouncementAppPlatforms < ActiveRecord::Migration[7.2]
+ def change
+ add_column :app_announcements, :show_on_android, :boolean, null: false, default: true
+ add_column :app_announcements, :show_on_ios, :boolean, null: false, default: true
+ add_column :app_announcements, :android_title, :string
+ add_column :app_announcements, :android_body, :text
+ add_column :app_announcements, :android_action_url, :string
+ add_column :app_announcements, :android_action_label, :string
+ add_column :app_announcements, :ios_title, :string
+ add_column :app_announcements, :ios_body, :text
+ add_column :app_announcements, :ios_action_url, :string
+ add_column :app_announcements, :ios_action_label, :string
+
+ reversible do |dir|
+ dir.up do
+ execute <<~SQL.squish
+ UPDATE app_announcements
+ SET show_on_android = show_on_app,
+ show_on_ios = show_on_app
+ SQL
+ end
+ end
+
+ remove_column :app_announcements, :show_on_app, :boolean, null: false, default: true
+ end
+end
diff --git a/backend/db/schema.rb b/backend/db/schema.rb
index 7444af5..f886449 100644
--- a/backend/db/schema.rb
+++ b/backend/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.2].define(version: 2026_08_20_140000) do
+ActiveRecord::Schema[7.2].define(version: 2026_08_20_180000) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
@@ -55,7 +55,6 @@ ActiveRecord::Schema[7.2].define(version: 2026_08_20_140000) do
t.string "kind", default: "info", null: false
t.string "severity", default: "info", null: false
t.string "status", default: "draft", null: false
- t.boolean "show_on_app", default: true, null: false
t.boolean "show_on_web_public", default: false, null: false
t.boolean "show_on_web_private", default: false, null: false
t.string "title", null: false
@@ -68,6 +67,16 @@ ActiveRecord::Schema[7.2].define(version: 2026_08_20_140000) do
t.uuid "created_by_admin_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.boolean "show_on_android", default: true, null: false
+ t.boolean "show_on_ios", default: true, null: false
+ t.string "android_title"
+ t.text "android_body"
+ t.string "android_action_url"
+ t.string "android_action_label"
+ t.string "ios_title"
+ t.text "ios_body"
+ t.string "ios_action_url"
+ t.string "ios_action_label"
t.index ["created_by_admin_id"], name: "index_app_announcements_on_created_by_admin_id"
t.index ["status", "starts_at", "ends_at"], name: "index_app_announcements_on_status_and_starts_at_and_ends_at"
t.index ["status"], name: "index_app_announcements_on_status"
diff --git a/backend/public/admin.css b/backend/public/admin.css
index 4b22020..61576d6 100644
--- a/backend/public/admin.css
+++ b/backend/public/admin.css
@@ -230,6 +230,20 @@ body.admin-body {
.badge--paused { background: #555; color: #fff; }
.badge--ready { background: #1b5e20; color: #c8e6c9; }
.badge--ok { background: #1b5e20; color: #c8e6c9; }
+.badge--ingest-home { background: #1565c0; color: #e3f2fd; }
+.badge--ingest-lab { background: #6a1b9a; color: #f3e5f5; }
+.badge--ingest-cloud { background: #e65100; color: #fff3e0; }
+
+.admin-ingest {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 4px;
+}
+.admin-ingest__slug {
+ font-size: 0.85rem;
+ color: #ddd;
+}
.team-list {
list-style: none;
@@ -652,6 +666,15 @@ body.admin-body {
color: var(--muted);
}
+.admin-platform-copy {
+ margin-top: 0.35rem;
+}
+
+.admin-platform-copy > div {
+ display: grid;
+ gap: 0.25rem;
+}
+
.admin-form-actions {
display: flex;
flex-wrap: wrap;
diff --git a/backend/spec/models/app_announcement_spec.rb b/backend/spec/models/app_announcement_spec.rb
index 0ba0a38..bb9ad16 100644
--- a/backend/spec/models/app_announcement_spec.rb
+++ b/backend/spec/models/app_announcement_spec.rb
@@ -10,7 +10,8 @@ RSpec.describe AppAnnouncement do
status: "published",
title: "Avviso",
body: "Testo",
- show_on_app: true,
+ show_on_android: true,
+ show_on_ios: true,
show_on_web_public: false,
show_on_web_private: false
}.merge(attrs))
@@ -35,22 +36,55 @@ RSpec.describe AppAnnouncement do
it "filters by selected channels" do
public_item = create_notice!(
- title: "Pubblico", show_on_app: false, show_on_web_public: true
+ title: "Pubblico", show_on_android: false, show_on_ios: false, show_on_web_public: true
)
private_item = create_notice!(
- title: "Privato", show_on_app: false, show_on_web_private: true
+ title: "Privato", show_on_android: false, show_on_ios: false, show_on_web_private: true
)
- app_item = create_notice!(title: "App")
+ android_item = create_notice!(title: "Android", show_on_ios: false)
+ ios_item = create_notice!(title: "iOS", show_on_android: false, show_on_ios: true)
expect(described_class.for_channel(:web_public)).to contain_exactly(public_item)
expect(described_class.for_channel(:web_private)).to contain_exactly(private_item)
- expect(described_class.for_app).to contain_exactly(app_item)
+ expect(described_class.for_platform("android")).to contain_exactly(android_item)
+ expect(described_class.for_platform("ios")).to contain_exactly(ios_item)
+ expect(described_class.for_app).to contain_exactly(android_item, ios_item)
+ end
+
+ it "uses platform-specific copy and links when present" do
+ item = create_notice!(
+ title: "Comune",
+ body: "Testo comune",
+ action_url: "https://example.com/comune",
+ action_label: "Apri",
+ android_title: "Aggiorna su Android",
+ android_body: "Apri Play Store",
+ android_action_url: "https://play.google.com/store/apps/details?id=com.matchlivetv.match_live_tv",
+ android_action_label: "Play Store",
+ ios_title: "Aggiorna su iOS",
+ ios_body: "Apri App Store",
+ ios_action_url: "https://apps.apple.com/app/id000",
+ ios_action_label: "App Store"
+ )
+
+ android = item.as_api_json(platform: "android")
+ ios = item.as_api_json(platform: "ios")
+
+ expect(android[:title]).to eq("Aggiorna su Android")
+ expect(android[:body]).to eq("Apri Play Store")
+ expect(android[:action_url]).to include("play.google.com")
+ expect(android[:action_label]).to eq("Play Store")
+ expect(ios[:title]).to eq("Aggiorna su iOS")
+ expect(ios[:body]).to eq("Apri App Store")
+ expect(ios[:action_url]).to include("apps.apple.com")
+ expect(ios[:action_label]).to eq("App Store")
end
it "requires at least one channel" do
item = described_class.new(
kind: "info", status: "draft", title: "X", body: "Y",
- show_on_app: false, show_on_web_public: false, show_on_web_private: false
+ show_on_android: false, show_on_ios: false,
+ show_on_web_public: false, show_on_web_private: false
)
expect(item).not_to be_valid
expect(item.errors[:base]).to be_present
diff --git a/backend/spec/requests/admin/announcements_spec.rb b/backend/spec/requests/admin/announcements_spec.rb
index af4e724..5bef892 100644
--- a/backend/spec/requests/admin/announcements_spec.rb
+++ b/backend/spec/requests/admin/announcements_spec.rb
@@ -18,7 +18,8 @@ RSpec.describe "Admin announcements", type: :request do
title: "Nuova versione",
body: "Aggiorna l'app dallo store.",
dismissible: "1",
- show_on_app: "1",
+ show_on_android: "1",
+ show_on_ios: "1",
show_on_web_public: "1",
show_on_web_private: "0"
}
@@ -28,7 +29,8 @@ RSpec.describe "Admin announcements", type: :request do
notice = AppAnnouncement.last
expect(notice.title).to eq("Nuova versione")
expect(notice).to be_published
- expect(notice.show_on_app).to be(true)
+ expect(notice.show_on_android).to be(true)
+ expect(notice.show_on_ios).to be(true)
expect(notice.show_on_web_public).to be(true)
expect(notice.show_on_web_private).to be(false)
diff --git a/backend/spec/requests/api/v1/announcements_spec.rb b/backend/spec/requests/api/v1/announcements_spec.rb
index a6cfcf1..4322761 100644
--- a/backend/spec/requests/api/v1/announcements_spec.rb
+++ b/backend/spec/requests/api/v1/announcements_spec.rb
@@ -3,21 +3,23 @@
require "rails_helper"
RSpec.describe "Api::V1::Announcements", type: :request do
- it "GET /api/v1/announcements senza autenticazione restituisce solo gli avvisi attivi per l'app" do
+ it "GET /api/v1/announcements senza autenticazione restituisce solo gli avvisi attivi per la piattaforma" do
AppAnnouncement.create!(
kind: "maintenance",
severity: "warning",
status: "published",
title: "Manutenzione stasera",
body: "Dalle 23:00 alle 01:00 il servizio sarà offline.",
- show_on_app: true
+ show_on_android: true,
+ show_on_ios: true
)
AppAnnouncement.create!(
kind: "info",
status: "published",
title: "Solo sito",
body: "Non in app",
- show_on_app: false,
+ show_on_android: false,
+ show_on_ios: false,
show_on_web_public: true
)
AppAnnouncement.create!(
@@ -26,14 +28,27 @@ RSpec.describe "Api::V1::Announcements", type: :request do
title: "Bozza",
body: "Non deve uscire"
)
+ AppAnnouncement.create!(
+ kind: "update",
+ status: "published",
+ title: "Aggiorna",
+ body: "Versione nuova",
+ show_on_android: true,
+ show_on_ios: false,
+ android_title: "Aggiorna Android",
+ android_action_url: "https://play.google.com/store/apps/details?id=com.matchlivetv.match_live_tv"
+ )
get "/api/v1/announcements", params: { platform: "android" }
expect(response).to have_http_status(:ok)
- body = JSON.parse(response.body)
- expect(body.length).to eq(1)
- expect(body.first["title"]).to eq("Manutenzione stasera")
- expect(body.first["kind"]).to eq("maintenance")
- expect(body.first["dismissible"]).to eq(true)
+ android_body = JSON.parse(response.body)
+ expect(android_body.map { |row| row["title"] }).to contain_exactly("Manutenzione stasera", "Aggiorna Android")
+
+ get "/api/v1/announcements", params: { platform: "ios" }
+
+ expect(response).to have_http_status(:ok)
+ ios_body = JSON.parse(response.body)
+ expect(ios_body.map { |row| row["title"] }).to eq(["Manutenzione stasera"])
end
end
diff --git a/backend/spec/requests/public/announcements_spec.rb b/backend/spec/requests/public/announcements_spec.rb
index afdf5ba..7aa845c 100644
--- a/backend/spec/requests/public/announcements_spec.rb
+++ b/backend/spec/requests/public/announcements_spec.rb
@@ -11,12 +11,12 @@ RSpec.describe "Public site announcements", type: :request do
AppAnnouncement.create!(
kind: "maintenance", status: "published", title: "Manutenzione sito",
body: "Stasera il sito sarà offline.",
- show_on_app: false, show_on_web_public: true, show_on_web_private: false
+ show_on_android: false, show_on_ios: false, show_on_web_public: true, show_on_web_private: false
)
AppAnnouncement.create!(
kind: "info", status: "published", title: "Solo soci",
body: "Messaggio interno.",
- show_on_app: false, show_on_web_public: false, show_on_web_private: true
+ show_on_android: false, show_on_ios: false, show_on_web_public: false, show_on_web_private: true
)
get root_path
@@ -30,12 +30,12 @@ RSpec.describe "Public site announcements", type: :request do
AppAnnouncement.create!(
kind: "info", status: "published", title: "Solo soci",
body: "Messaggio interno.",
- show_on_app: false, show_on_web_public: false, show_on_web_private: true
+ show_on_android: false, show_on_ios: false, show_on_web_public: false, show_on_web_private: true
)
AppAnnouncement.create!(
kind: "info", status: "published", title: "Manutenzione sito",
body: "Stasera il sito sarà offline.",
- show_on_app: false, show_on_web_public: true, show_on_web_private: false
+ show_on_android: false, show_on_ios: false, show_on_web_public: true, show_on_web_private: false
)
post public_login_path, params: { email: coach.email, password: "Password123" }
|