Backup commit.
[TownSquare.git] / townsquare / lib / account.py
blobf799a9319e421b92e68438f1345895445cc8b6fa
1 import logging, re, datetime, uuid, hashlib
2 from zlib import crc32
4 from fma import SuperDoc
5 from fma.orm import relation
8 def _hash_passkey(passkey, salt):
9 #CHECK: use static salt?
10 #return hashlib.sha1(salt + hashlib.md5(passkey).hexdigest()).hexdigest()
11 return hashlib.sha1(salt + passkey).hexdigest()
13 def _generate_activation_key():
14 #CHECK: more sophisticated generator?
15 #return str(uuid.uuid4())
16 return '%x' % (crc32(str(uuid.uuid4())) & 0xffffffffL)
19 class Error(Exception):
20 pass
22 class NameInvalid(Error): pass
23 class NameExists(Error): pass
24 class EmailInvalid(Error): pass
25 class EmailExists(Error): pass
28 class Account(SuperDoc):
29 _collection_name = 'accounts'
31 idname = unicode
33 _opt = {
34 'req' : ['idname','email','passkey']
37 @property
38 def url(self):
39 return '';
41 def save(self):
42 if not self._saved():
43 #TODO: check for existing name or email
44 if self.idname is None:
45 if self.name is None:
46 raise NameInvalid
47 self.idname = self.name.lower()
48 else:
49 self.idname = self.idname.lower()
50 #TODO: name validity check here
51 if len(self.idname) < 4 or len(self.idname) > 32:
52 raise NameInvalid
53 # Check if the id already existed
54 #TODO: expiration (when the account activation is expired, the name could be used)
55 if self._monga.col(Account).find_one(idname=self.idname):
56 raise NameExists
57 self.email = self.email.lower()
58 #TODO: check email address validity here
59 # Check if the email address already existed
60 if self._monga.col(Account).find_one(email=self.email):
61 raise EmailExists
62 if hasattr(self, 'creation_timestamp') is not True or len(self.creation_timestamp) is 0:
63 self.creation_timestamp = datetime.datetime.utcnow()
64 self.salt = '%x' % (crc32(str(uuid.uuid4())) & 0xffffffffL)
65 self.passkey = _hash_passkey(self.passkey, self.salt)
66 #TODO: check config for activation method
67 if hasattr(self, 'active') is False or self.active is not True:
68 self.active = False
69 self.activation_key = _generate_activation_key()
70 #self.banned = False
71 #if self.admin is None:
72 # self.admin = False
73 else:
74 #TODO: check for changed properties
75 pass
76 super(Account, self).save()
78 def activate(self, actkey):
79 #TODO: expiration
80 if self.activation_key == actkey:
81 self.active = True
82 #TODO: clear completely
83 self.activation_key = None
84 return True
85 return False
87 def regenerate_activation_key(self, active_check=True):
88 if (active_check and self.activate is not True) or active_check == False:
89 self.activation_key = _generate_activation_key()
91 def authenticate(self, passkey):
92 """ Stateless
93 """
94 if not self._saved():
95 return False
96 return self.passkey == _hash_passkey(passkey, self.salt)
98 def change_passkey(self, newpasskey):
99 """ WARNING: no old passkey checking (use authenticate first)
101 self.passkey = _hash_passkey(newpasskey, self.salt)
105 #def register(name, email, password):
106 # acc = Account()
107 # acc.name = name
108 # acc.idname = name.lower()
109 # acc.email = email
110 # acc.passkey = password
111 # #acc.admin = True
112 # #TODO: catch exception here!
113 # #acc.save()
114 # g.db.col(Account).insert(acc)
116 #def current():
117 # return None