Oysiyl commited on
Commit
cc65da2
·
1 Parent(s): e32bdbe

Filter QR analytics to post-creation scans

Browse files
Files changed (2) hide show
  1. hf_dashboard.py +60 -7
  2. tests-unit/hf_dashboard_test.py +20 -6
hf_dashboard.py CHANGED
@@ -118,6 +118,35 @@ def _table_select(table: str, *, query: str) -> list[dict[str, Any]]:
118
  return []
119
 
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  def _insert_row(table: str, row: Mapping[str, Any], *, upsert: bool = False) -> list[dict[str, Any]]:
122
  prefer = "return=representation"
123
  if upsert:
@@ -699,12 +728,36 @@ def get_generation_detail(request: Any | None, records: list[dict[str, Any]], in
699
  ),
700
  )
701
 
702
- total_scans = len(scan_rows)
703
- last_scanned_at = str(scan_rows[0].get("scanned_at") or "").replace("T", " ")[:19] if scan_rows else "Never"
704
- unique_scans = len({str(row.get('visitor_hash') or '') for row in scan_rows if str(row.get('visitor_hash') or '').strip()})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
 
706
- countries = Counter(str(row.get("country_code") or "Unknown") for row in scan_rows)
707
- scans_by_day = Counter(str(row.get("scanned_at") or "")[:10] for row in scan_rows if str(row.get("scanned_at") or ""))
 
 
708
 
709
  top_countries_rows = [[country, count] for country, count in countries.most_common(10)]
710
  scans_by_day_rows = [[day, scans_by_day[day]] for day in sorted(scans_by_day.keys())]
@@ -724,8 +777,8 @@ def get_generation_detail(request: Any | None, records: list[dict[str, Any]], in
724
  f"- Destination: {record.get('destination_url_original') or '—'}",
725
  f"- Short URL: {record.get('short_url') or '—'}",
726
  f"- Effective QR text: {record.get('effective_qr_text') or '—'}",
727
- f"- Total scans: {total_scans}",
728
- f"- Approx. unique scans: {unique_scans}",
729
  f"- Last scanned at: {last_scanned_at}",
730
  ]
731
  )
 
118
  return []
119
 
120
 
121
+ def _parse_timestamp(value: Any) -> datetime | None:
122
+ text = str(value or "").strip()
123
+ if not text:
124
+ return None
125
+ if text.endswith("Z"):
126
+ text = text[:-1] + "+00:00"
127
+ if "." in text:
128
+ main, suffix = text.split(".", 1)
129
+ tz_index_plus = suffix.find("+")
130
+ tz_index_minus = suffix.find("-")
131
+ tz_index_candidates = [idx for idx in (tz_index_plus, tz_index_minus) if idx != -1]
132
+ tz_index = min(tz_index_candidates) if tz_index_candidates else -1
133
+ if tz_index != -1:
134
+ fraction = suffix[:tz_index]
135
+ timezone_part = suffix[tz_index:]
136
+ else:
137
+ fraction = suffix
138
+ timezone_part = ""
139
+ if fraction:
140
+ fraction = (fraction + "000000")[:6]
141
+ text = f"{main}.{fraction}{timezone_part}"
142
+ if len(text) >= 3 and text[-3] in {"+", "-"} and text[-2:].isdigit():
143
+ text = text + ":00"
144
+ try:
145
+ return datetime.fromisoformat(text)
146
+ except ValueError:
147
+ return None
148
+
149
+
150
  def _insert_row(table: str, row: Mapping[str, Any], *, upsert: bool = False) -> list[dict[str, Any]]:
151
  prefer = "return=representation"
152
  if upsert:
 
728
  ),
729
  )
730
 
731
+ created_at_dt = _parse_timestamp(record.get("created_at"))
732
+ filtered_scan_rows = [
733
+ row
734
+ for row in scan_rows
735
+ if not bool(row.get("is_bot"))
736
+ and not bool(row.get("is_prefetch"))
737
+ and (
738
+ created_at_dt is None
739
+ or (_parse_timestamp(row.get("scanned_at")) or created_at_dt) >= created_at_dt
740
+ )
741
+ ]
742
+
743
+ total_scans = len(filtered_scan_rows)
744
+ last_scanned_at = (
745
+ str(filtered_scan_rows[0].get("scanned_at") or "").replace("T", " ")[:19]
746
+ if filtered_scan_rows
747
+ else "Never"
748
+ )
749
+ unique_scans = len(
750
+ {
751
+ str(row.get("visitor_hash") or "")
752
+ for row in filtered_scan_rows
753
+ if str(row.get("visitor_hash") or "").strip()
754
+ }
755
+ )
756
 
757
+ countries = Counter(str(row.get("country_code") or "Unknown") for row in filtered_scan_rows)
758
+ scans_by_day = Counter(
759
+ str(row.get("scanned_at") or "")[:10] for row in filtered_scan_rows if str(row.get("scanned_at") or "")
760
+ )
761
 
762
  top_countries_rows = [[country, count] for country, count in countries.most_common(10)]
763
  scans_by_day_rows = [[day, scans_by_day[day]] for day in sorted(scans_by_day.keys())]
 
777
  f"- Destination: {record.get('destination_url_original') or '—'}",
778
  f"- Short URL: {record.get('short_url') or '—'}",
779
  f"- Effective QR text: {record.get('effective_qr_text') or '—'}",
780
+ f"- Total scans since this QR was created: {total_scans}",
781
+ f"- Approx. unique scans since creation: {unique_scans}",
782
  f"- Last scanned at: {last_scanned_at}",
783
  ]
784
  )
tests-unit/hf_dashboard_test.py CHANGED
@@ -116,26 +116,40 @@ def test_get_generation_detail_aggregates_scan_analytics(monkeypatch) -> None:
116
  if table == "short_link_scan_events":
117
  return [
118
  {
119
- "scanned_at": "2026-05-31T12:00:00+00:00",
 
 
 
 
 
 
 
120
  "country_code": "US",
121
  "visitor_hash": "v1",
122
  "is_bot": False,
123
  "is_prefetch": False,
124
  },
125
  {
126
- "scanned_at": "2026-05-31T13:00:00+00:00",
127
  "country_code": "NL",
128
  "visitor_hash": "v2",
129
  "is_bot": False,
130
  "is_prefetch": False,
131
  },
132
  {
133
- "scanned_at": "2026-05-31T14:00:00+00:00",
134
  "country_code": "US",
135
  "visitor_hash": "v1",
136
  "is_bot": False,
137
  "is_prefetch": False,
138
  },
 
 
 
 
 
 
 
139
  ]
140
  raise AssertionError(f"Unexpected table: {table}")
141
 
@@ -144,7 +158,7 @@ def test_get_generation_detail_aggregates_scan_analytics(monkeypatch) -> None:
144
  {
145
  "id": "gen-1",
146
  "app_user_id": "user-1",
147
- "created_at": "2026-05-31T10:00:00+00:00",
148
  "status": "completed",
149
  "input_type": "URL",
150
  "qr_mode": "standard",
@@ -159,8 +173,8 @@ def test_get_generation_detail_aggregates_scan_analytics(monkeypatch) -> None:
159
 
160
  detail = hf_dashboard.get_generation_detail(FakeRequest(oauth_info=HF_OAUTH_INFO), records, 0)
161
 
162
- assert "Total scans: 3" in detail["detail_markdown"]
163
- assert "Approx. unique scans: 2" in detail["detail_markdown"]
164
  assert detail["image"] == "https://cdn.example/full.png"
165
  assert detail["top_countries_rows"] == [["US", 2], ["NL", 1]]
166
  assert detail["scans_by_day_rows"] == [["2026-05-31", 3]]
 
116
  if table == "short_link_scan_events":
117
  return [
118
  {
119
+ "scanned_at": "2026-05-31T14:00:00+00:00",
120
+ "country_code": "US",
121
+ "visitor_hash": "old-v",
122
+ "is_bot": False,
123
+ "is_prefetch": False,
124
+ },
125
+ {
126
+ "scanned_at": "2026-05-31T15:00:00+00:00",
127
  "country_code": "US",
128
  "visitor_hash": "v1",
129
  "is_bot": False,
130
  "is_prefetch": False,
131
  },
132
  {
133
+ "scanned_at": "2026-05-31T16:00:00+00:00",
134
  "country_code": "NL",
135
  "visitor_hash": "v2",
136
  "is_bot": False,
137
  "is_prefetch": False,
138
  },
139
  {
140
+ "scanned_at": "2026-05-31T17:00:00+00:00",
141
  "country_code": "US",
142
  "visitor_hash": "v1",
143
  "is_bot": False,
144
  "is_prefetch": False,
145
  },
146
+ {
147
+ "scanned_at": "2026-05-31T18:00:00+00:00",
148
+ "country_code": "US",
149
+ "visitor_hash": "bot-v",
150
+ "is_bot": True,
151
+ "is_prefetch": False,
152
+ },
153
  ]
154
  raise AssertionError(f"Unexpected table: {table}")
155
 
 
158
  {
159
  "id": "gen-1",
160
  "app_user_id": "user-1",
161
+ "created_at": "2026-05-31T14:47:47+00:00",
162
  "status": "completed",
163
  "input_type": "URL",
164
  "qr_mode": "standard",
 
173
 
174
  detail = hf_dashboard.get_generation_detail(FakeRequest(oauth_info=HF_OAUTH_INFO), records, 0)
175
 
176
+ assert "Total scans since this QR was created: 3" in detail["detail_markdown"]
177
+ assert "Approx. unique scans since creation: 2" in detail["detail_markdown"]
178
  assert detail["image"] == "https://cdn.example/full.png"
179
  assert detail["top_countries_rows"] == [["US", 2], ["NL", 1]]
180
  assert detail["scans_by_day_rows"] == [["2026-05-31", 3]]