Skip to content

Commit 8c2eb8c

Browse files
committed
Merge tag '10.0.0' into rel
2 parents e3f7d3c + e3246d7 commit 8c2eb8c

File tree

623 files changed

+25647
-18828
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

623 files changed

+25647
-18828
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
- image: 'cimg/python:3.10'
1111
environment:
1212
TOX_POSARGS: ''
13+
PYTEST_COVERAGE: --cov-report=xml --cov-config .coveragerc --cov=. --cov-append
1314
- image: 'docker.elastic.co/elasticsearch/elasticsearch:7.14.0'
1415
name: search
1516
environment:

CHANGELOG.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
Version 10.0.0
2+
--------------
3+
4+
This release is a Django 4.2 upgrade, so it has a major version bump, 10.0!
5+
6+
:Date: August 14, 2023
7+
8+
* `@ericholscher <https://github.com/ericholscher>`__: Update deprecation timezone to use PDT (`#10631 <https://github.com/readthedocs/readthedocs.org/pull/10631>`__)
9+
* `@stsewd <https://github.com/stsewd>`__: Custom domain: increase header value length (`#10625 <https://github.com/readthedocs/readthedocs.org/pull/10625>`__)
10+
* `@ericholscher <https://github.com/ericholscher>`__: Use same HomepageView for Community & Business (`#10621 <https://github.com/readthedocs/readthedocs.org/pull/10621>`__)
11+
* `@humitos <https://github.com/humitos>`__: Black: run black over all the code base (`#10619 <https://github.com/readthedocs/readthedocs.org/pull/10619>`__)
12+
* `@stsewd <https://github.com/stsewd>`__: Build: Fix exceptions (`#10616 <https://github.com/readthedocs/readthedocs.org/pull/10616>`__)
13+
* `@stsewd <https://github.com/stsewd>`__: Revert "Proxito: test new implementation more broadly (#10599)" (`#10614 <https://github.com/readthedocs/readthedocs.org/pull/10614>`__)
14+
* `@humitos <https://github.com/humitos>`__: Translations: update them all (`#10613 <https://github.com/readthedocs/readthedocs.org/pull/10613>`__)
15+
* `@humitos <https://github.com/humitos>`__: Deprecation: codify browndates for "no config file deprecation" (`#10612 <https://github.com/readthedocs/readthedocs.org/pull/10612>`__)
16+
* `@humitos <https://github.com/humitos>`__: Testing: run Coverage report only on CircleCI (`#10611 <https://github.com/readthedocs/readthedocs.org/pull/10611>`__)
17+
* `@humitos <https://github.com/humitos>`__: Profile: redirect to `/accounts/edit/` view on successful edit (`#10610 <https://github.com/readthedocs/readthedocs.org/pull/10610>`__)
18+
* `@humitos <https://github.com/humitos>`__: Release 9.16.4 (`#10609 <https://github.com/readthedocs/readthedocs.org/pull/10609>`__)
19+
* `@stsewd <https://github.com/stsewd>`__: Admin: show creation/modification dates on the admin page (`#10607 <https://github.com/readthedocs/readthedocs.org/pull/10607>`__)
20+
* `@stsewd <https://github.com/stsewd>`__: Versions: keep type of version in sync with the project (`#10606 <https://github.com/readthedocs/readthedocs.org/pull/10606>`__)
21+
* `@stsewd <https://github.com/stsewd>`__: Proxito: test new implementation more broadly (`#10599 <https://github.com/readthedocs/readthedocs.org/pull/10599>`__)
22+
* `@humitos <https://github.com/humitos>`__: Django: upgrade to 4.2 (`#10595 <https://github.com/readthedocs/readthedocs.org/pull/10595>`__)
23+
* `@stsewd <https://github.com/stsewd>`__: Build: replace GitPython with git commands (`#10594 <https://github.com/readthedocs/readthedocs.org/pull/10594>`__)
24+
* `@agjohnson <https://github.com/agjohnson>`__: Add organization listing filter (`#10593 <https://github.com/readthedocs/readthedocs.org/pull/10593>`__)
25+
* `@humitos <https://github.com/humitos>`__: Deprecation: notification and feature flag for `build.image` config (`#10589 <https://github.com/readthedocs/readthedocs.org/pull/10589>`__)
26+
* `@stsewd <https://github.com/stsewd>`__: Subscriptions: use djstripe for products/features (`#10238 <https://github.com/readthedocs/readthedocs.org/pull/10238>`__)
27+
128
Version 9.16.4
229
--------------
330

common

dockerfiles/settings/build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33

44
class BuildDevSettings(DockerBaseSettings):
5-
65
@property
76
def DATABASES(self): # noqa
87
return {}
98

109
DONT_HIT_DB = True
1110

11+
1212
BuildDevSettings.load_settings(__name__)

dockerfiles/settings/celery.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CeleryDevSettings(DockerBaseSettings):
1313
# http://storage:9000/... This setting fixes that.
1414
# Once we can use CORS, we should define this setting in the
1515
# ``docker_compose.py`` file instead.
16-
S3_MEDIA_STORAGE_OVERRIDE_HOSTNAME = 'storage:9000'
16+
S3_MEDIA_STORAGE_OVERRIDE_HOSTNAME = "storage:9000"
1717

1818

1919
CeleryDevSettings.load_settings(__name__)

dockerfiles/settings/proxito.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ProxitoDevSettings(CommunityProxitoSettingsMixin, DockerBaseSettings):
1616
@property
1717
def DEBUG_TOOLBAR_CONFIG(self):
1818
return {
19-
'SHOW_TOOLBAR_CALLBACK': lambda request: False,
19+
"SHOW_TOOLBAR_CALLBACK": lambda request: False,
2020
}
2121

2222

dockerfiles/settings/web.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ class WebDevSettings(DockerBaseSettings):
66

77
# Router is useful from webs only because they have access to the database.
88
# Builders will use the same queue that was assigned the first time on retry
9-
CELERY_ROUTES = (
10-
'readthedocs.builds.tasks.TaskRouter',
11-
)
9+
CELERY_ROUTES = ("readthedocs.builds.tasks.TaskRouter",)
1210

1311

1412
WebDevSettings.load_settings(__name__)

docs/_ext/djangodocs.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def setup(app):
66
)
77

88
return {
9-
'version': 'builtin',
10-
'parallel_read_safe': True,
11-
'parallel_write_safe': True,
9+
"version": "builtin",
10+
"parallel_read_safe": True,
11+
"parallel_write_safe": True,
1212
}

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777

7878
master_doc = "index"
7979
copyright = "Read the Docs, Inc & contributors"
80-
version = "9.16.4"
80+
version = "10.0.0"
8181
release = version
8282
exclude_patterns = ["_build", "shared", "_includes"]
8383
default_role = "obj"

docs/dev/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ or taking the open source Read the Docs codebase for your own custom installatio
2727
i18n
2828
server-side-search
2929
search-integration
30+
subscriptions
3031
settings
3132
tests

docs/dev/subscriptions.rst

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
Subscriptions
2+
=============
3+
4+
Subscriptions are available on |com_brand|,
5+
we make use of Stripe to handle the payments and subscriptions.
6+
We use dj-stripe to handle the integration with Stripe.
7+
8+
Local testing
9+
-------------
10+
11+
To test subscriptions locally, you need to have access to the Stripe account,
12+
and define the following settings with the keys from Stripe test mode:
13+
14+
- ``STRIPE_SECRET``: https://dashboard.stripe.com/test/apikeys
15+
- ``STRIPE_TEST_SECRET_KEY``: https://dashboard.stripe.com/test/apikeys
16+
- ``DJSTRIPE_WEBHOOK_SECRET``: https://dashboard.stripe.com/test/webhooks
17+
18+
To test the webhook locally, you need to run your local instance with ngrok, for example:
19+
20+
.. code-block:: bash
21+
22+
ngrok http 80
23+
inv docker.up --http-domain xxx.ngrok.io
24+
25+
If this is your first time setting up subscriptions, you will to re-sync djstripe with Stripe:
26+
27+
.. code-block:: bash
28+
29+
inv docker.manage djstripe_sync_models
30+
31+
The subscription settings (``RTD_PRODUCTS``) already mapped to match the Stripe prices from the test mode.
32+
To subscribe to any plan, you can use any `test card from Stripe <https://stripe.com/docs/testing>`__,
33+
for example: ``4242 4242 4242 4242`` (use any future date and any value for the other fields).
34+
35+
Modeling
36+
--------
37+
38+
Subscriptions are attached to an organization (customer),
39+
and can have multiple products attached to it.
40+
A product can have multiple prices, usually monthly and yearly.
41+
42+
When a user subscribes to a plan (product), they are subscribing to a price of a product,
43+
for example, the monthly price of the "Basic plan" product.
44+
45+
A subscription has a "main" product (``RTDProduct(extra=False)``),
46+
and can have several "extra" products (``RTDProduct(extra=True)``).
47+
For example, an organization can have a subscription with a "Basic Plan" product, and an "Extra builder" product.
48+
49+
Each product is mapped to a set of features (``RTD_PRODUCTS``) that the user will have access to
50+
(different prices of the same product have the same features).
51+
If a subscription has multiple products, the features are multiplied by the quantity and added together.
52+
For example, if a subscription has a "Basic Plan" product with a two concurrent builders,
53+
and an "Extra builder" product with quantity three, the total number of concurrent builders the
54+
organization has will be five.
55+
56+
Life cycle of a subscription
57+
----------------------------
58+
59+
When a new organization is created, a stripe customer is created for that organization,
60+
and this customer is subscribed to the trial product (``RTD_ORG_DEFAULT_STRIPE_SUBSCRIPTION_PRICE``).
61+
62+
After the trial period is over, the subscription is canceled,
63+
and their organization is disabled.
64+
65+
During or after the trial a user can upgrade their subscription to a paid plan
66+
(``RTDProduct(listed=True)``).
67+
68+
Custom products
69+
---------------
70+
71+
We provide 3 paid plans that users can subscribe to: Basic, Advanced and Pro.
72+
Additionally, we provide an Enterprise plan, this plan is customized for each customer,
73+
and it's manually created by the RTD core team.
74+
75+
To create a custom plan, you need to create a new product in Stripe,
76+
and add the product id to the ``RTD_PRODUCTS`` setting mapped to the features that the plan will provide.
77+
After that, you can create a subscription for the organization with the custom product,
78+
our appliction will automatically relate this new product to the organization.
79+
80+
Extra products
81+
--------------
82+
83+
We have one extra product: Extra builder.
84+
85+
To create a new extra product, you need to create a new product in Stripe,
86+
and add the product id to the ``RTD_PRODUCTS`` setting mapped to the features that the
87+
extra product will provide, this product should have the ``extra`` attribute set to ``True``.
88+
89+
To subscribe an organization to an extra product,
90+
you just need to add the product to its subscription with the desired quantity,
91+
our appliction will automatically relate this new product to the organization.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "readthedocs",
3-
"version": "9.16.4",
3+
"version": "10.0.0",
44
"description": "Read the Docs build dependencies",
55
"author": "Read the Docs, Inc <[email protected]>",
66
"scripts": {

pytest.ini

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ filterwarnings =
2222
ignore:DateTimeField .* received a naive datetime .* while time zone support is active:RuntimeWarning
2323
ignore:.*:DeprecationWarning
2424

25-
ignore:.*:django.utils.deprecation.RemovedInDjango40Warning
26-
ignore:.*:django.utils.deprecation.RemovedInDjango41Warning
25+
ignore:.*:django.utils.deprecation.RemovedInDjango50Warning
2726
ignore:.*:elasticsearch.exceptions.ElasticsearchWarning
2827
ignore:.*:PendingDeprecationWarning

readthedocs/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Read the Docs."""
22

33

4-
__version__ = "9.16.4"
4+
__version__ = "10.0.0"

readthedocs/acl/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BACKEND_REQUEST_KEY = '_auth_request_key'
1+
BACKEND_REQUEST_KEY = "_auth_request_key"

readthedocs/analytics/admin.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
from .models import PageView
66

77

8+
@admin.register(PageView)
89
class PageViewAdmin(admin.ModelAdmin):
9-
raw_id_fields = ('project', 'version')
10-
list_display = ('project', 'version', 'path', 'view_count', 'date')
11-
search_fields = ('project__slug', 'version__slug', 'path')
12-
readonly_fields = ('date',)
13-
list_select_related = ('project', 'version', 'version__project')
14-
15-
16-
admin.site.register(PageView, PageViewAdmin)
10+
raw_id_fields = ("project", "version")
11+
list_display = ("project", "version", "path", "view_count", "date")
12+
search_fields = ("project__slug", "version__slug", "path")
13+
readonly_fields = ("date",)
14+
list_select_related = ("project", "version", "version__project")

readthedocs/analytics/apps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ class AnalyticsAppConfig(AppConfig):
88
"""Analytics app init code."""
99

1010
default_auto_field = "django.db.models.BigAutoField"
11-
name = 'readthedocs.analytics'
12-
verbose_name = 'Analytics'
11+
name = "readthedocs.analytics"
12+
verbose_name = "Analytics"

readthedocs/analytics/migrations/0001_initial.py

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,49 @@
66

77

88
class Migration(migrations.Migration):
9-
109
initial = True
1110

1211
dependencies = [
13-
('builds', '0022_migrate_protected_versions'),
14-
('projects', '0048_remove_version_privacy_field'),
12+
("builds", "0022_migrate_protected_versions"),
13+
("projects", "0048_remove_version_privacy_field"),
1514
]
1615

1716
operations = [
1817
migrations.CreateModel(
19-
name='PageView',
18+
name="PageView",
2019
fields=[
21-
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22-
('path', models.CharField(max_length=4096)),
23-
('view_count', models.PositiveIntegerField(default=0)),
24-
('date', models.DateField(db_index=True, default=datetime.date.today)),
25-
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_views', to='projects.Project')),
26-
('version', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_views', to='builds.Version', verbose_name='Version')),
20+
(
21+
"id",
22+
models.AutoField(
23+
auto_created=True,
24+
primary_key=True,
25+
serialize=False,
26+
verbose_name="ID",
27+
),
28+
),
29+
("path", models.CharField(max_length=4096)),
30+
("view_count", models.PositiveIntegerField(default=0)),
31+
("date", models.DateField(db_index=True, default=datetime.date.today)),
32+
(
33+
"project",
34+
models.ForeignKey(
35+
on_delete=django.db.models.deletion.CASCADE,
36+
related_name="page_views",
37+
to="projects.Project",
38+
),
39+
),
40+
(
41+
"version",
42+
models.ForeignKey(
43+
on_delete=django.db.models.deletion.CASCADE,
44+
related_name="page_views",
45+
to="builds.Version",
46+
verbose_name="Version",
47+
),
48+
),
2749
],
2850
options={
29-
'unique_together': {('project', 'version', 'path', 'date')},
51+
"unique_together": {("project", "version", "path", "date")},
3052
},
3153
),
3254
]

readthedocs/analytics/migrations/0002_track_status_code.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66

77
class Migration(migrations.Migration):
8-
98
dependencies = [
109
("builds", "0041_track_task_id"),
1110
("projects", "0087_use_booleanfield_null"),

readthedocs/analytics/migrations/0003_remove_index.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77

88
class Migration(migrations.Migration):
9-
109
dependencies = [
1110
("analytics", "0002_track_status_code"),
1211
]

readthedocs/analytics/migrations/0004_merge_duplicate_records.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def forwards_func(apps, schema_editor):
2929

3030

3131
class Migration(migrations.Migration):
32-
3332
dependencies = [
3433
("analytics", "0003_remove_index"),
3534
]

readthedocs/analytics/migrations/0005_add_unique_constraint.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55

66
class Migration(migrations.Migration):
7-
87
dependencies = [
98
("analytics", "0004_merge_duplicate_records"),
109
]

readthedocs/analytics/migrations/0006_alter_pageview_id.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55

66
class Migration(migrations.Migration):
7-
87
dependencies = [
98
("analytics", "0005_add_unique_constraint"),
109
]

0 commit comments

Comments
 (0)