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 backend_status = models.CharField(max_length=140,
166 default="Provisioning in progress")
167 deleted = models.BooleanField(default=False)
169 timezone = TimeZoneField()
171 dashboards = models.ManyToManyField('DashboardView', through='UserDashboardView', blank=True)
173 objects = UserManager()
174 deleted_objects = DeletedUserManager()
176 USERNAME_FIELD = 'email'
177 REQUIRED_FIELDS = ['firstname', 'lastname']
179 PI_FORBIDDEN_FIELDS = ["is_admin", "site", "is_staff"]
180 USER_FORBIDDEN_FIELDS = ["is_admin", "is_active", "site", "is_staff", "is_readonly"]
182 def __init__(self, *args, **kwargs):
183 super(User, self).__init__(*args, **kwargs)
184 self._initial = self._dict # for DiffModelMixIn
186 def isReadOnlyUser(self):
187 return self.is_readonly
189 def get_full_name(self):
190 # The user is identified by their email address
193 def get_short_name(self):
194 # The user is identified by their email address
197 def delete(self, *args, **kwds):
198 # so we have something to give the observer
199 purge = kwds.get('purge',False)
203 purge = purge or observer_disabled
208 super(User, self).delete(*args, **kwds)
212 self.save(update_fields=['enacted','deleted'])
216 return self.email[:self.email.find('@')]
218 def __unicode__(self):
221 def has_perm(self, perm, obj=None):
222 "Does the user have a specific permission?"
223 # Simplest possible answer: Yes, always
226 def has_module_perms(self, app_label):
227 "Does the user have permissions to view the app `app_label`?"
228 # Simplest possible answer: Yes, always
231 def is_superuser(self):
234 def get_dashboards(self):
235 DEFAULT_DASHBOARDS=["Tenant"]
237 dashboards = sorted(list(self.userdashboardviews.all()), key=attrgetter('order'))
238 dashboards = [x.dashboardView for x in dashboards]
241 for dashboardName in DEFAULT_DASHBOARDS:
242 dbv = DashboardView.objects.filter(name=dashboardName)
244 dashboards.append(dbv[0])
248 # def get_roles(self):
249 # from core.models.site import SitePrivilege
250 # from core.models.slice import SliceMembership
252 # site_privileges = SitePrivilege.objects.filter(user=self)
253 # slice_memberships = SliceMembership.objects.filter(user=self)
254 # roles = defaultdict(list)
255 # for site_privilege in site_privileges:
256 # roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
257 # for slice_membership in slice_memberships:
258 # roles[slice_membership.role.role_type].append(slice_membership.slice.name)
261 def save(self, *args, **kwds):
263 self.set_password(self.password)
265 if self.password=="!":
\r
266 self.send_temporary_password()
\r
268 self.username = self.email
269 super(User, self).save(*args, **kwds)
271 self._initial = self._dict
273 def send_temporary_password(self):
274 password = User.objects.make_random_password()
275 self.set_password(password)
\r
276 subject, from_email, to = 'OpenCloud Account Credentials', 'support@opencloud.us', str(self.email)
\r
277 text_content = 'This is an important message.'
\r
278 userUrl="http://%s/" % get_request().get_host()
\r
279 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
280 msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
\r
281 msg.attach_alternative(html_content, "text/html")
\r
284 def can_update(self, user):
285 from core.models import SitePrivilege
286 _cant_update_fieldName = None
291 # site pis can update
292 site_privs = SitePrivilege.objects.filter(user=user, site=self.site)
293 for site_priv in site_privs:
294 if site_priv.role.role == 'pi':
295 for fieldName in self.diff.keys():
296 if fieldName in self.PI_FORBIDDEN_FIELDS:
297 _cant_update_fieldName = fieldName
300 if (user.id == self.id):
301 for fieldName in self.diff.keys():
302 if fieldName in self.USER_FORBIDDEN_FIELDS:
303 _cant_update_fieldName = fieldName
310 def select_by_user(user):
312 qs = User.objects.all()
314 # can see all users at any site where this user has pi role
315 from core.models.site import SitePrivilege
316 site_privs = SitePrivilege.objects.filter(user=user)
317 sites = [sp.site for sp in site_privs if sp.role.role == 'pi']
318 # get site privs of users at these sites
319 site_privs = SitePrivilege.objects.filter(site__in=sites)
320 user_ids = [sp.user.id for sp in site_privs] + [user.id]
321 qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
324 def save_by_user(self, user, *args, **kwds):
325 if not self.can_update(user):
326 if getattr(self, "_cant_update_fieldName", None) is not None:
327 raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
329 raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
331 self.save(*args, **kwds)
333 def delete_by_user(self, user, *args, **kwds):
334 if not self.can_update(user):
335 raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
336 self.delete(*args, **kwds)
338 class UserDashboardView(PlCoreBase):
339 user = models.ForeignKey(User, related_name='userdashboardviews')
340 dashboardView = models.ForeignKey(DashboardView, related_name='userdashboardviews')
341 order = models.IntegerField(default=0)