--- /dev/null
+import random
+import base64
+import time
+import urllib
+
+from PLC.Debug import log
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Sites import Site, Sites
+from PLC.Messages import Message, Messages
+from PLC.Auth import Auth
+from PLC.sendmail import sendmail
+
+class VerifyPerson(Method):
+ """
+ Verify a new (must be disabled) user's e-mail address and registration.
+
+ If verification_key is not specified, then a new verification_key
+ will be generated and stored with the user's account. The key will
+ be e-mailed to the user in the form of a link to a web page.
+
+ The web page should verify the key by calling this function again
+ and specifying verification_key. If the key matches what has been
+ stored in the user's account, then an e-mail will be sent to the
+ user's PI (and support if the user is requesting a PI role),
+ asking the PI (or support) to enable the account.
+
+ Returns 1 if the verification key if valid.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ Auth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Person.fields['verification_key'],
+ Person.fields['verification_expires']
+ ]
+
+ returns = Parameter(int, '1 if verification_key is valid')
+
+ def call(self, auth, person_id_or_email, verification_key = None, verification_expires = None):
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+ person = persons[0]
+
+ if person['peer_id'] is not None:
+ raise PLCInvalidArgument, "Not a local account"
+
+ if person['enabled']:
+ raise PLCInvalidArgument, "Account must be new (disabled)"
+
+ # Get the primary site name
+ person_sites = Sites(self.api, person['site_ids'])
+ if person_sites:
+ site_name = person_sites[0]['name']
+ else:
+ site_name = "No Site"
+
+ # Generate 32 random bytes
+ bytes = random.sample(xrange(0, 256), 32)
+ # Base64 encode their string representation
+ random_key = base64.b64encode("".join(map(chr, bytes)))
+
+ if verification_key is not None:
+ if person['verification_key'] is None or \
+ person['verification_expires'] is None or \
+ person['verification_expires'] < time.time():
+ person.delete()
+ raise PLCPermissionDenied, "Verification key has expired. Please re-register."
+ elif person['verification_key'] != verification_key:
+ raise PLCPermissionDenied, "Verification key incorrect"
+ else:
+ person['verification_key'] = None
+ person['verification_expires'] = None
+ person.sync()
+
+ # Get the PI(s) of each site that the user is registering with
+ person_ids = set()
+ for site in person_sites:
+ person_ids.update(site['person_ids'])
+ persons = Persons(self.api, person_ids)
+ pis = filter(lambda person: 'pi' in person['roles'], persons)
+
+ # Send e-mail to PI(s) and copy the user
+ To = [("%s %s" % (pi['first_name'], pi['last_name']), pi['email']) for pi in pis]
+ Cc = ("%s %s" % (person['first_name'], person['last_name']), person['email'])
+
+ if 'pi' in person['roles']:
+ # And support if user is requesting a PI role
+ To.append(("%s Support" % self.api.config.PLC_NAME,
+ self.api.config.PLC_MAIL_SUPPORT_ADDRESS))
+ message_id = 'New PI account'
+ else:
+ message_id = 'New account'
+ else:
+ # Only allow one verification at a time
+ if person['verification_expires'] is not None and \
+ person['verification_expires'] > time.time():
+ raise PLCPermissionDenied, "Verification request already pending"
+
+ if verification_expires is None:
+ verification_expires = int(time.time() + (24 * 60 * 60))
+
+ person['verification_key'] = random_key
+ person['verification_expires'] = verification_expires
+ person.sync()
+
+ # Send e-mail to user
+ To = ("%s %s" % (person['first_name'], person['last_name']), person['email'])
+ Cc = None
+
+ message_id = 'Verify account'
+
+ messages = Messages(self.api, [message_id])
+ if messages:
+ # Send message to user
+ message = messages[0]
+
+ params = {'PLC_NAME': self.api.config.PLC_NAME,
+ 'PLC_MAIL_SUPPORT_ADDRESS': self.api.config.PLC_MAIL_SUPPORT_ADDRESS,
+ 'PLC_WWW_HOST': self.api.config.PLC_WWW_HOST,
+ 'PLC_WWW_SSL_PORT': self.api.config.PLC_WWW_SSL_PORT,
+ 'person_id': person['person_id'],
+ # Will be used in a URL, so must quote appropriately
+ 'verification_key': urllib.quote_plus(random_key),
+ 'site_name': site_name,
+ 'first_name': person['first_name'],
+ 'last_name': person['last_name'],
+ 'email': person['email'],
+ 'roles': ", ".join(person['roles'])}
+
+ sendmail(self.api,
+ To = To,
+ Cc = Cc,
+ Subject = message['subject'] % params,
+ Body = message['template'] % params)
+ else:
+ print >> log, "Warning: No message template '%s'" % message_id
+
+ # Logging variables
+ self.object_ids = [person['person_id']]
+ self.message = message_id
+
+ return 1