use the SMTP library as advertised
[plcapi.git] / PLC / Persons.py
index 8da70ef..bc4b4c1 100644 (file)
@@ -5,18 +5,13 @@
 # Copyright (C) 2006 The Trustees of Princeton University
 #
 
-from types import StringTypes
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
+from hashlib import md5
 import time
 from random import Random
 import re
 import crypt
 
 from PLC.Faults import *
-from PLC.Debug import log
 from PLC.Parameter import Parameter, Mixed
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
@@ -78,7 +73,7 @@ class Person(Row):
         Validate email address. Stolen from Mailman.
         """
         email = email.lower()
-        invalid_email = PLCInvalidArgument("Invalid e-mail address")
+        invalid_email = PLCInvalidArgument("Invalid e-mail address %s"%email)
 
         if not email:
             raise invalid_email
@@ -97,7 +92,7 @@ class Person(Row):
 
         for person in conflicts:
             if 'person_id' not in self or self['person_id'] != person['person_id']:
-                raise PLCInvalidArgument, "E-mail address already in use"
+                raise PLCInvalidArgument("E-mail address already in use")
 
         return email
 
@@ -115,8 +110,8 @@ class Person(Row):
         else:
             # Generate a somewhat unique 8 character salt string
             salt = str(time.time()) + str(Random().random())
-            salt = md5(salt).hexdigest()[:8]
-            return crypt.crypt(password.encode(self.api.encoding), magic + salt + "$")
+            salt = md5(salt.encode()).hexdigest()[:8]
+            return crypt.crypt(password, magic + salt + "$")
 
     validate_date_created = Row.validate_timestamp
     validate_last_updated = Row.validate_timestamp
@@ -143,8 +138,8 @@ class Person(Row):
 
         if 'pi' in self['roles']:
             if set(self['site_ids']).intersection(person['site_ids']):
-                # Can update person is neither a PI or ADMIN
-                return (not (('pi' in person['roles']) or ('admin' in person['roles'])))
+                # non-admin users cannot update a person who is neither a PI or ADMIN
+                return (not set(['pi','admin']).intersection(person['roles']))
 
         return False
 
@@ -163,10 +158,10 @@ class Person(Row):
         if self.can_update(person):
             return True
 
-        if 'pi' in self['roles'] or 'tech' in self['roles']:
+        # pis and techs can see all people on their site
+        if set(['pi','tech']).intersection(self['roles']):
             if set(self['site_ids']).intersection(person['site_ids']):
-                # Can view people with equal or higher role IDs
-                return 'admin' not in person['roles']
+                return True
 
         return False
 
@@ -231,7 +226,7 @@ class Person(Row):
         # Translate roles into role_ids
         if role_names:
             roles = Roles(self.api, role_names).dict('role_id')
-            role_ids += roles.keys()
+            role_ids += list(roles.keys())
 
         # Add new ids, remove stale ids
         if self['role_ids'] != role_ids:
@@ -263,7 +258,7 @@ class Person(Row):
         # Translate roles into role_ids
         if site_names:
             sites = Sites(self.api, site_names, ['site_id']).dict('site_id')
-            site_ids += sites.keys()
+            site_ids += list(sites.keys())
 
         # Add new ids, remove stale ids
         if self['site_ids'] != site_ids:
@@ -300,8 +295,8 @@ class Person(Row):
         if keys:
             from PLC.Methods.AddPersonKey import AddPersonKey
             from PLC.Methods.UpdateKey import UpdateKey
-            updated_keys = filter(lambda key: 'key_id' in key, keys)
-            added_keys = filter(lambda key: 'key_id' not in key, keys)
+            updated_keys = [key for key in keys if 'key_id' in key]
+            added_keys = [key for key in keys if 'key_id' not in key]
 
             for key in added_keys:
                 AddPersonKey.__call__(AddPersonKey(self.api), auth, self['person_id'], key)
@@ -327,7 +322,7 @@ class Person(Row):
         # Translate roles into role_ids
         if slice_names:
             slices = Slices(self.api, slice_names, ['slice_id']).dict('slice_id')
-            slice_ids += slices.keys()
+            slice_ids += list(slices.keys())
 
         # Add new ids, remove stale ids
         if self['slice_ids'] != slice_ids:
@@ -360,10 +355,10 @@ class Person(Row):
         # Mark as deleted
         self['deleted'] = True
 
-        # delete will fail if verification_expires exists and isn't validated
-        if 'verification_expires' in self:
-            self['verification_expires'] = \
-            self.validate_verification_expires(self['verification_expires'])
+        # delete will fail if timestamp fields aren't validated, so lets remove them
+        for field in ['verification_expires', 'date_created', 'last_updated']:
+            if field in self:
+                self.pop(field)
 
         # don't validate, so duplicates can be consistently removed
         self.sync(commit, validate=False)
@@ -379,29 +374,30 @@ class Persons(Table):
 
         view = "view_persons"
         for tagname in self.tag_columns:
-            view= "%s left join %s using (%s)"%(view,Person.tagvalue_view_name(tagname),
+            view= "%s left join %s using (%s)"%(view, Person.tagvalue_view_name(tagname),
                                                 Person.primary_key)
 
         sql = "SELECT %s FROM %s WHERE deleted IS False" % \
-            (", ".join(self.columns.keys()+self.tag_columns.keys()),view)
+            (", ".join(list(self.columns.keys())+list(self.tag_columns.keys())), view)
 
         if person_filter is not None:
             if isinstance(person_filter, (list, tuple, set)):
                 # Separate the list into integers and strings
-                ints = filter(lambda x: isinstance(x, (int, long)), person_filter)
-                strs = filter(lambda x: isinstance(x, StringTypes), person_filter)
+                ints = [x for x in person_filter if isinstance(x, int)]
+                strs = [x for x in person_filter if isinstance(x, str)]
                 person_filter = Filter(Person.fields, {'person_id': ints, 'email': strs})
                 sql += " AND (%s) %s" % person_filter.sql(api, "OR")
             elif isinstance(person_filter, dict):
-                person_filter = Filter(Person.fields, person_filter)
+                allowed_fields = dict(list(Person.fields.items())+list(Person.tags.items()))
+                person_filter = Filter(allowed_fields, person_filter)
                 sql += " AND (%s) %s" % person_filter.sql(api, "AND")
-            elif isinstance (person_filter, StringTypes):
-                person_filter = Filter(Person.fields, {'email':person_filter})
+            elif isinstance (person_filter, str):
+                person_filter = Filter(Person.fields, {'email': person_filter})
                 sql += " AND (%s) %s" % person_filter.sql(api, "AND")
-            elif isinstance (person_filter, (int, long)):
-                person_filter = Filter(Person.fields, {'person_id':person_filter})
+            elif isinstance (person_filter, int):
+                person_filter = Filter(Person.fields, {'person_id': person_filter})
                 sql += " AND (%s) %s" % person_filter.sql(api, "AND")
             else:
-                raise PLCInvalidArgument, "Wrong person filter %r"%person_filter
+                raise PLCInvalidArgument("Wrong person filter %r"%person_filter)
 
         self.selectall(sql)