arthexis 0.1.24__py3-none-any.whl → 0.1.25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arthexis might be problematic. Click here for more details.

pages/tests.py CHANGED
@@ -515,6 +515,23 @@ class InvitationTests(TestCase):
515
515
  self.assertEqual(lead.mac_address, "")
516
516
  self.assertEqual(len(mail.outbox), 0)
517
517
 
518
+ def test_request_invite_uses_original_referer(self):
519
+ InviteLead.objects.all().delete()
520
+ self.client.get(
521
+ reverse("pages:index"),
522
+ HTTP_REFERER="https://campaign.example/landing",
523
+ )
524
+
525
+ resp = self.client.post(
526
+ reverse("pages:request-invite"),
527
+ {"email": "origin@example.com"},
528
+ HTTP_REFERER="http://testserver/pages/request-invite/",
529
+ )
530
+
531
+ self.assertEqual(resp.status_code, 200)
532
+ lead = InviteLead.objects.get()
533
+ self.assertEqual(lead.referer, "https://campaign.example/landing")
534
+
518
535
  def test_request_invite_falls_back_to_send_mail(self):
519
536
  node = Node.objects.create(
520
537
  hostname="local", address="127.0.0.1", mac_address="00:11:22:33:44:55"
@@ -3531,6 +3548,28 @@ class UserStorySubmissionTests(TestCase):
3531
3548
  story = UserStory.objects.get()
3532
3549
  self.assertEqual(story.language_code, "es")
3533
3550
 
3551
+ def test_submission_prefers_original_referer(self):
3552
+ self.client.get(
3553
+ reverse("pages:index"),
3554
+ HTTP_REFERER="https://ads.example/original",
3555
+ )
3556
+ response = self.client.post(
3557
+ self.url,
3558
+ {
3559
+ "rating": 3,
3560
+ "comments": "Works well",
3561
+ "path": "/wizard/step-2/",
3562
+ "name": "visitor@example.com",
3563
+ "take_screenshot": "0",
3564
+ },
3565
+ HTTP_REFERER="http://testserver/wizard/step-2/",
3566
+ HTTP_USER_AGENT="FeedbackBot/2.0",
3567
+ )
3568
+
3569
+ self.assertEqual(response.status_code, 200)
3570
+ story = UserStory.objects.get()
3571
+ self.assertEqual(story.referer, "https://ads.example/original")
3572
+
3534
3573
  def test_superuser_submission_creates_triage_todo(self):
3535
3574
  Todo.objects.all().delete()
3536
3575
  superuser = get_user_model().objects.create_superuser(
@@ -3591,6 +3630,7 @@ class UserStorySubmissionTests(TestCase):
3591
3630
  screenshot_file,
3592
3631
  method="USER_STORY",
3593
3632
  user=self.user,
3633
+ link_duplicates=True,
3594
3634
  )
3595
3635
 
3596
3636
  def test_anonymous_submission_uses_provided_email(self):
pages/utils.py CHANGED
@@ -1,6 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from urllib.parse import urlsplit
4
+
5
+ from django.core.exceptions import DisallowedHost
6
+ from django.http.request import split_domain_port
1
7
  from django.urls import path as django_path
2
8
 
3
9
 
10
+ ORIGINAL_REFERER_SESSION_KEY = "pages:original_referer"
11
+
12
+
4
13
  def landing(label=None):
5
14
  """Decorator to mark a view as a landing page."""
6
15
 
@@ -12,6 +21,67 @@ def landing(label=None):
12
21
  return decorator
13
22
 
14
23
 
24
+ def cache_original_referer(request) -> None:
25
+ """Persist the first external referer observed for the session."""
26
+
27
+ session = getattr(request, "session", None)
28
+ if not hasattr(session, "get"):
29
+ return
30
+
31
+ original = session.get(ORIGINAL_REFERER_SESSION_KEY)
32
+ if original:
33
+ request.original_referer = original
34
+ return
35
+
36
+ referer = (request.META.get("HTTP_REFERER") or "").strip()
37
+ if not referer:
38
+ return
39
+
40
+ try:
41
+ parsed = urlsplit(referer)
42
+ except ValueError:
43
+ return
44
+
45
+ if parsed.scheme not in {"http", "https"} or not parsed.netloc:
46
+ return
47
+
48
+ try:
49
+ host = request.get_host()
50
+ except DisallowedHost:
51
+ host = ""
52
+
53
+ referer_host, _ = split_domain_port(parsed.netloc)
54
+ request_host, _ = split_domain_port(host)
55
+
56
+ if referer_host and request_host:
57
+ if referer_host.lower() == request_host.lower():
58
+ return
59
+
60
+ referer_value = referer[:1000]
61
+ session[ORIGINAL_REFERER_SESSION_KEY] = referer_value
62
+ request.original_referer = referer_value
63
+
64
+
65
+ def get_original_referer(request) -> str:
66
+ """Return the original external referer recorded for the session."""
67
+
68
+ if hasattr(request, "original_referer"):
69
+ return request.original_referer or ""
70
+
71
+ session = getattr(request, "session", None)
72
+ if hasattr(session, "get"):
73
+ referer = session.get(ORIGINAL_REFERER_SESSION_KEY)
74
+ if referer:
75
+ request.original_referer = referer
76
+ return referer
77
+
78
+ referer = (request.META.get("HTTP_REFERER") or "").strip()
79
+ if referer:
80
+ referer = referer[:1000]
81
+ request.original_referer = referer
82
+ return referer
83
+
84
+
15
85
  def landing_leads_supported() -> bool:
16
86
  """Return ``True`` when the local node supports landing lead tracking."""
17
87
 
pages/views.py CHANGED
@@ -67,6 +67,7 @@ from core.models import (
67
67
  Todo,
68
68
  )
69
69
  from ocpp.models import Charger
70
+ from .utils import get_original_referer
70
71
 
71
72
  try: # pragma: no cover - optional dependency guard
72
73
  from graphviz import Digraph
@@ -1114,7 +1115,7 @@ def request_invite(request):
1114
1115
  comment=comment,
1115
1116
  user=request.user if request.user.is_authenticated else None,
1116
1117
  path=request.path,
1117
- referer=request.META.get("HTTP_REFERER", ""),
1118
+ referer=get_original_referer(request),
1118
1119
  user_agent=request.META.get("HTTP_USER_AGENT", ""),
1119
1120
  ip_address=ip_address,
1120
1121
  mac_address=mac_address or "",
@@ -1592,7 +1593,7 @@ def submit_user_story(request):
1592
1593
  if not story.name:
1593
1594
  story.name = str(_("Anonymous"))[:40]
1594
1595
  story.path = (story.path or request.get_full_path())[:500]
1595
- story.referer = request.META.get("HTTP_REFERER", "")
1596
+ story.referer = get_original_referer(request)
1596
1597
  story.user_agent = request.META.get("HTTP_USER_AGENT", "")
1597
1598
  story.ip_address = client_ip or None
1598
1599
  story.is_user_data = True
@@ -1664,6 +1665,7 @@ def submit_user_story(request):
1664
1665
  screenshot_path,
1665
1666
  method="USER_STORY",
1666
1667
  user=story.user if story.user_id else None,
1668
+ link_duplicates=True,
1667
1669
  )
1668
1670
  except Exception: # pragma: no cover - best effort persistence
1669
1671
  logger.exception(