Skip to content

Commit

Permalink
[NEW] Location view/Lesson view
Browse files Browse the repository at this point in the history
  • Loading branch information
boot-sandre committed Sep 23, 2023
1 parent 1645f21 commit 6ff6dad
Show file tree
Hide file tree
Showing 17 changed files with 401 additions and 125 deletions.
18 changes: 10 additions & 8 deletions skii/endpoint/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import json
import logging
from ipaddress import IPv4Address, IPv6Address
from pprint import pformat
from typing import Type, Mapping, Any, cast, List

from django.core.serializers.json import DjangoJSONEncoder
Expand All @@ -17,8 +16,12 @@
from ninja.types import DictStrAny
from pydantic import BaseModel

from skii.endpoint.routers.student import sub_route as route_student
from skii.endpoint.routers.teacher import sub_route as route_teacher
from skii.endpoint.routers import (
route_student,
route_teacher,
route_location,
route_lesson,
)

# Get current package version
from packaging.version import parse as parse_version
Expand All @@ -29,6 +32,8 @@

current_package_name = __package__.split(".")[0]
distrib_version = parse_version(__import__(current_package_name).__version__)


logger.info(f"Package: {current_package_name}")
logger.info(f"Distribution version: {distrib_version}")

Expand All @@ -48,7 +53,6 @@ class SkiiJsonRenderer(BaseRenderer):
json_dumps_params: Mapping[str, Any] = {}

def render(self, request, data, *, response_status):
logger.debug(f"SkiiJsonRenderer: {pformat(data)}")
return json.dumps(data, cls=self.encoder_class, **self.json_dumps_params)


Expand Down Expand Up @@ -87,11 +91,9 @@ def configure_api_skii() -> NinjaAPI:
new_api = NinjaAPI(**api_kwargs)
new_api.add_router(prefix="student", router=route_student)
new_api.add_router(prefix="teacher", router=route_teacher)
new_api.add_router(prefix="location", router=route_location)
new_api.add_router(prefix="lesson", router=route_lesson)

from .routers import LessonEventRouter, LocationResourceRouter

LocationResourceRouter.link_with_api(api=new_api)
LessonEventRouter.link_with_api(api=new_api)
return new_api


Expand Down
11 changes: 6 additions & 5 deletions skii/endpoint/routers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from .student import sub_route as route_student
from .teacher import sub_route as route_teacher

from .location import LocationResourceRouter
from .lesson import LessonEventRouter
from .location import router as route_location
from .lesson import router as route_lesson

__all__ = [
LocationResourceRouter,
LessonEventRouter,
route_location,
route_student,
route_teacher,
route_lesson,
]
101 changes: 91 additions & 10 deletions skii/endpoint/routers/lesson.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,100 @@
from typing import List

from django.db.models import Model
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from ninja import Router

from skii.endpoint.routers.abstract import RestRouterProducer
from apps.base.schemas import FormInvalidResponseContract
from skii.endpoint.schemas.identifier import IntStrUUID4
from skii.endpoint.schemas.response import SkiiMsgContract
from skii.platform.models.common import GeoCoordinate
from skii.platform.models.event import LessonEvent
from skii.platform.schemas.event import LessonContract, LessonSaveContract


class AutomatedLessonRouter(RestRouterProducer):
class Config(RestRouterProducer.Config):
model: Model = LessonEvent
name: str = "lesson"
operation: List[str] = ["create", "read", "update", "delete", "list"]
tags = ["lesson"]
# Create a django ninja API router dedicated to the student
router = Router(tags=["lesson"])


LessonEventRouter = AutomatedLessonRouter()
RouterContract = LessonContract
RouterSaveContract = LessonSaveContract
RouterModel = LessonEvent
RouterListContract = List[RouterContract]

__all__ = [LessonEventRouter]

@router.post(
path="/create/",
response={
200: RouterContract,
422: FormInvalidResponseContract,
},
)
def record_create(request: HttpRequest, payload: RouterSaveContract):
record_payload = payload.dict()
record = RouterModel(**record_payload)
record.save()
record.refresh_from_db()
return 200, record


@router.get(
path="/read/{pk}/",
response={
200: RouterContract,
422: FormInvalidResponseContract,
},
)
def record_read(request: HttpRequest, pk: IntStrUUID4):
return 200, get_object_or_404(RouterModel, pk=pk)


@router.post(
path="/update/{pk}/",
response={
200: RouterContract,
422: FormInvalidResponseContract,
},
)
def record_update(request: HttpRequest, pk: IntStrUUID4, payload: RouterSaveContract):
record_payload = payload.dict()
if "coordinate" in record_payload:
geo_coordinate = record_payload["coordinate"]
del record_payload["coordinate"]
geo_coordinate_obj, created = GeoCoordinate.objects.update_or_create(
geo_coordinate, **geo_coordinate
)
record_payload["coordinate"] = geo_coordinate_obj
record = get_object_or_404(RouterModel, pk=pk)
for attr, value in record_payload.items():
setattr(record, attr, value)
record.save()
record.refresh_from_db()
return 200, record


@router.get(
path="/delete/{pk}/",
response={
200: SkiiMsgContract,
422: FormInvalidResponseContract,
},
)
def record_delete(request: HttpRequest, pk: IntStrUUID4):
qs = RouterModel.objects.all().filter(pk=pk)
if qs.exists():
qs.delete()
return 200, SkiiMsgContract(message="Record deleted")


@router.get(
path="/list/",
response={
200: RouterListContract,
422: FormInvalidResponseContract,
},
)
def record_list(request: HttpRequest):
return 200, RouterModel.objects.all()


__all__ = [router]
147 changes: 103 additions & 44 deletions skii/endpoint/routers/location.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,107 @@
from typing import List, Any
from typing import List

from django.db.models import Model
from ninja import Schema
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from ninja import Router

from skii.endpoint.routers.abstract import RestRouterProducer
from apps.base.schemas import FormInvalidResponseContract
from skii.endpoint.schemas.identifier import IntStrUUID4
from skii.endpoint.schemas.response import SkiiMsgContract
from skii.platform.models.common import GeoCoordinate
from skii.platform.models.resource import LocationResource
from skii.platform.schemas.common import CountryContract, GeoCoordinateContract


class AutomatedLocationRouter(RestRouterProducer):
class Config(RestRouterProducer.Config):
# Model Config
model: Model = LocationResource
name: str = "location"
# Router config
operation: List[str] = ["create", "read", "update", "delete", "list"]
base_class: Schema = IntStrUUID4
tags = ["lesson"]
# Introspection config
depth: int = 1
save_depth: int = 0
# Fields config/tweak
fields: List[str] | None = None
save_fields: List[str] | None = None
exclude_fields: List[str] | None = ["uuid"]
save_exclude_fields: List[str] | None = ["uuid"] + ["created", "last_modified"]
custom_fields: List[tuple[Any, Any, Any]] | None = [
(
"country",
CountryContract,
CountryContract.parse_obj(dict(flag="", code="", name="")),
),
(
"coordinate",
GeoCoordinateContract,
GeoCoordinateContract.parse_obj(
dict(latitude=25.4536, longitude=70.4457)
),
),
]
save_custom_fields: List[tuple[Any, Any, Any]] | None = None


LocationResourceRouter = AutomatedLocationRouter()

__all__ = [LocationResourceRouter]
from skii.platform.schemas.resource import LocationContract, LocationSaveContract


# Create a django ninja API router dedicated to the student
router = Router(tags=["location"])


RouterContract = LocationContract
RouterSaveContract = LocationSaveContract
RouterModel = LocationResource
RouterListContract = List[RouterContract]


@router.post(
path="/create/",
response={
200: RouterContract,
422: FormInvalidResponseContract,
},
)
def record_create(request: HttpRequest, payload: RouterSaveContract):
record_payload = payload.dict()
if "coordinate" in record_payload:
geo_coordinate = record_payload["coordinate"]
del record_payload["coordinate"]
geo_coordinate_obj, created = GeoCoordinate.objects.update_or_create(
geo_coordinate, **geo_coordinate
)
record_payload["coordinate"] = geo_coordinate_obj
record = RouterModel(**record_payload)
record.save()
record.refresh_from_db()
return 200, record


@router.get(
path="/read/{pk}/",
response={
200: RouterContract,
422: FormInvalidResponseContract,
},
)
def record_read(request: HttpRequest, pk: IntStrUUID4):
return 200, get_object_or_404(RouterModel, pk=pk)


@router.post(
path="/update/{pk}/",
response={
200: RouterContract,
422: FormInvalidResponseContract,
},
)
def record_update(request: HttpRequest, pk: IntStrUUID4, payload: RouterSaveContract):
record_payload = payload.dict()
if "coordinate" in record_payload:
geo_coordinate = record_payload["coordinate"]
del record_payload["coordinate"]
geo_coordinate_obj, created = GeoCoordinate.objects.update_or_create(
geo_coordinate, **geo_coordinate
)
record_payload["coordinate"] = geo_coordinate_obj
record = get_object_or_404(RouterModel, pk=pk)
for attr, value in record_payload.items():
setattr(record, attr, value)
record.save()
record.refresh_from_db()
return 200, record


@router.get(
path="/delete/{pk}/",
response={
200: SkiiMsgContract,
422: FormInvalidResponseContract,
},
)
def record_delete(request: HttpRequest, pk: IntStrUUID4):
qs = RouterModel.objects.all().filter(pk=pk)
if qs.exists():
qs.delete()
return 200, SkiiMsgContract(message="Record deleted")


@router.get(
path="/list/",
response={
200: RouterListContract,
422: FormInvalidResponseContract,
},
)
def record_list(request: HttpRequest):
return 200, RouterModel.objects.all()


__all__ = [router]
17 changes: 8 additions & 9 deletions skii/endpoint/routers/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ def add_view_update(self):
422: FormInvalidResponseContract,
},
)
def record_update(request: HttpRequest, pk: IntStrUUID4, payload: save_contract):
def record_update(
request: HttpRequest, pk: IntStrUUID4, payload: save_contract
):
record_payload = payload.dict()
record = get_object_or_404(router_model, pk=pk)
for attr, value in record_payload.items():
Expand Down Expand Up @@ -135,7 +137,7 @@ class Config:
# Introspection config
depth: int = 0
save_depth: int = 0
base_class: Schema = IntStrUUID4
base_class: Schema = None
# Fields config/tweak
fields: List[str] | None = None
save_fields: List[str] | None = None
Expand All @@ -147,13 +149,16 @@ class Config:
def __init__(self, *args, **kwargs):
"""Autogenerate contract/schema from django models."""
res = super().__init__(*args, **kwargs)
logger.debug("Now we generate standard read contract")
self.contract = self.create_contract(
fields=self.Config.fields,
exclude_fields=self.Config.exclude_fields,
custom_fields=self.Config.custom_fields,
depth=self.Config.depth,
)
logger.debug("Now we define List of read contract")
self.list_contract = List[self.contract]
logger.debug("Now we define the save contract")
self.save_contract = self.create_contract(
fields=self.Config.save_fields,
exclude_fields=self.Config.save_exclude_fields,
Expand All @@ -178,7 +183,7 @@ def create_contract(
contract = create_schema(
model=self.Config.model,
name=self.Config.name + "-contract",
base_class=self.Config.base_class,
# base_class=self.Config.base_class,
depth=depth,
exclude=exclude_fields,
custom_fields=custom_fields,
Expand All @@ -193,11 +198,5 @@ def create_contract(
logger.debug(
f"{self.Config.name} Contract have required fields {contract_schema['required']}"
)
logger.debug(
f"{self.Config.name} Save Contract have fields {contract_schema['properties'].keys()}"
)
logger.debug(
f"{self.Config.name} Save Contract have required fields {contract_schema['required']}"
)

return contract
Loading

0 comments on commit 6ff6dad

Please sign in to comment.