addons-server/apps/users/models.py

193 строки
6.8 KiB
Python

from datetime import datetime
import hashlib
import random
import re
import string
import time
from django.conf import settings
from django.contrib.auth.models import User as DjangoUser
from django.core.mail import send_mail
from django.db import models
from django.template import Context, loader
import commonware.log
from tower import ugettext as _
import amo
import amo.models
from amo.urlresolvers import reverse
from translations.fields import PurifiedField
log = commonware.log.getLogger('z.users')
def get_hexdigest(algorithm, salt, raw_password):
return hashlib.new(algorithm, salt + raw_password).hexdigest()
def rand_string(length):
return ''.join(random.choice(string.letters) for i in xrange(length))
def create_password(algorithm, raw_password):
salt = get_hexdigest(algorithm, rand_string(12), rand_string(12))[:64]
hsh = get_hexdigest(algorithm, salt, raw_password)
return '$'.join([algorithm, salt, hsh])
class UserProfile(amo.models.ModelBase):
nickname = models.CharField(max_length=255, unique=True, default='',
null=True, blank=True)
firstname = models.CharField(max_length=255, default='', blank=True)
lastname = models.CharField(max_length=255, default='', blank=True)
password = models.CharField(max_length=255, default='')
email = models.EmailField(unique=True)
averagerating = models.CharField(max_length=255, blank=True)
bio = PurifiedField()
confirmationcode = models.CharField(max_length=255, default='',
blank=True)
deleted = models.BooleanField(default=False)
display_collections = models.BooleanField(default=False)
display_collections_fav = models.BooleanField(default=False)
emailhidden = models.BooleanField(default=False)
homepage = models.CharField(max_length=255, blank=True, default='')
location = models.CharField(max_length=255, blank=True, default='')
notes = models.TextField(blank=True)
notifycompat = models.BooleanField(default=True)
notifyevents = models.BooleanField(default=True)
occupation = models.CharField(max_length=255, default='', blank=True)
picture_type = models.CharField(max_length=75, default='', blank=True)
resetcode = models.CharField(max_length=255, default='', blank=True)
resetcode_expires = models.DateTimeField(default=datetime.now,
blank=True)
sandboxshown = models.BooleanField(default=False)
user = models.ForeignKey(DjangoUser, null=True, editable=False, blank=True)
class Meta:
db_table = 'users'
def __unicode__(self):
return '%s: %s' % (self.id, self.display_name)
def get_url_path(self):
return reverse('users.profile', args=[self.id])
@amo.cached_property
def addons_listed(self):
"""public add-ons this user is listed as author of"""
return self.addons.valid().filter(addonuser__listed=True)
@property
def name(self):
"""Can be used while we're transitioning from separate first/last names
to a single field. Bug 546818#6"""
return (u'%s %s' % (self.firstname, self.lastname)).strip()
@property
def picture_url(self):
split_id = re.match(r'((\d*?)(\d{0,3}?))\d{1,3}$', str(self.id))
if not self.picture_type:
return settings.MEDIA_URL + '/img/zamboni/anon_user.png'
else:
return settings.USER_PIC_URL % (
split_id.group(2) or 0, split_id.group(1) or 0, self.id,
int(time.mktime(self.modified.timetuple())))
@amo.cached_property
def is_developer(self):
return bool(self.addons.filter(authors=self,
addonuser__listed=True)[:1])
@property
def display_name(self):
if not self.nickname:
return '%s %s' % (self.firstname, self.lastname)
else:
return self.nickname
@property
def welcome_name(self):
if self.firstname:
return self.firstname
elif self.nickname:
return self.nickname
elif self.lastname:
return self.lastname
return ''
@amo.cached_property
def reviews(self):
"""All reviews that are not dev replies."""
return self._reviews_all.filter(reply_to=None)
def anonymize(self):
log.info("User (%s: <%s>) is being anonymized." % (self, self.email))
self.email = ""
self.password = "sha512$Anonymous$Password"
self.firstname = ""
self.lastname = ""
self.nickname = None
self.homepage = ""
self.deleted = True
self.picture_type = ""
self.save()
def save(self, force_insert=False, force_update=False, using=None):
# we have to fix stupid things that we defined poorly in remora
if self.resetcode_expires is None:
self.resetcode_expires = datetime.now()
super(UserProfile, self).save(force_insert, force_update, using)
def check_password(self, raw_password):
if '$' not in self.password:
valid = (get_hexdigest('md5', '', raw_password) == self.password)
if valid:
# Upgrade an old password.
self.set_password(raw_password)
self.save()
return valid
algo, salt, hsh = self.password.split('$')
return hsh == get_hexdigest(algo, salt, raw_password)
def set_password(self, raw_password, algorithm='sha512'):
self.password = create_password(algorithm, raw_password)
def email_confirmation_code(self):
log.debug("Sending account confirmation code for user (%s)", self)
url = "%s%s" % (settings.SITE_URL,
reverse('users.confirm',
args=[self.id, self.confirmationcode]))
domain = settings.DOMAIN
t = loader.get_template('users/email/confirm.ltxt')
c = {'domain': domain, 'url': url, }
send_mail(_("Please confirm your email address"),
t.render(Context(c)), None, [self.email])
def create_django_user(self):
"""Make a django.contrib.auth.User for this UserProfile."""
# Reusing the id will make our life easier, because we can use the
# OneToOneField as pk for Profile linked back to the auth.user
# in the future.
self.user = DjangoUser(id=self.pk)
self.user.first_name = self.firstname
self.user.last_name = self.lastname
self.user.username = self.email
self.user.email = self.email
self.user.password = self.password
self.user.date_joined = self.created
if self.groups.filter(rules='*:*').count():
self.user.is_superuser = self.user.is_staff = True
self.user.save()
self.save()
return self.user