5 from collections import defaultdict
6 from django.forms.models import model_to_dict
7 from django.db import models
8 from django.db.models import F, Q
9 from core.models import PlCoreBase,Site, DashboardView, DiffModelMixIn
10 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
11 from timezones.fields import TimeZoneField
12 from operator import itemgetter, attrgetter
13 from django.core.mail import EmailMultiAlternatives
14 from core.middleware import get_request
16 from django.core.exceptions import PermissionDenied
18 # ------ from plcorebase.py ------
20 # This is a no-op if observer_disabled is set to 1 in the config file
21 from observer import *
23 print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
27 # guard against something failing
28 def notify_observer(*args, **kwargs):
32 # Create your models here.
33 class UserManager(BaseUserManager):
34 def create_user(self, email, firstname, lastname, password=None):
36 Creates and saves a User with the given email, date of
40 raise ValueError('Users must have an email address')
43 email=UserManager.normalize_email(email),
48 #user.set_password(password)
50 user.save(using=self._db)
53 def create_superuser(self, email, firstname, lastname, password):
55 Creates and saves a superuser with the given email, date of
58 user = self.create_user(email,
64 user.save(using=self._db)
67 def get_queryset(self):
68 parent=super(UserManager, self)
69 if hasattr(parent, "get_queryset"):
70 return parent.get_queryset().filter(deleted=False)
72 return parent.get_query_set().filter(deleted=False)
74 # deprecated in django 1.7 in favor of get_queryset().
75 def get_query_set(self):
76 return self.get_queryset()
78 class DeletedUserManager(UserManager):
79 def get_queryset(self):
80 return super(UserManager, self).get_query_set().filter(deleted=True)
82 # deprecated in django 1.7 in favor of get_queryset()
83 def get_query_set(self):
84 return self.get_queryset()
86 class User(AbstractBaseUser): #, DiffModelMixIn):
88 # ---- copy stuff from DiffModelMixin ----
92 return model_to_dict(self, fields=[field.name for field in
99 diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]]
103 def has_changed(self):
104 return bool(self.diff)
107 def changed_fields(self):
108 return self.diff.keys()
110 def has_field_changed(self, field_name):
111 return field_name in self.diff.keys()
113 def get_field_diff(self, field_name):
114 return self.diff.get(field_name, None)
117 def getValidators(cls):
118 """ primarily for REST API, return a dictionary of field names mapped
119 to lists of the type of validations that need to be applied to
123 for field in cls._meta.fields:
125 if field.blank==False:
127 if field.__class__.__name__=="URLField":
129 validators[field.name] = l
131 # ---- end copy stuff from DiffModelMixin ----
134 def remote_password(self):
135 return hashlib.md5(self.password).hexdigest()[:12]
140 email = models.EmailField(
141 verbose_name='email address',
147 username = models.CharField(max_length=255, default="Something" )
149 firstname = models.CharField(help_text="person's given name", max_length=200)
150 lastname = models.CharField(help_text="person's surname", max_length=200)
152 phone = models.CharField(null=True, blank=True, help_text="phone number contact", max_length=100)
153 user_url = models.URLField(null=True, blank=True)
154 site = models.ForeignKey(Site, related_name='users', help_text="Site this user will be homed too", null=True)
155 public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key string")
157 is_active = models.BooleanField(default=True)
158 is_admin = models.BooleanField(default=False)
159 is_staff = models.BooleanField(default=True)
160 is_readonly = models.BooleanField(default=False)
161 is_registering = models.BooleanField(default=False)
163 created = models.DateTimeField(auto_now_add=True)
164 updated = models.DateTimeField(auto_now=True)
165 enacted = models.DateTimeField(null=True, default=None)
166 policed = models.DateTimeField(null=True, default=None)
167 backend_status = models.CharField(max_length=140,
168 default="Provisioning in progress")
169 deleted = models.BooleanField(default=False)
171 timezone = TimeZoneField()
173 dashboards = models.ManyToManyField('DashboardView', through='UserDashboardView', blank=True)
175 objects = UserManager()
176 deleted_objects = DeletedUserManager()
178 USERNAME_FIELD = 'email'
179 REQUIRED_FIELDS = ['firstname', 'lastname']
181 PI_FORBIDDEN_FIELDS = ["is_admin", "site", "is_staff"]
182 USER_FORBIDDEN_FIELDS = ["is_admin", "is_active", "site", "is_staff", "is_readonly"]
184 def __init__(self, *args, **kwargs):
185 super(User, self).__init__(*args, **kwargs)
186 self._initial = self._dict # for DiffModelMixIn
188 def isReadOnlyUser(self):
189 return self.is_readonly
191 def get_full_name(self):
192 # The user is identified by their email address
195 def get_short_name(self):
196 # The user is identified by their email address
199 def delete(self, *args, **kwds):
200 # so we have something to give the observer
201 purge = kwds.get('purge',False)
205 purge = purge or observer_disabled
210 super(User, self).delete(*args, **kwds)
214 self.save(update_fields=['enacted','deleted'])
218 return self.email[:self.email.find('@')]
220 def __unicode__(self):
223 def has_perm(self, perm, obj=None):
224 "Does the user have a specific permission?"
225 # Simplest possible answer: Yes, always
228 def has_module_perms(self, app_label):
229 "Does the user have permissions to view the app `app_label`?"
230 # Simplest possible answer: Yes, always
233 def is_superuser(self):
236 def get_dashboards(self):
237 DEFAULT_DASHBOARDS=["Tenant"]
239 dashboards = sorted(list(self.userdashboardviews.all()), key=attrgetter('order'))
240 dashboards = [x.dashboardView for x in dashboards]
243 for dashboardName in DEFAULT_DASHBOARDS:
244 dbv = DashboardView.objects.filter(name=dashboardName)
246 dashboards.append(dbv[0])
250 # def get_roles(self):
251 # from core.models.site import SitePrivilege
252 # from core.models.slice import SliceMembership
254 # site_privileges = SitePrivilege.objects.filter(user=self)
255 # slice_memberships = SliceMembership.objects.filter(user=self)
256 # roles = defaultdict(list)
257 # for site_privilege in site_privileges:
258 # roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
259 # for slice_membership in slice_memberships:
260 # roles[slice_membership.role.role_type].append(slice_membership.slice.name)
263 def save(self, *args, **kwds):
265 self.set_password(self.password)
266 print "XXX", self, self.is_active, self.is_registering
267 if self.is_active and self.is_registering:
268 self.send_temporary_password()
\r
269 self.is_registering=False
\r
271 self.username = self.email
272 super(User, self).save(*args, **kwds)
274 self._initial = self._dict
276 def send_temporary_password(self):
277 password = User.objects.make_random_password()
278 self.set_password(password)
\r
279 subject, from_email, to = 'OpenCloud Account Credentials', 'support@opencloud.us', str(self.email)
\r
280 text_content = 'This is an important message.'
\r
281 userUrl="http://%s/" % get_request().get_host()
\r
282 html_content = """<p>Your account has been created on OpenCloud. Please log in <a href="""+userUrl+""">here</a> to activate your account<br><br>Username: """+self.email+"""<br>Temporary Password: """+password+"""<br>Please change your password once you successully login into the site.</p>"""
\r
283 msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
\r
284 msg.attach_alternative(html_content, "text/html")
\r
287 def can_update(self, user):
288 from core.models import SitePrivilege
289 _cant_update_fieldName = None
294 # site pis can update
295 site_privs = SitePrivilege.objects.filter(user=user, site=self.site)
296 for site_priv in site_privs:
297 if site_priv.role.role == 'pi':
298 for fieldName in self.diff.keys():
299 if fieldName in self.PI_FORBIDDEN_FIELDS:
300 _cant_update_fieldName = fieldName
303 if (user.id == self.id):
304 for fieldName in self.diff.keys():
305 if fieldName in self.USER_FORBIDDEN_FIELDS:
306 _cant_update_fieldName = fieldName
313 def select_by_user(user):
315 qs = User.objects.all()
317 # can see all users at any site where this user has pi role
318 from core.models.site import SitePrivilege
319 site_privs = SitePrivilege.objects.filter(user=user)
320 sites = [sp.site for sp in site_privs if sp.role.role == 'pi']
321 # get site privs of users at these sites
322 site_privs = SitePrivilege.objects.filter(site__in=sites)
323 user_ids = [sp.user.id for sp in site_privs] + [user.id]
324 qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
327 def save_by_user(self, user, *args, **kwds):
328 if not self.can_update(user):
329 if getattr(self, "_cant_update_fieldName", None) is not None:
330 raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
332 raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
334 self.save(*args, **kwds)
336 def delete_by_user(self, user, *args, **kwds):
337 if not self.can_update(user):
338 raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
339 self.delete(*args, **kwds)
341 class UserDashboardView(PlCoreBase):
342 user = models.ForeignKey(User, related_name='userdashboardviews')
343 dashboardView = models.ForeignKey(DashboardView, related_name='userdashboardviews')
344 order = models.IntegerField(default=0)