Skip to content

Commit 87bb73c

Browse files
authored
Merge pull request #5833 from readthedocs/humitos/hide-protected-privacy-level
Hide "Protected" privacy level from users
2 parents 63904d3 + 0959af7 commit 87bb73c

File tree

7 files changed

+76
-20
lines changed

7 files changed

+76
-20
lines changed

docs/privacy.rst

+1-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Privacy Levels
22
==============
33

44
Read the Docs supports 3 different privacy levels on 2 different objects;
5-
Public, Protected, Private on Projects and Versions.
5+
Public, Private on Projects and Versions.
66

77
Understanding the Privacy Levels
88
--------------------------------
@@ -12,8 +12,6 @@ Understanding the Privacy Levels
1212
+============+============+===========+===========+=============+
1313
| Private | No | No | No | Yes |
1414
+------------+------------+-----------+-----------+-------------+
15-
| Protected | Yes | No | No | Yes |
16-
+------------+------------+-----------+-----------+-------------+
1715
| Public | Yes | Yes | Yes | Yes |
1816
+------------+------------+-----------+-----------+-------------+
1917

@@ -27,18 +25,6 @@ Public
2725
This is the easiest and most obvious. It is also the default.
2826
It means that everything is available to be seen by everyone.
2927

30-
Protected
31-
~~~~~~~~~
32-
33-
Protected means that your object won't show up in Listing Pages,
34-
but Detail pages still work. For example, a Project that is Protected will
35-
not show on the homepage Recently Updated list, however,
36-
if you link directly to the project, you will get a 200 and the page will display.
37-
38-
Protected Versions are similar, they won't show up in your version listings,
39-
but will be available once linked to.
40-
41-
4228
Private
4329
~~~~~~~
4430

readthedocs/builds/forms.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
from django.utils.translation import ugettext_lazy as _
77

88
from readthedocs.builds.models import Version
9+
from readthedocs.core.mixins import HideProtectedLevelMixin
910
from readthedocs.core.utils import trigger_build
1011

1112

12-
class VersionForm(forms.ModelForm):
13+
class VersionForm(HideProtectedLevelMixin, forms.ModelForm):
1314

1415
class Meta:
1516
model = Version

readthedocs/core/mixins.py

+26
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
from django.contrib.auth.decorators import login_required
66
from django.utils.decorators import method_decorator
7+
from django.utils.translation import ugettext_lazy as _
78
from vanilla import ListView
89

10+
from readthedocs.projects.constants import PRIVACY_CHOICES, PROTECTED
11+
912

1013
class ListViewWithForm(ListView):
1114

@@ -22,3 +25,26 @@ class LoginRequiredMixin:
2225
@method_decorator(login_required)
2326
def dispatch(self, *args, **kwargs):
2427
return super().dispatch(*args, **kwargs)
28+
29+
30+
class HideProtectedLevelMixin:
31+
32+
"""
33+
Hide ``protected`` privacy level from Form.
34+
35+
Remove Protected for now since it causes confusions to users.
36+
37+
If the current ``privacy_level`` is ``protected`` we show it (so users keep
38+
seeing consistency values), and hide it otherwise (so it can't be selected).
39+
40+
There is a better way to manage this by using Version states.
41+
See: https://github.com/rtfd/readthedocs.org/issues/5321
42+
"""
43+
44+
def __init__(self, *args, **kwargs):
45+
super().__init__(*args, **kwargs)
46+
47+
if self.instance is None or self.instance.privacy_level != PROTECTED:
48+
privacy_level = list(PRIVACY_CHOICES)
49+
privacy_level.remove((PROTECTED, _('Protected')))
50+
self.fields['privacy_level'].choices = privacy_level

readthedocs/projects/forms.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.utils.translation import ugettext_lazy as _
1414
from textclassifier.validators import ClassifierValidator
1515

16+
from readthedocs.core.mixins import HideProtectedLevelMixin
1617
from readthedocs.core.utils import slugify, trigger_build
1718
from readthedocs.core.utils.extend import SettingsOverrideObject
1819
from readthedocs.integrations.models import Integration
@@ -188,7 +189,7 @@ def clean_tags(self):
188189
return tags
189190

190191

191-
class ProjectAdvancedForm(ProjectTriggerBuildMixin, ProjectForm):
192+
class ProjectAdvancedForm(HideProtectedLevelMixin, ProjectTriggerBuildMixin, ProjectForm):
192193

193194
"""Advanced project option form."""
194195

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.21 on 2019-07-03 13:00
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('projects', '0043_add-build-field'),
12+
]
13+
14+
operations = [
15+
migrations.AlterField(
16+
model_name='project',
17+
name='privacy_level',
18+
field=models.CharField(choices=[('public', 'Public'), ('protected', 'Protected'), ('private', 'Private')], default='public', help_text='Level of privacy that you want on the repository.', max_length=20, verbose_name='Privacy Level'),
19+
),
20+
]

readthedocs/projects/models.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ class Project(models.Model):
328328
choices=constants.PRIVACY_CHOICES,
329329
default=settings.DEFAULT_PRIVACY_LEVEL,
330330
help_text=_(
331-
'Level of privacy that you want on the repository. '
332-
'Protected means public but not in listings.',
331+
'Level of privacy that you want on the repository.',
333332
),
334333
)
335334
version_privacy_level = models.CharField(

readthedocs/rtd_tests/tests/test_project_forms.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
from django.contrib.auth.models import User
33
from django.test import TestCase
44
from django.test.utils import override_settings
5+
from django.utils.translation import ugettext_lazy as _
56
from django_dynamic_fixture import get
67
from textclassifier.validators import ClassifierValidator
7-
88
from readthedocs.builds.constants import LATEST, STABLE
99
from readthedocs.builds.models import Version
1010
from readthedocs.projects.constants import (
1111
PRIVATE,
12+
PRIVACY_CHOICES,
1213
PROTECTED,
1314
PUBLIC,
1415
REPO_TYPE_GIT,
@@ -272,6 +273,28 @@ def test_default_version_field_if_no_active_version(self):
272273
self.assertTrue(form.fields['default_version'].widget.attrs['readonly'])
273274
self.assertEqual(form.fields['default_version'].initial, 'latest')
274275

276+
def test_hide_protected_privacy_level_new_objects(self):
277+
"""
278+
Test PROTECTED is only allowed in old objects.
279+
280+
New projects are not allowed to set the privacy level as protected.
281+
"""
282+
# New default object
283+
project = get(Project)
284+
form = ProjectAdvancedForm(instance=project)
285+
286+
privacy_choices = list(PRIVACY_CHOICES)
287+
privacy_choices.remove((PROTECTED, _('Protected')))
288+
self.assertEqual(form.fields['privacy_level'].choices, privacy_choices)
289+
290+
# "Old" object with privacy_level previously set as protected
291+
project = get(
292+
Project,
293+
privacy_level=PROTECTED,
294+
)
295+
form = ProjectAdvancedForm(instance=project)
296+
self.assertEqual(form.fields['privacy_level'].choices, list(PRIVACY_CHOICES))
297+
275298

276299
class TestProjectAdvancedFormDefaultBranch(TestCase):
277300

0 commit comments

Comments
 (0)