Skip to content

Commit fab04cc

Browse files
committed
Notify users about the usage of deprecated webhooks
Each time a deprecated webhook is hit, a notification is created (without duplicating it) to be sent.
1 parent 1648006 commit fab04cc

File tree

8 files changed

+93
-1
lines changed

8 files changed

+93
-1
lines changed

readthedocs/core/views/hooks.py

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from readthedocs.core.utils import trigger_build
1212
from readthedocs.builds.constants import LATEST
13+
from readthedocs.notifications.decorators import notify_deprecated_endpoint
1314
from readthedocs.projects import constants
1415
from readthedocs.projects.models import Project, Feature
1516
from readthedocs.projects.tasks import sync_repository_task
@@ -141,6 +142,7 @@ def _build_url(url, projects, branches):
141142

142143

143144
@csrf_exempt
145+
@notify_deprecated_endpoint
144146
def github_build(request): # noqa: D205
145147
"""
146148
GitHub webhook consumer.
@@ -196,6 +198,7 @@ def github_build(request): # noqa: D205
196198

197199

198200
@csrf_exempt
201+
@notify_deprecated_endpoint
199202
def gitlab_build(request): # noqa: D205
200203
"""
201204
GitLab webhook consumer.
@@ -231,6 +234,7 @@ def gitlab_build(request): # noqa: D205
231234

232235

233236
@csrf_exempt
237+
@notify_deprecated_endpoint
234238
def bitbucket_build(request):
235239
"""
236240
Consume webhooks from multiple versions of Bitbucket's API.
@@ -307,6 +311,7 @@ def bitbucket_build(request):
307311

308312

309313
@csrf_exempt
314+
@notify_deprecated_endpoint
310315
def generic_build(request, project_id_or_slug=None):
311316
"""
312317
Generic webhook build endpoint.

readthedocs/notifications/backends.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def send_notification(request, notification):
3333
for cls_name in backends:
3434
backend = import_string(cls_name)(request)
3535
# Do not send email notification if defined explicitly
36-
if backend.name == EmailBackend.name and not notification.send_email:
36+
if backend.name in EmailBackend.name and not notification.send_email:
3737
pass
3838
else:
3939
backend.send(notification)
@@ -79,6 +79,33 @@ def send(self, notification):
7979
)
8080

8181

82+
class DelayedEmailBackend(Backend):
83+
84+
"""
85+
Delay an email to be sent in the future.
86+
87+
This backend adds the message into the storage, which will be consumed later
88+
by a Celery task that will send the email.
89+
"""
90+
91+
name = 'delayed_email'
92+
93+
def send(self, notification):
94+
cls_name = settings.MESSAGE_STORAGE
95+
cls = import_string(cls_name)
96+
storage = cls(self.request)
97+
98+
storage.add(
99+
level=notification.level,
100+
message=notification.render(
101+
backend_name=self.name,
102+
source_format=HTML,
103+
),
104+
extra_tags='',
105+
user=notification.user,
106+
)
107+
108+
82109
class SiteBackend(Backend):
83110

84111
"""
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import logging
4+
5+
from django.db.models import Q
6+
7+
from readthedocs.projects.models import Project
8+
from readthedocs.projects.notifications import DeprecatedWebhookEndpointNotification
9+
10+
log = logging.getLogger(__name__)
11+
12+
13+
def notify_deprecated_endpoint(function):
14+
"""
15+
Decorator to notify owners that the endpoint is DEPRECATED.
16+
"""
17+
def wrap(request, *args, project_id_or_slug=None, **kwargs):
18+
try:
19+
project = Project.objects.get(
20+
Q(pk=project_id_or_slug) | Q(slug=project_id_or_slug),
21+
)
22+
except (Project.DoesNotExist, ValueError):
23+
log.info('Project not found: slug=%s', project_id_or_slug)
24+
25+
# Send one notification to each owner of the project
26+
for user in project.users.all():
27+
notification = DeprecatedWebhookEndpointNotification(
28+
project,
29+
request,
30+
user,
31+
)
32+
notification.send()
33+
return function(request, *args, project_id_or_slug, **kwargs)
34+
35+
return wrap

readthedocs/projects/notifications.py

+7
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,10 @@ class ResourceUsageNotification(Notification):
1111
context_object_name = 'project'
1212
subject = 'Builds for {{ project.name }} are using too many resources'
1313
level = REQUIREMENT
14+
15+
16+
class DeprecatedWebhookEndpointNotification(Notification):
17+
name = 'deprecated_webhook_endpoint'
18+
context_object_name = 'project'
19+
subject = 'Project {{ project.name }} is using a deprecated webhook'
20+
level = REQUIREMENT

readthedocs/projects/tasks.py

+5
Original file line numberDiff line numberDiff line change
@@ -1364,3 +1364,8 @@ def finish_inactive_builds():
13641364
'Builds marked as "Terminated due inactivity": %s',
13651365
builds_finished,
13661366
)
1367+
1368+
1369+
@app.task
1370+
def send_deprecated_endpoint_notifications():
1371+
pass

readthedocs/settings/base.py

+5
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ def USE_PROMOS(self): # noqa
264264
'schedule': crontab(minute=0, hour='*/3'),
265265
'options': {'queue': 'web'},
266266
},
267+
'every-week-endpoint-deprecated-notifications': {
268+
'task': 'readthedocs.projects.tasks.send_deprecated_endpoint_notifications',
269+
'schedule': crontab(minute=0, hour='10', day_of_week='monday'),
270+
'options': {'queue': 'web'},
271+
},
267272
}
268273

269274
# Docker
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<p>Just a heads up, your project {{ project.name }} has configured a <em>DEPRECATED</em> webhook to trigger new builds and should be upgraded. Projects hitting these deprecated webhook will stop building on Jan 1, 2019. Please, update it soon!</p>
2+
3+
<p>To update the webhook your project is hitting, you need to go to the project's settings under your VCS service (GitHub, Bitbucket or GitLab) and remove the Read the Docs webhook from there.</p>
4+
5+
<p>Once you have done that, you need to go to your <a href="{% url "projects_integrations" project.slug %}">project's Integrations</a> under Read the Docs project's Admin, click integration and then in "Resync webhook" button.</p>
6+
7+
<p>Thanks!</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Your project {{ project.name }} has configured a <em>DEPRECATED</em> webhook to trigger new builds and should be upgraded. Projects hitting these deprecated webhooks will stop building on Jan 1, 2019. <a href="{% url "projects_integrations" project.slug %}">Please, update it soon!</a>

0 commit comments

Comments
 (0)