Implementeaza PRD 5.6 complet (14 stories, TDD). Doua axe:
Lifecycle trimiteri blocate (Val A):
- submissions_admin.py: sterge/repune scoped (404 cross-account inaintea lui 409 stare)
- reactivare dedup peste `error` cu CAS (WHERE id=? AND status='error'), creds noi in
submissions + accounts.rar_creds_enc; worker invalideaza sesiunea RAR la creds proaspete
(JWT 30h vechi nu mai trimite cu parola gresita); camp aditiv `reactivated:true`
- retentie randuri blocate 30z; purge_expired exclude queued/sending; purge_after curatat
la reactivare/requeue
- API DELETE /v1/prezentari/{id} + /repune (200+JSON); UI butoane + bulk + banner actionabil
Observabilitate:
- app/observ.py log_event: dublu canal app_events (DB) + RotatingFileHandler per-proces,
redactare creds/PII la scriere (redact_pii/vin_partial)
- request_id middleware + X-Request-ID pe toate raspunsurile
- handler global excepții -> 500 envelope 6-chei + request_id (traceback doar in jurnal)
- audit cerere API (api_prezentari/api_auth_esuat) + audit worker (rar_login/tranzitii)
- tab "Jurnal" filtrabil scoped (non-admin doar contul sau); retentie jurnal 90z
- rar_error expus in GET /v1/prezentari/{id} (recovery observabil)
pytest -q: 741 passed, 0 failed. Docs: PRD raport VERIFY, contract endpointuri noi, ROADMAP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
85 lines
3.8 KiB
HTML
85 lines
3.8 KiB
HTML
<div id="status-bar" class="status-bar card"
|
|
hx-get="/_fragments/status"
|
|
hx-trigger="every 15s"
|
|
hx-swap="outerHTML">
|
|
|
|
<!-- Cont in asteptare de activare (regasit din vechiul _banner; mereu vizibil) -->
|
|
{% if not account_active %}
|
|
<div style="margin-bottom:12px; padding:8px 10px; border-left:3px solid var(--warn);
|
|
background:color-mix(in srgb, var(--warn) 12%, var(--card)); border-radius:6px; font-size:13px;">
|
|
<strong>Cont in asteptare de activare.</strong>
|
|
Configureaza credentialele RAR si pregateste importul acum; trimiterea catre RAR
|
|
porneste automat dupa activare de catre administrator.
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Rand 1: doua bife binare + ultima autentificare -->
|
|
<div style="display:flex; gap:28px; flex-wrap:wrap; align-items:center; font-size:14px;">
|
|
|
|
{# Bifa: glifa (✓/✗) + culoare + text — accesibil (nu doar culoare, design review) #}
|
|
{% macro bifa(ok, text, tip) %}
|
|
<span title="{{ tip }}" style="display:inline-flex; align-items:center; gap:7px;">
|
|
{% if ok %}
|
|
<span class="s-sent" aria-hidden="true" style="font-weight:bold;">✓</span>
|
|
<span class="s-sent">{{ text }}</span>
|
|
{% else %}
|
|
<span class="s-error" aria-hidden="true" style="font-weight:bold;">✗</span>
|
|
<span class="s-error">{{ text }}</span>
|
|
{% endif %}
|
|
</span>
|
|
{% endmacro %}
|
|
|
|
{{ bifa(worker_ok, worker_lbl[0], worker_lbl[1]) }}
|
|
{{ bifa(rar_ok, rar_lbl[0], rar_lbl[1]) }}
|
|
|
|
<span style="display:inline-flex; align-items:center; gap:6px;">
|
|
<span class="muted">{{ eticheta_ultima_auth }}:</span>
|
|
<span>{{ last_login }}</span>
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Rand 2: contoare coada -->
|
|
<div style="margin-top:10px; display:flex; gap:20px; flex-wrap:wrap; font-size:14px;">
|
|
<span><span class="muted">In asteptare:</span> <span class="s-queued">{{ counts_queued }}</span></span>
|
|
<span><span class="muted">Declarate la RAR:</span> <span class="s-sent">{{ counts_sent }}</span></span>
|
|
<span><span class="muted">Blocate:</span>
|
|
<span class="{{ 's-error' if blocate_total else 'muted' }}">{{ blocate_total }}</span>
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Necesita atentia ta (US-014): categorii actionabile — link la lista filtrata
|
|
+ identificatorii primelor randuri blocate. Se randeaza DOAR daca exista randuri
|
|
blocate; cand contorul ajunge 0 (sters/re-pus/purjat), sectiunea dispare. -->
|
|
{% if blocate_actionabil %}
|
|
<div style="margin-top:12px; padding-top:10px; border-top:1px solid var(--line);">
|
|
<div style="font-size:13px; font-weight:600; margin-bottom:8px;">Necesita atentia ta</div>
|
|
<div style="display:flex; gap:18px; flex-wrap:wrap;">
|
|
{% for cat in blocate_actionabil %}
|
|
<div style="min-width:200px;">
|
|
{# Link: filtreaza lista Trimiteri pe aceasta stare (HTMX in-place) cu fallback
|
|
deep-link server-side (?tab=acasa&status=...). #}
|
|
<a class="{{ cat.eticheta[2] }}" style="font-size:13px; font-weight:600; text-decoration:none;"
|
|
href="/?tab=acasa&status={{ cat.status }}"
|
|
hx-get="/_fragments/submissions?status={{ cat.status }}"
|
|
hx-target="#submissions-wrap" hx-swap="innerHTML"
|
|
onclick="var s=document.getElementById('trimiteri-section'); if(s) s.scrollIntoView({behavior:'smooth'});">
|
|
{{ cat.eticheta[0] }} ({{ cat.n }}) ›
|
|
</a>
|
|
<ul style="list-style:none; margin:6px 0 0; padding:0;">
|
|
{% for r in cat.randuri %}
|
|
<li class="muted" style="font-size:12px;">
|
|
#{{ r.id }} {{ r.vin }}{% if r.nr %} / {{ r.nr }}{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
{% if cat.rest %}
|
|
<li class="muted" style="font-size:12px;">…si inca {{ cat.rest }}</li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
</div>
|