Skip to content

Commit

Permalink
Merge pull request #11 from StreamsTech/angularjs-analytics
Browse files Browse the repository at this point in the history
Angularjs analytics
  • Loading branch information
shahjalalh authored Nov 22, 2017
2 parents 153bb5e + f762522 commit 5b8d9c4
Show file tree
Hide file tree
Showing 19 changed files with 379 additions and 45 deletions.
61 changes: 61 additions & 0 deletions geonode/class_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from .db_connections import Database
from django.db import models


class ClassFactory(object):
DJANGO_MODEL = {
'bigint': models.BigIntegerField,
'character varying': models.CharField,
'integer': models.IntegerField,
'boolean': models.BooleanField,
'text': models.TextField,
'smallint': models.SmallIntegerField
}
def __init__(self):
super(ClassFactory, self).__init__()

def create_model(self, name, fields=None, app_label='', module='', options=None, admin_opts=None, db='default'):
"""
Create specified model
EX: model = create_model('NycRoad', app_label='front_end', options=dict(db_table='nyc_road'))
"""
class Meta:
# Using type('Meta', ...) gives a dictproxy error during model creation
pass
if app_label:
# app_label must be set using the Meta inner class
setattr(Meta, 'app_label', app_label)
# Update Meta with any options that were provided
if options is not None:
for key, value in options.iteritems():
setattr(Meta, key, value)

# Set up a dictionary to simulate declarations within a class
attrs = {'__module__': module, 'Meta': Meta, 'database':db}
# Add in any fields that were provided
if fields:
attrs.update(fields)
# Create the class, which automatically triggers ModelBase processing
model = type(name, (models.Model,), attrs)
# Create an Admin class if admin options were provided
# if admin_opts is not None:
# class Admin(admin.ModelAdmin):
# pass
# for key, value in admin_opts:
# setattr(Admin, key, value)
# admin.site.register(model, Admin)
return model

def get_model_field(self, data_type,column_name=None, blank=True, is_null=True, character_maximum_length=None, *args, **kwargs):
if character_maximum_length is None:
if column_name == 'fid':
return self.DJANGO_MODEL[data_type](null=is_null, primary_key=True)
else:
return self.DJANGO_MODEL[data_type](null=is_null)
else:
return self.DJANGO_MODEL[data_type](null=is_null, max_length=character_maximum_length)

def get_model(self, name, table_name, app_label='dynamic', db=None):
schema_infos = Database(db_name=db).get_table_schema_info(table_name=table_name)
fields = {f.column_name: self.get_model_field(**f) for f in schema_infos if f.data_type in self.DJANGO_MODEL}
return self.create_model(name, app_label=app_label, fields=fields, options=dict(db_table=table_name), db=db)
50 changes: 50 additions & 0 deletions geonode/db_connections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from django.db import connections
from django.conf import settings


class InformationSchemaColumns:
_KEYS = ['column_name', 'is_nullable', 'data_type', 'character_maximum_length']
column_name = None
is_nullable = None
data_type = None
character_maximum_length = None
def __init__(self, *args, **kwargs):
self.column_name = kwargs.get('column_name', '')
self.is_nullable = kwargs.get('is_nullable', 'YES')
self.data_type = kwargs.get('data_type', None)
self.character_maximum_length = kwargs.get('character_maximum_length', None)

@property
def is_null(self):
return True if self.is_nullable == 'YES' else False

def keys(self):
return self._KEYS

def __getitem__(self, key):
return getattr(self, key)


class Database(object):
'''
This class will handle db connection
'''
TABLE_SCHEMA_INFO_QUERY = "SELECT %s FROM information_schema.columns WHERE TABLE_NAME = '%s'"

def __init__(self, db_name=None):
if db_name is None:
k, v = settings.DATABASES.items()[0]
self.cursor = connections[k]
else:
self.cursor = connections[db_name]

def get_table_schema_info(self, table_name):
columns_details = []
schema_columns = InformationSchemaColumns._KEYS
with self.cursor.cursor() as cursor:
sql = self.TABLE_SCHEMA_INFO_QUERY % (','.join(schema_columns), table_name)
cursor.execute(sql)
for row in cursor.fetchall():
columns_details.append(InformationSchemaColumns(**dict(zip(schema_columns, row))))

return columns_details
16 changes: 16 additions & 0 deletions geonode/db_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class DbRouter(object):
"""
A router to control all database operations on models in the
auth application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read auth models go to auth_db.
"""
return getattr(model, 'database', None)

def db_for_write(self, model, **hints):
"""
Attempts to write auth models go to auth_db.
"""
return getattr(model, 'database', None)
47 changes: 29 additions & 18 deletions geonode/documents/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from django.forms import HiddenInput, TextInput
from modeltranslation.forms import TranslationModelForm

from geonode.documents.models import Document
from geonode.documents.models import Document, DocumentLayers
from geonode.maps.models import Map
from geonode.layers.models import Layer
from geonode.groups.models import GroupProfile
Expand All @@ -42,47 +42,58 @@

class DocumentForm(ResourceBaseForm):

resource = forms.ChoiceField(label='Link to')
# resource = forms.ChoiceField(label='Link to')
resource = forms.CharField(
required=False,
label=_("Link to"),
widget=TextInput(
attrs={
'name': 'title__contains',
'id': 'resource'
}))

def __init__(self, *args, **kwargs):
super(DocumentForm, self).__init__(*args, **kwargs)
rbases = list(Layer.objects.all())
rbases += list(Map.objects.all())
rbases.sort(key=lambda x: x.title)
rbases_choices = []
rbases_choices.append(['no_link', '---------'])
# rbases_choices.append(['no_link', '---------'])
for obj in rbases:
type_id = ContentType.objects.get_for_model(obj.__class__).id
obj_id = obj.id
form_value = "type:%s-id:%s" % (type_id, obj_id)
display_text = '%s (%s)' % (obj.title, obj.polymorphic_ctype.model)
rbases_choices.append([form_value, display_text])
self.fields['resource'].choices = rbases_choices
"""
if self.instance.content_type:
self.fields['resource'].initial = 'type:%s-id:%s' % (
self.instance.content_type.id, self.instance.object_id)
"""

def save(self, *args, **kwargs):
contenttype_id = None
contenttype = None
object_id = None
resource = self.cleaned_data['resource']
if resource != 'no_link':
matches = re.match("type:(\d+)-id:(\d+)", resource).groups()
contenttype_id = matches[0]
object_id = matches[1]
contenttype = ContentType.objects.get(id=contenttype_id)
self.cleaned_data['content_type'] = contenttype_id
self.cleaned_data['object_id'] = object_id
self.instance.object_id = object_id
self.instance.content_type = contenttype
# contenttype_id = None
# contenttype = None
# object_id = None
# resource = self.cleaned_data['resource']
# if resource != 'no_link':
# matches = re.match("type:(\d+)-id:(\d+)", resource).groups()
# contenttype_id = matches[0]
# object_id = matches[1]
# contenttype = ContentType.objects.get(id=contenttype_id)
# self.cleaned_data['content_type'] = contenttype_id
# self.cleaned_data['object_id'] = object_id
# self.instance.object_id = object_id
# self.instance.content_type = contenttype
return super(DocumentForm, self).save(*args, **kwargs)

class Meta(ResourceBaseForm.Meta):
model = Document
exclude = ResourceBaseForm.Meta.exclude + (
'content_type',
'object_id',
# 'content_type',
# 'object_id',
'layers',
'doc_file',
'extension',
'doc_type',
Expand Down
49 changes: 49 additions & 0 deletions geonode/documents/migrations/0027_auto_20171120_0412.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('layers', '0026_auto_20171004_1311'),
('documents', '0026_auto_20171004_1243'),
]

operations = [
migrations.CreateModel(
name='DocumentLayers',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('content_type', models.ForeignKey(blank=True, to='contenttypes.ContentType', null=True)),
],
options={
'db_table': 'document_layers',
},
),
migrations.RemoveField(
model_name='document',
name='content_type',
),
migrations.RemoveField(
model_name='document',
name='object_id',
),
migrations.AddField(
model_name='documentlayers',
name='document',
field=models.ForeignKey(to='documents.Document'),
),
migrations.AddField(
model_name='documentlayers',
name='layer',
field=models.ForeignKey(blank=True, to='layers.Layer', null=True),
),
migrations.AddField(
model_name='document',
name='layers',
field=models.ManyToManyField(to='layers.Layer', null=True, through='documents.DocumentLayers', blank=True),
),
]
19 changes: 14 additions & 5 deletions geonode/documents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ class Document(ResourceBase):
"""

# Relation to the resource model
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.PositiveIntegerField(blank=True, null=True)
resource = generic.GenericForeignKey('content_type', 'object_id')

layers = models.ManyToManyField(Layer, blank=True, null=True, through='DocumentLayers', through_fields=('document', 'layer'))
doc_file = models.FileField(upload_to='documents',
null=True,
blank=True,
Expand Down Expand Up @@ -142,10 +140,21 @@ class Meta(ResourceBase.Meta):
pass


class DocumentLayers(models.Model):
document = models.ForeignKey(Document)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
layer = models.ForeignKey(Layer, blank=True, null=True)
resource = generic.GenericForeignKey('content_type', 'layer')

class Meta:
db_table = 'document_layers'


def get_related_documents(resource):
if isinstance(resource, Layer) or isinstance(resource, Map):
ct = ContentType.objects.get_for_model(resource)
return Document.objects.filter(content_type=ct, object_id=resource.pk)
# return Document.objects.filter(content_type=ct, object_id=resource.pk)
return DocumentLayers.objects.filter(content_type_id=ct.id, layer_id=resource.id)
else:
return None

Expand Down Expand Up @@ -178,7 +187,7 @@ def pre_save_document(instance, sender, **kwargs):
if instance.title == '' or instance.title is None:
instance.title = instance.doc_file.name

if instance.resource:
if getattr(instance, 'resource', None):
instance.csw_wkt_geometry = instance.resource.geographic_bounding_box.split(
';')[-1]
instance.bbox_x0 = instance.resource.bbox_x0
Expand Down
15 changes: 11 additions & 4 deletions geonode/documents/templates/documents/document_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,18 +188,25 @@ <h4 class="modal-title" id="myModalLabel">{% trans "Download Metadata" %}</h4>
</div>

<li class="list-group-item">
{{ document.layers.values_list }}
<h4>{% trans "Resource using this document" %}</h4>
{% if layer.maps %}
<p>{% trans "List of resources using this document:" %}</p>
{% comment %}{% if layer.maps %}{% endcomment %}
{% if document_layers %}
<p>{% trans "List of resources using this document:" %}</p>
{% for doc_layer in document_layers %}
<a href='{{ doc_layer.get_absolute_url }}'>{{ doc_layer.title }}</a>
{% endfor %}
{% else %}
<p>{% trans "This document is not related to any maps or layers" %}</p>
{% endif %}
<ul class="list-unstyled">
{% comment %}<ul class="list-unstyled">
{% if related.title %}
<p>{% trans "This document is related to a " %} {{ resource.content_type.name }}</p>
<a href='{{ related.get_absolute_url }}'>{{ related.title }}</a>
{% else %}
<p>{% trans "This document is not related to any maps or layers" %}</p>
{% endif %}
</ul>
</ul>{% endcomment %}
</li>

{% if "change_resourcebase_permissions" in perms_list %}
Expand Down
1 change: 1 addition & 0 deletions geonode/documents/templates/documents/document_upload.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
placeholder: 'Select layer, map or empty',
//width: 'element',
width: 'copy',
multiple: true,
ajax: {
traditional: true,
url: '{% url 'api_dispatch_list' api_name='api' resource_name='base' %}',
Expand Down
Loading

0 comments on commit 5b8d9c4

Please sign in to comment.