Skip to content

Commit 8c87149

Browse files
committed
Merge remote-tracking branch 'origin/develop' into cy/2447-profile-visibility
# Conflicts: # templates/v3/includes/_button.html # templates/v3/user_profile_edit.html # users/models.py # users/views.py
2 parents 56afc75 + a53bcb4 commit 8c87149

77 files changed

Lines changed: 2268 additions & 141 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

config/settings.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
"wagtail.images",
105105
"wagtail.search",
106106
"wagtail.admin",
107+
"wagtail.contrib.routable_page",
107108
"wagtail",
108109
"wagtailmarkdown",
109110
"modelcluster",
@@ -124,6 +125,7 @@
124125
"slack",
125126
"testimonials",
126127
"patches",
128+
"pages",
127129
"asciidoctor_sandbox",
128130
]
129131

@@ -238,7 +240,7 @@
238240
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
239241
"OPTIONS": {"min_length": 9},
240242
},
241-
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
243+
{"NAME": "users.validators.CommonPasswordValidator"},
242244
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
243245
]
244246

config/urls.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
StaticContentTemplateView,
4444
UserGuideTemplateView,
4545
)
46-
from marketing.views import PlausibleRedirectView, WhitePaperView
46+
from marketing.views import PlausibleRedirectView
4747
from libraries.api import LibrarySearchView
4848
from libraries.views import (
4949
LibraryDetail,
@@ -134,11 +134,6 @@
134134
PlausibleRedirectView.as_view(),
135135
name="bsm",
136136
),
137-
path(
138-
"outreach/<slug:category>/<slug:slug>",
139-
WhitePaperView.as_view(),
140-
name="whitepaper",
141-
),
142137
path(
143138
"accounts/social/signup/",
144139
CustomSocialSignupViewView.as_view(),
@@ -424,6 +419,10 @@
424419
),
425420
]
426421
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
422+
+ [
423+
path("outreach/", include(wagtail_urls)),
424+
path("pages/", include(wagtail_urls)),
425+
]
427426
+ [
428427
# Libraries docs, some HTML parts are re-written
429428
re_path(
@@ -457,10 +456,6 @@
457456
),
458457
]
459458
+ djdt_urls
460-
+ [
461-
# Wagtail catch-all (must be last!)
462-
path("", include(wagtail_urls)),
463-
]
464459
)
465460

466461
handler404 = "ak.views.custom_404_view"

config/v3_urls.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"""
4646

4747
from django.contrib.admin.views.decorators import staff_member_required
48-
from django.urls import path
48+
from django.urls import path, re_path
4949

5050
from core.views import LearnPageView, V3ComponentDemoView
5151
from news.views import V3AllTypesCreateView
@@ -88,8 +88,11 @@
8888
V3PasswordResetDoneView.as_view(),
8989
name="v3-password-reset-done",
9090
),
91-
path(
92-
"v3/accounts/password/reset/key/",
91+
# Same uidb36/key shape as allauth's account_reset_password_from_key
92+
# route; the view redirects to the ".../key/<uidb36>-set-password/"
93+
# placeholder URL after stashing the real key in the session.
94+
re_path(
95+
r"^v3/accounts/password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$",
9396
V3PasswordResetFromKeyView.as_view(),
9497
name="v3-password-reset-from-key",
9598
),

core/context_processors.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ class NavLink:
213213
is_unread: bool = False
214214

215215

216+
def edit_profile_url():
217+
"""Shared CTA URL for the profile edit page."""
218+
return f"{reverse('profile-account')}?edit=True"
219+
220+
216221
def header_context(request):
217222
"""Context processor for header nav links."""
218223
nav_links = [
@@ -229,6 +234,7 @@ def header_context(request):
229234
return {
230235
"nav_links": nav_links,
231236
"releases_url": reverse("releases-most-recent"),
237+
"edit_profile_url": edit_profile_url(),
232238
}
233239

234240

core/mixins.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ def get_context_data(self, **kwargs):
4242
context = super().get_context_data(**kwargs)
4343
return context
4444

45+
def serve(self, request, *args, **kwargs):
46+
if not flag_is_active(request, "v3"):
47+
raise Http404
48+
return super().serve(request, *args, **kwargs)
49+
4550
def get_v3_context_data(self, **kwargs):
4651
"""Override in subclasses to provide v3-specific context."""
4752
return {**kwargs}
@@ -91,7 +96,9 @@ def get_v3_context_data(self, **kwargs):
9196
context["background_image_url"] = large_static(
9297
"img/v3/auth-page/auth-page-background.png"
9398
)
94-
context["login_url"] = reverse_lazy("v3-login")
99+
# account_login is the real login page (CustomLoginView renders the
100+
# v3 login template); v3-login is only a design-preview route.
101+
context["login_url"] = reverse_lazy("account_login")
95102
context["signup_url"] = reverse_lazy("account_signup")
96103
context["password_reset_url"] = reverse_lazy("v3-password-reset")
97104
return context

core/views.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,16 @@ def get_context_data(self, **kwargs):
20082008
"badge": BadgeToken.BOOST_DAY,
20092009
"bio": "Boost Day contributor.",
20102010
},
2011+
{
2012+
# Collective author: group icon, no link or role (as produced by
2013+
# build_library_intro_context for e.g. "Various").
2014+
"name": "Various Authors",
2015+
"profile_url": None,
2016+
"role": None,
2017+
"avatar_url": "",
2018+
"badge": "",
2019+
"bio": "",
2020+
},
20112021
]
20122022

20132023
context["contributor_data"] = 10 * [

libraries/utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,25 @@ def patch_commit_authors(users):
470470
return users
471471

472472

473+
def apply_collective_author_overrides(author_dicts):
474+
"""Normalize collective authors (e.g. "Various Authors") in V3 profile dicts.
475+
476+
A collective author renders as a single labelled group icon with no profile
477+
link or role. Mutates each dict in place and returns the same list.
478+
"""
479+
from users.templatetags.avatar_tags import (
480+
collective_author_label,
481+
is_collective_author,
482+
)
483+
484+
for author in author_dicts:
485+
if is_collective_author(author["name"]):
486+
author["name"] = collective_author_label(author["name"])
487+
author["profile_url"] = None
488+
author["role"] = None
489+
return author_dicts
490+
491+
473492
def build_library_intro_context(
474493
library_version, *, max_authors=None, include_contributors=False
475494
):
@@ -520,6 +539,8 @@ def build_library_intro_context(
520539
for contributor in top_contributors
521540
)
522541

542+
apply_collective_author_overrides(author_dicts)
543+
523544
return {
524545
"library_name": library.display_name,
525546
"description": library_version.description or library.description or "",

libraries/views.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
Tier,
3535
)
3636
from .utils import (
37+
apply_collective_author_overrides,
3738
get_view_from_cookie,
3839
set_view_in_cookie,
3940
get_prioritized_library_view,
@@ -572,15 +573,17 @@ def get_v3_context_data(self, **kwargs):
572573
]
573574
)
574575
context["this_release_contributors"] = (
575-
this_release or SharedResources.library_release_contributors
576+
apply_collective_author_overrides(this_release)
577+
or SharedResources.library_release_contributors
576578
)
577579

578580
all_time = [
579581
a.to_v3_profile_dict("Contributor")
580582
for a in base_context.get("previous_contributors", [])
581583
]
582584
context["all_time_contributors"] = (
583-
all_time or SharedResources.library_all_contributors
585+
apply_collective_author_overrides(all_time)
586+
or SharedResources.library_all_contributors
584587
)
585588

586589
context["is_flagship_lib"] = self.object.tier == Tier.FLAGSHIP

marketing/models.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,15 @@ class DetailPage(EmailCapturePage):
148148
class OutreachHomePage(Page):
149149
"""A dummy homepage to just return a 404 at the `/outreach/` url"""
150150

151-
parent_page_types = ["wagtailcore.Page"]
152-
subpage_types = ["marketing.ProgramPageIndex", "marketing.TopicPage"]
151+
parent_page_types = [
152+
"wagtailcore.Page",
153+
"pages.RoutableHomePage",
154+
]
155+
subpage_types = [
156+
"marketing.ProgramPageIndex",
157+
"marketing.TopicPage",
158+
"testimonials.TestimonialsIndexPage",
159+
]
153160
max_count = 1 # one container
154161

155162
def route(self, request, path_components):
@@ -158,13 +165,14 @@ def route(self, request, path_components):
158165
/outreach/program_page/<slug>/ => delegate to ProgramPageIndex -> ProgramPage
159166
/outreach/<topic>/<detail>/ => delegate to TopicPage -> DetailPage
160167
"""
168+
print(path_components)
161169
if not path_components:
162170
return RouteResult(self)
163171

164-
_, second, *rest = path_components
172+
first, *rest = path_components
165173

166174
# Fixed segment for program pages
167-
if second == "program_page":
175+
if first == "program_page":
168176
try:
169177
program_page_index = ProgramPageIndex.objects.child_of(self).get()
170178
except ProgramPageIndex.DoesNotExist:
@@ -174,7 +182,7 @@ def route(self, request, path_components):
174182

175183
# Otherwise, first segment should be a TopicPage slug
176184
try:
177-
topic = TopicPage.objects.child_of(self).get(slug=second)
185+
topic = TopicPage.objects.child_of(self).get(slug=first)
178186
except TopicPage.DoesNotExist:
179187
raise Http404("Topic not found")
180188

marketing/tests.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
import pytest
55

66

7-
def test_whitepaper_view(tp):
8-
tp.assertGoodView("whitepaper", slug="_example")
9-
10-
117
@pytest.mark.parametrize("url_stem", ["qrc", "bsm"])
128
def test_plausible_redirect_and_plausible_payload(tp, url_stem):
139
"""XFF present; querystring preserved; payload/headers correct."""

0 commit comments

Comments
 (0)