VeuReu commited on
Commit
e2c60fb
verified
1 Parent(s): 6a418dc

Upload 10 files

Browse files
app.py CHANGED
@@ -14,7 +14,7 @@ from databases import set_db_path, init_schema, set_blockchain_enabled
14
  from api_client import APIClient
15
  from utils import ensure_dirs
16
  from auth import initialize_auth_system, render_login_form, render_sidebar, require_login
17
- from persistent_data_gate import ensure_temp_databases
18
  from mobile_verification import render_mobile_verification_screen, get_user_permissions
19
  from compliance_client import compliance_client
20
  from page_modules.new_video_processing import render_process_video_page
@@ -117,17 +117,14 @@ set_db_path(DB_PATH)
117
  # Configurar si els esdeveniments s'han de registrar a SQLite o a AWS QLDB
118
  set_blockchain_enabled(PRIVATE_BLOCKCHAIN_ENABLE)
119
 
120
- # Si est脿 habilitat el registre p煤blic i el digest mensual, publicar al
121
- # principi de cada mes un digest global via servei de compliance.
122
- if PUBLIC_BLOCKCHAIN_ENABLE and MONTHLY_DIGEST_ENABLED:
123
- try:
124
- today = datetime.utcnow().date()
125
- if today.day == 1:
126
- period = today.strftime("%Y-%m")
127
- compliance_client.publish_monthly_digest(period)
128
- except Exception:
129
- # No bloquejar l'app per errors de blockchain/compliance
130
- pass
131
 
132
  init_schema()
133
 
 
14
  from api_client import APIClient
15
  from utils import ensure_dirs
16
  from auth import initialize_auth_system, render_login_form, render_sidebar, require_login
17
+ from persistent_data_gate import ensure_temp_databases, maybe_publish_monthly_actions_digest
18
  from mobile_verification import render_mobile_verification_screen, get_user_permissions
19
  from compliance_client import compliance_client
20
  from page_modules.new_video_processing import render_process_video_page
 
117
  # Configurar si els esdeveniments s'han de registrar a SQLite o a AWS QLDB
118
  set_blockchain_enabled(PRIVATE_BLOCKCHAIN_ENABLE)
119
 
120
+ # Si est脿 habilitat el registre p煤blic i el digest mensual, publicar si cal
121
+ # el digest mensual sobre actions.db (es calcula al voltant del mes anterior).
122
+ maybe_publish_monthly_actions_digest(
123
+ base_dir,
124
+ compliance_client,
125
+ public_blockchain_enabled=PUBLIC_BLOCKCHAIN_ENABLE,
126
+ monthly_digest_enabled=MONTHLY_DIGEST_ENABLED,
127
+ )
 
 
 
128
 
129
  init_schema()
130
 
compliance_client.py CHANGED
@@ -569,9 +569,18 @@ class ComplianceClient:
569
 
570
  # === M脡TODOS DE BLOCKCHAIN (POLYGON) ===
571
 
572
- def publish_monthly_digest(self, period: str) -> Optional[str]:
573
- """Publica digest mensual en blockchain"""
574
- response = self._make_request("POST", "/api/blockchain/publish-digest", {"period": period})
 
 
 
 
 
 
 
 
 
575
 
576
  if response:
577
  tx_hash = response.get("transaction_hash")
 
569
 
570
  # === M脡TODOS DE BLOCKCHAIN (POLYGON) ===
571
 
572
+ def publish_monthly_digest(self, period: str, digest_hash: str | None = None) -> Optional[str]:
573
+ """Publica digest mensual en blockchain.
574
+
575
+ Si digest_hash no 茅s None, s'envia tamb茅 al backend perqu猫 el faci
576
+ servir com a arrel del digest mensual.
577
+ """
578
+
579
+ payload: Dict[str, Any] = {"period": period}
580
+ if digest_hash:
581
+ payload["digest_hash"] = digest_hash
582
+
583
+ response = self._make_request("POST", "/api/blockchain/publish-digest", payload)
584
 
585
  if response:
586
  tx_hash = response.get("transaction_hash")
databases.py CHANGED
@@ -275,11 +275,11 @@ def get_accessible_videos_with_sha1(session_id: str | None) -> List[Dict[str, An
275
  # Ordenem per nom de v铆deo per estabilitat
276
  return sorted(public_rows.values(), key=lambda r: (r["video_name"] or r["sha1sum"]))
277
 
278
- # 2) Tel猫fons associats a la sessi贸 actual
279
  phones: set[str] = set()
280
- with _connect_events_db() as econn:
281
- for row in econn.execute(
282
- "SELECT DISTINCT phone FROM events WHERE session = ? AND phone IS NOT NULL AND phone != ''",
283
  (session_id,),
284
  ):
285
  phones.add(row["phone"])
@@ -930,19 +930,6 @@ def insert_demo_feedback_row(
930
  )
931
 
932
 
933
- def _connect_events_db() -> sqlite3.Connection:
934
- """Connexi贸 directa a demo/temp/events.db.
935
-
936
- Es fa independent de DEFAULT_DB_PATH per mantenir aquesta BD separada
937
- de users.db, igual que feedback.db.
938
- """
939
-
940
- EVENTS_DB_PATH.parent.mkdir(parents=True, exist_ok=True)
941
- conn = sqlite3.connect(str(EVENTS_DB_PATH))
942
- conn.row_factory = sqlite3.Row
943
- return conn
944
-
945
-
946
  def _connect_videos_db() -> sqlite3.Connection:
947
  """Connexi贸 directa a demo/temp/videos.db.
948
 
 
275
  # Ordenem per nom de v铆deo per estabilitat
276
  return sorted(public_rows.values(), key=lambda r: (r["video_name"] or r["sha1sum"]))
277
 
278
+ # 2) Tel猫fons associats a la sessi贸 actual (a partir de actions.db)
279
  phones: set[str] = set()
280
+ with _connect_actions_db() as aconn:
281
+ for row in aconn.execute(
282
+ "SELECT DISTINCT phone FROM actions WHERE session = ? AND phone IS NOT NULL AND phone != ''",
283
  (session_id,),
284
  ):
285
  phones.add(row["phone"])
 
930
  )
931
 
932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
933
  def _connect_videos_db() -> sqlite3.Connection:
934
  """Connexi贸 directa a demo/temp/videos.db.
935
 
mobile_verification.py CHANGED
@@ -108,6 +108,28 @@ def send_sms_code(phone_number: str) -> bool:
108
  log("[SMS] Error retornat per compliance en enviar l'SMS de login")
109
  return False
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  return True
112
  except Exception as e:
113
  log(f"[SMS] Error generant/enviant codi via compliance: {e}")
 
108
  log("[SMS] Error retornat per compliance en enviar l'SMS de login")
109
  return False
110
 
111
+ # Registrar SMS de login a actions.db
112
+ try:
113
+ from databases import log_action
114
+
115
+ session_id = st.session_state.get("session_id", "")
116
+ user_obj = st.session_state.get("user") or {}
117
+ username = (
118
+ user_obj.get("username")
119
+ if isinstance(user_obj, dict)
120
+ else str(user_obj or "")
121
+ )
122
+
123
+ log_action(
124
+ session=session_id,
125
+ user=username,
126
+ phone=normalized_phone,
127
+ action="SMS sent for login verification",
128
+ sha1sum="",
129
+ )
130
+ except Exception:
131
+ pass
132
+
133
  return True
134
  except Exception as e:
135
  log(f"[SMS] Error generant/enviant codi via compliance: {e}")
page_modules/machine_room.py CHANGED
@@ -182,3 +182,28 @@ def render_machine_room_page() -> None:
182
  _save_config(cfg)
183
  st.success("Configuraci贸 desada correctament. Reinicia la p脿gina per veure els canvis aplicats.")
184
  st.experimental_rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  _save_config(cfg)
183
  st.success("Configuraci贸 desada correctament. Reinicia la p脿gina per veure els canvis aplicats.")
184
  st.experimental_rerun()
185
+
186
+ # Botons d'accions avan莽ades a la part inferior de la pantalla
187
+ st.markdown("---")
188
+
189
+ # Estil b脿sic per fer els botons secundaris de color taronja
190
+ st.markdown(
191
+ """
192
+ <style>
193
+ div[data-testid="baseButton-secondary"] button {
194
+ background-color: #f97316 !important;
195
+ border-color: #ea580c !important;
196
+ color: white !important;
197
+ }
198
+ </style>
199
+ """,
200
+ unsafe_allow_html=True,
201
+ )
202
+
203
+ col_b1, col_b2, col_b3 = st.columns(3)
204
+ with col_b1:
205
+ st.button("Bu茂dar fitxers temporals", type="secondary", use_container_width=True)
206
+ with col_b2:
207
+ st.button("Reconstruir audiodescripcions", type="secondary", use_container_width=True)
208
+ with col_b3:
209
+ st.button("Reentrenar refinament", type="secondary", use_container_width=True)
page_modules/new_video_processing.py CHANGED
@@ -492,10 +492,35 @@ def render_process_video_page(api, backend_base_url: str) -> None:
492
  # Notificar al validador per SMS nom茅s si est脿 habilitat a config.yaml
493
  if video_validator_sms_enabled:
494
  try:
495
- compliance_client.notify_video_upload(
496
  video_name=uploaded_file.name,
497
  sha1sum=sha1,
498
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  except Exception as sms_exc:
500
  print(f"[VIDEO SMS] Error enviant notificaci贸 al validor: {sms_exc}")
501
  else:
@@ -1814,27 +1839,39 @@ def render_process_video_page(api, backend_base_url: str) -> None:
1814
  try:
1815
  # Text de l'SMS en catal脿, tal com has indicat
1816
  sms_msg = "Noves audiodescripcions a validar segons la norma UNE-153020"
1817
- compliance_client.notify_une_validator_new_ads(
1818
  phone=une_phone_validator,
1819
  message=sms_msg,
1820
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
1821
  except Exception as e_sms_call:
1822
  _log(f"[UNE SMS] Error cridant compliance per UNE: {e_sms_call}")
1823
 
1824
- # Registrar estat d'espera de validaci贸 UNE a events.db
1825
  try:
1826
- log_event(
1827
- session=session_id,
1828
- ip=ip,
 
1829
  user=username or "",
1830
- password=password or "",
1831
- phone=une_phone_validator,
1832
  action="Waiting for UNE validation",
1833
- sha1sum=sha1,
1834
- visibility=vis_flag,
1835
  )
1836
  except Exception as e_evt_wait:
1837
- _log(f"[events] Error registrant Waiting for UNE validation: {e_evt_wait}")
1838
  except Exception as e_sms:
1839
  _log(f"[UNE SMS] Error en flux d'SMS/espera validaci贸: {e_sms}")
1840
 
 
492
  # Notificar al validador per SMS nom茅s si est脿 habilitat a config.yaml
493
  if video_validator_sms_enabled:
494
  try:
495
+ sms_ok = compliance_client.notify_video_upload(
496
  video_name=uploaded_file.name,
497
  sha1sum=sha1,
498
  )
499
+ if sms_ok:
500
+ try:
501
+ from databases import log_action
502
+
503
+ session_id = st.session_state.get("session_id", "")
504
+ user_obj = st.session_state.get("user") or {}
505
+ username = (
506
+ user_obj.get("username")
507
+ if isinstance(user_obj, dict)
508
+ else str(user_obj or "")
509
+ )
510
+ phone = (
511
+ st.session_state.get("sms_phone_verified")
512
+ or st.session_state.get("sms_phone")
513
+ or ""
514
+ )
515
+ log_action(
516
+ session=session_id,
517
+ user=username,
518
+ phone=phone,
519
+ action="SMS sent to video validator",
520
+ sha1sum=sha1 or "",
521
+ )
522
+ except Exception:
523
+ pass
524
  except Exception as sms_exc:
525
  print(f"[VIDEO SMS] Error enviant notificaci贸 al validor: {sms_exc}")
526
  else:
 
1839
  try:
1840
  # Text de l'SMS en catal脿, tal com has indicat
1841
  sms_msg = "Noves audiodescripcions a validar segons la norma UNE-153020"
1842
+ sms_ok = compliance_client.notify_une_validator_new_ads(
1843
  phone=une_phone_validator,
1844
  message=sms_msg,
1845
  )
1846
+ if sms_ok:
1847
+ try:
1848
+ from databases import log_action
1849
+
1850
+ log_action(
1851
+ session=session_id or "",
1852
+ user=username or "",
1853
+ phone=str(une_phone_validator or ""),
1854
+ action="SMS sent to UNE validator",
1855
+ sha1sum=sha1 or "",
1856
+ )
1857
+ except Exception:
1858
+ pass
1859
  except Exception as e_sms_call:
1860
  _log(f"[UNE SMS] Error cridant compliance per UNE: {e_sms_call}")
1861
 
1862
+ # Registrar estat d'espera de validaci贸 UNE a actions.db
1863
  try:
1864
+ from databases import log_action
1865
+
1866
+ log_action(
1867
+ session=session_id or "",
1868
  user=username or "",
1869
+ phone=str(une_phone_validator or ""),
 
1870
  action="Waiting for UNE validation",
1871
+ sha1sum=sha1 or "",
 
1872
  )
1873
  except Exception as e_evt_wait:
1874
+ _log(f"[actions] Error registrant Waiting for UNE validation: {e_evt_wait}")
1875
  except Exception as e_sms:
1876
  _log(f"[UNE SMS] Error en flux d'SMS/espera validaci贸: {e_sms}")
1877
 
page_modules/validation.py CHANGED
@@ -278,11 +278,25 @@ def render_validation_page(
278
  try:
279
  # Text proporcionat (en castell脿, per貌 segons els requisits de l'SMS)
280
  msg = "Su v铆deo ha sido aprobado. Puede entrar en la aplicaci贸n y subirlo de nuevo para generar la audiodescripci贸n"
281
- compliance_client.notify_user_video_approved(
282
  phone=owner_phone,
283
  message=msg,
284
  sha1sum=sha1,
285
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  except Exception as e_sms:
287
  _log(f"[VIDEO USER SMS] Error enviant SMS a l'usuari: {e_sms}")
288
 
 
278
  try:
279
  # Text proporcionat (en castell脿, per貌 segons els requisits de l'SMS)
280
  msg = "Su v铆deo ha sido aprobado. Puede entrar en la aplicaci贸n y subirlo de nuevo para generar la audiodescripci贸n"
281
+ sms_ok = compliance_client.notify_user_video_approved(
282
  phone=owner_phone,
283
  message=msg,
284
  sha1sum=sha1,
285
  )
286
+ if sms_ok:
287
+ try:
288
+ from databases import log_action
289
+
290
+ session_id = st.session_state.get("session_id", "")
291
+ log_action(
292
+ session=session_id,
293
+ user=username or "",
294
+ phone=owner_phone,
295
+ action="SMS sent to user for video approval",
296
+ sha1sum=sha1 or "",
297
+ )
298
+ except Exception:
299
+ pass
300
  except Exception as e_sms:
301
  _log(f"[VIDEO USER SMS] Error enviant SMS a l'usuari: {e_sms}")
302
 
persistent_data_gate.py CHANGED
@@ -109,7 +109,7 @@ def ensure_temp_databases(base_dir: Path, api_client) -> None:
109
  else:
110
  # Mode external: descarregar BDs del backend una sola vegada per sessi贸 del servidor
111
  ext_marker = db_temp_dir / ".external_db_imported"
112
- missing = [name for name in ("events.db", "feedback.db", "users.db", "videos.db") if not (db_temp_dir / name).exists()]
113
 
114
  if ext_marker.exists() and not missing:
115
  return
@@ -136,6 +136,115 @@ def ensure_temp_databases(base_dir: Path, api_client) -> None:
136
  return
137
 
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  def _extract_zip_bytes(zip_bytes: bytes, target_dir: Path) -> None:
140
  target_dir.mkdir(parents=True, exist_ok=True)
141
  with zipfile.ZipFile(io.BytesIO(zip_bytes)) as zf:
@@ -349,26 +458,26 @@ def confirm_changes_and_logout(base_dir: Path, api_client, session_id: str) -> N
349
  # No aturar tot el proc茅s per un error puntual
350
  continue
351
 
352
- # --- 2) Digest d'esdeveniments per a la sessi贸 (public blockchain) ---
353
  events_digest_info = None
354
  if public_blockchain_enabled:
355
- events_db = db_temp_dir / "events.db"
356
  try:
357
  import sqlite3
358
  import hashlib
359
  import json
360
 
361
- with sqlite3.connect(str(events_db)) as econn:
362
- econn.row_factory = sqlite3.Row
363
- cur = econn.cursor()
364
 
365
- # Comprovar que existeix la taula events
366
  cur.execute(
367
- "SELECT name FROM sqlite_master WHERE type='table' AND name='events'"
368
  )
369
  if cur.fetchone():
370
  cur.execute(
371
- "SELECT * FROM events WHERE session = ?", (session_id,)
372
  )
373
  rows = cur.fetchall()
374
  if rows:
@@ -399,6 +508,19 @@ def confirm_changes_and_logout(base_dir: Path, api_client, session_id: str) -> N
399
  print(
400
  f"[POLYGON PUBLISH] ok tx_hash={tx_hash} tx_url={tx_url}"
401
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  else:
403
  print("[POLYGON PUBLISH] error: resposta buida o nul路la")
404
  except Exception as bexc:
@@ -549,6 +671,8 @@ def confirm_changes_and_logout(base_dir: Path, api_client, session_id: str) -> N
549
  user_sms_enabled = bool(validation_cfg.get("user_sms_enabled", False))
550
 
551
  if user_sms_enabled:
 
 
552
  for sha1, phone in revoked_sha1s.items():
553
  if not phone:
554
  continue
@@ -557,20 +681,27 @@ def confirm_changes_and_logout(base_dir: Path, api_client, session_id: str) -> N
557
  "Els permisos per utilitzar el vostre v铆deo han estat revocats. "
558
  "Les dades associades han estat eliminades del sistema."
559
  )
560
- compliance_client.notify_user_video_approved(
561
  phone=phone,
562
  message=msg,
563
  sha1sum=sha1,
564
  )
 
 
 
 
 
 
 
 
 
 
 
565
  except Exception:
566
  continue
567
  except Exception:
568
  pass
569
 
570
- # --- 4) Nous v铆deos a videos.db associats a la sessi贸 (excloent revocats) ---
571
- videos_db = db_temp_dir / "videos.db"
572
- new_sha1s: set[str] = set()
573
-
574
  try:
575
  import sqlite3
576
 
 
109
  else:
110
  # Mode external: descarregar BDs del backend una sola vegada per sessi贸 del servidor
111
  ext_marker = db_temp_dir / ".external_db_imported"
112
+ missing = [name for name in ("feedback.db", "users.db", "videos.db") if not (db_temp_dir / name).exists()]
113
 
114
  if ext_marker.exists() and not missing:
115
  return
 
136
  return
137
 
138
 
139
+ def maybe_publish_monthly_actions_digest(
140
+ base_dir: Path,
141
+ compliance_client,
142
+ public_blockchain_enabled: bool,
143
+ monthly_digest_enabled: bool,
144
+ ) -> None:
145
+ """Publica, si cal, el digest mensual sobre actions.db a Polygon.
146
+
147
+ S'executa despr茅s de tenir demo/temp/db poblats. Calcula el hash de totes
148
+ les accions del mes anterior (segons camp timestamp) i, si encara no s'ha
149
+ registrat una acci贸 "Monthly Digest sent to Polygon" amb aquest hash,
150
+ el publica via servei de compliance.
151
+ """
152
+
153
+ if not (public_blockchain_enabled and monthly_digest_enabled):
154
+ return
155
+
156
+ try:
157
+ from datetime import datetime, date
158
+ import sqlite3
159
+ import hashlib
160
+ import json
161
+
162
+ db_temp_dir = base_dir / "temp" / "db"
163
+ actions_db_path = db_temp_dir / "actions.db"
164
+ if not actions_db_path.exists():
165
+ return
166
+
167
+ today = datetime.utcnow().date()
168
+ # Per铆ode objectiu: mes anterior
169
+ if today.month == 1:
170
+ year = today.year - 1
171
+ month = 12
172
+ else:
173
+ year = today.year
174
+ month = today.month - 1
175
+
176
+ period = f"{year:04d}-{month:02d}"
177
+
178
+ # Rang de timestamps per al mes anterior
179
+ start_ts = f"{period}-01 00:00:00"
180
+ if month == 12:
181
+ next_year = year + 1
182
+ next_month = 1
183
+ else:
184
+ next_year = year
185
+ next_month = month + 1
186
+ end_period = f"{next_year:04d}-{next_month:02d}"
187
+ end_ts = f"{end_period}-01 00:00:00"
188
+
189
+ with sqlite3.connect(str(actions_db_path)) as conn:
190
+ conn.row_factory = sqlite3.Row
191
+ cur = conn.cursor()
192
+
193
+ # Assegurar que la taula actions existeix
194
+ cur.execute(
195
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='actions'"
196
+ )
197
+ if not cur.fetchone():
198
+ return
199
+
200
+ # Llegir totes les accions del per铆ode
201
+ cur.execute(
202
+ "SELECT * FROM actions WHERE timestamp >= ? AND timestamp < ?",
203
+ (start_ts, end_ts),
204
+ )
205
+ rows = cur.fetchall()
206
+ if not rows:
207
+ return
208
+
209
+ payload: list[dict[str, Any]] = []
210
+ for r in rows:
211
+ payload.append({k: r[k] for k in r.keys()})
212
+
213
+ serialized = json.dumps(payload, sort_keys=True, separators=(",", ":"))
214
+ digest_hash = hashlib.sha256(serialized.encode("utf-8")).hexdigest()
215
+
216
+ # Comprovar si ja hem enregistrat aquest digest com enviat
217
+ cur.execute(
218
+ "SELECT 1 FROM actions WHERE action = 'Monthly Digest sent to Polygon' AND sha1sum = ? LIMIT 1",
219
+ (digest_hash,),
220
+ )
221
+ if cur.fetchone():
222
+ return
223
+
224
+ # Publicar via servei de compliance
225
+ try:
226
+ resp = compliance_client.publish_monthly_digest(period, digest_hash=digest_hash)
227
+ if resp:
228
+ try:
229
+ from databases import log_action
230
+
231
+ log_action(
232
+ session="", # digest global per per铆ode
233
+ user="",
234
+ phone="",
235
+ action="Monthly Digest sent to Polygon",
236
+ sha1sum=digest_hash,
237
+ )
238
+ except Exception:
239
+ pass
240
+ except Exception:
241
+ # No aturar el flux per errors de digest mensual
242
+ return
243
+ except Exception:
244
+ # No ha de bloquejar l'aplicaci贸
245
+ return
246
+
247
+
248
  def _extract_zip_bytes(zip_bytes: bytes, target_dir: Path) -> None:
249
  target_dir.mkdir(parents=True, exist_ok=True)
250
  with zipfile.ZipFile(io.BytesIO(zip_bytes)) as zf:
 
458
  # No aturar tot el proc茅s per un error puntual
459
  continue
460
 
461
+ # --- 2) Digest d'accions per a la sessi贸 (public blockchain) ---
462
  events_digest_info = None
463
  if public_blockchain_enabled:
464
+ actions_db_path = db_temp_dir / "actions.db"
465
  try:
466
  import sqlite3
467
  import hashlib
468
  import json
469
 
470
+ with sqlite3.connect(str(actions_db_path)) as aconn:
471
+ aconn.row_factory = sqlite3.Row
472
+ cur = aconn.cursor()
473
 
474
+ # Comprovar que existeix la taula actions
475
  cur.execute(
476
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='actions'"
477
  )
478
  if cur.fetchone():
479
  cur.execute(
480
+ "SELECT * FROM actions WHERE session = ?", (session_id,)
481
  )
482
  rows = cur.fetchall()
483
  if rows:
 
508
  print(
509
  f"[POLYGON PUBLISH] ok tx_hash={tx_hash} tx_url={tx_url}"
510
  )
511
+ # Registrar publicaci贸 del digest a actions.db
512
+ try:
513
+ from databases import log_action
514
+
515
+ log_action(
516
+ session=session_id or "",
517
+ user="", # no tenim usuari expl铆cit aqu铆
518
+ phone="",
519
+ action="Polygon events digest published",
520
+ sha1sum=digest_hash,
521
+ )
522
+ except Exception:
523
+ pass
524
  else:
525
  print("[POLYGON PUBLISH] error: resposta buida o nul路la")
526
  except Exception as bexc:
 
671
  user_sms_enabled = bool(validation_cfg.get("user_sms_enabled", False))
672
 
673
  if user_sms_enabled:
674
+ from databases import log_action
675
+
676
  for sha1, phone in revoked_sha1s.items():
677
  if not phone:
678
  continue
 
681
  "Els permisos per utilitzar el vostre v铆deo han estat revocats. "
682
  "Les dades associades han estat eliminades del sistema."
683
  )
684
+ sms_ok = compliance_client.notify_user_video_approved(
685
  phone=phone,
686
  message=msg,
687
  sha1sum=sha1,
688
  )
689
+ if sms_ok:
690
+ try:
691
+ log_action(
692
+ session=session_id or "",
693
+ user="", # desconegut en aquest context
694
+ phone=phone,
695
+ action="SMS sent to user for video revocation",
696
+ sha1sum=sha1 or "",
697
+ )
698
+ except Exception:
699
+ pass
700
  except Exception:
701
  continue
702
  except Exception:
703
  pass
704
 
 
 
 
 
705
  try:
706
  import sqlite3
707