Extended Redis event and added modeldefs endpoint
Change-Id: Ic73c1330df3284e54107ccdc01770edc87e95ede
diff --git a/xos/api/utility/modeldefs.py b/xos/api/utility/modeldefs.py
new file mode 100644
index 0000000..c3b5e21
--- /dev/null
+++ b/xos/api/utility/modeldefs.py
@@ -0,0 +1,119 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.exceptions import APIException
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+import json
+from core.models import UserDashboardView, DashboardView
+from api.xosapi_helpers import XOSViewSet, PlusModelSerializer
+import django.apps
+from rest_framework.views import APIView
+
+
+class ModelDefsList(APIView):
+ method_kind = "list"
+ method_name = "modeldefs"
+
+ typeMap = {
+ 'BooleanField': 'boolean',
+ 'TextField': 'text',
+ 'CharField': 'string',
+ 'ForeignKey': 'number',
+ 'IntegerField': 'number',
+ 'AutoField': 'number',
+ 'DateTimeField': 'date'
+ }
+
+ validatorMap = {
+ 'EmailValidator': 'email',
+ 'MaxLengthValidator': 'maxlength',
+ 'URLValidator': 'url',
+ 'MinValueValidator': 'min',
+ 'MaxValueValidator': 'max',
+ 'validate_ipv46_address': 'ip'
+ }
+
+ def convertType(self, type):
+ try:
+ jsType = self.typeMap[type]
+ return jsType
+ except Exception:
+ return None
+
+ def convertValidator(self, validator):
+ try:
+ jsValidator = self.validatorMap[validator]
+ return jsValidator
+ except Exception:
+ return None
+
+ def getRelationType(self, field):
+ if (field.many_to_many):
+ return 'many_to_many'
+ if (field.many_to_one):
+ return 'many_to_one'
+ if (field.one_to_many):
+ return 'one_to_many'
+ if (field.one_to_one):
+ return 'one_to_one'
+
+ def get(self, request, format=None):
+ models = django.apps.apps.get_models()
+
+ response = []
+
+ for model in models:
+ if 'core' in model.__module__:
+ # if 'Instance' == model.__name__:
+ modeldef = {}
+ modeldef['name'] = model.__name__
+
+ fields = []
+ relations = []
+ for f in model._meta.fields:
+
+ field = {
+ 'name': f.name,
+ 'hint': f.help_text,
+ 'validators': {
+ }
+ }
+
+ fieldtype = self.convertType(f.get_internal_type())
+ if fieldtype is not None:
+ field['type'] = fieldtype
+
+ if not f.blank and not f.null:
+ field['validators']['required'] = True
+
+ for v in f.validators:
+ validator_name = v.__class__.__name__
+ if 'function' in validator_name:
+ validator_name = v.__name__
+ validator_name = self.convertValidator(validator_name)
+
+ if hasattr(v, 'limit_value'):
+ field['validators'][validator_name] = v.limit_value
+ else:
+ field['validators'][validator_name] = True
+
+ fields.append(field)
+
+ if f.is_relation and f.related_model:
+
+ # Add the relation details to the model
+ field['relation'] = {
+ 'model': f.related_model.__name__,
+ 'type': self.getRelationType(f)
+ }
+
+ relations.append(f.related_model.__name__)
+
+ modeldef['fields'] = fields
+
+ # TODO add relation type (eg: OneToMany, ManyToMany)
+ modeldef['relations'] = list(set(relations))
+ response.append(modeldef)
+ return Response(response)
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index 0671e0b..66046ee 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -18,6 +18,10 @@
import redis
from redis import ConnectionError
+
+def date_handler(obj):
+ return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+
try:
# This is a no-op if observer_disabled is set to 1 in the config file
from synchronizers.base import *
@@ -285,19 +289,19 @@
self.save(update_fields=['enacted','deleted','policed'], silent=silent)
collector = XOSCollector(using=router.db_for_write(self.__class__, instance=self))
- collector.collect([self])
- with transaction.atomic():
- for (k, models) in collector.data.items():
- for model in models:
- if model.deleted:
- # in case it's already been deleted, don't delete again
- continue
- model.deleted = True
+ collector.collect([self])
+ with transaction.atomic():
+ for (k, models) in collector.data.items():
+ for model in models:
+ if model.deleted:
+ # in case it's already been deleted, don't delete again
+ continue
+ model.deleted = True
model.enacted=None
model.policed=None
journal_object(model, "delete.cascade.mark_deleted", msg="root = %r" % self)
- model.save(update_fields=['enacted','deleted','policed'], silent=silent)
-
+ model.save(update_fields=['enacted','deleted','policed'], silent=silent)
+
def save(self, *args, **kwargs):
journal_object(self, "plcorebase.save")
@@ -347,7 +351,9 @@
try:
r = redis.Redis("redis")
- payload = json.dumps({'pk':self.pk,'changed_fields':changed_fields})
+ # NOTE the redis event has been extended with model properties to facilitate the support of real time notification in the UI
+ # keep this monitored for performance reasons and eventually revert it back to fetch model properties via the REST API
+ payload = json.dumps({'pk': self.pk, 'changed_fields': changed_fields, 'object': model_to_dict(self)}, default=date_handler)
r.publish(self.__class__.__name__, payload)
except ConnectionError:
# Redis not running.