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=True)
159 is_staff = models.BooleanField(default=True)
160 is_readonly = models.BooleanField(default=False)
162 created = models.DateTimeField(auto_now_add=True)
163 updated = models.DateTimeField(auto_now=True)
164 enacted = models.DateTimeField(null=True, default=None)
165 policed = models.DateTimeField(null=True, default=None)
166 backend_status = models.CharField(max_length=140,
167 default="Provisioning in progress")
168 deleted = models.BooleanField(default=False)
170 timezone = TimeZoneField()
172 dashboards = models.ManyToManyField('DashboardView', through='UserDashboardView', blank=True)
174 objects = UserManager()
175 deleted_objects = DeletedUserManager()
177 USERNAME_FIELD = 'email'
178 REQUIRED_FIELDS = ['firstname', 'lastname']
180 PI_FORBIDDEN_FIELDS = ["is_admin", "site", "is_staff"]
181 USER_FORBIDDEN_FIELDS = ["is_admin", "is_active", "site", "is_staff", "is_readonly"]
183 def __init__(self, *args, **kwargs):
184 super(User, self).__init__(*args, **kwargs)
185 self._initial = self._dict # for DiffModelMixIn
187 def isReadOnlyUser(self):
188 return self.is_readonly
190 def get_full_name(self):
191 # The user is identified by their email address
194 def get_short_name(self):
195 # The user is identified by their email address
198 def delete(self, *args, **kwds):
199 # so we have something to give the observer
200 purge = kwds.get('purge',False)
204 purge = purge or observer_disabled
209 super(User, self).delete(*args, **kwds)
213 self.save(update_fields=['enacted','deleted'])
217 return self.email[:self.email.find('@')]
219 def __unicode__(self):
222 def has_perm(self, perm, obj=None):
223 "Does the user have a specific permission?"
224 # Simplest possible answer: Yes, always
227 def has_module_perms(self, app_label):
228 "Does the user have permissions to view the app `app_label`?"
229 # Simplest possible answer: Yes, always
232 def is_superuser(self):
235 def get_dashboards(self):
236 DEFAULT_DASHBOARDS=["Tenant"]
238 dashboards = sorted(list(self.userdashboardviews.all()), key=attrgetter('order'))
239 dashboards = [x.dashboardView for x in dashboards]
242 for dashboardName in DEFAULT_DASHBOARDS:
243 dbv = DashboardView.objects.filter(name=dashboardName)
245 dashboards.append(dbv[0])
249 # def get_roles(self):
250 # from core.models.site import SitePrivilege
251 # from core.models.slice import SliceMembership
253 # site_privileges = SitePrivilege.objects.filter(user=self)
254 # slice_memberships = SliceMembership.objects.filter(user=self)
255 # roles = defaultdict(list)
256 # for site_privilege in site_privileges:
257 # roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
258 # for slice_membership in slice_memberships:
259 # roles[slice_membership.role.role_type].append(slice_membership.slice.name)
262 def save(self, *args, **kwds):
264 self.set_password(self.password)
266 if self.password=="!":
\r
267 self.send_temporary_password()
\r
269 self.username = self.email
270 super(User, self).save(*args, **kwds)
272 self._initial = self._dict
274 def send_temporary_password(self):
275 password = User.objects.make_random_password()
276 self.set_password(password)
\r
277 subject, from_email, to = 'OpenCloud Account Credentials', 'support@opencloud.us', str(self.email)
\r
278 text_content = 'This is an important message.'
\r
279 userUrl="http://%s/" % get_request().get_host()
\r
280 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
281 msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
\r
282 msg.attach_alternative(html_content, "text/html")
\r
285 def can_update(self, user):
286 from core.models import SitePrivilege
287 _cant_update_fieldName = None
292 # site pis can update
293 site_privs = SitePrivilege.objects.filter(user=user, site=self.site)
294 for site_priv in site_privs:
295 if site_priv.role.role == 'pi':
296 for fieldName in self.diff.keys():
297 if fieldName in self.PI_FORBIDDEN_FIELDS:
298 _cant_update_fieldName = fieldName
301 if (user.id == self.id):
302 for fieldName in self.diff.keys():
303 if fieldName in self.USER_FORBIDDEN_FIELDS:
304 _cant_update_fieldName = fieldName
311 def select_by_user(user):
313 qs = User.objects.all()
315 # can see all users at any site where this user has pi role
316 from core.models.site import SitePrivilege
317 site_privs = SitePrivilege.objects.filter(user=user)
318 sites = [sp.site for sp in site_privs if sp.role.role == 'pi']
319 # get site privs of users at these sites
320 site_privs = SitePrivilege.objects.filter(site__in=sites)
321 user_ids = [sp.user.id for sp in site_privs] + [user.id]
322 qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
325 def save_by_user(self, user, *args, **kwds):
326 if not self.can_update(user):
327 if getattr(self, "_cant_update_fieldName", None) is not None:
328 raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
330 raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
332 self.save(*args, **kwds)
334 def delete_by_user(self, user, *args, **kwds):
335 if not self.can_update(user):
336 raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
337 self.delete(*args, **kwds)
339 class UserDashboardView(PlCoreBase):
340 user = models.ForeignKey(User, related_name='userdashboardviews')
341 dashboardView = models.ForeignKey(DashboardView, related_name='userdashboardviews')
342 order = models.IntegerField(default=0)