/site/remote/models.py
Python | 326 lines | 315 code | 10 blank | 1 comment | 10 complexity | 6956378814d31ae0ae9b86a1e6b7a91b MD5 | raw file
- from django.db import models
- from django.http import Http404, HttpResponse, HttpResponseNotFound
- from django.core.exceptions import ValidationError
- import traceback
- import sys
- import renderbasic
- import renderjquery
- import renderxml
- debug = False
- preRenderedCache = {}
- class Theme(models.Model):
- name = models.CharField(max_length=15)
-
- maxX = models.PositiveIntegerField(default = 5)
- maxY = models.PositiveIntegerField(default = 0)
- def __unicode__(self):
- return self.name
- def renderpage(self, remote, baseUrl, staticBaseUrl):
- """ Should return a dictionary with keys as integer page numbers and values should be objects of type HttpResponse."""
- if self.name == 'Basic':
- return renderbasic.render(remote, baseUrl, staticBaseUrl)
- elif self.name == 'jQuery':
- return renderjquery.render(remote, baseUrl, staticBaseUrl)
- elif self.name == 'xml':
- return renderxml.render(remote, baseUrl, staticBaseUrl)
- else:
- return {0: HttpResponse('<html><head><title>A page</title></head><body>A page body</body></html>')}
- class Remote(models.Model):
- name = models.CharField(max_length=50)
- theme = models.ForeignKey(Theme)
- theme_config = models.CharField(max_length=255, default = '', blank = True)
- style = models.TextField(default = '', blank = True, help_text = "Custom styleing for the theme, in jQuery theme this should be a chunk of CSS without any style-tag.")
- offlineApp = models.BooleanField(default = True, help_text = "If the remote should work as an HTML5 offline application, reduces page load time especially on mobile devices.")
- def __unicode__(self):
- return self.name
- def render(self, baseUrl, staticBaseUrl):
- return self.theme.renderpage(self, baseUrl, staticBaseUrl)
- def save(self):
- self.style = self.style.replace('url(images', 'url(/static/automagically/jquery/images')
- super(Remote, self).save()
- render(self)
- class Page(models.Model):
- name = models.CharField(max_length=25)
- number = models.PositiveIntegerField(default = 0)
- config = models.CharField(max_length=255, default = '', blank = True, help_text = "Additional configuration information here.")
- remote = models.ForeignKey(Remote)
-
- def save(self):
- super(Page, self).save()
- if debug:
- print 'Render, page changed'
- render(self.remote)
- def remoteText(self):
- return self.remote.name
- def __unicode__(self):
- return self.name
- class Widget(models.Model):
- displayText = models.CharField(max_length = 25, default = '', blank = True)
- page = models.ForeignKey(Page)
- x = models.PositiveIntegerField(default = 0)
- y = models.PositiveIntegerField(default = 0)
- xSize = models.PositiveIntegerField(default = 0)
- ySize = models.PositiveIntegerField(default = 0)
- def save(self):
- super(Widget, self).save()
- print 'Render, widget changed'
- try:
- render(self.page.remote)
- except:
- pass
- def delete(self):
- r = self.page.remote
- super(Widget, self).delete()
- try:
- render(r)
- except:
- pass
- def remote(self):
- return self.page.remote
- def clean(self):
-
- for w in Widget.objects.filter(page = self.page, y = self.y, x = self.x):
- if w != self:
- try:
- wi, t = w.getSubTypeInstance()
- except:
- wi = None
- if wi != self:
- raise ValidationError('There is alredy another widget at this page and position. That is this widget: ' + str(w) + '. Please set another value for Page/X/Y.')
- if self.page.remote.theme.maxX != 0 and ((len(Widget.objects.filter(page = self.page, y = self.y)) > self.page.remote.theme.maxX) or (self.x > self.page.remote.theme.maxX)):
-
- raise ValidationError(u'To high X-value or too many widgets at this Y-value, max for this theme is %d.' %(self.page.remote.theme.maxX))
- if self.page.remote.theme.maxY != 0 and ((len(Widget.objects.filter(page = self.page, x = self.x)) > self.page.remote.theme.maxY) or (self.y > self.page.remote.theme.maxY)):
-
- raise ValidationError(u'To high Y-value or too many widget at this X-value, max for this theme is %d.' %(self.page.remote.theme.maxY))
- def getSubTypeInstance(self):
- t = self.getSubType()
- if t == 'SingleDevCmd':
- return self.singledevcmd, t
- elif t == 'OnOffDev':
- return self.onoffdev, t
- elif t == 'DimDev':
- return self.dimdev, t
- elif t == 'VariableValue':
- return self.variablevalue, t
- elif t == 'GenericContent':
- return self.genericcontent, t
- elif t == 'Heading':
- return self.heading, t
- elif t == 'Link':
- return self.link, t
- else:
- print 'Unknown type in getSubTypeInstance'
- return None, 'Unknown'
- def getSubType(self):
- if hasattr(self, 'singledevcmd'):
- return 'SingleDevCmd'
- elif hasattr(self, 'onoffdev'):
- return 'OnOffDev'
- elif hasattr(self, 'dimdev'):
- return 'DimDev'
- elif hasattr(self, 'variablevalue'):
- return 'VariableValue'
- elif hasattr(self, 'genericcontent'):
- return 'GenericContent'
- elif hasattr(self, 'heading'):
- return 'Heading'
- elif hasattr(self, 'link'):
- return 'Link'
- else:
- print 'Unknown type in getSubType'
- return None
- def __unicode__(self):
- if self.displayText == '':
- subType, t = self.getSubTypeInstance()
- if subType:
- return subType.getDisplayText()
- else:
- return 'Unable to call subType.getDisplayText'
- return self.displayText
- class SingleDevCmd(Widget):
- dev = models.ForeignKey('core.Device')
- cmd = models.ForeignKey('core.Command')
-
- def getDisplayText(self):
- return self.dev.name
- def clean(self):
- super(SingleDevCmd, self).clean()
- if self.cmd.cmd == 'DIM':
- if not self.dev.dim:
- raise ValidationError('Dimming not supported by selected device')
- if self.cmd.cmd == 'ACTIVATE':
- if not self.dev.activate:
- raise ValidationError('Activate not supported by selected device')
- if self.cmd.cmd in ['ON', 'OFF']:
- if not self.dev.onOff:
- raise ValidationError('On/Off not supported by selected device')
- if self.cmd.cmd not in ['ON', 'OFF', 'ACTIVATE', 'DIM']:
- raise ValidationError('Selected command is not supported by selected device')
- class OnOffDev(Widget):
- dev = models.ForeignKey('core.Device')
- def getDisplayText(self):
- return self.dev.name
- def clean(self):
- super(OnOffDev, self).clean()
- if not self.dev.onOff:
- raise ValidationError('On/Off not supported by selected device')
- class DimDev(Widget):
- dev = models.ForeignKey('core.Device')
- def getDisplayText(self):
- return self.dev.name
- def clean(self):
- super(DimDev, self).clean()
- if not self.dev.dim:
- raise ValidationError('Dimming not supported by selected device')
- class VariableValue(Widget):
- var = models.ForeignKey('core.GlobalVariable')
- def getDisplayText(self):
- return self.var.name
- class Heading(Widget):
- divider = models.BooleanField(default = False, blank = True)
- def getDisplayText(self):
- return 'Divider'
- class Link(Widget):
- targetpage = models.ForeignKey(Page, null = True, blank = True, default = None, help_text="Link to another page of this or another remote")
- url = models.CharField(max_length = 255, default = '', blank = True, help_text = "Entar a URL")
- def clean(self):
- super(Link, self).clean()
- if self.page == None:
- if self.url == '':
- raise ValidationError("Cant have empty page and no URL")
- if self.url != '':
- if (not self.url.startswith('http://')) or (not self.url.startswith('https://')):
- self.url = 'http://' + self.url
- def getDisplayText(self):
- return self.linktext
- class GenericContent(Widget):
- content = models.TextField(default = '')
- def getDisplayText(self):
- return 'Generic Content'
- def render(remote):
- baseUrl = '/remote/' + str(remote.id) + '/'
- staticBaseUrl = '/static/automagically/'
- preRenderedCache[int(remote.id)] = remote.render(baseUrl, staticBaseUrl)
- print 'rendered into preRenderedCache', remote.id
- def getPreRendered(remote_id, page):
- if int(remote_id) not in preRenderedCache:
- print 'Remote missing in cache, need to render it'
- try:
- r = Remote.objects.get(id = remote_id)
- render(r)
- except:
- if debug:
- raise
- else:
- strings = traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)
- print 'Error rendering page'
- for s in strings:
- print s
- raise Http404
- return preRenderedCache[int(remote_id)].get(int(page), preRenderedCache.get(0))
- def getPreRenderedCacheManifest(remote_id):
- if int(remote_id) not in preRenderedCache:
- print 'Remote missing in cache, need to render it'
- try:
- r = Remote.objects.get(id = remote_id)
- render(r)
- except:
- if debug:
- raise
- else:
- strings = traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)
- print 'Error rendering page in getPreRenderedCacheManifest'
- for s in strings:
- print s
- raise Http404
- return preRenderedCache[int(remote_id)].get('CACHE_MANIFEST', HttpResponseNotFound())
- def getConfig(remote, page = None):
- """ Merge the two configs from remote and optionaly page
- and return that as a dictionary. Expect a , separated
- list of key/value pairs sepparated by :. Config in
- page take precedance over the one in remote."""
- res = {}
- cfg = remote.theme_config
- if page:
- cfg += ',' + page.config
- for s in cfg.split(','):
- if s != '':
- kv = s.split(':', 1)
- res[kv[0]] = kv[1]
- return res