Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dropdown to select Advanced Settings #4710

Merged
merged 19 commits into from
Oct 23, 2018
Merged
29 changes: 26 additions & 3 deletions readthedocs/builds/forms.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
"""Django forms for the builds app."""

from __future__ import absolute_import
from __future__ import (
absolute_import,
division,
print_function,
unicode_literals,
)

from builtins import object
from django import forms
from django.utils.translation import ugettext_lazy as _

from readthedocs.builds.models import VersionAlias, Version
from readthedocs.projects.models import Project
from readthedocs.builds.models import Version, VersionAlias
from readthedocs.core.utils import trigger_build
from readthedocs.projects.models import Project


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

def clean_active(self):
active = self.cleaned_data['active']
if self._is_default_version() and not active:
msg = _(
'{version} is the default version of the project, '
'it should be active.'
)
raise forms.ValidationError(
msg.format(version=self.instance.verbose_name)
)
return active

def _is_default_version(self):
project = self.instance.project
return project.default_version == self.instance.slug

def save(self, commit=True):
obj = super(VersionForm, self).save(commit=commit)
if obj.active and not obj.built and not obj.uploaded:
Expand Down
33 changes: 31 additions & 2 deletions readthedocs/projects/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"""Project forms."""

from __future__ import (
absolute_import, division, print_function, unicode_literals)
absolute_import,
division,
print_function,
unicode_literals,
)

from random import choice

Expand All @@ -23,9 +27,16 @@
from readthedocs.integrations.models import Integration
from readthedocs.oauth.models import RemoteRepository
from readthedocs.projects import constants
from readthedocs.projects.constants import PUBLIC
from readthedocs.projects.exceptions import ProjectSpamError
from readthedocs.projects.models import (
Domain, EmailHook, Feature, Project, ProjectRelationship, WebHook)
Domain,
EmailHook,
Feature,
Project,
ProjectRelationship,
WebHook,
)
from readthedocs.redirects.models import Redirect


Expand Down Expand Up @@ -202,6 +213,24 @@ class Meta(object):
# 'num_major', 'num_minor', 'num_point',
)

def __init__(self, *args, **kwargs):
super(ProjectAdvancedForm, self).__init__(*args, **kwargs)

default_choice = (None, '-' * 9)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I Pythonic way to do this would be to use something like empty_value: https://docs.djangoproject.com/en/2.1/ref/forms/fields/#django.forms.TypedChoiceField.empty_value

I'm not 100% sure that this is possible here, but I think it should be.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are just replacing the widget (Select), so it's not possible https://docs.djangoproject.com/en/2.1/ref/forms/widgets/#django.forms.Select

all_versions = self.instance.versions.values_list(
'slug', 'verbose_name'
)
self.fields['default_branch'].widget = forms.Select(
choices=[default_choice] + list(all_versions)
)

active_versions = self.instance.all_active_versions().values_list(
'slug', 'verbose_name'
)
self.fields['default_version'].widget = forms.Select(
choices=active_versions
)

def clean_conf_py_file(self):
filename = self.cleaned_data.get('conf_py_file', '').strip()
if filename and 'conf.py' not in filename:
Expand Down
54 changes: 54 additions & 0 deletions readthedocs/rtd_tests/tests/test_build_forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-

from __future__ import division, print_function, unicode_literals

from django.test import TestCase
from django_dynamic_fixture import get

from readthedocs.builds.forms import VersionForm
from readthedocs.builds.models import Version
from readthedocs.projects.constants import PRIVATE
from readthedocs.projects.models import Project


class TestVersionForm(TestCase):

def setUp(self):
self.project = get(Project)

def test_default_version_is_active(self):
version = get(
Version,
project=self.project,
active=False,
)
self.project.default_version = version.slug
self.project.save()

form = VersionForm(
{
'active': True,
'privacy_level': PRIVATE,
},
instance=version
)
self.assertTrue(form.is_valid())

def test_default_version_is_inactive(self):
version = get(
Version,
project=self.project,
active=True,
)
self.project.default_version = version.slug
self.project.save()

form = VersionForm(
{
'active': False,
'privacy_level': PRIVATE,
},
instance=version
)
self.assertFalse(form.is_valid())
self.assertIn('active', form.errors)
84 changes: 82 additions & 2 deletions readthedocs/rtd_tests/tests/test_project_forms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-

from __future__ import (
absolute_import, division, print_function, unicode_literals)
absolute_import,
division,
print_function,
unicode_literals,
)

import mock
from django.contrib.auth.models import User
Expand All @@ -10,9 +14,17 @@
from django_dynamic_fixture import get
from textclassifier.validators import ClassifierValidator

from readthedocs.builds.constants import LATEST
from readthedocs.builds.models import Version
from readthedocs.projects.constants import PRIVATE, PROTECTED, PUBLIC
from readthedocs.projects.exceptions import ProjectSpamError
from readthedocs.projects.forms import (
ProjectBasicsForm, ProjectExtraForm, TranslationForm, UpdateProjectForm)
ProjectAdvancedForm,
ProjectBasicsForm,
ProjectExtraForm,
TranslationForm,
UpdateProjectForm,
)
from readthedocs.projects.models import Project


Expand Down Expand Up @@ -94,6 +106,74 @@ def test_import_repo_url(self):
self.assertEqual(form.is_valid(), valid, msg=url)


class TestProjectAdvancedForm(TestCase):

def setUp(self):
self.project = get(Project)
get(
Version,
project=self.project,
slug='public-1',
active=True,
privacy_level=PUBLIC,
)
get(
Version,
project=self.project,
slug='public-2',
active=True,
privacy_level=PUBLIC,
)
get(
Version,
project=self.project,
slug='public-3',
active=False,
privacy_level=PROTECTED,
)
get(
Version,
project=self.project,
slug='private',
active=True,
privacy_level=PRIVATE,
)
get(
Version,
project=self.project,
slug='protected',
active=True,
privacy_level=PROTECTED,
)

def test_list_only_active_versions_on_default_version(self):
form = ProjectAdvancedForm(instance=self.project)
# This version is created automatically by the project on save
self.assertTrue(self.project.versions.filter(slug=LATEST).exists())
self.assertEqual(
set(
slug
for slug, _ in form.fields['default_version'].widget.choices
),
{'latest', 'public-1', 'public-2', 'private', 'protected'},
)

def test_list_all_versions_on_default_branch(self):
form = ProjectAdvancedForm(instance=self.project)
# This version is created automatically by the project on save
self.assertTrue(self.project.versions.filter(slug=LATEST).exists())
self.assertEqual(
set(
slug
for slug, _ in form.fields['default_branch'].widget.choices
),
{
None, 'latest', 'public-1', 'public-2',
'public-3', 'protected', 'private'
},
)


class TestTranslationForms(TestCase):

def setUp(self):
Expand Down