Skip to content

Commit 7fb4b18

Browse files
stsewdagjohnson
authored andcommitted
Dropdown to select Advanced Settings (#4710)
* added auto suggest in version * auto fill for branches * changes in syntax * switched to choicefield and multiple files in option * futher syntax changes * Updates based on feedback * Put back removed code * Simplified logic * Linter 👍 * Validate revert case * Tests for AdvancedForm * Filter by privacy level * Remove privacy checks * Tests for VersionForm * Rename variables * Fix translation * Fix format
1 parent ea058d5 commit 7fb4b18

File tree

4 files changed

+193
-7
lines changed

4 files changed

+193
-7
lines changed

readthedocs/builds/forms.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
"""Django forms for the builds app."""
22

3-
from __future__ import absolute_import
3+
from __future__ import (
4+
absolute_import,
5+
division,
6+
print_function,
7+
unicode_literals,
8+
)
9+
410
from builtins import object
511
from django import forms
12+
from django.utils.translation import ugettext_lazy as _
613

7-
from readthedocs.builds.models import VersionAlias, Version
8-
from readthedocs.projects.models import Project
14+
from readthedocs.builds.models import Version, VersionAlias
915
from readthedocs.core.utils import trigger_build
16+
from readthedocs.projects.models import Project
1017

1118

1219
class AliasForm(forms.ModelForm):
@@ -33,6 +40,22 @@ class Meta(object):
3340
model = Version
3441
fields = ['active', 'privacy_level', 'tags']
3542

43+
def clean_active(self):
44+
active = self.cleaned_data['active']
45+
if self._is_default_version() and not active:
46+
msg = _(
47+
'{version} is the default version of the project, '
48+
'it should be active.'
49+
)
50+
raise forms.ValidationError(
51+
msg.format(version=self.instance.verbose_name)
52+
)
53+
return active
54+
55+
def _is_default_version(self):
56+
project = self.instance.project
57+
return project.default_version == self.instance.slug
58+
3659
def save(self, commit=True):
3760
obj = super(VersionForm, self).save(commit=commit)
3861
if obj.active and not obj.built and not obj.uploaded:

readthedocs/projects/forms.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
"""Project forms."""
33

44
from __future__ import (
5-
absolute_import, division, print_function, unicode_literals)
5+
absolute_import,
6+
division,
7+
print_function,
8+
unicode_literals,
9+
)
610

711
from random import choice
812

@@ -23,9 +27,16 @@
2327
from readthedocs.integrations.models import Integration
2428
from readthedocs.oauth.models import RemoteRepository
2529
from readthedocs.projects import constants
30+
from readthedocs.projects.constants import PUBLIC
2631
from readthedocs.projects.exceptions import ProjectSpamError
2732
from readthedocs.projects.models import (
28-
Domain, EmailHook, Feature, Project, ProjectRelationship, WebHook)
33+
Domain,
34+
EmailHook,
35+
Feature,
36+
Project,
37+
ProjectRelationship,
38+
WebHook,
39+
)
2940
from readthedocs.redirects.models import Redirect
3041

3142

@@ -208,6 +219,24 @@ class Meta(object):
208219
# 'num_major', 'num_minor', 'num_point',
209220
)
210221

222+
def __init__(self, *args, **kwargs):
223+
super(ProjectAdvancedForm, self).__init__(*args, **kwargs)
224+
225+
default_choice = (None, '-' * 9)
226+
all_versions = self.instance.versions.values_list(
227+
'slug', 'verbose_name'
228+
)
229+
self.fields['default_branch'].widget = forms.Select(
230+
choices=[default_choice] + list(all_versions)
231+
)
232+
233+
active_versions = self.instance.all_active_versions().values_list(
234+
'slug', 'verbose_name'
235+
)
236+
self.fields['default_version'].widget = forms.Select(
237+
choices=active_versions
238+
)
239+
211240
def clean_conf_py_file(self):
212241
filename = self.cleaned_data.get('conf_py_file', '').strip()
213242
if filename and 'conf.py' not in filename:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from __future__ import division, print_function, unicode_literals
4+
5+
from django.test import TestCase
6+
from django_dynamic_fixture import get
7+
8+
from readthedocs.builds.forms import VersionForm
9+
from readthedocs.builds.models import Version
10+
from readthedocs.projects.constants import PRIVATE
11+
from readthedocs.projects.models import Project
12+
13+
14+
class TestVersionForm(TestCase):
15+
16+
def setUp(self):
17+
self.project = get(Project)
18+
19+
def test_default_version_is_active(self):
20+
version = get(
21+
Version,
22+
project=self.project,
23+
active=False,
24+
)
25+
self.project.default_version = version.slug
26+
self.project.save()
27+
28+
form = VersionForm(
29+
{
30+
'active': True,
31+
'privacy_level': PRIVATE,
32+
},
33+
instance=version
34+
)
35+
self.assertTrue(form.is_valid())
36+
37+
def test_default_version_is_inactive(self):
38+
version = get(
39+
Version,
40+
project=self.project,
41+
active=True,
42+
)
43+
self.project.default_version = version.slug
44+
self.project.save()
45+
46+
form = VersionForm(
47+
{
48+
'active': False,
49+
'privacy_level': PRIVATE,
50+
},
51+
instance=version
52+
)
53+
self.assertFalse(form.is_valid())
54+
self.assertIn('active', form.errors)

readthedocs/rtd_tests/tests/test_project_forms.py

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# -*- coding: utf-8 -*-
22

33
from __future__ import (
4-
absolute_import, division, print_function, unicode_literals)
4+
absolute_import,
5+
division,
6+
print_function,
7+
unicode_literals,
8+
)
59

610
import mock
711
from django.contrib.auth.models import User
@@ -10,9 +14,17 @@
1014
from django_dynamic_fixture import get
1115
from textclassifier.validators import ClassifierValidator
1216

17+
from readthedocs.builds.constants import LATEST
18+
from readthedocs.builds.models import Version
19+
from readthedocs.projects.constants import PRIVATE, PROTECTED, PUBLIC
1320
from readthedocs.projects.exceptions import ProjectSpamError
1421
from readthedocs.projects.forms import (
15-
ProjectBasicsForm, ProjectExtraForm, TranslationForm, UpdateProjectForm)
22+
ProjectAdvancedForm,
23+
ProjectBasicsForm,
24+
ProjectExtraForm,
25+
TranslationForm,
26+
UpdateProjectForm,
27+
)
1628
from readthedocs.projects.models import Project
1729

1830

@@ -104,6 +116,74 @@ def test_empty_slug(self):
104116
self.assertIn('name', form.errors)
105117

106118

119+
class TestProjectAdvancedForm(TestCase):
120+
121+
def setUp(self):
122+
self.project = get(Project)
123+
get(
124+
Version,
125+
project=self.project,
126+
slug='public-1',
127+
active=True,
128+
privacy_level=PUBLIC,
129+
)
130+
get(
131+
Version,
132+
project=self.project,
133+
slug='public-2',
134+
active=True,
135+
privacy_level=PUBLIC,
136+
)
137+
get(
138+
Version,
139+
project=self.project,
140+
slug='public-3',
141+
active=False,
142+
privacy_level=PROTECTED,
143+
)
144+
get(
145+
Version,
146+
project=self.project,
147+
slug='private',
148+
active=True,
149+
privacy_level=PRIVATE,
150+
)
151+
get(
152+
Version,
153+
project=self.project,
154+
slug='protected',
155+
active=True,
156+
privacy_level=PROTECTED,
157+
)
158+
159+
def test_list_only_active_versions_on_default_version(self):
160+
form = ProjectAdvancedForm(instance=self.project)
161+
# This version is created automatically by the project on save
162+
self.assertTrue(self.project.versions.filter(slug=LATEST).exists())
163+
self.assertEqual(
164+
set(
165+
slug
166+
for slug, _ in form.fields['default_version'].widget.choices
167+
),
168+
{'latest', 'public-1', 'public-2', 'private', 'protected'},
169+
)
170+
171+
def test_list_all_versions_on_default_branch(self):
172+
form = ProjectAdvancedForm(instance=self.project)
173+
# This version is created automatically by the project on save
174+
self.assertTrue(self.project.versions.filter(slug=LATEST).exists())
175+
self.assertEqual(
176+
set(
177+
slug
178+
for slug, _ in form.fields['default_branch'].widget.choices
179+
),
180+
{
181+
None, 'latest', 'public-1', 'public-2',
182+
'public-3', 'protected', 'private'
183+
},
184+
)
185+
186+
107187
class TestTranslationForms(TestCase):
108188

109189
def setUp(self):

0 commit comments

Comments
 (0)