diff --git a/readthedocs/projects/admin.py b/readthedocs/projects/admin.py index c847f848735..edb2ae939ff 100644 --- a/readthedocs/projects/admin.py +++ b/readthedocs/projects/admin.py @@ -366,7 +366,7 @@ class DomainAdmin(admin.ModelAdmin): class FeatureAdmin(admin.ModelAdmin): model = Feature form = FeatureForm - list_display = ('feature_id', 'project_count', 'default_true') + list_display = ('feature_id', 'project_count', 'default_true', 'future_default_true') search_fields = ('feature_id',) filter_horizontal = ('projects',) readonly_fields = ('add_date',) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 81d1ebeae7f..ed2020bf238 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -722,7 +722,7 @@ class FeatureForm(forms.ModelForm): class Meta: model = Feature - fields = ['projects', 'feature_id', 'default_true'] + fields = ['projects', 'feature_id', 'default_true', 'future_default_true'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/readthedocs/projects/migrations/0064_add_feature_future_default_true.py b/readthedocs/projects/migrations/0064_add_feature_future_default_true.py new file mode 100644 index 00000000000..353d3b9c1b2 --- /dev/null +++ b/readthedocs/projects/migrations/0064_add_feature_future_default_true.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.16 on 2020-10-16 14:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0063_extend_domain_from_timestamp_model'), + ] + + operations = [ + migrations.AddField( + model_name='feature', + name='future_default_true', + field=models.BooleanField(default=False, verbose_name='Default all future projects to True'), + ), + migrations.AlterField( + model_name='feature', + name='default_true', + field=models.BooleanField(default=False, verbose_name='Default all past projects to True'), + ), + ] diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index aadb451057f..bc977a9ec49 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -1742,8 +1742,14 @@ def add_features(sender, **kwargs): _('Date feature was added'), auto_now_add=True, ) + # TODO: rename this field to `past_default_true` and follow this steps when deploying + # https://github.com/readthedocs/readthedocs.org/pull/7524#issuecomment-703663724 default_true = models.BooleanField( - _('Historical default is True'), + _('Default all past projects to True'), + default=False, + ) + future_default_true = models.BooleanField( + _('Default all future projects to True'), default=False, ) diff --git a/readthedocs/projects/querysets.py b/readthedocs/projects/querysets.py index 4c5acda0baa..7ed7addb70e 100644 --- a/readthedocs/projects/querysets.py +++ b/readthedocs/projects/querysets.py @@ -239,7 +239,8 @@ class FeatureQuerySet(models.QuerySet): def for_project(self, project): return self.filter( Q(projects=project) | - Q(default_true=True, add_date__gt=project.pub_date), + Q(default_true=True, add_date__gt=project.pub_date) | + Q(future_default_true=True, add_date__lt=project.pub_date) ).distinct() diff --git a/readthedocs/rtd_tests/tests/test_project_querysets.py b/readthedocs/rtd_tests/tests/test_project_querysets.py index d48f7470090..6c531b03fbc 100644 --- a/readthedocs/rtd_tests/tests/test_project_querysets.py +++ b/readthedocs/rtd_tests/tests/test_project_querysets.py @@ -259,6 +259,32 @@ def test_feature_for_project_is_implicitly_applied(self): ordered=False, ) + def test_feature_future_default_true(self): + project = fixture.get(Project, main_language_project=None) + # Explicit feature + feature1 = fixture.get(Feature, projects=[project]) + + # False implicit feature + feature2 = fixture.get( + Feature, + projects=[], + add_date=project.pub_date + timedelta(days=1), + future_default_true=False, + ) + + # True implicit feature after add date + feature3 = fixture.get( + Feature, + projects=[], + add_date=project.pub_date - timedelta(days=1), + future_default_true=True, + ) + self.assertQuerysetEqual( + Feature.objects.for_project(project), + [repr(feature1), repr(feature3)], + ordered=False, + ) + def test_feature_multiple_projects(self): project1 = fixture.get(Project, main_language_project=None) project2 = fixture.get(Project, main_language_project=None)