Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
[plstackapi.git] / planetstack / core / models / plcorebase.py
1 import datetime
2 import os
3 import sys
4 from django.db import models
5 from django.forms.models import model_to_dict
6 from django.core.urlresolvers import reverse
7 from django.forms.models import model_to_dict
8 import model_policy
9
10 try:
11     # This is a no-op if observer_disabled is set to 1 in the config file
12     from observer import *
13 except:
14     print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
15     import traceback
16     traceback.print_exc()
17
18     # guard against something failing
19     def notify_observer(*args, **kwargs):
20         pass
21
22 # This manager will be inherited by all subclasses because
23 # the core model is abstract.
24 class PlCoreBaseDeletionManager(models.Manager):
25     def get_query_set(self):
26         return super(PlCoreBaseDeletionManager, self).get_query_set().filter(deleted=True)
27
28 # This manager will be inherited by all subclasses because
29 # the core model is abstract.
30 class PlCoreBaseManager(models.Manager):
31     def get_query_set(self):
32         return super(PlCoreBaseManager, self).get_query_set().filter(deleted=False)
33
34 class PlCoreBase(models.Model):
35     objects = PlCoreBaseManager()
36     deleted_objects = PlCoreBaseDeletionManager()
37
38     # default values for created and updated are only there to keep evolution
39     # from failing.
40     created = models.DateTimeField(auto_now_add=True, default=datetime.datetime.now())
41     updated = models.DateTimeField(auto_now=True, default=datetime.datetime.now())
42     enacted = models.DateTimeField(null=True, default=None)
43     backend_status = models.CharField(max_length=140,
44                                       default="Provisioning in progress")
45     deleted = models.BooleanField(default=False)
46
47     class Meta:
48         # Changing abstract to False would require the managers of subclasses of
49         # PlCoreBase to be customized individually.
50         abstract = True
51         app_label = "core"
52
53     def __init__(self, *args, **kwargs):
54         super(PlCoreBase, self).__init__(*args, **kwargs)
55         self.__initial = self._dict
56
57     @property
58     def diff(self):
59         d1 = self.__initial
60         d2 = self._dict
61         diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]]
62         return dict(diffs)
63
64     @property
65     def has_changed(self):
66         return bool(self.diff)
67
68     @property
69     def changed_fields(self):
70         return self.diff.keys()
71
72     def get_field_diff(self, field_name):
73         return self.diff.get(field_name, None)
74
75     def can_update(self, user):
76         if user.is_readonly:
77             return False
78         if user.is_admin:
79             return True
80         return False
81
82     def delete(self, *args, **kwds):
83         # so we have something to give the observer
84         purge = kwds.get('purge',False)
85         try:
86             purge = purge or observer_disabled
87         except NameError:
88             pass
89             
90         if (purge):
91             del kwds['purge']
92             super(PlCoreBase, self).delete(*args, **kwds)
93         else:
94             self.deleted = True
95             self.enacted=None
96             self.save(update_fields=['enacted','deleted'])
97
98
99     def save(self, *args, **kwargs):
100         super(PlCoreBase, self).save(*args, **kwargs)
101
102         # This is a no-op if observer_disabled is set
103         notify_observer()
104
105         self.__initial = self._dict
106
107     def save_by_user(self, user, *args, **kwds):
108         if self.can_update(user):
109             self.save(*args, **kwds)
110
111     def delete_by_user(self, user, *args, **kwds):
112         if self.can_update(user):
113             self.delete(*args, **kwds)
114
115     @property
116     def _dict(self):
117         return model_to_dict(self, fields=[field.name for field in
118                              self._meta.fields])
119
120
121