Catalyst / admin/Strike 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Strike

public

Web-Based UK Cyber Compliance Tool with Reporting

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
Strike / strikexi-v2 / backend / app / user_report.py 4047 B · main
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
"""
Admin-only Users Report (PDF).

Lists every account in the platform — both admin-created and self-service
signups — with their profile details, role and account type. Rendered to PDF
via WeasyPrint (consistent with the assessment report engine).
"""
import os
from datetime import datetime

from jinja2 import Template
from weasyprint import HTML

REPORTS_DIR = "/app/reports"


def _origin_label(origin: str) -> str:
    return "Self-service signup" if origin == "self_service" else "Admin created"


def _fmt(dt) -> str:
    return dt.strftime("%d %b %Y %H:%M") if dt else "—"


_TEMPLATE = Template(r"""
<!DOCTYPE html>
<html><head><meta charset="utf-8"><style>
  @page { size: A4 landscape; margin: 1.4cm 1.2cm; @bottom-center {
      content: "StrikeXi Users Report  —  Confidential  —  Page " counter(page) " of " counter(pages);
      font-size: 9px; color: #8a97a6; } }
  body { font-family: "DejaVu Sans", sans-serif; color: #2c3e50; font-size: 11px; }
  .brand { font-size: 26px; font-weight: bold; color: #16324f; }
  .brand span { color: #2e86de; }
  .subtitle { font-size: 14px; color: #5b6b7b; margin: 2px 0 14px; }
  .meta { font-size: 11px; color: #5b6b7b; margin-bottom: 12px; }
  .meta b { color:#16324f; }
  h2 { color:#16324f; border-bottom: 2px solid #2e86de; padding-bottom: 4px; margin-top: 18px; font-size: 14px; }
  table { width:100%; border-collapse: collapse; margin-top:8px; }
  th, td { text-align:left; padding:5px 6px; border-bottom:1px solid #e3e9ef; font-size:9.5px; }
  th { background:#16324f; color:#fff; }
  .pill { font-size:9px; padding:1px 6px; border-radius:8px; }
  .ss { background:#eaf3fd; color:#2e86de; }
  .adm { background:#eef2f7; color:#5b6b7b; }
  .summary span { display:inline-block; margin-right:18px; font-size:12px; }
</style></head><body>

  <div class="brand">Strike<span>Xi</span></div>
  <div class="subtitle">Platform Users Report</div>
  <div class="meta">
    <b>Generated:</b> {{ generated }} &nbsp;·&nbsp;
    <b>By:</b> {{ admin }} &nbsp;·&nbsp;
    <b>Total accounts:</b> {{ users|length }}
  </div>

  <div class="summary">
    <span><b>{{ count_admin_created }}</b> admin-created</span>
    <span><b>{{ count_self_service }}</b> self-service signups</span>
    <span><b>{{ count_admins }}</b> administrators</span>
  </div>

  <h2>All Users</h2>
  <table>
    <tr>
      <th>Username</th><th>Surname</th><th>First Name</th><th>Company</th>
      <th>Email</th><th>Contact</th><th>Role</th><th>Account Type</th>
      <th>Active</th><th>MFA</th><th>Last Login</th><th>Created</th>
    </tr>
    {% for u in users %}
    <tr>
      <td><b>{{ u.username }}</b></td>
      <td>{{ u.surname or '—' }}</td>
      <td>{{ u.first_name or '—' }}</td>
      <td>{{ u.company_name or '—' }}</td>
      <td>{{ u.email or '—' }}</td>
      <td>{{ u.contact_number or '—' }}</td>
      <td>{{ u.role }}</td>
      <td><span class="pill {{ 'ss' if u.signup_origin == 'self_service' else 'adm' }}">{{ origin_label(u.signup_origin) }}</span></td>
      <td>{{ 'Yes' if u.is_active else 'No' }}</td>
      <td>{{ 'On' if u.mfa_enabled else 'Off' }}</td>
      <td>{{ fmt(u.last_login) }}</td>
      <td>{{ fmt(u.created_at) }}</td>
    </tr>
    {% endfor %}
  </table>

</body></html>
""")


def generate_users_report(users, admin_username: str) -> str:
    count_self_service = sum(1 for u in users if u.signup_origin == "self_service")
    count_admin_created = len(users) - count_self_service
    count_admins = sum(1 for u in users if u.role == "admin")

    html = _TEMPLATE.render(
        users=users,
        admin=admin_username,
        generated=datetime.now().strftime("%d %B %Y %H:%M"),
        count_self_service=count_self_service,
        count_admin_created=count_admin_created,
        count_admins=count_admins,
        origin_label=_origin_label,
        fmt=_fmt,
    )

    os.makedirs(REPORTS_DIR, exist_ok=True)
    out_path = os.path.join(REPORTS_DIR, "StrikeXi_Users_Report.pdf")
    HTML(string=html).write_pdf(out_path)
    return out_path