Commit b1f1f3e4 authored by Florent Chehab's avatar Florent Chehab

Further improvements to backend dynamic imports

parent 304fa96f
Pipeline #36173 passed with stages
in 4 minutes and 51 seconds
from django.contrib import admin
from reversion_compare.admin import CompareVersionAdmin
from shared import get_api_config, get_api_objs
api_config = get_api_config()
from shared import get_api_objs
VERSIONNED_MODELS = map(
lambda obj: obj.Model,
......
from django.contrib.auth.models import User
from django.db import models
from rest_framework import serializers
from backend_app.models.university import University
from backend_app.fields import JSONField
from backend_app.models.abstract.my_model import (
MyModel,
MyModelSerializer,
MyModelViewSet,
)
from django.contrib.auth.models import User
from backend_app.utils import get_viewset_permissions, get_model_config, get_user_level
from backend_app.models.university import University
from backend_app.permissions.__list_user_post_permission import (
list_user_post_permission,
)
from backend_app.utils import get_model_config, get_user_level, get_viewset_permissions
from rest_framework import serializers
class UserData(MyModel):
......
from django.conf import settings
from dotmap import DotMap
from typing import List
from shared import get_api_config
import importlib
from django.contrib.auth.models import User
api_config = get_api_config()
from shared import get_api_objs
ALL_VIEWSETS = {}
for model in api_config:
model = DotMap(model)
if "is_api_view" in model and model.is_api_view:
continue
if not model.requires_testing:
if model.viewset != "UserDataViewSet":
module = importlib.import_module(
"backend_app.models.{}".format(model.import_location)
)
ALL_VIEWSETS[model.viewset] = getattr(module, model.viewset)
if settings.TESTING:
for model in api_config:
model = DotMap(model)
if "is_api_view" in model and model.is_api_view:
continue
if model.requires_testing:
if model.viewset != "UserDataViewSet":
module = importlib.import_module(
"backend_app.models.{}".format(model.import_location)
)
ALL_VIEWSETS[model.viewset] = getattr(module, model.viewset)
for api_obj in get_api_objs(
has_model=None,
requires_testing=False,
is_api_view=False,
ignore_models=["UserData"],
):
ALL_VIEWSETS[api_obj.viewset] = api_obj.Viewset
for api_obj in get_api_objs(
has_model=None, requires_testing=True, is_api_view=False, ignore_models=["UserData"]
):
ALL_VIEWSETS[api_obj.viewset] = api_obj.Viewset
class Request(object):
......@@ -38,7 +26,11 @@ class Request(object):
self.method = method
def list_user_post_permission(user):
def list_user_post_permission(user: User) -> List[str]:
"""
Function the list the viewset to which a user can submit a post request to.
"""
viewsets_user_can_post = []
request = Request(user, "POST")
for viewset_name in ALL_VIEWSETS:
......
from django.conf import settings
from django.conf.urls import include, url
from rest_framework import routers
from rest_framework.documentation import include_docs_urls
from backend_app.permissions import DEFAULT_VIEWSET_PERMISSIONS
from shared import get_api_config
from shared import get_api_objs
from dotmap import DotMap
from .other_viewsets import AppModerationStatusViewSet
import importlib
urlpatterns = [url(r"^api-docs/", include_docs_urls(title="Outgoing API"))]
router = routers.DefaultRouter()
ALL_MODELS = []
ALL_VIEWSETS = []
ALL_MODELS = map(
lambda obj: obj.Model,
get_api_objs(has_model=True, ignore_in_admin=False, requires_testing="smart"),
)
# Automatically load models and viewset based on API config file
api_config = get_api_config()
ALL_VIEWSETS = []
for entry in api_config:
model_obj = DotMap(entry)
if "is_api_view" in model_obj and model_obj.is_api_view:
continue
if (not model_obj.requires_testing) or (
settings.TESTING and model_obj.requires_testing
):
module = importlib.import_module(
"backend_app.models.{}".format(model_obj.import_location)
)
Viewset = getattr(module, model_obj.viewset)
ALL_VIEWSETS.append(Viewset)
if model_obj.model is not None and not model_obj.ignore_in_admin:
ALL_MODELS.append(getattr(module, model_obj.model))
for api_obj in get_api_objs(
has_model=None, requires_testing="smart", is_api_view=False
):
ALL_VIEWSETS.append(api_obj.Viewset)
# Creating the correct router entry
str_url = model_obj.api_end_point
if "api_attr" in model_obj:
str_url += "/{}".format(model_obj.api_attr)
if "api_name" in model_obj:
router.register(str_url, Viewset, model_obj.api_name)
else:
router.register(str_url, Viewset)
# Creating the correct router entry
str_url = api_obj.api_end_point
if "api_attr" in api_obj:
str_url += "/{}".format(api_obj.api_attr)
if "api_name" in api_obj:
router.register(str_url, api_obj.Viewset, api_obj.api_name)
else:
router.register(str_url, api_obj.Viewset)
# Add all the endpoints for the base api
urlpatterns += [
url(r"^api/", include(router.urls)),
url(r"^api/serverModerationStatus/", AppModerationStatusViewSet.as_view()),
]
urlpatterns.append(url(r"^api/", include(router.urls)))
for api_obj in get_api_objs(has_model=None, requires_testing="smart", is_api_view=True):
urlpatterns.append(
url(r"^api/{}/".format(api_obj.api_end_point), api_obj.Viewset.as_view())
)
#######
# Models and Viewset checks
......
from shared import get_api_config
from shared import load_api_config
def find_api_end_point_for_viewset(viewset_name):
api_config = get_api_config()
api_config = load_api_config()
for obj in api_config:
if obj["viewset"] == viewset_name:
return obj["api_end_point"]
......
from shared import get_api_config
from shared import load_api_config
def get_model_config(model):
api_config = get_api_config()
api_config = load_api_config()
for obj in api_config:
if "is_api_view" in obj and obj["is_api_view"]:
......
......@@ -8,11 +8,11 @@ from backend_app.permissions import (
)
from rest_framework.permissions import IsAdminUser
from backend_app.permissions import DEFAULT_VIEWSET_PERMISSIONS
from shared import get_api_config
from shared import load_api_config
def get_viewset_permissions(viewset):
api_config = get_api_config()
api_config = load_api_config()
for obj in api_config:
if obj["viewset"] == viewset:
custom_permission = obj["viewset_permission"]
......
from .get_api_config import get_api_config, get_api_objs
from .get_api_config import load_api_config, get_api_objs
from .obj_moderation_permission import (
DEFAULT_OBJ_MODERATION_LV,
OBJ_MODERATION_PERMISSIONS,
)
__all__ = [
"get_api_config",
"load_api_config",
"DEFAULT_OBJ_MODERATION_LV",
"OBJ_MODERATION_PERMISSIONS",
"get_api_objs",
......
......@@ -38,6 +38,7 @@
- viewset: AppModerationStatusViewSet
api_end_point: serverModerationStatus
import_location: other_viewsets
read_only: true
is_api_view: true
......
import importlib
from os.path import dirname, join, realpath
from typing import List, Optional, Union, Dict
from django.conf import settings
import yaml
from os.path import join, realpath, dirname
from .obj_moderation_permission import OBJ_MODERATION_PERMISSIONS
from dotmap import DotMap
from django.conf import settings
import importlib
from .obj_moderation_permission import OBJ_MODERATION_PERMISSIONS
def get_api_config():
def load_api_config() -> List[Dict]:
"""
Returns the list of api objects without filtering add default attributes
added to all objects if they are missing.
"""
current_dir = dirname(realpath(__file__))
with open(join(current_dir, "api_config.yml"), "r") as f:
api_config = yaml.load(f)
......@@ -35,16 +44,26 @@ def get_api_config():
def get_api_objs(
has_model,
ignore_in_admin=None,
versionned=None,
requires_testing=None,
is_api_view=False,
) -> dict:
has_model: Optional[bool],
ignore_in_admin: Optional[bool] = None,
versionned: Optional[bool] = None,
requires_testing: Union[None, bool, "smart"] = None,
is_api_view: Optional[bool] = False,
ignore_models: List[str] = list(),
) -> List[DotMap]:
"""
Returns a list of DotMap objects corresponding the api config file
with filtering applied to some attributes.
If the parameter is `None` then no filtering is applied to this attribute.
If the parameter is `True` or `False` the object is returned only if it matched.
There is one exception for the parameter `requires_testing` if it is set to `smart` then
the object is returned only if doesn't require testing or if testing is activated.
"""
out = list()
for entry in get_api_config():
for entry in load_api_config():
obj = DotMap(entry)
if has_model is not None:
......@@ -66,12 +85,16 @@ def get_api_objs(
continue
if requires_testing is not None:
if requires_testing and not settings.TESTING:
continue
if requires_testing and not obj.requires_testing:
continue
if not requires_testing and obj.requires_testing:
continue
if requires_testing == "smart":
if obj.requires_testing and not settings.TESTING:
continue
else:
if requires_testing and not settings.TESTING:
continue
if requires_testing and not obj.requires_testing:
continue
if not requires_testing and obj.requires_testing:
continue
if is_api_view is not None:
if is_api_view and not obj.is_api_view:
......@@ -84,6 +107,8 @@ def get_api_objs(
)
if obj.model is not None:
if obj.model in ignore_models:
continue
Model = getattr(module, obj.model)
obj.Model = Model
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment