Files
edx-platform/common/djangoapps/microsite_configuration/models.py
2016-02-02 19:01:09 +05:00

182 lines
5.8 KiB
Python

"""
Model to store a microsite in the database.
The object is stored as a json representation of the python dict
that would have been used in the settings.
"""
import collections
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import pre_save, pre_delete
from django.db.models.base import ObjectDoesNotExist
from django.contrib.sites.models import Site
from jsonfield.fields import JSONField
from model_utils.models import TimeStampedModel
from simple_history.models import HistoricalRecords
class Microsite(models.Model):
"""
This is where the information about the microsite gets stored to the db.
To achieve the maximum flexibility, most of the fields are stored inside
a json field.
Notes:
- The key field was required for the dict definition at the settings, and it
is used in some of the microsite_configuration methods.
- The site field is django site.
- The values field must be validated on save to prevent the platform from crashing
badly in the case the string is not able to be loaded as json.
"""
site = models.OneToOneField(Site, related_name='microsite')
key = models.CharField(max_length=63, db_index=True, unique=True)
values = JSONField(null=False, blank=True, load_kwargs={'object_pairs_hook': collections.OrderedDict})
def __unicode__(self):
return self.key
def get_organizations(self):
"""
Helper method to return a list of organizations associated with our particular Microsite
"""
return MicrositeOrganizationMapping.get_organizations_for_microsite_by_pk(self.id) # pylint: disable=no-member
@classmethod
def get_microsite_for_domain(cls, domain):
"""
Returns the microsite associated with this domain. Note that we always convert to lowercase, or
None if no match
"""
# remove any port number from the hostname
domain = domain.split(':')[0]
microsites = cls.objects.filter(site__domain__iexact=domain)
return microsites[0] if microsites else None
class MicrositeHistory(TimeStampedModel):
"""
This is an archive table for Microsites model, so that we can maintain a history of changes. Note that the
key field is no longer unique
"""
site = models.ForeignKey(Site, related_name='microsite_history')
key = models.CharField(max_length=63, db_index=True)
values = JSONField(null=False, blank=True, load_kwargs={'object_pairs_hook': collections.OrderedDict})
def __unicode__(self):
return self.key
class Meta(object):
""" Meta class for this Django model """
verbose_name_plural = "Microsite histories"
def _make_archive_copy(instance):
"""
Helper method to make a copy of a Microsite into the history table
"""
archive_object = MicrositeHistory(
key=instance.key,
site=instance.site,
values=instance.values,
)
archive_object.save()
@receiver(pre_delete, sender=Microsite)
def on_microsite_deleted(sender, instance, **kwargs): # pylint: disable=unused-argument
"""
Archive the exam attempt when the item is about to be deleted
Make a clone and populate in the History table
"""
_make_archive_copy(instance)
@receiver(pre_save, sender=Microsite)
def on_microsite_updated(sender, instance, **kwargs): # pylint: disable=unused-argument
"""
Archive the microsite on an update operation
"""
if instance.id:
# on an update case, get the original and archive it
original = Microsite.objects.get(id=instance.id)
_make_archive_copy(original)
class MicrositeOrganizationMapping(models.Model):
"""
Mapping of Organization to which Microsite it belongs
"""
organization = models.CharField(max_length=63, db_index=True, unique=True)
microsite = models.ForeignKey(Microsite, db_index=True)
# for archiving
history = HistoricalRecords()
def __unicode__(self):
"""String conversion"""
return u'{microsite_key}: {organization}'.format(
microsite_key=self.microsite.key,
organization=self.organization
)
@classmethod
def get_organizations_for_microsite_by_pk(cls, microsite_pk):
"""
Returns a list of organizations associated with the microsite key, returned as a set
"""
return cls.objects.filter(microsite_id=microsite_pk).values_list('organization', flat=True)
@classmethod
def get_microsite_for_organization(cls, org):
"""
Returns the microsite object for a given organization based on the table mapping, None if
no mapping exists
"""
try:
item = cls.objects.select_related('microsite').get(organization=org)
return item.microsite
except ObjectDoesNotExist:
return None
class MicrositeTemplate(models.Model):
"""
A HTML template that a microsite can use
"""
microsite = models.ForeignKey(Microsite, db_index=True)
template_uri = models.CharField(max_length=255, db_index=True)
template = models.TextField()
# for archiving
history = HistoricalRecords()
def __unicode__(self):
"""String conversion"""
return u'{microsite_key}: {template_uri}'.format(
microsite_key=self.microsite.key,
template_uri=self.template_uri
)
class Meta(object):
""" Meta class for this Django model """
unique_together = (('microsite', 'template_uri'),)
@classmethod
def get_template_for_microsite(cls, domain, template_uri):
"""
Returns the template object for the microsite, None if not found
"""
try:
return cls.objects.get(microsite__site__domain=domain, template_uri=template_uri)
except ObjectDoesNotExist:
return None