Skip to content

Commit 8d81859

Browse files
committed
feat(networks): make navbar community links network-aware
On a network host (up.profile.hcommons.org) or network path prefix, the community nav links now point at the network's own Commons domain: activity, groups and sites become up.hcommons.org/activity/ etc., built as {network_slug}.{NAV_DEFAULT_DOMAIN} so each environment maps to its own Commons domain (stemedplus.hcommons-dev.org on dev). The network-aware set is an explicit key allowlist — news feed, groups, sites — rather than a hostname match, because KC Organizations lives on the default domain too but must stay fixed. Works, Help & Support, KC Organizations, About and the Team Blog never follow the network (Works remains environment-specific via the NAV_WORKS_URL env var). The network context takes precedence over the referer-derived session domain, whose behaviour is otherwise unchanged.
1 parent 980c0cd commit 8d81859

2 files changed

Lines changed: 148 additions & 1 deletion

File tree

knowledge_commons_profiles/newprofile/context_processors.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ def _rewrite_domain(url, default_domain, target_domain):
2424
return urlunparse(parsed._replace(netloc=new_netloc))
2525

2626

27+
# Nav links that follow the network context (the community surfaces on
28+
# the network's own Commons domain). Everything else — Works, Help &
29+
# Support, KC Organizations, About, Team Blog — stays fixed regardless
30+
# of network. KC Organizations lives ON the default domain, so this
31+
# must be an explicit key allowlist rather than a hostname match.
32+
NETWORK_AWARE_NAV_KEYS = frozenset(
33+
{"NAV_NEWS_FEED_URL", "NAV_GROUPS_URL", "NAV_SITES_URL"}
34+
)
35+
36+
2737
def nav_links(request):
2838
urls = {
2939
"NAV_NEWS_FEED_URL": settings.NAV_NEWS_FEED_URL,
@@ -36,6 +46,23 @@ def nav_links(request):
3646
"NAV_BLOG_URL": settings.NAV_BLOG_URL,
3747
}
3848

49+
default_domain = getattr(settings, "NAV_DEFAULT_DOMAIN", "hcommons.org")
50+
51+
# a network host or path prefix (NetworkSubdomainMiddleware) pins
52+
# the community links to that network's Commons domain and takes
53+
# precedence over the referer-derived session domain below
54+
network_slug = getattr(request, "network_slug", None)
55+
if network_slug:
56+
network_domain = f"{network_slug}.{default_domain}"
57+
return {
58+
key: (
59+
_rewrite_domain(url, default_domain, network_domain)
60+
if key in NETWORK_AWARE_NAV_KEYS
61+
else url
62+
)
63+
for key, url in urls.items()
64+
}
65+
3966
session = getattr(request, "session", {})
4067
network_domain = session.get("nav_network_domain")
4168
if not network_domain:
@@ -48,7 +75,6 @@ def nav_links(request):
4875
session.pop("nav_network_domain_ts", None)
4976
return urls
5077

51-
default_domain = getattr(settings, "NAV_DEFAULT_DOMAIN", "hcommons.org")
5278
return {
5379
key: _rewrite_domain(url, default_domain, network_domain)
5480
for key, url in urls.items()
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
"""
2+
Tests for network-aware navbar links.
3+
4+
On a network host (up.profile.hcommons.org) or network path prefix,
5+
the community links (news feed/activity, groups, sites) point at the
6+
network's own Commons domain (up.hcommons.org). Works, Help & Support,
7+
KC Organizations, About and the Team Blog never follow the network —
8+
including KC Organizations, which lives on the default domain and must
9+
be excluded by key, not by hostname.
10+
"""
11+
12+
import json
13+
import time
14+
15+
from django.test import RequestFactory
16+
from django.test import TestCase
17+
from django.test import override_settings
18+
19+
from knowledge_commons_profiles.newprofile.context_processors import nav_links
20+
from knowledge_commons_profiles.newprofile.models import Profile
21+
22+
NAV_SETTINGS = {
23+
"NAV_NEWS_FEED_URL": "https://hcommons.org/activity/",
24+
"NAV_GROUPS_URL": "https://hcommons.org/groups/",
25+
"NAV_SITES_URL": "https://hcommons.org/sites/",
26+
"NAV_WORKS_URL": "https://works.hcommons.org/",
27+
"NAV_SUPPORT_URL": "https://support.hcommons.org/",
28+
"NAV_ORGANIZATIONS_URL": "https://hcommons.org/societies/",
29+
"NAV_ABOUT_URL": "https://sustaining.hcommons.org/",
30+
"NAV_BLOG_URL": "https://team.hcommons.org/",
31+
"NAV_DEFAULT_DOMAIN": "hcommons.org",
32+
}
33+
34+
35+
@override_settings(**NAV_SETTINGS)
36+
class NetworkAwareNavLinksTests(TestCase):
37+
def _nav_for_network(self, slug, session=None):
38+
request = RequestFactory().get("/members/")
39+
request.network_slug = slug
40+
request.network = slug
41+
request.session = session if session is not None else {}
42+
return nav_links(request)
43+
44+
def test_community_links_follow_the_network(self):
45+
urls = self._nav_for_network("up")
46+
self.assertEqual(
47+
urls["NAV_NEWS_FEED_URL"], "https://up.hcommons.org/activity/"
48+
)
49+
self.assertEqual(
50+
urls["NAV_GROUPS_URL"], "https://up.hcommons.org/groups/"
51+
)
52+
self.assertEqual(
53+
urls["NAV_SITES_URL"], "https://up.hcommons.org/sites/"
54+
)
55+
56+
def test_fixed_links_never_follow_the_network(self):
57+
urls = self._nav_for_network("stemedplus")
58+
self.assertEqual(
59+
urls["NAV_WORKS_URL"], "https://works.hcommons.org/"
60+
)
61+
self.assertEqual(
62+
urls["NAV_SUPPORT_URL"], "https://support.hcommons.org/"
63+
)
64+
# KC Organizations lives ON the default domain and must still
65+
# not follow the network
66+
self.assertEqual(
67+
urls["NAV_ORGANIZATIONS_URL"], "https://hcommons.org/societies/"
68+
)
69+
self.assertEqual(
70+
urls["NAV_ABOUT_URL"], "https://sustaining.hcommons.org/"
71+
)
72+
self.assertEqual(urls["NAV_BLOG_URL"], "https://team.hcommons.org/")
73+
74+
def test_no_network_leaves_links_unchanged(self):
75+
urls = self._nav_for_network(None)
76+
self.assertEqual(
77+
urls["NAV_NEWS_FEED_URL"], "https://hcommons.org/activity/"
78+
)
79+
self.assertEqual(
80+
urls["NAV_GROUPS_URL"], "https://hcommons.org/groups/"
81+
)
82+
83+
def test_network_beats_referer_session_domain(self):
84+
session = {
85+
"nav_network_domain": "msu.edu",
86+
"nav_network_domain_ts": time.time(),
87+
}
88+
urls = self._nav_for_network("up", session=session)
89+
self.assertEqual(
90+
urls["NAV_NEWS_FEED_URL"], "https://up.hcommons.org/activity/"
91+
)
92+
93+
94+
@override_settings(
95+
**NAV_SETTINGS,
96+
ALLOWED_HOSTS=["*"],
97+
KNOWN_SOCIETY_MAPPINGS={"stemedplus": "STEMED+"},
98+
NETWORK_DISPLAY_NAMES={
99+
"up": "Association of University Presses",
100+
"stemed+": "STEM Ed+",
101+
},
102+
NETWORK_SUBDOMAIN_BASE_DOMAINS=["profile.hcommons-dev.org"],
103+
NETWORK_SUBDOMAIN_IGNORED=["www"],
104+
)
105+
class NetworkNavRenderingTests(TestCase):
106+
def setUp(self):
107+
Profile.objects.create(
108+
username="alice",
109+
name="Alice",
110+
is_member_of=json.dumps({"UP": True}),
111+
)
112+
113+
def test_subdomain_page_renders_network_nav_links(self):
114+
response = self.client.get(
115+
"/members/", headers={"host": "up.profile.hcommons-dev.org"}
116+
)
117+
self.assertEqual(response.status_code, 200)
118+
self.assertContains(response, "https://up.hcommons.org/activity/")
119+
self.assertContains(response, "https://up.hcommons.org/groups/")
120+
self.assertContains(response, "https://works.hcommons.org/")
121+
self.assertContains(response, "https://hcommons.org/societies/")

0 commit comments

Comments
 (0)