StringTypes has gone
[plcapi.git] / PLC / Persons.py
index 060a46f..dc971b3 100644 (file)
@@ -5,7 +5,6 @@
 # Copyright (C) 2006 The Trustees of Princeton University
 #
 
-from types import StringTypes
 try:
     from hashlib import md5
 except ImportError:
@@ -16,7 +15,6 @@ 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 +76,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 +95,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
 
@@ -143,8 +141,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
 
@@ -155,7 +153,7 @@ class Person(Row):
 
         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)
@@ -163,10 +161,10 @@ class Person(Row):
         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']):
-                # Can view people with equal or higher role IDs
-                return 'admin' not in person['roles']
+                return True
 
         return False
 
@@ -231,7 +229,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 +261,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 +298,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 +325,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:
@@ -359,6 +357,12 @@ class Person(Row):
 
         # 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)
 
@@ -377,25 +381,26 @@ class Persons(Table):
                                                 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):
+            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)):
+            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)