Skip to content

Commit 8ef2a8c

Browse files
committed
Remove generic URL feature 😿️
1 parent 2d89f39 commit 8ef2a8c

File tree

5 files changed

+49
-169
lines changed

5 files changed

+49
-169
lines changed

readthedocs/organizations/tests/test_views.py

+3-32
Original file line numberDiff line numberDiff line change
@@ -406,16 +406,6 @@ def setUp(self):
406406
)
407407
self.client.force_login(self.owner)
408408

409-
def test_members_list_redirects_to_organization_choose(self):
410-
self.assertEqual(Organization.objects.count(), 2)
411-
resp = self.client.get(reverse("organization_members", kwargs={"slug": "-"}))
412-
self.assertRedirects(
413-
resp,
414-
reverse(
415-
"organization_choose", kwargs={"next_name": "organization_members"}
416-
),
417-
)
418-
419409
def test_choose_organization_edit(self):
420410
"""
421411
Verify that the choose page works.
@@ -435,17 +425,6 @@ def test_choose_organization_edit(self):
435425
),
436426
)
437427

438-
def test_no_redirect_organization_team_detail(self):
439-
"""
440-
Verify that organization views w extra URL kwargs just return 404 if unspecified slug.
441-
"""
442-
resp = self.client.get(
443-
reverse(
444-
"organization_team_detail", kwargs={"slug": "-", "team": self.team.pk}
445-
)
446-
)
447-
self.assertEqual(resp.status_code, 404)
448-
449428

450429
@override_settings(
451430
RTD_ALLOW_ORGANIZATIONS=True,
@@ -467,7 +446,9 @@ def setUp(self):
467446

468447
def test_unspecified_slug_redirects_to_organization_edit(self):
469448
self.assertEqual(Organization.objects.count(), 1)
470-
resp = self.client.get(reverse("organization_edit", kwargs={"slug": "-"}))
449+
resp = self.client.get(
450+
reverse("organization_choose", kwargs={"next_name": "organization_edit"})
451+
)
471452
self.assertRedirects(
472453
resp, reverse("organization_edit", kwargs={"slug": self.organization.slug})
473454
)
@@ -486,16 +467,6 @@ def setUp(self):
486467
self.project = get(Project, slug="project")
487468
self.client.force_login(self.owner)
488469

489-
def test_unspecified_slug_redirects_to_organization_edit(self):
490-
self.assertEqual(Organization.objects.count(), 0)
491-
resp = self.client.get(reverse("organization_members", kwargs={"slug": "-"}))
492-
self.assertRedirects(
493-
resp,
494-
reverse(
495-
"organization_choose", kwargs={"next_name": "organization_members"}
496-
),
497-
)
498-
499470
def test_choose_organization_edit(self):
500471
self.assertEqual(Organization.objects.count(), 0)
501472
resp = self.client.get(

readthedocs/organizations/views/base.py

+21-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Base classes for organization views."""
22
from functools import lru_cache
33

4+
from django.conf import settings
45
from django.contrib.messages.views import SuccessMessageMixin
6+
from django.http import Http404
57
from django.shortcuts import get_object_or_404
68
from django.urls import reverse_lazy
79

@@ -18,14 +20,27 @@
1820
Team,
1921
TeamMember,
2022
)
21-
from readthedocs.organizations.views.decorators import (
22-
redirect_if_organization_unspecified,
23-
redirect_if_organizations_disabled,
24-
)
23+
24+
25+
class CheckOrganizationsEnabled:
26+
27+
"""
28+
Return 404 if organizations aren't enabled.
29+
30+
All organization views should inherit this class.
31+
This is mainly for our tests to work,
32+
adding the organization urls conditionally on readthedocs/urls.py
33+
doesn't work as the file is evaluated only once, not per-test case.
34+
"""
35+
36+
def dispatch(self, *args, **kwargs):
37+
if not settings.RTD_ALLOW_ORGANIZATIONS:
38+
raise Http404
39+
return super().dispatch(*args, **kwargs)
2540

2641

2742
# Mixins
28-
class OrganizationMixin:
43+
class OrganizationMixin(CheckOrganizationsEnabled):
2944

3045
"""
3146
Mixin class that provides organization sublevel objects.
@@ -43,11 +58,6 @@ class OrganizationMixin:
4358
org_url_field = 'slug'
4459
admin_only = True
4560

46-
@redirect_if_organizations_disabled
47-
@redirect_if_organization_unspecified
48-
def dispatch(self, *args, **kwargs):
49-
return super().dispatch(*args, **kwargs)
50-
5161
def get_queryset(self):
5262
"""Return queryset that returns organizations for user."""
5363
return self.get_organization_queryset()
@@ -118,7 +128,7 @@ def get_form(self, data=None, files=None, **kwargs):
118128

119129

120130
# Base views
121-
class OrganizationView:
131+
class OrganizationView(CheckOrganizationsEnabled):
122132

123133
"""Mixin for an organization view that doesn't have nested components."""
124134

@@ -130,11 +140,6 @@ class OrganizationView:
130140
lookup_field = 'slug'
131141
lookup_url_field = 'slug'
132142

133-
@redirect_if_organizations_disabled
134-
@redirect_if_organization_unspecified
135-
def dispatch(self, *args, **kwargs):
136-
return super().dispatch(*args, **kwargs)
137-
138143
def get_queryset(self):
139144
if self.admin_only:
140145
return Organization.objects.for_admin_user(user=self.request.user)

readthedocs/organizations/views/decorators.py

-105
This file was deleted.

readthedocs/organizations/views/private.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
from django.conf import settings
55
from django.contrib import messages
66
from django.http import HttpResponseBadRequest
7-
from django.urls import reverse_lazy
7+
from django.shortcuts import redirect
8+
from django.urls import reverse, reverse_lazy
89
from django.utils import timezone
10+
from django.utils.http import urlencode
911
from django.utils.translation import gettext_lazy as _
1012
from vanilla import CreateView, DeleteView, FormView, ListView, UpdateView
1113

@@ -72,10 +74,27 @@ def get_queryset(self):
7274
class ChooseOrganization(ListOrganization):
7375
template_name = "organizations/organization_choose.html"
7476

77+
def dispatch(self, request, *args, **kwargs):
78+
79+
self.next_name = self.kwargs["next_name"]
80+
self.next_querystring = self.request.GET.get("next_querystring")
81+
82+
# Check if user has exactly 1 organization and automatically redirect in this case
83+
organizations = self.get_queryset()
84+
if organizations.count() == 1:
85+
redirect_url = reverse(
86+
self.next_name, kwargs={"slug": organizations[0].slug}
87+
)
88+
if self.next_querystring:
89+
redirect_url += "?" + urlencode(self.next_querystring)
90+
return redirect(redirect_url)
91+
92+
return super().dispatch(request, *args, **kwargs)
93+
7594
def get_context_data(self, **kwargs):
7695
c = super().get_context_data(**kwargs)
77-
c["next_name"] = self.kwargs["next_name"]
78-
c["next_querystring"] = self.request.GET.get("next_querystring")
96+
c["next_name"] = self.next_name
97+
c["next_querystring"] = self.next_querystring
7998
return c
8099

81100

readthedocs/organizations/views/public.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,21 @@
88

99
from readthedocs.organizations.models import Team
1010
from readthedocs.organizations.views.base import (
11+
CheckOrganizationsEnabled,
1112
OrganizationMixin,
1213
OrganizationTeamMemberView,
1314
OrganizationTeamView,
1415
OrganizationView,
1516
)
16-
from readthedocs.organizations.views.decorators import (
17-
redirect_if_organizations_disabled,
18-
)
1917
from readthedocs.projects.models import Project
2018

2119
log = structlog.get_logger(__name__)
2220

2321

24-
class OrganizationTemplateView(TemplateView):
22+
class OrganizationTemplateView(CheckOrganizationsEnabled, TemplateView):
2523

2624
"""Wrapper around `TemplateView` to check if organizations are enabled."""
2725

28-
@redirect_if_organizations_disabled
29-
def dispatch(self, *args, **kwargs):
30-
return super().dispatch(*args, **kwargs)
31-
3226

3327
# Organization
3428

@@ -98,14 +92,10 @@ def get_context_data(self, **kwargs):
9892
return context
9993

10094

101-
class RedirectRedeemTeamInvitation(GenericView):
95+
class RedirectRedeemTeamInvitation(CheckOrganizationsEnabled, GenericView):
10296

10397
"""Redirect invitation links to the new view."""
10498

105-
@redirect_if_organizations_disabled
106-
def dispatch(self, *args, **kwargs):
107-
return super().dispatch(*args, **kwargs)
108-
10999
# pylint: disable=unused-argument
110100
def get(self, request, *args, **kwargs):
111101
return HttpResponseRedirect(

0 commit comments

Comments
 (0)