CORD-1093: Updated legacy code to xproto converter with several bug
fixes

Change-Id: Ica25711410cf97cc96d7427558c8222b171f7084
diff --git a/xos/tools/apigen/lib.py b/xos/tools/apigen/lib.py
index 70d0ac4..1a7b12e 100644
--- a/xos/tools/apigen/lib.py
+++ b/xos/tools/apigen/lib.py
@@ -76,13 +76,35 @@
     return format_options_string(output_dict)
     
 def xp_to_xproto(field, idx):
-    t = field.get_internal_type()
+    at = type(field).__name__
+    try:
+        t = field.get_internal_type()
+    except AttributeError:
+        t = type(field).__name__
+
     link = False
+    through = None
 
     if (t=='CharField' or t=='TextField' or t=='SlugField'):
         xptype = 'string'
     elif (t=='BooleanField'):
         xptype = 'bool'
+    elif (t=='ManyToManyField'):
+        if (at=='ManyToManyField'):
+	    xptype = 'manytomany'
+	    peer = field.related.model.__name__
+	    through = field.related.model.through
+	    if (field.related.name):
+		dst_port = ':' + field.related.name
+	    else:
+		dst_port = ''
+        else:
+            xptype = 'manytomany'
+	    peer = field.related.model.__name__
+	    dst_port = ''
+
+
+        link = True
     elif (t=='ForeignKey'):
         xptype = 'manytoone'
         peer = field.related.model.__name__
@@ -107,7 +129,9 @@
         xptype = 'string'
     elif (t=='OneToOneField'):
         link = True
- 
+         
+    else:
+        raise Exception('Bad field')
     
     if (field.null==False):
        modifier = 'required'
@@ -115,7 +139,12 @@
        modifier = 'optional'
 
     if (link):
-       str = '%s %s %s->%s%s = %d'%(modifier, xptype, field.name, peer, dst_port, idx)
+       if (through):
+          dst_model = '%s/%s'%(peer,through)
+       else:
+          dst_model = '%s'%peer
+
+       str = '%s %s %s->%s%s = %d'%(modifier, xptype, field.name, dst_model, dst_port, idx)
     else:
        str = '%s %s %s = %d'%(modifier, xptype, field.name, idx)
 
diff --git a/xos/tools/apigen/modelgen2 b/xos/tools/apigen/modelgen2
index 916fbe5..b78719a 100755
--- a/xos/tools/apigen/modelgen2
+++ b/xos/tools/apigen/modelgen2
@@ -18,6 +18,7 @@
 sys.path.append('/opt/xos')
 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
 from django.db.models.fields.related import ForeignKey, ManyToManyField
+from django.contrib.contenttypes.fields import GenericRelation
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 
@@ -184,7 +185,7 @@
 	def add_object(self, o):
                 global app_map
 		obj = GenObj(o)
-		fields = o._meta.fields
+		fields = o._meta.get_fields(include_hidden=False)
                 try:
                     obj.app = app_map[o.__name__] # full name
                     if hasattr(o, "_meta") and hasattr(o._meta, "app_label"):
@@ -208,42 +209,51 @@
                 except KeyError:
                     self.apps[obj.app] = {file_name:[obj]}
 
+
 		self[str(obj).lower()]=obj
 
 	def compute_links(self):
 
 		for obj in self.values():
                 	base_props = [f.name for f in obj.model.__base__._meta.fields] + ['id']
-			#if (str(obj)=='network'):
-			#	pdb.set_trace()
-			fields = obj.model._meta.fields
+			fields = list(obj.model._meta.fields + obj.model._meta.many_to_many)
+
+                        other_fields = obj.model._meta.get_fields()
+                        for o in other_fields:
+                            if (type(o)==GenericRelation): fields+=[o]
+
+
 			for f in fields:
-				if (f and f.rel):
+                                if f.name in base_props or type(f).__name__=='ManyToOneRel': continue
+
+				if (f and hasattr(f, 'rel') and f.rel):
 					to_name = str(f.rel.to)
 				else:
 					to_name = None
 
-				if type(f)==ForeignKey and to_name and to_name in self.keys():
-					refobj = self[f.to_name]
 
-					if (str(obj)=='slice' and f.to_name=='networks'):
-						obj.refs.append(refobj)
-					related_name = f.related_query_name()
-					if (related_name!='+' and related_name.lower()!=str(obj).lower()):
-						cobj = copy.deepcopy(obj)
-						cobj.multi = True
-						cobj.plural_name = related_name
-						refobj.refs.append(cobj)
-                                elif f.name.endswith("_ptr"):
+                                if f.name.endswith("_ptr"):
                                         # django inherited model, for example HPCService
                                         # cause swagger and REST to break
                                         pass
 				else:
                                         f.type = f.__class__.__name__
+
                                         if (type(f)==ForeignKey):
                                             f.related.model.class_name = f.related.model.__name__
+                                        elif (type(f)==ManyToManyField or type(f)==GenericRelation):
+                                            f.related.model.class_name = f.related.model.__name__
+                                            try:
+                                               f.related.model.through = f.related.through.__name__
+                                            except AttributeError: 
+                                               pass
+                                
+                
                                         if (f.name not in base_props):
                                             obj.fields.append(f)
+                                        
+                                        #if (f.name == 'tags'): pdb.set_trace()
+
                                         obj.all_fields.append(f)
                                         obj.props.append(f.name)
 
diff --git a/xos/tools/apigen/xproto.template.txt b/xos/tools/apigen/xproto.template.txt
index 8320443..252e99a 100644
--- a/xos/tools/apigen/xproto.template.txt
+++ b/xos/tools/apigen/xproto.template.txt
@@ -1,7 +1,7 @@
 {% for object in generator.all() %}
 
 message {{ object.camel() }} ({%- if (object.bases) -%}{{ object.bases}}){%- endif -%} {
-  {%- for field in object.fields %}
+  {%- for field in object.all_fields %}
      {{ xp_to_xproto(field, loop.index) }} {{xp_options(field)}};
   {%- endfor %}
 }