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)
115 # ---- end copy stuff from DiffModelMixin ----
118 def remote_password(self):
119 return hashlib.md5(self.password).hexdigest()[:12]
124 email = models.EmailField(
125 verbose_name='email address',
131 username = models.CharField(max_length=255, default="Something" )
133 firstname = models.CharField(help_text="person's given name", max_length=200)
134 lastname = models.CharField(help_text="person's surname", max_length=200)
136 phone = models.CharField(null=True, blank=True, help_text="phone number contact", max_length=100)
137 user_url = models.URLField(null=True, blank=True)
138 site = models.ForeignKey(Site, related_name='users', help_text="Site this user will be homed too", null=True)
139 public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key string")
141 is_active = models.BooleanField(default=True)
142 is_admin = models.BooleanField(default=True)
143 is_staff = models.BooleanField(default=True)
144 is_readonly = models.BooleanField(default=False)
146 created = models.DateTimeField(auto_now_add=True)
147 updated = models.DateTimeField(auto_now=True)
148 enacted = models.DateTimeField(null=True, default=None)
149 backend_status = models.CharField(max_length=140,
150 default="Provisioning in progress")
151 deleted = models.BooleanField(default=False)
153 timezone = TimeZoneField()
155 dashboards = models.ManyToManyField('DashboardView', through='UserDashboardView', blank=True)
157 objects = UserManager()
158 deleted_objects = DeletedUserManager()
160 USERNAME_FIELD = 'email'
161 REQUIRED_FIELDS = ['firstname', 'lastname']
163 PI_FORBIDDEN_FIELDS = ["is_admin", "site", "is_staff"]
164 USER_FORBIDDEN_FIELDS = ["is_admin", "is_active", "site", "is_staff", "is_readonly"]
166 def __init__(self, *args, **kwargs):
167 super(User, self).__init__(*args, **kwargs)
168 self._initial = self._dict # for DiffModelMixIn
170 def isReadOnlyUser(self):
171 return self.is_readonly
173 def get_full_name(self):
174 # The user is identified by their email address
177 def get_short_name(self):
178 # The user is identified by their email address
181 def delete(self, *args, **kwds):
182 # so we have something to give the observer
183 purge = kwds.get('purge',False)
187 purge = purge or observer_disabled
192 super(User, self).delete(*args, **kwds)
196 self.save(update_fields=['enacted','deleted'])
200 return self.email[:self.email.find('@')]
202 def __unicode__(self):
205 def has_perm(self, perm, obj=None):
206 "Does the user have a specific permission?"
207 # Simplest possible answer: Yes, always
210 def has_module_perms(self, app_label):
211 "Does the user have permissions to view the app `app_label`?"
212 # Simplest possible answer: Yes, always
215 def is_superuser(self):
218 def get_dashboards(self):
219 DEFAULT_DASHBOARDS=["Tenant"]
221 dashboards = sorted(list(self.userdashboardviews.all()), key=attrgetter('order'))
222 dashboards = [x.dashboardView for x in dashboards]
225 for dashboardName in DEFAULT_DASHBOARDS:
226 dbv = DashboardView.objects.filter(name=dashboardName)
228 dashboards.append(dbv[0])
232 # def get_roles(self):
233 # from core.models.site import SitePrivilege
234 # from core.models.slice import SliceMembership
236 # site_privileges = SitePrivilege.objects.filter(user=self)
237 # slice_memberships = SliceMembership.objects.filter(user=self)
238 # roles = defaultdict(list)
239 # for site_privilege in site_privileges:
240 # roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
241 # for slice_membership in slice_memberships:
242 # roles[slice_membership.role.role_type].append(slice_membership.slice.name)
245 def save(self, *args, **kwds):
247 self.set_password(self.password)
249 if self.password=="!":
\r
250 self.send_temporary_password()
\r
252 self.username = self.email
253 super(User, self).save(*args, **kwds)
255 self._initial = self._dict
257 def send_temporary_password(self):
258 password = User.objects.make_random_password()
259 self.set_password(password)
\r
260 subject, from_email, to = 'OpenCloud Account Credentials', 'support@opencloud.us', str(self.email)
\r
261 text_content = 'This is an important message.'
\r
262 userUrl="http://%s/" % get_request().get_host()
\r
263 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
264 msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
\r
265 msg.attach_alternative(html_content, "text/html")
\r
268 def can_update(self, user):
269 from core.models import SitePrivilege
270 _cant_update_fieldName = None
275 # site pis can update
276 site_privs = SitePrivilege.objects.filter(user=user, site=self.site)
277 for site_priv in site_privs:
278 if site_priv.role.role == 'pi':
279 for fieldName in self.diff.keys():
280 if fieldName in self.PI_FORBIDDEN_FIELDS:
281 _cant_update_fieldName = fieldName
284 if (user.id == self.id):
285 for fieldName in self.diff.keys():
286 if fieldName in self.USER_FORBIDDEN_FIELDS:
287 _cant_update_fieldName = fieldName
294 def select_by_user(user):
296 qs = User.objects.all()
298 # can see all users at any site where this user has pi role
299 from core.models.site import SitePrivilege
300 site_privs = SitePrivilege.objects.filter(user=user)
301 sites = [sp.site for sp in site_privs if sp.role.role == 'pi']
302 # get site privs of users at these sites
303 site_privs = SitePrivilege.objects.filter(site__in=sites)
304 user_ids = [sp.user.id for sp in site_privs] + [user.id]
305 qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
308 def save_by_user(self, user, *args, **kwds):
309 if not self.can_update(user):
310 if getattr(self, "_cant_update_fieldName", None) is not None:
311 raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
313 raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
315 self.save(*args, **kwds)
317 def delete_by_user(self, user, *args, **kwds):
318 if not self.can_update(user):
319 raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
320 self.delete(*args, **kwds)
322 class UserDashboardView(PlCoreBase):
323 user = models.ForeignKey(User, related_name='userdashboardviews')
324 dashboardView = models.ForeignKey(DashboardView, related_name='userdashboardviews')
325 order = models.IntegerField(default=0)