First draft for leases
[plcapi.git] / PLC / Persons.py
index 6feb270..5a02403 100644 (file)
@@ -9,8 +9,10 @@
 #
 
 from types import StringTypes
-from datetime import datetime
-import md5
+try:
+    from hashlib import md5
+except ImportError:
+    from md5 import md5
 import time
 from random import Random
 import re
@@ -57,6 +59,7 @@ class Person(Row):
         'slice_ids': Parameter([int], "List of slice identifiers"),
         'peer_id': Parameter(int, "Peer to which this user belongs", nullok = True),
         'peer_person_id': Parameter(int, "Foreign user identifier at peer", nullok = True),
+        'person_tag_ids' : Parameter ([int], "List of tags attached to this person"),
         }
     related_fields = {
        'roles': [Mixed(Parameter(int, "Role identifier"),
@@ -68,44 +71,34 @@ class Person(Row):
        'slices': [Mixed(Parameter(int, "Slice identifier"),
                         Parameter(str, "Slice name"))]
        }       
+    view_tags_name = "view_person_tags"
+    # tags are used by the Add/Get/Update methods to expose tags
+    # this is initialized here and updated by the accessors factory
+    tags = { }
 
     def validate_email(self, email):
         """
         Validate email address. Stolen from Mailman.
         """
-
+        email = email.lower()
         invalid_email = PLCInvalidArgument("Invalid e-mail address")
-        email_badchars = r'[][()<>|;^,\200-\377]'
 
-        # Pretty minimal, cheesy check.  We could do better...
-        if not email or email.count(' ') > 0:
-            raise invalid_email
-        if re.search(email_badchars, email) or email[0] == '-':
+        if not email:
             raise invalid_email
 
-        email = email.lower()
-        at_sign = email.find('@')
-        if at_sign < 1:
-            raise invalid_email
-        user = email[:at_sign]
-        rest = email[at_sign+1:]
-        domain = rest.split('.')
-
-        # This means local, unqualified addresses, are not allowed
-        if not domain:
-            raise invalid_email
-        if len(domain) < 2:
+        email_re = re.compile('\A[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9._\-]+\.[a-zA-Z]+\Z')
+        if not email_re.match(email):
             raise invalid_email
 
                # check only against users on the same peer  
-       if 'peer_id' in self:
+        if 'peer_id' in self:
             namespace_peer_id = self['peer_id']
         else:
             namespace_peer_id = None
          
-       conflicts = Persons(self.api, {'email':email,'peer_id':namespace_peer_id}) 
+        conflicts = Persons(self.api, {'email':email,'peer_id':namespace_peer_id}) 
        
-       for person in conflicts:
+        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"
 
@@ -125,7 +118,7 @@ class Person(Row):
         else:
             # Generate a somewhat unique 8 character salt string
             salt = str(time.time()) + str(Random().random())
-            salt = md5.md5(salt).hexdigest()[:8] 
+            salt = md5(salt).hexdigest()[:8] 
             return crypt.crypt(password.encode(self.api.encoding), magic + salt + "$")
 
     validate_date_created = Row.validate_timestamp
@@ -380,15 +373,20 @@ class Persons(Table):
     def __init__(self, api, person_filter = None, columns = None):
         Table.__init__(self, api, Person, columns)
 
-       sql = "SELECT %s FROM view_persons WHERE deleted IS False" % \
-              ", ".join(self.columns)
+        view = "view_persons"
+        for tagname in self.tag_columns:
+            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)
 
         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)
-                node_filter = Filter(Person.fields, {'person_id': ints, 'email': strs})
+                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)