* dev: initiate external apis * dev: external api * dev: external public api implementation * dev: add prefix to all api tokens * dev: flag to enable disable api token api access * dev: webhook model create and apis * dev: webhook settings * fix: webhook logs * chore: removed drf spectacular * dev: remove retry_count and fix api logging for get requests * dev: refactor webhook logic * fix: celery retry mechanism * chore: event and action change * chore: migrations changes * dev: proxy setup for apis * chore: changed retry time and cleanup * chore: added issue comment and inbox issue api endpoints * fix: migration files * fix: added env variables * fix: removed issue attachment from proxy * fix: added new migration file * fix: restricted wehbook access * chore: changed urls * chore: fixed porject serializer * fix: set expire for api token * fix: retrive endpoint for api token * feat: Api Token screens & api integration * dev: webhook endpoint changes * dev: add fields for webhook updates * feat: Download Api secret key * chore: removed BASE API URL * feat: revoke token access * dev: migration fixes * feat: workspace webhooks (#2748) * feat: workspace webhook store, services integeration and rendered webhook list and create * chore: handled webhook update and rengenerate token in workspace webhooks * feat: regenerate key and delete functionality --------- Co-authored-by: Ramesh Kumar <rameshkumar@rameshs-MacBook-Pro.local> Co-authored-by: gurusainath <gurusainath007@gmail.com> Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com> * fix: url validation added * fix: seperated env for webhook and api * Web hooks refactoring * add show option for generated hook key * Api token restructure * webhook minor fixes * fix build errors * chore: improvements in file structring * dev: rate limiting the open apis --------- Co-authored-by: pablohashescobar <nikhilschacko@gmail.com> Co-authored-by: LAKHAN BAHETI <lakhanbaheti9@gmail.com> Co-authored-by: rahulramesha <71900764+rahulramesha@users.noreply.github.com> Co-authored-by: Ramesh Kumar <rameshkumar@rameshs-MacBook-Pro.local> Co-authored-by: gurusainath <gurusainath007@gmail.com> Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com> Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com> Co-authored-by: rahulramesha <rahulramesham@gmail.com>
101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
# Python imports
|
|
import re
|
|
import json
|
|
import requests
|
|
|
|
# Django imports
|
|
from django.conf import settings
|
|
|
|
# Third party imports
|
|
from rest_framework.views import APIView
|
|
from rest_framework.response import Response
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
|
|
# Module imports
|
|
from plane.authentication.api_authentication import APIKeyAuthentication
|
|
from plane.proxy.rate_limit import ApiKeyRateThrottle
|
|
|
|
|
|
class BaseAPIView(APIView):
|
|
authentication_classes = [
|
|
APIKeyAuthentication,
|
|
]
|
|
|
|
permission_classes = [
|
|
IsAuthenticated,
|
|
]
|
|
|
|
throttle_classes = [
|
|
ApiKeyRateThrottle,
|
|
]
|
|
|
|
def _get_jwt_token(self, request):
|
|
refresh = RefreshToken.for_user(request.user)
|
|
return str(refresh.access_token)
|
|
|
|
def _get_url_path(self, request):
|
|
match = re.search(r"/v1/(.*)", request.path)
|
|
return match.group(1) if match else ""
|
|
|
|
def _get_headers(self, request):
|
|
return {
|
|
"Authorization": f"Bearer {self._get_jwt_token(request=request)}",
|
|
"Content-Type": request.headers.get("Content-Type", "application/json"),
|
|
}
|
|
|
|
def _get_url(self, request):
|
|
path = self._get_url_path(request=request)
|
|
url = request.build_absolute_uri("/api/" + path)
|
|
return url
|
|
|
|
def _get_query_params(self, request):
|
|
query_params = request.GET
|
|
return query_params
|
|
|
|
def _get_payload(self, request):
|
|
content_type = request.headers.get("Content-Type", "application/json")
|
|
if content_type.startswith("multipart/form-data"):
|
|
files_dict = {k: v[0] for k, v in request.FILES.lists()}
|
|
return (None, files_dict)
|
|
else:
|
|
return (json.dumps(request.data), None)
|
|
|
|
def _make_request(self, request, method="GET"):
|
|
data_payload, files_payload = self._get_payload(request=request)
|
|
response = requests.request(
|
|
method=method,
|
|
url=self._get_url(request=request),
|
|
headers=self._get_headers(request=request),
|
|
params=self._get_query_params(request=request),
|
|
data=data_payload,
|
|
files=files_payload,
|
|
)
|
|
return response.json(), response.status_code
|
|
|
|
def finalize_response(self, request, response, *args, **kwargs):
|
|
# Call super to get the default response
|
|
response = super().finalize_response(request, response, *args, **kwargs)
|
|
|
|
# Add custom headers if they exist in the request META
|
|
ratelimit_remaining = request.META.get('X-RateLimit-Remaining')
|
|
if ratelimit_remaining is not None:
|
|
response['X-RateLimit-Remaining'] = ratelimit_remaining
|
|
|
|
ratelimit_reset = request.META.get('X-RateLimit-Reset')
|
|
if ratelimit_reset is not None:
|
|
response['X-RateLimit-Reset'] = ratelimit_reset
|
|
|
|
return response
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
response, status_code = self._make_request(request=request, method="GET")
|
|
return Response(response, status=status_code)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
response, status_code = self._make_request(request=request, method="POST")
|
|
return Response(response, status=status_code)
|
|
|
|
def partial_update(self, request, *args, **kwargs):
|
|
response, status_code = self._make_request(request=request, method="PATCH")
|
|
return Response(response, status=status_code)
|