{% comment %} One page of recipients, filtered by outcome. Bounded to a hundred rows: a ten-thousand-recipient broadcast has a counter for the whole and a list for the part an operator can act on. The reason is a machine-readable Denial code on the row; the sentence comes from apps.messaging.codes.describe, which is the same copy the inbox shows for the same code. Contact names are attacker-controlled and are escaped like any other template value (SECURITY-BASELINE §2). {% endcomment %}
| {% comment %} A recipient can outlive its contact. Issue #29's GDPR erasure nulls this foreign key rather than cascading, because the row is an anonymised counter the broadcast's figures are recomputed from — see apps/broadcasts/models.py. Reversing the detail URL with a null id raises NoReverseMatch, so the erased case gets a label instead of a link. {% endcomment %} {% if row.contact_id %} {{ row.contact.first_name }} {{ row.contact.last_name }} {% else %} Erased contact {% endif %} | {{ row.reason_label }} |
| Nobody in this group. |