|
1 | 1 | import json |
2 | 2 | from collections import defaultdict |
3 | 3 | from datetime import datetime |
4 | | -from functools import wraps |
5 | | -from typing import Callable |
6 | 4 |
|
7 | 5 | from django import forms |
8 | 6 | from django.core.handlers.wsgi import WSGIRequest |
9 | 7 | from django.http import HttpRequest, JsonResponse |
10 | 8 | from django.utils.decorators import method_decorator |
11 | 9 | from django.utils.html import escape |
12 | 10 | from django.views import View |
13 | | -from django.views.decorators.csrf import csrf_exempt |
14 | 11 |
|
15 | 12 | from lando.api.legacy.commit_message import replace_reviewers |
16 | 13 | from lando.main.auth import require_authenticated_user |
17 | 14 | from lando.main.models import ( |
18 | | - CommitMap, |
19 | 15 | JobStatus, |
20 | 16 | LandingJob, |
21 | 17 | Repo, |
22 | 18 | Revision, |
23 | 19 | add_revisions_to_job, |
24 | 20 | ) |
25 | 21 | from lando.main.models.landing_job import get_jobs_for_pull |
26 | | -from lando.main.models.revision import DiffWarning, DiffWarningStatus |
27 | | -from lando.main.scm import SCMType |
28 | 22 | from lando.utils.github import GitHubAPIClient, PullRequest, PullRequestPatchHelper |
29 | 23 | from lando.utils.github_checks import ( |
30 | 24 | ALL_PULL_REQUEST_BLOCKERS, |
31 | 25 | ALL_PULL_REQUEST_WARNINGS, |
32 | 26 | PullRequestChecks, |
33 | 27 | ) |
34 | 28 | from lando.utils.landing_checks import LandingChecks |
35 | | -from lando.utils.phabricator import PHABRICATOR_API_KEY_HEADER, get_phabricator_client |
36 | | - |
37 | | - |
38 | | -class APIView(View): |
39 | | - """A base class for API views.""" |
40 | | - |
41 | | - pass |
42 | | - |
43 | | - |
44 | | -def phabricator_api_key_required(func: Callable) -> Callable: |
45 | | - """A simple wrapper that checks for a valid Phabricator API token.""" |
46 | | - |
47 | | - @wraps(func) |
48 | | - def _wrapper(self: View, request: WSGIRequest, *args, **kwargs) -> Callable: |
49 | | - if PHABRICATOR_API_KEY_HEADER not in request.headers: |
50 | | - return JsonResponse( |
51 | | - {"error": f"{PHABRICATOR_API_KEY_HEADER} missing."}, status=400 |
52 | | - ) |
53 | | - |
54 | | - api_key = request.headers[PHABRICATOR_API_KEY_HEADER] |
55 | | - client = get_phabricator_client(api_key=api_key) |
56 | | - if not client.verify_api_token(): |
57 | | - return JsonResponse({"error": "Invalid Phabricator API token."}, status=401) |
58 | | - |
59 | | - return func(self, request, *args, **kwargs) |
60 | | - |
61 | | - return _wrapper |
62 | 29 |
|
63 | 30 |
|
64 | 31 | def generate_warnings_and_blockers( |
@@ -92,117 +59,6 @@ def generate_warnings_and_blockers( |
92 | 59 | return {"warnings": warnings, "blockers": blockers} |
93 | 60 |
|
94 | 61 |
|
95 | | -@method_decorator(csrf_exempt, name="dispatch") |
96 | | -class LegacyDiffWarningView(View): |
97 | | - """ |
98 | | - This class provides the API controllers for the legacy `DiffWarning` model. |
99 | | -
|
100 | | - These API endpoints can be used by clients (such as Code Review bot) to |
101 | | - get, create, or archive warnings. |
102 | | - """ |
103 | | - |
104 | | - @phabricator_api_key_required |
105 | | - def post(self, request: WSGIRequest) -> JsonResponse: |
106 | | - """Create a new `DiffWarning` based on provided revision and diff IDs. |
107 | | -
|
108 | | - Args: |
109 | | - data (dict): A dictionary containing data to store in the warning. `data` |
110 | | - should contain at least a `message` key that contains the message to |
111 | | - show in the warning. |
112 | | -
|
113 | | - Returns: |
114 | | - dict: a dictionary representation of the object that was created. |
115 | | - """ |
116 | | - |
117 | | - class Form(forms.Form): |
118 | | - def data_validator(data): |
119 | | - if not data or "message" not in data: |
120 | | - raise forms.ValidationError( |
121 | | - "Provided data is missing the message value" |
122 | | - ) |
123 | | - |
124 | | - revision_id = forms.IntegerField() |
125 | | - diff_id = forms.IntegerField() |
126 | | - group = forms.CharField() |
127 | | - data = forms.JSONField(validators=[data_validator]) |
128 | | - |
129 | | - # TODO: validate whether revision/diff exist or not. |
130 | | - form = Form(json.loads(request.body)) |
131 | | - if form.is_valid(): |
132 | | - data = form.cleaned_data |
133 | | - warning = DiffWarning.objects.create(**data) |
134 | | - return JsonResponse(warning.serialize(), status=201) |
135 | | - |
136 | | - return JsonResponse({"errors": dict(form.errors)}, status=400) |
137 | | - |
138 | | - @phabricator_api_key_required |
139 | | - def delete(self, request: WSGIRequest, diff_warning_id: int) -> JsonResponse: |
140 | | - """Archive a `DiffWarning` based on provided pk.""" |
141 | | - warning = DiffWarning.objects.get(pk=diff_warning_id) |
142 | | - if not warning: |
143 | | - return JsonResponse({}, status=404) |
144 | | - |
145 | | - warning.status = DiffWarningStatus.ARCHIVED |
146 | | - warning.save() |
147 | | - return JsonResponse(warning.serialize(), status=200) |
148 | | - |
149 | | - @phabricator_api_key_required |
150 | | - def get(self, request: WSGIRequest, **kwargs) -> JsonResponse: |
151 | | - """Return a list of active revision diff warnings, if any.""" |
152 | | - |
153 | | - class Form(forms.Form): |
154 | | - revision_id = forms.IntegerField() |
155 | | - diff_id = forms.IntegerField() |
156 | | - group = forms.CharField() |
157 | | - |
158 | | - form = Form(request.GET) |
159 | | - if form.is_valid(): |
160 | | - warnings = DiffWarning.objects.filter(**form.cleaned_data).all() |
161 | | - return JsonResponse( |
162 | | - [warning.serialize() for warning in warnings], status=200, safe=False |
163 | | - ) |
164 | | - |
165 | | - return JsonResponse({"errors": dict(form.errors)}, status=400) |
166 | | - |
167 | | - |
168 | | -class CommitMapBaseView(View): |
169 | | - """CommitMap base view to be extended for bidirectional git - hg mapping.""" |
170 | | - |
171 | | - scm: str |
172 | | - |
173 | | - def get( |
174 | | - self, request: WSGIRequest, git_repo_name: str, commit_hash: str |
175 | | - ) -> JsonResponse: |
176 | | - try: |
177 | | - commit = CommitMap.map_hash_from(self.scm, git_repo_name, commit_hash) |
178 | | - except CommitMap.DoesNotExist as exc: |
179 | | - error_detail = f"No commit found in {self.scm} for {commit_hash} in {git_repo_name}: {exc}" |
180 | | - return JsonResponse( |
181 | | - {"error": "No commits found", "detail": error_detail}, status=404 |
182 | | - ) |
183 | | - except CommitMap.MultipleObjectsReturned as exc: |
184 | | - error_detail = f"Multiple commits found in {self.scm} for {commit_hash} in {git_repo_name}: {exc}" |
185 | | - return JsonResponse( |
186 | | - {"error": "Multiple commits found", "detail": error_detail}, status=400 |
187 | | - ) |
188 | | - |
189 | | - return JsonResponse(commit.serialize(), status=200) |
190 | | - |
191 | | - |
192 | | -@method_decorator(csrf_exempt, name="dispatch") |
193 | | -class git2hgCommitMapView(CommitMapBaseView): |
194 | | - """Return corresponding CommitMap given a git hash.""" |
195 | | - |
196 | | - scm = SCMType.GIT |
197 | | - |
198 | | - |
199 | | -@method_decorator(csrf_exempt, name="dispatch") |
200 | | -class hg2gitCommitMapView(CommitMapBaseView): |
201 | | - """Return corresponding CommitMap given an hg hash.""" |
202 | | - |
203 | | - scm = SCMType.HG |
204 | | - |
205 | | - |
206 | 62 | class PullRequestAPIView(View): |
207 | 63 | """Set various common attributes for views that extend this one.""" |
208 | 64 |
|
@@ -314,7 +170,7 @@ class Form(forms.Form): |
314 | 170 | return JsonResponse({"id": job.id}, status=201) |
315 | 171 |
|
316 | 172 |
|
317 | | -class PullRequestChecksAPIView(PullRequestAPIView): |
| 173 | +class ChecksPullRequestAPIView(PullRequestAPIView): |
318 | 174 | def get( |
319 | 175 | self, request: WSGIRequest, repo_name: str, pull_number: int |
320 | 176 | ) -> JsonResponse: |
|
0 commit comments