trailing spaces in sql schema
[plcapi.git] / PLC / Persons.py
index 060a46f..bc4b4c1 100644 (file)
@@ -5,18 +5,13 @@
 # Copyright (C) 2006 The Trustees of Princeton University
 #
 
 # 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 *
 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
 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()
         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
 
         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']:
 
         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
 
 
         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())
         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
 
     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']):
 
         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
 
 
         return False
 
@@ -155,7 +150,7 @@ class Person(Row):
 
         1. We are the person.
         2. We are an admin.
 
         1. We are the person.
         2. We are an admin.
-        3. We are a PI and the person is at one of our sites.
+        3. We are a PI or Tech and the person is at one of our sites.
         """
 
         assert isinstance(person, Person)
         """
 
         assert isinstance(person, Person)
@@ -163,10 +158,10 @@ class Person(Row):
         if self.can_update(person):
             return True
 
         if self.can_update(person):
             return True
 
-        if 'pi' 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']):
             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
 
 
         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')
         # 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:
 
         # 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')
         # 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:
 
         # 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
         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)
 
             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')
         # 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:
 
         # Add new ids, remove stale ids
         if self['slice_ids'] != slice_ids:
@@ -359,6 +354,12 @@ class Person(Row):
 
         # Mark as deleted
         self['deleted'] = True
 
         # Mark as deleted
         self['deleted'] = True
+
+        # 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)
 
         # don't validate, so duplicates can be consistently removed
         self.sync(commit, validate=False)
 
@@ -373,29 +374,30 @@ class Persons(Table):
 
         view = "view_persons"
         for tagname in self.tag_columns:
 
         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" % \
                                                 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
 
         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_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")
                 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")
                 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:
                 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)
 
         self.selectall(sql)