class Report(models.Model): date_run = models.DateTimeField() slug = AutoSlugField(populate_from=['date_run'], max_length=250, editable=False, unique=True) table = JSONField(_('table')) template = models.ForeignKey(ReportTemplate, verbose_name=_('template'), related_name='reports') report_file = models.FileField(_('report_file'), upload_to=get_upload, blank=True, null=True, max_length=255) def __unicode__(self): return self.date_run.isoformat() def dictify(self): report = { 'id': self.id, 'table': self.table, 'date_run': json.dumps(self.date_run, default=_dthandler) } return report
class BaseProperty(models.Model): key = models.CharField(_('key'), max_length=50) slug = AutoSlugField(populate_from=['key'], max_length=750, editable=False, unique=True) default = models.CharField(_('default value'), max_length=255, blank=True, null=True) value = models.CharField(_('value'), max_length=255, blank=True) DATATYPE_CHOICES = ( (u'u', _(u'Default')), (_("Basic"), ( (u's', _(u'String')), (u'b', _(u'Boolean')), (u'n', _(u'Number')), )), (_("Advanced"), ( (u'x', _(u'Text')), (u'd', _(u'Date')), (u't', _(u'Time')), (u'c', _(u'Choices')), (u'f', _(u'Float')), (u'r', _(u'Collaborator')), )), (_("Auto"), ( (u'w', _(u'Auto now')), (u'a', _(u'Auto now add')), (u'i', _(u'Auto increment')), (u'o', _(u'Auto increment update')), (u'e', _(u'Auto user')), )), ) required = models.BooleanField(_('is required?'), default=False) display = models.BooleanField(_('use as label'), default=False) description = models.TextField(_('description'), blank=True, null=True) validation = models.TextField( _('validation'), blank=True, null=True, # default=""" #// The property value and name are provided #// and modifications on the value will be used. #// In case of error, set the error variable to #// a string. #name; #value; #error = ""; # """, help_text=_("Code in Javascript to " "validate the property")) order = models.IntegerField(_('order'), blank=True, null=True) auto = models.IntegerField(_('auto'), blank=True, null=True) class Meta: abstract = True ordering = ("order", "key") def save(self, *args, **kwargs): if self.key: self.key = self.key.strip() super(BaseProperty, self).save(*args, **kwargs) def __unicode__(self): return "%s: %s" % (self.key, self.value) def get_datatype_dict(self): return { "default": u"u", "number": u"n", "string": u"s", "boolean": u"b", "date": u"d", "time": u"t", "choices": u"c", "text": u"x", "float": u"f", "collaborator": u"r", "auto_now": u"w", "auto_now_add": u"a", "auto_increment": u"i", "auto_increment_update": u"o", "auto_user": u"e", } def get_datatype(self): datatype_dict = dict(self.DATATYPE_CHOICES) return datatype_dict.get(self.datatype) def get_datatype_value(self): dd = self.get_datatype_dict() value = dd.keys()[dd.values().index(self.datatype)] return value def get_choices(self): choices = [(u"", u"---------")] if self.default: if not "," in self.default: self.default = u"%s," % self.default for choice in self.default.split(","): choice_strip = choice.strip() key = u"%s" % slugify(choice_strip) if key and choice_strip: choices.append((key, choice_strip)) return choices
class BaseType(models.Model): name = models.CharField(_('name'), max_length=150) slug = AutoSlugField(populate_from=['name'], max_length=200, editable=False, unique=True) plural_name = models.CharField(_('plural name'), max_length=175, null=True, blank=True) description = models.TextField(_('description'), null=True, blank=True) schema = models.ForeignKey(Schema) order = models.IntegerField(_('order'), null=True, blank=True) total = models.IntegerField(_("total objects"), default=0) validation = models.TextField( _('validation'), blank=True, null=True, # default=""" #// The properties list ordered by "Order" #// and then by "Name" is provided and it #// will be used. In case of error, set #// error variable to string; #properties; #error = ""; # """, help_text=_("Code in Javascript to " "validate all the properties")) options = models.TextField(_('options'), null=True, blank=True) def get_options(self): options = json.loads(self.options or "{}") return options def set_options(self, dic): if isinstance(dic, dict): self.options = json.dumps(dic) def update_options(self, dic): options = self.get_options() options.update(dic) self.options = json.dumps(options) def get_option(self, key=None): return self.get_options()[key] def set_option(self, key, value): if key and value: options = self.get_options() options[key] = value self.options = json.dumps(options) class Meta: abstract = True ordering = ("order", "name") @models.permalink def get_absolute_url(self): return ('nodes_list_full', [self.schema.graph.slug, self.id]) def has_color(self): return 'color' in self.get_options() def get_color(self): if self.has_color(): return self.get_option('color') else: return self.create_color() def set_color(self, color): with transaction.atomic(): self.set_option('color', color) self.save()
class ReportTemplate(models.Model): name = models.CharField(_('name'), max_length=150) slug = AutoSlugField(populate_from=['name'], max_length=250, editable=False, unique=True) start_date = models.DateTimeField(_('start date')) FREQUENCY_CHOICES = (((u'h'), _(u'Hourly')), ((u'd'), _(u'Daily')), ((u'w'), _(u'Weekly')), ((u'm'), _(u'Monthly'))) frequency = models.CharField(_('frequency'), max_length=1, choices=FREQUENCY_CHOICES, default=u'w') last_run = models.DateTimeField(_('last run'), blank=True, null=True) layout = JSONField(_('layout')) description = models.TextField(_('description'), blank=True, null=True) graph = models.ForeignKey(Graph, verbose_name=_('graph'), related_name='report_templates') queries = models.ManyToManyField(Query, verbose_name=_('queries'), related_name='report_templates', blank='true', null='true') email_to = models.ManyToManyField(User, verbose_name=_("email_to"), related_name="report_templates", blank=True, null=True) is_disabled = models.BooleanField(default=False) def __unicode__(self): return self.name def execute(self): queries = self.queries.all() query_dicts = { query.id: (query.execute(headers=True), query.name) for query in queries } table = [] for row in self.layout["layout"]: # pragma: no cover new_row = [] for cell in row: query = cell.get('displayQuery', '') if query: query = int(query) attrs = query_dicts[query] cell['series'] = attrs[0] cell['name'] = attrs[1] new_row.append(cell) table.append(new_row) table = { "pagebreaks": self.layout["pagebreaks"], # pragma: no cover "layout": table } report = Report(date_run=datetime.datetime.now(), table=table, template=self) self.last_run = datetime.datetime.now() self.save(update_fields=["last_run"]) report.save() def dictify(self): template = { 'name': self.name, 'slug': self.slug, 'start_date': json.dumps(self.start_date, default=_dthandler), 'frequency': self.frequency, 'last_run': json.dumps(self.last_run, default=_dthandler), 'layout': self.layout, 'description': self.description, 'collabs': [{ "id": u.username, "display": u.username } for u in self.email_to.all()], 'is_disabled': self.is_disabled } return template
class Graph(models.Model, GraphMixin): name = models.CharField(_('name'), max_length=120) slug = AutoSlugField(populate_from=['name'], max_length=200, editable=False, unique=True) description = models.TextField(_('description'), null=True, blank=True) public = models.BooleanField(_('is public?'), default=True, help_text=_("It means publicly available " "to be browsed")) order = models.IntegerField(_('order'), null=True, blank=True) owner = models.ForeignKey(User, verbose_name=_('owner'), related_name='graphs') data = models.OneToOneField(Data, verbose_name=_('data')) schema = models.OneToOneField(Schema, verbose_name=_('schema'), null=True, blank=True) relaxed = models.BooleanField(_('Is schema-relaxed?'), default=False) options = models.TextField(_('options'), null=True, blank=True) last_modified = models.DateTimeField(_("last modified"), null=True, blank=True) class Meta: unique_together = ["owner", "name"] # TODO: Add constraint in forms ordering = ("order", ) permissions = ( ('view_graph', _('View graph')), ('change_collaborators', _("Change collaborators")), ('view_graph_reports', _("View graph reports")), ('add_graph_reports', _("Add graph reports")), ('change_graph_reports', _("Change graph reports")), ('delete_graph_reports', _("Delete graph reports")), ('view_graph_queries', _("View graph gueries")), ('add_graph_queries', _("Add graph gueries")), ('change_graph_queries', _("Change graph gueries")), ('delete_graph_queries', _("Delete graph gueries")), ('view_graph_analytics', _("View graph analytics")), ('add_graph_analytics', _("Add graph analytics")), ('delete_graph_analytics', _("Delete graph analytics")), ) def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return ('graph_view', [self.slug]) def is_empty(self): return self.data.total_nodes == 0 def clone(self, new_graph, clone_data=True): schema = self.schema new_schema = new_graph.schema nt_map, rt_map = self._clone_schema(schema, new_schema) if clone_data: self._clone_data(new_graph, nt_map, rt_map) def _clone_schema(self, schema, new_schema): nodetypes_map = {} # map old/new nodetypes IDs relationtypes_map = {} # map old/new relationtypes IDs nodetypes = schema.nodetype_set.all() for nt in nodetypes: new_nt = NodeType(schema=new_schema, name=nt.name, plural_name=nt.plural_name, description=nt.description, order=nt.order, total=0, validation=nt.validation) new_nt.save() nodetypes_map[nt.id] = new_nt.id properties = nt.properties.all() for np in properties: new_np = NodeProperty(node=new_nt, key=np.key, value=np.value, default=np.default, datatype=np.datatype, required=np.required, display=np.display, description=np.description, validation=np.validation, order=np.order) new_np.save() relationtypes = schema.relationshiptype_set.all() for rt in relationtypes: source = NodeType.objects.get(schema=new_schema, name=rt.source.name) target = NodeType.objects.get(schema=new_schema, name=rt.target.name) new_rt = RelationshipType(schema=new_schema, source=source, target=target, name=rt.name, plural_name=rt.plural_name, description=rt.description, order=rt.order, total=0, validation=rt.validation, inverse=rt.inverse, plural_inverse=rt.plural_inverse, arity_source=rt.arity_source, arity_target=rt.arity_target) new_rt.save() relationtypes_map[rt.id] = new_rt.id properties = rt.properties.all() for rp in properties: new_rp = RelationshipProperty(relationship=new_rt, key=rp.key, value=rp.value, default=rp.default, datatype=rp.datatype, required=rp.required, display=rp.display, description=rp.description, validation=rp.validation, order=rp.order) new_rp.save() return nodetypes_map, relationtypes_map def _clone_data(self, new_graph, nodetypes_map, relationtypes_map): nodes_map = {} # map old/new nodes IDs data = self.data new_data = new_graph.data nodes = self.nodes.all() for n in nodes: node_label = int(n.label) if node_label in nodetypes_map: nt = NodeType.objects.get(pk=nodetypes_map[node_label]) new_node = new_graph.nodes.create(label=unicode(nt.id), properties=n.properties) nodes_map[n.id] = new_node relations = self.relationships.all() for r in relations: rel_label = int(r.label) if rel_label in relationtypes_map: rt = RelationshipType.objects.get( pk=relationtypes_map[rel_label]) new_graph.relationships.create(nodes_map[r.source.id], nodes_map[r.target.id], label=unicode(rt.id), properties=r.properties) media_nodes = data.data.all() for mn in media_nodes: node_id = int(mn.node_id) if node_id in nodes_map: new_mn = MediaNode(node_id=nodes_map[node_id].id, data=new_data) new_mn.save() media_links = mn.links.all() for ml in media_links: new_ml = MediaLink(media_node=new_mn, media_label=ml.media_label, media_link=ml.media_link) new_ml.save() def get_collaborators(self, include_anonymous=False, as_queryset=False): all_collaborators = get_users_with_perms(self) if include_anonymous: if as_queryset: return all_collaborators.exclude(id=self.owner.id) else: return list(all_collaborators.exclude(id=self.owner.id)) else: if as_queryset: return all_collaborators.exclude(id__in=[self.owner.id, settings.ANONYMOUS_USER_ID]) else: return list(all_collaborators.exclude( id__in=[self.owner.id, settings.ANONYMOUS_USER_ID])) def get_options(self): options = json.loads(self.options or "{}") return options def set_options(self, dic): if isinstance(dic, dict): self.options = json.dumps(dic) def update_options(self, dic): options = self.get_options() options.update(dic) self.options = json.dumps(options) def get_option(self, key=None): return self.get_options()[key] def set_option(self, key, value): if key and value: options = self.get_options() options[key] = value self.options = json.dumps(options)