- import Faults
[plcapi.git] / PLC / Persons.py
index c61e8bd..4261bfc 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Persons.py,v 1.17 2006/11/08 22:45:20 mlhuang Exp $
+# $Id: Persons.py,v 1.28 2007/01/05 19:50:20 tmack Exp $
 #
 
 from types import StringTypes
@@ -16,10 +16,12 @@ import re
 import crypt
 
 from PLC.Faults import *
+from PLC.Debug import log
 from PLC.Parameter import Parameter
 from PLC.Filter import Filter
 from PLC.Table import Row, Table
 from PLC.Keys import Key, Keys
+from PLC.Messages import Message, Messages
 import PLC.Sites
 
 class Person(Row):
@@ -43,15 +45,32 @@ class Person(Row):
         'bio': Parameter(str, "Biography", max = 254, nullok = True),
         'enabled': Parameter(bool, "Has been enabled"),
         'password': Parameter(str, "Account password in crypt() form", max = 254),
-        'last_updated': Parameter(int, "Date and time of last update", ro = True),
+        'verification_key': Parameter(str, "Reset password key", max = 254),
+       'verification_expires': Parameter(str, "Date/Time when verification_key expires", max = 254),
+       'last_updated': Parameter(int, "Date and time of last update", ro = True),
         'date_created': Parameter(int, "Date and time when account was created", ro = True),
         'role_ids': Parameter([int], "List of role identifiers"),
         'roles': Parameter([str], "List of roles"),
         'site_ids': Parameter([int], "List of site identifiers"),
         'key_ids': Parameter([int], "List of key identifiers"),
         'slice_ids': Parameter([int], "List of slice identifiers"),
+        'peer_id': Parameter(int, "Peer at which this slice was created", nullok = True),
         }
 
+    # for Cache
+    class_key = 'email'
+    foreign_fields = ['first_name', 'last_name', 'title', 'email', 'phone', 'url',
+                     'bio', 'enabled', 'password', ]
+    # forget about these ones, they are read-only anyway
+    # handling them causes Cache to re-sync all over again 
+    # 'last_updated', 'date_created'
+    foreign_xrefs = [
+        {'field' : 'key_ids',  'class': 'Key',  'table' : 'person_key' } ,
+        {'field' : 'site_ids', 'class': 'Site', 'table' : 'person_site'},
+#       xxx this is not handled by Cache yet
+#        'role_ids': Parameter([int], "List of role identifiers"),
+]
+
     def validate_email(self, email):
         """
         Validate email address. Stolen from Mailman.
@@ -81,8 +100,8 @@ class Person(Row):
             raise invalid_email
 
         conflicts = Persons(self.api, [email])
-        for person_id, person in conflicts.iteritems():
-            if 'person_id' not in self or self['person_id'] != 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"
 
         return email
@@ -104,6 +123,13 @@ class Person(Row):
             salt = md5.md5(salt).hexdigest()[:8] 
             return crypt.crypt(password.encode(self.api.encoding), magic + salt + "$")
 
+    # timestamps
+    # verification_expires in the DB but not exposed here
+    def validate_date_created (self, timestamp):
+       return self.validate_timestamp (timestamp)
+    def validate_last_updated (self, timestamp):
+       return self.validate_timestamp (timestamp)
+
     def can_update(self, person):
         """
         Returns true if we can update the specified person. We can
@@ -265,6 +291,71 @@ class Person(Row):
         self['site_ids'].remove(site_id)
         self['site_ids'].insert(0, site_id)
 
+    def send_initiate_password_reset_email(self):
+       # email user next step instructions
+        to_addr = {}
+        to_addr[self['email']] = "%s %s" % \
+            (self['first_name'], self['last_name'])
+        from_addr = {}
+        from_addr[self.api.config.PLC_MAIL_SUPPORT_ADDRESS] = \
+        "%s %s" % ('Planetlab', 'Support')
+
+       # fill in template
+        messages = Messages(self.api, ['ASSWORD_RESET_INITIATE'])
+        if not messages:
+            print >> log, "No such message template"
+           return 1
+
+        message = messages[0]
+        subject = message['subject']
+        template = message['template'] % \
+            (self.api.config.PLC_WWW_HOST,
+             self['verification_key'], self['person_id'],
+             self.api.config.PLC_MAIL_SUPPORT_ADDRESS,
+             self.api.config.PLC_WWW_HOST)
+
+        self.api.mailer.mail(to_addr, None, from_addr, subject, template)
+    
+    def send_account_registered_email(self, site):
+       
+       to_addr = {}
+       cc_addr = {}
+       from_addr = {}
+       from_addr[self.api.config.PLC_MAIL_SUPPORT_ADDRESS] = \
+        "%s %s" % ('Planetlab', 'Support')
+
+       # email user
+       user_full_name = "%s %s" % (self['first_name'], self['last_name'])
+       to_addr[self['email']] = "%s" % user_full_name
+
+       # if the account had a admin role or a pi role, email support.
+        if set(['admin', 'pi']).intersection(self['roles']):
+            to_addr[self.api.config.PLC_MAIL_SUPPORT_ADDRESS] = \
+                "%s %s" % ('Planetlab', 'Support')
+       
+       # cc site pi's
+       site_persons = Persons(self.api, site['person_ids'])
+        for person in site_persons:
+            if 'pi' in person['roles'] and not person['email'] in to_addr.keys():
+                cc_addr[person['email']] = "%s %s" % \
+               (person['first_name'], person['last_name'])
+
+       # fill in template
+       messages = Messages(self.api, ['ACCOUNT_REGISTERED'])
+        if not messages:
+           print >> log, "No such message template"
+            return 1
+
+        message = messages[0]
+        subject = message['subject'] % (user_full_name, site['name'])
+        template = message['template'] % \
+           (user_full_name, site['name'], ", ".join(self['roles']),
+            self.api.config.PLC_WWW_HOST, self['person_id'],
+             self.api.config.PLC_MAIL_SUPPORT_ADDRESS,
+             self.api.config.PLC_WWW_HOST)
+                               
+       self.api.mailer.mail(to_addr, cc_addr, from_addr, subject, template)
+
     def delete(self, commit = True):
         """
         Delete existing account.
@@ -272,7 +363,7 @@ class Person(Row):
 
         # Delete all keys
         keys = Keys(self.api, self['key_ids'])
-        for key in keys.values():
+        for key in keys:
             key.delete(commit = False)
 
         # Clean up miscellaneous join tables
@@ -290,11 +381,11 @@ class Persons(Table):
     database.
     """
 
-    def __init__(self, api, person_filter = None):
-        Table.__init__(self, api, Person)
+    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(Person.fields)
+              ", ".join(self.columns)
 
         if person_filter is not None:
             if isinstance(person_filter, (list, tuple, set)):
@@ -306,5 +397,4 @@ class Persons(Table):
             elif isinstance(person_filter, dict):
                 person_filter = Filter(Person.fields, person_filter)
                 sql += " AND (%s)" % person_filter.sql(api, "AND")
-
         self.selectall(sql)