arthexis 0.1.19__py3-none-any.whl → 0.1.21__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.
@@ -2,7 +2,6 @@ from utils.sites import get_site
2
2
  from django.urls import Resolver404, resolve
3
3
  from django.conf import settings
4
4
  from pathlib import Path
5
- from types import SimpleNamespace
6
5
  from nodes.models import Node
7
6
  from core.models import Reference
8
7
  from core.reference_utils import filter_visible_references
@@ -11,7 +10,8 @@ from .models import Module
11
10
  _FAVICON_DIR = Path(settings.BASE_DIR) / "pages" / "fixtures" / "data"
12
11
  _FAVICON_FILENAMES = {
13
12
  "default": "favicon.txt",
14
- "Constellation": "favicon_constellation.txt",
13
+ "Watchtower": "favicon_watchtower.txt",
14
+ "Constellation": "favicon_watchtower.txt",
15
15
  "Control": "favicon_control.txt",
16
16
  "Satellite": "favicon_satellite.txt",
17
17
  }
@@ -48,7 +48,6 @@ def nav_links(request):
48
48
  modules = []
49
49
 
50
50
  valid_modules = []
51
- datasette_enabled = False
52
51
  current_module = None
53
52
  user = getattr(request, "user", None)
54
53
  user_is_authenticated = getattr(user, "is_authenticated", False)
@@ -72,19 +71,24 @@ def nav_links(request):
72
71
  required_groups = getattr(
73
72
  view_func, "required_security_groups", frozenset()
74
73
  )
74
+ blocked_reason = None
75
75
  if required_groups:
76
76
  requires_login = True
77
- setattr(landing, "requires_login", True)
78
77
  if not user_is_authenticated:
79
- continue
80
- if not user_is_superuser and not (
78
+ blocked_reason = "login"
79
+ elif not user_is_superuser and not (
81
80
  user_group_names & set(required_groups)
82
81
  ):
83
- continue
82
+ blocked_reason = "permission"
84
83
  elif requires_login and not user_is_authenticated:
85
- setattr(landing, "requires_login", True)
86
- if staff_only and not request.user.is_staff:
87
- continue
84
+ blocked_reason = "login"
85
+
86
+ if staff_only and not getattr(request.user, "is_staff", False):
87
+ if blocked_reason != "login":
88
+ blocked_reason = "permission"
89
+
90
+ landing.nav_is_locked = bool(blocked_reason)
91
+ landing.nav_lock_reason = blocked_reason
88
92
  landings.append(landing)
89
93
  if landings:
90
94
  normalized_module_path = module.path.rstrip("/") or "/"
@@ -100,7 +104,7 @@ def nav_links(request):
100
104
  landings = [landings[0]]
101
105
  app_name = getattr(module.application, "name", "").lower()
102
106
  if app_name == "awg":
103
- module.menu = "Calculate"
107
+ module.menu = "Calculators"
104
108
  elif module.path.rstrip("/").lower() == "/man":
105
109
  module.menu = "Manual"
106
110
  module.enabled_landings = landings
@@ -111,15 +115,6 @@ def nav_links(request):
111
115
  ):
112
116
  current_module = module
113
117
 
114
- datasette_lock = Path(settings.BASE_DIR) / "locks" / "datasette.lck"
115
- if datasette_lock.exists():
116
- datasette_enabled = True
117
- datasette_module = SimpleNamespace(
118
- menu_label="Data",
119
- path="/data/",
120
- enabled_landings=[SimpleNamespace(path="/data/", label="Datasette")],
121
- )
122
- valid_modules.append(datasette_module)
123
118
 
124
119
  valid_modules.sort(key=lambda m: m.menu_label.lower())
125
120
 
@@ -153,5 +148,4 @@ def nav_links(request):
153
148
  "nav_modules": valid_modules,
154
149
  "favicon_url": favicon_url,
155
150
  "header_references": header_references,
156
- "datasette_enabled": datasette_enabled,
157
151
  }
pages/defaults.py CHANGED
@@ -7,7 +7,7 @@ DEFAULT_APPLICATION_DESCRIPTIONS: Dict[str, str] = {
7
7
  "awg": "Power, Energy and Cost calculations.",
8
8
  "core": "Support for Business Processes and monetization.",
9
9
  "ocpp": "Compatibility with Standards and Good Practices.",
10
- "nodes": "System and Node-level operations,",
10
+ "nodes": "System and Node-level operations.",
11
11
  "pages": "User QA, Continuity Design and Chaos Testing.",
12
12
  "teams": "Identity, Entitlements and Access Controls.",
13
13
  }
pages/module_defaults.py CHANGED
@@ -10,15 +10,15 @@ LandingDefinition = tuple[str, str]
10
10
 
11
11
 
12
12
  ROLE_MODULE_DEFAULTS: Mapping[str, tuple[ModuleDefinition, ...]] = {
13
- "Constellation": (
13
+ "Watchtower": (
14
14
  {
15
15
  "application": "ocpp",
16
16
  "path": "/ocpp/",
17
17
  "menu": "Chargers",
18
18
  "landings": (
19
- ("/ocpp/", "CPMS Online Dashboard"),
20
- ("/ocpp/simulator/", "Charge Point Simulator"),
21
- ("/ocpp/rfid/", "RFID Tag Validator"),
19
+ ("/ocpp/cpms/dashboard/", "CPMS Online Dashboard"),
20
+ ("/ocpp/evcs/simulator/", "Charge Point Simulator"),
21
+ ("/ocpp/rfid/validator/", "RFID Tag Validator"),
22
22
  ),
23
23
  },
24
24
  {
@@ -26,7 +26,7 @@ ROLE_MODULE_DEFAULTS: Mapping[str, tuple[ModuleDefinition, ...]] = {
26
26
  "path": "/awg/",
27
27
  "menu": "",
28
28
  "landings": (
29
- ("/awg/", "AWG Calculator"),
29
+ ("/awg/", "AWG Cable Calculator"),
30
30
  ("/awg/energy-tariff/", "Energy Tariff Calculator"),
31
31
  ),
32
32
  },
pages/tests.py CHANGED
@@ -3,6 +3,7 @@ import os
3
3
  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
4
4
 
5
5
  import django
6
+ import pytest
6
7
 
7
8
  django.setup()
8
9
 
@@ -508,6 +509,7 @@ class InvitationTests(TestCase):
508
509
  lead = InviteLead.objects.get()
509
510
  self.assertEqual(lead.mac_address, "aa:bb:cc:dd:ee:ff")
510
511
 
512
+ @pytest.mark.feature("ap-router")
511
513
  @patch("pages.views.public_wifi.grant_public_access")
512
514
  @patch(
513
515
  "pages.views.public_wifi.resolve_mac_address",
@@ -1360,6 +1362,7 @@ class SiteAdminRegisterCurrentTests(TestCase):
1360
1362
  self.assertEqual(site.name, "")
1361
1363
 
1362
1364
 
1365
+ @pytest.mark.feature("screenshot-poll")
1363
1366
  class SiteAdminScreenshotTests(TestCase):
1364
1367
  def setUp(self):
1365
1368
  self.client = Client()
@@ -1479,17 +1482,17 @@ class NavAppsTests(TestCase):
1479
1482
  )
1480
1483
  app = Application.objects.create(name="Readme")
1481
1484
  Module.objects.create(
1482
- node_role=role, application=app, path="/", is_default=True, menu="Cookbook"
1485
+ node_role=role, application=app, path="/", is_default=True, menu="Cookbooks"
1483
1486
  )
1484
1487
 
1485
1488
  def test_nav_pill_renders(self):
1486
1489
  resp = self.client.get(reverse("pages:index"))
1487
- self.assertContains(resp, "COOKBOOK")
1490
+ self.assertContains(resp, "COOKBOOKS")
1488
1491
  self.assertContains(resp, "badge rounded-pill")
1489
1492
 
1490
1493
  def test_nav_pill_renders_with_port(self):
1491
1494
  resp = self.client.get(reverse("pages:index"), HTTP_HOST="127.0.0.1:8000")
1492
- self.assertContains(resp, "COOKBOOK")
1495
+ self.assertContains(resp, "COOKBOOKS")
1493
1496
 
1494
1497
  def test_nav_pill_uses_menu_field(self):
1495
1498
  site_app = Module.objects.get()
@@ -1497,7 +1500,7 @@ class NavAppsTests(TestCase):
1497
1500
  site_app.save()
1498
1501
  resp = self.client.get(reverse("pages:index"))
1499
1502
  self.assertContains(resp, 'badge rounded-pill text-bg-secondary">DOCS')
1500
- self.assertNotContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOK')
1503
+ self.assertNotContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOKS')
1501
1504
 
1502
1505
  def test_app_without_root_url_excluded(self):
1503
1506
  role = NodeRole.objects.get(name="Terminal")
@@ -1562,20 +1565,22 @@ class RoleLandingRedirectTests(TestCase):
1562
1565
 
1563
1566
  def test_satellite_redirects_to_dashboard(self):
1564
1567
  target = self._configure_role_landing(
1565
- "Satellite", "/ocpp/", "CPMS Online Dashboard"
1568
+ "Satellite", "/ocpp/cpms/dashboard/", "CPMS Online Dashboard"
1566
1569
  )
1567
1570
  resp = self.client.get(reverse("pages:index"))
1568
1571
  self.assertRedirects(resp, target, fetch_redirect_response=False)
1569
1572
 
1570
1573
  def test_control_redirects_to_rfid(self):
1571
1574
  target = self._configure_role_landing(
1572
- "Control", "/ocpp/rfid/", "RFID Tag Validator"
1575
+ "Control", "/ocpp/rfid/validator/", "RFID Tag Validator"
1573
1576
  )
1574
1577
  resp = self.client.get(reverse("pages:index"))
1575
1578
  self.assertRedirects(resp, target, fetch_redirect_response=False)
1576
1579
 
1577
1580
  def test_security_group_redirect_takes_priority(self):
1578
- self._configure_role_landing("Control", "/ocpp/rfid/", "RFID Tag Validator")
1581
+ self._configure_role_landing(
1582
+ "Control", "/ocpp/rfid/validator/", "RFID Tag Validator"
1583
+ )
1579
1584
  role = self.node.role
1580
1585
  group = SecurityGroup.objects.create(name="Operators")
1581
1586
  group_landing = self._ensure_landing(role, "/ocpp/group/", "Group Landing")
@@ -1592,7 +1597,9 @@ class RoleLandingRedirectTests(TestCase):
1592
1597
  )
1593
1598
 
1594
1599
  def test_user_redirect_overrides_group_with_higher_priority(self):
1595
- self._configure_role_landing("Control", "/ocpp/rfid/", "RFID Tag Validator")
1600
+ self._configure_role_landing(
1601
+ "Control", "/ocpp/rfid/validator/", "RFID Tag Validator"
1602
+ )
1596
1603
  role = self.node.role
1597
1604
  group = SecurityGroup.objects.create(name="Operators")
1598
1605
  group_landing = self._ensure_landing(role, "/ocpp/group/", "Group Landing")
@@ -1614,10 +1621,10 @@ class RoleLandingRedirectTests(TestCase):
1614
1621
  )
1615
1622
 
1616
1623
 
1617
- class ConstellationNavTests(TestCase):
1624
+ class WatchtowerNavTests(TestCase):
1618
1625
  def setUp(self):
1619
1626
  self.client = Client()
1620
- role, _ = NodeRole.objects.get_or_create(name="Constellation")
1627
+ role, _ = NodeRole.objects.get_or_create(name="Watchtower")
1621
1628
  Node.objects.update_or_create(
1622
1629
  mac_address=Node.get_current_mac(),
1623
1630
  defaults={
@@ -1627,38 +1634,56 @@ class ConstellationNavTests(TestCase):
1627
1634
  },
1628
1635
  )
1629
1636
  Site.objects.update_or_create(
1630
- id=1, defaults={"domain": "testserver", "name": ""}
1637
+ id=1, defaults={"domain": "arthexis.com", "name": "Arthexis"}
1631
1638
  )
1632
1639
  fixtures = [
1633
1640
  Path(
1634
1641
  settings.BASE_DIR,
1635
1642
  "pages",
1636
1643
  "fixtures",
1637
- "constellation__application_ocpp.json",
1644
+ "default__application_pages.json",
1645
+ ),
1646
+ Path(
1647
+ settings.BASE_DIR,
1648
+ "pages",
1649
+ "fixtures",
1650
+ "watchtower__application_ocpp.json",
1651
+ ),
1652
+ Path(
1653
+ settings.BASE_DIR,
1654
+ "pages",
1655
+ "fixtures",
1656
+ "watchtower__module_ocpp.json",
1638
1657
  ),
1639
1658
  Path(
1640
1659
  settings.BASE_DIR,
1641
1660
  "pages",
1642
1661
  "fixtures",
1643
- "constellation__module_ocpp.json",
1662
+ "watchtower__landing_ocpp_dashboard.json",
1644
1663
  ),
1645
1664
  Path(
1646
1665
  settings.BASE_DIR,
1647
1666
  "pages",
1648
1667
  "fixtures",
1649
- "constellation__landing_ocpp_dashboard.json",
1668
+ "watchtower__landing_ocpp_cp_simulator.json",
1650
1669
  ),
1651
1670
  Path(
1652
1671
  settings.BASE_DIR,
1653
1672
  "pages",
1654
1673
  "fixtures",
1655
- "constellation__landing_ocpp_cp_simulator.json",
1674
+ "watchtower__landing_ocpp_rfid.json",
1656
1675
  ),
1657
1676
  Path(
1658
1677
  settings.BASE_DIR,
1659
1678
  "pages",
1660
1679
  "fixtures",
1661
- "constellation__landing_ocpp_rfid.json",
1680
+ "watchtower__module_readme.json",
1681
+ ),
1682
+ Path(
1683
+ settings.BASE_DIR,
1684
+ "pages",
1685
+ "fixtures",
1686
+ "watchtower__landing_readme.json",
1662
1687
  ),
1663
1688
  ]
1664
1689
  call_command("loaddata", *map(str, fixtures))
@@ -1671,13 +1696,13 @@ class ConstellationNavTests(TestCase):
1671
1696
  self.assertNotIn("RFID", nav_labels)
1672
1697
  self.assertTrue(
1673
1698
  Module.objects.filter(
1674
- path="/ocpp/", node_role__name="Constellation"
1699
+ path="/ocpp/", node_role__name="Watchtower"
1675
1700
  ).exists()
1676
1701
  )
1677
1702
  self.assertFalse(
1678
1703
  Module.objects.filter(
1679
1704
  path="/ocpp/rfid/",
1680
- node_role__name="Constellation",
1705
+ node_role__name="Watchtower",
1681
1706
  is_deleted=False,
1682
1707
  ).exists()
1683
1708
  )
@@ -1689,9 +1714,16 @@ class ConstellationNavTests(TestCase):
1689
1714
  landing_labels = [landing.label for landing in ocpp_module.enabled_landings]
1690
1715
  self.assertIn("RFID Tag Validator", landing_labels)
1691
1716
 
1717
+ @override_settings(ALLOWED_HOSTS=["testserver", "arthexis.com"])
1718
+ def test_cookbooks_pill_visible_for_arthexis(self):
1719
+ resp = self.client.get(
1720
+ reverse("pages:index"), HTTP_HOST="arthexis.com"
1721
+ )
1722
+ self.assertContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOKS')
1723
+
1692
1724
  def test_ocpp_dashboard_visible(self):
1693
1725
  resp = self.client.get(reverse("pages:index"))
1694
- self.assertContains(resp, 'href="/ocpp/"')
1726
+ self.assertContains(resp, 'href="/ocpp/cpms/dashboard/"')
1695
1727
 
1696
1728
 
1697
1729
  class ReleaseModuleNavTests(TestCase):
@@ -1833,7 +1865,7 @@ class ControlNavTests(TestCase):
1833
1865
  self.client.force_login(user)
1834
1866
  resp = self.client.get(reverse("pages:index"))
1835
1867
  self.assertEqual(resp.status_code, 200)
1836
- self.assertContains(resp, 'href="/ocpp/"')
1868
+ self.assertContains(resp, 'href="/ocpp/cpms/dashboard/"')
1837
1869
  self.assertContains(
1838
1870
  resp, 'badge rounded-pill text-bg-secondary">CHARGERS'
1839
1871
  )
@@ -1865,10 +1897,27 @@ class ControlNavTests(TestCase):
1865
1897
  self.assertFalse(resp.context["header_references"])
1866
1898
  self.assertNotContains(resp, "https://example.com/hidden")
1867
1899
 
1900
+ def test_header_link_hidden_when_only_site_matches(self):
1901
+ terminal_role, _ = NodeRole.objects.get_or_create(name="Terminal")
1902
+ site = Site.objects.get(domain="testserver")
1903
+ reference = Reference.objects.create(
1904
+ alt_text="Restricted",
1905
+ value="https://example.com/restricted",
1906
+ show_in_header=True,
1907
+ )
1908
+ reference.roles.add(terminal_role)
1909
+ reference.sites.add(site)
1910
+
1911
+ resp = self.client.get(reverse("pages:index"))
1912
+
1913
+ self.assertIn("header_references", resp.context)
1914
+ self.assertFalse(resp.context["header_references"])
1915
+ self.assertNotContains(resp, "https://example.com/restricted")
1916
+
1868
1917
  def test_readme_pill_visible(self):
1869
1918
  resp = self.client.get(reverse("pages:readme"))
1870
1919
  self.assertContains(resp, 'href="/read/"')
1871
- self.assertContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOK')
1920
+ self.assertContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOKS')
1872
1921
 
1873
1922
  def test_cookbook_pill_has_no_dropdown(self):
1874
1923
  module = Module.objects.get(node_role__name="Control", path="/read/")
@@ -1883,7 +1932,7 @@ class ControlNavTests(TestCase):
1883
1932
 
1884
1933
  self.assertContains(
1885
1934
  resp,
1886
- '<a class="nav-link" href="/read/"><span class="badge rounded-pill text-bg-secondary">COOKBOOK</span></a>',
1935
+ '<a class="nav-link" href="/read/"><span class="badge rounded-pill text-bg-secondary">COOKBOOKS</span></a>',
1887
1936
  html=True,
1888
1937
  )
1889
1938
  self.assertNotContains(resp, 'dropdown-item" href="/man/"')
@@ -1990,7 +2039,7 @@ class SatelliteNavTests(TestCase):
1990
2039
  def test_readme_pill_visible(self):
1991
2040
  resp = self.client.get(reverse("pages:readme"))
1992
2041
  self.assertContains(resp, 'href="/read/"')
1993
- self.assertContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOK')
2042
+ self.assertContains(resp, 'badge rounded-pill text-bg-secondary">COOKBOOKS')
1994
2043
 
1995
2044
 
1996
2045
  class PowerNavTests(TestCase):
@@ -2025,9 +2074,9 @@ class PowerNavTests(TestCase):
2025
2074
  power_module = module
2026
2075
  break
2027
2076
  self.assertIsNotNone(power_module)
2028
- self.assertEqual(power_module.menu_label.upper(), "CALCULATE")
2077
+ self.assertEqual(power_module.menu_label.upper(), "CALCULATORS")
2029
2078
  landing_labels = {landing.label for landing in power_module.enabled_landings}
2030
- self.assertIn("AWG Calculator", landing_labels)
2079
+ self.assertIn("AWG Cable Calculator", landing_labels)
2031
2080
 
2032
2081
  def test_manual_pill_label(self):
2033
2082
  resp = self.client.get(reverse("pages:index"))
@@ -2051,9 +2100,26 @@ class PowerNavTests(TestCase):
2051
2100
  break
2052
2101
  self.assertIsNotNone(power_module)
2053
2102
  landing_labels = {landing.label for landing in power_module.enabled_landings}
2054
- self.assertIn("AWG Calculator", landing_labels)
2103
+ self.assertIn("AWG Cable Calculator", landing_labels)
2055
2104
  self.assertIn("Energy Tariff Calculator", landing_labels)
2056
2105
 
2106
+ def test_locked_landing_shows_lock_icon(self):
2107
+ resp = self.client.get(reverse("pages:index"))
2108
+ html = resp.content.decode()
2109
+ energy_index = html.find("Energy Tariff Calculator")
2110
+ self.assertGreaterEqual(energy_index, 0)
2111
+ icon_index = html.find("dropdown-lock-icon", energy_index, energy_index + 300)
2112
+ self.assertGreaterEqual(icon_index, 0)
2113
+
2114
+ def test_lock_icon_disappears_after_login(self):
2115
+ self.client.force_login(self.user)
2116
+ resp = self.client.get(reverse("pages:index"))
2117
+ html = resp.content.decode()
2118
+ energy_index = html.find("Energy Tariff Calculator")
2119
+ self.assertGreaterEqual(energy_index, 0)
2120
+ icon_index = html.find("dropdown-lock-icon", energy_index, energy_index + 300)
2121
+ self.assertEqual(icon_index, -1)
2122
+
2057
2123
 
2058
2124
  class StaffNavVisibilityTests(TestCase):
2059
2125
  def setUp(self):
@@ -2075,12 +2141,12 @@ class StaffNavVisibilityTests(TestCase):
2075
2141
  def test_nonstaff_pill_hidden(self):
2076
2142
  self.client.login(username="user", password="pw")
2077
2143
  resp = self.client.get(reverse("pages:index"))
2078
- self.assertContains(resp, 'href="/ocpp/"')
2144
+ self.assertContains(resp, 'href="/ocpp/cpms/dashboard/"')
2079
2145
 
2080
2146
  def test_staff_sees_pill(self):
2081
2147
  self.client.login(username="staff", password="pw")
2082
2148
  resp = self.client.get(reverse("pages:index"))
2083
- self.assertContains(resp, 'href="/ocpp/"')
2149
+ self.assertContains(resp, 'href="/ocpp/cpms/dashboard/"')
2084
2150
 
2085
2151
 
2086
2152
  class ModuleAdminReloadActionTests(TestCase):
@@ -2093,7 +2159,7 @@ class ModuleAdminReloadActionTests(TestCase):
2093
2159
  password="pw",
2094
2160
  )
2095
2161
  self.client.force_login(self.superuser)
2096
- self.role, _ = NodeRole.objects.get_or_create(name="Constellation")
2162
+ self.role, _ = NodeRole.objects.get_or_create(name="Watchtower")
2097
2163
  Application.objects.get_or_create(name="ocpp")
2098
2164
  Application.objects.get_or_create(name="awg")
2099
2165
  Site.objects.update_or_create(
@@ -2131,7 +2197,11 @@ class ModuleAdminReloadActionTests(TestCase):
2131
2197
  )
2132
2198
  self.assertSetEqual(
2133
2199
  charger_landings,
2134
- {"/ocpp/", "/ocpp/simulator/", "/ocpp/rfid/"},
2200
+ {
2201
+ "/ocpp/cpms/dashboard/",
2202
+ "/ocpp/evcs/simulator/",
2203
+ "/ocpp/rfid/validator/",
2204
+ },
2135
2205
  )
2136
2206
 
2137
2207
  calculator_landings = set(
@@ -2331,12 +2401,12 @@ class LandingCreationTests(TestCase):
2331
2401
 
2332
2402
 
2333
2403
  class LandingFixtureTests(TestCase):
2334
- def test_constellation_fixture_loads_without_duplicates(self):
2404
+ def test_watchtower_fixture_loads_without_duplicates(self):
2335
2405
  from glob import glob
2336
2406
 
2337
- NodeRole.objects.get_or_create(name="Constellation")
2407
+ NodeRole.objects.get_or_create(name="Watchtower")
2338
2408
  fixtures = glob(
2339
- str(Path(settings.BASE_DIR, "pages", "fixtures", "constellation__*.json"))
2409
+ str(Path(settings.BASE_DIR, "pages", "fixtures", "watchtower__*.json"))
2340
2410
  )
2341
2411
  fixtures = sorted(
2342
2412
  fixtures,
@@ -2346,9 +2416,11 @@ class LandingFixtureTests(TestCase):
2346
2416
  )
2347
2417
  call_command("loaddata", *fixtures)
2348
2418
  call_command("loaddata", *fixtures)
2349
- module = Module.objects.get(path="/ocpp/", node_role__name="Constellation")
2419
+ module = Module.objects.get(path="/ocpp/", node_role__name="Watchtower")
2350
2420
  module.create_landings()
2351
- self.assertEqual(module.landings.filter(path="/ocpp/rfid/").count(), 1)
2421
+ self.assertEqual(
2422
+ module.landings.filter(path="/ocpp/rfid/validator/").count(), 1
2423
+ )
2352
2424
 
2353
2425
 
2354
2426
  class AllowedHostSubnetTests(TestCase):
@@ -2501,9 +2573,9 @@ class FaviconTests(TestCase):
2501
2573
  )
2502
2574
  self.assertContains(resp, b64)
2503
2575
 
2504
- def test_constellation_nodes_use_goldenrod_favicon(self):
2576
+ def test_watchtower_nodes_use_goldenrod_favicon(self):
2505
2577
  with override_settings(MEDIA_ROOT=self.tmpdir):
2506
- role, _ = NodeRole.objects.get_or_create(name="Constellation")
2578
+ role, _ = NodeRole.objects.get_or_create(name="Watchtower")
2507
2579
  Node.objects.update_or_create(
2508
2580
  mac_address=Node.get_current_mac(),
2509
2581
  defaults={
@@ -2518,7 +2590,7 @@ class FaviconTests(TestCase):
2518
2590
  resp = self.client.get(reverse("pages:index"))
2519
2591
  b64 = (
2520
2592
  Path(settings.BASE_DIR)
2521
- .joinpath("pages", "fixtures", "data", "favicon_constellation.txt")
2593
+ .joinpath("pages", "fixtures", "data", "favicon_watchtower.txt")
2522
2594
  .read_text()
2523
2595
  .strip()
2524
2596
  )
@@ -3149,47 +3221,6 @@ class AdminModelGraphViewTests(TestCase):
3149
3221
  self.assertEqual(kwargs.get("format"), "pdf")
3150
3222
 
3151
3223
 
3152
- class DatasetteTests(TestCase):
3153
- def setUp(self):
3154
- self.client = Client()
3155
- User = get_user_model()
3156
- self.user = User.objects.create_user(username="ds", password="pwd")
3157
- Site.objects.update_or_create(id=1, defaults={"name": "Terminal"})
3158
-
3159
- def test_datasette_auth_endpoint(self):
3160
- resp = self.client.get(reverse("pages:datasette-auth"))
3161
- self.assertEqual(resp.status_code, 401)
3162
- self.client.force_login(self.user)
3163
- resp = self.client.get(reverse("pages:datasette-auth"))
3164
- self.assertEqual(resp.status_code, 200)
3165
-
3166
- def test_navbar_includes_datasette_when_enabled(self):
3167
- lock_dir = Path(settings.BASE_DIR) / "locks"
3168
- lock_dir.mkdir(exist_ok=True)
3169
- lock_file = lock_dir / "datasette.lck"
3170
- try:
3171
- lock_file.touch()
3172
- resp = self.client.get(reverse("pages:index"))
3173
- self.assertContains(resp, 'href="/data/"')
3174
- finally:
3175
- lock_file.unlink(missing_ok=True)
3176
-
3177
- def test_admin_home_includes_datasette_button_when_enabled(self):
3178
- lock_dir = Path(settings.BASE_DIR) / "locks"
3179
- lock_dir.mkdir(exist_ok=True)
3180
- lock_file = lock_dir / "datasette.lck"
3181
- try:
3182
- lock_file.touch()
3183
- self.user.is_staff = True
3184
- self.user.is_superuser = True
3185
- self.user.save()
3186
- self.client.force_login(self.user)
3187
- resp = self.client.get(reverse("admin:index"))
3188
- self.assertContains(resp, 'href="/data/"')
3189
- self.assertContains(resp, ">Datasette<")
3190
- finally:
3191
- lock_file.unlink(missing_ok=True)
3192
-
3193
3224
 
3194
3225
  class UserStorySubmissionTests(TestCase):
3195
3226
  def setUp(self):
pages/urls.py CHANGED
@@ -6,6 +6,7 @@ app_name = "pages"
6
6
 
7
7
  urlpatterns = [
8
8
  path("", views.index, name="index"),
9
+ path("read/<path:doc>/edit/", views.readme_edit, name="readme-edit"),
9
10
  path("read/", views.readme, name="readme"),
10
11
  path("read/<path:doc>", views.readme, name="readme-document"),
11
12
  path("sitemap.xml", views.sitemap, name="pages-sitemap"),
@@ -20,7 +21,6 @@ urlpatterns = [
20
21
  views.invitation_login,
21
22
  name="invitation-login",
22
23
  ),
23
- path("datasette-auth/", views.datasette_auth, name="datasette-auth"),
24
24
  path("man/", views.manual_list, name="manual-list"),
25
25
  path("man/<slug:slug>/", views.manual_detail, name="manual-detail"),
26
26
  path("man/<slug:slug>/pdf/", views.manual_pdf, name="manual-pdf"),