|
1 | 1 | """Views for builds app."""
|
2 | 2 |
|
| 3 | +import signal |
| 4 | + |
3 | 5 | import structlog
|
4 | 6 | import textwrap
|
5 | 7 | from urllib.parse import urlparse
|
|
21 | 23 | from readthedocs.doc_builder.exceptions import BuildAppError
|
22 | 24 | from readthedocs.projects.models import Project
|
23 | 25 |
|
| 26 | +try: |
| 27 | + from readthedocsinc.worker import app |
| 28 | +except ImportError: |
| 29 | + from readthedocs.worker import app |
| 30 | + |
| 31 | + |
24 | 32 | log = structlog.get_logger(__name__)
|
25 | 33 |
|
26 | 34 |
|
@@ -148,6 +156,22 @@ class BuildDetail(BuildBase, DetailView):
|
148 | 156 |
|
149 | 157 | pk_url_kwarg = 'build_pk'
|
150 | 158 |
|
| 159 | + @method_decorator(login_required) |
| 160 | + def post(self, request, project_slug, build_pk): |
| 161 | + project = get_object_or_404(Project, slug=project_slug) |
| 162 | + build = get_object_or_404(Build, pk=build_pk) |
| 163 | + |
| 164 | + if not AdminPermission.is_admin(request.user, project): |
| 165 | + return HttpResponseForbidden() |
| 166 | + |
| 167 | + # NOTE: `terminate=True` is required for the child to attend our call |
| 168 | + # immediately. Otherwise, it finishes the task. |
| 169 | + app.control.revoke(build.task_id, signal=signal.SIGINT, terminate=True) |
| 170 | + |
| 171 | + return HttpResponseRedirect( |
| 172 | + reverse('builds_detail', args=[project.slug, build.pk]), |
| 173 | + ) |
| 174 | + |
151 | 175 | def get_context_data(self, **kwargs):
|
152 | 176 | context = super().get_context_data(**kwargs)
|
153 | 177 | context['project'] = self.project
|
|
0 commit comments