Skip to content

Commit

Permalink
feature: generic listing and detail for externals
Browse files Browse the repository at this point in the history
  • Loading branch information
elitonzky committed May 4, 2023
1 parent 2b57363 commit 311a8c9
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
3 changes: 3 additions & 0 deletions weni/internal/externals/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from django.urls import path
from weni.internal.externals.views import ExternalServicesAPIView
from weni.internal.externals.views import GenericExternals


urlpatterns = [
path("externals", ExternalServicesAPIView.as_view(), name="api.v2.externals"),
path(r"externals/<str:uuid>/", ExternalServicesAPIView.as_view(), name="api.v2.externals"),
path("externals/generic", GenericExternals.as_view(), name="api.v2.externals.generic.list"),
path(r"externals/generic/<str:type>/", GenericExternals.as_view(), name="api.v2.externals.generic.detail"),
]
121 changes: 121 additions & 0 deletions weni/internal/externals/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

import inspect

from typing import TYPE_CHECKING

from django.contrib.auth.models import User
Expand All @@ -13,6 +16,7 @@
from weni.internal.externals.serializers import ExternalServicesSerializer
from temba.externals.models import ExternalService

from temba.externals.types import TYPES

if TYPE_CHECKING:
from rest_framework.request import Request
Expand All @@ -39,3 +43,120 @@ def delete(self, request, uuid=None):
external_service.release(user)

return Response(status=status.HTTP_204_NO_CONTENT)


class GenericExternals(APIView):
authentication_classes = [InternalOIDCAuthentication]
permission_classes = [IsAuthenticated, CanCommunicateInternally]
pagination_class = None
renderer_classes = [JSONRenderer]
throttle_classes = []

def get(self, request, type=None):
if type:
return self.retrieve(request, type)

external_types = {}
for value in TYPES:
fields_types = {}
attributes_type = extract_type_info(TYPES[value])
if not attributes_type:
return Response(status=status.HTTP_404_NOT_FOUND)

fields_types['attributes'] = attributes_type
external_types[value] = fields_types

payload = {
"external_types": external_types,
}
return Response(payload)

def retrieve(self, request, type=None):
external_type = TYPES.get(type, None)
if not external_type:
return Response(status=status.HTTP_404_NOT_FOUND)

fields_form = {}
fields_in_form = []
if external_type.connect_view and external_type.connect_view.form_class:
form = external_type.connect_view.form_class.base_fields
for field in form:
fields_in_form.append(extract_form_info(form[field], field))

if not fields_in_form:
return Response(status=status.HTTP_404_NOT_FOUND)

fields_form['form'] = fields_in_form

fields_types = {}
attributes_type = extract_type_info(external_type)
if not attributes_type:
return Response(status=status.HTTP_404_NOT_FOUND)

fields_types['attributes'] = attributes_type

payload = {
"attributes": fields_types.get('attributes'),
"form": fields_form.get('form')
}

return Response(payload)


def extract_type_info(cls):
"""
Extracts information about a class instance.
Parameters:
cls (object): An instance of a class.
Returns:
dict: A dictionary containing information about the class instance.
"""
excluded_types = {"<class 'function'>"}
excluded_items = {"CONFIG_APP_KEY", "CONFIG_APP_SECRET", "connect_blurb", "icon"}
info = {}

for name, value in cls.__class__.__dict__.items():
if name.startswith("_") or inspect.isclass(value) \
or str(type(value)) in excluded_types or name in excluded_items:
continue

info[name] = value

if not info or "name" not in info:
return None

return info


def extract_form_info(form, name_form):
"""
Extracts information about a form field.
Parameters:
form (django.forms): The form field to extract information from.
name_form (str): The name of the form field.
Returns:
dict: A dictionary containing information about the form field.
"""
detail = {}
detail["name"] = name_form if name_form else None

try:
detail["type"] = str(form.widget.input_type)
except AttributeError:
detail["type"] = None

detail["help_text"] = str(form.help_text) if form.help_text else None

if detail.get("type") == "select":
detail["choices"] = form.choices

detail["label"] = str(form.label) if form.label else None

if not detail.get("name") or not detail.get("type"):
return None

return detail

0 comments on commit 311a8c9

Please sign in to comment.