Skip to content

Commit 5f5f502

Browse files
committed
Bring back project privacy level
But... only for .com and is used to show the dashboard and build output of public versions Closes #2663
1 parent 046c4bd commit 5f5f502

File tree

7 files changed

+88
-7
lines changed

7 files changed

+88
-7
lines changed

docs/commercial/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ Advertising-free
3535
organizations
3636
single-sign-on
3737
sharing
38+
privacy-level
3839
analytics

docs/commercial/privacy-level.rst

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Project Privacy Level
2+
---------------------
3+
4+
.. note::
5+
6+
This feature only exists on `Read the Docs for Business <https://readthedocs.com/>`__.
7+
8+
By default, only users that belong to your organization can see the dashboard of your project and its builds.
9+
If you want users outside your organization and anonymous users to be able to see the dashboard of your project,
10+
and the build output of *public versions* you can set the privacy level of your project to ``Public``.
11+
12+
- Go the :guilabel:`Admin` tab of your project.
13+
- Click on :guilabel:`Advanced Settings`.
14+
- Change to :guilabel:`Privacy level` to `Public`.
15+
16+
17+
.. note::
18+
19+
To control access to the documentation itself,
20+
see :ref:`versions:privacy levels`.

docs/versions.rst

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ Private versions are available only to people who have permissions to see them.
111111
They will not display on any list view, and will 404 when you link them to others.
112112
If you want to share your docs temporarily, see :doc:`/commercial/sharing`.
113113

114+
In addition, if you want other users to view the build page of your public versions,
115+
you'll neeed to the set the :doc:`privacy level of your project </commercial/privacy-level>` to public.
116+
114117
Tags and branches
115118
-----------------
116119

readthedocs/projects/forms.py

+15-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from urllib.parse import urlparse
55

66
from crispy_forms.helper import FormHelper
7-
from crispy_forms.layout import Fieldset, Layout, HTML, Submit
7+
from crispy_forms.layout import HTML, Fieldset, Layout, Submit
88
from django import forms
99
from django.conf import settings
1010
from django.contrib.auth.models import User
@@ -14,6 +14,7 @@
1414
from textclassifier.validators import ClassifierValidator
1515

1616
from readthedocs.builds.constants import INTERNAL
17+
from readthedocs.core.mixins import HideProtectedLevelMixin
1718
from readthedocs.core.utils import slugify, trigger_build
1819
from readthedocs.core.utils.extend import SettingsOverrideObject
1920
from readthedocs.integrations.models import Integration
@@ -190,7 +191,7 @@ def clean_tags(self):
190191
return tags
191192

192193

193-
class ProjectAdvancedForm(ProjectTriggerBuildMixin, ProjectForm):
194+
class ProjectAdvancedForm(HideProtectedLevelMixin, ProjectTriggerBuildMixin, ProjectForm):
194195

195196
"""Advanced project option form."""
196197

@@ -203,7 +204,8 @@ class Meta:
203204
'analytics_disabled',
204205
'show_version_warning',
205206
'single_version',
206-
'external_builds_enabled'
207+
'external_builds_enabled',
208+
'privacy_level',
207209
)
208210
# These that can be set per-version using a config file.
209211
per_version_settings = (
@@ -232,17 +234,24 @@ def __init__(self, *args, **kwargs):
232234
help_text = render_to_string(
233235
'projects/project_advanced_settings_helptext.html'
234236
)
235-
self.helper.layout = Layout(
237+
238+
per_project_settings = list(self.Meta.per_project_settings)
239+
if not settings.ALLOW_PRIVATE_REPOS:
240+
self.fields.pop('privacy_level')
241+
per_project_settings.remove('privacy_level')
242+
243+
field_sets = [
236244
Fieldset(
237245
_("Global settings"),
238-
*self.Meta.per_project_settings,
246+
*per_project_settings,
239247
),
240248
Fieldset(
241249
_("Default settings"),
242250
HTML(help_text),
243251
*self.Meta.per_version_settings,
244252
),
245-
)
253+
]
254+
self.helper.layout = Layout(*field_sets)
246255
self.helper.add_input(Submit('save', _('Save')))
247256

248257
default_choice = (None, '-' * 9)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 2.2.16 on 2020-10-01 18:00
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('projects', '0063_extend_domain_from_timestamp_model'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='project',
15+
name='privacy_level',
16+
field=models.CharField(choices=[('public', 'Public'), ('protected', 'Protected'), ('private', 'Private')], default='public', help_text='Should the project dashboard be public?', max_length=20, verbose_name='Privacy Level'),
17+
),
18+
]

readthedocs/projects/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ class Project(models.Model):
365365
choices=constants.PRIVACY_CHOICES,
366366
default=settings.DEFAULT_PRIVACY_LEVEL,
367367
help_text=_(
368-
'Level of privacy that you want on the repository.',
368+
'Should the project dashboard be public?',
369369
),
370370
)
371371

readthedocs/rtd_tests/tests/test_project_forms.py

+30
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
PUBLIC,
1616
REPO_TYPE_GIT,
1717
REPO_TYPE_HG,
18+
SPHINX,
1819
)
1920
from readthedocs.projects.exceptions import ProjectSpamError
2021
from readthedocs.projects.forms import (
@@ -274,6 +275,35 @@ def test_default_version_field_if_no_active_version(self):
274275
self.assertTrue(form.fields['default_version'].widget.attrs['readonly'])
275276
self.assertEqual(form.fields['default_version'].initial, 'latest')
276277

278+
@override_settings(ALLOW_PRIVATE_REPOS=False)
279+
def test_cant_update_privacy_level(self):
280+
form = ProjectAdvancedForm(
281+
{
282+
'default_version': LATEST,
283+
'documentation_type': SPHINX,
284+
'python_interpreter': 'python3',
285+
'privacy_level': PRIVATE,
286+
},
287+
instance=self.project,
288+
)
289+
# The form is valid, but the field is ignored
290+
self.assertTrue(form.is_valid())
291+
self.assertEqual(self.project.privacy_level, PUBLIC)
292+
293+
@override_settings(ALLOW_PRIVATE_REPOS=True)
294+
def test_can_update_privacy_level(self):
295+
form = ProjectAdvancedForm(
296+
{
297+
'default_version': LATEST,
298+
'documentation_type': SPHINX,
299+
'python_interpreter': 'python3',
300+
'privacy_level': PRIVATE,
301+
},
302+
instance=self.project,
303+
)
304+
self.assertTrue(form.is_valid())
305+
self.assertEqual(self.project.privacy_level, PRIVATE)
306+
277307

278308
class TestProjectAdvancedFormDefaultBranch(TestCase):
279309

0 commit comments

Comments
 (0)